Bulletins: améliore page, modifie API pour récuperer le bul. but court avec le même appel.

This commit is contained in:
Emmanuel Viennet 2023-10-13 22:25:44 +02:00
parent a732b8161e
commit 3000cfe7ba
15 changed files with 126 additions and 66 deletions

View File

@ -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/<int:arg>")
@ -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,

View File

@ -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)

View File

@ -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,
)

View File

@ -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

View File

@ -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",
},
),

View File

@ -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),

View File

@ -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

View File

@ -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]

View File

@ -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",
},
),

View File

@ -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():

View File

@ -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;

View File

@ -14,21 +14,32 @@
<input type="hidden" name="formsemestre_id" value="{{formsemestre.id}}"></input>
<input type="hidden" name="etudid" value="{{etud.id}}"></input>
<input type="hidden" name="fmt" value="{{fmt}}"></input>
Bulletin
<span class="bull_liensemestre">
{{formsemestre.html_link_status() | safe}}
</span>
<div class="bull_titre_semestre">
Bulletin
<span class="bull_liensemestre">
{{formsemestre.html_link_status() | safe}}
{% if formsemestre.etuds_inscriptions[etud.id].parcour %}
<span class="parcours">Parcours {{formsemestre.etuds_inscriptions[etud.id].parcour.code}}</span>
{% endif %}
</span>
</div>
<div>
<em>établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20)</em>
<span class="rightjust">
<select name="version" onchange="document.f.submit()" class="noprint">
{% for (v, e) in (
("short", "Version courte"),
("selectedevals", "Version intermédiaire"),
("long", "Version complète"),
) %}
<option value="{{v}}" {% if (v == version) %}selected{% endif %}>{{e}}</option>
<select name="version" onchange="self.location.href='{{
url_for('notes.formsemestre_bulletinetud',
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
etudid=etud.id,
)
}}&version='+this.value;"" class="noprint">
{% 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 %}
<option value="{{v}}" {% if (v == version) %}selected{% endif %}>{{e}}</option>
{% endfor %}
</select>
</span>
@ -46,13 +57,15 @@
</div>
{% if formsemestre.formation.is_apc() %}
<div>
<a style="margin-left: 32px;" class="stdlink"
href="{{url_for(
'notes.bulletin_but_html',
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
etudid=etud.id
)}}">version courte spéciale BUT</a>
{% if version != "butcourt" %}
<a style="margin-left: 32px;" class="stdlink"
href="{{url_for(
'notes.bulletin_but_html',
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
etudid=etud.id
)}}">version courte spéciale BUT</a>
{% endif %}
<a style="margin-left: 32px;" class="stdlink"
href="{{url_for('notes.validation_rcues',
scodoc_dept=g.scodoc_dept, etudid=etud.id,

View File

@ -39,40 +39,10 @@
{%- endmacro %}
{% block app_content %}
<div class="but_bul_court_links">
<a href="{{url_for(
'notes.bulletin_but_pdf', scodoc_dept=g.scodoc_dept, etudid=etud.id,
formsemestre_id=formsemestre.id
)}}" class="stdlink">version pdf {{scu.ICON_PDF|safe}}</a>
<a style="margin-left: 32px;"
href="{{url_for(
'notes.formsemestre_bulletinetud',
scodoc_dept=g.scodoc_dept, etudid=etud.id,
formsemestre_id=formsemestre.id
)}}" class="stdlink">version complète</a>
<a style="margin-left: 32px;" class="stdlink"
href="{{url_for('notes.validation_rcues',
scodoc_dept=g.scodoc_dept, etudid=etud.id,
formsemestre_id=formsemestre.id
)}}">visualiser les compétences BUT</a>
</div>
{% include 'bul_head.j2' %}
<div class="but_bul_court">
<div id="infos_etudiant">
<div class="nom">{{etud.nomprenom}}</div>
<div class="formation">BUT {{formsemestre.formation.referentiel_competence.specialite}}</div>
{% if formsemestre.etuds_inscriptions[etud.id].parcour %}
<div class="parcours">Parcours {{formsemestre.etuds_inscriptions[etud.id].parcour.code}}</div>
{% endif %}
<div class="annee_scolaire">Année {{formsemestre.annee_scolaire_str()}}</div>
<div class="semestre">Semestre {{formsemestre.semestre_id}}</div>
</div>
<div id="logo">
<a href="{{
url_for('scolar.ficheEtud', scodoc_dept=g.scodoc_dept, etudid=etud.id)
}}">{{etud.photo_html()|safe}}</a>
</div>
{% if bul.options.show_abs %}
<div id="assiduite">
<div class="ligne-entete">Absences {{bul.semestre.absences.metrique}}</div>

View File

@ -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)

View File

@ -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 #########