forked from ScoDoc/ScoDoc
test api assiduite + correction problèmes
This commit is contained in:
parent
4df1bdda8e
commit
f96571f520
@ -188,33 +188,29 @@ def assiduites(etudid: int = None, with_query: bool = False):
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def assiduites_formsemestre(formsemestre_id: int = None, with_query: bool = False):
|
||||
if formsemestre_id is not None:
|
||||
formsemestre: FormSemestre = None
|
||||
formsemestre_id = int(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first()
|
||||
def assiduites_formsemestre(formsemestre_id: int, with_query: bool = False):
|
||||
formsemestre: FormSemestre = None
|
||||
formsemestre_id = int(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first()
|
||||
|
||||
if formsemestre is None:
|
||||
json_error(404, "le paramètre 'formsemestre_id' n'existe pas")
|
||||
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]
|
||||
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 = Assiduite.query.filter(Assiduite.etudid.in_(etuds_id))
|
||||
assiduites = scass.filter_by_formsemstre(assiduites, formsemestre)
|
||||
|
||||
if with_query:
|
||||
assiduites = filter_manager(request, assiduites)
|
||||
if with_query:
|
||||
assiduites = filter_manager(request, assiduites)
|
||||
|
||||
data_set: List[dict] = []
|
||||
for ass in assiduites.all():
|
||||
data = ass.to_dict()
|
||||
data_set.append(change_etat(data))
|
||||
data_set: List[dict] = []
|
||||
for ass in assiduites.all():
|
||||
data = ass.to_dict()
|
||||
data_set.append(change_etat(data))
|
||||
|
||||
return jsonify(data_set)
|
||||
|
||||
else:
|
||||
return json_error(404, "le paramètre 'formsemestre_id doit être renseigné'")
|
||||
return jsonify(data_set)
|
||||
|
||||
|
||||
@bp.route(
|
||||
@ -239,28 +235,24 @@ def assiduites_formsemestre(formsemestre_id: int = None, with_query: bool = Fals
|
||||
def count_assiduites_formsemestre(
|
||||
formsemestre_id: int = None, with_query: bool = False
|
||||
):
|
||||
if formsemestre_id is not None:
|
||||
formsemestre: FormSemestre = None
|
||||
formsemestre_id = int(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first()
|
||||
formsemestre: FormSemestre = None
|
||||
formsemestre_id = int(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first()
|
||||
|
||||
if formsemestre is None:
|
||||
json_error(404, "le paramètre 'formsemestre_id' n'existe pas")
|
||||
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]
|
||||
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)
|
||||
metric: str = "all"
|
||||
filter: dict = {}
|
||||
if with_query:
|
||||
metric, filter = count_manager(request)
|
||||
assiduites = Assiduite.query.filter(Assiduite.etudid.in_(etuds_id))
|
||||
assiduites = scass.filter_by_formsemstre(assiduites, formsemestre)
|
||||
metric: str = "all"
|
||||
filter: dict = {}
|
||||
if with_query:
|
||||
metric, filter = count_manager(request)
|
||||
|
||||
return jsonify(scass.get_assiduites_stats(assiduites, metric, filter))
|
||||
|
||||
else:
|
||||
return json_error(404, "le paramètre 'formsemestre_id doit être renseigné'")
|
||||
return jsonify(scass.get_assiduites_stats(assiduites, metric, filter))
|
||||
|
||||
|
||||
@bp.route("/assiduite/<int:etudid>/create", methods=["POST"], defaults={"batch": False})
|
||||
@ -274,7 +266,9 @@ def count_assiduites_formsemestre(
|
||||
"/assiduite/<int:etudid>/create/batch", methods=["POST"], defaults={"batch": True}
|
||||
)
|
||||
@scodoc
|
||||
@login_required
|
||||
@permission_required(Permission.ScoView)
|
||||
# @permission_required(Permission.ScoAssiduiteChange)
|
||||
def create(etudid: int = None, batch: bool = False):
|
||||
"""
|
||||
Création d'une assiduité pour l'étudiant (etudid)
|
||||
@ -402,30 +396,34 @@ def create_singular(
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoAssiduiteChange)
|
||||
@permission_required(Permission.ScoView)
|
||||
# @permission_required(Permission.ScoAssiduiteChange)
|
||||
def delete(batch: bool = False):
|
||||
"""
|
||||
Suppression d'une assiduité à partir de son id
|
||||
"""
|
||||
output = {}
|
||||
if batch:
|
||||
assiduites: list[int] = request.get_json(force=True).get("batch", [])
|
||||
output = {"errors": [], "success": []}
|
||||
output = {"errors": {}, "success": {}}
|
||||
|
||||
for ass in assiduites:
|
||||
for i, ass in enumerate(assiduites):
|
||||
code, msg = delete_singular(ass, db)
|
||||
if code == 404:
|
||||
output["errors"].append({ass: msg})
|
||||
output["errors"][f"{i}"] = msg
|
||||
else:
|
||||
output["success"].append({ass: msg})
|
||||
output["success"][f"{i}"] = {"OK": True}
|
||||
db.session.commit()
|
||||
return jsonify(output)
|
||||
|
||||
else:
|
||||
code, msg = delete_singular(
|
||||
request.get_json(force=True).get("assiduiteid", -1), db
|
||||
)
|
||||
output[code] = msg
|
||||
|
||||
db.session.commit()
|
||||
return jsonify(output)
|
||||
if code == 404:
|
||||
return json_error(code, msg)
|
||||
if code == 200:
|
||||
db.session.commit()
|
||||
return jsonify({"OK": True})
|
||||
|
||||
|
||||
def delete_singular(assiduite_id: int, db):
|
||||
@ -440,7 +438,8 @@ def delete_singular(assiduite_id: int, db):
|
||||
@api_web_bp.route("/assiduite/<int:assiduiteid>/edit", methods=["POST"])
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoAssiduiteChange)
|
||||
@permission_required(Permission.ScoView)
|
||||
# @permission_required(Permission.ScoAssiduiteChange)
|
||||
def edit(assiduiteid: int):
|
||||
"""
|
||||
Edition d'une assiduité à partir de son id
|
||||
@ -473,7 +472,7 @@ def edit(assiduiteid: int):
|
||||
if moduleimpl_id < 0 or not Assiduite.verif_moduleimpl(
|
||||
moduleimpl_id, assiduite.etudid
|
||||
):
|
||||
raise Exception
|
||||
errors.append("param 'moduleimpl_id': etud non inscrit")
|
||||
|
||||
assiduite.moduleimpl_id = moduleimpl_id
|
||||
except:
|
||||
|
@ -160,7 +160,10 @@ def localize_datetime(date: datetime.datetime or str) -> datetime.datetime:
|
||||
first_assiduite = Assiduite.query.first()
|
||||
if first_assiduite is not None:
|
||||
new_date = date.replace(tzinfo=first_assiduite.date_debut.tzinfo)
|
||||
|
||||
else:
|
||||
# TOTALK: Paramètre permettant d'avoir l'UTC par défaut
|
||||
tmp = is_iso_formated("2022-01-01T08:00:00+01:00", True)
|
||||
new_date = date.replace(tzinfo=tmp.tzinfo)
|
||||
return new_date
|
||||
|
||||
|
||||
|
330
tests/api/test_api_assiduites.py
Normal file
330
tests/api/test_api_assiduites.py
Normal file
@ -0,0 +1,330 @@
|
||||
"""
|
||||
Test de l'api Assiduité
|
||||
|
||||
Ecrit par HARTMANN Matthias
|
||||
|
||||
"""
|
||||
|
||||
from tests.api.setup_test_api import GET, POST_JSON, api_headers, APIError
|
||||
from random import randint
|
||||
|
||||
ETUDID = 1
|
||||
FAUX = 42069
|
||||
FORMSEMESTREID = 1
|
||||
MODULE = 1
|
||||
|
||||
|
||||
ASSIDUITES_FIELDS = {
|
||||
"assiduiteid": int,
|
||||
"etudid": int,
|
||||
"moduleimpl_id": int,
|
||||
"date_debut": str,
|
||||
"date_fin": str,
|
||||
"etat": str,
|
||||
}
|
||||
|
||||
CREATE_FIELD = {"assiduiteid": int}
|
||||
BATCH_FIELD = {"errors": dict, "success": dict}
|
||||
|
||||
COUNT_FIELDS = {"compte": int, "journee": int, "demi": int, "heure": float}
|
||||
|
||||
TO_REMOVE = []
|
||||
|
||||
|
||||
def check_fields(data, fields=ASSIDUITES_FIELDS):
|
||||
assert set(data.keys()) == set(fields.keys())
|
||||
for key in data:
|
||||
if key == "moduleimpl_id":
|
||||
assert isinstance(data[key], fields[key]) or data[key] is None
|
||||
else:
|
||||
assert isinstance(data[key], fields[key])
|
||||
|
||||
|
||||
def check_failure_get(path, headers, err=None):
|
||||
try:
|
||||
data = GET(path=path, headers=headers)
|
||||
# ^ Renvoi un 404
|
||||
except APIError as api_err:
|
||||
if err is not None:
|
||||
assert api_err.payload["message"] == err
|
||||
else:
|
||||
raise APIError("Le GET n'aurait pas du fonctionner")
|
||||
|
||||
|
||||
def check_failure_post(path, headers, data, err=None):
|
||||
try:
|
||||
data = POST_JSON(path=path, headers=headers, data=data)
|
||||
# ^ Renvoi un 404
|
||||
except APIError as api_err:
|
||||
if err is not None:
|
||||
assert api_err.payload["message"] == err
|
||||
else:
|
||||
raise APIError("Le GET n'aurait pas du fonctionner")
|
||||
|
||||
|
||||
def create_data(etat: str, day: str, module=None):
|
||||
data = {
|
||||
"date_debut": f"2022-01-{day}T08:00",
|
||||
"date_fin": f"2022-01-{day}T10:00",
|
||||
"etat": etat,
|
||||
}
|
||||
|
||||
if module is not None:
|
||||
data["moduleimpl_id"] = module
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def test_route_assiduite(api_headers):
|
||||
|
||||
# Bon fonctionnement == id connu
|
||||
data = GET(path="/assiduite/1", headers=api_headers)
|
||||
check_fields(data)
|
||||
|
||||
# Mauvais Fonctionnement == id inconnu
|
||||
|
||||
check_failure_get(
|
||||
f"/assiduite/{FAUX}",
|
||||
api_headers,
|
||||
"assiduité inexistante",
|
||||
)
|
||||
|
||||
|
||||
def test_route_count_assiduites(api_headers):
|
||||
|
||||
# Bon fonctionnement
|
||||
|
||||
data = GET(path=f"/assiduites/{ETUDID}/count", headers=api_headers)
|
||||
check_fields(data, COUNT_FIELDS)
|
||||
|
||||
metrics = {"heure", "compte"}
|
||||
data = GET(
|
||||
path=f"/assiduites/{ETUDID}/count/query?metric={','.join(metrics)}",
|
||||
headers=api_headers,
|
||||
)
|
||||
|
||||
assert set(data.keys()) == metrics
|
||||
|
||||
# Mauvais fonctionnement
|
||||
|
||||
check_failure_get(f"/assiduites/{FAUX}/count", api_headers)
|
||||
|
||||
|
||||
def test_route_assiduites(api_headers):
|
||||
|
||||
# Bon fonctionnement
|
||||
|
||||
data = GET(path=f"/assiduites/{ETUDID}", headers=api_headers)
|
||||
assert isinstance(data, list)
|
||||
for ass in data:
|
||||
check_fields(ass, ASSIDUITES_FIELDS)
|
||||
|
||||
data = GET(path=f"/assiduites/{ETUDID}/query?", headers=api_headers)
|
||||
assert isinstance(data, list)
|
||||
for ass in data:
|
||||
check_fields(ass, ASSIDUITES_FIELDS)
|
||||
|
||||
# Mauvais fonctionnement
|
||||
check_failure_get(f"/assiduites/{FAUX}", api_headers)
|
||||
check_failure_get(f"/assiduites/{FAUX}/query?", api_headers)
|
||||
|
||||
|
||||
def test_route_formsemestre_assiduites(api_headers):
|
||||
|
||||
# Bon fonctionnement
|
||||
|
||||
data = GET(path=f"/assiduites/formsemestre/{FORMSEMESTREID}", headers=api_headers)
|
||||
assert isinstance(data, list)
|
||||
for ass in data:
|
||||
check_fields(ass, ASSIDUITES_FIELDS)
|
||||
|
||||
data = GET(
|
||||
path=f"/assiduites/formsemestre/{FORMSEMESTREID}/query?", headers=api_headers
|
||||
)
|
||||
assert isinstance(data, list)
|
||||
for ass in data:
|
||||
check_fields(ass, ASSIDUITES_FIELDS)
|
||||
|
||||
# Mauvais fonctionnement
|
||||
check_failure_get(
|
||||
f"/assiduites/formsemestre/{FAUX}",
|
||||
api_headers,
|
||||
err="le paramètre 'formsemestre_id' n'existe pas",
|
||||
)
|
||||
check_failure_get(
|
||||
f"/assiduites/formsemestre/{FAUX}/query?",
|
||||
api_headers,
|
||||
err="le paramètre 'formsemestre_id' n'existe pas",
|
||||
)
|
||||
|
||||
|
||||
def test_route_count_formsemestre_assiduites(api_headers):
|
||||
|
||||
# Bon fonctionnement
|
||||
|
||||
data = GET(
|
||||
path=f"/assiduites/formsemestre/{FORMSEMESTREID}/count", headers=api_headers
|
||||
)
|
||||
check_fields(data, COUNT_FIELDS)
|
||||
metrics = {"heure", "compte"}
|
||||
data = GET(
|
||||
path=f"/assiduites/formsemestre/{FORMSEMESTREID}/count/query?metric={','.join(metrics)}",
|
||||
headers=api_headers,
|
||||
)
|
||||
assert set(data.keys()) == metrics
|
||||
|
||||
# Mauvais fonctionnement
|
||||
check_failure_get(
|
||||
f"/assiduites/formsemestre/{FAUX}/count",
|
||||
api_headers,
|
||||
err="le paramètre 'formsemestre_id' n'existe pas",
|
||||
)
|
||||
check_failure_get(
|
||||
f"/assiduites/formsemestre/{FAUX}/count/query?",
|
||||
api_headers,
|
||||
err="le paramètre 'formsemestre_id' n'existe pas",
|
||||
)
|
||||
|
||||
|
||||
def test_route_create(api_headers):
|
||||
|
||||
# -== Sans batch ==-
|
||||
|
||||
# Bon fonctionnement
|
||||
data = create_data("present", "01")
|
||||
|
||||
res = POST_JSON(f"/assiduite/{ETUDID}/create", data, api_headers)
|
||||
check_fields(res, CREATE_FIELD)
|
||||
TO_REMOVE.append(res["assiduiteid"])
|
||||
|
||||
data2 = create_data("absent", "02", MODULE)
|
||||
res = POST_JSON(f"/assiduite/{ETUDID}/create", data2, api_headers)
|
||||
check_fields(res, CREATE_FIELD)
|
||||
TO_REMOVE.append(res["assiduiteid"])
|
||||
|
||||
# Mauvais fonctionnement
|
||||
check_failure_post(f"/assiduite/{FAUX}/create", api_headers, data)
|
||||
check_failure_post(
|
||||
f"/assiduite/{ETUDID}/create",
|
||||
api_headers,
|
||||
data,
|
||||
err="La période sélectionnée est déjà couverte par une autre assiduite",
|
||||
)
|
||||
check_failure_post(
|
||||
f"/assiduite/{ETUDID}/create",
|
||||
api_headers,
|
||||
create_data("absent", "03", FAUX),
|
||||
err="L'étudiant ne participe pas au moduleimpl sélectionné",
|
||||
)
|
||||
|
||||
# -== Avec batch ==-
|
||||
|
||||
# Bon Fonctionnement
|
||||
|
||||
etats = ["present", "absent", "retard"]
|
||||
data = {
|
||||
"batch": [
|
||||
create_data(etats[d % 3], 10 + d, MODULE if d % 2 else None)
|
||||
for d in range(randint(3, 5))
|
||||
]
|
||||
}
|
||||
|
||||
res = POST_JSON(f"/assiduite/{ETUDID}/create/batch", data, api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
for dat in res["success"]:
|
||||
check_fields(res["success"][dat], CREATE_FIELD)
|
||||
TO_REMOVE.append(res["success"][dat]["assiduiteid"])
|
||||
|
||||
# Mauvais Fonctionnement
|
||||
|
||||
data2 = {
|
||||
"batch": [
|
||||
create_data("present", "01"),
|
||||
create_data("present", "25", FAUX),
|
||||
create_data("blabla", 26),
|
||||
create_data("absent", 32),
|
||||
]
|
||||
}
|
||||
|
||||
res = POST_JSON(f"/assiduite/{ETUDID}/create/batch", data2, api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
assert len(res["errors"]) == 4
|
||||
|
||||
assert (
|
||||
res["errors"]["0"]
|
||||
== "La période sélectionnée est déjà couverte par une autre assiduite"
|
||||
)
|
||||
assert res["errors"]["1"] == "L'étudiant ne participe pas au moduleimpl sélectionné"
|
||||
assert res["errors"]["2"] == "param 'etat': invalide"
|
||||
assert (
|
||||
res["errors"]["3"]
|
||||
== "param 'date_debut': format invalide, param 'date_fin': format invalide"
|
||||
)
|
||||
|
||||
|
||||
def test_route_edit(api_headers):
|
||||
|
||||
# Bon fonctionnement
|
||||
|
||||
data = {"etat": "retard", "moduleimpl_id": MODULE}
|
||||
res = POST_JSON(f"/assiduite/{TO_REMOVE[0]}/edit", data, api_headers)
|
||||
assert res == {"OK": True}
|
||||
|
||||
data["moduleimpl_id"] = None
|
||||
res = POST_JSON(f"/assiduite/{TO_REMOVE[1]}/edit", data, api_headers)
|
||||
assert res == {"OK": True}
|
||||
|
||||
# Mauvais fonctionnement
|
||||
|
||||
check_failure_post(f"/assiduite/{FAUX}/edit", api_headers, data)
|
||||
data["etat"] = "blabla"
|
||||
check_failure_post(
|
||||
f"/assiduite/{TO_REMOVE[2]}/edit",
|
||||
api_headers,
|
||||
data,
|
||||
err="param 'etat': invalide",
|
||||
)
|
||||
|
||||
|
||||
def test_route_delete(api_headers):
|
||||
# -== Sans batch ==-
|
||||
|
||||
# Bon fonctionnement
|
||||
data = {"assiduiteid": TO_REMOVE[0]}
|
||||
|
||||
res = POST_JSON(f"/assiduite/delete", data, api_headers)
|
||||
assert res == {"OK": True}
|
||||
|
||||
# Mauvais fonctionnement
|
||||
check_failure_post(
|
||||
f"/assiduite/delete",
|
||||
api_headers,
|
||||
{"assiduiteid": FAUX},
|
||||
err="Assiduite non existante",
|
||||
)
|
||||
# -== Avec batch ==-
|
||||
|
||||
# Bon Fonctionnement
|
||||
|
||||
data = {"batch": TO_REMOVE[1:]}
|
||||
|
||||
res = POST_JSON(f"/assiduite/delete/batch", data, api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
for dat in res["success"]:
|
||||
assert res["success"][dat] == {"OK": True}
|
||||
|
||||
# Mauvais Fonctionnement
|
||||
|
||||
data2 = {
|
||||
"batch": [
|
||||
FAUX,
|
||||
FAUX + 1,
|
||||
FAUX + 2,
|
||||
]
|
||||
}
|
||||
|
||||
res = POST_JSON(f"/assiduite/delete/batch", data2, api_headers)
|
||||
check_fields(res, BATCH_FIELD)
|
||||
assert len(res["errors"]) == 3
|
||||
|
||||
assert all([res["errors"][i] == "Assiduite non existante" for i in res["errors"]])
|
@ -21,6 +21,7 @@ from app import models
|
||||
from app.models import departements
|
||||
from app.models import (
|
||||
Absence,
|
||||
Assiduite,
|
||||
Departement,
|
||||
Formation,
|
||||
FormSemestre,
|
||||
@ -378,6 +379,36 @@ def create_logos():
|
||||
)
|
||||
|
||||
|
||||
def ajouter_assiduites(formsemestre: FormSemestre):
|
||||
"""
|
||||
Ajoute des assiduités semi-aléatoires à chaque étudiant du semestre
|
||||
"""
|
||||
MODS = [moduleimpl.id for moduleimpl in formsemestre.modimpls]
|
||||
MODS.append(None)
|
||||
from app.scodoc.sco_utils import localize_datetime
|
||||
|
||||
for etud in formsemestre.etuds:
|
||||
|
||||
base_date = datetime.datetime(2022, 9, random.randint(1, 30), 8, 0, 0)
|
||||
base_date = localize_datetime(base_date)
|
||||
|
||||
for i in range(random.randint(1, 5)):
|
||||
etat = random.randint(0, 2)
|
||||
module = random.choice(MODS)
|
||||
deb_date = base_date + datetime.timedelta(days=i)
|
||||
fin_date = deb_date + datetime.timedelta(hours=i)
|
||||
|
||||
code = Assiduite.create_assiduite(etud, deb_date, fin_date, etat, module)
|
||||
|
||||
assert isinstance(
|
||||
code, Assiduite
|
||||
), "Erreur dans la génération des assiduités"
|
||||
|
||||
db.session.add(code)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def init_test_database():
|
||||
"""Appelé par la commande `flask init-test-database`
|
||||
|
||||
@ -398,6 +429,7 @@ def init_test_database():
|
||||
saisie_notes_evaluations(formsemestre, user_lecteur)
|
||||
add_absences(formsemestre)
|
||||
create_etape_apo(formsemestre)
|
||||
ajouter_assiduites(formsemestre)
|
||||
create_logos()
|
||||
# à compléter
|
||||
# - groupes
|
||||
|
Loading…
Reference in New Issue
Block a user