Compare commits

..

6 Commits

8 changed files with 115 additions and 124 deletions

View File

@ -8,51 +8,12 @@ from app.api import bp
from app.api.errors import error_response from app.api.errors import error_response
from app.api.auth import token_auth, token_permission_required from app.api.auth import token_auth, token_permission_required
from app.api.tools import get_etu_from_request from app.api.tools import get_etu_from_request
from app.scodoc.sco_bulletins_json import make_json_formsemestre_bulletinetud from app.models import FormSemestreInscription, FormSemestre, Identite
from app.scodoc.sco_bulletins import get_formsemestre_bulletin_etud_json
from app.scodoc.sco_groups import get_etud_groups from app.scodoc.sco_groups import get_etud_groups
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
@bp.route("/etudiants", methods=["GET"])
@token_permission_required(Permission.APIView)
def etudiants():
"""
Retourne la liste de tous les étudiants
Exemple de résultat :
{
"civilite": "X",
"code_ine": null,
"code_nip": null,
"date_naissance": null,
"email": null,
"emailperso": null,
"etudid": 18,
"nom": "MOREL",
"prenom": "JACQUES"
},
{
"civilite": "X",
"code_ine": null,
"code_nip": null,
"date_naissance": null,
"email": null,
"emailperso": null,
"etudid": 19,
"nom": "FOURNIER",
"prenom": "ANNE"
},
...
"""
# Récupération de tous les étudiants
etu = models.Identite.query.all()
# Mise en forme des données
data = [d.to_dict_bul(include_urls=False) for d in etu]
return jsonify(data)
@bp.route("/etudiants/courant", methods=["GET"]) @bp.route("/etudiants/courant", methods=["GET"])
@token_permission_required(Permission.APIView) @token_permission_required(Permission.APIView)
def etudiants_courant(): def etudiants_courant():
@ -85,13 +46,13 @@ def etudiants_courant():
... ...
""" """
# Récupération de tous les étudiants # Récupération de tous les étudiants
etus = models.Identite.query.all() etus = Identite.query.filter(
Identite.id == FormSemestreInscription.etudid,
FormSemestreInscription.formsemestre_id == FormSemestre.id,
FormSemestre.date_debut <= app.db.func.now(),
FormSemestre.date_fin >= app.db.func.now())
data = [] data = [etu.to_dict_bul(include_urls=False) for etu in etus]
# Récupère uniquement les étudiants courant
for etu in etus:
if etu.inscription_courante() is not None:
data.append(etu.to_dict_bul(include_urls=False))
return jsonify(data) return jsonify(data)
@ -190,7 +151,7 @@ def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None)
for formsemestre_inscription in formsemestres_inscriptions: for formsemestre_inscription in formsemestres_inscriptions:
res = models.FormSemestre.query.filter_by( res = models.FormSemestre.query.filter_by(
id=formsemestre_inscription.formsemestre_id id=formsemestre_inscription.formsemestre_id
).first() ).first_or_404()
formsemestres.append(res) formsemestres.append(res)
data = [] data = []
@ -227,25 +188,23 @@ def etudiant_bulletin_semestre(
""" """
# Fonction utilisée : app.scodoc.sco_bulletins_json.make_json_formsemestre_bulletinetud() # Fonction utilisée : app.scodoc.sco_bulletins_json.make_json_formsemestre_bulletinetud()
formsemestre = models.FormSemestre.query.filter_by(id=formsemestre_id).first() formsemestre = models.FormSemestre.query.filter_by(id=formsemestre_id).first_or_404()
dept = models.Departement.query.filter_by(id=formsemestre.dept_id).first() dept = models.Departement.query.filter_by(id=formsemestre.dept_id).first_or_404()
app.set_sco_dept(dept.acronym) app.set_sco_dept(dept.acronym)
if etudid is None: # Récupération de l'étudiant
# Récupération de l'étudiant try:
try: etu = get_etu_from_request(etudid, nip, ine)
etu = get_etu_from_request(etudid, nip, ine) except AttributeError:
etudid = etu.etudid return error_response(
except AttributeError: 409,
return error_response( message="La requête ne peut être traitée en létat actuel.\n "
409, "Veilliez vérifier que l'id de l'étudiant (etudid, nip, ine) est valide",
message="La requête ne peut être traitée en létat actuel.\n " )
"Veilliez vérifier que l'id de l'étudiant (etudid, nip, ine) est valide",
)
return make_json_formsemestre_bulletinetud(formsemestre_id, etudid) return get_formsemestre_bulletin_etud_json(formsemestre, etu)
@bp.route( @bp.route(
@ -311,7 +270,7 @@ def etudiant_groups(
) )
# Récupération du formsemestre # Récupération du formsemestre
sem = models.FormSemestre.query.filter_by(id=formsemestre_id).first() sem = models.FormSemestre.query.filter_by(id=formsemestre_id).first_or_404()
try: try:
# Utilisation de la fonction get_etud_groups # Utilisation de la fonction get_etud_groups
data = get_etud_groups(etudid, sem.id) data = get_etud_groups(etudid, sem.id)

View File

@ -6,8 +6,6 @@
"""ScoDoc 9 models : Référentiel Compétence BUT 2021 """ScoDoc 9 models : Référentiel Compétence BUT 2021
""" """
from datetime import datetime from datetime import datetime
from enum import unique
from typing import Any
from sqlalchemy.orm import class_mapper from sqlalchemy.orm import class_mapper
import sqlalchemy import sqlalchemy
@ -28,6 +26,8 @@ def attribute_names(cls):
class XMLModel: class XMLModel:
"""Mixin class, to ease loading Orebut XMLs"""
_xml_attribs = {} # to be overloaded _xml_attribs = {} # to be overloaded
id = "_" id = "_"
@ -162,6 +162,7 @@ class ApcCompetence(db.Model, XMLModel):
class ApcSituationPro(db.Model, XMLModel): class ApcSituationPro(db.Model, XMLModel):
"Situation professionnelle"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
competence_id = db.Column( competence_id = db.Column(
db.Integer, db.ForeignKey("apc_competence.id"), nullable=False db.Integer, db.ForeignKey("apc_competence.id"), nullable=False
@ -173,6 +174,7 @@ class ApcSituationPro(db.Model, XMLModel):
class ApcComposanteEssentielle(db.Model, XMLModel): class ApcComposanteEssentielle(db.Model, XMLModel):
"Composante essentielle"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
competence_id = db.Column( competence_id = db.Column(
db.Integer, db.ForeignKey("apc_competence.id"), nullable=False db.Integer, db.ForeignKey("apc_competence.id"), nullable=False
@ -199,6 +201,9 @@ class ApcNiveau(db.Model, XMLModel):
cascade="all, delete-orphan", cascade="all, delete-orphan",
) )
def __repr__(self):
return f"<{self.__class__.__name__} ordre={self.ordre}>"
def to_dict(self): def to_dict(self):
return { return {
"libelle": self.libelle, "libelle": self.libelle,
@ -222,14 +227,14 @@ class ApcAppCritique(db.Model, XMLModel):
backref=db.backref("app_critiques", lazy="dynamic"), backref=db.backref("app_critiques", lazy="dynamic"),
) )
def to_dict(self): def to_dict(self) -> dict:
return {"libelle": self.libelle} return {"libelle": self.libelle}
def get_label(self): def get_label(self) -> str:
return self.code + " - " + self.titre return self.code + " - " + self.titre
def __repr__(self): def __repr__(self):
return "<AppCritique {}>".format(self.code) return f"<{self.__class__.__name__} {self.code}>"
def get_saes(self): def get_saes(self):
"""Liste des SAE associées""" """Liste des SAE associées"""
@ -258,6 +263,9 @@ class ApcParcours(db.Model, XMLModel):
cascade="all, delete-orphan", cascade="all, delete-orphan",
) )
def __repr__(self):
return f"<{self.__class__.__name__} {self.code}>"
def to_dict(self): def to_dict(self):
return { return {
"code": self.code, "code": self.code,
@ -274,6 +282,9 @@ class ApcAnneeParcours(db.Model, XMLModel):
) )
ordre = db.Column(db.Integer) ordre = db.Column(db.Integer)
def __repr__(self):
return f"<{self.__class__.__name__} ordre={self.ordre}>"
def to_dict(self): def to_dict(self):
return { return {
"ordre": self.ordre, "ordre": self.ordre,
@ -320,3 +331,6 @@ class ApcParcoursNiveauCompetence(db.Model):
cascade="save-update, merge, delete, delete-orphan", cascade="save-update, merge, delete, delete-orphan",
), ),
) )
def __repr__(self):
return f"<{self.__class__.__name__} {self.competence} {self.annee_parcours}>"

View File

@ -7,7 +7,6 @@ from app.comp import df_cache
from app.models import SHORT_STR_LEN from app.models import SHORT_STR_LEN
from app.models.modules import Module from app.models.modules import Module
from app.models.ues import UniteEns from app.models.ues import UniteEns
from app.scodoc import notesdb as ndb
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu

View File

@ -32,7 +32,7 @@ import email
import time import time
from flask import g, request from flask import g, request
from flask import flash, render_template, url_for from flask import flash, jsonify, render_template, url_for
from flask_login import current_user from flask_login import current_user
from app import email from app import email
@ -76,6 +76,34 @@ from app.scodoc import sco_bulletins_legacy
from app.scodoc import sco_bulletins_ucac # format expérimental UCAC Cameroun from app.scodoc import sco_bulletins_ucac # format expérimental UCAC Cameroun
def get_formsemestre_bulletin_etud_json(
formsemestre: FormSemestre,
etud: Identite,
force_publishing=False,
version="long",
) -> str:
"""Le JSON du bulletin d'un étudiant, quel que soit le type de formation."""
if formsemestre.formation.is_apc():
r = bulletin_but.BulletinBUT(formsemestre)
return jsonify(
r.bulletin_etud(
etud,
formsemestre,
force_publishing=force_publishing,
version=version,
)
)
return formsemestre_bulletinetud(
etud,
formsemestre_id=formsemestre.id,
format="json",
version=version,
xml_with_decisions=True,
force_publishing=force_publishing,
)
# -------------
def make_context_dict(formsemestre: FormSemestre, etud: dict) -> dict: def make_context_dict(formsemestre: FormSemestre, etud: dict) -> dict:
"""Construit dictionnaire avec valeurs pour substitution des textes """Construit dictionnaire avec valeurs pour substitution des textes
(preferences bul_pdf_*) (preferences bul_pdf_*)
@ -799,7 +827,10 @@ def formsemestre_bulletinetud(
force_publishing=False, # force publication meme si semestre non publie sur "portail" force_publishing=False, # force publication meme si semestre non publie sur "portail"
prefer_mail_perso=False, prefer_mail_perso=False,
): ):
"page bulletin de notes" """Page bulletin de notes
pour les formations classiques hors BUT (page HTML)
ou le format "oldjson".
"""
format = format or "html" format = format or "html"
formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id) formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id)
if not formsemestre: if not formsemestre:

View File

@ -34,14 +34,14 @@
}) })
.catch(error => { .catch(error => {
let div = document.createElement("div"); let div = document.createElement("div");
div.innerText = "Une erreur s'est produite lors du transfère des données."; div.innerText = "Une erreur s'est produite lors du transfert des données.";
div.style.fontSize = "24px"; div.style.fontSize = "24px";
div.style.color = "#d93030"; div.style.color = "#d93030";
let releve = document.querySelector("releve-but"); let releve = document.querySelector("releve-but");
releve.after(div); releve.after(div);
releve.remove(); releve.remove();
throw 'Fin du script - données invalides'; throw 'Fin du script - données invalides';
}); });
document.querySelector("html").style.scrollBehavior = "smooth"; document.querySelector("html").style.scrollBehavior = "smooth";

View File

@ -13,14 +13,13 @@
<script src="/ScoDoc/static/js/ref_competences.js"></script> <script src="/ScoDoc/static/js/ref_competences.js"></script>
<div class="help"> <div class="help">
Référentiel chargé le {{ref.scodoc_date_loaded.strftime("%d/%m/%Y à %H:%M") if ref.scodoc_date_loaded else ""}} à partir du fichier <tt>{{ref.scodoc_orig_filename or "(inconnu)"}}</tt>. Référentiel chargé le {{ref.scodoc_date_loaded.strftime("%d/%m/%Y à %H:%M") if ref.scodoc_date_loaded else ""}} à
partir du fichier <tt>{{ref.scodoc_orig_filename or "(inconnu)"}}</tt>.
</div> </div>
<div class="part2"> <div class="part2">
<a class="stdlink" <a class="stdlink" href="{{url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept)}}">liste des référentiels</a>
href="{{url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept)}}"
>revenir à la liste des référentiels</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -312,53 +312,42 @@ def formsemestre_bulletinetud(
raise ScoValueError( raise ScoValueError(
"Paramètre manquant: spécifier etudid, code_nip ou code_ine" "Paramètre manquant: spécifier etudid, code_nip ou code_ine"
) )
if formsemestre.formation.is_apc() and format != "oldjson": if format == "json":
if format == "json": return sco_bulletins.get_formsemestre_bulletin_etud_json(
r = bulletin_but.BulletinBUT(formsemestre) formsemestre, etud, version=version
return jsonify(
r.bulletin_etud(
etud,
formsemestre,
force_publishing=force_publishing,
version=version,
)
)
elif format == "html":
return render_template(
"but/bulletin.html",
appreciations=models.BulAppreciations.query.filter_by(
etudid=etudid, formsemestre_id=formsemestre.id
).order_by(models.BulAppreciations.date),
bul_url=url_for(
"notes.formsemestre_bulletinetud",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
etudid=etudid,
format="json",
force_publishing=1, # pour ScoDoc lui même
version=version,
),
can_edit_appreciations=formsemestre.est_responsable(current_user)
or (current_user.has_permission(Permission.ScoEtudInscrit)),
etud=etud,
formsemestre=formsemestre,
inscription_courante=etud.inscription_courante(),
inscription_str=etud.inscription_descr()["inscription_str"],
is_apc=formsemestre.formation.is_apc(),
menu_autres_operations=sco_bulletins.make_menu_autres_operations(
formsemestre, etud, "notes.formsemestre_bulletinetud", version
),
sco=ScoData(etud=etud),
scu=scu,
time=time,
title=f"Bul. {etud.nom} - BUT",
version=version,
)
if not (etudid or code_nip or code_ine):
raise ScoValueError(
"Paramètre manquant: spécifier code_nip ou etudid ou code_ine"
) )
if formsemestre.formation.is_apc() and format == "html":
return render_template(
"but/bulletin.html",
appreciations=models.BulAppreciations.query.filter_by(
etudid=etudid, formsemestre_id=formsemestre.id
).order_by(models.BulAppreciations.date),
bul_url=url_for(
"notes.formsemestre_bulletinetud",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
etudid=etudid,
format="json",
force_publishing=1, # pour ScoDoc lui même
version=version,
),
can_edit_appreciations=formsemestre.est_responsable(current_user)
or (current_user.has_permission(Permission.ScoEtudInscrit)),
etud=etud,
formsemestre=formsemestre,
inscription_courante=etud.inscription_courante(),
inscription_str=etud.inscription_descr()["inscription_str"],
is_apc=formsemestre.formation.is_apc(),
menu_autres_operations=sco_bulletins.make_menu_autres_operations(
formsemestre, etud, "notes.formsemestre_bulletinetud", version
),
sco=ScoData(etud=etud),
scu=scu,
time=time,
title=f"Bul. {etud.nom} - BUT",
version=version,
)
if format == "oldjson": if format == "oldjson":
format = "json" format = "json"
r = sco_bulletins.formsemestre_bulletinetud( r = sco_bulletins.formsemestre_bulletinetud(

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.2.11" SCOVERSION = "9.2.12"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"