1
0
forked from ScoDoc/ScoDoc

WIP suite de la migration

This commit is contained in:
Emmanuel Viennet 2021-06-21 10:17:16 +02:00
parent 8f91d5292c
commit 6a4d6e5109
43 changed files with 494 additions and 1240 deletions

View File

@ -1,838 +0,0 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""Site ScoDoc pour plusieurs departements:
gestion de l'installation et des creation de départements.
Chaque departement est géré par un ZScolar sous ZScoDoc.
"""
import time
import datetime
import string
import glob
import re
import inspect
import urllib
import urllib2
import cgi
import xml
from cStringIO import StringIO
from zipfile import ZipFile
import os.path
import traceback
from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error
MIMEMultipart,
)
from email.MIMEText import MIMEText # pylint: disable=no-name-in-module,import-error
from email.MIMEBase import MIMEBase # pylint: disable=no-name-in-module,import-error
from email.Header import Header # pylint: disable=no-name-in-module,import-error
from email import Encoders # pylint: disable=no-name-in-module,import-error
from app.scodoc.sco_zope import (
ObjectManager,
PropertyManager,
RoleManager,
Item,
Persistent,
Implicit,
ClassSecurityInfo,
DTMLFile,
Globals,
)
try:
import Products.ZPsycopgDA.DA as ZopeDA
except:
import ZPsycopgDA.DA as ZopeDA # interp.py
import app.scodoc.sco_utils as scu
from app.scodoc import VERSION
import mails
from app.scodoc.notes_log import log
from app.scodoc import sco_find_etud
from app.scodoc import sco_users
from app.scodoc.sco_permissions import (
ScoView,
ScoEnsView,
ScoImplement,
ScoChangeFormation,
ScoObservateur,
ScoEtudInscrit,
ScoEtudChangeGroups,
ScoEtudChangeAdr,
ScoEtudSupprAnnotations,
ScoEditAllEvals,
ScoEditAllNotes,
ScoEditFormationTags,
ScoEditApo,
ScoSuperAdmin,
)
from app.scodoc.sco_exceptions import (
ScoValueError,
ScoLockedFormError,
ScoGenError,
AccessDenied,
)
from app.scodoc import html_sco_header
class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Implicit):
"ZScoDoc object"
meta_type = "ZScoDoc"
security = ClassSecurityInfo()
file_path = Globals.package_home(globals())
# This is the list of the methods associated to 'tabs' in the ZMI
# Be aware that The first in the list is the one shown by default, so if
# the 'View' tab is the first, you will never see your tabs by cliquing
# on the object.
manage_options = (
({"label": "Contents", "action": "manage_main"},)
+ PropertyManager.manage_options # add the 'Properties' tab
+ ({"label": "View", "action": "index_html"},)
+ Item.manage_options # add the 'Undo' & 'Owner' tab
+ RoleManager.manage_options # add the 'Security' tab
)
def __init__(self, id, title):
"Initialise a new instance of ZScoDoc"
self.id = id
self.title = title
self.manage_addProperty("admin_password_initialized", "0", "string")
security.declareProtected(ScoView, "ScoDocURL")
def ScoDocURL(self):
"base URL for this instance (top level for ScoDoc site)"
return self.absolute_url()
def _check_admin_perm(self, REQUEST):
"""Check if user has permission to add/delete departements"""
authuser = REQUEST.AUTHENTICATED_USER
if authuser.has_role("manager") or authuser.has_permission(
Permission.ScoSuperAdmin, self
):
return ""
else:
return """<h2>Vous n'avez pas le droit d'accéder à cette page</h2>"""
def _check_users_folder(self, REQUEST=None):
"""Vérifie UserFolder et le crée s'il le faut"""
try:
_ = self.UsersDB
return "<!-- uf ok -->"
except:
e = self._check_admin_perm(REQUEST)
if not e: # admin permissions:
self.create_users_cnx(REQUEST)
self.create_users_folder(REQUEST)
return '<div class="head_message">Création du connecteur utilisateurs réussie</div>'
else:
return """<div class="head_message">Installation non terminée: connectez vous avec les droits d'administrateur</div>"""
security.declareProtected("View", "create_users_folder")
def create_users_folder(self, REQUEST=None):
"""Create Zope user folder"""
e = self._check_admin_perm(REQUEST)
if e:
return e
if REQUEST is None:
REQUEST = {}
REQUEST.form["pgauth_connection"] = "UsersDB"
REQUEST.form["pgauth_table"] = "sco_users"
REQUEST.form["pgauth_usernameColumn"] = "user_name"
REQUEST.form["pgauth_passwordColumn"] = "passwd"
REQUEST.form["pgauth_rolesColumn"] = "roles"
add_method = self.manage_addProduct["OFSP"].manage_addexUserFolder
log("create_users_folder: in %s" % self.id)
return add_method(
authId="pgAuthSource",
propId="nullPropSource",
memberId="nullMemberSource",
groupId="nullGroupSource",
cryptoId="MD51",
# doAuth='1', doProp='1', doMember='1', doGroup='1', allDone='1',
cookie_mode=2,
session_length=500,
not_session_length=0,
REQUEST=REQUEST,
)
def _fix_users_folder(self):
"""removes docLogin and docLogout dtml methods from exUserFolder, so that we use ours.
(called each time be index_html, to fix old ScoDoc installations.)
"""
try:
self.acl_users.manage_delObjects(ids=["docLogin", "docLogout"])
except:
pass
# add missing getAuthFailedMessage (bug in exUserFolder ?)
try:
_ = self.getAuthFailedMessage
except:
log("adding getAuthFailedMessage to Zope install")
parent = self.aq_parent
from OFS.DTMLMethod import addDTMLMethod # pylint: disable=import-error
addDTMLMethod(parent, "getAuthFailedMessage", file="Identification")
security.declareProtected("View", "create_users_cnx")
def create_users_cnx(self, REQUEST=None):
"""Create Zope connector to UsersDB
Note: la connexion est fixée (SCOUSERS) (base crée par l'installeur) !
Les utilisateurs avancés pourront la changer ensuite.
"""
# ce connecteur zope - db est encore pour l'instant utilisé par exUserFolder.pgAuthSource
# (en lecture seule en principe)
oid = "UsersDB"
log("create_users_cnx: in %s" % self.id)
da = ZopeDA.Connection(
oid,
"Cnx bd utilisateurs",
scu.SCO_DEFAULT_SQL_USERS_CNX,
False,
check=1,
tilevel=2,
encoding="LATIN1",
)
self._setObject(oid, da)
security.declareProtected("View", "change_admin_user")
def change_admin_user(self, password, REQUEST=None):
"""Change password of admin user"""
# note: controle sur le role et non pas sur une permission
# (non definies au top level)
if not REQUEST.AUTHENTICATED_USER.has_role("Manager"):
log("user %s is not Manager" % REQUEST.AUTHENTICATED_USER)
log("roles=%s" % REQUEST.AUTHENTICATED_USER.getRolesInContext(self))
raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération")
log("trying to change admin password")
# 1-- check strong password
if not sco_users.is_valid_password(password):
log("refusing weak password")
return REQUEST.RESPONSE.redirect(
"change_admin_user_form?message=Mot%20de%20passe%20trop%20simple,%20recommencez"
)
# 2-- change password for admin user
username = "admin"
acl_users = self.aq_parent.acl_users
user = acl_users.getUser(username)
r = acl_users._changeUser(
username, password, password, user.roles, user.domains
)
if not r:
# OK, set property to indicate we changed the password
log("admin password changed successfully")
self.manage_changeProperties(admin_password_initialized="1")
return r or REQUEST.RESPONSE.redirect("index_html")
security.declareProtected("View", "change_admin_user_form")
def change_admin_user_form(self, message="", REQUEST=None):
"""Form allowing to change the ScoDoc admin password"""
# note: controle sur le role et non pas sur une permission
# (non definies au top level)
if not REQUEST.AUTHENTICATED_USER.has_role("Manager"):
raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération")
H = [
html_sco_header.scodoc_top_html_header(
self, REQUEST, page_title="ScoDoc: changement mot de passe"
)
]
if message:
H.append('<div id="message">%s</div>' % message)
H.append(
"""<h2>Changement du mot de passe administrateur (utilisateur admin)</h2>
<p>
<form action="change_admin_user" method="post"><table>
<tr><td>Nouveau mot de passe:</td><td><input type="password" size="14" name="password"/></td></tr>
<tr><td>Confirmation: </td><td><input type="password" size="14" name="password2" /></td></tr>
</table>
<input type="submit" value="Changer">
"""
)
H.append("""</body></html>""")
return "\n".join(H)
security.declareProtected("View", "list_depts")
def list_depts(self, viewable=True, format=None, REQUEST=None):
"""List departments
If viewable, list only depts viewable the current user.
"""
authuser = REQUEST.AUTHENTICATED_USER
viewable = int(viewable)
return scu.sendResult(
REQUEST,
[
d.id
for d in self._list_depts()
if (not viewable)
or authuser.has_permission(Permission.ScoView, d.Scolarite)
],
name="depts",
format=format,
)
def _list_depts(self, REQUEST=None): # not published
# List departments folders
# (returns a list of Zope folders containing a ZScolar instance)
folders = self.objectValues("Folder")
# select folders with Scolarite object:
r = []
for folder in folders:
try:
_ = folder.Scolarite
r.append(folder)
except:
pass
return r
security.declareProtected("View", "create_dept")
def create_dept(self, REQUEST=None, DeptId="", pass2=False):
"""Creation (ajout) d'un site departement
(instance ZScolar + dossier la contenant)
"""
e = self._check_admin_perm(REQUEST)
if e:
return e
if not DeptId:
raise ValueError("nom de departement invalide")
if not pass2:
# 1- Creation de repertoire Dept
log("creating Zope folder " + DeptId)
add_method = self.manage_addProduct["OFSP"].manage_addFolder
add_method(DeptId, title="Site dept. " + DeptId)
DeptFolder = self[DeptId]
if not pass2:
# 2- Creation du repertoire Fotos
log("creating Zope folder %s/Fotos" % DeptId)
add_method = DeptFolder.manage_addProduct["OFSP"].manage_addFolder
add_method("Fotos", title="Photos identites " + DeptId)
# 3- Creation instance ScoDoc
log("creating Zope ZScolar instance")
add_method = DeptFolder.manage_addProduct["ScoDoc"].manage_addZScolarForm
return add_method(DeptId, REQUEST=REQUEST)
security.declareProtected("View", "delete_dept")
def delete_dept(self, REQUEST=None, DeptId="", force=False):
"""Supprime un departement (de Zope seulement, ne touche pas la BD)"""
e = self._check_admin_perm(REQUEST)
if e:
return e
if not force and DeptId not in [x.id for x in self._list_depts()]:
raise ValueError("nom de departement invalide")
self.manage_delObjects(ids=[DeptId])
return (
"<p>Département "
+ DeptId
+ """ supprimé du serveur web (la base de données n'est pas affectée)!</p><p><a href="/ScoDoc">Continuer</a></p>"""
)
security.declareProtected("View", "index_html")
def index_html(self, REQUEST=None, message=None):
"""Top level page for ScoDoc"""
authuser = REQUEST.AUTHENTICATED_USER
deptList = self._list_depts()
self._fix_users_folder() # fix our exUserFolder
isAdmin = not self._check_admin_perm(REQUEST)
try:
admin_password_initialized = self.admin_password_initialized
except:
admin_password_initialized = "0"
if isAdmin and admin_password_initialized != "1":
return REQUEST.RESPONSE.redirect(
"ScoDoc/change_admin_user_form?message=Le%20mot%20de%20passe%20administrateur%20doit%20etre%20change%20!"
)
# Si l'URL indique que l'on est dans un folder, affiche page login du departement
try:
deptfoldername = REQUEST.URL0.split("ScoDoc")[1].split("/")[1]
if deptfoldername in [x.id for x in self._list_depts()]:
return self.index_dept(deptfoldername=deptfoldername, REQUEST=REQUEST)
except:
pass
H = [
html_sco_header.scodoc_top_html_header(
self, REQUEST, page_title="ScoDoc: bienvenue"
),
self._check_users_folder(REQUEST=REQUEST), # ensure setup is done
]
if message:
H.append('<div id="message">%s</div>' % message)
if isAdmin and not message:
H.append('<div id="message">Attention: connecté comme administrateur</div>')
H.append(
"""
<div class="maindiv">
<h2>ScoDoc: gestion scolarité</h2>
"""
)
if authuser.has_role("Authenticated"):
H.append(
"""<p>Bonjour <font color="red"><b>%s</b></font>.</p>""" % str(authuser)
)
H.append(
"""<p>N'oubliez pas de vous <a href="acl_users/logout">déconnecter</a> après usage.</p>"""
)
else:
H.append(
"""<p>Ce site est <font color="red"><b>réservé au personnel autorisé</b></font></p>"""
)
H.append(self.authentication_form(destination="."))
if not deptList:
H.append("<em>aucun département existant !</em>")
# si pas de dept et pas admin, propose lien pour loger admin
if not isAdmin:
H.append(
"""<p><a href="/force_admin_authentication">Identifiez vous comme administrateur</a> (au début: nom 'admin', mot de passe 'scodoc')</p>"""
)
else:
H.append('<ul class="main">')
if isAdmin:
dest_folder = "/Scolarite"
else:
dest_folder = ""
for deptFolder in self._list_depts():
if authuser.has_permission(Permission.ScoView, deptFolder.Scolarite):
link_cls = "link_accessible"
else:
link_cls = "link_unauthorized"
# Essai de recuperer le nom du departement dans ses preferences
try:
DeptName = (
deptFolder.Scolarite.get_preference("DeptName") or deptFolder.id
)
except:
DeptName = deptFolder.id
H.append(
'<li><a class="stdlink %s" href="%s%s">Département %s</a>'
% (link_cls, deptFolder.absolute_url(), dest_folder, DeptName)
)
# check if roles are initialized in this depts, and do it if necessary
if deptFolder.Scolarite.roles_initialized == "0":
if isAdmin:
deptFolder.Scolarite._setup_initial_roles_and_permissions()
else:
H.append(" (non initialisé, connectez vous comme admin)")
H.append("</li>")
H.append("</ul>")
# Recherche etudiant
H.append(sco_find_etud.form_search_etud_in_accessible_depts(self, REQUEST))
if isAdmin:
H.append('<p><a href="scodoc_admin">Administration de ScoDoc</a></p>')
else:
H.append(
'<p><a href="%s/force_admin_authentication">Se connecter comme administrateur</a></p>'
% REQUEST.BASE0
)
# Lien expérimental temporaire:
H.append(
'<p><a href="/ScoDoc/static/mobile">Version mobile (expérimentale, à vos risques et périls)</a></p>'
)
H.append(
"""
<div id="scodoc_attribution">
<p><a href="%s">ScoDoc</a> est un logiciel libre de suivi de la scolarité des étudiants conçu par
E. Viennet (Université Paris 13).</p>
</div>
</div>"""
% (scu.SCO_WEBSITE,)
)
H.append("""</body></html>""")
return "\n".join(H)
def authentication_form(self, destination=""):
"""html snippet for authentication"""
return (
"""<!-- authentication_form -->
<form action="doLogin" method="post">
<input type="hidden" name="destination" value="%s"/>
<p>
<table border="0" cellpadding="3">
<tr>
<td><b>Nom:</b></td>
<td><input id="name" type="text" name="__ac_name" size="20"/></td>
</tr><tr>
<td><b>Mot de passe:</b></td>
<td><input id="password" type="password" name="__ac_password" size="20"/></td>
<td><input id="submit" name="submit" type="submit" value="OK"/></td>
</tr>
</table>
</p>
</form>"""
% destination
)
security.declareProtected("View", "index_dept")
def index_dept(self, deptfoldername="", REQUEST=None):
"""Page d'accueil departement"""
authuser = REQUEST.AUTHENTICATED_USER
try:
dept = getattr(self, deptfoldername)
if authuser.has_permission(Permission.ScoView, dept):
return REQUEST.RESPONSE.redirect("ScoDoc/%s/Scolarite" % deptfoldername)
except:
log(
"*** problem in index_dept (%s) user=%s"
% (deptfoldername, str(authuser))
)
H = [
html_sco_header.standard_html_header(),
"""<div style="margin: 1em;">
<h2>Scolarité du département %s</h2>"""
% deptfoldername,
"""<p>Ce site est
<font color="#FF0000"><b>réservé au personnel du département</b></font>.
</p>""",
self.authentication_form(destination="Scolarite"),
"""
<p>Pour quitter, <a href="acl_users/logout">logout</a></p>
<p><a href="%s">Retour à l'accueil</a></p>
</div>
"""
% self.ScoDocURL(),
html_sco_header.standard_html_footer(),
]
return "\n".join(H)
security.declareProtected("View", "doLogin")
def doLogin(self, REQUEST=None, destination=None):
"redirect to destination after login"
if destination:
return REQUEST.RESPONSE.redirect(destination)
security.declareProtected("View", "docLogin")
docLogin = DTMLFile("dtml/docLogin", globals())
security.declareProtected("View", "docLogout")
docLogout = DTMLFile("dtml/docLogout", globals())
security.declareProtected("View", "query_string_to_form_inputs")
def query_string_to_form_inputs(self, query_string=""):
"""Return html snippet representing the query string as POST form hidden inputs.
This is useful in conjonction with exUserfolder to correctly redirect the response
after authentication.
"""
H = []
for a in query_string.split("&"):
if a:
nv = a.split("=")
if len(nv) == 2:
name, value = nv
H.append(
'<input type="hidden" name="'
+ name
+ '" value="'
+ value
+ '"/>'
)
return "<!-- query string -->\n" + "\n".join(H)
security.declareProtected("View", "standard_error_message")
def standard_error_message(
self,
error_value=None,
error_message=None, # unused ?
error_type=None,
error_traceback=None,
error_tb=None,
**kv
):
"Recuperation des exceptions Zope"
# neat (or should I say dirty ?) hack to get REQUEST
# in fact, our caller (probably SimpleItem.py) has the REQUEST variable
# that we'd like to use for our logs, but does not pass it as an argument.
try:
frame = inspect.currentframe()
REQUEST = frame.f_back.f_locals["REQUEST"]
except:
REQUEST = {}
# Authentication uses exceptions, pass them up
HTTP_X_FORWARDED_FOR = REQUEST.get("HTTP_X_FORWARDED_FOR", "")
if error_type == "LoginRequired":
log("LoginRequired from %s" % HTTP_X_FORWARDED_FOR)
self.login_page = error_value
return error_value
elif error_type == "Unauthorized":
log("Unauthorized from %s" % HTTP_X_FORWARDED_FOR)
return self.acl_users.docLogin(self, REQUEST=REQUEST)
log("exception caught: %s" % error_type)
log(traceback.format_exc())
params = {
"error_type": error_type,
"error_value": error_value,
"error_tb": error_tb,
"sco_exc_mail": scu.SCO_EXC_MAIL,
"sco_dev_mail": scu.SCO_DEV_MAIL,
}
if error_type == "ScoGenError":
return "<p>" + str(error_value) + "</p>"
elif error_type in ("ScoValueError", "FormatError"):
# Not a bug, presents a gentle message to the user:
H = [
html_sco_header.standard_html_header(),
"""<h2>Erreur !</h2><p>%s</p>""" % error_value,
]
if error_value.dest_url:
H.append('<p><a href="%s">Continuer</a></p>' % error_value.dest_url)
H.append(html_sco_header.standard_html_footer())
return "\n".join(H)
else: # Other exceptions, try carefully to build an error page...
# log('exc A')
H = []
try:
H.append(html_sco_header.standard_html_header())
except:
pass
H.append(
"""<table border="0" width="100%%"><tr valign="top">
<td width="10%%" align="center"></td>
<td width="90%%"><h2>Erreur !</h2>
<p>Une erreur est survenue</p>
<p>
<strong>Error Type: %(error_type)s</strong><br>
<strong>Error Value: %(error_value)s</strong><br>
</p>
<hr noshade>
<p>L'URL est peut-etre incorrecte ?</p>
<p>Si l'erreur persiste, contactez Emmanuel Viennet:
<a href="mailto:%(sco_dev_mail)s">%(sco_dev_mail)s</a>
en copiant ce message d'erreur et le contenu du cadre bleu ci-dessous si possible.
</p>
</td></tr>
</table> """
% params
)
# display error traceback (? may open a security risk via xss attack ?)
params["txt_html"] = self._report_request(REQUEST, fmt="html")
H.append(
"""<h4 class="scodoc">Zope Traceback (à envoyer par mail à <a href="mailto:%(sco_dev_mail)s">%(sco_dev_mail)s</a>)</h4><div style="background-color: rgb(153,153,204); border: 1px;">
%(error_tb)s
<p><b>Informations:</b><br/>
%(txt_html)s
</p>
</div>
<p>Merci de votre patience !</p>
"""
% params
)
try:
H.append(html_sco_header.standard_html_footer())
except:
log("no footer found for error page")
pass
# --- Mail:
params["error_traceback_txt"] = scu.scodoc_html2txt(error_tb)
txt = (
"""
ErrorType: %(error_type)s
%(error_traceback_txt)s
"""
% params
)
mails.send_debug_alert(context, txt, REQUEST=REQUEST)
# ---
log("done processing exception")
# log( '\n page=\n' + '\n'.join(H) )
return "\n".join(H)
security.declareProtected("View", "scodoc_admin")
def scodoc_admin(self, REQUEST=None):
"""Page Operations d'administration"""
e = self._check_admin_perm(REQUEST)
if e:
return e
H = [
html_sco_header.scodoc_top_html_header(
self, REQUEST, page_title="ScoDoc: bienvenue"
),
"""
<h3>Administration ScoDoc</h3>
<p><a href="change_admin_user_form">changer le mot de passe super-administrateur</a></p>
<p><a href="%s">retour à la page d'accueil</a></p>
<h4 class="scodoc">Création d'un département</h4>
<p class="help_important">Le département doit avoir été créé au préalable sur le serveur en utilisant le script
<tt>create_dept.sh</tt> (à lancer comme <tt>root</tt> dans le répertoire <tt>config</tt> de ScoDoc).
</p>"""
% self.absolute_url(),
]
deptList = [x.id for x in self._list_depts()] # definis dans Zope
deptIds = set(self._list_depts_ids()) # definis sur le filesystem
existingDepts = set(deptList)
addableDepts = deptIds - existingDepts
if not addableDepts:
# aucun departement defini: aide utilisateur
H.append("<p>Aucun département à ajouter !</p>")
else:
H.append("""<form action="create_dept"><select name="DeptId"/>""")
for deptId in addableDepts:
H.append("""<option value="%s">%s</option>""" % (deptId, deptId))
H.append(
"""</select>
<input type="submit" value="Créer département">
</form>"""
)
if deptList:
H.append(
"""
<h4 class="scodoc">Suppression d'un département</h4>
<p>Ceci permet de supprimer le site web associé à un département, mais n'affecte pas la base de données
(le site peut donc être recréé sans perte de données).
</p>
<form action="delete_dept">
<select name="DeptId">
"""
)
for deptFolder in self._list_depts():
H.append(
'<option value="%s">%s</option>' % (deptFolder.id, deptFolder.id)
)
H.append(
"""</select>
<input type="submit" value="Supprimer département">
</form>"""
)
H.append("""</body></html>""")
return "\n".join(H)
def _list_depts_ids(self):
"""Liste de id de departements definis par create_dept.sh
(fichiers depts/*.cfg)
"""
filenames = glob.glob(scu.SCODOC_VAR_DIR + "/config/depts/*.cfg")
ids = [os.path.split(os.path.splitext(f)[0])[1] for f in filenames]
return ids
security.declareProtected("View", "http_expiration_date")
def http_expiration_date(self):
"http expiration date for cachable elements (css, ...)"
d = datetime.timedelta(minutes=10)
return (datetime.datetime.utcnow() + d).strftime("%a, %d %b %Y %H:%M:%S GMT")
security.declareProtected("View", "get_etud_dept")
def get_etud_dept(self, REQUEST=None):
"""Returns the dept id (eg "GEII") of an etud (identified by etudid, INE or NIP in REQUEST).
Warning: This function is inefficient and its result should be cached.
"""
depts = self._list_depts()
depts_etud = [] # liste des depts où l'etud est defini
for dept in depts:
etuds = dept.Scolarite.getEtudInfo(REQUEST=REQUEST)
if etuds:
depts_etud.append((dept, etuds))
if not depts_etud:
return "" # not found
elif len(depts_etud) == 1:
return depts_etud[0][0].id
# inscriptions dans plusieurs departements: cherche la plus recente
last_dept = None
last_date = None
for (dept, etuds) in depts_etud:
sco_etud.fill_etuds_info(self, etuds)
etud = etuds[0]
if etud["sems"]:
if (not last_date) or (etud["sems"][0]["date_fin_iso"] > last_date):
last_date = etud["sems"][0]["date_fin_iso"]
last_dept = dept
if not last_dept:
# est present dans plusieurs semestres mais inscrit dans aucun
return depts_etud[0][0]
return last_dept.id
security.declareProtected("View", "table_etud_in_accessible_depts")
table_etud_in_accessible_depts = sco_find_etud.table_etud_in_accessible_depts
security.declareProtected("View", "search_inscr_etud_by_nip")
search_inscr_etud_by_nip = sco_find_etud.search_inscr_etud_by_nip
def manage_addZScoDoc(self, id="ScoDoc", title="Site ScoDoc", REQUEST=None):
"Add a ZScoDoc instance to a folder."
log("============== creating a new ScoDoc instance =============")
zscodoc = ZScoDoc(
id, title
) # ne cree (presque rien), tout se passe lors du 1er accès
self._setObject(id, zscodoc)
if REQUEST is not None:
REQUEST.RESPONSE.redirect("/ScoDoc/manage_workspace")
return id

View File

@ -27,7 +27,7 @@ for sem in sems:
print sem['formsemestre_id'], sem['titre_num']
# Recupere la table de notes:
nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_id)
nt = sco_core.get_notes_cache(context).get_NotesTable(context.Notes, formsemestre_id)
"""

View File

@ -54,9 +54,10 @@ from reportlab.lib import styles
from reportlab.lib.units import inch, cm, mm
from reportlab.rl_config import defaultPageSize # pylint: disable=no-name-in-module
import app.scodoc.sco_utils as scu
import app.scodoc.sco_excel
import app.scodoc.sco_pdf
from app.scodoc import html_sco_header
from app.scodoc import sco_utils as scu
from app.scodoc import sco_excel
from app.scodoc import sco_pdf
from app.scodoc.sco_pdf import SU
from app.scodoc.notes_log import log

View File

@ -100,7 +100,7 @@ def retreive_dept():
# Alarms by email:
def sendAlarm(context, subj, txt):
import sco_utils
import mails
import sco_emails
import sco_preferences
msg = MIMEMultipart()
@ -111,7 +111,7 @@ def sendAlarm(context, subj, txt):
msg.epilogue = ""
txt = MIMEText(txt, "plain", sco_utils.SCO_ENCODING)
msg.attach(txt)
mails.sendEmail(context, msg)
sco_emails.sendEmail(context, msg)
# Debug: log call stack

View File

@ -57,7 +57,8 @@ import pprint
from app.scodoc.gen_tables import GenTable, SeqGenTable
import app.scodoc.sco_utils as scu
from app.scodoc import sco_codes_parcours # sco_codes_parcours.NEXT -> sem suivant
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import pe_tagtable
from app.scodoc import pe_tools
from app.scodoc import pe_semestretag
@ -331,7 +332,7 @@ class JuryPE:
nt = self.get_cache_notes_d_un_semestre(
self.context, sem["formsemestre_id"]
)
# context.Notes._getNotesCache().get_NotesTable(context.Notes, sem['formsemestre_id'])
# sco_core.get_notes_cache(context).get_NotesTable(context.Notes, sem['formsemestre_id'])
etudiantsDuSemestre = (
nt.get_etudids()
) # nt.identdict.keys() # identification des etudiants du semestre
@ -1139,7 +1140,7 @@ class JuryPE:
self, context, formsemestre_id
): # inutile en realité !
"""Charge la table des notes d'un formsemestre"""
return context.Notes._getNotesCache().get_NotesTable(
return sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id
)

View File

@ -38,6 +38,7 @@ Created on Fri Sep 9 09:15:05 2016
from app.scodoc.notes_log import log
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_core
from app.scodoc import sco_tag_module
from app.scodoc import pe_tagtable
@ -269,8 +270,8 @@ class SemestreTag(pe_tagtable.TableTag):
# => le formsemestre_id du semestre dont vient la capitalisation
fid_prec = fids_prec[0]
# Lecture des notes de ce semestre
nt_prec = self.context.Notes._getNotesCache().get_NotesTable(
self.context.Notes, fid_prec
nt_prec = sco_core.get_notes_cache(self.context).get_NotesTable(
self.context, fid_prec
) # le tableau de note du semestre considéré
# Y-a-t-il un module équivalent c'est à dire correspondant au même code (le module_id n'étant pas significatif en cas de changement de PPN)

View File

@ -41,9 +41,10 @@ from app.scodoc import notesdb as ndb
from app.scodoc.scolog import logdb
from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError
from app.scodoc import sco_abs_notification
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_preferences
from app.scodoc import sco_etud
# --- Misc tools.... ------------------
@ -968,7 +969,7 @@ class CAbsSemEtud:
self.etudid = etudid
self._loaded = False
formsemestre_id = sem["formsemestre_id"]
context.Notes._getNotesCache().add_listener(
sco_core.get_notes_cache(context).add_listener(
self.invalidate, formsemestre_id, (etudid, formsemestre_id)
)
@ -992,11 +993,11 @@ class CAbsSemEtud:
debut_sem = ndb.DateDMYtoISO(self.sem["date_debut"])
fin_sem = ndb.DateDMYtoISO(self.sem["date_fin"])
self._CountAbs = self.sco_abs.CountAbs(
context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
self._CountAbs = CountAbs(
self.context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
)
self._CountAbsJust = self.sco_abs.CountAbsJust(
context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
self._CountAbsJust = CountAbsJust(
self.context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
)
self._loaded = True

View File

@ -37,7 +37,7 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from app.scodoc import mails
from app.scodoc import sco_emails
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log
@ -119,7 +119,7 @@ def abs_notify_send(
for email in destinations:
del msg["To"]
msg["To"] = email
mails.sendEmail(context, msg)
sco_emails.sendEmail(context, msg)
ndb.SimpleQuery(
context,
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""",

View File

@ -39,6 +39,7 @@ from app.scodoc.scolog import logdb
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_abs
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_find_etud
from app.scodoc import sco_formsemestre
@ -124,7 +125,7 @@ def doSignaleAbsence(
if moduleimpl_id and moduleimpl_id != "NULL":
mod = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
formsemestre_id = mod["formsemestre_id"]
nt = context.Notes._getNotesCache().get_NotesTable(
nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id
)
ues = nt.get_ues(etudid=etudid)
@ -185,7 +186,7 @@ def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
require_module = sco_preferences.get_preference(
context, "abs_require_module", formsemestre_id
)
nt = context.Notes._getNotesCache().get_NotesTable(
nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id
)
ues = nt.get_ues(etudid=etudid)

View File

@ -31,7 +31,7 @@
"""
import app.scodoc.sco_utils as scu
from app.scodoc import ImportScolars
from app.scodoc import sco_import_etuds
from app.scodoc import sco_groups
from app.scodoc import sco_trombino
from app.scodoc import sco_excel
@ -227,8 +227,8 @@ def etud_get_archived_file(context, REQUEST, etudid, archive_name, filename):
# --- Upload d'un ensemble de fichiers (pour un groupe d'étudiants)
def etudarchive_generate_excel_sample(context, group_id=None, REQUEST=None):
"""Feuille excel pour import fichiers etudiants (utilisé pour admissions)"""
fmt = ImportScolars.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample(
fmt = sco_import_etuds.sco_import_format()
data = sco_import_etuds.sco_import_generate_excel_sample(
fmt,
context=context,
group_ids=[group_id],

View File

@ -41,13 +41,14 @@ from email.header import Header
from reportlab.lib.colors import Color
from app.scodoc import mails
from app.scodoc import sco_emails
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_exceptions import AccessDenied
from app.scodoc import html_sco_header
from app.scodoc import sco_abs
from app.scodoc import sco_abs_views
from app.scodoc import sco_bulletins_generator
from app.scodoc import sco_bulletins_json
@ -1048,7 +1049,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
email.encoders.encode_base64(att)
msg.attach(att)
log("mail bulletin a %s" % msg["To"])
mails.sendEmail(context, msg)
sco_emails.sendEmail(context, msg)
def _formsemestre_bulletinetud_header_html(

View File

@ -47,6 +47,7 @@ from app.scodoc import sco_abs
from app.scodoc import sco_edit_module
from app.scodoc import sco_evaluations
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_formulas
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_etud
@ -211,8 +212,8 @@ def do_moduleimpl_moyennes(context, nt, mod):
inssem_set = set(
[
x["etudid"]
for x in context.do_formsemestre_inscription_listinscrits(
mod["formsemestre_id"]
for x in sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
context, mod["formsemestre_id"]
)
]
)

View File

@ -254,7 +254,7 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
)
#
if create:
formation_id = context.do_formation_create(tf[2], REQUEST)
formation_id = do_formation_create(context, tf[2], REQUEST)
else:
do_formation_edit(context, tf[2])
return REQUEST.RESPONSE.redirect("ue_list?formation_id=%s" % formation_id)

View File

@ -41,6 +41,7 @@ from email import Encoders # pylint: disable=no-name-in-module,import-error
import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log
from app.scodoc import VERSION
def sendEmail(context, msg): # TODO A REECRIRE ScoDoc8

View File

@ -389,7 +389,7 @@ apo_csv_store(context, csv_data, annee_scolaire, sem_id)
groups_infos = sco_groups_view.DisplayedGroupsInfos(context, [sco_groups.get_default_group(context, formsemestre_id)], formsemestre_id=formsemestre_id, REQUEST=REQUEST)
nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_id)
nt = sco_core.get_notes_cache(context).get_NotesTable(context.Notes, formsemestre_id)
#
s = SemSet(context, 'NSS29902')

View File

@ -37,7 +37,7 @@ from email.mime.text import MIMEText
from email.header import Header
from email.mime.base import MIMEBase
from app.scodoc import mails
from app.scodoc import sco_emails
import app.scodoc.sco_utils as scu
from app.scodoc.sco_utils import SCO_ENCODING
import app.scodoc.notesdb as ndb
@ -46,7 +46,6 @@ from app.scodoc.sco_exceptions import ScoGenError, ScoValueError
from app.scodoc.notes_log import log
from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc import safehtml
from app.scodoc import sco_formsemestre
from app.scodoc import sco_preferences
from app.scodoc.scolog import logdb
@ -450,7 +449,7 @@ def notify_etud_change(context, email_addr, etud, before, after, subject):
msg["To"] = email_addr
mime_txt = MIMEText(txt, "plain", SCO_ENCODING)
msg.attach(mime_txt)
mails.sendEmail(context, msg)
sco_emails.sendEmail(context, msg)
return txt
@ -901,6 +900,7 @@ def fill_etuds_info(etuds):
Pour chaque etudiant, ajoute ou formatte les champs
-> informations pour fiche etudiant ou listes diverses
"""
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
context = None # XXX en attendant la suppression du context ScoDoc7
@ -1004,6 +1004,8 @@ def fill_etuds_info(etuds):
def descr_situation_etud(context, etudid, ne=""):
"""chaine decrivant la situation actuelle de l'etudiant"""
from app.scodoc import sco_formsemestre
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(

View File

@ -45,6 +45,7 @@ from app.scodoc import sco_core
from app.scodoc import sco_edit_module
from app.scodoc import sco_edit_ue
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_news
@ -180,6 +181,146 @@ def do_evaluation_list_in_formsemestre(context, formsemestre_id):
return evals
def _check_evaluation_args(context, args):
"Check coefficient, dates and duration, raises exception if invalid"
moduleimpl_id = args["moduleimpl_id"]
# check bareme
note_max = args.get("note_max", None)
if note_max is None:
raise ScoValueError("missing note_max")
try:
note_max = float(note_max)
except ValueError:
raise ScoValueError("Invalid note_max value")
if note_max < 0:
raise ScoValueError("Invalid note_max value (must be positive or null)")
# check coefficient
coef = args.get("coefficient", None)
if coef is None:
raise ScoValueError("missing coefficient")
try:
coef = float(coef)
except ValueError:
raise ScoValueError("Invalid coefficient value")
if coef < 0:
raise ScoValueError("Invalid coefficient value (must be positive or null)")
# check date
jour = args.get("jour", None)
args["jour"] = jour
if jour:
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
date_debut = datetime.date(y, m, d)
d, m, y = [int(x) for x in sem["date_fin"].split("/")]
date_fin = datetime.date(y, m, d)
# passe par ndb.DateDMYtoISO pour avoir date pivot
y, m, d = [int(x) for x in ndb.DateDMYtoISO(jour).split("-")]
jour = datetime.date(y, m, d)
if (jour > date_fin) or (jour < date_debut):
raise ScoValueError(
"La date de l'évaluation (%s/%s/%s) n'est pas dans le semestre !"
% (d, m, y)
)
heure_debut = args.get("heure_debut", None)
args["heure_debut"] = heure_debut
heure_fin = args.get("heure_fin", None)
args["heure_fin"] = heure_fin
if jour and ((not heure_debut) or (not heure_fin)):
raise ScoValueError("Les heures doivent être précisées")
d = ndb.TimeDuration(heure_debut, heure_fin)
if d and ((d < 0) or (d > 60 * 12)):
raise ScoValueError("Heures de l'évaluation incohérentes !")
def do_evaluation_create(
context,
moduleimpl_id=None,
jour=None,
heure_debut=None,
heure_fin=None,
description=None,
note_max=None,
coefficient=None,
visibulletin=None,
publish_incomplete=None,
evaluation_type=None,
numero=None,
REQUEST=None,
):
"""Create an evaluation"""
if not sco_permissions_check.can_edit_evaluation(
context, REQUEST, moduleimpl_id=moduleimpl_id
):
raise AccessDenied(
"Modification évaluation impossible pour %s"
% scu.get_current_user_name(REQUEST)
)
args = locals()
log("do_evaluation_create: args=" + str(args))
_check_evaluation_args(context, args)
# Check numeros
module_evaluation_renumber(
context, moduleimpl_id, REQUEST=REQUEST, only_if_unumbered=True
)
if not "numero" in args or args["numero"] is None:
n = None
# determine le numero avec la date
# Liste des eval existantes triees par date, la plus ancienne en tete
ModEvals = do_evaluation_list(
context,
args={"moduleimpl_id": moduleimpl_id},
sortkey="jour asc, heure_debut asc",
)
if args["jour"]:
next_eval = None
t = (
ndb.DateDMYtoISO(args["jour"]),
ndb.TimetoISO8601(args["heure_debut"]),
)
for e in ModEvals:
if (
ndb.DateDMYtoISO(e["jour"]),
ndb.TimetoISO8601(e["heure_debut"]),
) > t:
next_eval = e
break
if next_eval:
n = module_evaluation_insert_before(
context, ModEvals, next_eval, REQUEST
)
else:
n = None # a placer en fin
if n is None: # pas de date ou en fin:
if ModEvals:
log(pprint.pformat(ModEvals[-1]))
n = ModEvals[-1]["numero"] + 1
else:
n = 0 # the only one
# log("creating with numero n=%d" % n)
args["numero"] = n
#
cnx = ndb.GetDBConnexion()
r = _evaluationEditor.create(cnx, args)
# news
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
mod = sco_edit_module.do_module_list(context, args={"module_id": M["module_id"]})[0]
mod["moduleimpl_id"] = M["moduleimpl_id"]
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
sco_news.add(
context,
REQUEST,
typ=sco_news.NEWS_NOTE,
object=moduleimpl_id,
text='Création d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
url=mod["url"],
)
return r
def do_evaluation_edit(context, REQUEST, args):
"edit an evaluation"
evaluation_id = args["evaluation_id"]
@ -187,9 +328,16 @@ def do_evaluation_edit(context, REQUEST, args):
if not the_evals:
raise ValueError("evaluation inexistante !")
moduleimpl_id = the_evals[0]["moduleimpl_id"]
if not sco_permissions_check.can_edit_evaluation(
context, REQUEST, moduleimpl_id=moduleimpl_id
):
raise AccessDenied(
"Modification évaluation impossible pour %s"
% scu.get_current_user_name(REQUEST)
)
args["moduleimpl_id"] = moduleimpl_id
context._check_evaluation_args(args)
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
_check_evaluation_args(context, args)
cnx = ndb.GetDBConnexion()
context._evaluationEditor.edit(cnx, args)
# inval cache pour ce semestre
@ -204,7 +352,14 @@ def do_evaluation_delete(context, REQUEST, evaluation_id):
the_evals = do_evaluation_list(context, {"evaluation_id": evaluation_id})
if not the_evals:
raise ValueError("evaluation inexistante !")
moduleimpl_id = the_evals[0]["moduleimpl_id"]
if not sco_permissions_check.can_edit_evaluation(
context, REQUEST, moduleimpl_id=moduleimpl_id
):
raise AccessDenied(
"Modification évaluation impossible pour %s"
% scu.get_current_user_name(REQUEST)
)
NotesDB = do_evaluation_get_all_notes(context, evaluation_id) # { etudid : value }
notes = [x["value"] for x in NotesDB.values()]
if notes:
@ -212,8 +367,6 @@ def do_evaluation_delete(context, REQUEST, evaluation_id):
"Impossible de supprimer cette évaluation: il reste des notes"
)
moduleimpl_id = the_evals[0]["moduleimpl_id"]
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
cnx = ndb.GetDBConnexion()
context._evaluationEditor.delete(cnx, evaluation_id)
@ -295,7 +448,9 @@ def do_evaluation_etat(
# Il faut considerer les inscriptions au semestre
# (pour avoir l'etat et le groupe) et aussi les inscriptions
# au module (pour gerer les modules optionnels correctement)
insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
context, formsemestre_id
)
insmod = sco_moduleimpl.do_moduleimpl_inscription_list(
context, moduleimpl_id=E["moduleimpl_id"]
)
@ -676,7 +831,7 @@ def evaluation_date_first_completion(context, evaluation_id):
# E = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
# M = sco_moduleimpl.do_moduleimpl_list(context,moduleimpl_id=E["moduleimpl_id"])[0]
# formsemestre_id = M["formsemestre_id"]
# insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
# insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(context, formsemestre_id)
# insmod = sco_moduleimpl.do_moduleimpl_inscription_list(context,moduleimpl_id=E["moduleimpl_id"])
# insmodset = set([x["etudid"] for x in insmod])
# retire de insem ceux qui ne sont pas inscrits au module
@ -814,9 +969,14 @@ def module_evaluation_move(context, evaluation_id, after=0, REQUEST=None, redire
"""
e = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
redirect = int(redirect)
# access: can change eval ? (raises exception)
context._evaluation_check_write_access(REQUEST, moduleimpl_id=e["moduleimpl_id"])
# access: can change eval ?
if not sco_permissions_check.can_edit_evaluation(
context, REQUEST, moduleimpl_id=e["moduleimpl_id"]
):
raise AccessDenied(
"Modification évaluation impossible pour %s"
% scu.get_current_user_name(REQUEST)
)
module_evaluation_renumber(
context, e["moduleimpl_id"], REQUEST=REQUEST, only_if_unumbered=True
@ -977,13 +1137,14 @@ def evaluation_create_form(
formsemestre_id = M["formsemestre_id"]
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
if not readonly:
try:
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
except AccessDenied as e:
if not sco_permissions_check.can_edit_evaluation(
context, REQUEST, moduleimpl_id=moduleimpl_id
):
return (
html_sco_header.sco_header(context, REQUEST)
+ "<h2>Opération non autorisée</h2><p>"
+ str(e)
+ "Modification évaluation impossible pour %s"
% scu.get_current_user_name(REQUEST)
+ "</p>"
+ '<p><a href="%s">Revenir</a></p>' % (str(REQUEST.HTTP_REFERER),)
+ html_sco_header.sco_footer(context, REQUEST)
@ -1227,7 +1388,7 @@ def evaluation_create_form(
tf[2]["visibulletin"] = 0
if not edit:
# creation d'une evaluation
evaluation_id = context.do_evaluation_create(REQUEST=REQUEST, **tf[2])
evaluation_id = do_evaluation_create(context, REQUEST=REQUEST, **tf[2])
return REQUEST.RESPONSE.redirect(dest_url)
else:
do_evaluation_edit(context, REQUEST, tf[2])

View File

@ -38,6 +38,7 @@ from app.scodoc import notesdb
from app.scodoc.notes_log import log
from app.scodoc.scolog import logdb
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_preferences
# colors, voir exemple format.py

View File

@ -28,6 +28,7 @@
"""Recherche d'étudiants
"""
from scodoc_manager import sco_mgr
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable
@ -266,12 +267,6 @@ def form_search_etud_in_accessible_depts(context, REQUEST):
"""
def can_view_dept(context, REQUEST):
"""True if auth user can access (View) this context"""
authuser = REQUEST.AUTHENTICATED_USER
return authuser.has_permission(Permission.ScoView)
def search_etud_in_accessible_depts(context, expnom=None, code_nip=None, REQUEST=None):
"""
context est le ZScoDoc
@ -279,10 +274,10 @@ def search_etud_in_accessible_depts(context, expnom=None, code_nip=None, REQUEST
"""
result = []
accessible_depts = []
deptList = context._list_depts() # definis dans Zope
for dept in deptList:
dept_list = sco_mgr.get_dept_ids()
for dept in dept_list:
# log('%s searching %s' % (str(REQUEST.AUTHENTICATED_USER),dept))
if can_view_dept(dept, REQUEST):
if REQUEST.AUTHENTICATED_USER.has_permission(Permission.ScoView, dept=dept):
if expnom or code_nip:
accessible_depts.append(dept.Scolarite.DeptId())
etuds = search_etuds_infos(

View File

@ -35,16 +35,17 @@ import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_formsemestre
from app.scodoc import sco_tag_module
from app.scodoc import sco_preferences
from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_permissions import Permission
from app.scodoc import VERSION
from app.scodoc import sco_edit_matiere
from app.scodoc import sco_edit_module
from app.scodoc import sco_edit_ue
from app.scodoc import sco_formsemestre
from app.scodoc import sco_news
from app.scodoc import sco_preferences
from app.scodoc import sco_tag_module
from app.scodoc import VERSION
from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_permissions import Permission
_formationEditor = ndb.EditableTable(
"notes_formations",
@ -164,6 +165,8 @@ def formation_import_xml(
"""Create a formation from XML representation
(format dumped by formation_export( format='xml' ))
"""
from app.scodoc import sco_edit_formation
log("formation_import_xml: doc=%s" % doc)
try:
dom = xml.dom.minidom.parseString(doc)
@ -199,7 +202,7 @@ def formation_import_xml(
# create formation
# F_unquoted = F.copy()
# unescape_html_dict(F_unquoted)
formation_id = context.do_formation_create(F, REQUEST)
formation_id = sco_edit_formation.do_formation_create(context, F, REQUEST)
log("formation %s created" % formation_id)
ues_old2new = {} # xml ue_id : new ue_id
modules_old2new = {} # xml module_id : new module_id
@ -362,3 +365,24 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
context,
),
)
def formation_create_new_version(context, formation_id, redirect=True, REQUEST=None):
"duplicate formation, with new version number"
xml = formation_export(context, formation_id, export_ids=True, format="xml")
new_id, modules_old2new, ues_old2new = formation_import_xml(context, REQUEST, xml)
# news
F = formation_list(context, args={"formation_id": new_id})[0]
sco_news.add(
context,
REQUEST,
typ=sco_news.NEWS_FORM,
object=new_id,
text="Nouvelle version de la formation %(acronyme)s" % F,
)
if redirect:
return REQUEST.RESPONSE.redirect(
"ue_list?formation_id=" + new_id + "&msg=Nouvelle version !"
)
else:
return new_id, modules_old2new, ues_old2new

View File

@ -29,16 +29,16 @@
"""
import time
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log
from app.scodoc.gen_tables import GenTable
from scodoc_manager import sco_mgr
from app.scodoc import sco_codes_parcours
from app.scodoc.sco_codes_parcours import NO_SEMESTRE_ID
from app.scodoc import sco_core
from app.scodoc import sco_preferences
from app.scodoc.gen_tables import GenTable
from app.scodoc.notes_log import log
from app.scodoc.sco_codes_parcours import NO_SEMESTRE_ID
from app.scodoc.sco_exceptions import ScoValueError
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
_formsemestreEditor = ndb.EditableTable(
"notes_formsemestre",
@ -219,6 +219,41 @@ def etapes_apo_str(etapes):
return ", ".join([str(x) for x in etapes])
def do_formsemestre_create(context, args, REQUEST, silent=False):
"create a formsemestre"
cnx = ndb.GetDBConnexion()
formsemestre_id = _formsemestreEditor.create(cnx, args)
if args["etapes"]:
args["formsemestre_id"] = formsemestre_id
write_formsemestre_etapes(context, args)
if args["responsables"]:
args["formsemestre_id"] = formsemestre_id
write_formsemestre_responsables(context, args)
# create default partition
partition_id = sco_groups.partition_create(
context, formsemestre_id, default=True, redirect=0, REQUEST=REQUEST
)
_group_id = sco_groups.createGroup(
context, partition_id, default=True, REQUEST=REQUEST
)
# news
if not args.has_key("titre"):
args["titre"] = "sans titre"
args["formsemestre_id"] = formsemestre_id
args["url"] = "Notes/formsemestre_status?formsemestre_id=%(formsemestre_id)s" % args
if not silent:
sco_news.add(
context,
REQUEST,
typ=sco_news.NEWS_SEM,
text='Création du semestre <a href="%(url)s">%(titre)s</a>' % args,
url=args["url"],
)
return formsemestre_id
def do_formsemestre_edit(context, sem, cnx=None, **kw):
"""Apply modifications to formsemestre.
Update etapes and resps. Invalidate cache."""
@ -500,7 +535,7 @@ def sem_est_courant(context, sem):
def scodoc_get_all_unlocked_sems(context):
"""Liste de tous les semestres non verrouillés de tous les départements"""
depts = context._list_depts()
depts = sco_mgr.get_dept_ids()
semdepts = []
for dept in depts:
semdepts += [

View File

@ -715,7 +715,9 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
)
if not edit:
# creation du semestre
formsemestre_id = context.do_formsemestre_create(tf[2], REQUEST)
formsemestre_id = sco_formsemestre.do_formsemestre_create(
context, tf[2], REQUEST
)
# creation des modules
for module_id in tf[2]["tf-checked"]:
modargs = {
@ -1014,7 +1016,7 @@ def do_formsemestre_clone(
args["date_debut"] = date_debut
args["date_fin"] = date_fin
args["etat"] = 1 # non verrouillé
formsemestre_id = context.do_formsemestre_create(args, REQUEST)
formsemestre_id = sco_formsemestre.do_formsemestre_create(context, args, REQUEST)
log("created formsemestre %s" % formsemestre_id)
# 2- create moduleimpls
mods_orig = sco_moduleimpl.do_moduleimpl_list(
@ -1041,7 +1043,7 @@ def do_formsemestre_clone(
args = e.copy()
del args["jour"] # erase date
args["moduleimpl_id"] = mid
_ = context.do_evaluation_create(REQUEST=REQUEST, **args)
_ = sco_evaluations.do_evaluation_create(context, REQUEST=REQUEST, **args)
# 3- copy uecoefs
objs = sco_formsemestre.formsemestre_uecoef_list(
@ -1196,14 +1198,18 @@ def do_formsemestres_associate_new_version(context, formsemestre_ids, REQUEST=No
cnx = ndb.GetDBConnexion()
# New formation:
formation_id, modules_old2new, ues_old2new = context.formation_create_new_version(
formation_id, redirect=False, REQUEST=REQUEST
(
formation_id,
modules_old2new,
ues_old2new,
) = sco_formations.formation_create_new_version(
context, formation_id, redirect=False, REQUEST=REQUEST
)
for formsemestre_id in formsemestre_ids:
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
sem["formation_id"] = formation_id
context.do_formsemestre_edit(sem, cnx=cnx, html_quote=False)
sco_formsemestre.do_formsemestre_edit(context, sem, cnx=cnx, html_quote=False)
_reassociate_moduleimpls(
context, cnx, formsemestre_id, ues_old2new, modules_old2new
)
@ -1339,7 +1345,7 @@ def do_formsemestre_delete(context, formsemestre_id, REQUEST):
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
# --- Destruction des modules de ce semestre
mods = context.do_moduleimpl_list(formsemestre_id=formsemestre_id)
mods = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
for mod in mods:
# evaluations
evals = sco_evaluations.do_evaluation_list(
@ -1474,7 +1480,7 @@ def formsemestre_change_lock(
if etat not in (0, 1):
raise ScoValueError("formsemestre_lock: invalid value for etat (%s)" % etat)
args = {"formsemestre_id": formsemestre_id, "etat": etat}
context.do_formsemestre_edit(args)
sco_formsemestre.do_formsemestre_edit(context, args)
if REQUEST:
return REQUEST.RESPONSE.redirect(
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
@ -1517,7 +1523,7 @@ def formsemestre_change_publication_bul(
"formsemestre_change_publication_bul: invalid value for etat (%s)" % etat
)
args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat}
context.do_formsemestre_edit(args)
sco_formsemestre.do_formsemestre_edit(context, args)
if REQUEST:
return REQUEST.RESPONSE.redirect(
"formsemestre_status?formsemestre_id=%s" % formsemestre_id

View File

@ -63,7 +63,9 @@ def formsemestre_ext_create(context, etudid, sem_params, REQUEST=None):
sem_params["modalite"] = "EXT"
sem_params["etapes"] = None
sem_params["responsables"] = [str(REQUEST.AUTHENTICATED_USER)]
formsemestre_id = context.do_formsemestre_create(sem_params, REQUEST, silent=True)
formsemestre_id = sco_formsemestre.do_formsemestre_create(
context, sem_params, REQUEST, silent=True
)
# nota: le semestre est créé vide: pas de modules
# Inscription au semestre

View File

@ -43,7 +43,6 @@ from app.scodoc import sco_moduleimpl
from app.scodoc import sco_groups
from app.scodoc import sco_etud
from app.scodoc import sco_core
from app.scodoc import sco_formsemestre_edit
from app.scodoc import html_sco_header
@ -62,6 +61,19 @@ def do_formsemestre_inscription_list(context, *args, **kw):
return _formsemestre_inscriptionEditor.list(cnx, *args, **kw)
def do_formsemestre_inscription_listinscrits(context, formsemestre_id):
"""Liste les inscrits (état I) à ce semestre et cache le résultat"""
cache = sco_core.get_formsemestre_inscription_cache(context)
r = cache.get(formsemestre_id)
if r is None:
# retreive list
r = do_formsemestre_inscription_list(
context, args={"formsemestre_id": formsemestre_id, "etat": "I"}
)
cache.set(formsemestre_id, r)
return r
def do_formsemestre_inscription_create(context, args, REQUEST, method=None):
"create a formsemestre_inscription (and sco event)"
cnx = ndb.GetDBConnexion()
@ -126,6 +138,8 @@ def do_formsemestre_desinscription(context, etudid, formsemestre_id, REQUEST=Non
"""Désinscription d'un étudiant.
Si semestre extérieur et dernier inscrit, suppression de ce semestre.
"""
from app.scodoc import sco_formsemestre_edit
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
# -- check lock
if sem["etat"] != "1":

View File

@ -346,7 +346,9 @@ def formsemestre_status_menubar(context, sem, REQUEST):
"title": "Créer/modifier les partitions...",
"endpoint": "scolar.editPartitionForm",
"args": {"formsemestre_id": formsemestre_id},
"enabled": sco_groups.can_change_groups(context, REQUEST, formsemestre_id),
"enabled": sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
),
},
]
# 1 item / partition:
@ -355,7 +357,10 @@ def formsemestre_status_menubar(context, sem, REQUEST):
)
submenu = []
enabled = (
sco_groups.can_change_groups(context, REQUEST, formsemestre_id) and partitions
sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
)
and partitions
)
for partition in partitions:
submenu.append(
@ -873,13 +878,17 @@ def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
H.append("</table>")
else:
H.append('<p class="help indent">Aucun groupe dans cette partition')
if sco_groups.can_change_groups(context, REQUEST, formsemestre_id):
if sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
H.append(
' (<a href="affectGroups?partition_id=%s" class="stdlink">créer</a>)'
% partition["partition_id"]
)
H.append("</p>")
if sco_groups.can_change_groups(context, REQUEST, formsemestre_id):
if sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
H.append(
'<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>'
% formsemestre_id

View File

@ -51,26 +51,12 @@ from app.scodoc import html_sco_header
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_permissions_check
from app.scodoc.sco_exceptions import ScoException, AccessDenied, ScoValueError
from app.scodoc.sco_permissions import Permission
from app.scodoc.TrivialFormulator import TrivialFormulator
def can_change_groups(context, REQUEST, formsemestre_id):
"Vrai si l'utilisateur peut changer les groupes dans ce semestre"
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if sem["etat"] != "1":
return False # semestre verrouillé
authuser = REQUEST.AUTHENTICATED_USER
if authuser.has_permission(Permission.ScoEtudChangeGroups):
return True # admin, chef dept
uid = str(authuser)
if uid in sem["responsables"]:
return True
return False
def checkGroupName(
groupName,
): # XXX unused: now allow any string as a group or partition name
@ -275,6 +261,8 @@ def get_group_members(context, group_id, etat=None):
def get_group_infos(context, group_id, etat=None): # was _getlisteetud
"""legacy code: used by group_list and trombino"""
from app.scodoc import sco_formsemestre
cnx = ndb.GetDBConnexion()
group = get_group(context, group_id)
sem = sco_formsemestre.get_formsemestre(context, group["formsemestre_id"])
@ -446,12 +434,14 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
<etud etuid="" sexe="" nom="" prenom="" origin=""/>
</groupe>
"""
from app.scodoc import sco_formsemestre
t0 = time.time()
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
groups = get_partition_groups(context, partition)
nt = context.Notes._getNotesCache().get_NotesTable(
nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id
) # > inscrdict
etuds_set = set(nt.inscrdict)
@ -621,9 +611,11 @@ def setGroups(
groupsToCreate: lignes "group_name;etudid;...\n"
groupsToDelete: group_id;group_id;...
"""
from app.scodoc import sco_formsemestre
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log("***setGroups: partition_id=%s" % partition_id)
log("groupsLists=%s" % groupsLists)
@ -710,7 +702,9 @@ def createGroup(context, partition_id, group_name="", default=False, REQUEST=Non
"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if REQUEST and not can_change_groups(context, REQUEST, formsemestre_id):
if REQUEST and not sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
#
if group_name:
@ -747,7 +741,9 @@ def suppressGroup(context, group_id, partition_id=None, REQUEST=None):
else:
partition_id = group["partition_id"]
partition = get_partition(context, partition_id)
if not can_change_groups(context, REQUEST, partition["formsemestre_id"]):
if not sco_permissions_check.can_change_groups(
context, REQUEST, partition["formsemestre_id"]
):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log(
"suppressGroup: group_id=%s group_name=%s partition_name=%s"
@ -766,7 +762,9 @@ def partition_create(
redirect=1,
):
"""Create a new partition"""
if REQUEST and not can_change_groups(context, REQUEST, formsemestre_id):
if REQUEST and not sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if partition_name:
partition_name = partition_name.strip()
@ -810,7 +808,7 @@ def getArrowIconsTags(context, REQUEST):
def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
"""Form to create/suppress partitions"""
# ad-hoc form
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
partitions = get_partitions_list(context, formsemestre_id)
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST)
@ -940,7 +938,7 @@ def partition_set_attr(context, partition_id, attr, value, REQUEST=None):
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log("partition_set_attr(%s, %s, %s)" % (partition_id, attr, value))
@ -963,7 +961,7 @@ def partition_delete(
default partition cannot be suppressed (unless force)"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if not partition["partition_name"] and not force:
@ -1007,7 +1005,7 @@ def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1):
"""Move before/after previous one (decrement/increment numero)"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
#
redirect = int(redirect)
@ -1042,7 +1040,7 @@ def partition_rename(context, partition_id, REQUEST=None):
"""Form to rename a partition"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
H = ["<h2>Renommer une partition</h2>"]
tf = TrivialFormulator(
@ -1103,7 +1101,7 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
"Partition %s déjà existante dans ce semestre !" % partition_name
)
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
redirect = int(redirect)
cnx = ndb.GetDBConnexion()
@ -1128,7 +1126,7 @@ def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1):
if group["group_name"] is None:
raise ValueError("can't set a name to default group")
formsemestre_id = group["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
redirect = int(redirect)
cnx = ndb.GetDBConnexion()
@ -1145,7 +1143,7 @@ def group_rename(context, group_id, REQUEST=None):
"""Form to rename a group"""
group = get_group(context, group_id)
formsemestre_id = group["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
tf = TrivialFormulator(
@ -1193,7 +1191,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
formsemestre_id = partition["formsemestre_id"]
# renvoie sur page édition groupes
dest_url = "affectGroups?partition_id=%s" % partition_id
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
@ -1261,7 +1259,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
createGroup(context, partition_id, group_name, REQUEST=REQUEST)
)
#
nt = context.Notes._getNotesCache().get_NotesTable(
nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id
) # > identdict
identdict = nt.identdict

View File

@ -40,7 +40,9 @@ def affectGroups(context, partition_id, REQUEST=None):
# Ported from DTML and adapted to new group management (nov 2009)
partition = sco_groups.get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not sco_groups.can_change_groups(context, REQUEST, formsemestre_id):
if not sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
H = [

View File

@ -53,6 +53,7 @@ from app.scodoc.sco_exceptions import (
ScoGenError,
)
from app.scodoc import html_sco_header
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups

View File

@ -31,7 +31,7 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from app.scodoc import mails
from app.scodoc import sco_emails
import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoException
@ -228,4 +228,4 @@ Pour plus d'informations sur ce logiciel, voir %s
msg.epilogue = ""
txt = MIMEText(txt, "plain", scu.SCO_ENCODING)
msg.attach(txt)
mails.sendEmail(context, msg)
sco_emails.sendEmail(context, msg)

View File

@ -107,8 +107,8 @@ def list_inscrits(context, formsemestre_id, with_dems=False):
{ etudid : etud }
"""
if not with_dems:
ins = context.Notes.do_formsemestre_inscription_listinscrits(
formsemestre_id
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
context, formsemestre_id
) # optimized
else:
args = {"formsemestre_id": formsemestre_id}
@ -215,8 +215,8 @@ def do_inscrit(context, sem, etudids, REQUEST=None, inscrit_groupes=False):
def do_desinscrit(context, sem, etudids, REQUEST):
log("do_desinscrit: %s" % etudids)
for etudid in etudids:
context.do_formsemestre_desinscription(
etudid, sem["formsemestre_id"], REQUEST=REQUEST
sco_formsemestre_inscriptions.do_formsemestre_desinscription(
context, etudid, sem["formsemestre_id"], REQUEST=REQUEST
)

View File

@ -91,7 +91,9 @@ def moduleimpl_inscriptions_edit(
% (moduleimpl_id, mod["titre"], mod["code"]),
]
# Liste des inscrits à ce semestre
inscrits = context.Notes.do_formsemestre_inscription_listinscrits(formsemestre_id)
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
context, formsemestre_id
)
for ins in inscrits:
etuds_info = sco_etud.get_etud_info(etudid=ins["etudid"], filled=1)
if not etuds_info:

View File

@ -40,7 +40,7 @@ import PyRSS2Gen # pylint: disable=import-error
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log
from app.scodoc import mails
from app.scodoc import sco_emails
from app.scodoc.sco_utils import SCO_ENCODING, SCO_ANNONCES_WEBSITE
from app.scodoc import sco_formsemestre
from app.scodoc import sco_moduleimpl
@ -301,4 +301,4 @@ def _send_news_by_mail(context, n):
del msg["To"]
msg["To"] = email_addr
# log('xxx mail: %s' % msg)
mails.sendEmail(context, msg)
sco_emails.sendEmail(context, msg)

View File

@ -70,18 +70,18 @@ def _menuScolarite(context, authuser, sem, etudid):
if ins["etat"] != "D":
dem_title = "Démission"
dem_url = "formDem"
dem_url = "scolar.formDem"
else:
dem_title = "Annuler la démission"
dem_url = "doCancelDem"
dem_url = "scolar.doCancelDem"
# Note: seul un etudiant inscrit (I) peut devenir défaillant.
if ins["etat"] != sco_codes_parcours.DEF:
def_title = "Déclarer défaillance"
def_url = "formDef"
def_url = "scolar.formDef"
elif ins["etat"] == sco_codes_parcours.DEF:
def_title = "Annuler la défaillance"
def_url = "doCancelDef"
def_url = "scolar.doCancelDef"
def_enabled = (
(ins["etat"] != "D")
and authuser.has_permission(Permission.ScoEtudInscrit)

View File

@ -9,9 +9,7 @@ from app.scodoc.sco_permissions import Permission
from app.scodoc import html_sco_header
from app.scodoc import sco_etud
from app.scodoc import sco_exceptions
from app.scodoc import sco_formsemestre
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_parcours_dut
def can_edit_notes(context, authuser, moduleimpl_id, allow_ens=True):
@ -21,6 +19,9 @@ def can_edit_notes(context, authuser, moduleimpl_id, allow_ens=True):
Si des décisions de jury ont déjà été saisies dans ce semestre,
seul le directeur des études peut saisir des notes (et il ne devrait pas).
"""
from app.scodoc import sco_formsemestre
from app.scodoc import sco_parcours_dut
uid = str(authuser)
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
@ -49,6 +50,39 @@ def can_edit_notes(context, authuser, moduleimpl_id, allow_ens=True):
return True
def can_edit_evaluation(context, REQUEST, moduleimpl_id=None):
"""Vérifie que l'on a le droit de modifier, créer ou détruire une
évaluation dans ce module.
Sinon, lance une exception.
(nb: n'implique pas le droit de saisir ou modifier des notes)
"""
# was _evaluation_check_write_access
# AccessDenied("Modification évaluation impossible pour %s" % (uid,))
from app.scodoc import sco_formsemestre
from app.scodoc import sco_moduleimpl
# acces pour resp. moduleimpl et resp. form semestre (dir etud)
if moduleimpl_id is None:
raise ValueError("no moduleimpl specified") # bug
authuser = REQUEST.AUTHENTICATED_USER
uid = str(authuser)
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
if (
authuser.has_permission(Permission.ScoEditAllEvals)
or uid == M["responsable_id"]
or uid in sem["responsables"]
):
return True
elif sem["ens_can_edit_eval"]:
for ens in M["ens"]:
if ens["ens_id"] == uid:
return True
return False
def can_suppress_annotation(context, annotation_id, REQUEST):
"""True if current user can suppress this annotation
Seuls l'auteur de l'annotation et le chef de dept peuvent supprimer
@ -60,13 +94,9 @@ def can_suppress_annotation(context, annotation_id, REQUEST):
raise sco_exceptions.ScoValueError("annotation inexistante !")
anno = annos[0]
authuser = REQUEST.AUTHENTICATED_USER
# note: les anciennes installations n'ont pas le role ScoEtudSupprAnnotations
# c'est pourquoi on teste aussi ScoEtudInscrit (normalement détenue par le chef)
return (
(str(authuser) == anno["zope_authenticated_user"])
or authuser.has_permission(Permission.ScoEtudSupprAnnotations)
or authuser.has_permission(Permission.ScoEtudInscrit)
)
str(authuser) == anno["zope_authenticated_user"]
) or authuser.has_permission(Permission.ScoEtudAddAnnotations)
def can_edit_suivi(context, REQUEST=None):
@ -77,6 +107,8 @@ def can_edit_suivi(context, REQUEST=None):
def can_validate_sem(context, REQUEST, formsemestre_id):
"Vrai si utilisateur peut saisir decision de jury dans ce semestre"
from app.scodoc import sco_formsemestre
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if sem["etat"] != "1":
return False # semestre verrouillé
@ -86,6 +118,7 @@ def can_validate_sem(context, REQUEST, formsemestre_id):
def can_edit_pv(context, REQUEST, formsemestre_id):
"Vrai si utilisateur peut editer un PV de jury de ce semestre"
from app.scodoc import sco_formsemestre
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if is_chef_or_diretud(context, REQUEST, sem):
@ -114,6 +147,8 @@ def check_access_diretud(
"""Check if access granted: responsable or ScoImplement
Return True|False, HTML_error_page
"""
from app.scodoc import sco_formsemestre
authuser = REQUEST.AUTHENTICATED_USER
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
header = html_sco_header.sco_header(
@ -137,3 +172,19 @@ def check_access_diretud(
)
else:
return True, ""
def can_change_groups(context, REQUEST, formsemestre_id):
"Vrai si l'utilisateur peut changer les groupes dans ce semestre"
from app.scodoc import sco_formsemestre
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if sem["etat"] != "1":
return False # semestre verrouillé
authuser = REQUEST.AUTHENTICATED_USER
if authuser.has_permission(Permission.ScoEtudChangeGroups):
return True # admin, chef dept
uid = str(authuser)
if uid in sem["responsables"]:
return True
return False

View File

@ -46,6 +46,7 @@ from app.scodoc.sco_permissions import Permission
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
from app.scodoc import html_sco_header
from app.scodoc import htmlutils
from app.scodoc import sco_abs
from app.scodoc import sco_core
from app.scodoc import sco_edit_module
from app.scodoc import sco_evaluations

View File

@ -50,7 +50,7 @@ from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_pdf import SU
from app.scodoc import html_sco_header
from app.scodoc import htmlutils
from app.scodoc import ImportScolars
from app.scodoc import sco_import_etuds
from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups
@ -470,8 +470,8 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
# --------------------- Upload des photos de tout un groupe
def photos_generate_excel_sample(context, group_ids=[], REQUEST=None):
"""Feuille excel pour import fichiers photos"""
fmt = ImportScolars.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample(
fmt = sco_import_etuds.sco_import_format()
data = sco_import_etuds.sco_import_generate_excel_sample(
fmt,
context=context,
group_ids=group_ids,

View File

@ -164,7 +164,7 @@ def external_ue_inscrit_et_note(
evaluation_id = ModEvals[0]["evaluation_id"]
else:
# crée une évaluation:
evaluation_id = context.do_evaluation_create(
evaluation_id = sco_evaluations.do_evaluation_create(context,
REQUEST=REQUEST,
moduleimpl_id=moduleimpl_id,
note_max=20.0,

View File

@ -385,6 +385,15 @@ def UsersURL():
return "NotImplemented"
def get_current_user_name(REQUEST):
"""return a displayable string identifying the current user.
XXX For now, the login, but will be the name. #sco8
"""
authuser = REQUEST.AUTHENTICATED_USER
uid = str(authuser)
return uid
# ---- Simple python utilities

View File

@ -81,8 +81,10 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_abs
from app.scodoc import sco_abs_notification, sco_abs_views
from app.scodoc import sco_abs_notification
from app.scodoc import sco_abs_views
from app.scodoc import sco_compute_moy
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre
@ -248,7 +250,9 @@ def SignaleAbsenceGrHebdo(
else:
# Si aucun etudiant n'est inscrit au module choisi...
moduleimpl_id = None
nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_id)
nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id
)
sem = sco_formsemestre.do_formsemestre_list(
context, {"formsemestre_id": formsemestre_id}
)[0]
@ -421,7 +425,7 @@ def SignaleAbsenceGrSemestre(
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
if etuds:
nt = context.Notes._getNotesCache().get_NotesTable(
nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id
)
sem = sco_formsemestre.do_formsemestre_list(
@ -638,7 +642,7 @@ def _gen_form_saisie_groupe(
# UE capitalisee dans semestre courant ?
cap = []
if etud["cursem"]:
nt = context.Notes._getNotesCache().get_NotesTable(
nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, etud["cursem"]["formsemestre_id"]
) # > get_ues, get_etud_ue_status
for ue in nt.get_ues():

View File

@ -41,7 +41,7 @@ def sco_exemple(etudid="NON"):
}
# En ScoDoc 7, on a souvent des vues qui en appellent d'autres
# En ScoDoc 7, on avait des vues qui en appellaient d'autres
# avec context.sco_exemple( etudid="E12" )
@bp.route("/<scodoc_dept>/Scolarite/sco_exemple2")
@login_required

View File

@ -486,33 +486,11 @@ def formation_import_xml_form(context, REQUEST):
)
@bp.route("/formation_create_new_version")
@permission_required(Permission.ScoChangeFormation)
@scodoc7func(context)
def formation_create_new_version(context, formation_id, redirect=True, REQUEST=None):
"duplicate formation, with new version number"
xml = sco_formations.formation_export(
context, formation_id, export_ids=True, format="xml"
)
new_id, modules_old2new, ues_old2new = sco_formations.formation_import_xml(
context, REQUEST, xml
)
# news
F = sco_formations.formation_list(context, args={"formation_id": new_id})[0]
sco_news.add(
context,
REQUEST,
typ=sco_news.NEWS_FORM,
object=new_id,
text="Nouvelle version de la formation %(acronyme)s" % F,
)
if redirect:
return REQUEST.RESPONSE.redirect(
"ue_list?formation_id=" + new_id + "&msg=Nouvelle version !"
)
else:
return new_id, modules_old2new, ues_old2new
sco_publish(
"/formation_create_new_version",
sco_formations.formation_create_new_version,
Permission.ScoChangeFormation,
)
# --- UE
sco_publish(
@ -579,42 +557,6 @@ sco_publish("/ue_move", sco_edit_formation.ue_move, Permission.ScoChangeFormatio
# --- Semestres de formation
@bp.route("/do_formsemestre_create")
@permission_required(Permission.ScoImplement)
@scodoc7func(context)
def do_formsemestre_create(context, args, REQUEST, silent=False):
"create a formsemestre"
cnx = ndb.GetDBConnexion()
formsemestre_id = sco_formsemestre._formsemestreEditor.create(cnx, args)
if args["etapes"]:
args["formsemestre_id"] = formsemestre_id
sco_formsemestre.write_formsemestre_etapes(context, args)
if args["responsables"]:
args["formsemestre_id"] = formsemestre_id
sco_formsemestre.write_formsemestre_responsables(context, args)
# create default partition
partition_id = sco_groups.partition_create(
context, formsemestre_id, default=True, redirect=0, REQUEST=REQUEST
)
_group_id = sco_groups.createGroup(
context, partition_id, default=True, REQUEST=REQUEST
)
# news
if not args.has_key("titre"):
args["titre"] = "sans titre"
args["formsemestre_id"] = formsemestre_id
args["url"] = "Notes/formsemestre_status?formsemestre_id=%(formsemestre_id)s" % args
if not silent:
sco_news.add(
context,
REQUEST,
typ=sco_news.NEWS_SEM,
text='Création du semestre <a href="%(url)s">%(titre)s</a>' % args,
url=args["url"],
)
return formsemestre_id
@bp.route("/formsemestre_list")
@ -1285,14 +1227,9 @@ def do_formsemestre_inscription_listinscrits(
context, formsemestre_id, format=None, REQUEST=None
):
"""Liste les inscrits (état I) à ce semestre et cache le résultat"""
cache = sco_core.get_formsemestre_inscription_cache(context)
r = cache.get(formsemestre_id)
if r is None:
# retreive list
r = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
context, args={"formsemestre_id": formsemestre_id, "etat": "I"}
r = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
context, formsemestre_id
)
cache.set(formsemestre_id, r)
return scu.sendResult(REQUEST, r, format=format, name="inscrits")
@ -1365,7 +1302,9 @@ def formsemestre_desinscription(
parameters={"etudid": etudid, "formsemestre_id": formsemestre_id},
)
context.do_formsemestre_desinscription(etudid, formsemestre_id, REQUEST=REQUEST)
sco_formsemestre_inscriptions.do_formsemestre_desinscription(
context, etudid, formsemestre_id, REQUEST=REQUEST
)
return (
html_sco_header.sco_header(context, REQUEST)
@ -1458,170 +1397,6 @@ sco_publish(
# --- Evaluations
def _evaluation_check_write_access(context, REQUEST, moduleimpl_id=None):
"""Vérifie que l'on a le droit de modifier, créer ou détruire une
évaluation dans ce module.
Sinon, lance une exception.
(nb: n'implique pas le droit de saisir ou modifier des notes)
"""
# acces pour resp. moduleimpl et resp. form semestre (dir etud)
if moduleimpl_id is None:
raise ValueError("no moduleimpl specified") # bug
authuser = REQUEST.AUTHENTICATED_USER
uid = str(authuser)
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
if (
(not authuser.has_permission(Permission.ScoEditAllEvals))
and uid != M["responsable_id"]
and uid not in sem["responsables"]
):
if sem["ens_can_edit_eval"]:
for ens in M["ens"]:
if ens["ens_id"] == uid:
return # ok
raise AccessDenied("Modification évaluation impossible pour %s" % (uid,))
@bp.route("/do_evaluation_create")
@permission_required(Permission.ScoEnsView)
@scodoc7func(context)
def do_evaluation_create(
context,
moduleimpl_id=None,
jour=None,
heure_debut=None,
heure_fin=None,
description=None,
note_max=None,
coefficient=None,
visibulletin=None,
publish_incomplete=None,
evaluation_type=None,
numero=None,
REQUEST=None,
**kw
):
"""Create an evaluation"""
args = locals()
log("do_evaluation_create: args=" + str(args))
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
context._check_evaluation_args(args)
# Check numeros
sco_evaluations.module_evaluation_renumber(
context, moduleimpl_id, REQUEST=REQUEST, only_if_unumbered=True
)
if not "numero" in args or args["numero"] is None:
n = None
# determine le numero avec la date
# Liste des eval existantes triees par date, la plus ancienne en tete
ModEvals = sco_evaluations.do_evaluation_list(
context,
args={"moduleimpl_id": moduleimpl_id},
sortkey="jour asc, heure_debut asc",
)
if args["jour"]:
next_eval = None
t = (
ndb.DateDMYtoISO(args["jour"]),
ndb.TimetoISO8601(args["heure_debut"]),
)
for e in ModEvals:
if (
ndb.DateDMYtoISO(e["jour"]),
ndb.TimetoISO8601(e["heure_debut"]),
) > t:
next_eval = e
break
if next_eval:
n = sco_evaluations.module_evaluation_insert_before(
context, ModEvals, next_eval, REQUEST
)
else:
n = None # a placer en fin
if n is None: # pas de date ou en fin:
if ModEvals:
log(pprint.pformat(ModEvals[-1]))
n = ModEvals[-1]["numero"] + 1
else:
n = 0 # the only one
# log("creating with numero n=%d" % n)
args["numero"] = n
#
cnx = ndb.GetDBConnexion()
r = sco_evaluations._evaluationEditor.create(cnx, args)
# news
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
mod = sco_edit_module.do_module_list(context, args={"module_id": M["module_id"]})[0]
mod["moduleimpl_id"] = M["moduleimpl_id"]
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
sco_news.add(
context,
REQUEST,
typ=sco_news.NEWS_NOTE,
object=moduleimpl_id,
text='Création d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
url=mod["url"],
)
return r
def _check_evaluation_args(context, args):
"Check coefficient, dates and duration, raises exception if invalid"
moduleimpl_id = args["moduleimpl_id"]
# check bareme
note_max = args.get("note_max", None)
if note_max is None:
raise ScoValueError("missing note_max")
try:
note_max = float(note_max)
except ValueError:
raise ScoValueError("Invalid note_max value")
if note_max < 0:
raise ScoValueError("Invalid note_max value (must be positive or null)")
# check coefficient
coef = args.get("coefficient", None)
if coef is None:
raise ScoValueError("missing coefficient")
try:
coef = float(coef)
except ValueError:
raise ScoValueError("Invalid coefficient value")
if coef < 0:
raise ScoValueError("Invalid coefficient value (must be positive or null)")
# check date
jour = args.get("jour", None)
args["jour"] = jour
if jour:
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
date_debut = datetime.date(y, m, d)
d, m, y = [int(x) for x in sem["date_fin"].split("/")]
date_fin = datetime.date(y, m, d)
# passe par ndb.DateDMYtoISO pour avoir date pivot
y, m, d = [int(x) for x in ndb.DateDMYtoISO(jour).split("-")]
jour = datetime.date(y, m, d)
if (jour > date_fin) or (jour < date_debut):
raise ScoValueError(
"La date de l'évaluation (%s/%s/%s) n'est pas dans le semestre !"
% (d, m, y)
)
heure_debut = args.get("heure_debut", None)
args["heure_debut"] = heure_debut
heure_fin = args.get("heure_fin", None)
args["heure_fin"] = heure_fin
if jour and ((not heure_debut) or (not heure_fin)):
raise ScoValueError("Les heures doivent être précisées")
d = ndb.TimeDuration(heure_debut, heure_fin)
if d and ((d < 0) or (d > 60 * 12)):
raise ScoValueError("Heures de l'évaluation incohérentes !")
@bp.route("/evaluation_delete")
@permission_required(Permission.ScoEnsView)
@scodoc7func(context)

View File

@ -85,7 +85,7 @@ from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import html_sidebar
from app.scodoc import imageresize
from app.scodoc import ImportScolars
from app.scodoc import sco_import_etuds
from app.scodoc import sco_abs
from app.scodoc import sco_archives_etud
from app.scodoc import sco_codes_parcours
@ -1736,7 +1736,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
<table>
<tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr>"""
]
for t in ImportScolars.sco_import_format(
for t in sco_import_etuds.sco_import_format(
with_codesemestre=(formsemestre_id == None)
):
if int(t[3]):
@ -1752,7 +1752,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
elif tf[0] == -1:
return REQUEST.RESPONSE.redirect(dest_url)
else:
return ImportScolars.students_import_excel(
return sco_import_etuds.students_import_excel(
context,
tf[2]["csvfile"],
REQUEST=REQUEST,
@ -1771,8 +1771,8 @@ def import_generate_excel_sample(context, REQUEST, with_codesemestre="1"):
with_codesemestre = int(with_codesemestre)
else:
with_codesemestre = 0
format = ImportScolars.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample(
format = sco_import_etuds.sco_import_format()
data = sco_import_etuds.sco_import_generate_excel_sample(
format, with_codesemestre, exclude_cols=["photo_filename"], REQUEST=REQUEST
)
return sco_excel.sendExcelFile(REQUEST, data, "ImportEtudiants.xls")
@ -1787,8 +1787,8 @@ def import_generate_admission_sample(context, REQUEST, formsemestre_id):
group = sco_groups.get_group(
context, sco_groups.get_default_group(context, formsemestre_id)
)
fmt = ImportScolars.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample(
fmt = sco_import_etuds.sco_import_format()
data = sco_import_etuds.sco_import_generate_excel_sample(
fmt,
only_tables=["identite", "admissions", "adresse"],
exclude_cols=["nationalite", "foto", "photo_filename"],
@ -1889,7 +1889,7 @@ def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None
Seule la première feuille du classeur sera utilisée.
<div id="adm_table_description_format">
"""
+ ImportScolars.adm_table_description_format(context).html()
+ sco_import_etuds.adm_table_description_format(context).html()
+ """</div>"""
)
@ -1913,7 +1913,7 @@ def _students_import_admission(
context, csvfile, type_admission="", REQUEST=None, formsemestre_id=None
):
"import donnees admission from Excel file (v2016)"
diag = ImportScolars.scolars_import_admission(
diag = sco_import_etuds.scolars_import_admission(
csvfile,
context.Notes,
REQUEST,

10
refactor.py Normal file → Executable file
View File

@ -9,7 +9,7 @@
- remplace context.xxx par module.xxx
./refactor.py refactor method module app/scodoc/*.py
./refactor.py refactor module.method app/scodoc/*.py
@ -34,14 +34,6 @@ import tempfile
import shutil
import click
# import flask
# import app
# from app import create_app, cli, db
# from app.auth.models import User, Role, UserRole
# from app.views import notes
TYPES_TO_SCAN = {
types.FunctionType,
# types.ClassType,