1
0
forked from ScoDoc/ScoDoc

WIP: new API revue et corrigée (en cours)

This commit is contained in:
Emmanuel Viennet 2022-07-19 22:17:10 +02:00
parent 455ce295d8
commit ca1fe679db
16 changed files with 370 additions and 965 deletions

View File

@ -31,4 +31,3 @@ from app.api import evaluations
from app.api import jury
from app.api import absences
from app.api import logos
from app.api import debug

View File

@ -1,15 +1,22 @@
#################################################### Absences #########################################################
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""ScoDoc 9 API : Absences
"""
from flask import jsonify
from app.api import bp
from app.api.errors import error_response
from app.api.auth import token_auth, token_permission_required
from app.models import Identite, FormSemestre
from app.models import Identite
from app.scodoc import notesdb as ndb
from app.scodoc import sco_abs
from app.scodoc.sco_abs import list_abs_date, annule_absence, annule_justif, add_abslist
# from app.scodoc.sco_abs import annule_absence, annule_justif, add_abslist
from app.scodoc.sco_groups import get_group_members
from app.scodoc.sco_permissions import Permission
@ -53,10 +60,10 @@ def absences(etudid: int = None):
)
# Absences de l'étudiant
ndb.open_db_connection()
absences = sco_abs.list_abs_date(etud.id)
for absence in absences:
abs_list = sco_abs.list_abs_date(etud.id)
for absence in abs_list:
absence["jour"] = absence["jour"].isoformat()
return jsonify(absences)
return jsonify(abs_list)
@bp.route("/absences/etudid/<int:etudid>/just", methods=["GET"])
@ -158,9 +165,6 @@ def abs_groupe_etat(group_id: int, date_debut=None, date_fin=None):
...
]
"""
# Fonction utilisée : app.scodoc.sco_groups.get_group_members() et app.scodoc.sco_abs.list_abs_date()
# Utilisation de la fonction get_group_members
members = get_group_members(group_id)
data = []
@ -175,88 +179,89 @@ def abs_groupe_etat(group_id: int, date_debut=None, date_fin=None):
return jsonify(data)
@bp.route(
"/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs",
methods=["POST"],
defaults={"just_or_not": 0},
)
@bp.route(
"/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs/only_not_just",
methods=["POST"],
defaults={"just_or_not": 1},
)
@bp.route(
"/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs/only_just",
methods=["POST"],
defaults={"just_or_not": 2},
)
@token_auth.login_required
@token_permission_required(Permission.APIAbsChange)
def reset_etud_abs(etudid: int, list_abs, just_or_not: int = 0):
"""
Set la liste des absences d'un étudiant sur tout un semestre.
(les absences existant pour cet étudiant sur cette période sont effacées)
# XXX TODO EV: A REVOIR (data json dans le POST + modifier les routes)
# @bp.route(
# "/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs",
# methods=["POST"],
# defaults={"just_or_not": 0},
# )
# @bp.route(
# "/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs/only_not_just",
# methods=["POST"],
# defaults={"just_or_not": 1},
# )
# @bp.route(
# "/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs/only_just",
# methods=["POST"],
# defaults={"just_or_not": 2},
# )
# @token_auth.login_required
# @token_permission_required(Permission.APIAbsChange)
# def reset_etud_abs(etudid: int, list_abs: str, just_or_not: int = 0):
# """
# Set la liste des absences d'un étudiant sur tout un semestre.
# (les absences existant pour cet étudiant sur cette période sont effacées)
etudid : l'id d'un étudiant
list_abs : json d'absences
just_or_not : 0 (pour les absences justifiées et non justifiées),
1 (pour les absences justifiées),
2 (pour les absences non justifiées)
"""
# Toutes les absences
if just_or_not == 0:
# suppression des absences et justificatif déjà existant pour éviter les doublons
for abs in list_abs:
# Récupération de la date au format iso
jour = abs["jour"].isoformat()
if abs["matin"] is True:
annule_absence(etudid, jour, True)
annule_justif(etudid, jour, True)
else:
annule_absence(etudid, jour, False)
annule_justif(etudid, jour, False)
# etudid : l'id d'un étudiant
# list_abs : json d'absences
# just_or_not : 0 (pour les absences justifiées et non justifiées),
# 1 (pour les absences justifiées),
# 2 (pour les absences non justifiées)
# """
# # Toutes les absences
# if just_or_not == 0:
# # suppression des absences et justificatif déjà existant pour éviter les doublons
# for abs in list_abs:
# # Récupération de la date au format iso
# jour = abs["jour"].isoformat()
# if abs["matin"] is True:
# annule_absence(etudid, jour, True)
# annule_justif(etudid, jour, True)
# else:
# annule_absence(etudid, jour, False)
# annule_justif(etudid, jour, False)
# Ajout de la liste d'absences en base
add_abslist(list_abs)
# # Ajout de la liste d'absences en base
# add_abslist(list_abs)
# Uniquement les absences justifiées
elif just_or_not == 1:
list_abs_not_just = []
# Trie des absences justifiées
for abs in list_abs:
if abs["estjust"] is False:
list_abs_not_just.append(abs)
# suppression des absences et justificatif déjà existant pour éviter les doublons
for abs in list_abs:
# Récupération de la date au format iso
jour = abs["jour"].isoformat()
if abs["matin"] is True:
annule_absence(etudid, jour, True)
annule_justif(etudid, jour, True)
else:
annule_absence(etudid, jour, False)
annule_justif(etudid, jour, False)
# # Uniquement les absences justifiées
# elif just_or_not == 1:
# list_abs_not_just = []
# # Trie des absences justifiées
# for abs in list_abs:
# if abs["estjust"] is False:
# list_abs_not_just.append(abs)
# # suppression des absences et justificatif déjà existant pour éviter les doublons
# for abs in list_abs:
# # Récupération de la date au format iso
# jour = abs["jour"].isoformat()
# if abs["matin"] is True:
# annule_absence(etudid, jour, True)
# annule_justif(etudid, jour, True)
# else:
# annule_absence(etudid, jour, False)
# annule_justif(etudid, jour, False)
# Ajout de la liste d'absences en base
add_abslist(list_abs_not_just)
# # Ajout de la liste d'absences en base
# add_abslist(list_abs_not_just)
# Uniquement les absences non justifiées
elif just_or_not == 2:
list_abs_just = []
# Trie des absences non justifiées
for abs in list_abs:
if abs["estjust"] is True:
list_abs_just.append(abs)
# suppression des absences et justificatif déjà existant pour éviter les doublons
for abs in list_abs:
# Récupération de la date au format iso
jour = abs["jour"].isoformat()
if abs["matin"] is True:
annule_absence(etudid, jour, True)
annule_justif(etudid, jour, True)
else:
annule_absence(etudid, jour, False)
annule_justif(etudid, jour, False)
# # Uniquement les absences non justifiées
# elif just_or_not == 2:
# list_abs_just = []
# # Trie des absences non justifiées
# for abs in list_abs:
# if abs["estjust"] is True:
# list_abs_just.append(abs)
# # suppression des absences et justificatif déjà existant pour éviter les doublons
# for abs in list_abs:
# # Récupération de la date au format iso
# jour = abs["jour"].isoformat()
# if abs["matin"] is True:
# annule_absence(etudid, jour, True)
# annule_justif(etudid, jour, True)
# else:
# annule_absence(etudid, jour, False)
# annule_justif(etudid, jour, False)
# Ajout de la liste d'absences en base
add_abslist(list_abs_just)
# # Ajout de la liste d'absences en base
# add_abslist(list_abs_just)

View File

@ -1,31 +0,0 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""
!!! ATTENTION !!!
Fichier a utilisé uniquement à des fins de debug
"""

View File

@ -14,12 +14,13 @@ import app
from app.api import bp
from app.api.errors import error_response
from app.api.auth import token_auth, token_permission_required
from app.api.tools import get_last_instance_etud_from_etudid_or_nip_or_ine
from app.api import tools
from app.models import Departement, FormSemestreInscription, FormSemestre, Identite
from app.scodoc import sco_bulletins
from app.scodoc import sco_groups
from app.scodoc.sco_bulletins import do_formsemestre_bulletinetud
from app.scodoc.sco_permissions import Permission
from app.scodoc import sco_utils as scu
@bp.route("/etudiants/courants", defaults={"long": False})
@ -106,7 +107,7 @@ def etudiant(etudid: int = None, nip: str = None, ine: str = None):
"description": ""
}
"""
etud = get_last_instance_etud_from_etudid_or_nip_or_ine(etudid, nip, ine)
etud = tools.get_etud(etudid, nip, ine)
if etud is None:
return error_response(
@ -153,36 +154,39 @@ def etudiants(etudid: int = None, nip: str = None, ine: str = None):
def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None):
"""
Liste des semestres qu'un étudiant a suivi, triés par ordre chronologique.
Attention, si accès via NIP ou INE, les semestres peuvent être de départements différents
(si l'étudiant a changé de département). L'id du département est `dept_id`.
Accès par etudid, nip ou ine
Exemple de résultat :
[
{
"block_moyennes": false,
"bul_bgcolor": "white",
"bul_hide_xml": false,
"date_debut_iso": "2021-09-01",
"date_debut": "01/09/2021",
"date_fin_iso": "2022-08-31",
"date_fin": "31/08/2022",
"resp_can_edit": false,
"dept_id": 1,
"elt_annee_apo": null,
"elt_sem_apo": null,
"ens_can_edit_eval": false,
"etat": true,
"resp_can_change_ens": true,
"formation_id": 1,
"formsemestre_id": 1,
"gestion_compensation": false,
"gestion_semestrielle": false,
"id": 1,
"modalite": "FI",
"ens_can_edit_eval": false,
"formation_id": 1,
"gestion_compensation": false,
"elt_sem_apo": null,
"semestre_id": 1,
"bul_hide_xml": false,
"elt_annee_apo": null,
"titre": "Semestre test",
"block_moyennes": false,
"scodoc7_id": null,
"date_debut": "01/09/2021",
"gestion_semestrielle": false,
"bul_bgcolor": "white",
"formsemestre_id": 1,
"titre_num": "Semestre test semestre 1",
"date_debut_iso": "2021-09-01",
"date_fin_iso": "2022-08-31",
"resp_can_change_ens": true,
"resp_can_edit": false,
"responsables": []
"scodoc7_id": null,
"semestre_id": 1,
"titre_num": "Semestre test semestre 1",
"titre": "Semestre test",
},
...
]
@ -263,22 +267,21 @@ def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None)
methods=["GET"],
defaults={"version": "short", "pdf": False},
)
# Version PDF non fonctionnelle
# @bp.route(
# "/etudiant/etudid/<int:etudid>/formsemestre/<int:formsemestre_id>/bulletin/short/pdf",
# methods=["GET"],
# defaults={"version": "short", "pdf": True},
# )
# @bp.route(
# "/etudiant/nip/<string:nip>/formsemestre/<int:formsemestre_id>/bulletin/short/pdf",
# methods=["GET"],
# defaults={"version": "short", "pdf": True},
# )
# @bp.route(
# "/etudiant/ine/<string:ine>/formsemestre/<int:formsemestre_id>/bulletin/short/pdf",
# methods=["GET"],
# defaults={"version": "short", "pdf": True},
# )
@bp.route(
"/etudiant/etudid/<int:etudid>/formsemestre/<int:formsemestre_id>/bulletin/short/pdf",
methods=["GET"],
defaults={"version": "short", "pdf": True},
)
@bp.route(
"/etudiant/nip/<string:nip>/formsemestre/<int:formsemestre_id>/bulletin/short/pdf",
methods=["GET"],
defaults={"version": "short", "pdf": True},
)
@bp.route(
"/etudiant/ine/<string:ine>/formsemestre/<int:formsemestre_id>/bulletin/short/pdf",
methods=["GET"],
defaults={"version": "short", "pdf": True},
)
@token_auth.login_required
@token_permission_required(Permission.APIView)
def etudiant_bulletin_semestre( # XXX TODO Ajouter la possibilité de retourner en version pdf
@ -296,150 +299,8 @@ def etudiant_bulletin_semestre( # XXX TODO Ajouter la possibilité de retourner
etudid : l'etudid d'un étudiant
nip : le code nip d'un étudiant
ine : le code ine d'un étudiant
Exemple de résultat :
{
"version": "0",
"type": "BUT",
"date": "2022-04-27T07:18:16.450634Z",
"publie": true,
"etudiant": {
"civilite": "X",
"code_ine": "1",
"code_nip": "1",
"date_naissance": "",
"email": "SACHA.COSTA@example.com",
"emailperso": "",
"etudid": 1,
"nom": "COSTA",
"prenom": "SACHA",
"nomprenom": "Sacha COSTA",
"lieu_naissance": "",
"dept_naissance": "",
"nationalite": "",
"boursier": "",
"fiche_url": "/ScoDoc/TAPI/Scolarite/ficheEtud?etudid=1",
"photo_url": "/ScoDoc/TAPI/Scolarite/get_photo_image?etudid=1&size=small",
"id": 1,
"codepostaldomicile": "",
"paysdomicile": "",
"telephonemobile": "",
"typeadresse": "domicile",
"domicile": "",
"villedomicile": "",
"telephone": "",
"fax": "",
"description": "",
},
"formation": {
"id": 1,
"acronyme": "BUT R&amp;T",
"titre_officiel": "Bachelor technologique r\u00e9seaux et t\u00e9l\u00e9communications",
"titre": "BUT R&amp;T",
},
"formsemestre_id": 1,
"etat_inscription": "I",
"options": {
"show_abs": true,
"show_abs_modules": false,
"show_ects": true,
"show_codemodules": false,
"show_matieres": false,
"show_rangs": true,
"show_ue_rangs": true,
"show_mod_rangs": true,
"show_moypromo": false,
"show_minmax": false,
"show_minmax_mod": false,
"show_minmax_eval": false,
"show_coef": true,
"show_ue_cap_details": false,
"show_ue_cap_current": true,
"show_temporary": true,
"temporary_txt": "Provisoire",
"show_uevalid": true,
"show_date_inscr": true,
},
"ressources": {
"R101": {
"id": 1,
"titre": "Initiation aux r\u00e9seaux informatiques",
"code_apogee": null,
"url": "/ScoDoc/TAPI/Scolarite/Notes/moduleimpl_status?moduleimpl_id=1",
"moyenne": {},
"evaluations": [
{
"id": 1,
"description": "eval1",
"date": "2022-04-20",
"heure_debut": "08:00",
"heure_fin": "09:00",
"coef": "01.00",
"poids": {
"RT1.1": 1.0,
},
"note": {
"value": "12.00",
"min": "00.00",
"max": "18.00",
"moy": "10.88",
},
"url": "/ScoDoc/TAPI/Scolarite/Notes/evaluation_listenotes?evaluation_id=1",
}
],
},
},
"saes": {
"SAE11": {
"id": 2,
"titre": "Se sensibiliser \u00e0 l&apos;hygi\u00e8ne informatique et \u00e0 la cybers\u00e9curit\u00e9",
"code_apogee": null,
"url": "/ScoDoc/TAPI/Scolarite/Notes/moduleimpl_status?moduleimpl_id=2",
"moyenne": {},
"evaluations": [],
},
},
"ues": {
"RT1.1": {
"id": 1,
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
"numero": 1,
"type": 0,
"color": "#B80004",
"competence": null,
"moyenne": {
"value": "08.50",
"min": "06.00",
"max": "16.50",
"moy": "11.31",
"rang": "12",
"total": 16,
},
"bonus": "00.00",
"malus": "00.00",
"capitalise": null,
"ressources": {
"R101": {"id": 1, "coef": 12.0, "moyenne": "12.00"},
},
"saes": {
"SAE11": {"id": 2, "coef": 16.0, "moyenne": "~"},
},
"ECTS": {"acquis": 0.0, "total": 12.0},
},
"semestre": {
"etapes": [],
"date_debut": "2021-09-01",
"date_fin": "2022-08-31",
"annee_universitaire": "2021 - 2022",
"numero": 1,
"inscription": "",
"groupes": [],
"absences": {"injustifie": 1, "total": 2},
"ECTS": {"acquis": 0, "total": 30.0},
"notes": {"value": "10.60", "min": "02.40", "moy": "11.05", "max": "17.40"},
"rang": {"value": "10", "total": 16},
},
},
}
Exemple de résultat : voir https://scodoc.org/ScoDoc9API/#bulletin
"""
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first_or_404()
dept = Departement.query.filter_by(id=formsemestre.dept_id).first_or_404()
@ -466,11 +327,10 @@ def etudiant_bulletin_semestre( # XXX TODO Ajouter la possibilité de retourner
app.set_sco_dept(dept.acronym)
if pdf:
response = make_response(
do_formsemestre_bulletinetud(formsemestre, etudid, version, "pdf")
pdf_response, _ = do_formsemestre_bulletinetud(
formsemestre, etudid, version=version, format="pdf"
)
response.headers["Content-Type"] = "application/json"
return response
return pdf_response
return sco_bulletins.get_formsemestre_bulletin_etud_json(
formsemestre, etud, version=version

View File

@ -1,10 +1,18 @@
############################################### Evaluations ###########################################################
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""
ScoDoc 9 API : accès aux évaluations
"""
from flask import jsonify
import app
from app import models
from app.models import Evaluation
from app.api import bp
from app.api.auth import token_auth, token_permission_required
from app.api.errors import error_response
@ -18,7 +26,7 @@ from app.scodoc.sco_permissions import Permission
@token_permission_required(Permission.APIView)
def evaluations(moduleimpl_id: int):
"""
Retourne la liste des évaluations à partir de l'id d'un moduleimpl
Retourne la liste des évaluations d'un moduleimpl
moduleimpl_id : l'id d'un moduleimpl
@ -40,7 +48,7 @@ def evaluations(moduleimpl_id: int):
"evaluation_id": 1,
"jouriso": "2022-04-20",
"duree": "1h",
"descrheure": " de 08h00 \u00e0 09h00",
"descrheure": " de 08h00 à 09h00",
"matin": 1,
"apresmidi": 0
},
@ -88,16 +96,11 @@ def evaluation_notes(evaluation_id: int):
...
}
"""
# Fonction utilisée : app.scodoc.sco_evaluation_db.do_evaluation_get_all_notes()
evaluation = models.Evaluation.query.filter_by(id=evaluation_id).first_or_404()
dept = models.Departement.query.filter_by(
id=evaluation.moduleimpl.formsemestre.dept_id
).first()
dept = evaluation.moduleimpl.formsemestre.departement
app.set_sco_dept(dept.acronym)
try:
# Utilisation de la fonction do_evaluation_get_all_notes
data = do_evaluation_get_all_notes(evaluation_id)
except AttributeError: # ???
return error_response(

View File

@ -1,4 +1,13 @@
##############################################" Formations ############################################################
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""
ScoDoc 9 API : accès aux formations
"""
from flask import jsonify
import app
@ -10,6 +19,7 @@ from app.models.formations import Formation
from app.scodoc import sco_formations
from app.scodoc.sco_permissions import Permission
@bp.route("/formations", methods=["GET"])
@token_auth.login_required
@token_permission_required(Permission.APIView)
@ -17,16 +27,11 @@ def formations():
"""
Retourne la liste de toutes les formations (tous départements)
Exemple de résultat :
"""
# Récupération de toutes les formations
list_formations = models.Formation.query.all()
# Mise en forme des données
data = [d.to_dict() for d in list_formations]
data = [d.to_dict() for d in models.Formation.query]
return jsonify(data)
@bp.route("/formations_ids", methods=["GET"])
@token_auth.login_required
@token_permission_required(Permission.APIView)
@ -36,12 +41,7 @@ def formations_ids():
Exemple de résultat : [ 17, 99, 32 ]
"""
# Récupération de toutes les formations
list_formations = models.Formation.query.all()
# Mise en forme des données
data = [d.id for d in list_formations]
data = [d.id for d in models.Formation.query]
return jsonify(data)
@ -50,7 +50,7 @@ def formations_ids():
@token_permission_required(Permission.APIView)
def formation_by_id(formation_id: int):
"""
Retourne une formation en fonction d'un id donné
La formation d'id donné
formation_id : l'id d'une formation
@ -58,7 +58,7 @@ def formation_by_id(formation_id: int):
{
"id": 1,
"acronyme": "BUT R&amp;T",
"titre_officiel": "Bachelor technologique r\u00e9seaux et t\u00e9l\u00e9communications",
"titre_officiel": "Bachelor technologique réseaux et télécommunications",
"formation_code": "V1RET",
"code_specialite": null,
"dept_id": 1,
@ -69,13 +69,8 @@ def formation_by_id(formation_id: int):
"formation_id": 1
}
"""
# Récupération de la formation
formation = models.Formation.query.filter_by(id=formation_id).first_or_404()
# Mise en forme des données
data = formation.to_dict()
return jsonify(data)
formation = models.Formation.query.get_or_404(formation_id)
return jsonify(formation.to_dict())
@bp.route(
@ -187,10 +182,8 @@ def formation_export_by_formation_id(formation_id: int, export_ids=False):
}
"""
formation = Formation.query.get_or_404(formation_id)
dept = models.Departement.query.filter_by(id=formation.dept_id).first()
app.set_sco_dept(dept.acronym)
app.set_sco_dept(formation.departement.acronym)
try:
# Utilisation de la fonction formation_export
data = sco_formations.formation_export(formation_id, export_ids)
except ValueError:
return error_response(500, message="Erreur inconnue")
@ -236,9 +229,8 @@ def moduleimpl(moduleimpl_id: int):
}
}
"""
modimpl = models.ModuleImpl.query.filter_by(id=moduleimpl_id).first_or_404()
data = modimpl.to_dict()
return jsonify(data)
modimpl = models.ModuleImpl.query.get_or_404(moduleimpl_id)
return jsonify(modimpl.to_dict())
@bp.route(
@ -253,10 +245,9 @@ def referentiel_competences(formation_id: int):
formation_id : l'id d'une formation
return json, ou null si pas de référentiel associé.
return null si pas de référentiel associé.
"""
formation = models.Formation.query.filter_by(id=formation_id).first_or_404()
formation = models.Formation.query.get_or_404(formation_id)
if formation.referentiel_competence is None:
return jsonify(None)
return jsonify(formation.referentiel_competence.to_dict())

View File

@ -1,5 +1,12 @@
########################################## Formsemestres ##############################################################
import statistics
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""
ScoDoc 9 API : accès aux formsemestres
"""
from flask import jsonify
@ -7,11 +14,10 @@ import app
from app import models
from app.api import bp
from app.api.auth import token_auth, token_permission_required
from app.api.errors import error_response
from app.comp import res_sem
from app.comp.moy_mod import ModuleImplResults
from app.comp.res_compat import NotesTableCompat
from app.models import Departement, FormSemestre, FormSemestreEtape, ModuleImpl
from app.models import Evaluation, FormSemestre, FormSemestreEtape, ModuleImpl
from app.scodoc.sco_bulletins import get_formsemestre_bulletin_etud_json
from app.scodoc.sco_groups import get_etud_groups
from app.scodoc.sco_permissions import Permission
@ -22,7 +28,7 @@ import app.scodoc.sco_utils as scu
@bp.route("/formsemestre/<int:formsemestre_id>", methods=["GET"])
@token_auth.login_required
@token_permission_required(Permission.APIView)
def formsemestre(formsemestre_id: int):
def formsemestre_infos(formsemestre_id: int):
"""
Information sur le formsemestre indiqué.
@ -59,17 +65,8 @@ def formsemestre(formsemestre_id: int):
}
"""
formsemestre: FormSemestre = models.FormSemestre.query.filter_by(
id=formsemestre_id
).first_or_404()
data = formsemestre.to_dict(convert_parcours=True)
# Pour le moment on a besoin de fixer le departement
# pour accéder aux préferences
dept = Departement.query.get(formsemestre.dept_id)
app.set_sco_dept(dept.acronym)
data["annee_scolaire"] = formsemestre.annee_scolaire_str()
data["session_id"] = formsemestre.session_id()
return jsonify(data)
formsemestre: FormSemestre = models.FormSemestre.query.get_or_404(formsemestre_id)
return jsonify(formsemestre.to_dict_api())
@bp.route("/formsemestre/apo/<string:etape_apo>", methods=["GET"])
@ -92,9 +89,7 @@ def formsemestre_apo(etape_apo: str):
FormSemestreEtape.formsemestre_id == FormSemestre.id,
)
return jsonify(
[formsemestre.to_dict(convert_parcours=True) for formsemestre in formsemestres]
)
return jsonify([formsemestre.to_dict_api() for formsemestre in formsemestres])
@bp.route("/formsemestre/<int:formsemestre_id>/bulletins", methods=["GET"])
@ -106,183 +101,10 @@ def bulletins(formsemestre_id: int):
formsemestre_id : l'id d'un formesemestre
Exemple de résultat :
[
{
"version": "0",
"type": "BUT",
"date": "2022-04-27T07:18:16.450634Z",
"publie": true,
"etudiant": {
"civilite": "X",
"code_ine": "1",
"code_nip": "1",
"date_naissance": "",
"email": "SACHA.COSTA@example.com",
"emailperso": "",
"etudid": 1,
"nom": "COSTA",
"prenom": "SACHA",
"nomprenom": "Sacha COSTA",
"lieu_naissance": "",
"dept_naissance": "",
"nationalite": "",
"boursier": "",
"fiche_url": "/ScoDoc/TAPI/Scolarite/ficheEtud?etudid=1",
"photo_url": "/ScoDoc/TAPI/Scolarite/get_photo_image?etudid=1&size=small",
"id": 1,
"codepostaldomicile": "",
"paysdomicile": "",
"telephonemobile": "",
"typeadresse": "domicile",
"domicile": "",
"villedomicile": "",
"telephone": "",
"fax": "",
"description": ""
},
"formation": {
"id": 1,
"acronyme": "BUT R&amp;T",
"titre_officiel": "Bachelor technologique r\u00e9seaux et t\u00e9l\u00e9communications",
"titre": "BUT R&amp;T"
},
"formsemestre_id": 1,
"etat_inscription": "I",
"options": {
"show_abs": true,
"show_abs_modules": false,
"show_ects": true,
"show_codemodules": false,
"show_matieres": false,
"show_rangs": true,
"show_ue_rangs": true,
"show_mod_rangs": true,
"show_moypromo": false,
"show_minmax": false,
"show_minmax_mod": false,
"show_minmax_eval": false,
"show_coef": true,
"show_ue_cap_details": false,
"show_ue_cap_current": true,
"show_temporary": true,
"temporary_txt": "Provisoire",
"show_uevalid": true,
"show_date_inscr": true
},
"ressources": {
"R101": {
"id": 1,
"titre": "Initiation aux r\u00e9seaux informatiques",
"code_apogee": null,
"url": "/ScoDoc/TAPI/Scolarite/Notes/moduleimpl_status?moduleimpl_id=1",
"moyenne": {},
"evaluations": [
{
"id": 1,
"description": "eval1",
"date": "2022-04-20",
"heure_debut": "08:00",
"heure_fin": "09:00",
"coef": "01.00",
"poids": {
"RT1.1": 1.0,
},
"note": {
"value": "12.00",
"min": "00.00",
"max": "18.00",
"moy": "10.88"
},
"url": "/ScoDoc/TAPI/Scolarite/Notes/evaluation_listenotes?evaluation_id=1"
}
]
},
},
"saes": {
"SAE11": {
"id": 2,
"titre": "Se sensibiliser \u00e0 l&apos;hygi\u00e8ne informatique et \u00e0 la cybers\u00e9curit\u00e9",
"code_apogee": null,
"url": "/ScoDoc/TAPI/Scolarite/Notes/moduleimpl_status?moduleimpl_id=2",
"moyenne": {},
"evaluations": []
},
},
"ues": {
"RT1.1": {
"id": 1,
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
"numero": 1,
"type": 0,
"color": "#B80004",
"competence": null,
"moyenne": {
"value": "08.50",
"min": "06.00",
"max": "16.50",
"moy": "11.31",
"rang": "12",
"total": 16
},
"bonus": "00.00",
"malus": "00.00",
"capitalise": null,
"ressources": {
"R101": {
"id": 1,
"coef": 12.0,
"moyenne": "12.00"
},
},
"saes": {
"SAE11": {
"id": 2,
"coef": 16.0,
"moyenne": "~"
},
},
"ECTS": {
"acquis": 0.0,
"total": 12.0
}
},
"semestre": {
"etapes": [],
"date_debut": "2021-09-01",
"date_fin": "2022-08-31",
"annee_universitaire": "2021 - 2022",
"numero": 1,
"inscription": "",
"groupes": [],
"absences": {
"injustifie": 1,
"total": 2
},
"ECTS": {
"acquis": 0,
"total": 30.0
},
"notes": {
"value": "10.60",
"min": "02.40",
"moy": "11.05",
"max": "17.40"
},
"rang": {
"value": "10",
"total": 16
}
}
},
...
]
Exemple de résultat : liste, voir https://scodoc.org/ScoDoc9API/#bulletin
"""
formsemestre = models.FormSemestre.query.filter_by(
id=formsemestre_id
).first_or_404()
dept = models.Departement.query.filter_by(id=formsemestre.dept_id).first_or_404()
app.set_sco_dept(dept.acronym)
formsemestre = models.FormSemestre.query.get_or_404(formsemestre_id)
app.set_sco_dept(formsemestre.departement.acronym)
data = []
for etu in formsemestre.etuds:
@ -292,44 +114,6 @@ def bulletins(formsemestre_id: int):
return jsonify(data)
# XXX Attendre ScoDoc 9.3
# @bp.route("/formsemestre/<int:formsemestre_id>/jury", methods=["GET"])
# @token_auth.login_required
# @token_permission_required(Permission.APIView)
# def jury(formsemestre_id: int):
# """
# Retourne le récapitulatif des décisions jury
# formsemestre_id : l'id d'un formsemestre
# Exemple de résultat :
# """
# # Fonction utilisée : app.scodoc.sco_pvjury.formsemestre_pvjury()
# formsemestre = models.FormSemestre.query.filter_by(
# id=formsemestre_id
# ).first_or_404()
# dept = models.Departement.query.filter_by(id=formsemestre.dept_id).first_or_404()
# app.set_sco_dept(dept.acronym)
# data = formsemestre_pvjury(formsemestre_id)
# # try:
# # # Utilisation de la fonction formsemestre_pvjury
# # data = formsemestre_pvjury(formsemestre_id)
# # except AttributeError:
# # return error_response(
# # 409,
# # message="La requête ne peut être traitée en létat actuel. \n"
# # "Veillez vérifier la conformité du 'formation_id'",
# # )
# return jsonify(data)
@bp.route(
"/formsemestre/<int:formsemestre_id>/programme",
methods=["GET"],
@ -401,10 +185,7 @@ def formsemestre_programme(formsemestre_id: int):
"modules" : [ ... les modules qui ne sont ni des SAEs ni des ressources ... ]
}
"""
formsemestre: FormSemestre = models.FormSemestre.query.filter_by(
id=formsemestre_id
).first_or_404()
formsemestre: FormSemestre = models.FormSemestre.query.get_or_404(formsemestre_id)
ues = formsemestre.query_ues()
m_list = {
ModuleType.RESSOURCE: [],
@ -428,48 +209,37 @@ def formsemestre_programme(formsemestre_id: int):
@bp.route(
"/formsemestre/<int:formsemestre_id>/etudiants",
methods=["GET"],
defaults={"etat": "I"},
defaults={"etat": scu.INSCRIT},
)
@bp.route(
"/formsemestre/<int:formsemestre_id>/etudiants/demissionnaires",
methods=["GET"],
defaults={"etat": "D"},
defaults={"etat": scu.DEMISSION},
)
@bp.route(
"/formsemestre/<int:formsemestre_id>/etudiants/defaillants",
methods=["GET"],
defaults={"etat": "DEF"},
defaults={"etat": scu.DEF},
)
@token_auth.login_required
@token_permission_required(Permission.APIView)
def formsemestre_etudiants(formsemestre_id: int, etat: str):
"""
Retourne la liste des étudiants d'un semestre
Retourne la liste des étudiants d'un formsemestre
formsemestre_id : l'id d'un semestre
formsemestre_id : l'id d'un formsemestre
"""
# fonction to use : sco_groups.get_etud_groups
formsemestre = models.FormSemestre.query.filter_by(
formsemestre: FormSemestre = models.FormSemestre.query.filter_by(
id=formsemestre_id
).first_or_404()
# Récupération des étudiants du formsemestre
etuds = [etu.to_dict_short() for etu in formsemestre.etuds]
inscriptions = [ins for ins in formsemestre.inscriptions if ins.etat == etat]
etuds = [ins.etud.to_dict_short() for ins in inscriptions]
# Ajout des groupes de chaque étudiants
for etud in etuds:
etud["groups"] = get_etud_groups(etud["id"], formsemestre_id)
res = []
# Trie des étudiants suivant leur état d'inscription voulu
for etu in etuds:
formsemestre_inscription = models.FormSemestreInscription.query.filter_by(
formsemestre_id=formsemestre_id, etudid=etu["id"]
).first_or_404()
if formsemestre_inscription.etat == etat:
res.append(etu)
# Ajout des groups de chaques étudiants
for etu in res:
etu["groups"] = get_etud_groups(etu["id"], formsemestre_id)
return jsonify(res)
return jsonify(etuds)
@bp.route("/formsemestre/<int:formsemestre_id>/etat_evals", methods=["GET"])
@ -477,154 +247,103 @@ def formsemestre_etudiants(formsemestre_id: int, etat: str):
@token_permission_required(Permission.APIView)
def etat_evals(formsemestre_id: int):
"""
Retourne les informations sur l'état des évaluations d'un semestre donnée
Informations sur l'état des évaluations d'un formsemestre.
formsemestre_id : l'id d'un semestre
Exemple de résultat :
{
"RT1.1": [
{
"id": 1,
"titre": "Initiation aux réseaux informatiques",
"evaluations": [
{
"id": 1,
"description": null,
"datetime_epreuve": null,
"heure_fin": "09:00:00",
"coefficient": "02.00"
"comptee": "oui",
"inscrits": 16,
"manquantes": 0,
"ABS": 0,
"ATT": 0,
"EXC": 0,
"saisie_notes": {
"datetime_debut": "2021-09-11T00:00:00+02:00",
"datetime_fin": "2022-08-25T00:00:00+02:00",
"datetime_mediane": "2022-03-19T00:00:00+01:00"
}
},
{
"id": 22,
"description": null,
"datetime_epreuve": "Tue, 31 May 2022 00:00:00 GMT",
"heure_fin": "08:00:00",
"comptee": "oui",
"inscrits": 16,
"manquantes": 0,
"ABS": 0,
"ATT": 0,
"EXC": 0,
"saisie_notes": {
"datetime_debut": "2021-09-11T00:00:00+02:00",
"datetime_fin": "2022-08-25T00:00:00+02:00",
"datetime_mediane": "2022-03-19T00:00:00+01:00"
}
},
]
},
]
}
[
{
"id": 1, // moduleimpl_id
"titre": "Initiation aux réseaux informatiques",
"evaluations": [
{
"id": 1,
"description": null,
"datetime_epreuve": null,
"heure_fin": "09:00:00",
"coefficient": "02.00"
"is_complete": true,
"nb_inscrits": 16,
"nb_manquantes": 0,
"ABS": 0,
"ATT": 0,
"EXC": 0,
"saisie_notes": {
"datetime_debut": "2021-09-11T00:00:00+02:00",
"datetime_fin": "2022-08-25T00:00:00+02:00",
"datetime_mediane": "2022-03-19T00:00:00+01:00"
}
},
...
]
},
]
"""
# Récupération du semestre
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
# Set du dept
dept = Departement.query.get(formsemestre.dept_id)
app.set_sco_dept(dept.acronym)
# Récupération des Ues
list_ues = formsemestre.query_ues()
app.set_sco_dept(formsemestre.departement.acronym)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
ues = {}
result = []
for modimpl_id in nt.modimpls_results:
modimpl_results: ModuleImplResults = nt.modimpls_results[modimpl_id]
modimpl = ModuleImpl.query.get_or_404(modimpl_id)
modimpl_dict = modimpl.to_dict()
for ue in list_ues:
modules = []
mods = ue.modules
list_eval = []
for evaluation_id in modimpl_results.evaluations_etat:
eval_etat = modimpl_results.evaluations_etat[evaluation_id]
evaluation = Evaluation.query.get_or_404(evaluation_id)
eval_dict = evaluation.to_dict()
eval_dict["etat"] = eval_etat.to_dict()
for mod in mods:
dict_module = {}
moduleimpl = ModuleImpl.query.get_or_404(mod.id)
eval_dict["nb_inscrits"] = modimpl_results.nb_inscrits_module
eval_dict["nb_notes_manquantes"] = len(
modimpl_results.evals_etudids_sans_note[evaluation.id]
)
eval_dict["nb_notes_abs"] = sum(
modimpl_results.evals_notes[evaluation.id] == scu.NOTES_ABSENCE
)
eval_dict["nb_notes_att"] = eval_etat.nb_attente
eval_dict["nb_notes_exc"] = sum(
modimpl_results.evals_notes[evaluation.id] == scu.NOTES_NEUTRALISE
)
modimpl_results: ModuleImplResults = nt.modimpls_results[moduleimpl.id]
# Récupération de toutes les notes de l'évaluation
# eval["notes"] = modimpl_results.get_eval_notes_dict(evaluation_id)
dict_module["id"] = mod.id
dict_module["titre"] = mod.titre
notes = models.NotesNotes.query.filter_by(evaluation_id=evaluation.id).all()
list_eval = []
for evaluation in moduleimpl.evaluations:
eval_etat = modimpl_results.evaluations_etat[evaluation.id]
eval = {}
date_debut = None
date_fin = None
date_mediane = None
eval["id"] = evaluation.id
eval["description"] = evaluation.description
eval["datetime_epreuve"] = (
evaluation.jour.isoformat() if evaluation.jour is not None else None
)
eval["heure_fin"] = evaluation.heure_fin.isoformat()
eval["coefficient"] = evaluation.coefficient
eval["comptee"] = "oui" if eval_etat.is_complete else "non"
eval["inscrits"] = modimpl_results.nb_inscrits_module
eval["manquantes"] = len(
modimpl_results.evals_etudids_sans_note[evaluation.id]
)
eval["ABS"] = sum(
modimpl_results.evals_notes[evaluation.id] == scu.NOTES_ABSENCE
)
eval["ATT"] = eval_etat.nb_attente
eval["EXC"] = sum(
modimpl_results.evals_notes[evaluation.id] == scu.NOTES_NEUTRALISE
)
# Si il y a plus d'une note saisie pour l'évaluation
if len(notes) >= 1:
# Trie des notes en fonction de leurs dates
notes_sorted = sorted(notes, key=lambda note: note.date)
# Récupération de toutes les notes de l'évaluation
notes = models.NotesNotes.query.filter_by(
evaluation_id=evaluation.id
).all()
date_debut = notes_sorted[0].date
date_fin = notes_sorted[-1].date
date_debut = None
date_fin = None
date_mediane = None
# Récupération de l'id de la note médiane
list_id_notes_sorted = [note.id for note in notes_sorted]
id_mediane = list_id_notes_sorted[len(list_id_notes_sorted) // 2]
date_mediane = notes_sorted[id_mediane].date
# Si il y a plus d'une note saisie pour l'évaluation
if len(notes) >= 1:
# Trie des notes en fonction de leurs dates
notes_sorted = sorted(notes, key=lambda note: note.date)
eval_dict["saisie_notes"] = {
"datetime_debut": date_debut.isoformat()
if date_debut is not None
else None,
"datetime_fin": date_fin.isoformat() if date_fin is not None else None,
"datetime_mediane": date_mediane.isoformat()
if date_mediane is not None
else None,
}
date_debut = notes_sorted[0].date
date_fin = notes_sorted[-1].date
list_eval.append(eval)
# Récupération de l'id de la note médiane
list_id_notes_sorted = [note.id for note in notes_sorted]
modimpl_dict["evaluations"] = list_eval
result.append(modimpl_dict)
# Ici si la longueur est paire on prend, on prend le +1 car un indice ne peux pas avoir de nombre floatant
id_mediane = list_id_notes_sorted[
int((len(list_id_notes_sorted)) / 2)
]
for n in notes_sorted:
if n.id == id_mediane:
date_mediane = n.date
eval["saisie_notes"] = {
"datetime_debut": date_debut.isoformat()
if date_debut is not None
else None,
"datetime_fin": date_fin.isoformat()
if date_fin is not None
else None,
"datetime_mediane": date_mediane.isoformat()
if date_mediane is not None
else None,
}
list_eval.append(eval)
dict_module["evaluations"] = list_eval
modules.append(dict_module)
ues[ue.acronyme] = modules
return jsonify(ues)
return jsonify(result)

View File

@ -1,12 +1,21 @@
############################################### Partitions ############################################################
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""
ScoDoc 9 API : partitions
"""
from flask import jsonify
from app import models
from app.api import bp
from app.api.errors import error_response
from app.api.auth import token_auth, token_permission_required
from app.scodoc.sco_groups import get_group_members, setGroups, get_partitions_list
from app.models import FormSemestre, FormSemestreInscription, Identite
from app.models import GroupDescr, Partition
from app.models.groups import group_membership
from app.scodoc.sco_permissions import Permission
@ -41,15 +50,8 @@ def partition(formsemestre_id: int):
}
]
"""
# # Récupération de toutes les partitions
# partitions = models.Partition.query.filter_by(id=formsemestre_id)
#
# # Mise en forme des données
# data = [partition.to_dict() for partition in partitions]
data = get_partitions_list(formsemestre_id)
return jsonify(data)
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
return jsonify([partition.to_dict() for partition in formsemestre.partitions])
@bp.route("/partition/group/<int:group_id>", methods=["GET"])
@ -64,58 +66,32 @@ def etud_in_group(group_id: int, etat=None):
etat : état de l'inscription
Exemple de résultat :
[
{
"etudid": 10,
"id": 10,
"dept_id": 1,
"nom": "BOUTET",
"prenom": "Marguerite",
"nom_usuel": "",
"civilite": "F",
"date_naissance": null,
"lieu_naissance": null,
"dept_naissance": null,
"nationalite": null,
"statut": null,
"boursier": null,
"photo_filename": null,
"code_nip": "10",
"code_ine": "10",
"scodoc7_id": null,
"email": "MARGUERITE.BOUTET@example.com",
"emailperso": null,
"domicile": null,
"codepostaldomicile": null,
"villedomicile": null,
"paysdomicile": null,
"telephone": null,
"telephonemobile": null,
"fax": null,
"typeadresse": "domicile",
"description": null,
"group_id": 1,
"etat": "I",
"civilite_str": "Mme",
"nom_disp": "BOUTET",
"nomprenom": "Mme Marguerite BOUTET",
"ne": "e",
"email_default": "MARGUERITE.BOUTET@example.com"
},
...
]
[
{
'civilite': 'M',
'id': 123456,
'ine': None,
'nip': '987654321',
'nom': 'MARTIN',
'nom_usuel': null,
'prenom': 'JEAN'}
},
...
]
"""
# Fonction utilisée : app.scodoc.sco_groups.get_group_members()
group = GroupDescr.query.get_or_404(group_id)
if etat is None:
data = get_group_members(group_id)
query = group.etuds
else:
data = get_group_members(group_id, etat)
query = (
Identite.query.join(FormSemestreInscription)
.filter_by(formsemestre_id=group.partition.formsemestre_id, etat=etat)
.join(group_membership)
.filter_by(group_id=group_id)
)
if len(data) == 0:
return error_response(404, message="group_id inconnu")
return jsonify(data)
return jsonify([etud.to_dict_short() for etud in query])
@bp.route(

View File

@ -1,14 +1,22 @@
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""ScoDoc 9 API : outils
"""
from sqlalchemy import desc
from app import models
from app.api.errors import error_response
from app.models import Identite
from app.models import Identite, Admission
def get_last_instance_etud_from_etudid_or_nip_or_ine(
etudid=None, nip=None, ine=None
) -> models.Identite:
def get_etud(etudid=None, nip=None, ine=None) -> models.Identite:
"""
Retourne l'instance de l'etudiant la plus récente en fonction de l'etudid, code nip et code ine rentré en paramètres
L'instance d'étudiant la plus récente en fonction de l'etudid,
ou du code nip ou code ine.
etudid : None ou un int etudid
nip : None ou un int code_nip
@ -17,26 +25,15 @@ def get_last_instance_etud_from_etudid_or_nip_or_ine(
Return None si étudiant inexistant.
"""
if etudid is not None:
etud = Identite.query.get(etudid)
return Identite.query.get(etudid)
if nip is not None:
query = Identite.query.filter_by(code_nip=nip)
elif ine is not None:
query = Identite.query.filter_by(code_ine=ine)
else:
if nip is not None:
query = Identite.query.filter_by(code_nip=nip)
elif ine is not None:
query = Identite.query.filter_by(code_ine=ine)
else:
return error_response(
404,
message="parametre manquant",
)
if query.count() > 1: # cas rare d'un étudiant présent dans plusieurs depts
etuds = []
for e in query:
admission = e.admission.first()
etuds.append((((admission.annee or 0) if admission else 0), e))
etuds.sort()
etud = etuds[-1][1]
else:
etud = query.first()
return etud
return error_response(
404,
message="parametre manquant",
)
return query.join(Admission).order_by(desc(Admission.annee)).first()

View File

@ -33,6 +33,7 @@ Rappel: pour éviter les confusions, on appelera *poids* les coefficients d'une
évaluation dans un module, et *coefficients* ceux utilisés pour le calcul de la
moyenne générale d'une UE.
"""
import dataclasses
from dataclasses import dataclass
import numpy as np
import pandas as pd
@ -54,6 +55,10 @@ class EvaluationEtat:
nb_attente: int
is_complete: bool
def to_dict(self):
"convert to dict"
return dataclasses.asdict(self)
class ModuleImplResults:
"""Classe commune à toutes les formations (standard et APC).
@ -236,6 +241,16 @@ class ModuleImplResults:
self.evals_notes.values > scu.NOTES_ABSENCE, self.evals_notes.values, 0.0
) / [e.note_max / 20.0 for e in moduleimpl.evaluations]
def get_eval_notes_dict(self, evaluation_id: int) -> dict:
"""Notes d'une évaulation, brutes, sous forme d'un dict
{ etudid : valeur }
avec les valeurs float, ou "ABS" ou EXC
"""
return {
etudid: scu.fmt_note(x, keep_numeric=True)
for (etudid, x) in self.evals_notes[evaluation_id].items()
}
def get_evaluation_rattrapage(self, moduleimpl: ModuleImpl):
"""L'évaluation de rattrapage de ce module, ou None s'il n'en a pas.
Rattrapage: la moyenne du module est la meilleure note entre moyenne

View File

@ -29,15 +29,6 @@ class Absence(db.Model):
# XXX TODO: contrainte ajoutée: vérifier suppression du module
# (mettre à NULL sans supprimer)
def __init__(self, id, etudid, jour, estabs, estjust, matin, description):
self.id = id
self.etudid = etudid
self.jour = jour
self.estabs = estabs
self.estjust = estjust
self.matin = matin
self.description = description
def to_dict(self):
data = {
"id": self.id,

View File

@ -83,40 +83,6 @@ class ApcReferentielCompetences(db.Model, XMLModel):
)
formations = db.relationship("Formation", backref="referentiel_competence")
def __init__(
self,
id,
dept_id,
annexe,
specialite,
specialite_long,
type_titre,
type_structure,
type_departement,
version_orebut,
_xml_attribs,
#scodoc_date_loaded,
scodoc_orig_filename,
# competences,
# parcours,
# formations,
):
self.id = id
self.dept_id = dept_id
self.annexe = annexe
self.specialite = specialite
self.specialite_long = specialite_long
self.type_titre = type_titre
self.type_structure = type_structure
self.type_departement = type_departement
self.version_orebut = version_orebut
self._xml_attribs = _xml_attribs
#self.scodoc_date_loaded = scodoc_date_loaded
self.scodoc_orig_filename = scodoc_orig_filename
# self.competences = competences
# self.parcours = parcours
# self.formations = formations
def __repr__(self):
return f"<ApcReferentielCompetences {self.id} {self.specialite!r} {self.departement!r}>"
@ -225,32 +191,6 @@ class ApcCompetence(db.Model, XMLModel):
cascade="all, delete-orphan",
)
def __init__(
self,
id,
referentiel_id,
id_orebut,
titre,
titre_long,
couleur,
numero,
_xml_attribs,
situations,
composantes_essentielles,
niveaux,
):
self.id = id
self.referentiel_id = referentiel_id
self.id_orebut = id_orebut
self.titre = titre
self.titre_long = titre_long
self.couleur = couleur
self.numero = numero
self._xml_attribs = _xml_attribs
self.situations = situations
self.composantes_essentielles = composantes_essentielles
self.niveaux = niveaux
def __repr__(self):
return f"<ApcCompetence {self.id} {self.titre!r}>"
@ -288,12 +228,6 @@ class ApcSituationPro(db.Model, XMLModel):
)
libelle = db.Column(db.Text(), nullable=False)
# aucun attribut (le text devient le libellé)
def __init__(self, id, competence_id, libelle):
self.id = id
self.competence_id = competence_id
self.libelle = libelle
def to_dict(self):
return {"libelle": self.libelle}
@ -306,11 +240,6 @@ class ApcComposanteEssentielle(db.Model, XMLModel):
)
libelle = db.Column(db.Text(), nullable=False)
def __init__(self, id, competence_id, libelle):
self.id = id
self.competence_id = competence_id
self.libelle = libelle
def to_dict(self):
return {"libelle": self.libelle}
@ -339,14 +268,6 @@ class ApcNiveau(db.Model, XMLModel):
)
ues = db.relationship("UniteEns", back_populates="niveau_competence")
def __init__(self, id, competence_id, libelle, annee, ordre, app_critiques):
self.id = id
self.competence_id = competence_id
self.libelle = libelle
self.annee = annee
self.ordre = ordre
self.app_critiques = app_critiques
def __repr__(self):
return f"""<{self.__class__.__name__} {self.id} ordre={self.ordre!r} annee={
self.annee!r} {self.competence!r}>"""
@ -452,13 +373,6 @@ class ApcAppCritique(db.Model, XMLModel):
query = query.filter(ApcNiveau.competence == competence)
return query
def __init__(self, id, niveau_id, code, libelle, modules):
self.id = id
self.niveau_id = niveau_id
self.code = code
self.libelle = libelle
self.modules = modules
def to_dict(self) -> dict:
return {"libelle": self.libelle}
@ -517,14 +431,6 @@ class ApcParcours(db.Model, XMLModel):
cascade="all, delete-orphan",
)
def __init__(self, id, referentiel_id, numero, code, libelle, annes):
self.id = id
self.referentiel_id = referentiel_id
self.numero = numero
self.code = code
self.libelle = libelle
self.annes = annes
def __repr__(self):
return f"<{self.__class__.__name__} {self.id} {self.code!r} ref={self.referentiel}>"
@ -545,11 +451,6 @@ class ApcAnneeParcours(db.Model, XMLModel):
ordre = db.Column(db.Integer)
"numéro de l'année: 1, 2, 3"
def __init__(self, id, parcours_id, ordre):
self.id = id
self.parcours_id = parcours_id
self.ordre = ordre
def __repr__(self):
return f"<{self.__class__.__name__} {self.id} ordre={self.ordre!r} parcours={self.parcours.code!r}>"

View File

@ -654,11 +654,6 @@ class FormSemestreEtape(db.Model):
# etape_apo aurait du etre not null, mais oublié
etape_apo = db.Column(db.String(APO_CODE_STR_LEN), index=True)
def __init__(self, id, formsemestre_id, etape_apo):
self.id = id
self.formsemestre_id = formsemestre_id
self.etape_apo = etape_apo
def __bool__(self):
"Etape False if code empty"
return self.etape_apo is not None and (len(self.etape_apo) > 0)

View File

@ -58,12 +58,9 @@ class Partition(db.Model):
def to_dict(self, with_groups=False) -> dict:
"""as a dict, with or without groups"""
d = {
"id": self.id,
"formsemestre_id": self.partition_id,
"name": self.partition_name,
"numero": self.numero,
}
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
if with_groups:
d["groups"] = [group.to_dict(with_partition=False) for group in self.groups]
return d

View File

@ -47,24 +47,11 @@ class NotesNotes(db.Model):
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
uid = db.Column(db.Integer, db.ForeignKey("user.id"))
def __init__(self, etudid, evaluation_id, value, comment, date, uid):
self.etudid = etudid
self.evaluation_id = evaluation_id
self.value = value
self.comment = comment
self.date = date
self.uid = uid
def to_dict(self):
return {
"id": self.id,
"etudid": self.etudid,
"evaluation_id": self.evaluation_id,
"value": self.value,
"comment": self.comment,
"date": self.date,
"uid": self.uid,
}
def to_dict(self) -> dict:
"dict"
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
return d
class NotesNotesLog(db.Model):

View File

@ -136,7 +136,7 @@ def get_partition(partition_id):
return r[0]
def get_partitions_list(formsemestre_id, with_default=True):
def get_partitions_list(formsemestre_id, with_default=True) -> list[dict]:
"""Liste des partitions pour ce semestre (list of dicts)"""
partitions = ndb.SimpleDictFetch(
"""SELECT p.id AS partition_id, p.*
@ -146,9 +146,9 @@ def get_partitions_list(formsemestre_id, with_default=True):
{"formsemestre_id": formsemestre_id},
)
# Move 'all' at end of list (for menus)
R = [p for p in partitions if p["partition_name"] != None]
R = [p for p in partitions if p["partition_name"] is not None]
if with_default:
R += [p for p in partitions if p["partition_name"] == None]
R += [p for p in partitions if p["partition_name"] is None]
return R