From 34d64b3fd86d043664b8220aa11b18471b553418 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 7 May 2022 08:23:30 +0200 Subject: [PATCH 1/3] =?UTF-8?q?API:=20Fix=20acc=C3=A8s=20par=20INE=20et=20?= =?UTF-8?q?NIP=20alphanum=C3=A9riques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/absences.py | 4 +- app/api/etudiants.py | 22 ++++---- tests/api/test_api_etudiants.py | 45 +++++++++++++--- tests/api/test_api_jury.py | 52 +++++++++---------- .../fakedatabase/create_test_api_database.py | 15 +++--- 5 files changed, 88 insertions(+), 50 deletions(-) diff --git a/app/api/absences.py b/app/api/absences.py index 1992454c3..44b1c3500 100644 --- a/app/api/absences.py +++ b/app/api/absences.py @@ -14,8 +14,8 @@ from app.scodoc.sco_permissions import Permission @bp.route("/absences/etudid/", methods=["GET"]) -@bp.route("/absences/nip/", methods=["GET"]) -@bp.route("/absences/ine/", methods=["GET"]) +@bp.route("/absences/nip/", methods=["GET"]) +@bp.route("/absences/ine/", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) def absences(etudid: int = None, nip: int = None, ine: int = None): diff --git a/app/api/etudiants.py b/app/api/etudiants.py index afeb8abab..a41634f95 100644 --- a/app/api/etudiants.py +++ b/app/api/etudiants.py @@ -55,8 +55,8 @@ def etudiants_courant(long=False): @bp.route("/etudiant/etudid/", methods=["GET"]) -@bp.route("/etudiant/nip/", methods=["GET"]) -@bp.route("/etudiant/ine/", methods=["GET"]) +@bp.route("/etudiant/nip/", methods=["GET"]) +@bp.route("/etudiant/ine/", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) def etudiant(etudid: int = None, nip: int = None, ine: int = None): @@ -109,8 +109,8 @@ def etudiant(etudid: int = None, nip: int = None, ine: int = None): @bp.route("/etudiant/etudid//formsemestres") -@bp.route("/etudiant/nip//formsemestres") -@bp.route("/etudiant/ine//formsemestres") +@bp.route("/etudiant/nip//formsemestres") +@bp.route("/etudiant/ine//formsemestres") @token_auth.login_required @token_permission_required(Permission.APIView) def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None): @@ -175,12 +175,12 @@ def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None) defaults={"version": "long"}, ) @bp.route( - "/etudiant/nip//formsemestre//bulletin", + "/etudiant/nip//formsemestre//bulletin", methods=["GET"], defaults={"version": "long"}, ) @bp.route( - "/etudiant/ine//formsemestre//bulletin", + "/etudiant/ine//formsemestre//bulletin", methods=["GET"], defaults={"version": "long"}, ) @@ -190,12 +190,12 @@ def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None) defaults={"version": "short"}, ) @bp.route( - "/etudiant/nip//formsemestre//bulletin/short", + "/etudiant/nip//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short"}, ) @bp.route( - "/etudiant/ine//formsemestre//bulletin/short", + "/etudiant/ine//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short"}, ) @@ -408,10 +408,12 @@ def etudiant_bulletin_semestre( methods=["GET"], ) @bp.route( - "/etudiant/nip//formsemestre//groups", methods=["GET"] + "/etudiant/nip//formsemestre//groups", + methods=["GET"], ) @bp.route( - "/etudiant/ine//formsemestre//groups", methods=["GET"] + "/etudiant/ine//formsemestre//groups", + methods=["GET"], ) @token_auth.login_required @token_permission_required(Permission.APIView) diff --git a/tests/api/test_api_etudiants.py b/tests/api/test_api_etudiants.py index 621f0859b..c0ccfc9e7 100644 --- a/tests/api/test_api_etudiants.py +++ b/tests/api/test_api_etudiants.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -"""Test Logos +"""Test API: accès aux étudiants Utilisation : créer les variables d'environnement: (indiquer les valeurs @@ -58,7 +58,7 @@ def test_etudiants_courant(api_headers): def test_etudiant(api_headers): """ - Route: + Routes: /etudiant/etudid, /etudiant/nip, /etudiant/ine """ ######### Test etudid ######### @@ -87,7 +87,7 @@ def test_etudiant(api_headers): ######### Test code ine ######### r = requests.get( - API_URL + "/etudiant/ine/1", + API_URL + "/etudiant/ine/INE1", headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -97,6 +97,39 @@ def test_etudiant(api_headers): fields_ok = verify_fields(etud, ETUD_FIELDS) assert fields_ok is True + # Vérifie le requetage des 3 1er étudiants + for etudid in (1, 2, 3): + r = requests.get( + f"{API_URL }/etudiant/etudid/{etudid}", + headers=api_headers, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 200 + etud = r.json() + nip = etud["code_nip"] + ine = etud["code_ine"] + assert isinstance(etud["id"], int) + assert isinstance(nip, str) + assert isinstance(ine, str) + r = requests.get( + f"{API_URL }/etudiant/nip/{nip}", + headers=api_headers, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 200 + etud_nip = r.json() + # On doit avoir obtenue le même étudiant + assert etud_nip == etud + r = requests.get( + f"{API_URL }/etudiant/ine/{ine}", + headers=api_headers, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 200 + etud_ine = r.json() + # On doit avoir obtenue le même étudiant + assert etud_ine == etud + def test_etudiant_formsemestres(api_headers): """ @@ -132,7 +165,7 @@ def test_etudiant_formsemestres(api_headers): ######### Test code ine ######### r = requests.get( - API_URL + "/etudiant/ine/1/formsemestres", + API_URL + "/etudiant/ine/INE1/formsemestres", headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -172,7 +205,7 @@ def test_etudiant_bulletin_semestre(api_headers): ######### Test code ine ######### r = requests.get( - API_URL + "/etudiant/ine/1/formsemestre/1/bulletin", + API_URL + "/etudiant/ine/INE1/formsemestre/1/bulletin", headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -235,7 +268,7 @@ def test_etudiant_groups(api_headers): ######### Test code ine ######### r = requests.get( - API_URL + "/etudiant/ine/1/formsemestre/1/groups", + API_URL + "/etudiant/ine/INE1/formsemestre/1/groups", headers=api_headers, verify=CHECK_CERTIFICATE, ) diff --git a/tests/api/test_api_jury.py b/tests/api/test_api_jury.py index 13b0a0f1e..23454d00b 100644 --- a/tests/api/test_api_jury.py +++ b/tests/api/test_api_jury.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -"""Test Logos +"""Test API Jurys XXX TODO A ECRIRE Utilisation : créer les variables d'environnement: (indiquer les valeurs @@ -77,30 +77,30 @@ def test_set_decision_jury(api_headers): assert r.status_code == 200 -def test_annule_decision_jury(api_headers): - """ - Route: - """ - r = requests.get( - SCODOC_URL - + "/ScoDoc/api/jury/etudid//formsemestre//annule_decision", - headers=api_headers, - verify=CHECK_CERTIFICATE, - ) - assert r.status_code == 200 +# def test_annule_decision_jury(api_headers): +# """ +# Route: +# """ +# r = requests.get( +# SCODOC_URL +# + "/ScoDoc/api/jury/etudid//formsemestre//annule_decision", +# headers=api_headers, +# verify=CHECK_CERTIFICATE, +# ) +# assert r.status_code == 200 - r = requests.get( - SCODOC_URL - + "/ScoDoc/api/jury/nip//formsemestre//annule_decision", - headers=api_headers, - verify=CHECK_CERTIFICATE, - ) - assert r.status_code == 200 +# r = requests.get( +# SCODOC_URL +# + "/ScoDoc/api/jury/nip//formsemestre//annule_decision", +# headers=api_headers, +# verify=CHECK_CERTIFICATE, +# ) +# assert r.status_code == 200 - r = requests.get( - SCODOC_URL - + "/ScoDoc/api/jury/ine//formsemestre//annule_decision", - headers=api_headers, - verify=CHECK_CERTIFICATE, - ) - assert r.status_code == 200 +# r = requests.get( +# SCODOC_URL +# + "/ScoDoc/api/jury/ine//formsemestre//annule_decision", +# headers=api_headers, +# verify=CHECK_CERTIFICATE, +# ) +# assert r.status_code == 200 diff --git a/tools/fakedatabase/create_test_api_database.py b/tools/fakedatabase/create_test_api_database.py index ad1198f81..bfe4800e2 100644 --- a/tools/fakedatabase/create_test_api_database.py +++ b/tools/fakedatabase/create_test_api_database.py @@ -28,7 +28,7 @@ import sys from app.auth.models import Role, User from app import models -from app.models import Departement, Formation, FormSemestre +from app.models import Departement, Formation, FormSemestre, Identite from app import db from app.scodoc import ( sco_cache, @@ -95,15 +95,18 @@ def create_users(dept: Departement) -> tuple: return user, other -def create_fake_etud(dept: Departement) -> models.Identite: - """Créé un faux étudiant et l'insère dans la base""" +def create_fake_etud(dept: Departement) -> Identite: + """Créé un faux étudiant et l'insère dans la base.""" civilite = random.choice(("M", "F", "X")) nom, prenom = nomprenom(civilite) - etud = models.Identite(civilite=civilite, nom=nom, prenom=prenom, dept_id=dept.id) + etud: Identite = Identite( + civilite=civilite, nom=nom, prenom=prenom, dept_id=dept.id + ) db.session.add(etud) db.session.commit() - etud.code_nip = etud.id - etud.code_ine = etud.id + # créé un étudiant sur deux avec un NIP et INE alphanumérique + etud.code_nip = f"{etud.id}" if (etud.id % 2) else f"NIP{etud.id}" + etud.code_ine = f"INE{etud.id}" if (etud.id % 2) else f"{etud.id}" db.session.add(etud) db.session.commit() adresse = models.Adresse( From 21d9655655fe1b007df09e4f01573cb7d77cd271 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 9 May 2022 18:32:54 +0200 Subject: [PATCH 2/3] Export recap complet en excel brut --- app/scodoc/sco_recapcomplet.py | 10 +++++++--- sco_version.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index 179014cfa..6a22c1953 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -84,12 +84,15 @@ def formsemestre_recapcomplet( selected_etudid: etudid sélectionné (pour scroller au bon endroit) """ formsemestre = FormSemestre.query.get_or_404(formsemestre_id) - + file_formats = {"csv", "json", "xls", "xlsx", "xlsall", "xml"} + supported_formats = file_formats | {"html"} + if tabformat not in supported_formats: + raise ScoValueError(f"Format non supporté: {tabformat}") + is_file = tabformat in file_formats modejury = int(modejury) - xml_with_decisions = int(xml_with_decisions) force_publishing = int(force_publishing) - is_file = tabformat in {"csv", "json", "xls", "xlsx", "xlsall", "xml"} + data = _do_formsemestre_recapcomplet( formsemestre_id, format=tabformat, @@ -128,6 +131,7 @@ def formsemestre_recapcomplet( for (format, label) in ( ("html", "Tableau"), ("evals", "Avec toutes les évaluations"), + ("xlsx", "Excel non formatté"), ("xml", "Bulletins XML (obsolète)"), ("json", "Bulletins JSON"), ): diff --git a/sco_version.py b/sco_version.py index fe5771ed7..8c3e5f8bd 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.2.17" +SCOVERSION = "9.2.18" SCONAME = "ScoDoc" From 6e43ec6feb91f849fc0a206686b9127727833d51 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 9 May 2022 19:56:40 +0200 Subject: [PATCH 3/3] =?UTF-8?q?Affichage=20groupes=20sur=20page=20=C3=A9tu?= =?UTF-8?q?d.=20Closes=20#373?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_groups.py | 16 ++++++-- app/scodoc/sco_page_etud.py | 73 +++++++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py index 8e834b231..80d8e02c6 100644 --- a/app/scodoc/sco_groups.py +++ b/app/scodoc/sco_groups.py @@ -413,8 +413,15 @@ def formsemestre_get_etud_groupnames(formsemestre_id, attr="group_name"): return R -def etud_add_group_infos(etud, formsemestre_id, sep=" "): - """Add informations on partitions and group memberships to etud (a dict with an etudid)""" +def etud_add_group_infos(etud, formsemestre_id, sep=" ", only_to_show=False): + """Add informations on partitions and group memberships to etud + (a dict with an etudid) + If only_to_show, restrict to partions such that show_in_lists is True. + + etud['partitions'] = { partition_id : group + partition_name } + etud['groupes'] = "TDB, Gr2, TPB1" + etud['partitionsgroupes'] = "Groupes TD:TDB, Groupes TP:Gr2 (...)" + """ etud[ "partitions" ] = collections.OrderedDict() # partition_id : group + partition_name @@ -423,11 +430,14 @@ def etud_add_group_infos(etud, formsemestre_id, sep=" "): return etud infos = ndb.SimpleDictFetch( - """SELECT p.partition_name, g.*, g.id AS group_id + """SELECT p.partition_name, p.show_in_lists, g.*, g.id AS group_id FROM group_descr g, partition p, group_membership gm WHERE gm.etudid=%(etudid)s and gm.group_id = g.id and g.partition_id = p.id and p.formsemestre_id = %(formsemestre_id)s + """ + + (" and (p.show_in_lists is True) " if only_to_show else "") + + """ ORDER BY p.numero """, {"etudid": etud["etudid"], "formsemestre_id": formsemestre_id}, diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py index 3a99d2232..2631ef45c 100644 --- a/app/scodoc/sco_page_etud.py +++ b/app/scodoc/sco_page_etud.py @@ -153,14 +153,14 @@ def ficheEtud(etudid=None): try: # pour les bookmarks avec d'anciens ids... etudid = int(etudid) except ValueError: - raise ScoValueError("id invalide !") + 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("ficheEtud: etudid=%s request.args=%s" % (etudid, request.args)) + log(f"ficheEtud: etudid={etudid!r} request.args={request.args!r}") raise ScoValueError("Etudiant inexistant !") etud = etuds[0] etudid = etud["etudid"] @@ -173,7 +173,7 @@ def ficheEtud(etudid=None): if info["lieu_naissance"]: info["info_naissance"] += " à " + info["lieu_naissance"] if info["dept_naissance"]: - info["info_naissance"] += " (%s)" % info["dept_naissance"] + info["info_naissance"] += f" ({info['dept_naissance']})" info["etudfoto"] = sco_photos.etud_photo_html(etud) if ( (not info["domicile"]) @@ -205,7 +205,7 @@ def ficheEtud(etudid=None): ) else: info["emaillink"] = "(pas d'adresse e-mail)" - # champs dependant des permissions + # Champ dépendant des permissions: if authuser.has_permission(Permission.ScoEtudChangeAdr): info["modifadresse"] = ( 'modifier adresse' @@ -216,9 +216,10 @@ def ficheEtud(etudid=None): # Groupes: sco_groups.etud_add_group_infos( - info, info["cursem"]["formsemestre_id"] if info["cursem"] else None + info, + info["cursem"]["formsemestre_id"] if info["cursem"] else None, + only_to_show=True, ) - # Parcours de l'étudiant if info["sems"]: info["last_formsemestre_id"] = info["sems"][0]["formsemestre_id"] @@ -235,15 +236,28 @@ def ficheEtud(etudid=None): ) grlink = '%s' % descr["situation"] else: - group = sco_groups.get_etud_main_group(etudid, sem["formsemestre_id"]) - if group["partition_name"]: - gr_name = group["group_name"] - else: - gr_name = "tous" - grlink = ( - 'groupe %s' - % (group["group_id"], gr_name) + e = {"etudid": etudid} + sco_groups.etud_add_group_infos( + e, + sem["formsemestre_id"], + only_to_show=True, ) + + grlinks = [] + for partition in e["partitions"].values(): + if partition["partition_name"]: + gr_name = partition["group_name"] + else: + gr_name = "tous" + + grlinks.append( + f"""{gr_name} + """ + ) + grlink = ", ".join(grlinks) # infos ajoutées au semestre dans le parcours (groupe, menu) menu = _menuScolarite(authuser, sem, etudid) if menu: @@ -296,17 +310,18 @@ def ficheEtud(etudid=None): if not sco_permissions_check.can_suppress_annotation(a["id"]): a["dellink"] = "" else: - a[ - "dellink" - ] = '%s' % ( - etudid, - a["id"], - scu.icontag( - "delete_img", - border="0", - alt="suppress", - title="Supprimer cette annotation", - ), + a["dellink"] = ( + '%s' + % ( + etudid, + a["id"], + scu.icontag( + "delete_img", + border="0", + alt="suppress", + title="Supprimer cette annotation", + ), + ) ) author = sco_users.user_info(a["author"]) alist.append( @@ -422,9 +437,11 @@ def ficheEtud(etudid=None): # if info["groupes"].strip(): - info["groupes_row"] = ( - 'Groupe :%(groupes)s' % info - ) + info[ + "groupes_row" + ] = f""" + Groupes :{info['groupes']} + """ else: info["groupes_row"] = "" info["menus_etud"] = menus_etud(etudid)