WIP migration vues en cours / tout est en vrac !
This commit is contained in:
parent
77f68d1c4c
commit
dcb53e9c35
21
README.md
21
README.md
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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" % (
|
||||
datedebut,
|
||||
datefin,
|
||||
groups_infos.groups_query_args,
|
||||
urllib.quote(destination),
|
||||
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)
|
||||
|
@ -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"),
|
||||
|
@ -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>"""
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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,),
|
||||
|
@ -66,6 +66,12 @@ class FormatError(ScoValueError):
|
||||
pass
|
||||
|
||||
|
||||
class ScoInvalidDept(ScoValueError):
|
||||
"""departement invalide"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ScoConfigurationError(ScoValueError):
|
||||
"""Configuration invalid"""
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 = []
|
||||
|
@ -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>
|
||||
"""
|
||||
|
@ -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="
|
||||
|
@ -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 = []
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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="
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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>
|
||||
|
2050
app/views/scolar.py
2050
app/views/scolar.py
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user