forked from ScoDoc/ScoDoc
Assiduites : révisions + corrections linter
This commit is contained in:
parent
3998b5a366
commit
cf3258f5f9
@ -6,23 +6,20 @@
|
||||
"""ScoDoc 9 API : Assiduités
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
from typing import List
|
||||
from flask import g, jsonify, request
|
||||
|
||||
from app import db
|
||||
|
||||
from app.api import api_bp as bp, api_web_bp
|
||||
from app.scodoc.sco_utils import json_error
|
||||
from app.decorators import scodoc, permission_required
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from flask_login import login_required
|
||||
|
||||
|
||||
from app.models import Identite, Assiduite, FormSemestre, ModuleImpl
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.sco_assiduites as scass
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app import db
|
||||
from app.api import api_bp as bp
|
||||
from app.api import api_web_bp
|
||||
from app.decorators import permission_required, scodoc
|
||||
from app.models import Assiduite, FormSemestre, Identite, ModuleImpl
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_utils import json_error
|
||||
|
||||
|
||||
@bp.route("/assiduite/<int:assiduite_id>")
|
||||
@ -47,10 +44,9 @@ def assiduite(assiduite_id: int = None):
|
||||
query = Assiduite.query.filter_by(id=assiduite_id)
|
||||
# if g.scodoc_dept:
|
||||
# query = query.join(Identite).filter_by(dept_id=g.scodoc_dept_id)
|
||||
assiduite_query = query.first_or_404()
|
||||
|
||||
assiduite = query.first_or_404()
|
||||
|
||||
data = assiduite.to_dict()
|
||||
data = assiduite_query.to_dict()
|
||||
|
||||
return jsonify(change_etat(data))
|
||||
|
||||
@ -104,15 +100,15 @@ def count_assiduites(etudid: int = None, with_query: bool = False):
|
||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||
|
||||
etud: Identite = query.first_or_404(etudid)
|
||||
filter: dict[str, object] = {}
|
||||
filtered: dict[str, object] = {}
|
||||
metric: str = "all"
|
||||
|
||||
if with_query:
|
||||
metric, filter = count_manager(request)
|
||||
metric, filtered = count_manager(request)
|
||||
|
||||
return jsonify(
|
||||
scass.get_assiduites_stats(
|
||||
assiduites=etud.assiduites, metric=metric, filter=filter
|
||||
assiduites=etud.assiduites, metric=metric, filtered=filtered
|
||||
)
|
||||
)
|
||||
|
||||
@ -162,13 +158,13 @@ def assiduites(etudid: int = None, with_query: bool = False):
|
||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||
|
||||
etud: Identite = query.first_or_404(etudid)
|
||||
assiduites = etud.assiduites
|
||||
assiduites_query = etud.assiduites
|
||||
|
||||
if with_query:
|
||||
assiduites = filter_manager(request, assiduites)
|
||||
assiduites_query = filter_manager(request, assiduites_query)
|
||||
|
||||
data_set: List[dict] = []
|
||||
for ass in assiduites.all():
|
||||
for ass in assiduites_query.all():
|
||||
data = ass.to_dict()
|
||||
data_set.append(change_etat(data))
|
||||
|
||||
@ -200,17 +196,13 @@ def assiduites_formsemestre(formsemestre_id: int, with_query: bool = False):
|
||||
if formsemestre is None:
|
||||
return json_error(404, "le paramètre 'formsemestre_id' n'existe pas")
|
||||
|
||||
etuds = formsemestre.etuds.all()
|
||||
etuds_id = [etud.id for etud in etuds]
|
||||
|
||||
assiduites = Assiduite.query.filter(Assiduite.etudid.in_(etuds_id))
|
||||
assiduites = scass.filter_by_formsemstre(assiduites, formsemestre)
|
||||
assiduites_query = scass.filter_by_formsemestre(Assiduite.query, formsemestre)
|
||||
|
||||
if with_query:
|
||||
assiduites = filter_manager(request, assiduites)
|
||||
assiduites_query = filter_manager(request, assiduites_query)
|
||||
|
||||
data_set: List[dict] = []
|
||||
for ass in assiduites.all():
|
||||
for ass in assiduites_query.all():
|
||||
data = ass.to_dict()
|
||||
data_set.append(change_etat(data))
|
||||
|
||||
@ -249,14 +241,14 @@ def count_assiduites_formsemestre(
|
||||
etuds = formsemestre.etuds.all()
|
||||
etuds_id = [etud.id for etud in etuds]
|
||||
|
||||
assiduites = Assiduite.query.filter(Assiduite.etudid.in_(etuds_id))
|
||||
assiduites = scass.filter_by_formsemstre(assiduites, formsemestre)
|
||||
assiduites_query = Assiduite.query.filter(Assiduite.etudid.in_(etuds_id))
|
||||
assiduites_query = scass.filter_by_formsemestre(assiduites_query, formsemestre)
|
||||
metric: str = "all"
|
||||
filter: dict = {}
|
||||
filtered: dict = {}
|
||||
if with_query:
|
||||
metric, filter = count_manager(request)
|
||||
metric, filtered = count_manager(request)
|
||||
|
||||
return jsonify(scass.get_assiduites_stats(assiduites, metric, filter))
|
||||
return jsonify(scass.get_assiduites_stats(assiduites_query, metric, filtered))
|
||||
|
||||
|
||||
@bp.route("/assiduite/<int:etudid>/create", methods=["POST"])
|
||||
@ -269,27 +261,37 @@ def create(etudid: int = None):
|
||||
"""
|
||||
Création d'une assiduité pour l'étudiant (etudid)
|
||||
La requête doit avoir un content type "application/json":
|
||||
{
|
||||
"date_debut": str,
|
||||
"date_fin": str,
|
||||
"etat": str,
|
||||
}
|
||||
ou
|
||||
{
|
||||
"date_debut": str,
|
||||
"date_fin": str,
|
||||
"etat": str,
|
||||
"moduleimpl_id": int,
|
||||
}
|
||||
[
|
||||
{
|
||||
"date_debut": str,
|
||||
"date_fin": str,
|
||||
"etat": str,
|
||||
},
|
||||
{
|
||||
"date_debut": str,
|
||||
"date_fin": str,
|
||||
"etat": str,
|
||||
"moduleimpl_id": int,
|
||||
"desc":str,
|
||||
}
|
||||
...
|
||||
]
|
||||
|
||||
TODO:
|
||||
- vérifier si l'entrée est bien une liste
|
||||
|
||||
"""
|
||||
etud: Identite = Identite.query.filter_by(id=etudid).first_or_404()
|
||||
|
||||
create_list: list[object] = request.get_json(force=True)
|
||||
|
||||
if not isinstance(create_list, list):
|
||||
return json_error(404, "Le contenu envoyé n'est pas une liste")
|
||||
|
||||
errors: dict[int, str] = {}
|
||||
success: dict[int, object] = {}
|
||||
for i, data in enumerate(request.get_json(force=True)):
|
||||
code, obj = create_singular(data, etud)
|
||||
for i, data in enumerate(create_list):
|
||||
code, obj = _create_singular(data, etud)
|
||||
if code == 404:
|
||||
errors[i] = obj
|
||||
else:
|
||||
@ -298,7 +300,7 @@ def create(etudid: int = None):
|
||||
return jsonify({"errors": errors, "success": success})
|
||||
|
||||
|
||||
def create_singular(
|
||||
def _create_singular(
|
||||
data: dict,
|
||||
etud: Identite,
|
||||
) -> tuple[int, object]:
|
||||
@ -309,7 +311,7 @@ def create_singular(
|
||||
etat = data.get("etat", None)
|
||||
if etat is None:
|
||||
errors.append("param 'etat': manquant")
|
||||
elif etat not in scu.ETATS_ASSIDUITE.keys():
|
||||
elif etat not in scu.ETATS_ASSIDUITE:
|
||||
errors.append("param 'etat': invalide")
|
||||
|
||||
data = change_etat(data, False)
|
||||
@ -329,7 +331,7 @@ def create_singular(
|
||||
errors.append("param 'date_fin': manquant")
|
||||
fin = scu.is_iso_formated(date_fin, convert=True)
|
||||
if fin is None:
|
||||
errors.append(f"param 'date_fin': format invalide")
|
||||
errors.append("param 'date_fin': format invalide")
|
||||
|
||||
# cas 4 : moduleimpl_id
|
||||
|
||||
@ -343,9 +345,9 @@ def create_singular(
|
||||
|
||||
# cas 5 : desc
|
||||
|
||||
desc:str = data.get("desc", None)
|
||||
desc: str = data.get("desc", None)
|
||||
|
||||
if errors != []:
|
||||
if errors:
|
||||
err: str = ", ".join(errors)
|
||||
return (404, err)
|
||||
|
||||
@ -358,6 +360,7 @@ def create_singular(
|
||||
etat=etat,
|
||||
etud=etud,
|
||||
moduleimpl=moduleimpl,
|
||||
description=desc,
|
||||
)
|
||||
|
||||
db.session.add(nouv_assiduite)
|
||||
@ -379,12 +382,24 @@ def create_singular(
|
||||
def delete():
|
||||
"""
|
||||
Suppression d'une assiduité à partir de son id
|
||||
|
||||
Forme des données envoyées :
|
||||
|
||||
[
|
||||
<assiduite_id:int>,
|
||||
...
|
||||
]
|
||||
|
||||
|
||||
"""
|
||||
assiduites: list[int] = request.get_json(force=True)
|
||||
assiduites_list: list[int] = request.get_json(force=True)
|
||||
if not isinstance(assiduites_list, list):
|
||||
return json_error(404, "Le contenu envoyé n'est pas une liste")
|
||||
|
||||
output = {"errors": {}, "success": {}}
|
||||
|
||||
for i, ass in enumerate(assiduites):
|
||||
code, msg = delete_singular(ass, db)
|
||||
for i, ass in enumerate(assiduites_list):
|
||||
code, msg = _delete_singular(ass, db)
|
||||
if code == 404:
|
||||
output["errors"][f"{i}"] = msg
|
||||
else:
|
||||
@ -393,11 +408,11 @@ def delete():
|
||||
return jsonify(output)
|
||||
|
||||
|
||||
def delete_singular(assiduite_id: int, db):
|
||||
assiduite: Assiduite = Assiduite.query.filter_by(id=assiduite_id).first()
|
||||
if assiduite is None:
|
||||
def _delete_singular(assiduite_id: int, database):
|
||||
assiduite_unique: Assiduite = Assiduite.query.filter_by(id=assiduite_id).first()
|
||||
if assiduite_unique is None:
|
||||
return (404, "Assiduite non existante")
|
||||
db.session.delete(assiduite)
|
||||
database.session.delete(assiduite_unique)
|
||||
return (200, "OK")
|
||||
|
||||
|
||||
@ -412,11 +427,14 @@ def edit(assiduite_id: int):
|
||||
Edition d'une assiduité à partir de son id
|
||||
La requête doit avoir un content type "application/json":
|
||||
{
|
||||
"etat": str,
|
||||
"moduleimpl_id": int
|
||||
"etat"?: str,
|
||||
"moduleimpl_id"?: int
|
||||
"desc"?: str
|
||||
}
|
||||
"""
|
||||
assiduite: Assiduite = Assiduite.query.filter_by(id=assiduite_id).first_or_404()
|
||||
assiduite_unique: Assiduite = Assiduite.query.filter_by(
|
||||
id=assiduite_id
|
||||
).first_or_404()
|
||||
errors: List[str] = []
|
||||
data = request.get_json(force=True)
|
||||
|
||||
@ -428,7 +446,7 @@ def edit(assiduite_id: int):
|
||||
if data.get("etat") is None:
|
||||
errors.append("param 'etat': invalide")
|
||||
else:
|
||||
assiduite.etat = data.get("etat")
|
||||
assiduite_unique.etat = data.get("etat")
|
||||
|
||||
# Cas 2 : Moduleimpl_id
|
||||
moduleimpl_id = data.get("moduleimpl_id", False)
|
||||
@ -441,18 +459,24 @@ def edit(assiduite_id: int):
|
||||
errors.append("param 'moduleimpl_id': invalide")
|
||||
else:
|
||||
if not moduleimpl.est_inscrit(
|
||||
Identite.query.filter_by(id=assiduite.etudid).first()
|
||||
Identite.query.filter_by(id=assiduite_unique.etudid).first()
|
||||
):
|
||||
errors.append("param 'moduleimpl_id': etud non inscrit")
|
||||
else:
|
||||
assiduite.moduleimpl_id = moduleimpl_id
|
||||
assiduite_unique.moduleimpl_id = moduleimpl_id
|
||||
else:
|
||||
assiduite.moduleimpl_id = moduleimpl_id
|
||||
if errors != []:
|
||||
assiduite_unique.moduleimpl_id = moduleimpl_id
|
||||
|
||||
# Cas 3 : desc
|
||||
desc = data.get("desc", False)
|
||||
if desc is not False:
|
||||
assiduite_unique.desc = desc
|
||||
|
||||
if errors:
|
||||
err: str = ", ".join(errors)
|
||||
return json_error(404, err)
|
||||
|
||||
db.session.add(assiduite)
|
||||
db.session.add(assiduite_unique)
|
||||
db.session.commit()
|
||||
return jsonify({"OK": True})
|
||||
|
||||
@ -467,104 +491,104 @@ def change_etat(data: dict, from_int: bool = True):
|
||||
return data
|
||||
|
||||
|
||||
def count_manager(request) -> tuple[str, dict]:
|
||||
def count_manager(requested) -> tuple[str, dict]:
|
||||
"""
|
||||
Retourne la/les métriques à utiliser ainsi que le filtre donnés en query de la requête
|
||||
"""
|
||||
filter: dict = {}
|
||||
filtered: dict = {}
|
||||
# cas 1 : etat assiduite
|
||||
etat = request.args.get("etat")
|
||||
etat = requested.args.get("etat")
|
||||
if etat is not None:
|
||||
filter["etat"] = etat
|
||||
filtered["etat"] = etat
|
||||
|
||||
# cas 2 : date de début
|
||||
deb = request.args.get("date_debut")
|
||||
deb = requested.args.get("date_debut")
|
||||
deb: datetime = scu.is_iso_formated(deb, True)
|
||||
if deb is not None:
|
||||
filter["date_debut"] = deb
|
||||
filtered["date_debut"] = deb
|
||||
|
||||
# cas 3 : date de fin
|
||||
fin = request.args.get("date_fin")
|
||||
fin = requested.args.get("date_fin")
|
||||
fin = scu.is_iso_formated(fin, True)
|
||||
|
||||
if fin is not None:
|
||||
filter["date_fin"] = fin
|
||||
filtered["date_fin"] = fin
|
||||
|
||||
# cas 4 : moduleimpl_id
|
||||
module = request.args.get("moduleimpl_id", False)
|
||||
module = requested.args.get("moduleimpl_id", False)
|
||||
try:
|
||||
if module is False:
|
||||
raise Exception
|
||||
raise ValueError
|
||||
if module != "":
|
||||
module = int(module)
|
||||
else:
|
||||
module = None
|
||||
except Exception:
|
||||
except ValueError:
|
||||
module = False
|
||||
|
||||
if module is not False:
|
||||
filter["moduleimpl_id"] = module
|
||||
filtered["moduleimpl_id"] = module
|
||||
|
||||
# cas 5 : formsemestre_id
|
||||
formsemestre_id = request.args.get("formsemestre_id")
|
||||
formsemestre_id = requested.args.get("formsemestre_id")
|
||||
|
||||
if formsemestre_id is not None:
|
||||
formsemestre: FormSemestre = None
|
||||
formsemestre_id = int(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first()
|
||||
filter["formsemestre"] = formsemestre
|
||||
filtered["formsemestre"] = formsemestre
|
||||
|
||||
# cas 6 : type
|
||||
metric = request.args.get("metric", "all")
|
||||
metric = requested.args.get("metric", "all")
|
||||
|
||||
return (metric, filter)
|
||||
return (metric, filtered)
|
||||
|
||||
|
||||
def filter_manager(request, assiduites):
|
||||
def filter_manager(requested, assiduites_query):
|
||||
"""
|
||||
Retourne les assiduites entrées filtrées en fonction de la request
|
||||
"""
|
||||
# cas 1 : etat assiduite
|
||||
etat = request.args.get("etat")
|
||||
etat = requested.args.get("etat")
|
||||
if etat is not None:
|
||||
assiduites = scass.filter_by_etat(assiduites, etat)
|
||||
assiduites_query = scass.filter_by_etat(assiduites_query, etat)
|
||||
|
||||
# cas 2 : date de début
|
||||
deb = request.args.get("date_debut")
|
||||
deb = requested.args.get("date_debut")
|
||||
deb: datetime = scu.is_iso_formated(deb, True)
|
||||
if deb is not None:
|
||||
|
||||
assiduites = scass.filter_by_date(assiduites, deb, sup=True)
|
||||
assiduites_query = scass.filter_by_date(assiduites_query, deb, sup=True)
|
||||
|
||||
# cas 3 : date de fin
|
||||
fin = request.args.get("date_fin")
|
||||
fin = requested.args.get("date_fin")
|
||||
fin = scu.is_iso_formated(fin, True)
|
||||
|
||||
if fin is not None:
|
||||
assiduites = scass.filter_by_date(assiduites, fin, sup=False)
|
||||
assiduites_query = scass.filter_by_date(assiduites_query, fin, sup=False)
|
||||
|
||||
# cas 4 : moduleimpl_id
|
||||
module = request.args.get("moduleimpl_id", False)
|
||||
module = requested.args.get("moduleimpl_id", False)
|
||||
try:
|
||||
if module is False:
|
||||
raise Exception
|
||||
raise ValueError
|
||||
if module != "":
|
||||
module = int(module)
|
||||
else:
|
||||
module = None
|
||||
except Exception:
|
||||
except ValueError:
|
||||
module = False
|
||||
|
||||
if module is not False:
|
||||
assiduites = scass.filter_by_module_impl(assiduites, module)
|
||||
assiduites_query = scass.filter_by_module_impl(assiduites_query, module)
|
||||
|
||||
# cas 5 : formsemestre_id
|
||||
formsemestre_id = request.args.get("formsemestre_id")
|
||||
formsemestre_id = requested.args.get("formsemestre_id")
|
||||
|
||||
if formsemestre_id is not None:
|
||||
formsemestre: FormSemestre = None
|
||||
formsemestre_id = int(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first()
|
||||
assiduites = scass.filter_by_formsemstre(assiduites, formsemestre)
|
||||
assiduites_query = scass.filter_by_formsemestre(assiduites_query, formsemestre)
|
||||
|
||||
return assiduites
|
||||
return assiduites_query
|
||||
|
@ -1,13 +1,14 @@
|
||||
# -*- coding: UTF-8 -*
|
||||
"""Gestion de l'assiduité (assiduités + justificatifs)
|
||||
"""
|
||||
from app import db
|
||||
from app.models import ModuleImpl, ModuleImplInscription
|
||||
from app.models.etudiants import Identite
|
||||
from app.scodoc.sco_utils import EtatAssiduite, localize_datetime, is_period_overlapping
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from datetime import datetime
|
||||
|
||||
from app import db
|
||||
from app.models import ModuleImpl
|
||||
from app.models.etudiants import Identite
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_utils import EtatAssiduite, is_period_overlapping, localize_datetime
|
||||
|
||||
|
||||
class Assiduite(db.Model):
|
||||
"""
|
||||
@ -43,6 +44,8 @@ class Assiduite(db.Model):
|
||||
|
||||
desc = db.Column(db.Text)
|
||||
|
||||
entry_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
data = {
|
||||
"assiduite_id": self.assiduite_id,
|
||||
@ -52,6 +55,7 @@ class Assiduite(db.Model):
|
||||
"date_fin": self.date_fin,
|
||||
"etat": self.etat,
|
||||
"desc": self.desc,
|
||||
"entry_date": self.entry_date,
|
||||
}
|
||||
return data
|
||||
|
||||
@ -136,16 +140,14 @@ class Justificatif(db.Model):
|
||||
)
|
||||
etat = db.Column(
|
||||
db.Integer,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
entry_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||
|
||||
raison = db.Column(db.Text())
|
||||
|
||||
"""
|
||||
Les justificatifs sont enregistrés dans
|
||||
<archivedir>/justificatifs/<dept_id>/<etudid>/<nom_fichier.extension>
|
||||
|
||||
d'après sco_archives.py#JustificatifArchiver
|
||||
"""
|
||||
# Archive_id -> sco_archives_justificatifs.py
|
||||
fichier = db.Column(db.Text())
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
@ -157,5 +159,6 @@ class Justificatif(db.Model):
|
||||
"etat": self.etat,
|
||||
"raison": self.raison,
|
||||
"fichier": self.fichier,
|
||||
"entry_date": self.entry_date,
|
||||
}
|
||||
return data
|
||||
|
@ -65,6 +65,10 @@ class Identite(db.Model):
|
||||
passive_deletes=True,
|
||||
)
|
||||
|
||||
# Relations avec les assiduites et les justificatifs
|
||||
assiduites = db.relationship("Assiduite", backref="etudiant", lazy="dynamic")
|
||||
justificatifs = db.relationship("Justificatif", backref="etudiant", lazy="dynamic")
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"<Etud {self.id}/{self.departement.acronym} {self.nom!r} {self.prenom!r}>"
|
||||
|
@ -1,27 +1,29 @@
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.formsemestre import FormSemestre
|
||||
from app.models.assiduites import Assiduite
|
||||
from datetime import date, datetime, time, timedelta
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from datetime import datetime, date, time, timedelta
|
||||
from app.models.assiduites import Assiduite
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
||||
|
||||
# TOTALK: Réfléchir sur le fractionnement d'une assiduite prolongée
|
||||
|
||||
|
||||
def get_assiduites_stats(
|
||||
assiduites: Assiduite, metric: str = "all", filter: dict[str, object] = {}
|
||||
assiduites: Assiduite, metric: str = "all", filtered: dict[str, object] = None
|
||||
) -> Assiduite:
|
||||
if filter != {}:
|
||||
for key in filter:
|
||||
|
||||
if filtered is not None:
|
||||
for key in filtered:
|
||||
if key == "etat":
|
||||
assiduites = filter_by_etat(assiduites, filter[key])
|
||||
assiduites = filter_by_etat(assiduites, filtered[key])
|
||||
elif key == "date_fin":
|
||||
assiduites = filter_by_date(assiduites, filter[key], sup=False)
|
||||
assiduites = filter_by_date(assiduites, filtered[key], sup=False)
|
||||
elif key == "date_debut":
|
||||
assiduites = filter_by_date(assiduites, filter[key], sup=True)
|
||||
assiduites = filter_by_date(assiduites, filtered[key], sup=True)
|
||||
elif key == "moduleimpl_id":
|
||||
assiduites = filter_by_module_impl(assiduites, filter[key])
|
||||
assiduites = filter_by_module_impl(assiduites, filtered[key])
|
||||
elif key == "formsemestre":
|
||||
assiduites = filter_by_formsemstre(assiduites, filter[key])
|
||||
assiduites = filter_by_formsemestre(assiduites, filtered[key])
|
||||
|
||||
count: dict = get_count(assiduites)
|
||||
|
||||
@ -29,10 +31,10 @@ def get_assiduites_stats(
|
||||
|
||||
output: dict = {}
|
||||
|
||||
for key in count:
|
||||
for key, val in count.items():
|
||||
if key in metrics:
|
||||
output[key] = count[key]
|
||||
return output if output != {} else count
|
||||
output[key] = val
|
||||
return output if output else count
|
||||
|
||||
|
||||
def get_count(assiduites: Assiduite) -> dict[str, int or float]:
|
||||
@ -48,9 +50,11 @@ def get_count(assiduites: Assiduite) -> dict[str, int or float]:
|
||||
current_day: date = None
|
||||
current_time: str = None
|
||||
|
||||
MIDNIGHT: time = time(hour=0)
|
||||
NOON: time = time(hour=12)
|
||||
time_check = lambda d: (MIDNIGHT <= d.time() <= NOON)
|
||||
midnight: time = time(hour=0)
|
||||
noon: time = time(hour=12)
|
||||
|
||||
def time_check(dtime):
|
||||
return midnight <= dtime.time() <= noon
|
||||
|
||||
for ass in all_assiduites:
|
||||
delta: timedelta = ass.date_fin - ass.date_debut
|
||||
@ -82,7 +86,7 @@ def filter_by_etat(assiduites: Assiduite, etat: str) -> Assiduite:
|
||||
|
||||
|
||||
def filter_by_date(
|
||||
assiduites: Assiduite, date: datetime, sup: bool = True
|
||||
assiduites: Assiduite, date_: datetime, sup: bool = True
|
||||
) -> Assiduite:
|
||||
"""
|
||||
Filtrage d'une collection d'assiduites en fonction d'une date
|
||||
@ -91,15 +95,15 @@ def filter_by_date(
|
||||
Sup == False -> les assiduites doivent finir avant 'date'
|
||||
"""
|
||||
|
||||
if date.tzinfo is None:
|
||||
if date_.tzinfo is None:
|
||||
first_assiduite: Assiduite = assiduites.first()
|
||||
if first_assiduite is not None:
|
||||
date: datetime = date.replace(tzinfo=first_assiduite.date_debut.tzinfo)
|
||||
date_: datetime = date_.replace(tzinfo=first_assiduite.date_debut.tzinfo)
|
||||
|
||||
if sup:
|
||||
return assiduites.filter(Assiduite.date_debut >= date)
|
||||
else:
|
||||
return assiduites.filter(Assiduite.date_fin <= date)
|
||||
return assiduites.filter(Assiduite.date_debut >= date_)
|
||||
|
||||
return assiduites.filter(Assiduite.date_fin <= date_)
|
||||
|
||||
|
||||
def filter_by_module_impl(
|
||||
@ -111,18 +115,24 @@ def filter_by_module_impl(
|
||||
return assiduites.filter(Assiduite.moduleimpl_id == module_impl_id)
|
||||
|
||||
|
||||
def filter_by_formsemstre(assiduites: Assiduite, formsemestre: FormSemestre):
|
||||
def filter_by_formsemestre(assiduites_query: Assiduite, formsemestre: FormSemestre):
|
||||
"""
|
||||
Filtrage d'une collection d'assiduites en fonction d'un formsemestre
|
||||
"""
|
||||
|
||||
if formsemestre is None:
|
||||
return assiduites.filter(False)
|
||||
return assiduites_query.filter(False)
|
||||
|
||||
assiduites = assiduites.filter(
|
||||
Identite.query.filter_by(id=Assiduite.etudid).first()
|
||||
in formsemestre.etuds.all()
|
||||
assiduites_query = (
|
||||
assiduites_query.join(Identite, Assiduite.etudid == Identite.id)
|
||||
.join(
|
||||
FormSemestreInscription,
|
||||
Identite.id == FormSemestreInscription.etudid,
|
||||
)
|
||||
.filter(FormSemestreInscription.formsemestre_id == formsemestre.id)
|
||||
)
|
||||
|
||||
assiduites = assiduites.filter(Assiduite.date_debut >= formsemestre.date_debut)
|
||||
return assiduites.filter(Assiduite.date_fin <= formsemestre.date_fin)
|
||||
assiduites_query = assiduites_query.filter(
|
||||
Assiduite.date_debut >= formsemestre.date_debut
|
||||
)
|
||||
return assiduites_query.filter(Assiduite.date_fin <= formsemestre.date_fin)
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""Modèle Assiduites et Justificatifs
|
||||
"""Modeles assiduites et justificatifs
|
||||
|
||||
Revision ID: 943eb2deb22e
|
||||
Revises: 25e3ca6cc063
|
||||
Create Date: 2023-01-30 14:08:47.214916
|
||||
Revision ID: 961b2f2c595d
|
||||
Revises: 5c7b208355df
|
||||
Create Date: 2023-01-31 15:37:02.961533
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
@ -10,8 +10,8 @@ import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '943eb2deb22e'
|
||||
down_revision = '25e3ca6cc063'
|
||||
revision = '961b2f2c595d'
|
||||
down_revision = '5c7b208355df'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
@ -23,7 +23,8 @@ def upgrade():
|
||||
sa.Column('date_debut', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
|
||||
sa.Column('date_fin', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
|
||||
sa.Column('etudid', sa.Integer(), nullable=False),
|
||||
sa.Column('etat', sa.Integer(), nullable=True),
|
||||
sa.Column('etat', sa.Integer(), nullable=False),
|
||||
sa.Column('entry_date', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('raison', sa.Text(), nullable=True),
|
||||
sa.Column('fichier', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['etudid'], ['identite.id'], ondelete='CASCADE'),
|
||||
@ -38,16 +39,27 @@ def upgrade():
|
||||
sa.Column('etudid', sa.Integer(), nullable=False),
|
||||
sa.Column('etat', sa.Integer(), nullable=False),
|
||||
sa.Column('desc', sa.Text(), nullable=True),
|
||||
sa.Column('entry_date', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['etudid'], ['identite.id'], ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['moduleimpl_id'], ['notes_moduleimpl.id'], ondelete='SET NULL'),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_assiduites_etudid'), 'assiduites', ['etudid'], unique=False)
|
||||
op.drop_constraint('dispenseUE_formsemestre_id_ue_id_etudid_key', 'dispenseUE', type_='unique')
|
||||
op.drop_index('ix_dispenseUE_formsemestre_id', table_name='dispenseUE')
|
||||
op.create_unique_constraint(None, 'dispenseUE', ['ue_id', 'etudid'])
|
||||
op.drop_constraint('dispenseUE_formsemestre_id_fkey', 'dispenseUE', type_='foreignkey')
|
||||
op.drop_column('dispenseUE', 'formsemestre_id')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('dispenseUE', sa.Column('formsemestre_id', sa.INTEGER(), autoincrement=False, nullable=True))
|
||||
op.create_foreign_key('dispenseUE_formsemestre_id_fkey', 'dispenseUE', 'notes_formsemestre', ['formsemestre_id'], ['id'])
|
||||
op.drop_constraint(None, 'dispenseUE', type_='unique')
|
||||
op.create_index('ix_dispenseUE_formsemestre_id', 'dispenseUE', ['formsemestre_id'], unique=False)
|
||||
op.create_unique_constraint('dispenseUE_formsemestre_id_ue_id_etudid_key', 'dispenseUE', ['formsemestre_id', 'ue_id', 'etudid'])
|
||||
op.drop_index(op.f('ix_assiduites_etudid'), table_name='assiduites')
|
||||
op.drop_table('assiduites')
|
||||
op.drop_index(op.f('ix_justificatifs_etudid'), table_name='justificatifs')
|
@ -5,9 +5,10 @@ Ecrit par HARTMANN Matthias
|
||||
|
||||
"""
|
||||
|
||||
from tests.api.setup_test_api import GET, POST_JSON, api_headers, APIError
|
||||
from random import randint
|
||||
|
||||
from tests.api.setup_test_api import GET, POST_JSON, APIError, api_headers
|
||||
|
||||
ETUDID = 1
|
||||
FAUX = 42069
|
||||
FORMSEMESTREID = 1
|
||||
@ -22,6 +23,7 @@ ASSIDUITES_FIELDS = {
|
||||
"date_fin": str,
|
||||
"etat": str,
|
||||
"desc": str,
|
||||
"entry_date": str,
|
||||
}
|
||||
|
||||
CREATE_FIELD = {"assiduite_id": int}
|
||||
@ -32,7 +34,9 @@ COUNT_FIELDS = {"compte": int, "journee": int, "demi": int, "heure": float}
|
||||
TO_REMOVE = []
|
||||
|
||||
|
||||
def check_fields(data, fields=ASSIDUITES_FIELDS):
|
||||
def check_fields(data, fields: dict = None):
|
||||
if fields is None:
|
||||
fields = ASSIDUITES_FIELDS
|
||||
assert set(data.keys()) == set(fields.keys())
|
||||
for key in data:
|
||||
if key in ("moduleimpl_id", "desc"):
|
||||
@ -43,7 +47,7 @@ def check_fields(data, fields=ASSIDUITES_FIELDS):
|
||||
|
||||
def check_failure_get(path, headers, err=None):
|
||||
try:
|
||||
data = GET(path=path, headers=headers)
|
||||
GET(path=path, headers=headers)
|
||||
# ^ Renvoi un 404
|
||||
except APIError as api_err:
|
||||
if err is not None:
|
||||
@ -297,13 +301,13 @@ def test_route_delete(api_headers):
|
||||
# Bon fonctionnement
|
||||
data = TO_REMOVE[0]
|
||||
|
||||
res = POST_JSON(f"/assiduite/delete", [data], api_headers)
|
||||
res = POST_JSON("/assiduite/delete", [data], api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
for dat in res["success"]:
|
||||
assert res["success"][dat] == {"OK": True}
|
||||
|
||||
# Mauvais fonctionnement
|
||||
res = POST_JSON(f"/assiduite/delete", [data], api_headers)
|
||||
res = POST_JSON("/assiduite/delete", [data], api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
assert len(res["errors"]) == 1
|
||||
|
||||
@ -313,7 +317,7 @@ def test_route_delete(api_headers):
|
||||
|
||||
data = TO_REMOVE[1:]
|
||||
|
||||
res = POST_JSON(f"/assiduite/delete", data, api_headers)
|
||||
res = POST_JSON("/assiduite/delete", data, api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
for dat in res["success"]:
|
||||
assert res["success"][dat] == {"OK": True}
|
||||
@ -326,7 +330,7 @@ def test_route_delete(api_headers):
|
||||
FAUX + 2,
|
||||
]
|
||||
|
||||
res = POST_JSON(f"/assiduite/delete", data2, api_headers)
|
||||
res = POST_JSON("/assiduite/delete", data2, api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
assert len(res["errors"]) == 3
|
||||
|
||||
|
@ -59,6 +59,7 @@ def test_permissions(api_headers):
|
||||
"role_name": "Ens",
|
||||
"uid": 1,
|
||||
"version": "long",
|
||||
"assiduite_id": 1,
|
||||
}
|
||||
for rule in api_rules:
|
||||
path = rule.build(args)[1]
|
||||
|
@ -20,37 +20,39 @@ import app.scodoc.sco_utils as scu
|
||||
|
||||
|
||||
def test_general(test_client):
|
||||
""" """
|
||||
"""tests général du modèle assiduite"""
|
||||
|
||||
G = sco_fake_gen.ScoFake(verbose=False)
|
||||
g_fake = sco_fake_gen.ScoFake(verbose=False)
|
||||
|
||||
# Création d'une formation (1)
|
||||
|
||||
formation_id = G.create_formation()
|
||||
ue_id = G.create_ue(formation_id=formation_id, acronyme="T1", titre="UE TEST 1")
|
||||
matiere_id = G.create_matiere(ue_id=ue_id, titre="test matière")
|
||||
module_id_1 = G.create_module(
|
||||
formation_id = g_fake.create_formation()
|
||||
ue_id = g_fake.create_ue(
|
||||
formation_id=formation_id, acronyme="T1", titre="UE TEST 1"
|
||||
)
|
||||
matiere_id = g_fake.create_matiere(ue_id=ue_id, titre="test matière")
|
||||
module_id_1 = g_fake.create_module(
|
||||
matiere_id=matiere_id, code="Mo1", coefficient=1.0, titre="test module"
|
||||
)
|
||||
module_id_2 = G.create_module(
|
||||
module_id_2 = g_fake.create_module(
|
||||
matiere_id=matiere_id, code="Mo2", coefficient=1.0, titre="test module2"
|
||||
)
|
||||
|
||||
# Création semestre (2)
|
||||
|
||||
formsemestre_id_1 = G.create_formsemestre(
|
||||
formsemestre_id_1 = g_fake.create_formsemestre(
|
||||
formation_id=formation_id,
|
||||
semestre_id=1,
|
||||
date_debut="01/09/2022",
|
||||
date_fin="31/12/2022",
|
||||
)
|
||||
formsemestre_id_2 = G.create_formsemestre(
|
||||
formsemestre_id_2 = g_fake.create_formsemestre(
|
||||
formation_id=formation_id,
|
||||
semestre_id=2,
|
||||
date_debut="01/01/2023",
|
||||
date_fin="31/07/2023",
|
||||
)
|
||||
formsemestre_id_3 = G.create_formsemestre(
|
||||
formsemestre_id_3 = g_fake.create_formsemestre(
|
||||
formation_id=formation_id,
|
||||
semestre_id=3,
|
||||
date_debut="01/01/2024",
|
||||
@ -63,20 +65,20 @@ def test_general(test_client):
|
||||
|
||||
# Création des modulesimpls (4, 2 par semestre)
|
||||
|
||||
moduleimpl_1_1 = G.create_moduleimpl(
|
||||
moduleimpl_1_1 = g_fake.create_moduleimpl(
|
||||
module_id=module_id_1,
|
||||
formsemestre_id=formsemestre_id_1,
|
||||
)
|
||||
moduleimpl_1_2 = G.create_moduleimpl(
|
||||
moduleimpl_1_2 = g_fake.create_moduleimpl(
|
||||
module_id=module_id_2,
|
||||
formsemestre_id=formsemestre_id_1,
|
||||
)
|
||||
|
||||
moduleimpl_2_1 = G.create_moduleimpl(
|
||||
moduleimpl_2_1 = g_fake.create_moduleimpl(
|
||||
module_id=module_id_1,
|
||||
formsemestre_id=formsemestre_id_2,
|
||||
)
|
||||
moduleimpl_2_2 = G.create_moduleimpl(
|
||||
moduleimpl_2_2 = g_fake.create_moduleimpl(
|
||||
module_id=module_id_2,
|
||||
formsemestre_id=formsemestre_id_2,
|
||||
)
|
||||
@ -94,12 +96,14 @@ def test_general(test_client):
|
||||
|
||||
# Création des étudiants (3)
|
||||
|
||||
etuds_dict = [G.create_etud(code_nip=None, prenom=f"etud{i}") for i in range(3)]
|
||||
etuds_dict = [
|
||||
g_fake.create_etud(code_nip=None, prenom=f"etud{i}") for i in range(3)
|
||||
]
|
||||
|
||||
etuds = []
|
||||
for etud in etuds_dict:
|
||||
G.inscrit_etudiant(formsemestre_id=formsemestre_id_1, etud=etud)
|
||||
G.inscrit_etudiant(formsemestre_id=formsemestre_id_2, etud=etud)
|
||||
g_fake.inscrit_etudiant(formsemestre_id=formsemestre_id_1, etud=etud)
|
||||
g_fake.inscrit_etudiant(formsemestre_id=formsemestre_id_2, etud=etud)
|
||||
|
||||
etuds.append(Identite.query.filter_by(id=etud["id"]).first())
|
||||
|
||||
@ -107,7 +111,7 @@ def test_general(test_client):
|
||||
|
||||
# Etudiant faux
|
||||
|
||||
etud_faux_dict = G.create_etud(code_nip=None, prenom="etudfaux")
|
||||
etud_faux_dict = g_fake.create_etud(code_nip=None, prenom="etudfaux")
|
||||
etud_faux = Identite.query.filter_by(id=etud_faux_dict["id"]).first()
|
||||
|
||||
ajouter_assiduites(etuds, moduleimpls, etud_faux)
|
||||
@ -224,7 +228,7 @@ def ajouter_assiduites(
|
||||
|
||||
# Vérification de la création des assiduités
|
||||
assert [
|
||||
ass for ass in assiduites if type(ass) != Assiduite
|
||||
ass for ass in assiduites if not isinstance(ass, Assiduite)
|
||||
] == [], "La création des assiduités de base n'est pas OK"
|
||||
|
||||
# Vérification de la gestion des erreurs
|
||||
@ -333,13 +337,13 @@ def verifier_comptage_et_filtrage(
|
||||
FormSemestre.query.filter_by(id=fms["id"]).first() for fms in formsemestres
|
||||
]
|
||||
assert (
|
||||
scass.filter_by_formsemstre(etu1.assiduites, formsemestres[0]).count() == 3
|
||||
scass.filter_by_formsemestre(etu1.assiduites, formsemestres[0]).count() == 3
|
||||
), "Filtrage 'Formsemestre' mauvais"
|
||||
assert (
|
||||
scass.filter_by_formsemstre(etu1.assiduites, formsemestres[1]).count() == 3
|
||||
scass.filter_by_formsemestre(etu1.assiduites, formsemestres[1]).count() == 3
|
||||
), "Filtrage 'Formsemestre' mauvais"
|
||||
assert (
|
||||
scass.filter_by_formsemstre(etu1.assiduites, formsemestres[2]).count() == 0
|
||||
scass.filter_by_formsemestre(etu1.assiduites, formsemestres[2]).count() == 0
|
||||
), "Filtrage 'Formsemestre' mauvais"
|
||||
|
||||
# Date début
|
||||
|
Loading…
Reference in New Issue
Block a user