diff --git a/app/api/etudiants.py b/app/api/etudiants.py index 41a95760b..264271cda 100755 --- a/app/api/etudiants.py +++ b/app/api/etudiants.py @@ -20,6 +20,7 @@ from sqlalchemy.dialects.postgresql import VARCHAR import app from app.api import api_bp as bp, api_web_bp from app.api import tools +from app.but import bulletin_but_court from app.decorators import scodoc, permission_required from app.models import ( Admission, @@ -35,6 +36,7 @@ from app.scodoc.sco_permissions import Permission from app.scodoc.sco_utils import json_error, suppress_accents import app.scodoc.sco_photos as sco_photos +import app.scodoc.sco_utils as scu # Un exemple: # @bp.route("/api_function/") @@ -364,7 +366,7 @@ def bulletin( formsemestre_id : l'id d'un formsemestre code_type : "etudid", "nip" ou "ine" code : valeur du code INE, NIP ou etudid, selon code_type. - version : type de bulletin (par défaut, "long"): short, long, long_mat + version : type de bulletin (par défaut, "long"): short, long, selectedevals, butcourt pdf : si spécifié, bulletin au format PDF (et non JSON). Exemple de résultat : voir https://scodoc.org/ScoDoc9API/#bulletin @@ -372,6 +374,8 @@ def bulletin( if version == "pdf": version = "long" pdf = True + if version not in scu.BULLETINS_VERSIONS_BUT: + return json_error(404, "version invalide") # return f"{code_type}={code}, version={version}, pdf={pdf}" formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first_or_404() dept = Departement.query.filter_by(id=formsemestre.dept_id).first_or_404() @@ -394,6 +398,12 @@ def bulletin( etud = query.first() if etud is None: return json_error(404, message="etudiant inexistant") + + if version == "butcourt": + if pdf: + return bulletin_but_court.bulletin_but(formsemestre_id, etud.id, fmt="pdf") + else: + return json_error(404, message="butcourt available only in pdf") if pdf: pdf_response, _ = do_formsemestre_bulletinetud( formsemestre, diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index 494fe090b..8bdab7b48 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -24,6 +24,7 @@ from app.scodoc import codes_cursus from app.scodoc import sco_groups from app.scodoc import sco_preferences from app.scodoc.codes_cursus import UE_SPORT, DEF +from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_utils import fmt_note @@ -344,6 +345,8 @@ class BulletinBUT: - Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai (bulletins non publiés). """ + if version not in scu.BULLETINS_VERSIONS: + raise ScoValueError("version de bulletin demandée invalide") res = self.res formsemestre = res.formsemestre etat_inscription = etud.inscription_etat(formsemestre.id) diff --git a/app/but/bulletin_but_court.py b/app/but/bulletin_but_court.py index f88b319f5..2c326177c 100644 --- a/app/but/bulletin_but_court.py +++ b/app/but/bulletin_but_court.py @@ -115,5 +115,6 @@ def bulletin_but(formsemestre_id: int, etudid: int = None, fmt="html"): datetime=datetime, sco=ScoData(formsemestre=formsemestre, etud=etud), time=time, + version="butcourt", **args, ) diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index f4a4ea9c1..970272be7 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -775,11 +775,20 @@ class FormSemestre(db.Model): etuds.sort(key=lambda e: e.sort_key) return etuds - def get_partitions_list(self, with_default=True) -> list[Partition]: + def get_partitions_list( + self, with_default=True, only_listed=False + ) -> list[Partition]: """Liste des partitions pour ce semestre (list of dicts), triées par numéro, avec la partition par défaut en fin de liste. """ - partitions = [p for p in self.partitions if p.partition_name is not None] + if only_listed: + partitions = [ + p + for p in self.partitions + if p.partition_name is not None and p.show_in_lists + ] + else: + partitions = [p for p in self.partitions if p.partition_name is not None] if with_default: partitions += [p for p in self.partitions if p.partition_name is None] return partitions diff --git a/app/scodoc/sco_archives.py b/app/scodoc/sco_archives.py index 789509c3f..e296316ce 100644 --- a/app/scodoc/sco_archives.py +++ b/app/scodoc/sco_archives.py @@ -344,6 +344,8 @@ def do_formsemestre_archive( gen_formsemestre_recapcomplet_json, ) + if bul_version not in scu.BULLETINS_VERSIONS: + raise ScoValueError("version de bulletin demandée invalide") formsemestre = FormSemestre.get_formsemestre(formsemestre_id) res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) sem_archive_id = formsemestre_id @@ -537,7 +539,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement. "Version intermédiaire", "Version complète", ], - "allowed_values": scu.BULLETINS_VERSIONS, + "allowed_values": scu.BULLETINS_VERSIONS.keys(), "default": "long", }, ), diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py index 2ec0e2395..4d76712d7 100644 --- a/app/scodoc/sco_bulletins_generator.py +++ b/app/scodoc/sco_bulletins_generator.py @@ -283,7 +283,6 @@ def make_formsemestre_bulletin_etud( formsemestre_id = bul_dict["formsemestre_id"] bul_class_name = sco_preferences.get_preference("bul_class_name", formsemestre_id) - gen_class = None for bul_class_name in ( sco_preferences.get_preference("bul_class_name", formsemestre_id), diff --git a/app/scodoc/sco_bulletins_json.py b/app/scodoc/sco_bulletins_json.py index df5477694..7676ac162 100644 --- a/app/scodoc/sco_bulletins_json.py +++ b/app/scodoc/sco_bulletins_json.py @@ -85,7 +85,7 @@ def formsemestre_bulletinetud_published_dict( etudid, force_publishing=False, xml_nodate=False, - xml_with_decisions=False, # inclue les decisions même si non publiées + xml_with_decisions=False, # inclure les décisions même si non publiées version="long", ) -> dict: """Dictionnaire representant les informations _publiees_ du bulletin de notes @@ -95,8 +95,8 @@ def formsemestre_bulletinetud_published_dict( short (sans les évaluations) long (avec les évaluations) - short_mat (sans évaluations, et structuration en matières) - long_mat (avec évaluations, et structuration en matières) + # non implémenté: short_mat (sans évaluations, et structuration en matières) + # long_mat (avec évaluations, et structuration en matières) """ from app.scodoc import sco_bulletins diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py index 61a44cf00..5ccb6c9f3 100644 --- a/app/scodoc/sco_bulletins_pdf.py +++ b/app/scodoc/sco_bulletins_pdf.py @@ -215,6 +215,8 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"): "Document pdf avec tous les bulletins du semestre, et filename" from app.scodoc import sco_bulletins + if version not in scu.BULLETINS_VERSIONS: + raise ScoValueError("version de bulletin demandée invalide") cached = sco_cache.SemBulletinsPDFCache.get(str(formsemestre_id) + "_" + version) if cached: return cached[1], cached[0] diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py index ea95821f7..eb82de4c3 100644 --- a/app/scodoc/sco_preferences.py +++ b/app/scodoc/sco_preferences.py @@ -1317,7 +1317,7 @@ class BasePreferences: "labels": sco_bulletins_generator.bulletin_class_descriptions(), "allowed_values": sco_bulletins_generator.bulletin_class_names(), "title": "Format des bulletins", - "explanation": "format de présentation des bulletins de note (web et pdf)", + "explanation": "format de présentation des bulletins de note (web et pdf), non utilisé en BUT.", "category": "bul", }, ), diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 7a93198e7..31ff703ed 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -639,9 +639,16 @@ def get_mime_suffix(format_code: str) -> tuple[str, str]: TYPE_ADMISSION_DEFAULT = "Inconnue" TYPES_ADMISSION = (TYPE_ADMISSION_DEFAULT, "APB", "APB-PC", "CEF", "Direct") -BULLETINS_VERSIONS = ("short", "selectedevals", "long") +BULLETINS_VERSIONS = { + "short": "Version courte", + "selectedevals": "Version intermédiaire", + "long": "Version complète", +} +BULLETINS_VERSIONS_BUT = BULLETINS_VERSIONS | { + "butcourt": "Version courte spéciale BUT" +} -# Support for ScoDoc7 compatibility +# ----- Support for ScoDoc7 compatibility def ScoURL(): diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index c4d760e2d..c31d0de60 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -3078,11 +3078,17 @@ a.bull_link:hover { div.bulletin_menubar { padding-left: 25px; } - +div.bull_titre_semestre { + margin-top: 8px; + margin-bottom: 8px; + font-size: 120%; +} +div.bull_titre_semestre .parcours { + margin-left: 12px; +} .bull_liensemestre { font-weight: bold; } - .bull_liensemestre a { color: rgb(255, 0, 0); text-decoration: none; diff --git a/app/templates/bul_head.j2 b/app/templates/bul_head.j2 index 6c284062e..91acfb3d9 100644 --- a/app/templates/bul_head.j2 +++ b/app/templates/bul_head.j2 @@ -14,21 +14,32 @@ - Bulletin - - {{formsemestre.html_link_status() | safe}} - - +
+ Bulletin + + {{formsemestre.html_link_status() | safe}} + {% if formsemestre.etuds_inscriptions[etud.id].parcour %} + Parcours {{formsemestre.etuds_inscriptions[etud.id].parcour.code}} + {% endif %} + +
établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20) - + {% if formsemestre.formation.is_apc() %} + {% set menu_items = scu.BULLETINS_VERSIONS_BUT.items() %} + {% else %} + {% set menu_items = scu.BULLETINS_VERSIONS.items() %} + {% endif %} + {% for (v, e) in menu_items %} + {% endfor %} @@ -46,13 +57,15 @@
{% if formsemestre.formation.is_apc() %}
- version courte spéciale BUT + {% if version != "butcourt" %} + version courte spéciale BUT + {% endif %} - version pdf {{scu.ICON_PDF|safe}} - version complète - visualiser les compétences BUT -
+ +{% include 'bul_head.j2' %} +
-
-
{{etud.nomprenom}}
-
BUT {{formsemestre.formation.referentiel_competence.specialite}}
- {% if formsemestre.etuds_inscriptions[etud.id].parcour %} -
Parcours {{formsemestre.etuds_inscriptions[etud.id].parcour.code}}
- {% endif %} -
Année {{formsemestre.annee_scolaire_str()}}
-
Semestre {{formsemestre.semestre_id}}
-
- - - {% if bul.options.show_abs %}
Absences {{bul.semestre.absences.metrique}}
diff --git a/app/views/notes.py b/app/views/notes.py index d0063b654..c7a4613b0 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -289,6 +289,8 @@ def formsemestre_bulletinetud( code_ine=None, ): fmt = fmt or "html" + if version not in scu.BULLETINS_VERSIONS_BUT: + raise ScoValueError("version de bulletin demandée invalide") if not isinstance(etudid, int): raise ScoInvalidIdType("formsemestre_bulletinetud: etudid must be an integer !") if formsemestre_id is not None and not isinstance(formsemestre_id, int): @@ -312,6 +314,15 @@ def formsemestre_bulletinetud( raise ScoValueError( "Paramètre manquant: spécifier etudid, code_nip ou code_ine" ) + if version == "butcourt": + return redirect( + url_for( + "notes.bulletin_but_pdf" if fmt == "pdf" else "notes.bulletin_but_html", + scodoc_dept=g.scodoc_dept, + etudid=etud.id, + formsemestre_id=formsemestre_id, + ) + ) if fmt == "json": return sco_bulletins.get_formsemestre_bulletin_etud_json( formsemestre, etud, version=version, force_publishing=force_publishing @@ -1852,6 +1863,8 @@ sco_publish( @scodoc7func def formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"): "Publie les bulletins dans un classeur PDF" + if version not in scu.BULLETINS_VERSIONS: + raise ScoValueError("version de bulletin demandée invalide") pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf( formsemestre_id, version=version ) @@ -1871,7 +1884,7 @@ _EXPL_BULL = """Versions des bulletins: @permission_required(Permission.ScoView) @scodoc7func def formsemestre_bulletins_pdf_choice(formsemestre_id, version=None): - """Choix version puis envois classeur bulletins pdf""" + """Choix version puis envoi classeur bulletins pdf""" if version: pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf( formsemestre_id, version=version @@ -1890,6 +1903,8 @@ def formsemestre_bulletins_pdf_choice(formsemestre_id, version=None): @scodoc7func def etud_bulletins_pdf(etudid, version="selectedevals"): "Publie tous les bulletins d'un etudiants dans un classeur PDF" + if version not in scu.BULLETINS_VERSIONS: + raise ScoValueError("version de bulletin demandée invalide") pdfdoc, filename = sco_bulletins_pdf.get_etud_bulletins_pdf(etudid, version=version) return scu.sendPDFFile(pdfdoc, filename) diff --git a/tests/api/test_api_etudiants.py b/tests/api/test_api_etudiants.py index 41301059d..e66490fc3 100644 --- a/tests/api/test_api_etudiants.py +++ b/tests/api/test_api_etudiants.py @@ -762,6 +762,29 @@ def test_etudiant_bulletin_semestre(api_headers): bul = r.json() assert len(bul) == 14 # HARDCODED + ######## Bulletin BUT court en pdf ######### + r = requests.get( + API_URL + "/etudiant/ine/" + str(INE) + "/formsemestre/1/bulletin/butcourt/pdf", + headers=api_headers, + verify=CHECK_CERTIFICATE, + timeout=scu.SCO_TEST_API_TIMEOUT, + ) + assert r.status_code == 200 + assert r.content[:4] == b"%PDF" + + ######## Bulletin BUT format intermédiaire en pdf ######### + r = requests.get( + API_URL + + "/etudiant/ine/" + + str(INE) + + "/formsemestre/1/bulletin/selectedevals/pdf", + headers=api_headers, + verify=CHECK_CERTIFICATE, + timeout=scu.SCO_TEST_API_TIMEOUT, + ) + assert r.status_code == 200 + assert r.content[:4] == b"%PDF" + ################### LONG + PDF ##################### # ######### Test etudid #########