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'] print sem['formsemestre_id'], sem['titre_num']
# Recupere la table de notes: # 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.lib.units import inch, cm, mm
from reportlab.rl_config import defaultPageSize # pylint: disable=no-name-in-module from reportlab.rl_config import defaultPageSize # pylint: disable=no-name-in-module
import app.scodoc.sco_utils as scu from app.scodoc import html_sco_header
import app.scodoc.sco_excel from app.scodoc import sco_utils as scu
import app.scodoc.sco_pdf from app.scodoc import sco_excel
from app.scodoc import sco_pdf
from app.scodoc.sco_pdf import SU from app.scodoc.sco_pdf import SU
from app.scodoc.notes_log import log from app.scodoc.notes_log import log

View File

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

View File

@ -57,7 +57,8 @@ import pprint
from app.scodoc.gen_tables import GenTable, SeqGenTable from app.scodoc.gen_tables import GenTable, SeqGenTable
import app.scodoc.sco_utils as scu 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_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_tagtable
from app.scodoc import pe_tools from app.scodoc import pe_tools
from app.scodoc import pe_semestretag from app.scodoc import pe_semestretag
@ -331,7 +332,7 @@ class JuryPE:
nt = self.get_cache_notes_d_un_semestre( nt = self.get_cache_notes_d_un_semestre(
self.context, sem["formsemestre_id"] 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 = ( etudiantsDuSemestre = (
nt.get_etudids() nt.get_etudids()
) # nt.identdict.keys() # identification des etudiants du semestre ) # nt.identdict.keys() # identification des etudiants du semestre
@ -1139,7 +1140,7 @@ class JuryPE:
self, context, formsemestre_id self, context, formsemestre_id
): # inutile en realité ! ): # inutile en realité !
"""Charge la table des notes d'un formsemestre""" """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 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.notes_log import log
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours
from app.scodoc import sco_core
from app.scodoc import sco_tag_module from app.scodoc import sco_tag_module
from app.scodoc import pe_tagtable from app.scodoc import pe_tagtable
@ -269,8 +270,8 @@ class SemestreTag(pe_tagtable.TableTag):
# => le formsemestre_id du semestre dont vient la capitalisation # => le formsemestre_id du semestre dont vient la capitalisation
fid_prec = fids_prec[0] fid_prec = fids_prec[0]
# Lecture des notes de ce semestre # Lecture des notes de ce semestre
nt_prec = self.context.Notes._getNotesCache().get_NotesTable( nt_prec = sco_core.get_notes_cache(self.context).get_NotesTable(
self.context.Notes, fid_prec self.context, fid_prec
) # le tableau de note du semestre considéré ) # 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) # 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.scolog import logdb
from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError
from app.scodoc import sco_abs_notification 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_formsemestre
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc import sco_etud
# --- Misc tools.... ------------------ # --- Misc tools.... ------------------
@ -968,7 +969,7 @@ class CAbsSemEtud:
self.etudid = etudid self.etudid = etudid
self._loaded = False self._loaded = False
formsemestre_id = sem["formsemestre_id"] 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) self.invalidate, formsemestre_id, (etudid, formsemestre_id)
) )
@ -992,11 +993,11 @@ class CAbsSemEtud:
debut_sem = ndb.DateDMYtoISO(self.sem["date_debut"]) debut_sem = ndb.DateDMYtoISO(self.sem["date_debut"])
fin_sem = ndb.DateDMYtoISO(self.sem["date_fin"]) fin_sem = ndb.DateDMYtoISO(self.sem["date_fin"])
self._CountAbs = self.sco_abs.CountAbs( self._CountAbs = CountAbs(
context, etudid=self.etudid, debut=debut_sem, fin=fin_sem self.context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
) )
self._CountAbsJust = self.sco_abs.CountAbsJust( self._CountAbsJust = CountAbsJust(
context, etudid=self.etudid, debut=debut_sem, fin=fin_sem self.context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
) )
self._loaded = True self._loaded = True

View File

@ -37,7 +37,7 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText from email.mime.text import MIMEText
from email.header import Header 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.notesdb as ndb
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
@ -119,7 +119,7 @@ def abs_notify_send(
for email in destinations: for email in destinations:
del msg["To"] del msg["To"]
msg["To"] = email msg["To"] = email
mails.sendEmail(context, msg) sco_emails.sendEmail(context, msg)
ndb.SimpleQuery( ndb.SimpleQuery(
context, context,
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""", """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.gen_tables import GenTable
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_abs from app.scodoc import sco_abs
from app.scodoc import sco_core
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_find_etud from app.scodoc import sco_find_etud
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
@ -124,7 +125,7 @@ def doSignaleAbsence(
if moduleimpl_id and moduleimpl_id != "NULL": if moduleimpl_id and moduleimpl_id != "NULL":
mod = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0] mod = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
formsemestre_id = mod["formsemestre_id"] formsemestre_id = mod["formsemestre_id"]
nt = context.Notes._getNotesCache().get_NotesTable( nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id context.Notes, formsemestre_id
) )
ues = nt.get_ues(etudid=etudid) ues = nt.get_ues(etudid=etudid)
@ -185,7 +186,7 @@ def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
require_module = sco_preferences.get_preference( require_module = sco_preferences.get_preference(
context, "abs_require_module", formsemestre_id 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 context.Notes, formsemestre_id
) )
ues = nt.get_ues(etudid=etudid) ues = nt.get_ues(etudid=etudid)

View File

@ -31,7 +31,7 @@
""" """
import app.scodoc.sco_utils as scu 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_groups
from app.scodoc import sco_trombino from app.scodoc import sco_trombino
from app.scodoc import sco_excel 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) # --- Upload d'un ensemble de fichiers (pour un groupe d'étudiants)
def etudarchive_generate_excel_sample(context, group_id=None, REQUEST=None): def etudarchive_generate_excel_sample(context, group_id=None, REQUEST=None):
"""Feuille excel pour import fichiers etudiants (utilisé pour admissions)""" """Feuille excel pour import fichiers etudiants (utilisé pour admissions)"""
fmt = ImportScolars.sco_import_format() fmt = sco_import_etuds.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample( data = sco_import_etuds.sco_import_generate_excel_sample(
fmt, fmt,
context=context, context=context,
group_ids=[group_id], group_ids=[group_id],

View File

@ -41,13 +41,14 @@ from email.header import Header
from reportlab.lib.colors import Color 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.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_exceptions import AccessDenied from app.scodoc.sco_exceptions import AccessDenied
from app.scodoc import html_sco_header 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_abs_views
from app.scodoc import sco_bulletins_generator from app.scodoc import sco_bulletins_generator
from app.scodoc import sco_bulletins_json 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) email.encoders.encode_base64(att)
msg.attach(att) msg.attach(att)
log("mail bulletin a %s" % msg["To"]) log("mail bulletin a %s" % msg["To"])
mails.sendEmail(context, msg) sco_emails.sendEmail(context, msg)
def _formsemestre_bulletinetud_header_html( 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_edit_module
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_formulas from app.scodoc import sco_formulas
from app.scodoc import sco_moduleimpl from app.scodoc import sco_moduleimpl
from app.scodoc import sco_etud from app.scodoc import sco_etud
@ -211,8 +212,8 @@ def do_moduleimpl_moyennes(context, nt, mod):
inssem_set = set( inssem_set = set(
[ [
x["etudid"] x["etudid"]
for x in context.do_formsemestre_inscription_listinscrits( for x in sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
mod["formsemestre_id"] context, mod["formsemestre_id"]
) )
] ]
) )

View File

@ -254,7 +254,7 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
) )
# #
if create: if create:
formation_id = context.do_formation_create(tf[2], REQUEST) formation_id = do_formation_create(context, tf[2], REQUEST)
else: else:
do_formation_edit(context, tf[2]) do_formation_edit(context, tf[2])
return REQUEST.RESPONSE.redirect("ue_list?formation_id=%s" % formation_id) 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 import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc import VERSION
def sendEmail(context, msg): # TODO A REECRIRE ScoDoc8 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) 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') s = SemSet(context, 'NSS29902')

View File

@ -37,7 +37,7 @@ from email.mime.text import MIMEText
from email.header import Header from email.header import Header
from email.mime.base import MIMEBase from email.mime.base import MIMEBase
from app.scodoc import mails from app.scodoc import sco_emails
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.sco_utils import SCO_ENCODING from app.scodoc.sco_utils import SCO_ENCODING
import app.scodoc.notesdb as ndb 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.notes_log import log
from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc import safehtml from app.scodoc import safehtml
from app.scodoc import sco_formsemestre
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc.scolog import logdb 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 msg["To"] = email_addr
mime_txt = MIMEText(txt, "plain", SCO_ENCODING) mime_txt = MIMEText(txt, "plain", SCO_ENCODING)
msg.attach(mime_txt) msg.attach(mime_txt)
mails.sendEmail(context, msg) sco_emails.sendEmail(context, msg)
return txt return txt
@ -901,6 +900,7 @@ def fill_etuds_info(etuds):
Pour chaque etudiant, ajoute ou formatte les champs Pour chaque etudiant, ajoute ou formatte les champs
-> informations pour fiche etudiant ou listes diverses -> informations pour fiche etudiant ou listes diverses
""" """
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_formsemestre_inscriptions
context = None # XXX en attendant la suppression du context ScoDoc7 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=""): def descr_situation_etud(context, etudid, ne=""):
"""chaine decrivant la situation actuelle de l'etudiant""" """chaine decrivant la situation actuelle de l'etudiant"""
from app.scodoc import sco_formsemestre
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute( 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_module
from app.scodoc import sco_edit_ue from app.scodoc import sco_edit_ue
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl from app.scodoc import sco_moduleimpl
from app.scodoc import sco_news from app.scodoc import sco_news
@ -180,6 +181,146 @@ def do_evaluation_list_in_formsemestre(context, formsemestre_id):
return evals 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): def do_evaluation_edit(context, REQUEST, args):
"edit an evaluation" "edit an evaluation"
evaluation_id = args["evaluation_id"] evaluation_id = args["evaluation_id"]
@ -187,9 +328,16 @@ def do_evaluation_edit(context, REQUEST, args):
if not the_evals: if not the_evals:
raise ValueError("evaluation inexistante !") raise ValueError("evaluation inexistante !")
moduleimpl_id = the_evals[0]["moduleimpl_id"] 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 args["moduleimpl_id"] = moduleimpl_id
context._check_evaluation_args(args) _check_evaluation_args(context, args)
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
context._evaluationEditor.edit(cnx, args) context._evaluationEditor.edit(cnx, args)
# inval cache pour ce semestre # 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}) the_evals = do_evaluation_list(context, {"evaluation_id": evaluation_id})
if not the_evals: if not the_evals:
raise ValueError("evaluation inexistante !") 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 } NotesDB = do_evaluation_get_all_notes(context, evaluation_id) # { etudid : value }
notes = [x["value"] for x in NotesDB.values()] notes = [x["value"] for x in NotesDB.values()]
if notes: if notes:
@ -212,8 +367,6 @@ def do_evaluation_delete(context, REQUEST, evaluation_id):
"Impossible de supprimer cette évaluation: il reste des notes" "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() cnx = ndb.GetDBConnexion()
context._evaluationEditor.delete(cnx, evaluation_id) context._evaluationEditor.delete(cnx, evaluation_id)
@ -295,7 +448,9 @@ def do_evaluation_etat(
# Il faut considerer les inscriptions au semestre # Il faut considerer les inscriptions au semestre
# (pour avoir l'etat et le groupe) et aussi les inscriptions # (pour avoir l'etat et le groupe) et aussi les inscriptions
# au module (pour gerer les modules optionnels correctement) # 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( insmod = sco_moduleimpl.do_moduleimpl_inscription_list(
context, moduleimpl_id=E["moduleimpl_id"] 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] # E = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
# M = sco_moduleimpl.do_moduleimpl_list(context,moduleimpl_id=E["moduleimpl_id"])[0] # M = sco_moduleimpl.do_moduleimpl_list(context,moduleimpl_id=E["moduleimpl_id"])[0]
# formsemestre_id = M["formsemestre_id"] # 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"]) # insmod = sco_moduleimpl.do_moduleimpl_inscription_list(context,moduleimpl_id=E["moduleimpl_id"])
# insmodset = set([x["etudid"] for x in insmod]) # insmodset = set([x["etudid"] for x in insmod])
# retire de insem ceux qui ne sont pas inscrits au module # 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] e = do_evaluation_list(context, args={"evaluation_id": evaluation_id})[0]
redirect = int(redirect) redirect = int(redirect)
# access: can change eval ?
# access: can change eval ? (raises exception) if not sco_permissions_check.can_edit_evaluation(
context._evaluation_check_write_access(REQUEST, moduleimpl_id=e["moduleimpl_id"]) context, REQUEST, moduleimpl_id=e["moduleimpl_id"]
):
raise AccessDenied(
"Modification évaluation impossible pour %s"
% scu.get_current_user_name(REQUEST)
)
module_evaluation_renumber( module_evaluation_renumber(
context, e["moduleimpl_id"], REQUEST=REQUEST, only_if_unumbered=True context, e["moduleimpl_id"], REQUEST=REQUEST, only_if_unumbered=True
@ -977,13 +1137,14 @@ def evaluation_create_form(
formsemestre_id = M["formsemestre_id"] formsemestre_id = M["formsemestre_id"]
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
if not readonly: if not readonly:
try: if not sco_permissions_check.can_edit_evaluation(
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id) context, REQUEST, moduleimpl_id=moduleimpl_id
except AccessDenied as e: ):
return ( return (
html_sco_header.sco_header(context, REQUEST) html_sco_header.sco_header(context, REQUEST)
+ "<h2>Opération non autorisée</h2><p>" + "<h2>Opération non autorisée</h2><p>"
+ str(e) + "Modification évaluation impossible pour %s"
% scu.get_current_user_name(REQUEST)
+ "</p>" + "</p>"
+ '<p><a href="%s">Revenir</a></p>' % (str(REQUEST.HTTP_REFERER),) + '<p><a href="%s">Revenir</a></p>' % (str(REQUEST.HTTP_REFERER),)
+ html_sco_header.sco_footer(context, REQUEST) + html_sco_header.sco_footer(context, REQUEST)
@ -1227,7 +1388,7 @@ def evaluation_create_form(
tf[2]["visibulletin"] = 0 tf[2]["visibulletin"] = 0
if not edit: if not edit:
# creation d'une evaluation # 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) return REQUEST.RESPONSE.redirect(dest_url)
else: else:
do_evaluation_edit(context, REQUEST, tf[2]) 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.notes_log import log
from app.scodoc.scolog import logdb from app.scodoc.scolog import logdb
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_preferences
# colors, voir exemple format.py # colors, voir exemple format.py

View File

@ -28,6 +28,7 @@
"""Recherche d'étudiants """Recherche d'étudiants
""" """
from scodoc_manager import sco_mgr
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable 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): def search_etud_in_accessible_depts(context, expnom=None, code_nip=None, REQUEST=None):
""" """
context est le ZScoDoc context est le ZScoDoc
@ -279,10 +274,10 @@ def search_etud_in_accessible_depts(context, expnom=None, code_nip=None, REQUEST
""" """
result = [] result = []
accessible_depts = [] accessible_depts = []
deptList = context._list_depts() # definis dans Zope dept_list = sco_mgr.get_dept_ids()
for dept in deptList: for dept in dept_list:
# log('%s searching %s' % (str(REQUEST.AUTHENTICATED_USER),dept)) # 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: if expnom or code_nip:
accessible_depts.append(dept.Scolarite.DeptId()) accessible_depts.append(dept.Scolarite.DeptId())
etuds = search_etuds_infos( etuds = search_etuds_infos(

View File

@ -35,16 +35,17 @@ import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc import sco_codes_parcours 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_matiere
from app.scodoc import sco_edit_module from app.scodoc import sco_edit_module
from app.scodoc import sco_edit_ue 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( _formationEditor = ndb.EditableTable(
"notes_formations", "notes_formations",
@ -164,6 +165,8 @@ def formation_import_xml(
"""Create a formation from XML representation """Create a formation from XML representation
(format dumped by formation_export( format='xml' )) (format dumped by formation_export( format='xml' ))
""" """
from app.scodoc import sco_edit_formation
log("formation_import_xml: doc=%s" % doc) log("formation_import_xml: doc=%s" % doc)
try: try:
dom = xml.dom.minidom.parseString(doc) dom = xml.dom.minidom.parseString(doc)
@ -199,7 +202,7 @@ def formation_import_xml(
# create formation # create formation
# F_unquoted = F.copy() # F_unquoted = F.copy()
# unescape_html_dict(F_unquoted) # 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) log("formation %s created" % formation_id)
ues_old2new = {} # xml ue_id : new ue_id ues_old2new = {} # xml ue_id : new ue_id
modules_old2new = {} # xml module_id : new module_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, 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 time
import app.scodoc.sco_utils as scu from scodoc_manager import sco_mgr
import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log
from app.scodoc.gen_tables import GenTable
from app.scodoc import sco_codes_parcours 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_core
from app.scodoc import sco_preferences 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 from app.scodoc.sco_exceptions import ScoValueError
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
_formsemestreEditor = ndb.EditableTable( _formsemestreEditor = ndb.EditableTable(
"notes_formsemestre", "notes_formsemestre",
@ -219,6 +219,41 @@ def etapes_apo_str(etapes):
return ", ".join([str(x) for x in 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): def do_formsemestre_edit(context, sem, cnx=None, **kw):
"""Apply modifications to formsemestre. """Apply modifications to formsemestre.
Update etapes and resps. Invalidate cache.""" Update etapes and resps. Invalidate cache."""
@ -500,7 +535,7 @@ def sem_est_courant(context, sem):
def scodoc_get_all_unlocked_sems(context): def scodoc_get_all_unlocked_sems(context):
"""Liste de tous les semestres non verrouillés de tous les départements""" """Liste de tous les semestres non verrouillés de tous les départements"""
depts = context._list_depts() depts = sco_mgr.get_dept_ids()
semdepts = [] semdepts = []
for dept in depts: for dept in depts:
semdepts += [ semdepts += [

View File

@ -715,7 +715,9 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
) )
if not edit: if not edit:
# creation du semestre # 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 # creation des modules
for module_id in tf[2]["tf-checked"]: for module_id in tf[2]["tf-checked"]:
modargs = { modargs = {
@ -1014,7 +1016,7 @@ def do_formsemestre_clone(
args["date_debut"] = date_debut args["date_debut"] = date_debut
args["date_fin"] = date_fin args["date_fin"] = date_fin
args["etat"] = 1 # non verrouillé 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) log("created formsemestre %s" % formsemestre_id)
# 2- create moduleimpls # 2- create moduleimpls
mods_orig = sco_moduleimpl.do_moduleimpl_list( mods_orig = sco_moduleimpl.do_moduleimpl_list(
@ -1041,7 +1043,7 @@ def do_formsemestre_clone(
args = e.copy() args = e.copy()
del args["jour"] # erase date del args["jour"] # erase date
args["moduleimpl_id"] = mid args["moduleimpl_id"] = mid
_ = context.do_evaluation_create(REQUEST=REQUEST, **args) _ = sco_evaluations.do_evaluation_create(context, REQUEST=REQUEST, **args)
# 3- copy uecoefs # 3- copy uecoefs
objs = sco_formsemestre.formsemestre_uecoef_list( objs = sco_formsemestre.formsemestre_uecoef_list(
@ -1196,14 +1198,18 @@ def do_formsemestres_associate_new_version(context, formsemestre_ids, REQUEST=No
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
# New formation: # 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: for formsemestre_id in formsemestre_ids:
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
sem["formation_id"] = formation_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( _reassociate_moduleimpls(
context, cnx, formsemestre_id, ues_old2new, modules_old2new 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) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
# --- Destruction des modules de ce semestre # --- 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: for mod in mods:
# evaluations # evaluations
evals = sco_evaluations.do_evaluation_list( evals = sco_evaluations.do_evaluation_list(
@ -1474,7 +1480,7 @@ def formsemestre_change_lock(
if etat not in (0, 1): if etat not in (0, 1):
raise ScoValueError("formsemestre_lock: invalid value for etat (%s)" % etat) raise ScoValueError("formsemestre_lock: invalid value for etat (%s)" % etat)
args = {"formsemestre_id": formsemestre_id, "etat": etat} args = {"formsemestre_id": formsemestre_id, "etat": etat}
context.do_formsemestre_edit(args) sco_formsemestre.do_formsemestre_edit(context, args)
if REQUEST: if REQUEST:
return REQUEST.RESPONSE.redirect( return REQUEST.RESPONSE.redirect(
"formsemestre_status?formsemestre_id=%s" % formsemestre_id "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 "formsemestre_change_publication_bul: invalid value for etat (%s)" % etat
) )
args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat} args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat}
context.do_formsemestre_edit(args) sco_formsemestre.do_formsemestre_edit(context, args)
if REQUEST: if REQUEST:
return REQUEST.RESPONSE.redirect( return REQUEST.RESPONSE.redirect(
"formsemestre_status?formsemestre_id=%s" % formsemestre_id "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["modalite"] = "EXT"
sem_params["etapes"] = None sem_params["etapes"] = None
sem_params["responsables"] = [str(REQUEST.AUTHENTICATED_USER)] 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 # nota: le semestre est créé vide: pas de modules
# Inscription au semestre # 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_groups
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_core from app.scodoc import sco_core
from app.scodoc import sco_formsemestre_edit
from app.scodoc import html_sco_header 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) 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): def do_formsemestre_inscription_create(context, args, REQUEST, method=None):
"create a formsemestre_inscription (and sco event)" "create a formsemestre_inscription (and sco event)"
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
@ -126,6 +138,8 @@ def do_formsemestre_desinscription(context, etudid, formsemestre_id, REQUEST=Non
"""Désinscription d'un étudiant. """Désinscription d'un étudiant.
Si semestre extérieur et dernier inscrit, suppression de ce semestre. 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) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
# -- check lock # -- check lock
if sem["etat"] != "1": if sem["etat"] != "1":

View File

@ -346,7 +346,9 @@ def formsemestre_status_menubar(context, sem, REQUEST):
"title": "Créer/modifier les partitions...", "title": "Créer/modifier les partitions...",
"endpoint": "scolar.editPartitionForm", "endpoint": "scolar.editPartitionForm",
"args": {"formsemestre_id": formsemestre_id}, "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: # 1 item / partition:
@ -355,7 +357,10 @@ def formsemestre_status_menubar(context, sem, REQUEST):
) )
submenu = [] submenu = []
enabled = ( 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: for partition in partitions:
submenu.append( submenu.append(
@ -873,13 +878,17 @@ def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
H.append("</table>") H.append("</table>")
else: else:
H.append('<p class="help indent">Aucun groupe dans cette partition') 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( H.append(
' (<a href="affectGroups?partition_id=%s" class="stdlink">créer</a>)' ' (<a href="affectGroups?partition_id=%s" class="stdlink">créer</a>)'
% partition["partition_id"] % partition["partition_id"]
) )
H.append("</p>") 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( H.append(
'<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>' '<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>'
% formsemestre_id % 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_codes_parcours
from app.scodoc import sco_core from app.scodoc import sco_core
from app.scodoc import sco_etud 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_exceptions import ScoException, AccessDenied, ScoValueError
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc.TrivialFormulator import TrivialFormulator 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( def checkGroupName(
groupName, groupName,
): # XXX unused: now allow any string as a group or partition name ): # 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 def get_group_infos(context, group_id, etat=None): # was _getlisteetud
"""legacy code: used by group_list and trombino""" """legacy code: used by group_list and trombino"""
from app.scodoc import sco_formsemestre
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
group = get_group(context, group_id) group = get_group(context, group_id)
sem = sco_formsemestre.get_formsemestre(context, group["formsemestre_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=""/> <etud etuid="" sexe="" nom="" prenom="" origin=""/>
</groupe> </groupe>
""" """
from app.scodoc import sco_formsemestre
t0 = time.time() t0 = time.time()
partition = get_partition(context, partition_id) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"] formsemestre_id = partition["formsemestre_id"]
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
groups = get_partition_groups(context, partition) 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 context.Notes, formsemestre_id
) # > inscrdict ) # > inscrdict
etuds_set = set(nt.inscrdict) etuds_set = set(nt.inscrdict)
@ -621,9 +611,11 @@ def setGroups(
groupsToCreate: lignes "group_name;etudid;...\n" groupsToCreate: lignes "group_name;etudid;...\n"
groupsToDelete: group_id;group_id;... groupsToDelete: group_id;group_id;...
""" """
from app.scodoc import sco_formsemestre
partition = get_partition(context, partition_id) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log("***setGroups: partition_id=%s" % partition_id) log("***setGroups: partition_id=%s" % partition_id)
log("groupsLists=%s" % groupsLists) 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) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
# #
if group_name: if group_name:
@ -747,7 +741,9 @@ def suppressGroup(context, group_id, partition_id=None, REQUEST=None):
else: else:
partition_id = group["partition_id"] partition_id = group["partition_id"]
partition = get_partition(context, 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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log( log(
"suppressGroup: group_id=%s group_name=%s partition_name=%s" "suppressGroup: group_id=%s group_name=%s partition_name=%s"
@ -766,7 +762,9 @@ def partition_create(
redirect=1, redirect=1,
): ):
"""Create a new partition""" """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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if partition_name: if partition_name:
partition_name = partition_name.strip() partition_name = partition_name.strip()
@ -810,7 +808,7 @@ def getArrowIconsTags(context, REQUEST):
def editPartitionForm(context, formsemestre_id=None, REQUEST=None): def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
"""Form to create/suppress partitions""" """Form to create/suppress partitions"""
# ad-hoc form # 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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
partitions = get_partitions_list(context, formsemestre_id) partitions = get_partitions_list(context, formsemestre_id)
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST) 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) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log("partition_set_attr(%s, %s, %s)" % (partition_id, attr, value)) 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)""" default partition cannot be suppressed (unless force)"""
partition = get_partition(context, partition_id) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if not partition["partition_name"] and not force: 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)""" """Move before/after previous one (decrement/increment numero)"""
partition = get_partition(context, partition_id) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
# #
redirect = int(redirect) redirect = int(redirect)
@ -1042,7 +1040,7 @@ def partition_rename(context, partition_id, REQUEST=None):
"""Form to rename a partition""" """Form to rename a partition"""
partition = get_partition(context, partition_id) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
H = ["<h2>Renommer une partition</h2>"] H = ["<h2>Renommer une partition</h2>"]
tf = TrivialFormulator( 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 "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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
redirect = int(redirect) redirect = int(redirect)
cnx = ndb.GetDBConnexion() 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: if group["group_name"] is None:
raise ValueError("can't set a name to default group") raise ValueError("can't set a name to default group")
formsemestre_id = group["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
redirect = int(redirect) redirect = int(redirect)
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
@ -1145,7 +1143,7 @@ def group_rename(context, group_id, REQUEST=None):
"""Form to rename a group""" """Form to rename a group"""
group = get_group(context, group_id) group = get_group(context, group_id)
formsemestre_id = group["formsemestre_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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]] H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
tf = TrivialFormulator( tf = TrivialFormulator(
@ -1193,7 +1191,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
formsemestre_id = partition["formsemestre_id"] formsemestre_id = partition["formsemestre_id"]
# renvoie sur page édition groupes # renvoie sur page édition groupes
dest_url = "affectGroups?partition_id=%s" % partition_id 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 !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) 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) 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 context.Notes, formsemestre_id
) # > identdict ) # > identdict
identdict = nt.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) # Ported from DTML and adapted to new group management (nov 2009)
partition = sco_groups.get_partition(context, partition_id) partition = sco_groups.get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_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") raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
H = [ H = [

View File

@ -53,6 +53,7 @@ from app.scodoc.sco_exceptions import (
ScoGenError, ScoGenError,
) )
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_core
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups 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.mime.text import MIMEText
from email.header import Header from email.header import Header
from app.scodoc import mails from app.scodoc import sco_emails
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoException from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoException
@ -228,4 +228,4 @@ Pour plus d'informations sur ce logiciel, voir %s
msg.epilogue = "" msg.epilogue = ""
txt = MIMEText(txt, "plain", scu.SCO_ENCODING) txt = MIMEText(txt, "plain", scu.SCO_ENCODING)
msg.attach(txt) 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 } { etudid : etud }
""" """
if not with_dems: if not with_dems:
ins = context.Notes.do_formsemestre_inscription_listinscrits( ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
formsemestre_id context, formsemestre_id
) # optimized ) # optimized
else: else:
args = {"formsemestre_id": formsemestre_id} 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): def do_desinscrit(context, sem, etudids, REQUEST):
log("do_desinscrit: %s" % etudids) log("do_desinscrit: %s" % etudids)
for etudid in etudids: for etudid in etudids:
context.do_formsemestre_desinscription( sco_formsemestre_inscriptions.do_formsemestre_desinscription(
etudid, sem["formsemestre_id"], REQUEST=REQUEST context, etudid, sem["formsemestre_id"], REQUEST=REQUEST
) )

View File

@ -91,7 +91,9 @@ def moduleimpl_inscriptions_edit(
% (moduleimpl_id, mod["titre"], mod["code"]), % (moduleimpl_id, mod["titre"], mod["code"]),
] ]
# Liste des inscrits à ce semestre # 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: for ins in inscrits:
etuds_info = sco_etud.get_etud_info(etudid=ins["etudid"], filled=1) etuds_info = sco_etud.get_etud_info(etudid=ins["etudid"], filled=1)
if not etuds_info: 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.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.notes_log import log 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.sco_utils import SCO_ENCODING, SCO_ANNONCES_WEBSITE
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_moduleimpl from app.scodoc import sco_moduleimpl
@ -301,4 +301,4 @@ def _send_news_by_mail(context, n):
del msg["To"] del msg["To"]
msg["To"] = email_addr msg["To"] = email_addr
# log('xxx mail: %s' % msg) # 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": if ins["etat"] != "D":
dem_title = "Démission" dem_title = "Démission"
dem_url = "formDem" dem_url = "scolar.formDem"
else: else:
dem_title = "Annuler la démission" dem_title = "Annuler la démission"
dem_url = "doCancelDem" dem_url = "scolar.doCancelDem"
# Note: seul un etudiant inscrit (I) peut devenir défaillant. # Note: seul un etudiant inscrit (I) peut devenir défaillant.
if ins["etat"] != sco_codes_parcours.DEF: if ins["etat"] != sco_codes_parcours.DEF:
def_title = "Déclarer défaillance" def_title = "Déclarer défaillance"
def_url = "formDef" def_url = "scolar.formDef"
elif ins["etat"] == sco_codes_parcours.DEF: elif ins["etat"] == sco_codes_parcours.DEF:
def_title = "Annuler la défaillance" def_title = "Annuler la défaillance"
def_url = "doCancelDef" def_url = "scolar.doCancelDef"
def_enabled = ( def_enabled = (
(ins["etat"] != "D") (ins["etat"] != "D")
and authuser.has_permission(Permission.ScoEtudInscrit) 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 html_sco_header
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_exceptions from app.scodoc import sco_exceptions
from app.scodoc import sco_formsemestre
from app.scodoc import sco_moduleimpl from app.scodoc import sco_moduleimpl
from app.scodoc import sco_parcours_dut
def can_edit_notes(context, authuser, moduleimpl_id, allow_ens=True): 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, 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). 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) uid = str(authuser)
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0] M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"]) 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 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): def can_suppress_annotation(context, annotation_id, REQUEST):
"""True if current user can suppress this annotation """True if current user can suppress this annotation
Seuls l'auteur de l'annotation et le chef de dept peuvent supprimer 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 !") raise sco_exceptions.ScoValueError("annotation inexistante !")
anno = annos[0] anno = annos[0]
authuser = REQUEST.AUTHENTICATED_USER 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 ( return (
(str(authuser) == anno["zope_authenticated_user"]) str(authuser) == anno["zope_authenticated_user"]
or authuser.has_permission(Permission.ScoEtudSupprAnnotations) ) or authuser.has_permission(Permission.ScoEtudAddAnnotations)
or authuser.has_permission(Permission.ScoEtudInscrit)
)
def can_edit_suivi(context, REQUEST=None): 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): def can_validate_sem(context, REQUEST, formsemestre_id):
"Vrai si utilisateur peut saisir decision de jury dans ce semestre" "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) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if sem["etat"] != "1": if sem["etat"] != "1":
return False # semestre verrouillé return False # semestre verrouillé
@ -86,6 +118,7 @@ def can_validate_sem(context, REQUEST, formsemestre_id):
def can_edit_pv(context, REQUEST, formsemestre_id): def can_edit_pv(context, REQUEST, formsemestre_id):
"Vrai si utilisateur peut editer un PV de jury de ce semestre" "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) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if is_chef_or_diretud(context, REQUEST, sem): if is_chef_or_diretud(context, REQUEST, sem):
@ -114,6 +147,8 @@ def check_access_diretud(
"""Check if access granted: responsable or ScoImplement """Check if access granted: responsable or ScoImplement
Return True|False, HTML_error_page Return True|False, HTML_error_page
""" """
from app.scodoc import sco_formsemestre
authuser = REQUEST.AUTHENTICATED_USER authuser = REQUEST.AUTHENTICATED_USER
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
header = html_sco_header.sco_header( header = html_sco_header.sco_header(
@ -137,3 +172,19 @@ def check_access_diretud(
) )
else: else:
return True, "" 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.TrivialFormulator import TrivialFormulator, TF
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import htmlutils from app.scodoc import htmlutils
from app.scodoc import sco_abs
from app.scodoc import sco_core from app.scodoc import sco_core
from app.scodoc import sco_edit_module from app.scodoc import sco_edit_module
from app.scodoc import sco_evaluations 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.sco_pdf import SU
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import htmlutils 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_excel
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups 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 # --------------------- Upload des photos de tout un groupe
def photos_generate_excel_sample(context, group_ids=[], REQUEST=None): def photos_generate_excel_sample(context, group_ids=[], REQUEST=None):
"""Feuille excel pour import fichiers photos""" """Feuille excel pour import fichiers photos"""
fmt = ImportScolars.sco_import_format() fmt = sco_import_etuds.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample( data = sco_import_etuds.sco_import_generate_excel_sample(
fmt, fmt,
context=context, context=context,
group_ids=group_ids, group_ids=group_ids,

View File

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

View File

@ -385,6 +385,15 @@ def UsersURL():
return "NotImplemented" 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 # ---- 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.gen_tables import GenTable
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_abs 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_compute_moy
from app.scodoc import sco_core
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_excel from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
@ -248,7 +250,9 @@ def SignaleAbsenceGrHebdo(
else: else:
# Si aucun etudiant n'est inscrit au module choisi... # Si aucun etudiant n'est inscrit au module choisi...
moduleimpl_id = None 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( sem = sco_formsemestre.do_formsemestre_list(
context, {"formsemestre_id": formsemestre_id} context, {"formsemestre_id": formsemestre_id}
)[0] )[0]
@ -421,7 +425,7 @@ def SignaleAbsenceGrSemestre(
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
if etuds: if etuds:
nt = context.Notes._getNotesCache().get_NotesTable( nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, formsemestre_id context.Notes, formsemestre_id
) )
sem = sco_formsemestre.do_formsemestre_list( sem = sco_formsemestre.do_formsemestre_list(
@ -638,7 +642,7 @@ def _gen_form_saisie_groupe(
# UE capitalisee dans semestre courant ? # UE capitalisee dans semestre courant ?
cap = [] cap = []
if etud["cursem"]: if etud["cursem"]:
nt = context.Notes._getNotesCache().get_NotesTable( nt = sco_core.get_notes_cache(context).get_NotesTable(
context.Notes, etud["cursem"]["formsemestre_id"] context.Notes, etud["cursem"]["formsemestre_id"]
) # > get_ues, get_etud_ue_status ) # > get_ues, get_etud_ue_status
for ue in nt.get_ues(): 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" ) # avec context.sco_exemple( etudid="E12" )
@bp.route("/<scodoc_dept>/Scolarite/sco_exemple2") @bp.route("/<scodoc_dept>/Scolarite/sco_exemple2")
@login_required @login_required

View File

@ -486,33 +486,11 @@ def formation_import_xml_form(context, REQUEST):
) )
@bp.route("/formation_create_new_version") sco_publish(
@permission_required(Permission.ScoChangeFormation) "/formation_create_new_version",
@scodoc7func(context) sco_formations.formation_create_new_version,
def formation_create_new_version(context, formation_id, redirect=True, REQUEST=None): Permission.ScoChangeFormation,
"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
# --- UE # --- UE
sco_publish( sco_publish(
@ -579,42 +557,6 @@ sco_publish("/ue_move", sco_edit_formation.ue_move, Permission.ScoChangeFormatio
# --- Semestres de formation # --- 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") @bp.route("/formsemestre_list")
@ -1285,14 +1227,9 @@ def do_formsemestre_inscription_listinscrits(
context, formsemestre_id, format=None, REQUEST=None context, formsemestre_id, format=None, REQUEST=None
): ):
"""Liste les inscrits (état I) à ce semestre et cache le résultat""" """Liste les inscrits (état I) à ce semestre et cache le résultat"""
cache = sco_core.get_formsemestre_inscription_cache(context) r = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
r = cache.get(formsemestre_id) context, formsemestre_id
if r is None:
# retreive list
r = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
context, args={"formsemestre_id": formsemestre_id, "etat": "I"}
) )
cache.set(formsemestre_id, r)
return scu.sendResult(REQUEST, r, format=format, name="inscrits") return scu.sendResult(REQUEST, r, format=format, name="inscrits")
@ -1365,7 +1302,9 @@ def formsemestre_desinscription(
parameters={"etudid": etudid, "formsemestre_id": formsemestre_id}, 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 ( return (
html_sco_header.sco_header(context, REQUEST) html_sco_header.sco_header(context, REQUEST)
@ -1458,170 +1397,6 @@ sco_publish(
# --- Evaluations # --- 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") @bp.route("/evaluation_delete")
@permission_required(Permission.ScoEnsView) @permission_required(Permission.ScoEnsView)
@scodoc7func(context) @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_sco_header
from app.scodoc import html_sidebar from app.scodoc import html_sidebar
from app.scodoc import imageresize 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_abs
from app.scodoc import sco_archives_etud from app.scodoc import sco_archives_etud
from app.scodoc import sco_codes_parcours 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> <table>
<tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr>""" <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) with_codesemestre=(formsemestre_id == None)
): ):
if int(t[3]): 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: elif tf[0] == -1:
return REQUEST.RESPONSE.redirect(dest_url) return REQUEST.RESPONSE.redirect(dest_url)
else: else:
return ImportScolars.students_import_excel( return sco_import_etuds.students_import_excel(
context, context,
tf[2]["csvfile"], tf[2]["csvfile"],
REQUEST=REQUEST, REQUEST=REQUEST,
@ -1771,8 +1771,8 @@ def import_generate_excel_sample(context, REQUEST, with_codesemestre="1"):
with_codesemestre = int(with_codesemestre) with_codesemestre = int(with_codesemestre)
else: else:
with_codesemestre = 0 with_codesemestre = 0
format = ImportScolars.sco_import_format() format = sco_import_etuds.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample( data = sco_import_etuds.sco_import_generate_excel_sample(
format, with_codesemestre, exclude_cols=["photo_filename"], REQUEST=REQUEST format, with_codesemestre, exclude_cols=["photo_filename"], REQUEST=REQUEST
) )
return sco_excel.sendExcelFile(REQUEST, data, "ImportEtudiants.xls") 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( group = sco_groups.get_group(
context, sco_groups.get_default_group(context, formsemestre_id) context, sco_groups.get_default_group(context, formsemestre_id)
) )
fmt = ImportScolars.sco_import_format() fmt = sco_import_etuds.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample( data = sco_import_etuds.sco_import_generate_excel_sample(
fmt, fmt,
only_tables=["identite", "admissions", "adresse"], only_tables=["identite", "admissions", "adresse"],
exclude_cols=["nationalite", "foto", "photo_filename"], 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. Seule la première feuille du classeur sera utilisée.
<div id="adm_table_description_format"> <div id="adm_table_description_format">
""" """
+ ImportScolars.adm_table_description_format(context).html() + sco_import_etuds.adm_table_description_format(context).html()
+ """</div>""" + """</div>"""
) )
@ -1913,7 +1913,7 @@ def _students_import_admission(
context, csvfile, type_admission="", REQUEST=None, formsemestre_id=None context, csvfile, type_admission="", REQUEST=None, formsemestre_id=None
): ):
"import donnees admission from Excel file (v2016)" "import donnees admission from Excel file (v2016)"
diag = ImportScolars.scolars_import_admission( diag = sco_import_etuds.scolars_import_admission(
csvfile, csvfile,
context.Notes, context.Notes,
REQUEST, REQUEST,

10
refactor.py Normal file → Executable file
View File

@ -9,7 +9,7 @@
- remplace context.xxx par module.xxx - 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 shutil
import click 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_TO_SCAN = {
types.FunctionType, types.FunctionType,
# types.ClassType, # types.ClassType,