forked from ScoDoc/DocScoDoc
WIP: API edition partitions
This commit is contained in:
parent
98cb7bae37
commit
b53958c777
@ -15,6 +15,7 @@ from app.api.auth import token_auth, token_permission_required
|
||||
from app.models import FormSemestre, FormSemestreInscription, Identite
|
||||
from app.models import GroupDescr, Partition
|
||||
from app.models.groups import group_membership
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
@ -145,6 +146,8 @@ 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")
|
||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||
group_name = data.get("group_name")
|
||||
if group_name is None:
|
||||
@ -156,6 +159,7 @@ def group_create(partition_id: int):
|
||||
group = GroupDescr(group_name=group_name, partition_id=partition_id)
|
||||
db.session.add(group)
|
||||
db.session.commit()
|
||||
sco_cache.invalidate_formsemestre(partition.formsemestre_id)
|
||||
return jsonify(group.to_dict(with_partition=True))
|
||||
|
||||
|
||||
@ -163,19 +167,25 @@ def group_create(partition_id: int):
|
||||
@token_auth.login_required
|
||||
@token_permission_required(Permission.APIEditGroups)
|
||||
def group_delete(group_id: int):
|
||||
"""Delete group"""
|
||||
"""Suppression d'un groupe"""
|
||||
group = GroupDescr.query.get_or_404(group_id)
|
||||
if not group.partition.groups_editable:
|
||||
abort(404, "partition non editable")
|
||||
formsemestre_id = group.partition.formsemestre_id
|
||||
db.session.delete(group)
|
||||
db.session.commit()
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id)
|
||||
return jsonify({"OK": 1})
|
||||
|
||||
|
||||
@bp.route("/group/<init:group_id>/edit", methods=["POST"])
|
||||
@bp.route("/group/<int:group_id>/edit", methods=["POST"])
|
||||
@token_auth.login_required
|
||||
@token_permission_required(Permission.APIEditGroups)
|
||||
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")
|
||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||
group_name = data.get("group_name")
|
||||
if group_name is not None:
|
||||
@ -184,4 +194,124 @@ def group_edit(group_id: int):
|
||||
group.group_name = group_name.strip()
|
||||
db.session.add(group)
|
||||
db.session.commit()
|
||||
sco_cache.invalidate_formsemestre(group.partition.formsemestre_id)
|
||||
return jsonify(group.to_dict(with_partition=True))
|
||||
|
||||
|
||||
@bp.route("/formsemestre/<int:formsemestre_id>/partition/create", methods=["POST"])
|
||||
@token_auth.login_required
|
||||
@token_permission_required(Permission.APIEditGroups)
|
||||
def partition_create(formsemestre_id: int):
|
||||
"""Création d'une partition dans un semestre
|
||||
|
||||
The request content type should be "application/json":
|
||||
{
|
||||
"partition_name": str,
|
||||
"numero":int,
|
||||
"bul_show_rank":bool,
|
||||
"show_in_lists":bool,
|
||||
"groups_editable":bool
|
||||
}
|
||||
"""
|
||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
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")
|
||||
if not Partition.check_name(formsemestre, partition_name):
|
||||
abort(404, "invalid partition_name")
|
||||
numero = data.get("numero", 0)
|
||||
if not isinstance(numero, int):
|
||||
abort(404, "invalid type for numero")
|
||||
args = {
|
||||
"formsemestre_id": formsemestre_id,
|
||||
"partition_name": partition_name.strip(),
|
||||
"numero": numero,
|
||||
}
|
||||
for boolean_field in ("bul_show_rank", "show_in_lists", "groups_editable"):
|
||||
value = data.get(
|
||||
boolean_field, False if boolean_field != "groups_editable" else True
|
||||
)
|
||||
if not isinstance(boolean_field, bool):
|
||||
abort(404, f"invalid type for {boolean_field}")
|
||||
args[boolean_field] = value
|
||||
|
||||
partition = Partition(**args)
|
||||
db.session.add(partition)
|
||||
db.session.commit()
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id)
|
||||
return jsonify(partition.to_dict(with_groups=True))
|
||||
|
||||
|
||||
@bp.route("/partition/<int:partition_id>/edit", methods=["POST"])
|
||||
@token_auth.login_required
|
||||
@token_permission_required(Permission.APIEditGroups)
|
||||
def partition_edit(partition_id: int):
|
||||
"""Modification d'une partition dans un semestre
|
||||
|
||||
The request content type should be "application/json"
|
||||
All fields are optional:
|
||||
{
|
||||
"partition_name": str,
|
||||
"numero":int,
|
||||
"bul_show_rank":bool,
|
||||
"show_in_lists":bool,
|
||||
"groups_editable":bool
|
||||
}
|
||||
"""
|
||||
partition = Partition.query.get_or_404(partition_id)
|
||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||
modified = False
|
||||
partition_name = data.get("partition_name")
|
||||
if partition_name is not None and partition_name != partition.partition_name:
|
||||
if not Partition.check_name(
|
||||
partition.formsemestre, partition_name, existing=True
|
||||
):
|
||||
abort(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")
|
||||
partition.numero = numero
|
||||
modified = True
|
||||
|
||||
for boolean_field in ("bul_show_rank", "show_in_lists", "groups_editable"):
|
||||
value = data.get(boolean_field)
|
||||
if value is not None and value != getattr(partition, boolean_field):
|
||||
if not isinstance(boolean_field, bool):
|
||||
abort(404, f"invalid type for {boolean_field}")
|
||||
setattr(partition, boolean_field, value)
|
||||
modified = True
|
||||
|
||||
if modified:
|
||||
db.session.add(partition)
|
||||
db.session.commit()
|
||||
sco_cache.invalidate_formsemestre(partition.formsemestre_id)
|
||||
|
||||
return jsonify(partition.to_dict(with_groups=True))
|
||||
|
||||
|
||||
@bp.route("/partition/<int:partition_id>/delete", methods=["POST"])
|
||||
@token_auth.login_required
|
||||
@token_permission_required(Permission.APIEditGroups)
|
||||
def partition_delete(partition_id: int):
|
||||
"""Suppression d'une partition (et de tous ses groupes).
|
||||
|
||||
Note 1: La partition par défaut (tous les étudiants du sem.) ne peut
|
||||
pas être supprimée.
|
||||
Note 2: Si la partition de parcours est supprimée, les étudiants
|
||||
sont désinscrits des parcours.
|
||||
"""
|
||||
partition = Partition.query.get_or_404(partition_id)
|
||||
if not partition.partition_name:
|
||||
abort(404, "ne peut pas supprimer la partition par défaut")
|
||||
is_parcours = partition.is_parcours()
|
||||
formsemestre: FormSemestre = partition.formsemestre
|
||||
db.session.delete(partition)
|
||||
sco_cache.invalidate_formsemestre(formsemestre.id)
|
||||
if is_parcours:
|
||||
formsemestre.update_inscriptions_parcours_from_groups()
|
||||
return jsonify({"OK": 1})
|
||||
|
@ -1,4 +1,9 @@
|
||||
# -*- coding: UTF-8 -*
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
"""ScoDoc models: formsemestre
|
||||
"""
|
||||
|
@ -1,12 +1,17 @@
|
||||
# -*- coding: UTF-8 -*
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
"""Groups & partitions
|
||||
"""ScoDoc models: Groups & partitions
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
from app import db
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.models import GROUPNAME_STR_LEN
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
class Partition(db.Model):
|
||||
@ -41,6 +46,7 @@ class Partition(db.Model):
|
||||
"GroupDescr",
|
||||
backref=db.backref("partition", lazy=True),
|
||||
lazy="dynamic",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@ -56,6 +62,27 @@ class Partition(db.Model):
|
||||
def __repr__(self):
|
||||
return f"""<{self.__class__.__name__} {self.id} "{self.partition_name or '(default)'}">"""
|
||||
|
||||
@classmethod
|
||||
def check_name(
|
||||
cls, formsemestre: "FormSemestre", partition_name: str, existing=False
|
||||
) -> bool:
|
||||
"""check if a partition named 'partition_name' can be created in the given formsemestre.
|
||||
If existing is True, allow a partition_name already existing in the formsemestre.
|
||||
"""
|
||||
if not isinstance(partition_name, str):
|
||||
return False
|
||||
if not len(partition_name.strip()) > 0:
|
||||
return False
|
||||
if (not existing) and (
|
||||
partition_name in [p.partition_name for p in formsemestre.partitions]
|
||||
):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_parcours(self) -> bool:
|
||||
"Vrai s'il s'agit de la partitoon de parcours"
|
||||
return self.partition_name == scu.PARTITION_PARCOURS
|
||||
|
||||
def to_dict(self, with_groups=False) -> dict:
|
||||
"""as a dict, with or without groups"""
|
||||
d = dict(self.__dict__)
|
||||
|
Loading…
Reference in New Issue
Block a user