WIP migration vues en cours / tout est en vrac !

This commit is contained in:
Emmanuel Viennet 2021-06-02 22:40:34 +02:00
parent 77f68d1c4c
commit dcb53e9c35
25 changed files with 4503 additions and 85 deletions

View File

@ -50,6 +50,27 @@ Installer le bon vieux `pyExcelerator` dans l'environnement:
python -m unittest tests.test_users
# Work in Progress
## Migration ZScolar
### Méthodes qui ne devraient plus être publiées:
security.declareProtected(ScoView, "get_preferences")
def get_preferences(context, formsemestre_id=None):
"Get preferences for this instance (a dict-like instance)"
return sco_preferences.sem_preferences(context, formsemestre_id)
security.declareProtected(ScoView, "get_preference")
def get_preference(context, name, formsemestre_id=None):
"""Returns value of named preference.
All preferences have a sensible default value (see sco_preferences.py),
this function always returns a usable value for all defined preferences names.
"""
return sco_preferences.get_base_preferences(context).get(formsemestre_id, name)

View File

@ -904,15 +904,16 @@ class ZAbsences(
etuds = [e for e in etuds if e["etudid"] in mod_inscrits]
if not moduleimpl_id:
moduleimpl_id = None
base_url_noweeks = "SignaleAbsenceGrSemestre?datedebut=%s&datefin=%s&%s&destination=%s" % (
base_url_noweeks = (
"SignaleAbsenceGrSemestre?datedebut=%s&datefin=%s&%s&destination=%s"
% (
datedebut,
datefin,
groups_infos.groups_query_args,
urllib.quote(destination),
)
base_url = (
base_url_noweeks + "&nbweeks=%s" % nbweeks
) # sans le moduleimpl_id
)
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
if etuds:
nt = self.Notes._getNotesCache().get_NotesTable(self.Notes, formsemestre_id)

View File

@ -557,7 +557,8 @@ def formsemestre_delete_archive(
dest_url = "formsemestre_list_archives?formsemestre_id=%s" % (formsemestre_id)
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Confirmer la suppression de l'archive du %s ?</h2>
<p>La suppression sera définitive.</p>"""
% PVArchive.get_archive_date(archive_id).strftime("%d/%m/%Y %H:%M"),

View File

@ -201,7 +201,8 @@ def etud_delete_archive(context, REQUEST, etudid, archive_name, dialog_confirmed
archive_id = EtudsArchive.get_id_from_name(context, etudid, archive_name)
dest_url = "ficheEtud?etudid=%s" % etudid
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Confirmer la suppression des fichiers ?</h2>
<p>Fichier associé le %s à l'étudiant %s</p>
<p>La suppression sera définitive.</p>"""

View File

@ -65,7 +65,8 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
H.append('</ul><p><a href="%s">Revenir</a></p>' % context.NotesURL())
else:
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Confirmer la suppression de la formation %(titre)s (%(acronyme)s) ?</h2>
<p><b>Attention:</b> la suppression d'une formation est <b>irréversible</b> et implique la supression de toutes les UE, matières et modules de la formation !
</p>

View File

@ -267,7 +267,8 @@ def ue_delete(
ue = ue[0]
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"<h2>Suppression de l'UE %(titre)s (%(acronyme)s))</h2>" % ue,
dest_url="",
REQUEST=REQUEST,

View File

@ -215,9 +215,9 @@ def apo_semset_maq_status(
)
if apo_dups:
url_list = (
"view_apo_etuds?semset_id=%s&title=Doublons%%20Apogee&nips=%s"
% (semset_id, "&nips=".join(apo_dups))
url_list = "view_apo_etuds?semset_id=%s&title=Doublons%%20Apogee&nips=%s" % (
semset_id,
"&nips=".join(apo_dups),
)
H.append(
'<li><a href="%s">%d étudiants</a> présents dans les <em>plusieurs</em> maquettes Apogée chargées</li>'
@ -659,7 +659,8 @@ def view_apo_csv_delete(
semset = sco_semset.SemSet(context, semset_id=semset_id)
dest_url = "apo_semset_maq_status?semset_id=" + semset_id
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Confirmer la suppression du fichier étape <tt>%s</tt>?</h2>
<p>La suppression sera définitive.</p>"""
% (etape_apo,),

View File

@ -66,6 +66,12 @@ class FormatError(ScoValueError):
pass
class ScoInvalidDept(ScoValueError):
"""departement invalide"""
pass
class ScoConfigurationError(ScoValueError):
"""Configuration invalid"""

View File

@ -1129,7 +1129,8 @@ def formsemestre_associate_new_version(
% (s["formsemestre_id"], checked, disabled, s["titremois"])
)
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Associer à une nouvelle version de formation non verrouillée ?</h2>
<p>Le programme pédagogique ("formation") va être dupliqué pour que vous puissiez le modifier sans affecter les autres semestres. Les autres paramètres (étudiants, notes...) du semestre seront inchangés.</p>
<p>Veillez à ne pas abuser de cette possibilité, car créer trop de versions de formations va vous compliquer la gestion (à vous de garder trace des différences et à ne pas vous tromper par la suite...).
@ -1280,7 +1281,8 @@ def formsemestre_delete2(
"""Delete a formsemestre (confirmation)"""
# Confirmation dialog
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Vous voulez vraiment supprimer ce semestre ???</h2><p>(opération irréversible)</p>""",
dest_url="",
REQUEST=REQUEST,
@ -1423,7 +1425,8 @@ def formsemestre_change_lock(
msg = "déverrouillage"
else:
msg = "verrouillage"
return context.confirmDialog(
return scu.confirm_dialog(
context,
"<h2>Confirmer le %s du semestre ?</h2>" % msg,
helpmsg="""Les notes d'un semestre verrouillé ne peuvent plus être modifiées.
Un semestre verrouillé peut cependant être déverrouillé facilement à tout moment
@ -1462,7 +1465,8 @@ def formsemestre_change_publication_bul(
msg = "non"
else:
msg = ""
return context.confirmDialog(
return scu.confirm_dialog(
context,
"<h2>Confirmer la %s publication des bulletins ?</h2>" % msg,
helpmsg="""Il est parfois utile de désactiver la diffusion des bulletins,
par exemple pendant la tenue d'un jury ou avant harmonisation des notes.

View File

@ -725,12 +725,130 @@ def formsemestre_lists(context, formsemestre_id, REQUEST=None):
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
H = [
context.html_sem_header(REQUEST, "", sem),
context.make_listes_sem(sem, REQUEST),
_make_listes_sem(context, sem, REQUEST),
context.sco_footer(REQUEST),
]
return "\n".join(H)
# genere liste html pour accès aux groupes de ce semestre
# XXX #sco8 vérifier si c'est encore utilisé !
def _make_listes_sem(context, sem, REQUEST=None, with_absences=True):
context = context
authuser = REQUEST.AUTHENTICATED_USER
r = context.ScoURL() # root url
# construit l'URL "destination"
# (a laquelle on revient apres saisie absences)
query_args = cgi.parse_qs(REQUEST.QUERY_STRING)
if "head_message" in query_args:
del query_args["head_message"]
destination = "%s?%s" % (REQUEST.URL, urllib.urlencode(query_args, True))
destination = destination.replace(
"%", "%%"
) # car ici utilisee dans un format string !
#
H = []
# pas de menu absences si pas autorise:
if with_absences and not authuser.has_permission(ScoAbsChange, context):
with_absences = False
#
H.append(
'<h3>Listes de %(titre)s <span class="infostitresem">(%(mois_debut)s - %(mois_fin)s)</span></h3>'
% sem
)
formsemestre_id = sem["formsemestre_id"]
# calcule dates 1er jour semaine pour absences
try:
if with_absences:
first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday()
FA = [] # formulaire avec menu saisi absences
FA.append(
'<td><form action="Absences/SignaleAbsenceGrSemestre" method="get">'
)
FA.append(
'<input type="hidden" name="datefin" value="%(date_fin)s"/>' % sem
)
FA.append('<input type="hidden" name="group_ids" value="%(group_id)s"/>')
FA.append(
'<input type="hidden" name="destination" value="%s"/>' % destination
)
FA.append('<input type="submit" value="Saisir absences du" />')
FA.append('<select name="datedebut" class="noprint">')
date = first_monday
for jour in sco_abs.day_names(context):
FA.append('<option value="%s">%s</option>' % (date, jour))
date = date.next()
FA.append("</select>")
FA.append(
'<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>'
% sem
)
FA.append("</form></td>")
FormAbs = "\n".join(FA)
else:
FormAbs = ""
except ScoInvalidDateError: # dates incorrectes dans semestres ?
FormAbs = ""
#
H.append('<div id="grouplists">')
# Genere liste pour chaque partition (categorie de groupes)
for partition in sco_groups.get_partitions_list(context, sem["formsemestre_id"]):
if not partition["partition_name"]:
H.append("<h4>Tous les étudiants</h4>" % partition)
else:
H.append("<h4>Groupes de %(partition_name)s</h4>" % partition)
groups = sco_groups.get_partition_groups(context, partition)
if groups:
H.append("<table>")
for group in groups:
n_members = len(
sco_groups.get_group_members(context, group["group_id"])
)
group["url"] = r
if group["group_name"]:
group["label"] = "groupe %(group_name)s" % group
else:
group["label"] = "liste"
H.append('<tr class="listegroupelink">')
H.append(
"""<td>
<a href="%(url)s/groups_view?group_ids=%(group_id)s">%(label)s</a>
</td><td>
(<a href="%(url)s/groups_view?group_ids=%(group_id)s&format=xls">format tableur</a>)
<a href="%(url)s/groups_view?curtab=tab-photos&group_ids=%(group_id)s&etat=I">Photos</a>
</td>"""
% group
)
H.append("<td>(%d étudiants)</td>" % n_members)
if with_absences:
H.append(FormAbs % group)
H.append("</tr>")
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):
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):
H.append(
'<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>'
% formsemestre_id
)
H.append("</div>")
return "\n".join(H)
def html_expr_diagnostic(context, diagnostics):
"""Affiche messages d'erreur des formules utilisateurs"""
H = []

View File

@ -973,7 +973,8 @@ def partition_delete(
grnames = "(" + ", ".join([g["group_name"] or "" for g in groups]) + ")"
else:
grnames = ""
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Supprimer la partition "%s" ?</h2>
<p>Les groupes %s de cette partition seront supprimés</p>
"""

View File

@ -340,7 +340,8 @@ def formsemestre_inscr_passage(
if not a_inscrire and not a_desinscrire:
H.append("""<h3>Il n'y a rien à modifier !</h3>""")
H.append(
context.confirmDialog(
scu.confirm_dialog(
context,
dest_url="formsemestre_inscr_passage",
add_headers=False,
cancel_url="formsemestre_inscr_passage?formsemestre_id="

View File

@ -150,13 +150,27 @@ def _flatten_info(info):
return ids
def _getEtudInfoGroupes(context, group_ids, etat=None):
"""liste triée d'infos (dict) sur les etudiants du groupe indiqué.
Attention: lent, car plusieurs requetes SQL par etudiant !
"""
etuds = []
for group_id in group_ids:
members = sco_groups.get_group_members(context, group_id, etat=etat)
for m in members:
etud = context.getEtudInfo(etudid=m["etudid"], filled=True)[0]
etuds.append(etud)
return etuds
def formsemestre_poursuite_report(
context, formsemestre_id, format="html", REQUEST=None
):
"""Table avec informations "poursuite" """
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
etuds = context.getEtudInfoGroupes(
[sco_groups.get_default_group(context, formsemestre_id)]
etuds = _getEtudInfoGroupes(
context, [sco_groups.get_default_group(context, formsemestre_id)]
)
infos = []

View File

@ -88,11 +88,22 @@ def formsemestre_etuds_stats(context, sem, only_primo=False):
bs.append(etud["specialite"])
etud["bac-specialite"] = " ".join(bs)
#
if (not only_primo) or context.isPrimoEtud(etud, sem):
if (not only_primo) or is_primo_etud(context, etud, sem):
etuds.append(etud)
return etuds
def is_primo_etud(context, etud, sem):
"""Determine si un (filled) etud a ete inscrit avant ce semestre.
Regarde la liste des semestres dans lesquels l'étudiant est inscrit
"""
now = sem["dateord"]
for s in etud["sems"]: # le + recent d'abord
if s["dateord"] < now:
return False
return True
def _categories_and_results(etuds, category, result):
categories = {}
results = {}
@ -416,7 +427,7 @@ def table_suivi_cohorte(
and (not annee_bac or (annee_bac == str(etud["annee_bac"])))
and (not civilite or (civilite == etud["civilite"]))
and (not statut or (statut == etud["statut"]))
and (not only_primo or context.isPrimoEtud(etud, sem))
and (not only_primo or is_primo_etud(context, etud, sem))
):
orig_set.add(etudid)
# semestres suivants:
@ -708,14 +719,16 @@ def formsemestre_suivi_cohorte(
return t
base_url = REQUEST.URL0
burl = (
"%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&civilite=%s&statut=%s"
% (base_url, formsemestre_id, bac, bacspecialite, civilite, statut)
burl = "%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&civilite=%s&statut=%s" % (
base_url,
formsemestre_id,
bac,
bacspecialite,
civilite,
statut,
)
if percent:
pplink = (
'<p><a href="%s&percent=0">Afficher les résultats bruts</a></p>' % burl
)
pplink = '<p><a href="%s&percent=0">Afficher les résultats bruts</a></p>' % burl
else:
pplink = (
'<p><a href="%s&percent=1">Afficher les résultats en pourcentages</a></p>'
@ -1028,7 +1041,7 @@ def tsp_etud_list(
and (not annee_bac or (annee_bac == str(etud["annee_bac"])))
and (not civilite or (civilite == etud["civilite"]))
and (not statut or (statut == etud["statut"]))
and (not only_primo or context.isPrimoEtud(etud, sem))
and (not only_primo or is_primo_etud(context, etud, sem))
):
etuds.append(etud)

View File

@ -349,7 +349,8 @@ def do_evaluation_set_missing(
)
# Confirm action
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Mettre toutes les notes manquantes de l'évaluation
à la valeur %s ?</h2>
<p>Seuls les étudiants pour lesquels aucune note (ni valeur, ni ABS, ni EXC)
@ -418,7 +419,8 @@ def evaluation_suppress_alln(context, evaluation_id, REQUEST, dialog_confirmed=F
msg = "<p>Confirmer la suppression des %d notes ?</p>" % nb_suppress
if existing_decisions:
msg += """<p class="warning">Important: il y a déjà des décisions de jury enregistrées, qui seront potentiellement à revoir suite à cette modification !</p>"""
return context.confirmDialog(
return scu.confirm_dialog(
context,
msg,
dest_url="",
REQUEST=REQUEST,

View File

@ -362,7 +362,8 @@ def do_semset_delete(context, semset_id, dialog_confirmed=False, REQUEST=None):
raise ScoValueError("empty semset_id")
s = SemSet(context, semset_id=semset_id)
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"<h2>Suppression de l'ensemble %(title)s ?</h2>" % s,
dest_url="",
REQUEST=REQUEST,

View File

@ -205,7 +205,8 @@ def formsemestre_synchro_etuds(
H.append("""<h3>Il n'y a rien à modifier !</h3>""")
H.append(
context.confirmDialog(
scu.confirm_dialog(
context,
dest_url="formsemestre_synchro_etuds",
add_headers=False,
cancel_url="formsemestre_synchro_etuds?formsemestre_id="

View File

@ -185,12 +185,12 @@ def check_local_photos_availability(context, groups_infos, REQUEST, format=""):
parameters = {"group_ids": groups_infos.group_ids, "format": format}
return (
False,
context.confirmDialog(
scu.confirm_dialog(
context,
"""<p>Attention: %d photos ne sont pas disponibles et ne peuvent pas être exportées.</p><p>Vous pouvez <a class="stdlink" href="%s">exporter seulement les photos existantes</a>"""
% (
nb_missing,
groups_infos.base_url
+ "&dialog_confirmed=1&format=%s" % format,
groups_infos.base_url + "&dialog_confirmed=1&format=%s" % format,
),
dest_url="trombino",
OK="Exporter seulement les photos existantes",
@ -252,7 +252,8 @@ def trombino_copy_photos(context, group_ids=[], REQUEST=None, dialog_confirmed=F
+ footer
)
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Copier les photos du portail vers ScoDoc ?</h2>
<p>Les photos du groupe %s présentes dans ScoDoc seront remplacées par celles du portail (si elles existent).</p>
<p>(les photos sont normalement automatiquement copiées lors de leur première utilisation, l'usage de cette fonction n'est nécessaire que si les photos du portail ont été modifiées)</p>

View File

@ -840,7 +840,25 @@ def log_unknown_etud(context, REQUEST=None, format="html"):
"unknown student: etudid=%s code_nip=%s code_ine=%s"
% (etudid, code_nip, code_ine)
)
return context.ScoErrorResponse("unknown student", format=format, REQUEST=REQUEST)
return _sco_error_response("unknown student", format=format, REQUEST=REQUEST)
# XXX #sco8 à tester ou ré-écrire
def _sco_error_response(context, msg, format="html", REQUEST=None):
"""Send an error message to the client, in html or xml format."""
REQUEST.RESPONSE.setStatus(404, reason=msg)
if format == "html" or format == "pdf":
raise ScoValueError(msg)
elif format == "xml":
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
doc.error(msg=msg)
return repr(doc)
elif format == "json":
REQUEST.RESPONSE.setHeader("content-type", scu.JSON_MIMETYPE)
return "undefined" # XXX voir quoi faire en cas d'erreur json
else:
raise ValueError("ScoErrorResponse: invalid format")
# XXX
@ -869,3 +887,55 @@ def return_text_if_published(val, REQUEST):
if REQUEST and not isinstance(val, STRING_TYPES):
return sendJSON(REQUEST, val)
return val
def confirm_dialog(
context,
message="<p>Confirmer ?</p>",
OK="OK",
Cancel="Annuler",
dest_url="",
cancel_url="",
target_variable="dialog_confirmed",
parameters={},
add_headers=True, # complete page
REQUEST=None, # required
helpmsg=None,
):
# dialog de confirmation simple
parameters[target_variable] = 1
# Attention: la page a pu etre servie en GET avec des parametres
# si on laisse l'url "action" vide, les parametres restent alors que l'on passe en POST...
if not dest_url:
dest_url = REQUEST.URL
# strip remaining parameters from destination url:
dest_url = urllib.splitquery(dest_url)[0]
H = [
"""<form action="%s" method="post">""" % dest_url,
message,
"""<input type="submit" value="%s"/>""" % OK,
]
if cancel_url:
H.append(
"""<input type ="button" value="%s"
onClick="document.location='%s';"/>"""
% (Cancel, cancel_url)
)
for param in parameters.keys():
if parameters[param] is None:
parameters[param] = ""
if type(parameters[param]) == type([]):
for e in parameters[param]:
H.append('<input type="hidden" name="%s" value="%s"/>' % (param, e))
else:
H.append(
'<input type="hidden" name="%s" value="%s"/>'
% (param, parameters[param])
)
H.append("</form>")
if helpmsg:
H.append('<p class="help">' + helpmsg + "</p>")
if add_headers and REQUEST:
return context.sco_header(REQUEST) + "\n".join(H) + context.sco_footer(REQUEST)
else:
return "\n".join(H)

View File

@ -357,7 +357,8 @@ def _check_duplicate_code(cnx, args, code_name, context, edit=True, REQUEST=None
dest_url = ""
parameters = {}
if context:
err_page = context.confirmDialog(
err_page = scu.confirm_dialog(
context,
message="""<h3>Code étudiant (%s) dupliqué !</h3>""" % code_name,
helpmsg="""Le %s %s est déjà utilisé: un seul étudiant peut avoir ce code. Vérifier votre valeur ou supprimer l'autre étudiant avec cette valeur.<p><ul><li>"""
% (code_name, args[code_name])
@ -866,3 +867,171 @@ for l in f:
o.close()
"""
def list_scolog(context, etudid):
"liste des operations effectuees sur cet etudiant"
cnx = context.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(
"select * from scolog where etudid=%(etudid)s ORDER BY DATE DESC",
{"etudid": etudid},
)
return cursor.dictfetchall()
def fillEtudsInfo(context, etuds):
"""etuds est une liste d'etudiants (mappings)
Pour chaque etudiant, ajoute ou formatte les champs
-> informations pour fiche etudiant ou listes diverses
"""
cnx = context.GetDBConnexion()
# open('/tmp/t','w').write( str(etuds) )
for etud in etuds:
etudid = etud["etudid"]
etud["dept"] = context.DeptId()
adrs = adresse_list(cnx, {"etudid": etudid})
if not adrs:
# certains "vieux" etudiants n'ont pas d'adresse
adr = {}.fromkeys(_adresseEditor.dbfields, "")
adr["etudid"] = etudid
else:
adr = adrs[0]
if len(adrs) > 1:
log("fillEtudsInfo: etudid=%s a %d adresses" % (etudid, len(adrs)))
etud.update(adr)
format_etud_ident(etud)
# Semestres dans lesquel il est inscrit
ins = context.Notes.do_formsemestre_inscription_list({"etudid": etudid})
etud["ins"] = ins
sems = []
cursem = None # semestre "courant" ou il est inscrit
for i in ins:
sem = sco_formsemestre.get_formsemestre(context, i["formsemestre_id"])
if sco_formsemestre.sem_est_courant(context, sem):
cursem = sem
curi = i
sem["ins"] = i
sems.append(sem)
# trie les semestres par date de debut, le plus recent d'abord
# (important, ne pas changer (suivi cohortes))
sems.sort(lambda x, y: cmp(y["dateord"], x["dateord"]))
etud["sems"] = sems
etud["cursem"] = cursem
if cursem:
etud["inscription"] = cursem["titremois"]
etud["inscriptionstr"] = "Inscrit en " + cursem["titremois"]
etud["inscription_formsemestre_id"] = cursem["formsemestre_id"]
etud["etatincursem"] = curi["etat"]
etud["situation"] = descr_situation_etud(context, etudid, etud["ne"])
# XXX est-ce utile ? sco_groups.etud_add_group_infos(context, etud, cursem)
else:
if etud["sems"]:
if etud["sems"][0]["dateord"] > time.strftime(
"%Y-%m-%d", time.localtime()
):
etud["inscription"] = "futur"
etud["situation"] = "futur élève"
else:
etud["inscription"] = "ancien"
etud["situation"] = "ancien élève"
else:
etud["inscription"] = "non inscrit"
etud["situation"] = etud["inscription"]
etud["inscriptionstr"] = etud["inscription"]
etud["inscription_formsemestre_id"] = None
# XXXetud['partitions'] = {} # ne va pas chercher les groupes des anciens semestres
etud["etatincursem"] = "?"
# nettoyage champs souvents vides
if etud["nomlycee"]:
etud["ilycee"] = "Lycée " + format_lycee(etud["nomlycee"])
if etud["villelycee"]:
etud["ilycee"] += " (%s)" % etud["villelycee"]
etud["ilycee"] += "<br/>"
else:
if etud["codelycee"]:
etud["ilycee"] = format_lycee_from_code(etud["codelycee"])
else:
etud["ilycee"] = ""
rap = ""
if etud["rapporteur"] or etud["commentaire"]:
rap = "Note du rapporteur"
if etud["rapporteur"]:
rap += " (%s)" % etud["rapporteur"]
rap += ": "
if etud["commentaire"]:
rap += "<em>%s</em>" % etud["commentaire"]
etud["rap"] = rap
# if etud['boursier_prec']:
# pass
if etud["telephone"]:
etud["telephonestr"] = "<b>Tél.:</b> " + format_telephone(etud["telephone"])
else:
etud["telephonestr"] = ""
if etud["telephonemobile"]:
etud["telephonemobilestr"] = "<b>Mobile:</b> " + format_telephone(
etud["telephonemobile"]
)
else:
etud["telephonemobilestr"] = ""
etud["debouche"] = etud["debouche"] or ""
def descr_situation_etud(context, etudid, ne=""):
"""chaine decrivant la situation actuelle de l'etudiant"""
cnx = context.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute(
"select I.formsemestre_id, I.etat from notes_formsemestre_inscription I, notes_formsemestre S where etudid=%(etudid)s and S.formsemestre_id = I.formsemestre_id and date_debut < now() and date_fin > now() order by S.date_debut desc;",
{"etudid": etudid},
)
r = cursor.dictfetchone()
if not r:
situation = "non inscrit"
else:
sem = sco_formsemestre.get_formsemestre(context, r["formsemestre_id"])
if r["etat"] == "I":
situation = "inscrit%s en %s" % (ne, sem["titremois"])
# Cherche la date d'inscription dans scolar_events:
events = scolars.scolar_events_list(
cnx,
args={
"etudid": etudid,
"formsemestre_id": sem["formsemestre_id"],
"event_type": "INSCRIPTION",
},
)
if not events:
log(
"*** situation inconsistante pour %s (inscrit mais pas d'event)"
% etudid
)
date_ins = "???" # ???
else:
date_ins = events[0]["event_date"]
situation += " le " + str(date_ins)
else:
situation = "démission de %s" % sem["titremois"]
# Cherche la date de demission dans scolar_events:
events = scolars.scolar_events_list(
cnx,
args={
"etudid": etudid,
"formsemestre_id": sem["formsemestre_id"],
"event_type": "DEMISSION",
},
)
if not events:
log(
"*** situation inconsistante pour %s (demission mais pas d'event)"
% etudid
)
date_dem = "???" # ???
else:
date_dem = events[0]["event_date"]
situation += " le " + str(date_dem)
return situation

File diff suppressed because it is too large Load Diff

View File

@ -130,8 +130,6 @@ from app.scodoc import notes_table as notes_table
from app.scodoc.notes_table import NOTES_CACHE_INST, CacheNotesTable
import app.scodoc.VERSION as VERSION
context = ScoDoc7Context(globals())
def sco_publish(route, function, permission):
"""Declare a route for a python function,
@ -687,7 +685,8 @@ def _do_ue_delete(context, ue_id, delete_validations=False, REQUEST=None, force=
cnx, args={"ue_id": ue_id}
)
if validations and not delete_validations and not force:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"<p>%d étudiants ont validé l'UE %s (%s)</p><p>Si vous supprimez cette UE, ces validations vont être supprimées !</p>"
% (len(validations), ue["acronyme"], ue["titre"]),
dest_url="",
@ -920,7 +919,8 @@ def do_module_delete(context, oid, REQUEST):
# S'il y a des moduleimpls, on ne peut pas detruire le module !
mods = sco_moduleimpl.do_moduleimpl_list(context, module_id=oid)
if mods:
err_page = context.confirmDialog(
err_page = scu.confirm_dialog(
context,
message="""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>""",
helpmsg="""Il faut d'abord supprimer le semestre. Mais il est peut être préférable de laisser ce programme intact et d'en créer une nouvelle version pour la modifier.""",
dest_url="ue_list",
@ -2037,7 +2037,8 @@ def formsemestre_desinscription(
car il n'a pas d'autre étudiant inscrit.
</p>
"""
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Confirmer la demande de desinscription ?</h2>""" + msg_ext,
dest_url="",
REQUEST=REQUEST,
@ -2759,7 +2760,8 @@ def formsemestre_bulletins_mailetuds(
raise AccessDenied("vous n'avez pas le droit d'envoyer les bulletins")
# Confirmation dialog
if not dialog_confirmed:
return context.confirmDialog(
return scu.confirm_dialog(
context,
"<h2>Envoyer les %d bulletins par e-mail aux étudiants ?" % len(etudids),
dest_url="",
REQUEST=REQUEST,
@ -2988,7 +2990,8 @@ def formsemestre_validation_etud(
):
"Enregistre choix jury pour un étudiant"
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3023,7 +3026,8 @@ def formsemestre_validation_etud_manu(
):
"Enregistre choix jury pour un étudiant"
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3052,7 +3056,8 @@ def formsemestre_validate_previous_ue(
):
"Form. saisie UE validée hors ScoDoc "
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3078,7 +3083,8 @@ def formsemestre_ext_edit_ue_validations(
):
"Form. edition UE semestre extérieur"
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3102,7 +3108,8 @@ sco_publish(
def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST=None):
"""Suppress a validation (ue_id, etudid) and redirect to formsemestre"""
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3119,7 +3126,8 @@ def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST
def formsemestre_validation_auto(context, formsemestre_id, REQUEST):
"Formulaire saisie automatisee des decisions d'un semestre"
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3137,7 +3145,8 @@ def formsemestre_validation_auto(context, formsemestre_id, REQUEST):
def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST):
"Formulaire saisie automatisee des decisions d'un semestre"
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3155,7 +3164,8 @@ def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST):
def formsemestre_fix_validation_ues(context, formsemestre_id, REQUEST=None):
"Verif/reparation codes UE"
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3175,7 +3185,8 @@ def formsemestre_validation_suppress_etud(
):
"""Suppression des decisions de jury pour un etudiant."""
if not context._can_validate_sem(REQUEST, formsemestre_id):
return context.confirmDialog(
return scu.confirm_dialog(
context,
message="<p>Opération non autorisée pour %s</h2>"
% REQUEST.AUTHENTICATED_USER,
dest_url=context.ScoURL(),
@ -3194,7 +3205,8 @@ def formsemestre_validation_suppress_etud(
)
else:
existing = ""
return context.confirmDialog(
return scu.confirm_dialog(
context,
"""<h2>Confirmer la suppression des décisions du semestre %s (%s - %s) pour %s ?</h2>%s
<p>Cette opération est irréversible.
</p>

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@ alembic==1.5.5
attrdict==2.0.1
Babel==2.9.0
blinker==1.4
certifi==2021.5.30
chardet==4.0.0
click==7.1.2
dnspython==1.16.0
dominate==2.6.0
@ -33,10 +35,12 @@ python-dotenv==0.15.0
python-editor==1.0.4
pytz==2021.1
reportlab==3.5.59
requests==2.25.1
six==1.15.0
SQLAlchemy==1.3.23
stripogram==1.5
typing==3.7.4.3
urllib3==1.26.5
visitor==0.1.3
Werkzeug==1.0.1
WTForms==2.3.3

View File

@ -57,7 +57,7 @@ class ScoDocManager:
def get_dept_ids(self):
"get (unsorted) dept ids"
return [d.dept_id for d in descr_list]
return self.dept_descriptions.keys()
def get_db_uri(self):
"""