Ordre des groupes et partitions (API)

This commit is contained in:
Emmanuel Viennet 2022-07-24 22:04:37 +02:00
parent 936fe3d716
commit f16f344720
4 changed files with 86 additions and 20 deletions

View File

@ -7,12 +7,13 @@
"""
ScoDoc 9 API : partitions
"""
from flask import abort, jsonify, request
from flask import jsonify, request
import app
from app import db, log
from app.api import bp
from app.api.auth import permission_required_api
from app.api.errors import error_response
from app.models import FormSemestre, FormSemestreInscription, Identite
from app.models import GroupDescr, Partition
from app.models.groups import group_membership
@ -112,7 +113,7 @@ def etud_in_group_query(group_id: int):
"""Etudiants du groupe, filtrés par état"""
etat = request.args.get("etat")
if etat not in {scu.INSCRIT, scu.DEMISSION, scu.DEF}:
abort(404, "etat invalid")
return error_response(404, "etat: valeur invalide")
group = GroupDescr.query.get_or_404(group_id)
query = (
Identite.query.join(FormSemestreInscription)
@ -131,7 +132,7 @@ def set_etud_group(etudid: int, group_id: int):
etud = Identite.query.get_or_404(etudid)
group = GroupDescr.query.get_or_404(group_id)
if etud.id not in {e.id for e in group.partition.formsemestre.etuds}:
abort(404, "etud non inscrit au formsemestre du groupe")
return error_response(404, "etud non inscrit au formsemestre du groupe")
groups = (
GroupDescr.query.filter_by(partition_id=group.partition.id)
.join(group_membership)
@ -180,13 +181,13 @@ def group_create(partition_id: int):
"""
partition: Partition = Partition.query.get_or_404(partition_id)
if not partition.groups_editable:
abort(404, "partition non editable")
return error_response(404, "partition non editable")
data = request.get_json(force=True) # may raise 400 Bad Request
group_name = data.get("group_name")
if group_name is None:
abort(404, "missing group name or invalid data format")
return error_response(404, "missing group name or invalid data format")
if not GroupDescr.check_name(partition, group_name):
abort(404, "invalid group_name")
return error_response(404, "invalid group_name")
group_name = group_name.strip()
group = GroupDescr(group_name=group_name, partition_id=partition_id)
@ -204,7 +205,7 @@ def group_delete(group_id: int):
"""Suppression d'un groupe"""
group = GroupDescr.query.get_or_404(group_id)
if not group.partition.groups_editable:
abort(404, "partition non editable")
return error_response(404, "partition non editable")
formsemestre_id = group.partition.formsemestre_id
log(f"deleting {group}")
db.session.delete(group)
@ -220,12 +221,12 @@ def group_edit(group_id: int):
"""Edit a group"""
group: GroupDescr = GroupDescr.query.get_or_404(group_id)
if not group.partition.groups_editable:
abort(404, "partition non editable")
return error_response(404, "partition non editable")
data = request.get_json(force=True) # may raise 400 Bad Request
group_name = data.get("group_name")
if group_name is not None:
if not GroupDescr.check_name(group.partition, group_name, existing=True):
abort(404, "invalid group_name")
return error_response(404, "invalid group_name")
group.group_name = group_name.strip()
db.session.add(group)
db.session.commit()
@ -253,12 +254,12 @@ def partition_create(formsemestre_id: int):
data = request.get_json(force=True) # may raise 400 Bad Request
partition_name = data.get("partition_name")
if partition_name is None:
abort(404, "missing partition_name or invalid data format")
return error_response(404, "missing partition_name or invalid data format")
if not Partition.check_name(formsemestre, partition_name):
abort(404, "invalid partition_name")
return error_response(404, "invalid partition_name")
numero = data.get("numero", 0)
if not isinstance(numero, int):
abort(404, "invalid type for numero")
return error_response(404, "invalid type for numero")
args = {
"formsemestre_id": formsemestre_id,
"partition_name": partition_name.strip(),
@ -269,7 +270,7 @@ def partition_create(formsemestre_id: int):
boolean_field, False if boolean_field != "groups_editable" else True
)
if not isinstance(value, bool):
abort(404, f"invalid type for {boolean_field}")
return error_response(404, f"invalid type for {boolean_field}")
args[boolean_field] = value
partition = Partition(**args)
@ -281,6 +282,52 @@ def partition_create(formsemestre_id: int):
return jsonify(partition.to_dict(with_groups=True))
@bp.route("/formsemestre/<int:formsemestre_id>/partitions/order", methods=["POST"])
@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups)
def formsemestre_order_partitions(formsemestre_id: int):
"""Modifie l'ordre des partitions du formsemestre
JSON args: [partition_id1, partition_id2, ...]
"""
formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id)
partition_ids = request.get_json(force=True) # may raise 400 Bad Request
if not isinstance(partition_ids, int) and not all(
isinstance(x, int) for x in partition_ids
):
return error_response(
404,
message="paramètre liste des partitions invalide",
)
for p_id, numero in zip(partition_ids, range(len(partition_ids))):
p = Partition.query.get_or_404(p_id)
p.numero = numero
db.session.add(p)
db.session.commit()
return jsonify(formsemestre.to_dict())
@bp.route("/partition/<int:partition_id>/groups/order", methods=["POST"])
@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups)
def partition_order_groups(partition_id: int):
"""Modifie l'ordre des groupes de la partition
JSON args: [group_id1, group_id2, ...]
"""
partition = Partition.query.get_or_404(partition_id)
group_ids = request.get_json(force=True) # may raise 400 Bad Request
if not isinstance(group_ids, int) and not all(
isinstance(x, int) for x in group_ids
):
return error_response(
404,
message="paramètre liste de groupe invalide",
)
for group_id, numero in zip(group_ids, range(len(group_ids))):
group = GroupDescr.query.get_or_404(group_id)
group.numero = numero
db.session.add(group)
db.session.commit()
return jsonify(partition.to_dict(with_groups=True))
@bp.route("/partition/<int:partition_id>/edit", methods=["POST"])
@permission_required_api(Permission.ScoEtudChangeGroups, Permission.APIEditGroups)
def partition_edit(partition_id: int):
@ -304,14 +351,14 @@ def partition_edit(partition_id: int):
if not Partition.check_name(
partition.formsemestre, partition_name, existing=True
):
abort(404, "invalid partition_name")
return error_response(404, "invalid partition_name")
partition.partition_name = partition_name.strip()
modified = True
numero = data.get("numero")
if numero is not None and numero != partition.numero:
if not isinstance(numero, int):
abort(404, "invalid type for numero")
return error_response(404, "invalid type for numero")
partition.numero = numero
modified = True
@ -319,7 +366,7 @@ def partition_edit(partition_id: int):
value = data.get(boolean_field)
if value is not None and value != getattr(partition, boolean_field):
if not isinstance(value, bool):
abort(404, f"invalid type for {boolean_field}")
return error_response(404, f"invalid type for {boolean_field}")
setattr(partition, boolean_field, value)
modified = True
@ -345,7 +392,7 @@ def partition_delete(partition_id: int):
"""
partition = Partition.query.get_or_404(partition_id)
if not partition.partition_name:
abort(404, "ne peut pas supprimer la partition par défaut")
return error_response(404, "ne peut pas supprimer la partition par défaut")
is_parcours = partition.is_parcours()
formsemestre: FormSemestre = partition.formsemestre
log(f"deleting partition {partition}")

View File

@ -90,7 +90,7 @@ class Partition(db.Model):
d.pop("formsemestre", None)
if with_groups:
groups = sorted(self.groups, key=lambda g: g.group_name)
groups = sorted(self.groups, key=lambda g: (g.numero or 0, g.group_name))
# un dict et non plus une liste, pour JSON
d["groups"] = {
group.id: group.to_dict(with_partition=False) for group in groups
@ -109,6 +109,8 @@ class GroupDescr(db.Model):
partition_id = db.Column(db.Integer, db.ForeignKey("partition.id"))
# "A", "C2", ... (NULL for 'all'):
group_name = db.Column(db.String(GROUPNAME_STR_LEN))
# Numero = ordre de presentation)
numero = db.Column(db.Integer)
etuds = db.relationship(
"Identite",
@ -131,9 +133,12 @@ class GroupDescr(db.Model):
"id": self.id,
"partition_id": self.partition_id,
"name": self.group_name,
"numero": self.numero,
}
if with_partition:
d["partition"] = self.partition.to_dict(with_groups=False)
d["partition"] = sorted(
self.partition, key=lambda p: p.numero or 0
).to_dict(with_groups=False)
return d
@classmethod

View File

@ -87,7 +87,7 @@ partitionEditor = ndb.EditableTable(
)
groupEditor = ndb.EditableTable(
"group_descr", "group_id", ("group_id", "partition_id", "group_name")
"group_descr", "group_id", ("group_id", "partition_id", "group_name", "numero")
)
group_list = groupEditor.list

View File

@ -181,6 +181,20 @@ POST_JSON(
POST_JSON(f"/partition/{2379}/delete")
#
POST_JSON(
"/partition/2264/groups/order",
data=[5563, 5562, 5561, 5560, 5558, 5557, 5316, 5315],
)
POST_JSON(
"/formsemestre/1063/partitions/order",
data=[2264, 2263, 2265, 2266, 2267, 2372, 2378],
)
GET(f"/partition/2264")
# Recherche de formsemestres
sems = GET(f"/formsemestres/query?etape_apo=V1RT&annee_scolaire=2021")