Compare commits

...

3 Commits

Author SHA1 Message Date
ede5aa680d migration en cours 2021-06-21 12:13:25 +02:00
597b83e6a4 suite 2021-06-21 11:22:55 +02:00
6a4d6e5109 WIP suite de la migration 2021-06-21 10:17:16 +02:00
51 changed files with 641 additions and 1372 deletions

View File

@ -133,7 +133,7 @@ class User(UserMixin, db.Model):
Args:
perm: integer, one of the value defined in Permission class.
context:
dept: dept id (eg 'RT')
"""
if dept is False:
dept = g.scodoc_dept

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

@ -19,7 +19,7 @@ authuser = app.acl_users.getUserById('admin')
authuser = authuser.__of__(app.acl_users)
Exemple:
sems = context.Notes.formsemestre_list()
sems = sco_formsemestre.do_formsemestre_list.formsemestre_list(context)
formsemestre_id = sems[0]['formsemestre_id']
# Affiche tous les semestres:
@ -27,7 +27,7 @@ for sem in sems:
print sem['formsemestre_id'], sem['titre_num']
# Recupere la table de notes:
nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_id)
nt = sco_core.get_notes_cache(context).get_NotesTable(context, formsemestre_id)
"""

View File

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

View File

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

View File

@ -1205,7 +1205,7 @@ class NotesTable:
and moy_ue_cap >= self.parcours.NOTES_BARRE_VALID_UE
):
if not cnx:
cnx = self.context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
sco_parcours_dut.do_formsemestre_validate_ue(
cnx,
nt_cap,

View File

@ -57,7 +57,9 @@ import pprint
from app.scodoc.gen_tables import GenTable, SeqGenTable
import app.scodoc.sco_utils as scu
from app.scodoc import sco_codes_parcours # sco_codes_parcours.NEXT -> sem suivant
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import pe_tagtable
from app.scodoc import pe_tools
from app.scodoc import pe_semestretag
@ -331,7 +333,7 @@ class JuryPE:
nt = self.get_cache_notes_d_un_semestre(
self.context, sem["formsemestre_id"]
)
# context.Notes._getNotesCache().get_NotesTable(context.Notes, sem['formsemestre_id'])
# sco_core.get_notes_cache(context).get_NotesTable(context, sem['formsemestre_id'])
etudiantsDuSemestre = (
nt.get_etudids()
) # nt.identdict.keys() # identification des etudiants du semestre
@ -466,7 +468,7 @@ class JuryPE:
reponse = False
etud = self.get_cache_etudInfo_d_un_etudiant(self.context, etudid)
(_, parcours) = sco_report.get_codeparcoursetud(self.context.Notes, etud)
(_, parcours) = sco_report.get_codeparcoursetud(self.context, etud)
if (
len(set(sco_codes_parcours.CODES_SEM_REO.keys()) & set(parcours.values()))
> 0
@ -498,7 +500,7 @@ class JuryPE:
lastdate = max(sesdates) # date de fin de l'inscription la plus récente
# if PETable.AFFICHAGE_DEBUG_PE == True : pe_tools.pe_print(" derniere inscription = ", lastDateSem)
semestresDeScoDoc = self.context.Notes.formsemestre_list()
semestresDeScoDoc = sco_formsemestre.formsemestre_list(self.context)
semestresSuperieurs = [
sem for sem in semestresDeScoDoc if sem["semestre_id"] > sonDernierSidValide
] # Semestre de rang plus élevé que son dernier sem valide
@ -530,7 +532,7 @@ class JuryPE:
etud = self.get_cache_etudInfo_d_un_etudiant(self.context, etudid)
(code, parcours) = sco_report.get_codeparcoursetud(
self.context.Notes, etud
self.context, etud
) # description = '1234:A', parcours = {1:ADM, 2:NAR, ...}
sonDernierSemestreValide = max(
[
@ -1139,8 +1141,8 @@ class JuryPE:
self, context, formsemestre_id
): # inutile en realité !
"""Charge la table des notes d'un formsemestre"""
return context.Notes._getNotesCache().get_NotesTable(
context.Notes, formsemestre_id
return sco_core.get_notes_cache(context).get_NotesTable(
context, formsemestre_id
)
# ------------------------------------------------------------------------------------------------------------------
@ -1245,8 +1247,8 @@ def get_cosemestres_diplomants(context, semBase, avec_meme_formation=False):
> dont la formation est la même (optionnel)
> ne prenant en compte que les etudiants sans redoublement
"""
tousLesSems = (
context.Notes.formsemestre_list()
tousLesSems = sco_formsemestre.formsemestre_list(
context
) # tous les semestres memorises dans scodoc
diplome = get_annee_diplome_semestre(semBase)

View File

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

View File

@ -41,9 +41,10 @@ from app.scodoc import notesdb as ndb
from app.scodoc.scolog import logdb
from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError
from app.scodoc import sco_abs_notification
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_preferences
from app.scodoc import sco_etud
# --- Misc tools.... ------------------
@ -436,7 +437,7 @@ def GetAbsDescription(context, a, cursor=None):
if a["moduleimpl_id"] and a["moduleimpl_id"] != "NULL":
# Trouver le nom du module
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
context.Notes, moduleimpl_id=a["moduleimpl_id"]
context, moduleimpl_id=a["moduleimpl_id"]
)
if Mlist:
M = Mlist[0]
@ -968,7 +969,7 @@ class CAbsSemEtud:
self.etudid = etudid
self._loaded = False
formsemestre_id = sem["formsemestre_id"]
context.Notes._getNotesCache().add_listener(
sco_core.get_notes_cache(context).add_listener(
self.invalidate, formsemestre_id, (etudid, formsemestre_id)
)
@ -992,11 +993,11 @@ class CAbsSemEtud:
debut_sem = ndb.DateDMYtoISO(self.sem["date_debut"])
fin_sem = ndb.DateDMYtoISO(self.sem["date_fin"])
self._CountAbs = self.sco_abs.CountAbs(
context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
self._CountAbs = CountAbs(
self.context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
)
self._CountAbsJust = self.sco_abs.CountAbsJust(
context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
self._CountAbsJust = CountAbsJust(
self.context, etudid=self.etudid, debut=debut_sem, fin=fin_sem
)
self._loaded = True
@ -1054,8 +1055,8 @@ def invalidateAbsEtudDate(context, etudid, date):
True # efface toujours le PDF car il affiche en général les absences
)
context.Notes._inval_cache(
pdfonly=pdfonly, formsemestre_id=sem["formsemestre_id"]
sco_core.inval_cache(
context, pdfonly=pdfonly, formsemestre_id=sem["formsemestre_id"]
)
# Inval cache compteurs absences:

View File

@ -37,7 +37,7 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from app.scodoc import mails
from app.scodoc import sco_emails
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log
@ -62,7 +62,7 @@ def abs_notify(context, etudid, date):
debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
nbabs = sco_abs.CountAbs(context, etudid, debut=debut_sem, fin=fin_sem)
nbabsjust = context.CountAbsJust(etudid, debut=debut_sem, fin=fin_sem)
nbabsjust = sco_abs.CountAbsJust(context, etudid, debut=debut_sem, fin=fin_sem)
do_abs_notify(context, sem, etudid, date, nbabs, nbabsjust)
@ -119,7 +119,7 @@ def abs_notify_send(
for email in destinations:
del msg["To"]
msg["To"] = email
mails.sendEmail(context, msg)
sco_emails.sendEmail(context, msg)
ndb.SimpleQuery(
context,
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""",

View File

@ -39,6 +39,7 @@ from app.scodoc.scolog import logdb
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_abs
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_find_etud
from app.scodoc import sco_formsemestre
@ -124,9 +125,7 @@ def doSignaleAbsence(
if moduleimpl_id and moduleimpl_id != "NULL":
mod = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
formsemestre_id = mod["formsemestre_id"]
nt = context.Notes._getNotesCache().get_NotesTable(
context.Notes, formsemestre_id
)
nt = sco_core.get_notes_cache(context).get_NotesTable(context, formsemestre_id)
ues = nt.get_ues(etudid=etudid)
for ue in ues:
modimpls = nt.get_modimpls(ue_id=ue["ue_id"])
@ -185,9 +184,7 @@ def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
require_module = sco_preferences.get_preference(
context, "abs_require_module", formsemestre_id
)
nt = context.Notes._getNotesCache().get_NotesTable(
context.Notes, formsemestre_id
)
nt = sco_core.get_notes_cache(context).get_NotesTable(context, formsemestre_id)
ues = nt.get_ues(etudid=etudid)
if require_module:
menu_module = """
@ -740,7 +737,7 @@ def CalAbs(context, REQUEST=None): # etud implied
datedebut = str(anneescolaire) + "-08-31"
datefin = str(anneescolaire + 1) + "-07-31"
nbabs = sco_abs.CountAbs(context, etudid=etudid, debut=datedebut, fin=datefin)
nbabsjust = context.CountAbsJust(etudid=etudid, debut=datedebut, fin=datefin)
nbabsjust = sco_abs.CountAbsJust(context, etudid=etudid, debut=datedebut, fin=datefin)
events = []
for a in sco_abs.ListeAbsJust(context, etudid=etudid, datedebut=datedebut):
events.append(
@ -967,7 +964,7 @@ def _TablesAbsEtud(
ex = []
for ev in a["evals"]:
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
context.Notes, moduleimpl_id=ev["moduleimpl_id"]
context, moduleimpl_id=ev["moduleimpl_id"]
)[0]
if format == "html":
ex.append(
@ -984,7 +981,7 @@ def _TablesAbsEtud(
ex = []
for ev in a.get("absent", []):
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
context.Notes, moduleimpl_id=ev["moduleimpl_id"]
context, moduleimpl_id=ev["moduleimpl_id"]
)[0]
if format == "html":
ex.append(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -715,7 +715,9 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
)
if not edit:
# creation du semestre
formsemestre_id = context.do_formsemestre_create(tf[2], REQUEST)
formsemestre_id = sco_formsemestre.do_formsemestre_create(
context, tf[2], REQUEST
)
# creation des modules
for module_id in tf[2]["tf-checked"]:
modargs = {
@ -1014,7 +1016,7 @@ def do_formsemestre_clone(
args["date_debut"] = date_debut
args["date_fin"] = date_fin
args["etat"] = 1 # non verrouillé
formsemestre_id = context.do_formsemestre_create(args, REQUEST)
formsemestre_id = sco_formsemestre.do_formsemestre_create(context, args, REQUEST)
log("created formsemestre %s" % formsemestre_id)
# 2- create moduleimpls
mods_orig = sco_moduleimpl.do_moduleimpl_list(
@ -1041,7 +1043,9 @@ def do_formsemestre_clone(
args = e.copy()
del args["jour"] # erase date
args["moduleimpl_id"] = mid
_ = context.do_evaluation_create(REQUEST=REQUEST, **args)
_ = sco_evaluations.do_evaluation_create(
context, REQUEST=REQUEST, **args
)
# 3- copy uecoefs
objs = sco_formsemestre.formsemestre_uecoef_list(
@ -1196,14 +1200,18 @@ def do_formsemestres_associate_new_version(context, formsemestre_ids, REQUEST=No
cnx = ndb.GetDBConnexion()
# New formation:
formation_id, modules_old2new, ues_old2new = context.formation_create_new_version(
formation_id, redirect=False, REQUEST=REQUEST
(
formation_id,
modules_old2new,
ues_old2new,
) = sco_formations.formation_create_new_version(
context, formation_id, redirect=False, REQUEST=REQUEST
)
for formsemestre_id in formsemestre_ids:
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
sem["formation_id"] = formation_id
context.do_formsemestre_edit(sem, cnx=cnx, html_quote=False)
sco_formsemestre.do_formsemestre_edit(context, sem, cnx=cnx, html_quote=False)
_reassociate_moduleimpls(
context, cnx, formsemestre_id, ues_old2new, modules_old2new
)
@ -1339,7 +1347,7 @@ def do_formsemestre_delete(context, formsemestre_id, REQUEST):
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
# --- Destruction des modules de ce semestre
mods = context.do_moduleimpl_list(formsemestre_id=formsemestre_id)
mods = sco_moduleimpl.do_moduleimpl_list(context, formsemestre_id=formsemestre_id)
for mod in mods:
# evaluations
evals = sco_evaluations.do_evaluation_list(
@ -1474,7 +1482,7 @@ def formsemestre_change_lock(
if etat not in (0, 1):
raise ScoValueError("formsemestre_lock: invalid value for etat (%s)" % etat)
args = {"formsemestre_id": formsemestre_id, "etat": etat}
context.do_formsemestre_edit(args)
sco_formsemestre.do_formsemestre_edit(context, args)
if REQUEST:
return REQUEST.RESPONSE.redirect(
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
@ -1517,7 +1525,7 @@ def formsemestre_change_publication_bul(
"formsemestre_change_publication_bul: invalid value for etat (%s)" % etat
)
args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat}
context.do_formsemestre_edit(args)
sco_formsemestre.do_formsemestre_edit(context, args)
if REQUEST:
return REQUEST.RESPONSE.redirect(
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
@ -1529,7 +1537,6 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
"""Changement manuel des coefficients des UE capitalisées."""
from app.scodoc import notes_table
context = context.Notes # si appele d'en haut, eg par exception ScoValueError
ok, err = sco_permissions_check.check_access_diretud(
context, formsemestre_id, REQUEST
)

View File

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

View File

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

View File

@ -346,7 +346,9 @@ def formsemestre_status_menubar(context, sem, REQUEST):
"title": "Créer/modifier les partitions...",
"endpoint": "scolar.editPartitionForm",
"args": {"formsemestre_id": formsemestre_id},
"enabled": sco_groups.can_change_groups(context, REQUEST, formsemestre_id),
"enabled": sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
),
},
]
# 1 item / partition:
@ -355,7 +357,10 @@ def formsemestre_status_menubar(context, sem, REQUEST):
)
submenu = []
enabled = (
sco_groups.can_change_groups(context, REQUEST, formsemestre_id) and partitions
sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
)
and partitions
)
for partition in partitions:
submenu.append(
@ -522,10 +527,6 @@ def formsemestre_page_title(context, REQUEST):
"""Element HTML decrivant un semestre (barre de menu et infos)
Cherche dans REQUEST si un semestre est défini (formsemestre_id ou moduleimpl ou evaluation ou group)
"""
try:
context = context.Notes
except:
pass
formsemestre_id = retreive_formsemestre_from_request(context, REQUEST)
#
if not formsemestre_id:
@ -873,13 +874,17 @@ def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
H.append("</table>")
else:
H.append('<p class="help indent">Aucun groupe dans cette partition')
if sco_groups.can_change_groups(context, REQUEST, formsemestre_id):
if sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
H.append(
' (<a href="affectGroups?partition_id=%s" class="stdlink">créer</a>)'
% partition["partition_id"]
)
H.append("</p>")
if sco_groups.can_change_groups(context, REQUEST, formsemestre_id):
if sco_groups.sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
H.append(
'<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>'
% formsemestre_id

View File

@ -968,7 +968,7 @@ def formsemestre_fix_validation_ues(context, formsemestre_id, REQUEST=None):
) # > get_etudids, get_etud_decision_sem, get_ues, get_etud_decision_ues, get_etud_ue_status
etudids = nt.get_etudids()
modifs = [] # liste d'étudiants modifiés
cnx = context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
for etudid in etudids:
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
Se = sco_parcours_dut.SituationEtudParcours(context, etud, formsemestre_id)
@ -1046,7 +1046,7 @@ def formsemestre_fix_validation_ues(context, formsemestre_id, REQUEST=None):
def formsemestre_validation_suppress_etud(context, formsemestre_id, etudid):
"""Suppression des decisions de jury pour un etudiant."""
log("formsemestre_validation_suppress_etud( %s, %s)" % (formsemestre_id, etudid))
cnx = context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
args = {"formsemestre_id": formsemestre_id, "etudid": etudid}
try:
@ -1228,7 +1228,7 @@ def do_formsemestre_validate_previous_ue(
cette UE (utile seulement pour les semestres extérieurs).
"""
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
cnx = context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
nt = sco_core.get_notes_cache(context).get_NotesTable(
context, formsemestre_id
) # > get_etud_ue_status

View File

@ -51,26 +51,12 @@ from app.scodoc import html_sco_header
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_permissions_check
from app.scodoc.sco_exceptions import ScoException, AccessDenied, ScoValueError
from app.scodoc.sco_permissions import Permission
from app.scodoc.TrivialFormulator import TrivialFormulator
def can_change_groups(context, REQUEST, formsemestre_id):
"Vrai si l'utilisateur peut changer les groupes dans ce semestre"
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if sem["etat"] != "1":
return False # semestre verrouillé
authuser = REQUEST.AUTHENTICATED_USER
if authuser.has_permission(Permission.ScoEtudChangeGroups):
return True # admin, chef dept
uid = str(authuser)
if uid in sem["responsables"]:
return True
return False
def checkGroupName(
groupName,
): # XXX unused: now allow any string as a group or partition name
@ -275,6 +261,8 @@ def get_group_members(context, group_id, etat=None):
def get_group_infos(context, group_id, etat=None): # was _getlisteetud
"""legacy code: used by group_list and trombino"""
from app.scodoc import sco_formsemestre
cnx = ndb.GetDBConnexion()
group = get_group(context, group_id)
sem = sco_formsemestre.get_formsemestre(context, group["formsemestre_id"])
@ -446,13 +434,15 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
<etud etuid="" sexe="" nom="" prenom="" origin=""/>
</groupe>
"""
from app.scodoc import sco_formsemestre
t0 = time.time()
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
groups = get_partition_groups(context, partition)
nt = context.Notes._getNotesCache().get_NotesTable(
context.Notes, formsemestre_id
nt = sco_core.get_notes_cache(context).get_NotesTable(
context, formsemestre_id
) # > inscrdict
etuds_set = set(nt.inscrdict)
# XML response:
@ -605,7 +595,9 @@ def change_etud_group_in_partition(
)
cnx.commit()
# 4- invalidate cache
context.Notes._inval_cache(formsemestre_id=formsemestre_id) # > change etud group
sco_core.inval_cache(
context, formsemestre_id=formsemestre_id
) # > change etud group
def setGroups(
@ -621,9 +613,11 @@ def setGroups(
groupsToCreate: lignes "group_name;etudid;...\n"
groupsToDelete: group_id;group_id;...
"""
from app.scodoc import sco_formsemestre
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log("***setGroups: partition_id=%s" % partition_id)
log("groupsLists=%s" % groupsLists)
@ -710,7 +704,9 @@ def createGroup(context, partition_id, group_name="", default=False, REQUEST=Non
"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if REQUEST and not can_change_groups(context, REQUEST, formsemestre_id):
if REQUEST and not sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
#
if group_name:
@ -747,7 +743,9 @@ def suppressGroup(context, group_id, partition_id=None, REQUEST=None):
else:
partition_id = group["partition_id"]
partition = get_partition(context, partition_id)
if not can_change_groups(context, REQUEST, partition["formsemestre_id"]):
if not sco_permissions_check.can_change_groups(
context, REQUEST, partition["formsemestre_id"]
):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log(
"suppressGroup: group_id=%s group_name=%s partition_name=%s"
@ -766,7 +764,9 @@ def partition_create(
redirect=1,
):
"""Create a new partition"""
if REQUEST and not can_change_groups(context, REQUEST, formsemestre_id):
if REQUEST and not sco_permissions_check.can_change_groups(
context, REQUEST, formsemestre_id
):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if partition_name:
partition_name = partition_name.strip()
@ -810,7 +810,7 @@ def getArrowIconsTags(context, REQUEST):
def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
"""Form to create/suppress partitions"""
# ad-hoc form
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
partitions = get_partitions_list(context, formsemestre_id)
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST)
@ -940,7 +940,7 @@ def partition_set_attr(context, partition_id, attr, value, REQUEST=None):
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
log("partition_set_attr(%s, %s, %s)" % (partition_id, attr, value))
@ -950,8 +950,8 @@ def partition_set_attr(context, partition_id, attr, value, REQUEST=None):
partition[attr] = value
partitionEditor.edit(cnx, partition)
# invalid bulletin cache
context.Notes._inval_cache(
pdfonly=True, formsemestre_id=partition["formsemestre_id"]
sco_core.inval_cache(
context, pdfonly=True, formsemestre_id=partition["formsemestre_id"]
)
return "enregistré"
@ -963,7 +963,7 @@ def partition_delete(
default partition cannot be suppressed (unless force)"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if not partition["partition_name"] and not force:
@ -1007,7 +1007,7 @@ def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1):
"""Move before/after previous one (decrement/increment numero)"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
#
redirect = int(redirect)
@ -1042,7 +1042,7 @@ def partition_rename(context, partition_id, REQUEST=None):
"""Form to rename a partition"""
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
H = ["<h2>Renommer une partition</h2>"]
tf = TrivialFormulator(
@ -1103,7 +1103,7 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
"Partition %s déjà existante dans ce semestre !" % partition_name
)
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
redirect = int(redirect)
cnx = ndb.GetDBConnexion()
@ -1128,7 +1128,7 @@ def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1):
if group["group_name"] is None:
raise ValueError("can't set a name to default group")
formsemestre_id = group["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
redirect = int(redirect)
cnx = ndb.GetDBConnexion()
@ -1145,7 +1145,7 @@ def group_rename(context, group_id, REQUEST=None):
"""Form to rename a group"""
group = get_group(context, group_id)
formsemestre_id = group["formsemestre_id"]
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
tf = TrivialFormulator(
@ -1189,11 +1189,13 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
"""Reparti les etudiants dans des groupes dans une partition, en respectant le niveau
et la mixité.
"""
from app.scodoc import sco_formsemestre
partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"]
# renvoie sur page édition groupes
dest_url = "affectGroups?partition_id=%s" % partition_id
if not can_change_groups(context, REQUEST, formsemestre_id):
if not sco_permissions_check.can_change_groups(context, REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
@ -1261,8 +1263,8 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
createGroup(context, partition_id, group_name, REQUEST=REQUEST)
)
#
nt = context.Notes._getNotesCache().get_NotesTable(
context.Notes, formsemestre_id
nt = sco_core.get_notes_cache(context).get_NotesTable(
context, formsemestre_id
) # > identdict
identdict = nt.identdict
# build: { civilite : liste etudids trie par niveau croissant }
@ -1270,7 +1272,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
listes = {}
for civilite in civilites:
listes[civilite] = [
(get_prev_moy(context.Notes, x["etudid"], formsemestre_id), x["etudid"])
(get_prev_moy(context, x["etudid"], formsemestre_id), x["etudid"])
for x in identdict.values()
if x["civilite"] == civilite
]
@ -1474,6 +1476,8 @@ def form_group_choice(
"""Partie de formulaire pour le choix d'un ou plusieurs groupes.
Variable : group_ids
"""
from app.scodoc import sco_formsemestre
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if display_sem_title:
sem_title = "%s: " % sem["titremois"]

View File

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

View File

@ -791,10 +791,10 @@ def groups_table(
sco_etud.etud_add_lycee_infos(etud)
# et ajoute le parcours
Se = sco_parcours_dut.SituationEtudParcours(
context.Notes, etud, groups_infos.formsemestre_id
context, etud, groups_infos.formsemestre_id
)
m["parcours"] = Se.get_parcours_descr()
m["codeparcours"], _ = sco_report.get_codeparcoursetud(context.Notes, etud)
m["codeparcours"], _ = sco_report.get_codeparcoursetud(context, etud)
def dicttakestr(d, keys):
r = []

View File

@ -53,6 +53,7 @@ from app.scodoc.sco_exceptions import (
ScoGenError,
)
from app.scodoc import html_sco_header
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups
@ -231,7 +232,7 @@ def students_import_excel(
"import students from Excel file"
diag = scolars_import_excel_file(
csvfile,
context.Notes,
context,
REQUEST,
formsemestre_id=formsemestre_id,
check_homonyms=check_homonyms,
@ -268,7 +269,7 @@ def scolars_import_excel_file(
et les inscrit dans le semestre indiqué (et à TOUS ses modules)
"""
log("scolars_import_excel_file: formsemestre_id=%s" % formsemestre_id)
cnx = context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
annee_courante = time.localtime()[0]
always_require_ine = sco_preferences.get_preference(context, "always_require_ine")
@ -489,11 +490,40 @@ def scolars_import_excel_file(
cnx.commit()
# Invalide les caches des semestres dans lesquels on a inscrit des etudiants:
context.Notes._inval_cache(formsemestre_id_list=formsemestre_to_invalidate)
sco_core.inval_cache(context, formsemestre_id_list=formsemestre_to_invalidate)
return diag
def students_import_admission(
context, csvfile, type_admission="", REQUEST=None, formsemestre_id=None
):
"import donnees admission from Excel file (v2016)"
diag = scolars_import_admission(
csvfile,
context,
REQUEST,
formsemestre_id=formsemestre_id,
type_admission=type_admission,
)
if REQUEST:
H = [
html_sco_header.sco_header(
context, REQUEST, page_title="Import données admissions"
)
]
H.append("<p>Import terminé !</p>")
H.append(
'<p><a class="stdlink" href="%s">Continuer</a></p>'
% "formsemestre_status?formsemestre_id=%s"
% formsemestre_id
)
if diag:
H.append("<p>Diagnostic: <ul><li>%s</li></ul></p>" % "</li><li>".join(diag))
return "\n".join(H) + html_sco_header.sco_footer(REQUEST)
def _import_one_student(
context,
cnx,

View File

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

View File

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

View File

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

View File

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

View File

@ -70,18 +70,18 @@ def _menuScolarite(context, authuser, sem, etudid):
if ins["etat"] != "D":
dem_title = "Démission"
dem_url = "formDem"
dem_url = "scolar.formDem"
else:
dem_title = "Annuler la démission"
dem_url = "doCancelDem"
dem_url = "scolar.doCancelDem"
# Note: seul un etudiant inscrit (I) peut devenir défaillant.
if ins["etat"] != sco_codes_parcours.DEF:
def_title = "Déclarer défaillance"
def_url = "formDef"
def_url = "scolar.formDef"
elif ins["etat"] == sco_codes_parcours.DEF:
def_title = "Annuler la défaillance"
def_url = "doCancelDef"
def_url = "scolar.doCancelDef"
def_enabled = (
(ins["etat"] != "D")
and authuser.has_permission(Permission.ScoEtudInscrit)
@ -211,7 +211,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
for sem in info["sems"]:
if sem["ins"]["etat"] != "I":
descr, _ = etud_descr_situation_semestre(
context.Notes,
context,
etudid,
sem["formsemestre_id"],
info["ne"],
@ -239,10 +239,10 @@ def ficheEtud(context, etudid=None, REQUEST=None):
if info["sems"]:
Se = sco_parcours_dut.SituationEtudParcours(
context.Notes, etud, info["last_formsemestre_id"]
context, etud, info["last_formsemestre_id"]
)
info["liste_inscriptions"] = formsemestre_recap_parcours_table(
context.Notes,
context,
Se,
etudid,
with_links=False,
@ -535,7 +535,7 @@ def etud_info_html(context, etudid, with_photo="1", REQUEST=None, debug=False):
Used for popups information windows.
"""
try:
context = context.Notes
context = context
except:
pass
# log('etud_info_html: %s' % REQUEST.QUERY_STRING)
@ -551,7 +551,7 @@ def etud_info_html(context, etudid, with_photo="1", REQUEST=None, debug=False):
)
# experimental: may be too slow to be here
etud["codeparcours"], etud["decisions_jury"] = sco_report.get_codeparcoursetud(
context.Notes, etud, prefix="S", separator=", "
context, etud, prefix="S", separator=", "
)
bac = sco_bac.Baccalaureat(etud["bac"], etud["specialite"])

View File

@ -543,7 +543,7 @@ class SituationEtudParcoursGeneric:
"""Enregistre la decision (instance de DecisionSem)
Enregistre codes semestre et UE, et autorisations inscription.
"""
cnx = self.context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
# -- check
if decision.code_etat in self.parcours.UNUSED_CODES:
raise ScoValueError("code decision invalide dans ce parcours")
@ -909,7 +909,7 @@ def formsemestre_validate_ues(
Les UE des semestres NON ASSIDUS ne sont jamais validées (code AJ).
"""
valid_semestre = CODES_SEM_VALIDES.get(code_etat_sem, False)
cnx = context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
nt = sco_core.get_notes_cache(context).get_NotesTable(
context, formsemestre_id
) # > get_ues, get_etud_ue_status

View File

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

View File

@ -112,11 +112,12 @@ get_base_preferences(context, formsemestre_id)
"""
from flask import g
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc import sco_core
from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import ScoValueError, ScoException
from app.scodoc.TrivialFormulator import TrivialFormulator
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
_SCO_BASE_PREFERENCES = {} # { URL: BasePreferences instance }
@ -1919,7 +1920,7 @@ class BasePreferences(object):
# les preferences peuvent affecter les PDF cachés et les notes calculées:
if modif:
self.context.Notes._inval_cache(pdfonly=False) # > modif preferences
sco_core.inval_cache(self.context, pdfonly=False) # > modif preferences
finally:
scu.GSL.release()
@ -1947,7 +1948,7 @@ class BasePreferences(object):
if pdb:
log("deleting pref sem=%s %s" % (formsemestre_id, name))
self._editor.delete(cnx, pdb[0]["pref_id"])
self.context.Notes._inval_cache(pdfonly=False) # > modif preferences
sco_core.inval_cache(self.context, pdfonly=False) # > modif preferences
finally:
scu.GSL.release()
@ -2091,7 +2092,9 @@ class SemPreferences(object):
) # a bug !
sem = sco_formsemestre.get_formsemestre(self.context, self.formsemestre_id)
H = [
self.context.Notes.html_sem_header(REQUEST, "Préférences du semestre", sem),
html_sco_header.html_sem_header(
self.context, REQUEST, "Préférences du semestre", sem
),
"""
<p class="help">Les paramètres définis ici ne s'appliqueront qu'à ce semestre.</p>
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>

View File

@ -46,6 +46,7 @@ from app.scodoc.sco_permissions import Permission
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
from app.scodoc import html_sco_header
from app.scodoc import htmlutils
from app.scodoc import sco_abs
from app.scodoc import sco_core
from app.scodoc import sco_edit_module
from app.scodoc import sco_evaluations
@ -471,7 +472,7 @@ def _notes_add(context, uid, evaluation_id, notes, comment=None, do_it=True):
# Recherche notes existantes
NotesDB = sco_evaluations.do_evaluation_get_all_notes(context, evaluation_id)
# Met a jour la base
cnx = context.GetDBConnexion(autocommit=False)
cnx = ndb.GetDBConnexion(autocommit=False)
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
nb_changed = 0
nb_suppress = 0

View File

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

View File

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

View File

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

View File

@ -10,4 +10,4 @@ essais_bp = Blueprint("essais", __name__)
from app.views import notes, scolar, absences, essais
scolar.context.Notes = notes.context
scolar.context.Notes = notes.context # XXX transitoire #sco8

View File

@ -81,8 +81,10 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_abs
from app.scodoc import sco_abs_notification, sco_abs_views
from app.scodoc import sco_abs_notification
from app.scodoc import sco_abs_views
from app.scodoc import sco_compute_moy
from app.scodoc import sco_core
from app.scodoc import sco_etud
from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre
@ -238,7 +240,7 @@ def SignaleAbsenceGrHebdo(
[
x["etudid"]
for x in sco_moduleimpl.do_moduleimpl_inscription_list(
context.Notes, moduleimpl_id=moduleimpl_id
context, moduleimpl_id=moduleimpl_id
)
]
)
@ -248,7 +250,7 @@ def SignaleAbsenceGrHebdo(
else:
# Si aucun etudiant n'est inscrit au module choisi...
moduleimpl_id = None
nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_id)
nt = sco_core.get_notes_cache(context).get_NotesTable(context, formsemestre_id)
sem = sco_formsemestre.do_formsemestre_list(
context, {"formsemestre_id": formsemestre_id}
)[0]
@ -402,7 +404,7 @@ def SignaleAbsenceGrSemestre(
[
x["etudid"]
for x in sco_moduleimpl.do_moduleimpl_inscription_list(
context.Notes, moduleimpl_id=moduleimpl_id
context, moduleimpl_id=moduleimpl_id
)
]
)
@ -421,9 +423,7 @@ def SignaleAbsenceGrSemestre(
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
if etuds:
nt = context.Notes._getNotesCache().get_NotesTable(
context.Notes, formsemestre_id
)
nt = sco_core.get_notes_cache(context).get_NotesTable(context, formsemestre_id)
sem = sco_formsemestre.do_formsemestre_list(
context, {"formsemestre_id": formsemestre_id}
)[0]
@ -638,8 +638,8 @@ def _gen_form_saisie_groupe(
# UE capitalisee dans semestre courant ?
cap = []
if etud["cursem"]:
nt = context.Notes._getNotesCache().get_NotesTable(
context.Notes, etud["cursem"]["formsemestre_id"]
nt = sco_core.get_notes_cache(context).get_NotesTable(
context, etud["cursem"]["formsemestre_id"]
) # > get_ues, get_etud_ue_status
for ue in nt.get_ues():
status = nt.get_etud_ue_status(etudid, ue["ue_id"])
@ -765,8 +765,8 @@ def EtatAbsencesGr(
nbabs = sco_abs.CountAbs(
context, etudid=etud["etudid"], debut=datedebut, fin=datefin
)
nbabsjust = context.CountAbsJust(
etudid=etud["etudid"], debut=datedebut, fin=datefin
nbabsjust = sco_abs.CountAbsJust(
context, etudid=etud["etudid"], debut=datedebut, fin=datefin
)
nbjustifs_noabs = len(
sco_abs.ListeJustifs(
@ -846,8 +846,8 @@ def EtatAbsencesGr(
init_qtip=True,
javascripts=["js/etud_info.js"],
),
html_title=context.Notes.html_sem_header(
REQUEST, "%s" % title, sem, with_page_header=False
html_title=html_sco_header.html_sem_header(
context, REQUEST, "%s" % title, sem, with_page_header=False
)
+ "<p>Période du %s au %s (nombre de <b>demi-journées</b>)<br/>" % (debut, fin),
base_url="%s&formsemestre_id=%s&debut=%s&fin=%s"
@ -918,11 +918,11 @@ def EtatAbsencesDate(
)
if (nbabsam != 0) or (nbabspm != 0):
nbetud += 1
nbabsjustam = context.CountAbsJust(
etudid=etud["etudid"], debut=dateiso, fin=dateiso, matin=1
nbabsjustam = sco_abs.CountAbsJust(
context, etudid=etud["etudid"], debut=dateiso, fin=dateiso, matin=1
)
nbabsjustpm = context.CountAbsJust(
etudid=etud["etudid"], debut=dateiso, fin=dateiso, matin=0
nbabsjustpm = sco_abs.CountAbsJust(
context, etudid=etud["etudid"], debut=dateiso, fin=dateiso, matin=0
)
H.append(
"""<tr bgcolor="#FFFFFF"><td>
@ -1210,7 +1210,8 @@ def deleteBilletAbsence(context, billet_id, REQUEST=None, dialog_confirmed=False
)
if not dialog_confirmed:
tab = _tableBillets(context, billets)
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Supprimer ce billet ?</h2>""" + tab.html(),
dest_url="",
REQUEST=REQUEST,

View File

@ -73,7 +73,7 @@ def sidebar(context, REQUEST):
"barre gauche (overide std sco sidebar)"
# rewritten from legacy DTML code
# XXX rare cas restant d'utilisation de l'acquisition Zope2: à revoir
params = {"ScoURL": context.ScoURL()}
params = {"ScoURL": scu.ScoURL()}
H = [
"""<div id="sidebar-container">
<div class="sidebar">""",
@ -285,7 +285,7 @@ def entreprise_contact_list(context, entreprise_id=None, format="html", REQUEST=
c["etud"] = context.getEtudInfo(etudid=c["etudid"], filled=1)[0]
c["etudnom"] = c["etud"]["nomprenom"]
c["_etudnom_target"] = "%s/ficheEtud?etudid=%s" % (
context.ScoURL(),
scu.ScoURL(),
c["etudid"],
)
else:
@ -1012,7 +1012,7 @@ def entreprise_delete(context, entreprise_id, REQUEST=None):
for c in Cts:
H.append("""<li>%(date)s %(description)s</li>""" % c)
H.append("""</ul>""")
tf = context.TrivialFormulator(
tf = TrivialFormulator(
REQUEST.URL0,
REQUEST.form,
(("entreprise_id", {"input_type": "hidden"}),),
@ -1290,7 +1290,7 @@ def entreprise_edit(context, entreprise_id, REQUEST=None, start=1):
etud = etud[0]
H.append(
"""<a href="%s/ficheEtud?etudid=%s">%s</a>"""
% (context.ScoURL(), c["etudid"], etud["nomprenom"])
% (scu.ScoURL(), c["etudid"], etud["nomprenom"])
)
if c["description"]:
H.append("(%s)" % c["description"])

View File

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

View File

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

View File

@ -85,10 +85,11 @@ from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import html_sidebar
from app.scodoc import imageresize
from app.scodoc import ImportScolars
from app.scodoc import sco_import_etuds
from app.scodoc import sco_abs
from app.scodoc import sco_archives_etud
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_core
from app.scodoc import sco_debouche
from app.scodoc import sco_dept
from app.scodoc import sco_dump_db
@ -197,7 +198,7 @@ def edit_preferences(context, REQUEST):
def formsemestre_edit_preferences(context, formsemestre_id, REQUEST):
"""Edit preferences for a semestre"""
authuser = REQUEST.AUTHENTICATED_USER
sem = sco_formsemestre.get_formsemestre(context.Notes, formsemestre_id)
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
ok = (
authuser.has_permission(Permission.ScoImplement)
or ((str(authuser) in sem["responsables"]) and sem["resp_can_edit"])
@ -756,7 +757,8 @@ def formSuppressPhoto(context, etudid=None, REQUEST=None, dialog_confirmed=False
@scodoc7func(context)
def formDem(context, etudid, formsemestre_id, REQUEST):
"Formulaire Démission Etudiant"
return context._formDem_of_Def(
return _formDem_of_Def(
context,
etudid,
formsemestre_id,
REQUEST=REQUEST,
@ -770,7 +772,8 @@ def formDem(context, etudid, formsemestre_id, REQUEST):
@scodoc7func(context)
def formDef(context, etudid, formsemestre_id, REQUEST):
"Formulaire Défaillance Etudiant"
return context._formDem_of_Def(
return _formDem_of_Def(
context,
etudid,
formsemestre_id,
REQUEST=REQUEST,
@ -832,7 +835,8 @@ def _formDem_of_Def(
@scodoc7func(context)
def doDemEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=None):
"Déclare la démission d'un etudiant dans le semestre"
return context._doDem_or_Def_Etudiant(
return _do_dem_or_def_etud(
context,
etudid,
formsemestre_id,
event_date=event_date,
@ -848,7 +852,8 @@ def doDemEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=Non
@scodoc7func(context)
def doDefEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=None):
"Déclare la défaillance d'un etudiant dans le semestre"
return context._doDem_or_Def_Etudiant(
return _do_dem_or_def_etud(
context,
etudid,
formsemestre_id,
event_date=event_date,
@ -859,7 +864,7 @@ def doDefEtudiant(context, etudid, formsemestre_id, event_date=None, REQUEST=Non
)
def _doDem_or_Def_Etudiant(
def _do_dem_or_def_etud(
context,
etudid,
formsemestre_id,
@ -908,7 +913,8 @@ def doCancelDem(
context, etudid, formsemestre_id, dialog_confirmed=False, args=None, REQUEST=None
):
"Annule une démission"
return context._doCancelDem_or_Def(
return _do_cancel_dem_or_def(
context,
etudid,
formsemestre_id,
dialog_confirmed=dialog_confirmed,
@ -929,7 +935,8 @@ def doCancelDef(
context, etudid, formsemestre_id, dialog_confirmed=False, args=None, REQUEST=None
):
"Annule la défaillance de l'étudiant"
return context._doCancelDem_or_Def(
return _do_cancel_dem_or_def(
context,
etudid,
formsemestre_id,
dialog_confirmed=dialog_confirmed,
@ -943,7 +950,7 @@ def doCancelDef(
)
def _doCancelDem_or_Def(
def _do_cancel_dem_or_def(
context,
etudid,
formsemestre_id,
@ -1009,7 +1016,7 @@ def _doCancelDem_or_Def(
@scodoc7func(context)
def etudident_create_form(context, REQUEST=None):
"formulaire creation individuelle etudiant"
return context._etudident_create_or_edit_form(REQUEST, edit=False)
return _etudident_create_or_edit_form(context, REQUEST, edit=False)
@bp.route("/etudident_edit_form")
@ -1017,7 +1024,7 @@ def etudident_create_form(context, REQUEST=None):
@scodoc7func(context)
def etudident_edit_form(context, REQUEST=None):
"formulaire edition individuelle etudiant"
return context._etudident_create_or_edit_form(REQUEST, edit=True)
return _etudident_create_or_edit_form(context, REQUEST, edit=True)
def _etudident_create_or_edit_form(context, REQUEST, edit):
@ -1411,8 +1418,8 @@ def _etudident_create_or_edit_form(context, REQUEST, edit):
# Inval semesters with this student:
to_inval = [s["formsemestre_id"] for s in etud["sems"]]
if to_inval:
context.Notes._inval_cache(
formsemestre_id_list=to_inval
sco_core.inval_cache(
context, formsemestre_id_list=to_inval
) # > etudident_create_or_edit
#
return REQUEST.RESPONSE.redirect("ficheEtud?etudid=" + etudid)
@ -1476,7 +1483,7 @@ def etudident_delete(context, etudid, dialog_confirmed=False, REQUEST=None):
# Inval semestres où il était inscrit:
to_inval = [s["formsemestre_id"] for s in etud["sems"]]
if to_inval:
context.Notes._inval_cache(formsemestre_id_list=to_inval) # >
sco_core.inval_cache(context, formsemestre_id_list=to_inval) # >
return REQUEST.RESPONSE.redirect(
scu.ScoURL() + r"?head_message=Etudiant%20supprimé"
)
@ -1499,8 +1506,11 @@ def check_group_apogee(
cnx = ndb.GetDBConnexion()
H = [
context.Notes.html_sem_header(
REQUEST, "Etudiants du %s" % (group["group_name"] or "semestre"), sem
html_sco_header.html_sem_header(
context,
REQUEST,
"Etudiants du %s" % (group["group_name"] or "semestre"),
sem,
),
'<table class="sortable" id="listegroupe">',
"<tr><th>Nom</th><th>Nom usuel</th><th>Prénom</th><th>Mail</th><th>NIP (ScoDoc)</th><th>Apogée</th></tr>",
@ -1628,7 +1638,7 @@ def check_group_apogee(
def form_students_import_excel(context, REQUEST, formsemestre_id=None):
"formulaire import xls"
if formsemestre_id:
sem = sco_formsemestre.get_formsemestre(context.Notes, formsemestre_id)
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
dest_url = (
scu.ScoURL() + "/formsemestre_status?formsemestre_id=%s" % formsemestre_id
)
@ -1736,7 +1746,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
<table>
<tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr>"""
]
for t in ImportScolars.sco_import_format(
for t in sco_import_etuds.sco_import_format(
with_codesemestre=(formsemestre_id == None)
):
if int(t[3]):
@ -1752,7 +1762,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
elif tf[0] == -1:
return REQUEST.RESPONSE.redirect(dest_url)
else:
return ImportScolars.students_import_excel(
return sco_import_etuds.students_import_excel(
context,
tf[2]["csvfile"],
REQUEST=REQUEST,
@ -1771,8 +1781,8 @@ def import_generate_excel_sample(context, REQUEST, with_codesemestre="1"):
with_codesemestre = int(with_codesemestre)
else:
with_codesemestre = 0
format = ImportScolars.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample(
format = sco_import_etuds.sco_import_format()
data = sco_import_etuds.sco_import_generate_excel_sample(
format, with_codesemestre, exclude_cols=["photo_filename"], REQUEST=REQUEST
)
return sco_excel.sendExcelFile(REQUEST, data, "ImportEtudiants.xls")
@ -1787,13 +1797,13 @@ def import_generate_admission_sample(context, REQUEST, formsemestre_id):
group = sco_groups.get_group(
context, sco_groups.get_default_group(context, formsemestre_id)
)
fmt = ImportScolars.sco_import_format()
data = ImportScolars.sco_import_generate_excel_sample(
fmt = sco_import_etuds.sco_import_format()
data = sco_import_etuds.sco_import_generate_excel_sample(
fmt,
only_tables=["identite", "admissions", "adresse"],
exclude_cols=["nationalite", "foto", "photo_filename"],
group_ids=[group["group_id"]],
context=context.Notes,
context=context,
REQUEST=REQUEST,
)
return sco_excel.sendExcelFile(REQUEST, data, "AdmissionEtudiants.xls")
@ -1889,7 +1899,7 @@ def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None
Seule la première feuille du classeur sera utilisée.
<div id="adm_table_description_format">
"""
+ ImportScolars.adm_table_description_format(context).html()
+ sco_import_etuds.adm_table_description_format(context).html()
+ """</div>"""
)
@ -1900,7 +1910,8 @@ def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None
scu.ScoURL() + "/formsemestre_status?formsemestre_id=" + formsemestre_id
)
else:
return context._students_import_admission(
return sco_import_etuds.students_import_admission(
context,
tf[2]["csvfile"],
type_admission=tf[2]["type_admission"],
REQUEST=REQUEST,
@ -1908,36 +1919,6 @@ def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None
)
# unpublished
def _students_import_admission(
context, csvfile, type_admission="", REQUEST=None, formsemestre_id=None
):
"import donnees admission from Excel file (v2016)"
diag = ImportScolars.scolars_import_admission(
csvfile,
context.Notes,
REQUEST,
formsemestre_id=formsemestre_id,
type_admission=type_admission,
)
if REQUEST:
H = [
html_sco_header.sco_header(
context, REQUEST, page_title="Import données admissions"
)
]
H.append("<p>Import terminé !</p>")
H.append(
'<p><a class="stdlink" href="%s">Continuer</a></p>'
% "formsemestre_status?formsemestre_id=%s"
% formsemestre_id
)
if diag:
H.append("<p>Diagnostic: <ul><li>%s</li></ul></p>" % "</li><li>".join(diag))
return "\n".join(H) + html_sco_header.sco_footer(REQUEST)
@bp.route("/formsemestre_import_etud_admission")
@permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func(context)
@ -1950,10 +1931,10 @@ def formsemestre_import_etud_admission(
unknowns,
changed_mails,
) = sco_synchro_etuds.formsemestre_import_etud_admission(
context.Notes, formsemestre_id, import_identite=True, import_email=import_email
context, formsemestre_id, import_identite=True, import_email=import_email
)
H = [
context.Notes.html_sem_header(REQUEST, "Reimport données admission"),
html_sco_header.html_sem_header(context, REQUEST, "Reimport données admission"),
"<h3>Opération effectuée</h3>",
]
if no_nip:

10
refactor.py Normal file → Executable file
View File

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