diff --git a/app/api/jury.py b/app/api/jury.py index e71531eb21acb985a1b3f68a2141c4581d508cab..864dfe222173a062febfce31193db083df4bf060 100644 --- a/app/api/jury.py +++ b/app/api/jury.py @@ -66,7 +66,7 @@ def _news_delete_jury_etud(etud: Identite): "génère news sur effacement décision" # n'utilise pas g.scodoc_dept, pas toujours dispo en mode API url = url_for( - "scolar.ficheEtud", scodoc_dept=etud.departement.acronym, etudid=etud.id + "scolar.fiche_etud", scodoc_dept=etud.departement.acronym, etudid=etud.id ) ScolarNews.add( typ=ScolarNews.NEWS_JURY, diff --git a/app/but/jury_but_pv.py b/app/but/jury_but_pv.py index 9b970a61dfd7d69d85ba9d4622bd96e49e7cbc73..8ae09800f84a37121c1b24b6a533d47d01dbc3c6 100644 --- a/app/but/jury_but_pv.py +++ b/app/but/jury_but_pv.py @@ -154,7 +154,7 @@ def pvjury_table_but( "_nom_target_attrs": f'class="etudinfo" id="{etud.id}"', "_nom_td_attrs": f'id="{etud.id}" class="etudinfo"', "_nom_target": url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id, ), diff --git a/app/but/jury_but_view.py b/app/but/jury_but_view.py index 544d13f2b2b1902d2d8b46c5aa913c52584bedc1..8536ac63ca0bc036dabfd63e9cae28fedef1f9a8 100644 --- a/app/but/jury_but_view.py +++ b/app/but/jury_but_view.py @@ -447,7 +447,7 @@ def jury_but_semestriel( <div class="nom_etud">{etud.nomprenom}</div> </div> <div class="bull_photo"><a href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) }">{etud.photo_html(title="fiche de " + etud.nomprenom)}</a> </div> </div> diff --git a/app/comp/res_classic.py b/app/comp/res_classic.py index 89ff95e731385162a0055916a2b7d08533905f67..673668b995d64405c5e12c7f2849a10408fe7c2d 100644 --- a/app/comp/res_classic.py +++ b/app/comp/res_classic.py @@ -234,7 +234,7 @@ class ResultatsSemestreClassic(NotesTableCompat): raise ScoValueError( f"""<div class="scovalueerror"><p>Coefficient de l'UE capitalisée {ue.acronyme} impossible à déterminer pour l'étudiant <a href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) }" class="discretelink">{etud.nom_disp()}</a></p> <p>Il faut <a href="{ url_for("notes.formsemestre_edit_uecoefs", scodoc_dept=g.scodoc_dept, diff --git a/app/models/etudiants.py b/app/models/etudiants.py index 2f9caa069ec4daedf135741d1aea692333e4d33c..bc2d0560cdbf3bba45770b9b60139ca37f856a3c 100644 --- a/app/models/etudiants.py +++ b/app/models/etudiants.py @@ -119,6 +119,9 @@ class Identite(models.ScoDocModel): "Justificatif", back_populates="etudiant", lazy="dynamic", cascade="all, delete" ) + # Champs "protégés" par ViewEtudData (RGPD) + protected_attrs = {"boursier"} + def __repr__(self): return ( f"<Etud {self.id}/{self.departement.acronym} {self.nom!r} {self.prenom!r}>" @@ -176,7 +179,7 @@ class Identite(models.ScoDocModel): def url_fiche(self) -> str: "url de la fiche étudiant" return url_for( - "scolar.ficheEtud", scodoc_dept=self.departement.acronym, etudid=self.id + "scolar.fiche_etud", scodoc_dept=self.departement.acronym, etudid=self.id ) @classmethod @@ -433,9 +436,10 @@ class Identite(models.ScoDocModel): "prenom_etat_civil": self.prenom_etat_civil, } - def to_dict_scodoc7(self) -> dict: + def to_dict_scodoc7(self, restrict=False) -> dict: """Représentation dictionnaire, - compatible ScoDoc7 mais sans infos admission + compatible ScoDoc7 mais sans infos admission. + Si restrict, cache les infos "personnelles" si pas permission ViewEtudData """ e_dict = self.__dict__.copy() # dict(self.__dict__) e_dict.pop("_sa_instance_state", None) @@ -446,7 +450,7 @@ class Identite(models.ScoDocModel): e_dict["nomprenom"] = self.nomprenom adresse = self.adresses.first() if adresse: - e_dict.update(adresse.to_dict()) + e_dict.update(adresse.to_dict(restrict=restrict)) return {k: v or "" for k, v in e_dict.items()} # convert_null_outputs_to_empty def to_dict_bul(self, include_urls=True): @@ -481,7 +485,7 @@ class Identite(models.ScoDocModel): if include_urls and has_request_context(): # test request context so we can use this func in tests under the flask shell d["fiche_url"] = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=self.id + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=self.id ) d["photo_url"] = sco_photos.get_etud_photo_url(self.id) adresse = self.adresses.first() @@ -825,12 +829,25 @@ class Adresse(models.ScoDocModel): ) description = db.Column(db.Text) - def to_dict(self, convert_nulls_to_str=False): - """Représentation dictionnaire,""" + # Champs "protégés" par ViewEtudData (RGPD) + protected_attrs = { + "emailperso", + "domicile", + "codepostaldomicile", + "villedomicile", + "telephone", + "telephonemobile", + "fax", + } + + def to_dict(self, convert_nulls_to_str=False, restrict=False): + """Représentation dictionnaire. Si restrict, filtre les champs protégés (RGPD).""" e = dict(self.__dict__) e.pop("_sa_instance_state", None) if convert_nulls_to_str: - return {k: e[k] or "" for k in e} + e = {k: v or "" for k, v in e.items()} + if restrict: + e = {k: v for (k, v) in e.items() if k not in self.protected_attrs} return e @@ -885,12 +902,16 @@ class Admission(models.ScoDocModel): # classement (1..Ngr) par le jury dans le groupe APB apb_classement_gr = db.Column(db.Integer) + # Tous les champs sont "protégés" par ViewEtudData (RGPD) + # sauf: + not_protected_attrs = {"bac", "specialite", "anne_bac"} + def get_bac(self) -> Baccalaureat: "Le bac. utiliser bac.abbrev() pour avoir une chaine de caractères." return Baccalaureat(self.bac, specialite=self.specialite) - def to_dict(self, no_nulls=False): - """Représentation dictionnaire,""" + def to_dict(self, no_nulls=False, restrict=False): + """Représentation dictionnaire. Si restrict, filtre les champs protégés (RGPD).""" d = dict(self.__dict__) d.pop("_sa_instance_state", None) if no_nulls: @@ -905,6 +926,8 @@ class Admission(models.ScoDocModel): d[key] = 0 elif isinstance(col_type, sqlalchemy.Boolean): d[key] = False + if restrict: + d = {k: v for (k, v) in d.items() if k in self.not_protected_attrs} return d @classmethod diff --git a/app/pe/pe_jurype.py b/app/pe/pe_jurype.py index 01687f7c97c348707c49d9b5c9643a06086cc159..d6416c2e5e490d5fb0dd60dea17d36d9140af1ea 100644 --- a/app/pe/pe_jurype.py +++ b/app/pe/pe_jurype.py @@ -455,7 +455,9 @@ class JuryPE(object): reponse = False etud = self.get_cache_etudInfo_d_un_etudiant(etudid) - (_, parcours) = sco_report.get_code_cursus_etud(etud) + (_, parcours) = sco_report.get_code_cursus_etud( + etud["etudid"], sems=etud["sems"] + ) if ( len(codes_cursus.CODES_SEM_REO & set(parcours.values())) > 0 ): # Eliminé car NAR apparait dans le parcours @@ -527,7 +529,7 @@ class JuryPE(object): etud = self.get_cache_etudInfo_d_un_etudiant(etudid) (code, parcours) = sco_report.get_code_cursus_etud( - etud + etud["etudid"], sems=etud["sems"] ) # description = '1234:A', parcours = {1:ADM, 2:NAR, ...} sonDernierSemestreValide = max( [ diff --git a/app/scodoc/html_sidebar.py b/app/scodoc/html_sidebar.py index 9806b11591da49d15b13db161305ee7ab59f27f6..dce59627f9003fab7dea04fc85a970aa062fccdc 100755 --- a/app/scodoc/html_sidebar.py +++ b/app/scodoc/html_sidebar.py @@ -107,7 +107,7 @@ def sidebar(etudid: int = None): etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0] params.update(etud) params["fiche_url"] = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ) # compte les absences du semestre en cours H.append( diff --git a/app/scodoc/sco_abs_billets.py b/app/scodoc/sco_abs_billets.py index 18fe777fe521b271fca728e66be36e685cb2c3a3..4a9da0af835617b9dc72f99b610623c55fd4f793 100644 --- a/app/scodoc/sco_abs_billets.py +++ b/app/scodoc/sco_abs_billets.py @@ -129,7 +129,7 @@ def table_billets( ] = f'id="{billet.etudiant.id}" class="etudinfo"' if with_links: billet_dict["_nomprenom_target"] = url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=billet_dict["etudid"], ) diff --git a/app/scodoc/sco_abs_notification.py b/app/scodoc/sco_abs_notification.py index b97f4418537fc45ee52d3cdbee08d54625acf790..852f586d6e22eeb58e2cd110da2c7d28615f7ca3 100644 --- a/app/scodoc/sco_abs_notification.py +++ b/app/scodoc/sco_abs_notification.py @@ -34,7 +34,7 @@ Il suffit d'appeler abs_notify() après chaque ajout d'absence. import datetime from typing import Optional -from flask import current_app, g, url_for +from flask import g, url_for from flask_mail import Message from app import db @@ -42,6 +42,7 @@ from app import email from app import log from app.auth.models import User from app.models.absences import AbsenceNotification +from app.models.etudiants import Identite from app.models.events import Scolog from app.models.formsemestre import FormSemestre import app.scodoc.notesdb as ndb @@ -175,9 +176,15 @@ def abs_notify_get_destinations( if prefs["abs_notify_email"]: destinations.append(prefs["abs_notify_email"]) if prefs["abs_notify_etud"]: - etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0] - if etud["email_default"]: - destinations.append(etud["email_default"]) + etud = Identite.get_etud(etudid) + adresse = etud.adresses.first() + if adresse: + # Mail à utiliser pour les envois vers l'étudiant: + # choix qui pourrait être controlé par une preference + # ici priorité au mail institutionnel: + email_default = adresse.email or adresse.emailperso + if email_default: + destinations.append(email_default) # Notification (à chaque fois) des resp. de modules ayant des évaluations # à cette date @@ -271,7 +278,7 @@ def abs_notification_message( values["nbabsjust"] = nbabsjust values["nbabsnonjust"] = nbabs - nbabsjust values["url_ficheetud"] = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid, _external=True + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid, _external=True ) template = prefs["abs_notification_mail_tmpl"] diff --git a/app/scodoc/sco_archives_etud.py b/app/scodoc/sco_archives_etud.py index 1dca9f02804194603f9960a3160dc4fdbe261834..42fddde2d2c6d26b27bf26887c27542a44d1a5a8 100644 --- a/app/scodoc/sco_archives_etud.py +++ b/app/scodoc/sco_archives_etud.py @@ -177,7 +177,7 @@ def etud_upload_file_form(etudid): return "\n".join(H) + tf[1] + html_sco_header.sco_footer() elif tf[0] == -1: return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) else: data = tf[2]["datafile"].read() @@ -188,7 +188,7 @@ def etud_upload_file_form(etudid): etud_archive_id, data, filename, description=descr ) return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) @@ -228,7 +228,7 @@ def etud_delete_archive(etudid, archive_name, dialog_confirmed=False): ), dest_url="", cancel_url=url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid, head_message="annulation", @@ -239,7 +239,7 @@ def etud_delete_archive(etudid, archive_name, dialog_confirmed=False): ETUDS_ARCHIVER.delete_archive(archive_id, dept_id=etud["dept_id"]) flash("Archive supprimée") return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) diff --git a/app/scodoc/sco_cursus_dut.py b/app/scodoc/sco_cursus_dut.py index b9e26e322da92bb9f0843f37a835b5d5a37ec67c..47e7a5fefe7b27a9659b0acbaadbffea3b4f7a24 100644 --- a/app/scodoc/sco_cursus_dut.py +++ b/app/scodoc/sco_cursus_dut.py @@ -39,7 +39,6 @@ from app import log from app.scodoc.scolog import logdb from app.scodoc import sco_cache, sco_etud from app.scodoc import sco_formsemestre -from app.scodoc import sco_formations from app.scodoc.codes_cursus import ( CMP, ADC, diff --git a/app/scodoc/sco_debouche.py b/app/scodoc/sco_debouche.py index cc08e8d98f2cf3ee3e6b15a6be0d8e8b8e91ec20..f027b553c26a0cf8095d1739f609fa66eaa6b862 100644 --- a/app/scodoc/sco_debouche.py +++ b/app/scodoc/sco_debouche.py @@ -134,10 +134,10 @@ def table_debouche_etudids(etudids, keep_numeric=True): "nom": etud["nom"], "prenom": etud["prenom"], "_nom_target": url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ), "_prenom_target": url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ), "_nom_td_attrs": 'id="%s" class="etudinfo"' % (etud["etudid"]), # 'debouche' : etud['debouche'], diff --git a/app/scodoc/sco_etape_apogee_view.py b/app/scodoc/sco_etape_apogee_view.py index 6247d98695a892a99061ca36e6ac4b3562cef1a1..da833d5ce418aeb9480c334019ec93e5c9a3abca 100644 --- a/app/scodoc/sco_etape_apogee_view.py +++ b/app/scodoc/sco_etape_apogee_view.py @@ -542,7 +542,9 @@ def view_scodoc_etuds(semset_id, title="", nip_list="", fmt="html"): etuds = [sco_etud.get_etud_info(code_nip=nip, filled=True)[0] for nip in nips] for e in etuds: - tgt = url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=e["etudid"]) + tgt = url_for( + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=e["etudid"] + ) e["_nom_target"] = tgt e["_prenom_target"] = tgt e["_nom_td_attrs"] = f"""id="{e['etudid']}" class="etudinfo" """ @@ -770,7 +772,7 @@ def view_apo_csv(etape_apo="", semset_id="", fmt="html"): e["in_scodoc_str"] = {True: "oui", False: "non"}[e["in_scodoc"]] if e["in_scodoc"]: e["_in_scodoc_str_target"] = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, code_nip=e["nip"] + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=e["etudid"] ) e.update(sco_etud.get_etud_info(code_nip=e["nip"], filled=True)[0]) e["_nom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"],) diff --git a/app/scodoc/sco_etape_bilan.py b/app/scodoc/sco_etape_bilan.py index 575d2596af959381f432a4ec244e8006c25d81e0..86da71667d8ced199a36c934af5cdbb3675d9e56 100644 --- a/app/scodoc/sco_etape_bilan.py +++ b/app/scodoc/sco_etape_bilan.py @@ -692,7 +692,7 @@ class EtapeBilan: @staticmethod def link_etu(etudid, nom): return '<a class="stdlink" href="%s">%s</a>' % ( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid), nom, ) diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py index e7041021cea410216748d46d1b50b7b3dfc433e6..f6b8a18dfc277d353a625ac978d396316e40f7a8 100644 --- a/app/scodoc/sco_etud.py +++ b/app/scodoc/sco_etud.py @@ -64,7 +64,7 @@ def format_etud_ident(etud: dict): Note: par rapport à Identite.to_dict_bul(), ajoute les champs: - 'email_default', 'nom_disp', 'nom_usuel', 'civilite_etat_civil_str', 'ne', 'civilite_str' + 'nom_disp', 'nom_usuel', 'civilite_etat_civil_str', 'ne', 'civilite_str' """ etud["nom"] = format_nom(etud["nom"]) if "nom_usuel" in etud: @@ -98,10 +98,6 @@ def format_etud_ident(etud: dict): etud["ne"] = "e" else: # 'X' etud["ne"] = "(e)" - # Mail à utiliser pour les envois vers l'étudiant: - # choix qui pourrait être controé par une preference - # ici priorité au mail institutionnel: - etud["email_default"] = etud.get("email", "") or etud.get("emailperso", "") def force_uppercase(s): @@ -117,36 +113,6 @@ def _format_etat_civil(etud: dict) -> str: return etud["nomprenom"] -def format_lycee(nomlycee): - nomlycee = nomlycee.strip() - s = nomlycee.lower() - if s[:5] == "lycee" or s[:5] == "lycée": - return nomlycee[5:] - else: - return nomlycee - - -def format_telephone(n): - if n is None: - return "" - if len(n) < 7: - return n - else: - n = n.replace(" ", "").replace(".", "") - i = 0 - r = "" - j = len(n) - 1 - while j >= 0: - r = n[j] + r - if i % 2 == 1 and j != 0: - r = " " + r - i += 1 - j -= 1 - if len(r) == 13 and r[0] != "0": - r = "0" + r - return r - - def format_pays(s): "laisse le pays seulement si != FRANCE" if s.upper() != "FRANCE": @@ -283,14 +249,14 @@ def _check_duplicate_code(cnx, args, code_name, disable_notify=False, edit=True) listh.append( f"""Autre étudiant: <a href="{ url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=e["etudid"] )}">{e['nom']} {e['prenom']}</a>""" ) if etudid: OK = "retour à la fiche étudiant" - dest_endpoint = "scolar.ficheEtud" + dest_endpoint = "scolar.fiche_etud" parameters = {"etudid": etudid} else: if "tf_submitted" in args: @@ -619,7 +585,7 @@ def create_etud(cnx, args: dict = None): etud_dict = etudident_list(cnx, {"etudid": etudid})[0] fill_etuds_info([etud_dict]) etud_dict["url"] = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ) ScolarNews.add( typ=ScolarNews.NEWS_INSCR, @@ -724,19 +690,28 @@ def get_etablissements(): def get_lycee_infos(codelycee): - E = get_etablissements() - return E.get(codelycee, None) + etablissements = get_etablissements() + return etablissements.get(codelycee, None) -def format_lycee_from_code(codelycee): +def format_lycee_from_code(codelycee: str) -> str: "Description lycee à partir du code" - E = get_etablissements() - if codelycee in E: - e = E[codelycee] + etablissements = get_etablissements() + if codelycee in etablissements: + e = etablissements[codelycee] nomlycee = e["name"] - return "%s (%s)" % (nomlycee, e["commune"]) + return f"{nomlycee} ({e['commune']})" + return f"{codelycee} (établissement inconnu)" + + +def format_lycee(nomlycee: str) -> str: + "mise en forme nom de lycée" + nomlycee = nomlycee.strip() + s = nomlycee.lower() + if s[:5] == "lycee" or s[:5] == "lycée": + return nomlycee[5:] else: - return "%s (établissement inconnu)" % codelycee + return nomlycee def etud_add_lycee_infos(etud): @@ -821,36 +796,6 @@ def fill_etuds_info(etuds: list[dict], add_admission=True): # nettoyage champs souvent vides etud["codepostallycee"] = etud.get("codepostallycee", "") or "" etud["nomlycee"] = etud.get("nomlycee", "") or "" - if etud.get("nomlycee"): - etud["ilycee"] = "Lycée " + format_lycee(etud["nomlycee"]) - if etud["villelycee"]: - etud["ilycee"] += " (%s)" % etud.get("villelycee", "") - etud["ilycee"] += "<br>" - else: - if etud.get("codelycee"): - etud["ilycee"] = format_lycee_from_code(etud["codelycee"]) - else: - etud["ilycee"] = "" - rap = "" - if etud.get("rapporteur") or etud.get("commentaire"): - rap = "Note du rapporteur" - if etud.get("rapporteur"): - rap += " (%s)" % etud["rapporteur"] - rap += ": " - if etud.get("commentaire"): - rap += "<em>%s</em>" % etud["commentaire"] - etud["rap"] = rap - - if etud.get("telephone"): - etud["telephonestr"] = "<b>Tél.:</b> " + format_telephone(etud["telephone"]) - else: - etud["telephonestr"] = "" - if etud.get("telephonemobile"): - etud["telephonemobilestr"] = "<b>Mobile:</b> " + format_telephone( - etud["telephonemobile"] - ) - else: - etud["telephonemobilestr"] = "" def etud_inscriptions_infos(etudid: int, ne="") -> dict: diff --git a/app/scodoc/sco_evaluation_check_abs.py b/app/scodoc/sco_evaluation_check_abs.py index bd6b8ded4a03c02dfd1590e5222b09f330e8ff88..eb35312dc10433fb103af7cf3d9d92925add3aa1 100644 --- a/app/scodoc/sco_evaluation_check_abs.py +++ b/app/scodoc/sco_evaluation_check_abs.py @@ -156,7 +156,7 @@ def evaluation_check_absences_html( H.append( f"""<li><a class="discretelink" href="{ url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ) }">{etud.nomprenom}</a>""" ) diff --git a/app/scodoc/sco_export_results.py b/app/scodoc/sco_export_results.py index d9a89b2b941a7fe5a1e84a13e0379ce0f4b0cc39..beaf7378e23246510c4a79eee95bbcd2aa82700d 100644 --- a/app/scodoc/sco_export_results.py +++ b/app/scodoc/sco_export_results.py @@ -173,9 +173,10 @@ def _build_results_list(dpv_by_sem, etuds_infos): "nom_usuel": etud["nom_usuel"], "prenom": etud["prenom"], "civilite_str": etud["civilite_str"], - "_nom_target": "%s" - % url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), - "_nom_td_attrs": 'id="%s" class="etudinfo"' % etudid, + "_nom_target": url_for( + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid + ), + "_nom_td_attrs": f'id="{etudid}" class="etudinfo"', "bac": bac.abbrev(), "parcours": dec["parcours"], } diff --git a/app/scodoc/sco_find_etud.py b/app/scodoc/sco_find_etud.py index 579992da10b1f92f6793ca3de959e261113d9a8b..d86f4dee0feea4d3873881bf8acb0077e615a2f7 100644 --- a/app/scodoc/sco_find_etud.py +++ b/app/scodoc/sco_find_etud.py @@ -145,7 +145,7 @@ def search_etud_in_dept(expnom=""): if "dest_url" in vals: endpoint = vals["dest_url"] else: - endpoint = "scolar.ficheEtud" + endpoint = "scolar.fiche_etud" if "parameters_keys" in vals: for key in vals["parameters_keys"].split(","): url_args[key] = vals[key] @@ -328,8 +328,9 @@ def table_etud_in_accessible_depts(expnom=None): """ result, accessible_depts = search_etud_in_accessible_depts(expnom=expnom) H = [ - """<div class="table_etud_in_accessible_depts">""", - """<h3>Recherche multi-département de "<tt>%s</tt>"</h3>""" % expnom, + f"""<div class="table_etud_in_accessible_depts"> + <h3>Recherche multi-département de "<tt>{expnom}</tt>"</h3> + """, ] for etuds in result: if etuds: @@ -337,9 +338,9 @@ def table_etud_in_accessible_depts(expnom=None): # H.append('<h3>Département %s</h3>' % DeptId) for e in etuds: e["_nomprenom_target"] = url_for( - "scolar.ficheEtud", scodoc_dept=dept_id, etudid=e["etudid"] + "scolar.fiche_etud", scodoc_dept=dept_id, etudid=e["etudid"] ) - e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"]) + e["_nomprenom_td_attrs"] = f"""id="{e['etudid']}" class="etudinfo" """ tab = GenTable( titles={"nomprenom": "Étudiants en " + dept_id}, diff --git a/app/scodoc/sco_formsemestre_exterieurs.py b/app/scodoc/sco_formsemestre_exterieurs.py index 22b600af26a2e599ab14a1b385fd94219c474b24..7c2cc31b59e6f9ce28931757a1e3b35eed7fd9d6 100644 --- a/app/scodoc/sco_formsemestre_exterieurs.py +++ b/app/scodoc/sco_formsemestre_exterieurs.py @@ -102,7 +102,7 @@ def formsemestre_ext_create_form(etudid, formsemestre_id): scodoc_dept=g.scodoc_dept, etudid=etudid, only_ext=1) }"> inscrire à un autre semestre</a>" </p> - <h3><a href="{ url_for('scolar.ficheEtud', + <h3><a href="{ url_for('scolar.fiche_etud', scodoc_dept=g.scodoc_dept, etudid=etudid) }" class="stdlink">Étudiant {etud.nomprenom}</a></h3> """, @@ -221,7 +221,7 @@ def formsemestre_ext_create_form(etudid, formsemestre_id): tf[2]["formation_id"] = orig_sem["formation_id"] formsemestre_ext_create(etudid, tf[2]) return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py index b1d73150f10ca86a6564d90b5b947ad120c82844..11c6b07d8590e1f839cda5bf7f4a9bae1bd34cc6 100644 --- a/app/scodoc/sco_formsemestre_inscriptions.py +++ b/app/scodoc/sco_formsemestre_inscriptions.py @@ -400,7 +400,7 @@ def formsemestre_inscription_with_modules_form(etudid, only_ext=False): H.append("<p>aucune session de formation !</p>") H.append( f"""<h3>ou</h3> <a class="stdlink" href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) }">retour à la fiche de {etud.nomprenom}</a>""" ) return "\n".join(H) + footer @@ -440,7 +440,7 @@ def formsemestre_inscription_with_modules( dans le semestre {formsemestre.titre_mois()} </p> <ul> - <li><a href="{url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + <li><a href="{url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) }" class="stdlink">retour à la fiche de {etud.nomprenom}</a> </li> <li><a href="{url_for( @@ -501,7 +501,7 @@ def formsemestre_inscription_with_modules( method="formsemestre_inscription_with_modules", ) return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) else: # formulaire choix groupe @@ -656,7 +656,7 @@ function chkbx_select(field_id, state) { return "\n".join(H) + "\n" + tf[1] + footer elif tf[0] == -1: return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) else: # Inscriptions aux modules choisis @@ -697,7 +697,7 @@ function chkbx_select(field_id, state) { """<h3>Aucune modification à effectuer</h3> <p><a class="stdlink" href="%s">retour à la fiche étudiant</a></p> """ - % url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + % url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) return "\n".join(H) + footer @@ -755,7 +755,7 @@ function chkbx_select(field_id, state) { etudid, modulesimpls_ainscrire, modulesimpls_adesinscrire, - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid), ) ) return "\n".join(H) + footer @@ -820,7 +820,7 @@ def do_moduleimpl_incription_options( <p><a class="stdlink" href="%s"> Retour à la fiche étudiant</a></p> """ - % url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), + % url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid), html_sco_header.sco_footer(), ] return "\n".join(H) @@ -885,7 +885,7 @@ def formsemestre_inscrits_ailleurs(formsemestre_id): '<li><a href="%s" class="discretelink">%s</a> : ' % ( url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"], ), diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 2b89c1f7243d6a93b1be284bbde5a81a767eb81a..6aa773a784412be38c0f130c9cdc9643e80f9278 100755 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -1457,7 +1457,7 @@ def formsemestre_warning_etuds_sans_note( noms = ", ".join( [ f"""<a href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) }" class="discretelink">{etud.nomprenom}</a>""" for etud in etuds ] @@ -1519,13 +1519,13 @@ def formsemestre_note_etuds_sans_notes( a déjà des notes""" ) return redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) else: noms = "</li><li>".join( [ f"""<a href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) }" class="discretelink">{etud.nomprenom}</a>""" for etud in etuds ] diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index d11b334c1d2b745daf64d0f2080d4343813485e5..c8c9556238fa9048e8ab9868f78efe11c50fa7ae 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -117,8 +117,8 @@ def formsemestre_validation_etud_form( if read_only: check = True - etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0] - Se = sco_cursus.get_situation_etud_cursus(etud, formsemestre_id) + etud_d = sco_etud.get_etud_info(etudid=etudid, filled=True)[0] + Se = sco_cursus.get_situation_etud_cursus(etud_d, formsemestre_id) if not Se.sem["etat"]: raise ScoValueError("validation: semestre verrouille") @@ -132,7 +132,7 @@ def formsemestre_validation_etud_form( H = [ html_sco_header.sco_header( - page_title=f"Parcours {etud['nomprenom']}", + page_title=f"Parcours {etud.nomprenom}", javascripts=["js/recap_parcours.js"], ) ] @@ -177,26 +177,22 @@ def formsemestre_validation_etud_form( H.append('<table style="width: 100%"><tr><td>') if not check: H.append( - '<h2 class="formsemestre">%s: validation %s%s</h2>Parcours: %s' - % ( - etud["nomprenom"], - Se.parcours.SESSION_NAME_A, - Se.parcours.SESSION_NAME, - Se.get_cursus_descr(), - ) + f"""<h2 class="formsemestre">{etud.nomprenom}: validation { + Se.parcours.SESSION_NAME_A}{Se.parcours.SESSION_NAME + }</h2>Parcours: {Se.get_cursus_descr()} + """ ) else: H.append( - '<h2 class="formsemestre">Parcours de %s</h2>%s' - % (etud["nomprenom"], Se.get_cursus_descr()) + f"""<h2 class="formsemestre">Parcours de {etud.nomprenom}</h2>{Se.get_cursus_descr()}""" ) H.append( - '</td><td style="text-align: right;"><a href="%s">%s</a></td></tr></table>' - % ( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), - sco_photos.etud_photo_html(etud, title="fiche de %s" % etud["nom"]), - ) + f"""</td><td style="text-align: right;"><a href="{ + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) + }">{etud.photo_html(title="fiche de " + etud.nomprenom)}</a></td></tr> + </table> + """ ) etud_etat = nt.get_etud_etat(etudid) @@ -210,7 +206,7 @@ def formsemestre_validation_etud_form( <div class="warning"> Impossible de statuer sur cet étudiant: il est démissionnaire ou défaillant (voir <a href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) }">sa fiche</a>) </div> """ @@ -289,7 +285,7 @@ def formsemestre_validation_etud_form( etudid=etudid, origin_formsemestre_id=formsemestre_id ).all() if autorisations: - H.append(". Autorisé%s à s'inscrire en " % etud["ne"]) + H.append(f". Autorisé{etud.e} à s'inscrire en ") H.append(", ".join([f"S{aut.semestre_id}" for aut in autorisations]) + ".") H.append("</p>") diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py index aacbae646505ccbed91b9c992a8fdb50d1a424c2..c02a3e881c0835b82efac4f276d3af4d164a9747 100644 --- a/app/scodoc/sco_groups_view.py +++ b/app/scodoc/sco_groups_view.py @@ -561,7 +561,7 @@ def groups_table( else: etud["_emailperso_target"] = "" fiche_url = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] ) etud["_nom_disp_target"] = fiche_url etud["_nom_disp_order"] = etud_sort_key(etud) @@ -829,7 +829,9 @@ def groups_table( etud, groups_infos.formsemestre_id ) m["parcours"] = Se.get_cursus_descr() - m["code_cursus"], _ = sco_report.get_code_cursus_etud(etud) + m["code_cursus"], _ = sco_report.get_code_cursus_etud( + etud["etudid"], sems=etud["sems"] + ) rows = [[m.get(k, "") for k in keys] for m in groups_infos.members] title = "etudiants_%s" % groups_infos.groups_filename xls = sco_excel.excel_simple_table(titles=titles, lines=rows, sheet_name=title) diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py index 8a9ef08f8f7ad91275eca8525acc3a5314aab40c..f97e0d4409131d8f27a3634ea7b356f352135528 100644 --- a/app/scodoc/sco_inscr_passage.py +++ b/app/scodoc/sco_inscr_passage.py @@ -669,7 +669,7 @@ def etuds_select_boxes( elink = """<a class="discretelink %s" href="%s">%s</a>""" % ( c, url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"], ), diff --git a/app/scodoc/sco_lycee.py b/app/scodoc/sco_lycee.py index 606fabf2a7a226455c95d501c8904e72f9aadaaa..da274dc9f9672fbe7779852fdd0e2db0a93feb9e 100644 --- a/app/scodoc/sco_lycee.py +++ b/app/scodoc/sco_lycee.py @@ -143,7 +143,9 @@ def _table_etuds_lycees(etuds, group_lycees, title, preferences, no_links=False) if not no_links: for etud in etuds: fiche_url = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] + "scolar.fiche_etud", + scodoc_dept=g.scodoc_dept, + etudid=etud["etudid"], ) etud["_nom_target"] = fiche_url etud["_prenom_target"] = fiche_url @@ -232,7 +234,7 @@ def js_coords_lycees(etuds_by_lycee): '<a class="discretelink" href="%s" title="">%s</a>' % ( url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=e["etudid"], ), diff --git a/app/scodoc/sco_moduleimpl_inscriptions.py b/app/scodoc/sco_moduleimpl_inscriptions.py index 487368f0c174b2a6941cb404c50c5baa7bb65141..c110dacfae101872fc14adfc3155ea48d674512c 100644 --- a/app/scodoc/sco_moduleimpl_inscriptions.py +++ b/app/scodoc/sco_moduleimpl_inscriptions.py @@ -186,7 +186,7 @@ def moduleimpl_inscriptions_edit( H.append( f"""<a class="discretelink etudinfo" href="{ url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"], ) @@ -421,7 +421,7 @@ def moduleimpl_inscriptions_stats(formsemestre_id): H.append( f"""<li class="etud"><a class="discretelink" href="{ url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"], ) @@ -542,7 +542,7 @@ def _list_but_ue_inscriptions(res: NotesTableCompat, read_only: bool = True) -> H.append( f"""<tr><td><a class="discretelink etudinfo" id={etud.id} href="{url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id, )}" @@ -694,7 +694,7 @@ def _fmt_etud_set(etudids, max_list_size=7) -> str: [ f"""<a class="discretelink" href="{ url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id ) }">{etud.nomprenom}</a>""" for etud in sorted(etuds, key=attrgetter("sort_key")) diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py index 2a23059fe8bc9e27483114bd90e2cd797d1757e1..1bdb148c90951fc010f94ce31129586acc324bfb 100644 --- a/app/scodoc/sco_page_etud.py +++ b/app/scodoc/sco_page_etud.py @@ -25,38 +25,37 @@ # ############################################################################## -"""ScoDoc ficheEtud +"""ScoDoc fiche_etud Fiche description d'un étudiant et de son parcours """ -from flask import abort, url_for, g, render_template, request +from flask import url_for, g, render_template, request from flask_login import current_user +import sqlalchemy as sa -from app import db, log +from app import log +from app.auth.models import User from app.but import cursus_but -from app.models.etudiants import make_etud_args -from app.models import Identite, FormSemestre, ScoDocSiteConfig -from app.scodoc import html_sco_header -from app.scodoc import htmlutils -from app.scodoc import sco_archives_etud -from app.scodoc import sco_bac -from app.scodoc import codes_cursus -from app.scodoc import sco_formsemestre -from app.scodoc import sco_formsemestre_status -from app.scodoc import sco_groups -from app.scodoc import sco_cursus -from app.scodoc import sco_permissions_check -from app.scodoc import sco_photos -from app.scodoc import sco_users -from app.scodoc import sco_report -from app.scodoc import sco_etud +from app.models import Adresse, EtudAnnotation, FormSemestre, Identite, ScoDocSiteConfig +from app.scodoc import ( + codes_cursus, + html_sco_header, + htmlutils, + sco_archives_etud, + sco_bac, + sco_cursus, + sco_etud, + sco_formsemestre_status, + sco_groups, + sco_permissions_check, + sco_report, +) from app.scodoc.sco_bulletins import etud_descr_situation_semestre from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_formsemestre_validation import formsemestre_recap_parcours_table from app.scodoc.sco_permissions import Permission import app.scodoc.sco_utils as scu -import app.scodoc.notesdb as ndb def _menu_scolarite( @@ -157,29 +156,18 @@ def _menu_scolarite( ) -def ficheEtud(etudid=None): +def fiche_etud(etudid=None): "fiche d'informations sur un etudiant" - authuser = current_user - cnx = ndb.GetDBConnexion() - if etudid: - try: # pour les bookmarks avec d'anciens ids... - etudid = int(etudid) - except ValueError: - raise ScoValueError("id invalide !") from ValueError - # la sidebar est differente s'il y a ou pas un etudid - # voir html_sidebar.sidebar() - g.etudid = etudid - args = make_etud_args(etudid=etudid) - etuds = sco_etud.etudident_list(cnx, args) - if not etuds: - log(f"ficheEtud: etudid={etudid!r} request.args={request.args!r}") - raise ScoValueError("Étudiant inexistant !") - etud_ = etuds[0] # transition: etud_ à éliminer et remplacer par etud - etudid = etud_["etudid"] - etud = Identite.get_etud(etudid) - sco_etud.fill_etuds_info([etud_]) - # - info = etud_ + restrict_etud_data = not current_user.has_permission(Permission.ViewEtudData) + try: + etud = Identite.get_etud(etudid) + except Exception as exc: + log(f"fiche_etud: etudid={etudid!r} request.args={request.args!r}") + raise ScoValueError("Étudiant inexistant !") from exc + # la sidebar est differente s'il y a ou pas un etudid + # voir html_sidebar.sidebar() + g.etudid = etudid + info = etud.to_dict_scodoc7(restrict=restrict_etud_data) if etud.prenom_etat_civil: info["etat_civil"] = ( "<h3>Etat-civil: " @@ -193,45 +181,24 @@ def ficheEtud(etudid=None): else: info["etat_civil"] = "" info["ScoURL"] = scu.ScoURL() - info["authuser"] = authuser - info["info_naissance"] = info["date_naissance"] - if info["lieu_naissance"]: - info["info_naissance"] += " à " + info["lieu_naissance"] - if info["dept_naissance"]: - info["info_naissance"] += f" ({info['dept_naissance']})" - info["etudfoto"] = sco_photos.etud_photo_html(etud_) - if ( - (not info["domicile"]) - and (not info["codepostaldomicile"]) - and (not info["villedomicile"]) - ): - info["domicile"] = "<em>inconnue</em>" - if info["paysdomicile"]: - pays = sco_etud.format_pays(info["paysdomicile"]) - if pays: - info["paysdomicile"] = "(%s)" % pays - else: - info["paysdomicile"] = "" - if info["telephone"] or info["telephonemobile"]: - info["telephones"] = "<br>%s %s" % ( - info["telephonestr"], - info["telephonemobilestr"], - ) - else: - info["telephones"] = "" - # e-mail: - if info["email_default"]: - info["emaillink"] = ", ".join( - [ - '<a class="stdlink" href="mailto:%s">%s</a>' % (m, m) - for m in [etud_["email"], etud_["emailperso"]] - if m - ] - ) + info["authuser"] = current_user + if restrict_etud_data: + info["info_naissance"] = "" + adresse = None else: - info["emaillink"] = "<em>(pas d'adresse e-mail)</em>" + info["info_naissance"] = info["date_naissance"] + if info["lieu_naissance"]: + info["info_naissance"] += " à " + info["lieu_naissance"] + if info["dept_naissance"]: + info["info_naissance"] += f" ({info['dept_naissance']})" + adresse = etud.adresses.first() + info.update(_format_adresse(adresse)) + + info.update(etud.inscription_descr()) + info["etudfoto"] = etud.photo_html() + # Champ dépendant des permissions: - if authuser.has_permission(Permission.EtudChangeAdr): + if current_user.has_permission(Permission.EtudChangeAdr): info[ "modifadresse" ] = f"""<a class="stdlink" href="{ @@ -242,36 +209,32 @@ def ficheEtud(etudid=None): info["modifadresse"] = "" # Groupes: + inscription_courante = etud.inscription_courante() sco_groups.etud_add_group_infos( info, - info["cursem"]["formsemestre_id"] if info["cursem"] else None, + inscription_courante.formsemestre.id if inscription_courante else None, only_to_show=True, ) # Parcours de l'étudiant - if info["sems"]: - info["last_formsemestre_id"] = info["sems"][0]["formsemestre_id"] - else: - info["last_formsemestre_id"] = "" + inscriptions = etud.inscriptions() + info["last_formsemestre_id"] = ( + inscriptions[0].formsemestre.id if inscriptions else "" + ) + sem_info = {} - for sem in info["sems"]: - formsemestre: FormSemestre = db.session.get( - FormSemestre, sem["formsemestre_id"] - ) - if sem["ins"]["etat"] != scu.INSCRIT: + for inscription in inscriptions: + formsemestre = inscription.formsemestre + if inscription.etat != scu.INSCRIT: descr, _ = etud_descr_situation_semestre( etudid, formsemestre, - info["ne"], + etud.e, show_date_inscr=False, ) grlink = f"""<span class="fontred">{descr["situation"]}</span>""" else: e = {"etudid": etudid} - sco_groups.etud_add_group_infos( - e, - sem["formsemestre_id"], - only_to_show=True, - ) + sco_groups.etud_add_group_infos(e, formsemestre.id, only_to_show=True) grlinks = [] for partition in e["partitions"].values(): @@ -289,16 +252,16 @@ def ficheEtud(etudid=None): ) grlink = ", ".join(grlinks) # infos ajoutées au semestre dans le parcours (groupe, menu) - menu = _menu_scolarite(authuser, formsemestre, etudid, sem["ins"]["etat"]) + menu = _menu_scolarite(current_user, formsemestre, etudid, inscription.etat) if menu: - sem_info[sem["formsemestre_id"]] = ( + sem_info[formsemestre.id] = ( "<table><tr><td>" + grlink + "</td><td>" + menu + "</td></tr></table>" ) else: - sem_info[sem["formsemestre_id"]] = grlink + sem_info[formsemestre.id] = grlink - if info["sems"]: - Se = sco_cursus.get_situation_etud_cursus(etud_, info["last_formsemestre_id"]) + if inscriptions: + Se = sco_cursus.get_situation_etud_cursus(info, info["last_formsemestre_id"]) info["liste_inscriptions"] = formsemestre_recap_parcours_table( Se, etudid, @@ -318,20 +281,19 @@ def ficheEtud(etudid=None): </span> """ ) - last_formsemestre: FormSemestre = db.session.get( - FormSemestre, info["sems"][0]["formsemestre_id"] - ) + last_formsemestre: FormSemestre = inscriptions[0].formsemestre if last_formsemestre.formation.is_apc() and last_formsemestre.semestre_id > 2: info[ "link_bul_pdf" ] += f""" <span class="link_bul_pdf"> <a class="stdlink" href="{ - url_for("notes.validation_rcues", scodoc_dept=g.scodoc_dept, etudid=etudid, formsemestre_id=last_formsemestre.id) + url_for("notes.validation_rcues", + scodoc_dept=g.scodoc_dept, etudid=etudid, formsemestre_id=last_formsemestre.id) }">Visualiser les compétences BUT</a> </span> """ - if authuser.has_permission(Permission.EtudInscrit): + if current_user.has_permission(Permission.EtudInscrit): info[ "link_inscrire_ailleurs" ] = f"""<span class="link_bul_pdf"><a class="stdlink" href="{ @@ -348,8 +310,8 @@ def ficheEtud(etudid=None): info["link_inscrire_ailleurs"] = "" else: # non inscrit - l = [f"""<p><b>Étudiant{info["ne"]} non inscrit{info["ne"]}"""] - if authuser.has_permission(Permission.EtudInscrit): + l = [f"""<p><b>Étudiant{etud.e} non inscrit{etud.e}"""] + if current_user.has_permission(Permission.EtudInscrit): l.append( f"""<a href="{ url_for("notes.formsemestre_inscription_with_modules_form", @@ -362,44 +324,50 @@ def ficheEtud(etudid=None): info["link_inscrire_ailleurs"] = "" # Liste des annotations - alist = [] - annos = sco_etud.etud_annotations_list(cnx, args={"etudid": etudid}) - for a in annos: - if not sco_permissions_check.can_suppress_annotation(a["id"]): - a["dellink"] = "" - else: - a["dellink"] = ( - '<td class="annodel"><a href="doSuppressAnnotation?etudid=%s&annotation_id=%s">%s</a></td>' - % ( - etudid, - a["id"], - scu.icontag( + annotations_list = [] + annotations = EtudAnnotation.query.filter_by(etudid=etud.id).order_by( + sa.desc(EtudAnnotation.date) + ) + for annot in annotations: + del_link = ( + f"""<td class="annodel"><a href="{ + url_for("scolar.doSuppressAnnotation", + scodoc_dept=g.scodoc_dept, etudid=etudid, annotation_id=annot.id)}">{ + scu.icontag( "delete_img", border="0", alt="suppress", title="Supprimer cette annotation", - ), ) - ) - author = sco_users.user_info(a["author"]) - alist.append( - f"""<tr><td><span class="annodate">Le {a['date']} par {author['prenomnom']} : - </span><span class="annoc">{a['comment']}</span></td>{a['dellink']}</tr> + }</a></td>""" + if sco_permissions_check.can_suppress_annotation(annot.id) + else "" + ) + + author = User.query.filter_by(user_name=annot.author).first() + annotations_list.append( + f"""<tr><td><span class="annodate">Le {annot.date.strftime("%d/%m/%Y") if annot.date else "?"} + par {author.get_prenomnom() if author else "?"} : + </span><span class="annoc">{annot.comment or ""}</span></td>{del_link}</tr> """ ) - info["liste_annotations"] = "\n".join(alist) + info["liste_annotations"] = "\n".join(annotations_list) # fiche admission - has_adm_notes = ( - info["math"] or info["physique"] or info["anglais"] or info["francais"] + infos_admission = _infos_admission(etud, restrict_etud_data) + has_adm_notes = any( + infos_admission[k] for k in ("math", "physique", "anglais", "francais") ) - has_bac_info = ( - info["bac"] - or info["specialite"] - or info["annee_bac"] - or info["rapporteur"] - or info["commentaire"] - or info["classement"] - or info["type_admission"] + has_bac_info = any( + infos_admission[k] + for k in ( + "bac_specialite", + "annee_bac", + "rapporteur", + "commentaire", + "classement", + "type_admission", + "rap", + ) ) if has_bac_info or has_adm_notes: adm_tmpl = """<!-- Donnees admission --> @@ -411,7 +379,7 @@ def ficheEtud(etudid=None): <tr><th>Bac</th><th>Année</th><th>Rg</th> <th>Math</th><th>Physique</th><th>Anglais</th><th>Français</th></tr> <tr> -<td>%(bac)s (%(specialite)s)</td> +<td>%(bac_specialite)s</td> <td>%(annee_bac)s </td> <td>%(classement)s</td> <td>%(math)s</td><td>%(physique)s</td><td>%(anglais)s</td><td>%(francais)s</td> @@ -419,22 +387,22 @@ def ficheEtud(etudid=None): </table> """ adm_tmpl += """ -<div>Bac %(bac)s (%(specialite)s) obtenu en %(annee_bac)s </div> -<div class="ilycee">%(ilycee)s</div>""" - if info["type_admission"] or info["classement"]: +<div>Bac %(bac_specialite)s obtenu en %(annee_bac)s </div> +<div class="info_lycee">%(info_lycee)s</div>""" + if infos_admission["type_admission"] or infos_admission["classement"]: adm_tmpl += """<div class="vadmission">""" - if info["type_admission"]: + if infos_admission["type_admission"]: adm_tmpl += """<span>Voie d'admission: <span class="etud_type_admission">%(type_admission)s</span></span> """ - if info["classement"]: + if infos_admission["classement"]: adm_tmpl += """<span>Rang admission: <span class="etud_type_admission">%(classement)s</span></span>""" - if info["type_admission"] or info["classement"]: + if infos_admission["type_admission"] or infos_admission["classement"]: adm_tmpl += "</div>" - if info["rap"]: + if infos_admission["rap"]: adm_tmpl += """<div class="note_rapporteur">%(rap)s</div>""" adm_tmpl += """</div>""" else: adm_tmpl = "" # pas de boite "info admission" - info["adm_data"] = adm_tmpl % info + info["adm_data"] = adm_tmpl % infos_admission # Fichiers archivés: info["fichiers_archive_htm"] = ( @@ -455,18 +423,16 @@ def ficheEtud(etudid=None): if has_debouche: info[ "debouche_html" - ] = """<div id="fichedebouche" data-readonly="%s" data-etudid="%s"> + ] = f"""<div id="fichedebouche" + data-readonly="{suivi_readonly}" + data-etudid="{info['etudid']}"> <span class="debouche_tit">Devenir:</span> <div><form> <ul class="listdebouches"> - %s + {link_add_suivi} </ul> </form></div> - </div>""" % ( - suivi_readonly, - info["etudid"], - link_add_suivi, - ) + </div>""" else: info["debouche_html"] = "" # pas de boite "devenir" # @@ -492,70 +458,92 @@ def ficheEtud(etudid=None): else: info["groupes_row"] = "" info["menus_etud"] = menus_etud(etudid) - if info["boursier"]: + if info["boursier"] and not restrict_etud_data: info["bourse_span"] = """<span class="boursier">boursier</span>""" else: info["bourse_span"] = "" - # raccordement provisoire pour juillet 2022, avant refonte complète de cette fiche... - # info["but_infos_mkup"] = jury_but_view.infos_fiche_etud_html(etudid) - - # XXX dev - info["but_cursus_mkup"] = "" - if info["sems"]: - last_sem = FormSemestre.query.get_or_404(info["sems"][0]["formsemestre_id"]) - if last_sem.formation.is_apc(): - but_cursus = cursus_but.EtudCursusBUT(etud, last_sem.formation) - info[ - "but_cursus_mkup" - ] = f""" - <div class="section_but"> - {render_template( - "but/cursus_etud.j2", - cursus=but_cursus, - scu=scu, - )} - <div class="link_validation_rcues"> - <a href="{url_for("notes.validation_rcues", - scodoc_dept=g.scodoc_dept, etudid=etudid, - formsemestre_id=last_formsemestre.id)}" - title="Visualiser les compétences BUT" - > - <img src="/ScoDoc/static/icons/parcours-but.png" alt="validation_rcues" height="100px"/> - </a> - </div> + # Liens vers compétences BUT + if last_formsemestre and last_formsemestre.formation.is_apc(): + but_cursus = cursus_but.EtudCursusBUT(etud, last_formsemestre.formation) + info[ + "but_cursus_mkup" + ] = f""" + <div class="section_but"> + {render_template( + "but/cursus_etud.j2", + cursus=but_cursus, + scu=scu, + )} + <div class="link_validation_rcues"> + <a class="stdlink" href="{url_for("notes.validation_rcues", + scodoc_dept=g.scodoc_dept, etudid=etudid, + formsemestre_id=last_formsemestre.id)}" + title="Visualiser les compétences BUT" + > + <img src="/ScoDoc/static/icons/parcours-but.png" alt="validation_rcues" height="100px"/> + <div>Compétences BUT</div> + </a> </div> - """ + </div> + """ + else: + info["but_cursus_mkup"] = "" + + adresse_template = ( + "" + if restrict_etud_data + else """ + <!-- Adresse --> + <div class="ficheadresse" id="ficheadresse"> + <table> + <tr> + <td class="fichetitre2">Adresse :</td> + <td> %(domicile)s %(codepostaldomicile)s %(villedomicile)s %(paysdomicile)s + %(modifadresse)s + %(telephones)s + </td> + </tr> + </table> + </div> + """ + ) + + info_naissance = ( + f"""<tr><td class="fichetitre2">Né{etud.e} le :</td><td>{info["info_naissance"]}</td></tr>""" + if info["info_naissance"] + else "" + ) + situation_template = ( + f""" + <div class="fichesituation"> + <div class="fichetablesitu"> + <table> + <tr><td class="fichetitre2">Situation :</td><td>%(situation)s %(bourse_span)s</td></tr> + %(groupes_row)s + {info_naissance} + </table> + """ + + adresse_template + + """ + </div> + </div> + """ + ) - tmpl = """<div class="menus_etud">%(menus_etud)s</div> -<div class="ficheEtud" id="ficheEtud"><table> + tmpl = ( + """<div class="menus_etud">%(menus_etud)s</div> +<div class="fiche_etud" id="fiche_etud"><table> <tr><td> <h2>%(nomprenom)s (%(inscription)s)</h2> %(etat_civil)s -<span>%(emaillink)s</span> +<span>%(email_link)s</span> </td><td class="photocell"> <a href="etud_photo_orig_page?etudid=%(etudid)s">%(etudfoto)s</a> </td></tr></table> - -<div class="fichesituation"> -<div class="fichetablesitu"> -<table> -<tr><td class="fichetitre2">Situation :</td><td>%(situation)s %(bourse_span)s</td></tr> -%(groupes_row)s -<tr><td class="fichetitre2">Né%(ne)s le :</td><td>%(info_naissance)s</td></tr> -</table> - - -<!-- Adresse --> -<div class="ficheadresse" id="ficheadresse"> -<table><tr> -<td class="fichetitre2">Adresse :</td><td> %(domicile)s %(codepostaldomicile)s %(villedomicile)s %(paysdomicile)s -%(modifadresse)s -%(telephones)s -</td></tr></table> -</div> -</div> -</div> +""" + + situation_template + + """ %(inscriptions_mkup)s @@ -595,8 +583,9 @@ def ficheEtud(etudid=None): </div> """ + ) header = html_sco_header.sco_header( - page_title="Fiche étudiant %(prenom)s %(nom)s" % info, + page_title=f"Fiche étudiant {etud.nomprenom}", cssstyles=[ "libjs/jQuery-tagEditor/jquery.tag-editor.css", "css/jury_but.css", @@ -614,6 +603,92 @@ def ficheEtud(etudid=None): return header + tmpl % info + html_sco_header.sco_footer() +def _format_adresse(adresse: Adresse | None) -> dict: + """{ "telephonestr" : ..., "telephonemobilestr" : ... } (formats html)""" + d = { + "telephonestr": ("<b>Tél.:</b> " + scu.format_telephone(adresse.telephone)) + if (adresse and adresse.telephone) + else "", + "telephonemobilestr": ( + "<b>Mobile:</b> " + scu.format_telephone(adresse.telephonemobile) + ) + if (adresse and adresse.telephonemobile) + else "", + # e-mail: + "email_link": ", ".join( + [ + f"""<a class="stdlink" href="mailto:{m}">{m}</a>""" + for m in [adresse.email, adresse.emailperso] + if m + ] + ) + if adresse and (adresse.email or adresse.emailperso) + else "", + "domicile": (adresse.domicile or "") + if adresse + and (adresse.domicile or adresse.codepostaldomicile or adresse.villedomicile) + else "<em>inconnue</em>", + "paysdomicile": f"{sco_etud.format_pays(adresse.paysdomicile)}" + if adresse and adresse.paysdomicile + else "", + } + d["telephones"] = ( + f"<br>{d['telephonestr']} {d['telephonemobilestr']}" + if adresse and (adresse.telephone or adresse.telephonemobile) + else "" + ) + return d + + +def _infos_admission(etud: Identite, restrict_etud_data: bool) -> dict: + """dict with adminission data, restricted or not""" + # info sur rapporteur et son commentaire + rap = "" + if not restrict_etud_data: + if etud.admission.rapporteur or etud.admission.commentaire: + rap = "Note du rapporteur" + if etud.admission.rapporteur: + rap += f" ({etud.admission.rapporteur})" + rap += ": " + if etud.admission.commentaire: + rap += f"<em>{etud.admission.commentaire}</em>" + # nom du lycée + if restrict_etud_data: + info_lycee = "" + elif etud.admission.nomlycee: + info_lycee = "Lycée " + sco_etud.format_lycee(etud.admission.nomlycee) + if etud.admission.villelycee: + info_lycee += f" ({etud.admission.villelycee})" + info_lycee += "<br>" + elif etud.admission.codelycee: + info_lycee = sco_etud.format_lycee_from_code(etud.admission.codelycee) + else: + info_lycee = "" + + return { + # infos accessibles à tous: + "bac_specialite": f"{etud.admission.bac or ''}{(' '+(etud.admission.specialite or '')) if etud.admission.specialite else ''}", + "annee_bac": etud.admission.annee_bac or "", + # infos protégées par ViewEtudData: + "info_lycee": info_lycee, + "rapporteur": etud.admission.rapporteur if not restrict_etud_data else "", + "rap": rap, + "commentaire": (etud.admission.commentaire or "") + if not restrict_etud_data + else "", + "classement": (etud.admission.classement or "") + if not restrict_etud_data + else "", + "type_admission": (etud.admission.type_admission or "") + if not restrict_etud_data + else "", + "math": (etud.admission.math or "") if not restrict_etud_data else "", + "physique": (etud.admission.physique or "") if not restrict_etud_data else "", + "anglais": (etud.admission.anglais or "") if not restrict_etud_data else "", + "francais": (etud.admission.francais or "") if not restrict_etud_data else "", + } + + def menus_etud(etudid): """Menu etudiant (operations sur l'etudiant)""" authuser = current_user @@ -623,7 +698,7 @@ def menus_etud(etudid): menuEtud = [ { "title": etud["nomprenom"], - "endpoint": "scolar.ficheEtud", + "endpoint": "scolar.fiche_etud", "args": {"etudid": etud["etudid"]}, "enabled": True, "helpmsg": "Fiche étudiant", @@ -671,36 +746,33 @@ def etud_info_html(etudid, with_photo="1", debug=False): """ formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request() with_photo = int(with_photo) - etuds = sco_etud.get_etud_info(filled=True) - if etuds: - etud = etuds[0] - else: - abort(404, "etudiant inconnu") - photo_html = sco_photos.etud_photo_html(etud, title="fiche de " + etud["nom"]) - # experimental: may be too slow to be here - code_cursus, _ = sco_report.get_code_cursus_etud(etud, prefix="S", separator=", ") + etud = Identite.get_etud(etudid) - bac = sco_bac.Baccalaureat(etud["bac"], etud["specialite"]) + photo_html = etud.photo_html(etud, title="fiche de " + etud.nomprenom) + code_cursus, _ = sco_report.get_code_cursus_etud( + etud, formsemestres=etud.get_formsemestres(), prefix="S", separator=", " + ) + bac = sco_bac.Baccalaureat(etud.admission.bac, etud.admission.specialite) bac_abbrev = bac.abbrev() H = f"""<div class="etud_info_div"> <div class="eid_left"> <div class="eid_nom"><div><a class="stdlink" target="_blank" href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) }">{etud["nomprenom"]}</a></div></div> <div class="eid_info eid_bac">Bac: <span class="eid_bac">{bac_abbrev}</span></div> <div class="eid_info eid_parcours">{code_cursus}</div> """ # Informations sur l'etudiant dans le semestre courant: - sem = None + formsemestre = None if formsemestre_id: # un semestre est spécifié par la page - sem = sco_formsemestre.get_formsemestre(formsemestre_id) - elif etud["cursem"]: # le semestre "en cours" pour l'étudiant - sem = etud["cursem"] - if sem: - groups = sco_groups.get_etud_groups(etudid, formsemestre_id) + formsemestre = FormSemestre.get_formsemestre(formsemestre_id) + elif inscription_courante: # le semestre "en cours" pour l'étudiant + formsemestre = inscription_courante.formsemestre + if formsemestre: + groups = sco_groups.get_etud_groups(etudid, formsemestre.id) grc = sco_groups.listgroups_abbrev(groups) - H += f"""<div class="eid_info">En <b>S{sem["semestre_id"]}</b>: {grc}</div>""" + H += f"""<div class="eid_info">En <b>S{formsemestre.semestre_id}</b>: {grc}</div>""" H += "</div>" # fin partie gauche (eid_left) if with_photo: H += '<span class="eid_right">' + photo_html + "</span>" diff --git a/app/scodoc/sco_permissions.py b/app/scodoc/sco_permissions.py index d371833c97281c7a42a43bdc346a01449679496b..a9c437b876eb5d2dc938bb7d01016d3629078ee8 100644 --- a/app/scodoc/sco_permissions.py +++ b/app/scodoc/sco_permissions.py @@ -55,6 +55,7 @@ _SCO_PERMISSIONS = ( "Exporter les données de l'application relations entreprises", ), (1 << 29, "UsersChangeCASId", "Paramétrer l'id CAS"), + (1 << 30, "ViewEtudData", "Accéder aux données personnelles des étudiants"), # # XXX inutilisée ? (1 << 40, "EtudChangePhoto", "Modifier la photo d'un étudiant"), # Permissions du module Assiduité) diff --git a/app/scodoc/sco_poursuite_dut.py b/app/scodoc/sco_poursuite_dut.py index cfb4a2ed9506658c1602bef9b89a518202ee7938..f4038962a4fcaf0676d36bfe5dbd4b71af2df40f 100644 --- a/app/scodoc/sco_poursuite_dut.py +++ b/app/scodoc/sco_poursuite_dut.py @@ -187,7 +187,7 @@ def formsemestre_poursuite_report(formsemestre_id, fmt="html"): ids = [] for etud in etuds: fiche_url = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] ) etud["_nom_target"] = fiche_url etud["_prenom_target"] = fiche_url diff --git a/app/scodoc/sco_pv_forms.py b/app/scodoc/sco_pv_forms.py index 54722be17fcd6a6e8f93ca21588bec0ef2a58ab5..ce5e624c129cc06ea1d817ba286f392f5bd7d553 100644 --- a/app/scodoc/sco_pv_forms.py +++ b/app/scodoc/sco_pv_forms.py @@ -144,7 +144,7 @@ def pvjury_table( "code_nip": e["identite"]["code_nip"], "nomprenom": e["identite"]["nomprenom"], "_nomprenom_target": url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=e["identite"]["etudid"], ), @@ -351,7 +351,7 @@ def formsemestre_pvjury_pdf(formsemestre_id, group_ids: list[int] = None, etudid # PV pour ce seul étudiant: etud = Identite.get_etud(etudid) etuddescr = f"""<a class="discretelink" href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) }">{etud.nomprenom}</a>""" etudids = [etudid] else: diff --git a/app/scodoc/sco_report.py b/app/scodoc/sco_report.py index d532ea2c91f8db05d7dfc4b5f481b14ed69000c9..769c202f7ea8ae0d4fa5a18e6af755f9f354525a 100644 --- a/app/scodoc/sco_report.py +++ b/app/scodoc/sco_report.py @@ -1017,34 +1017,60 @@ EXP_LIC = re.compile(r"licence", re.I) EXP_LPRO = re.compile(r"professionnelle", re.I) -def _codesem(sem, short=True, prefix=""): +def _code_sem( + semestre_id: int, titre: str, mois_debut: int, short=True, prefix="" +) -> str: "code semestre: S1 ou S1d" - idx = sem["semestre_id"] + idx = semestre_id # semestre décalé ? # les semestres pairs normaux commencent entre janvier et mars # les impairs normaux entre aout et decembre d = "" - if idx and idx > 0 and sem["date_debut"]: - mois_debut = int(sem["date_debut"].split("/")[1]) + if idx > 0: if (idx % 2 and mois_debut < 3) or (idx % 2 == 0 and mois_debut >= 8): d = "d" if idx == -1: if short: idx = "Autre " else: - idx = sem["titre"] + " " + idx = titre + " " idx = EXP_LPRO.sub("pro.", idx) idx = EXP_LIC.sub("Lic.", idx) prefix = "" # indique titre au lieu de Sn - return "%s%s%s" % (prefix, idx, d) + return prefix + str(idx) + d -def get_code_cursus_etud(etud, prefix="", separator=""): +def _code_sem_formsemestre(formsemestre: FormSemestre, short=True, prefix="") -> str: + "code semestre: S1 ou S1d" + titre = formsemestre.titre + mois_debut = formsemestre.date_debut.month + semestre_id = formsemestre.semestre_id + return _code_sem(semestre_id, titre, mois_debut, short=short, prefix=prefix) + + +def _code_sem_dict(sem, short=True, prefix="") -> str: + "code semestre: S1 ou S1d, à parit d'un dict (sem ScoDoc 7)" + titre = sem["titre"] + mois_debut = int(sem["date_debut"].split("/")[1]) if sem["date_debut"] else 0 + semestre_id = sem["semestre_id"] + return _code_sem(semestre_id, titre, mois_debut, short=short, prefix=prefix) + + +def get_code_cursus_etud( + etudid: int, + sems: list[dict] = None, + formsemestres: list[FormSemestre] | None = None, + prefix="", + separator="", +) -> tuple[str, dict]: """calcule un code de cursus (parcours) pour un etudiant exemples: 1234A pour un etudiant ayant effectué S1, S2, S3, S4 puis diplome 12D pour un étudiant en S1, S2 puis démission en S2 12R pour un etudiant en S1, S2 réorienté en fin de S2 + + On peut passer soir la liste des semestres dict (anciennes fonctions ScoDoc7) + soit la liste des FormSemestre. Construit aussi un dict: { semestre_id : decision_jury | None } """ # Nota: approche plus moderne: @@ -1054,31 +1080,37 @@ def get_code_cursus_etud(etud, prefix="", separator=""): # p = [] decisions_jury = {} + + if formsemestres is None: + formsemestres = [ + FormSemestre.query.get_or_404(s["formsemestre_id"]) for s in (sems or []) + ] + # élimine les semestres spéciaux hors cursus (LP en 1 sem., ...) - sems = [s for s in etud["sems"] if s["semestre_id"] >= 0] - i = len(sems) - 1 + formsemestres = [s for s in formsemestres if s.semestre_id >= 0] + i = len(formsemestres) - 1 while i >= 0: - s = sems[i] # 'sems' est a l'envers, du plus recent au plus ancien - s_formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"]) - nt: NotesTableCompat = res_sem.load_formsemestre_results(s_formsemestre) + # 'sems' est a l'envers, du plus recent au plus ancien + formsemestre = formsemestres[i] + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) - p.append(_codesem(s, prefix=prefix)) + p.append(_code_sem_formsemestre(formsemestre, prefix=prefix)) # code decisions jury de chaque semestre: - if nt.get_etud_etat(etud["etudid"]) == "D": - decisions_jury[s["semestre_id"]] = "DEM" + if nt.get_etud_etat(etudid) == "D": + decisions_jury[formsemestre.semestre_id] = "DEM" else: - dec = nt.get_etud_decision_sem(etud["etudid"]) + dec = nt.get_etud_decision_sem(etudid) if not dec: - decisions_jury[s["semestre_id"]] = "" + decisions_jury[formsemestre.semestre_id] = "" else: - decisions_jury[s["semestre_id"]] = dec["code"] + decisions_jury[formsemestre.semestre_id] = dec["code"] # code etat dans le code_cursus sur dernier semestre seulement if i == 0: # Démission - if nt.get_etud_etat(etud["etudid"]) == "D": + if nt.get_etud_etat(etudid) == "D": p.append(":D") else: - dec = nt.get_etud_decision_sem(etud["etudid"]) + dec = nt.get_etud_decision_sem(etudid) if dec and dec["code"] in codes_cursus.CODES_SEM_REO: p.append(":R") if ( @@ -1176,14 +1208,16 @@ def table_suivi_cursus(formsemestre_id, only_primo=False, grouped_parcours=True) ) = tsp_etud_list(formsemestre_id, only_primo=only_primo) codes_etuds = collections.defaultdict(list) for etud in etuds: - etud["code_cursus"], etud["decisions_jury"] = get_code_cursus_etud(etud) + etud["code_cursus"], etud["decisions_jury"] = get_code_cursus_etud( + etud["etudid"], sems=etud["sems"] + ) codes_etuds[etud["code_cursus"]].append(etud) fiche_url = url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] ) etud["_nom_target"] = fiche_url etud["_prenom_target"] = fiche_url - etud["_nom_td_attrs"] = 'id="%s" class="etudinfo"' % (etud["etudid"]) + etud["_nom_td_attrs"] = f'''id="{etud['etudid']}" class="etudinfo"''' titles = { "parcours": "Code cursus", @@ -1461,7 +1495,7 @@ def graph_cursus( else: modalite = "" label = "%s%s\\n%d/%s - %d/%s\\n%d" % ( - _codesem(s, short=False, prefix="S"), + _code_sem_dict(s, short=False, prefix="S"), modalite, s["mois_debut_ord"], s["annee_debut"][2:], diff --git a/app/scodoc/sco_roles_default.py b/app/scodoc/sco_roles_default.py index 75cbdedd3639eecd1322666e2d6a6f4102affe2d..a727a94b2ad4516d2d4069cdd30d5e651b52ccea 100644 --- a/app/scodoc/sco_roles_default.py +++ b/app/scodoc/sco_roles_default.py @@ -13,8 +13,9 @@ SCO_ROLES_DEFAULTS = { p.EnsView, p.EtudAddAnnotations, p.Observateur, - p.UsersView, p.ScoView, + p.ViewEtudData, + p.UsersView, ), "Secr": ( p.AbsAddBillet, @@ -23,8 +24,9 @@ SCO_ROLES_DEFAULTS = { p.EtudAddAnnotations, p.EtudChangeAdr, p.Observateur, - p.UsersView, p.ScoView, + p.UsersView, + p.ViewEtudData, ), # Admin est le chef du département, pas le "super admin" # on doit donc lister toutes ses permissions: @@ -44,9 +46,10 @@ SCO_ROLES_DEFAULTS = { p.EtudInscrit, p.EditFormSemestre, p.Observateur, + p.ScoView, p.UsersAdmin, p.UsersView, - p.ScoView, + p.ViewEtudData, ), # Rôles pour l'application relations entreprises # ObservateurEntreprise est un observateur de l'application entreprise @@ -57,7 +60,8 @@ SCO_ROLES_DEFAULTS = { p.RelationsEntrepEdit, p.RelationsEntrepViewCorrs, ), - # AdminEntreprise est un admin de l'application entreprise (toutes les actions possibles de l'application) + # AdminEntreprise est un admin de l'application entreprise + # (toutes les actions possibles de l'application) "AdminEntreprise": ( p.RelationsEntrepView, p.RelationsEntrepEdit, diff --git a/app/scodoc/sco_trombino.py b/app/scodoc/sco_trombino.py index c197cefd9f56678c8d9875c4b30d95392138086d..a77e6ec31682695baa364321a4fab63a5e980a99 100644 --- a/app/scodoc/sco_trombino.py +++ b/app/scodoc/sco_trombino.py @@ -156,7 +156,7 @@ def trombino_html(groups_infos): '<a href="%s">%s</a>' % ( url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=t["etudid"] + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=t["etudid"] ), foto, ) diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index a6d5d8b917e51f49ee998dd2db76e8d887293593..97bfe47e5700fbb2a669107f6e2d945b29bda7a6 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -431,7 +431,7 @@ APO_MISSING_CODE_STR = "----" # shown in HTML pages in place of missing code Ap EDIT_NB_ETAPES = 6 # Nombre max de codes étapes / semestre presentés dans l'UI IT_SITUATION_MISSING_STR = ( - "____" # shown on ficheEtud (devenir) in place of empty situation + "____" # shown on fiche_etud (devenir) in place of empty situation ) RANG_ATTENTE_STR = "(attente)" # rang affiché sur bulletins quand notes en attente @@ -1285,6 +1285,27 @@ def format_prenom(s): return " ".join(r) +def format_telephone(n: str | None) -> str: + "Format a phone number for display" + if n is None: + return "" + if len(n) < 7: + return n + n = n.replace(" ", "").replace(".", "") + i = 0 + r = "" + j = len(n) - 1 + while j >= 0: + r = n[j] + r + if i % 2 == 1 and j != 0: + r = " " + r + i += 1 + j -= 1 + if len(r) == 13 and r[0] != "0": + r = "0" + r + return r + + # def timedate_human_repr(): "representation du temps courant pour utilisateur" diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index ac2c691a35f7ad5b25cfc7436ee97a4f082294d0..c6d62c491b81dd97b17af517b565d9b08fcf2a54 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -724,7 +724,7 @@ div.scoinfos { /* ----- fiches etudiants ------ */ -div.ficheEtud { +div.fiche_etud { background-color: #f5edc8; /* rgb(255,240,128); */ border: 1px solid gray; @@ -739,7 +739,7 @@ div.menus_etud { margin-top: 1px; } -div.ficheEtud h2 { +div.fiche_etud h2 { padding-top: 10px; } @@ -925,7 +925,7 @@ td.fichetitre2 { vertical-align: top; } -.ficheEtud span.boursier { +.fiche_etud span.boursier { background-color: red; color: white; margin-left: 12px; @@ -963,6 +963,7 @@ div.section_but { div.section_but > div.link_validation_rcues { align-self: center; + text-align: center; } .ficheannotations { diff --git a/app/templates/bul_head.j2 b/app/templates/bul_head.j2 index 8c725f012fc4215194ea424328a660d82806f962..0635c12c09df940c2b5373a6a04596133e44cd76 100644 --- a/app/templates/bul_head.j2 +++ b/app/templates/bul_head.j2 @@ -7,7 +7,7 @@ {% if not is_apc %} <h2><a class="discretelink" href="{{ url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id, + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id, )}}">{{etud.nomprenom}}</a></h2> {% endif %} <form name="f" method="GET" action="{{request.base_url}}"> @@ -81,7 +81,7 @@ </div> {% if not is_apc %} <div class="bull_photo"><a href="{{ - url_for('scolar.ficheEtud', scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for('scolar.fiche_etud', scodoc_dept=g.scodoc_dept, etudid=etud.id) }}">{{etud.photo_html(title="fiche de " + etud["nom"])|safe}}</a> </div> {% endif %} diff --git a/app/templates/entreprises/fiche_entreprise.j2 b/app/templates/entreprises/fiche_entreprise.j2 index e2c0da71ab1859b663e10a54158bb7d76cca830a..08bf7ff996033a8fdac8db6c41c4f1337ddf7788 100644 --- a/app/templates/entreprises/fiche_entreprise.j2 +++ b/app/templates/entreprises/fiche_entreprise.j2 @@ -183,7 +183,7 @@ <td>{{ (stage_apprentissage.date_fin-stage_apprentissage.date_debut).days//7 }} semaines</td> <td>{{ stage_apprentissage.type_offre }}</td> <td><a - href="{{ url_for('scolar.ficheEtud', scodoc_dept=etudiant.dept_id|get_dept_acronym, etudid=stage_apprentissage.etudid) }}">{{ + href="{{ url_for('scolar.fiche_etud', scodoc_dept=etudiant.dept_id|get_dept_acronym, etudid=stage_apprentissage.etudid) }}">{{ etudiant.nom|format_nom }} {{ etudiant.prenom|format_prenom }}</a></td> <td>{% if stage_apprentissage.formation_text %}{{ stage_apprentissage.formation_text }}{% endif %}</td> <td>{{ stage_apprentissage.notes }}</td> diff --git a/app/templates/scolar/partition_editor.j2 b/app/templates/scolar/partition_editor.j2 index ef0e534592e7f8ebcd2e898bdd6345f1fb8f9762..6d5bcf72e12359db5ecfa1cc69dfe4ffcce1abe6 100644 --- a/app/templates/scolar/partition_editor.j2 +++ b/app/templates/scolar/partition_editor.j2 @@ -165,7 +165,7 @@ span.calendarEdit { etudiants.forEach(etudiant => { output += ` <div data-etudid="${etudiant.etudid}" > - <div class=nom data-etudid="${etudiant.etudid}" data-nom="${etudiant.nom_disp}" data-prenom="${etudiant.prenom}"><a href="ficheEtud?etudid=${etudiant.etudid}">${etudiant.nom_disp} ${etudiant.prenom}</a><div class=small>${etudiant.bac}</div></div> + <div class=nom data-etudid="${etudiant.etudid}" data-nom="${etudiant.nom_disp}" data-prenom="${etudiant.prenom}"><a href="fiche_etud?etudid=${etudiant.etudid}">${etudiant.nom_disp} ${etudiant.prenom}</a><div class=small>${etudiant.bac}</div></div> ${(() => { let output = "<div class=grpPartitions>"; arrayPartitions.forEach((partition) => { diff --git a/app/templates/sidebar.j2 b/app/templates/sidebar.j2 index 865208c1ac71f345cec3c09c58256ed819240430..884931ad39f16f67bf6c7953a0d7310785f93c23 100755 --- a/app/templates/sidebar.j2 +++ b/app/templates/sidebar.j2 @@ -51,7 +51,7 @@ <div class="etud-insidebar"> {% if sco.etud %} <h2 id="insidebar-etud"><a href="{{url_for( - 'scolar.ficheEtud', scodoc_dept=g.scodoc_dept, etudid=sco.etud.id )}}" class="sidebar"> + 'scolar.fiche_etud', scodoc_dept=g.scodoc_dept, etudid=sco.etud.id )}}" class="sidebar"> <span class="fontred">{{sco.etud.nomprenom}}</span></a> </h2> <b>Absences</b> diff --git a/app/views/absences.py b/app/views/absences.py index 52082b2f8f0fff05093e218b18cc81f5fac55533..75e61f67bf9882ec0ea164acbfaceb0c76599c5b 100644 --- a/app/views/absences.py +++ b/app/views/absences.py @@ -358,7 +358,7 @@ def process_billet_absence_form(billet_id: int): page_title=f"Traitement billet d'absence de {etud.nomprenom}", ), f"""<h2>Traitement du billet {billet.id} : <a class="discretelink" href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) }">{etud.nomprenom}</a></h2> """, ] diff --git a/app/views/notes.py b/app/views/notes.py index 08086b4444897820f0c2eb5b42b75bf1f1f00db2..ae977682490d35f2e64a18664db218c9f9daea81 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -1193,7 +1193,7 @@ def view_module_abs(moduleimpl_id, fmt="html"): "nojust": nb_abs - nb_abs_just, "total": nb_abs, "_nomprenom_target": url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id ), } ) @@ -1492,7 +1492,7 @@ def formsemestre_desinscription(etudid, formsemestre_id, dialog_confirmed=False) flash("Étudiant désinscrit") return redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) @@ -2371,13 +2371,13 @@ def formsemestre_validation_but( <div class="nom_etud">{etud.nomprenom}</div> </div> <div class="bull_photo"><a href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) }">{etud.photo_html(title="fiche de " + etud.nomprenom)}</a> </div> </div> <div class="warning">Impossible de statuer sur cet étudiant: il est démissionnaire ou défaillant (voir <a class="stdlink" href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) }">sa fiche</a>) </div> </div> @@ -2450,7 +2450,7 @@ def formsemestre_validation_but( <div class="nom_etud">{etud.nomprenom}</div> </div> <div class="bull_photo"><a href="{ - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) }">{etud.photo_html(title="fiche de " + etud.nomprenom)}</a> </div> </div> @@ -2725,7 +2725,7 @@ def formsemestre_validation_suppress_etud( etud = Identite.get_etud(etudid) if formsemestre.formation.is_apc(): next_url = url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid, ) @@ -2915,7 +2915,7 @@ def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int): flash("Décisions de jury effacées") return redirect( url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id, ) @@ -2931,7 +2931,7 @@ def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int): "jury/erase_decisions_annee_formation.j2", annee=annee, cancel_url=url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id ), etud=etud, formation=formation, diff --git a/app/views/scolar.py b/app/views/scolar.py index 7be21ee042e0383985fb500168ea0506b8658992..d842dc1b2ab36d356c2a2b217bc35ab79bb86c3d 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -328,7 +328,7 @@ def showEtudLog(etudid, fmt="html"): filename="log_" + scu.make_filename(etud["nomprenom"]), html_next_section=f""" <ul><li> - <a href="{url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)}"> + <a href="{url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)}"> fiche de {etud['nomprenom']}</a></li> </ul>""", preferences=sco_preferences.SemPreferences(), @@ -625,7 +625,7 @@ def etud_info(etudid=None, fmt="xml"): # -------------------------- FICHE ETUDIANT -------------------------- -sco_publish("/ficheEtud", sco_page_etud.ficheEtud, Permission.ScoView) +sco_publish("/fiche_etud", sco_page_etud.fiche_etud, Permission.ScoView) sco_publish( "/etud_upload_file_form", @@ -720,7 +720,7 @@ def doAddAnnotation(etudid, comment): ) logdb(cnx, method="addAnnotation", etudid=etudid) return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) @@ -745,7 +745,7 @@ def doSuppressAnnotation(etudid, annotation_id): flash("Annotation supprimée") return flask.redirect( url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid, ) @@ -809,7 +809,7 @@ def form_change_coordonnees(etudid): initvalues=adr, submitlabel="Valider le formulaire", ) - dest_url = url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + dest_url = url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) if tf[0] == 0: return "\n".join(H) + tf[1] + html_sco_header.sco_footer() elif tf[0] == -1: @@ -1009,7 +1009,7 @@ def etud_photo_orig_page(etudid=None): html_sco_header.sco_header(page_title=etud["nomprenom"]), "<h2>%s</h2>" % etud["nomprenom"], '<div><a href="%s">' - % url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), + % url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid), sco_photos.etud_photo_orig_html(etud), "</a></div>", html_sco_header.sco_footer(), @@ -1053,7 +1053,7 @@ def form_change_photo(etudid=None): submitlabel="Valider", cancelbutton="Annuler", ) - dest_url = url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + dest_url = url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) if tf[0] == 0: return ( "\n".join(H) @@ -1092,7 +1092,7 @@ def form_suppress_photo(etudid=None, dialog_confirmed=False): f"<p>Confirmer la suppression de la photo de {etud.nom_disp()} ?</p>", dest_url="", cancel_url=url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id ), parameters={"etudid": etud.id}, ) @@ -1100,7 +1100,7 @@ def form_suppress_photo(etudid=None, dialog_confirmed=False): sco_photos.suppress_photo(etud) return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) ) @@ -1229,7 +1229,7 @@ def _do_dem_or_def_etud( ) if redirect: return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) @@ -1301,7 +1301,7 @@ def _do_cancel_dem_or_def( f"<p>Confirmer l'annulation de la {operation_name} ?</p>", dest_url="", cancel_url=url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ), parameters={"etudid": etudid, "formsemestre_id": formsemestre_id}, ) @@ -1325,7 +1325,7 @@ def _do_cancel_dem_or_def( flash(f"{operation_name} annulée.") return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) @@ -1784,7 +1784,7 @@ def _etudident_create_or_edit_form(edit): sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre_id) # return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid) ) @@ -1802,7 +1802,7 @@ def etud_copy_in_other_dept(etudid: int): action = request.form.get("action") if action == "cancel": return flask.redirect( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id) + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id) ) try: formsemestre_id = int(request.form.get("formsemestre_id")) @@ -1833,7 +1833,7 @@ def etud_copy_in_other_dept(etudid: int): # Attention, ce redirect change de département ! return flask.redirect( url_for( - "scolar.ficheEtud", + "scolar.fiche_etud", scodoc_dept=formsemestre.departement.acronym, etudid=new_etud.id, ) @@ -1881,12 +1881,12 @@ def etudident_delete(etudid: int = -1, dialog_confirmed=False): d'un semestre ! (pour cela, passez par sa fiche, menu associé au semestre)</p> <p><a class="stdlink" href="{url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid )}">Vérifier la fiche de {etud.nomprenom}</a> </p>""", dest_url="", cancel_url=url_for( - "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid + "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ), OK="Supprimer définitivement cet étudiant", parameters={"etudid": etudid}, @@ -2018,7 +2018,7 @@ def check_group_apogee(group_id, etat=None, fix=False, fixmail=False): H.append( '<tr><td><a href="%s">%s</a></td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>' % ( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), + url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid), nom, nom_usuel, prenom, diff --git a/migrations/versions/3fa988ff8970_config_permission_viewetuddata.py b/migrations/versions/3fa988ff8970_config_permission_viewetuddata.py new file mode 100644 index 0000000000000000000000000000000000000000..b4f6d62d3289d585f3957db857b44523d8b6f036 --- /dev/null +++ b/migrations/versions/3fa988ff8970_config_permission_viewetuddata.py @@ -0,0 +1,44 @@ +"""config nouvelle permission ViewEtudData: donne aux rôles Ens, Secr, Admin + +Revision ID: 3fa988ff8970 +Revises: b4859c04205f +Create Date: 2024-01-20 13:59:31.491442 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "3fa988ff8970" +down_revision = "b4859c04205f" +branch_labels = None +depends_on = None + + +def upgrade(): + # Donne la permission ViewEtudData aux rôles Admin, Ens, Secr + # cette permission est 1<<30 + op.execute( + "UPDATE role SET permissions = permissions | (1<<30) where role.name = 'Admin';" + ) + op.execute( + "UPDATE role SET permissions = permissions | (1<<30) where role.name = 'Ens';" + ) + op.execute( + "UPDATE role SET permissions = permissions | (1<<30) where role.name = 'Secr';" + ) + + +def downgrade(): + # retire la permission ViewEtudData aux rôles Admin, Ens, Secr + # cette permission est 1<<30 + op.execute( + "UPDATE role SET permissions = permissions & ~(1<<30) where role.name = 'Admin';" + ) + op.execute( + "UPDATE role SET permissions = permissions & ~(1<<30) where role.name = 'Ens';" + ) + op.execute( + "UPDATE role SET permissions = permissions & ~(1<<30) where role.name = 'Secr';" + ) diff --git a/tests/unit/test_etudiants.py b/tests/unit/test_etudiants.py index 47346ca87d6a07f7702bf91d03ca2f4d811806fd..f2d83d2ec3a1b4e8d5f5144139a8657721ea5893 100644 --- a/tests/unit/test_etudiants.py +++ b/tests/unit/test_etudiants.py @@ -357,16 +357,11 @@ def test_import_etuds_xlsx(test_client): "civilite_etat_civil_str": "Mme", "nom_disp": "NOM_USUEL10 (NOM10)", "ne": "(e)", - "email_default": "", "inscription": "ancien", "situation": "ancien élève", "inscriptionstr": "ancien", "inscription_formsemestre_id": None, "etatincursem": "?", - "ilycee": "", - "rap": "", - "telephonestr": "", - "telephonemobilestr": "", }, ) # Test de search_etud_in_dept