diff --git a/app/api/partitions.py b/app/api/partitions.py index 64ed136cc7..516fc41777 100644 --- a/app/api/partitions.py +++ b/app/api/partitions.py @@ -303,15 +303,19 @@ def group_create(partition_id: int): # partition-group-create return json_error(403, "partition non editable") if not partition.formsemestre.can_change_groups(): return json_error(401, "opération non autorisée") - data = request.get_json(force=True) # may raise 400 Bad Request - group_name = data.get("group_name") - if group_name is None: - return json_error(API_CLIENT_ERROR, "missing group name or invalid data format") - if not GroupDescr.check_name(partition, group_name): - return json_error(API_CLIENT_ERROR, "invalid group_name") - group_name = group_name.strip() - group = GroupDescr(group_name=group_name, partition_id=partition_id) + args = request.get_json(force=True) # may raise 400 Bad Request + group_name = args.get("group_name") + if not isinstance(group_name, str): + return json_error(API_CLIENT_ERROR, "missing group name or invalid data format") + args["group_name"] = args["group_name"].strip() + if not GroupDescr.check_name(partition, args["group_name"]): + return json_error(API_CLIENT_ERROR, "invalid group_name") + args["partition_id"] = partition_id + try: + group = GroupDescr(**args) + except TypeError: + return json_error(API_CLIENT_ERROR, "invalid arguments") db.session.add(group) db.session.commit() log(f"created group {group}") @@ -369,16 +373,22 @@ def group_edit(group_id: int): return json_error(403, "partition non editable") if not group.partition.formsemestre.can_change_groups(): return json_error(401, "opération non autorisée") - data = request.get_json(force=True) # may raise 400 Bad Request - group_name = data.get("group_name") - if group_name is not None: - group_name = group_name.strip() - if not GroupDescr.check_name(group.partition, group_name, existing=True): + + args = request.get_json(force=True) # may raise 400 Bad Request + if "group_name" in args: + if not isinstance(args["group_name"], str): + return json_error(API_CLIENT_ERROR, "invalid data format for group_name") + args["group_name"] = args["group_name"].strip() if args["group_name"] else "" + if not GroupDescr.check_name( + group.partition, args["group_name"], existing=True + ): return json_error(API_CLIENT_ERROR, "invalid group_name") - group.group_name = group_name - db.session.add(group) - db.session.commit() - log(f"modified {group}") + + group.from_dict(args) + db.session.add(group) + db.session.commit() + log(f"modified {group}") + app.set_sco_dept(group.partition.formsemestre.departement.acronym) sco_cache.invalidate_formsemestre(group.partition.formsemestre_id) return group.to_dict(with_partition=True) diff --git a/app/models/__init__.py b/app/models/__init__.py index 76967ed429..ababbdbcd7 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -53,8 +53,9 @@ class ScoDocModel: @classmethod def filter_model_attributes(cls, data: dict, excluded: set[str] = None) -> dict: """Returns a copy of dict with only the keys belonging to the Model and not in excluded. - By default, excluded == { 'id' }""" - excluded = {"id"} if excluded is None else set() + Add 'id' to excluded.""" + excluded = excluded or set() + excluded.add("id") # always exclude id # Les attributs du modèle qui sont des variables: (élimine les __ et les alias comme adm_id) my_attributes = [ a diff --git a/app/models/groups.py b/app/models/groups.py index 72a54acf6f..8b7ed5690d 100644 --- a/app/models/groups.py +++ b/app/models/groups.py @@ -11,14 +11,14 @@ from operator import attrgetter from sqlalchemy.exc import IntegrityError from app import db, log -from app.models import Scolog, GROUPNAME_STR_LEN, SHORT_STR_LEN +from app.models import ScoDocModel, Scolog, GROUPNAME_STR_LEN, SHORT_STR_LEN from app.models.etudiants import Identite from app.scodoc import sco_cache from app.scodoc import sco_utils as scu from app.scodoc.sco_exceptions import AccessDenied, ScoValueError -class Partition(db.Model): +class Partition(db.Model, ScoDocModel): """Partition: découpage d'une promotion en groupes""" __table_args__ = (db.UniqueConstraint("formsemestre_id", "partition_name"),) @@ -204,7 +204,7 @@ class Partition(db.Model): return group -class GroupDescr(db.Model): +class GroupDescr(db.Model, ScoDocModel): """Description d'un groupe d'une partition""" __tablename__ = "group_descr" diff --git a/app/templates/scolar/partition_editor.j2 b/app/templates/scolar/partition_editor.j2 index 534e0347f0..b524a6fb92 100644 --- a/app/templates/scolar/partition_editor.j2 +++ b/app/templates/scolar/partition_editor.j2 @@ -617,7 +617,7 @@ listeGroupesAutoaffectation(); }) .catch(error => { - document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données.

"; + document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données (1).

"; }) } @@ -665,13 +665,13 @@ document.querySelector(`#zoneGroupes .partition[data-idpartition="${idPartition}"]`).innerHTML += templateGroupe_zoneGroupes(r.id, name); // Lancement de l'édition du nom - divGroupe.querySelector(".modif").click(); + // divGroupe.querySelector(".modif").click(); listeGroupesAutoaffectation(); }) .catch(error => { - document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données.

"; - }) + document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données (4).

"; + }); } /********************/ @@ -746,12 +746,12 @@ .then(r => { return r.json() }) .then(r => { if (!r) { - document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données.

"; + document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données (2).

"; } listeGroupesAutoaffectation(); }) .catch(error => { - document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données.

"; + document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données (3).

"; }) } @@ -802,7 +802,7 @@ .then(r => { return r.json() }) .then(r => { if (r.OK != true) { - document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données.

"; + document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données (5).

"; } listeGroupesAutoaffectation(); }) @@ -916,12 +916,12 @@ .then(r => { return r.json() }) .then(r => { if (!r) { - document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données.

"; + document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données (6).

"; } listeGroupesAutoaffectation(); }) .catch(error => { - document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données.

"; + document.querySelector("main").innerHTML = "

Une erreur s'est produite lors de la sauvegarde des données (7).

"; }) } diff --git a/pytest.ini b/pytest.ini index e92885fe63..fd34473805 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,5 @@ [pytest] +norecursedirs = .git app/static markers = slow: marks tests as slow (deselect with '-m "not slow"') apo @@ -11,4 +12,4 @@ markers = filterwarnings = ignore:.*json.*:DeprecationWarning -# en attendant mise à jour de Flask-JSON \ No newline at end of file +# en attendant mise à jour de Flask-JSON diff --git a/tests/api/test_api_partitions.py b/tests/api/test_api_partitions.py index 32fc039bfc..b1a149f529 100644 --- a/tests/api/test_api_partitions.py +++ b/tests/api/test_api_partitions.py @@ -90,6 +90,7 @@ def test_formsemestre_partition(api_headers): ) assert isinstance(group_r, dict) assert group_r["group_name"] == group_d["group_name"] + assert group_r["edt_id"] is None # --- Liste groupes de la partition partition = GET(f"/partition/{partition_r['id']}", headers=headers) assert isinstance(partition, dict) @@ -99,6 +100,26 @@ def test_formsemestre_partition(api_headers): group = partition["groups"][str(group_r["id"])] # nb: str car clés json en string assert group["group_name"] == group_d["group_name"] + # --- Ajout d'un groupe avec edt_id + group_d = {"group_name": "extra", "edt_id": "GEDT"} + group_r = POST_JSON( + f"/partition/{partition_r['id']}/group/create", + group_d, + headers=headers, + ) + assert group_r["edt_id"] == "GEDT" + # Edit edt_id + group_r = POST_JSON( + f"/group/{group_r['id']}/edit", + {"edt_id": "GEDT2"}, + headers=headers, + ) + assert group_r["edt_id"] == "GEDT2" + partition = GET(f"/partition/{partition_r['id']}", headers=headers) + group = partition["groups"][str(group_r["id"])] # nb: str car clés json en string + assert group["group_name"] == group_d["group_name"] + assert group["edt_id"] == "GEDT2" + # Place un étudiant dans le groupe etud = GET(f"/formsemestre/{formsemestre_id}/etudiants", headers=headers)[0] repl = POST_JSON(f"/group/{group['id']}/set_etudiant/{etud['id']}", headers=headers)