Fix #578 API : Gestion semestre verrouillé. + tests unitaires API OK.
This commit is contained in:
parent
f3b2c6d4fe
commit
91e8c9185b
@ -171,6 +171,8 @@ def set_etud_group(etudid: int, group_id: int):
|
|||||||
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
)
|
)
|
||||||
group = query.first_or_404()
|
group = query.first_or_404()
|
||||||
|
if not group.partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
if etud.id not in {e.id for e in group.partition.formsemestre.etuds}:
|
if etud.id not in {e.id for e in group.partition.formsemestre.etuds}:
|
||||||
return json_error(404, "etud non inscrit au formsemestre du groupe")
|
return json_error(404, "etud non inscrit au formsemestre du groupe")
|
||||||
|
|
||||||
@ -197,6 +199,8 @@ def group_remove_etud(group_id: int, etudid: int):
|
|||||||
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
)
|
)
|
||||||
group = query.first_or_404()
|
group = query.first_or_404()
|
||||||
|
if not group.partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
if etud in group.etuds:
|
if etud in group.etuds:
|
||||||
group.etuds.remove(etud)
|
group.etuds.remove(etud)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -222,6 +226,8 @@ def partition_remove_etud(partition_id: int, etudid: int):
|
|||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
partition = query.first_or_404()
|
partition = query.first_or_404()
|
||||||
|
if not partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
groups = (
|
groups = (
|
||||||
GroupDescr.query.filter_by(partition_id=partition_id)
|
GroupDescr.query.filter_by(partition_id=partition_id)
|
||||||
.join(group_membership)
|
.join(group_membership)
|
||||||
@ -252,8 +258,10 @@ def group_create(partition_id: int):
|
|||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
partition: Partition = query.first_or_404()
|
partition: Partition = query.first_or_404()
|
||||||
|
if not partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
if not partition.groups_editable:
|
if not partition.groups_editable:
|
||||||
return json_error(404, "partition non editable")
|
return json_error(403, "partition non editable")
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
group_name = data.get("group_name")
|
group_name = data.get("group_name")
|
||||||
if group_name is None:
|
if group_name is None:
|
||||||
@ -284,8 +292,10 @@ def group_delete(group_id: int):
|
|||||||
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
)
|
)
|
||||||
group: GroupDescr = query.first_or_404()
|
group: GroupDescr = query.first_or_404()
|
||||||
|
if not group.partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
if not group.partition.groups_editable:
|
if not group.partition.groups_editable:
|
||||||
return json_error(404, "partition non editable")
|
return json_error(403, "partition non editable")
|
||||||
formsemestre_id = group.partition.formsemestre_id
|
formsemestre_id = group.partition.formsemestre_id
|
||||||
log(f"deleting {group}")
|
log(f"deleting {group}")
|
||||||
db.session.delete(group)
|
db.session.delete(group)
|
||||||
@ -308,8 +318,10 @@ def group_edit(group_id: int):
|
|||||||
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query.join(Partition).join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
)
|
)
|
||||||
group: GroupDescr = query.first_or_404()
|
group: GroupDescr = query.first_or_404()
|
||||||
|
if not group.partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
if not group.partition.groups_editable:
|
if not group.partition.groups_editable:
|
||||||
return json_error(404, "partition non editable")
|
return json_error(403, "partition non editable")
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
group_name = data.get("group_name")
|
group_name = data.get("group_name")
|
||||||
if group_name is not None:
|
if group_name is not None:
|
||||||
@ -348,6 +360,8 @@ def partition_create(formsemestre_id: int):
|
|||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
formsemestre: FormSemestre = query.first_or_404(formsemestre_id)
|
formsemestre: FormSemestre = query.first_or_404(formsemestre_id)
|
||||||
|
if not formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
partition_name = data.get("partition_name")
|
partition_name = data.get("partition_name")
|
||||||
if partition_name is None:
|
if partition_name is None:
|
||||||
@ -396,6 +410,8 @@ def formsemestre_order_partitions(formsemestre_id: int):
|
|||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
formsemestre: FormSemestre = query.first_or_404(formsemestre_id)
|
formsemestre: FormSemestre = query.first_or_404(formsemestre_id)
|
||||||
|
if not formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
partition_ids = request.get_json(force=True) # may raise 400 Bad Request
|
partition_ids = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
if not isinstance(partition_ids, int) and not all(
|
if not isinstance(partition_ids, int) and not all(
|
||||||
isinstance(x, int) for x in partition_ids
|
isinstance(x, int) for x in partition_ids
|
||||||
@ -433,6 +449,8 @@ def partition_order_groups(partition_id: int):
|
|||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
partition: Partition = query.first_or_404()
|
partition: Partition = query.first_or_404()
|
||||||
|
if not partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
group_ids = request.get_json(force=True) # may raise 400 Bad Request
|
group_ids = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
if not isinstance(group_ids, int) and not all(
|
if not isinstance(group_ids, int) and not all(
|
||||||
isinstance(x, int) for x in group_ids
|
isinstance(x, int) for x in group_ids
|
||||||
@ -474,6 +492,8 @@ def partition_edit(partition_id: int):
|
|||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
partition: Partition = query.first_or_404()
|
partition: Partition = query.first_or_404()
|
||||||
|
if not partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
modified = False
|
modified = False
|
||||||
partition_name = data.get("partition_name")
|
partition_name = data.get("partition_name")
|
||||||
@ -532,6 +552,8 @@ def partition_delete(partition_id: int):
|
|||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
partition: Partition = query.first_or_404()
|
partition: Partition = query.first_or_404()
|
||||||
|
if not partition.formsemestre.etat:
|
||||||
|
return json_error(403, "formsemestre verrouillé")
|
||||||
if not partition.partition_name:
|
if not partition.partition_name:
|
||||||
return json_error(404, "ne peut pas supprimer la partition par défaut")
|
return json_error(404, "ne peut pas supprimer la partition par défaut")
|
||||||
is_parcours = partition.is_parcours()
|
is_parcours = partition.is_parcours()
|
||||||
|
@ -63,51 +63,51 @@ class FormSemestre(db.Model):
|
|||||||
"False si verrouillé"
|
"False si verrouillé"
|
||||||
modalite = db.Column(
|
modalite = db.Column(
|
||||||
db.String(SHORT_STR_LEN), db.ForeignKey("notes_form_modalites.modalite")
|
db.String(SHORT_STR_LEN), db.ForeignKey("notes_form_modalites.modalite")
|
||||||
) # "FI", "FAP", "FC", ...
|
)
|
||||||
# gestion compensation sem DUT:
|
"Modalité de formation: 'FI', 'FAP', 'FC', ..."
|
||||||
gestion_compensation = db.Column(
|
gestion_compensation = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
# ne publie pas le bulletin XML ou JSON:
|
"gestion compensation sem DUT (inutilisé en APC)"
|
||||||
bul_hide_xml = db.Column(
|
bul_hide_xml = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
# Bloque le calcul des moyennes (générale et d'UE)
|
"ne publie pas le bulletin XML ou JSON"
|
||||||
block_moyennes = db.Column(
|
block_moyennes = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
# Bloque le calcul de la moyenne générale (utile pour BUT)
|
"Bloque le calcul des moyennes (générale et d'UE)"
|
||||||
block_moyenne_generale = db.Column(
|
block_moyenne_generale = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
"Si vrai, la moyenne générale indicative BUT n'est pas calculée"
|
"Si vrai, la moyenne générale indicative BUT n'est pas calculée"
|
||||||
# semestres decales (pour gestion jurys):
|
|
||||||
gestion_semestrielle = db.Column(
|
gestion_semestrielle = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
# couleur fond bulletins HTML:
|
"Semestres décalés (pour gestion jurys DUT, pas implémenté ou utile en BUT)"
|
||||||
bul_bgcolor = db.Column(
|
bul_bgcolor = db.Column(
|
||||||
db.String(SHORT_STR_LEN),
|
db.String(SHORT_STR_LEN),
|
||||||
default="white",
|
default="white",
|
||||||
server_default="white",
|
server_default="white",
|
||||||
nullable=False,
|
nullable=False,
|
||||||
)
|
)
|
||||||
# autorise resp. a modifier semestre:
|
"couleur fond bulletins HTML"
|
||||||
resp_can_edit = db.Column(
|
resp_can_edit = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
# autorise resp. a modifier slt les enseignants:
|
"autorise resp. à modifier le formsemestre"
|
||||||
resp_can_change_ens = db.Column(
|
resp_can_change_ens = db.Column(
|
||||||
db.Boolean(), nullable=False, default=True, server_default="true"
|
db.Boolean(), nullable=False, default=True, server_default="true"
|
||||||
)
|
)
|
||||||
# autorise les ens a creer des evals:
|
"autorise resp. a modifier slt les enseignants"
|
||||||
ens_can_edit_eval = db.Column(
|
ens_can_edit_eval = db.Column(
|
||||||
db.Boolean(), nullable=False, default=False, server_default="False"
|
db.Boolean(), nullable=False, default=False, server_default="False"
|
||||||
)
|
)
|
||||||
# code element semestre Apogee, eg 'VRTW1' ou 'V2INCS4,V2INLS4,...'
|
"autorise les enseignants à créer des évals dans leurs modimpls"
|
||||||
elt_sem_apo = db.Column(db.Text()) # peut être fort long !
|
elt_sem_apo = db.Column(db.Text()) # peut être fort long !
|
||||||
# code element annee Apogee, eg 'VRT1A' ou 'V2INLA,V2INCA,...'
|
"code element semestre Apogee, eg 'VRTW1' ou 'V2INCS4,V2INLS4,...'"
|
||||||
elt_annee_apo = db.Column(db.Text())
|
elt_annee_apo = db.Column(db.Text())
|
||||||
|
"code element annee Apogee, eg 'VRT1A' ou 'V2INLA,V2INCA,...'"
|
||||||
|
|
||||||
# Relations:
|
# Relations:
|
||||||
etapes = db.relationship(
|
etapes = db.relationship(
|
||||||
|
@ -4,4 +4,5 @@ markers =
|
|||||||
but_gb
|
but_gb
|
||||||
lemans
|
lemans
|
||||||
lyon
|
lyon
|
||||||
|
test_test
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.4.30"
|
SCOVERSION = "9.4.31"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ from app import models
|
|||||||
|
|
||||||
from app.auth.models import User, Role, UserRole
|
from app.auth.models import User, Role, UserRole
|
||||||
from app.entreprises.models import entreprises_reset_database
|
from app.entreprises.models import entreprises_reset_database
|
||||||
from app.models import departements
|
from app.models import Departement, departements
|
||||||
from app.models import Formation, UniteEns, Matiere, Module
|
from app.models import Formation, UniteEns, Matiere, Module
|
||||||
from app.models import FormSemestre, FormSemestreInscription
|
from app.models import FormSemestre, FormSemestreInscription
|
||||||
from app.models import GroupDescr
|
from app.models import GroupDescr
|
||||||
@ -73,6 +73,7 @@ def make_shell_context():
|
|||||||
"ctx": app.test_request_context(),
|
"ctx": app.test_request_context(),
|
||||||
"current_app": flask.current_app,
|
"current_app": flask.current_app,
|
||||||
"current_user": current_user,
|
"current_user": current_user,
|
||||||
|
"Departement": Departement,
|
||||||
"db": db,
|
"db": db,
|
||||||
"Evaluation": Evaluation,
|
"Evaluation": Evaluation,
|
||||||
"flask": flask,
|
"flask": flask,
|
||||||
|
@ -34,7 +34,11 @@ def test_list_users(api_admin_headers):
|
|||||||
|
|
||||||
# Tous les utilisateurs, vus par SuperAdmin:
|
# Tous les utilisateurs, vus par SuperAdmin:
|
||||||
users = GET("/users/query", headers=admin_h)
|
users = GET("/users/query", headers=admin_h)
|
||||||
|
assert len(users) > 2
|
||||||
|
# Les utilisateurs du dept. TAPI
|
||||||
|
users_TAPI = GET("/users/query?departement=TAPI", headers=admin_h)
|
||||||
|
nb_TAPI = len(users_TAPI)
|
||||||
|
assert nb_TAPI > 1
|
||||||
# Les utilisateurs de chaque département (+ ceux sans département)
|
# Les utilisateurs de chaque département (+ ceux sans département)
|
||||||
all_users = []
|
all_users = []
|
||||||
for acronym in [dept["acronym"] for dept in depts] + [""]:
|
for acronym in [dept["acronym"] for dept in depts] + [""]:
|
||||||
@ -59,9 +63,8 @@ def test_list_users(api_admin_headers):
|
|||||||
for i, u in enumerate(u for u in u_users if u["dept"] != "TAPI"):
|
for i, u in enumerate(u for u in u_users if u["dept"] != "TAPI"):
|
||||||
headers = get_auth_headers(u["user_name"], "test")
|
headers = get_auth_headers(u["user_name"], "test")
|
||||||
users_by_u = GET("/users/query", headers=headers)
|
users_by_u = GET("/users/query", headers=headers)
|
||||||
assert len(users_by_u) == 4 + i
|
assert len(users_by_u) == nb_TAPI + 1 + i
|
||||||
# explication: tous ont le droit de voir les 3 users de TAPI
|
# explication: tous ont le droit de voir les users de TAPI
|
||||||
# (test, other et u_TAPI)
|
|
||||||
# plus l'utilisateur de chaque département jusqu'au leur
|
# plus l'utilisateur de chaque département jusqu'au leur
|
||||||
# (u_AA voit AA, u_BB voit AA et BB, etc)
|
# (u_AA voit AA, u_BB voit AA et BB, etc)
|
||||||
|
|
||||||
@ -90,6 +93,10 @@ def test_edit_users(api_admin_headers):
|
|||||||
)
|
)
|
||||||
assert user["dept"] == "TAPI"
|
assert user["dept"] == "TAPI"
|
||||||
assert user["active"] is False
|
assert user["active"] is False
|
||||||
|
user = GET(f"/user/{user['id']}", headers=admin_h)
|
||||||
|
assert user["nom"] == "Toto"
|
||||||
|
assert user["dept"] == "TAPI"
|
||||||
|
assert user["active"] is False
|
||||||
|
|
||||||
|
|
||||||
def test_roles(api_admin_headers):
|
def test_roles(api_admin_headers):
|
||||||
@ -229,3 +236,10 @@ def test_modif_users_depts(api_admin_headers):
|
|||||||
ok = True
|
ok = True
|
||||||
assert ok
|
assert ok
|
||||||
# Nettoyage:
|
# Nettoyage:
|
||||||
|
# on ne peut pas supprimer l'utilisateur lambda, mais on
|
||||||
|
# le rend inactif et on le retire de son département
|
||||||
|
u = POST_JSON(
|
||||||
|
f"/user/{u_lambda['id']}/edit",
|
||||||
|
{"active": False, "dept": None},
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
47
tests/api/test_test.py
Normal file
47
tests/api/test_test.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# -*- coding: UTF-8 -*
|
||||||
|
|
||||||
|
"""Unit tests for... tests
|
||||||
|
|
||||||
|
Ensure test DB is in the expected initial state.
|
||||||
|
|
||||||
|
Usage: pytest tests/unit/test_test.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from tests.api.setup_test_api import (
|
||||||
|
api_headers,
|
||||||
|
GET,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.test_test
|
||||||
|
def test_test_db(api_headers):
|
||||||
|
"""Check that we indeed have: 2 users, 1 dept, 3 formsemestres.
|
||||||
|
Juste après init, les ensembles seront ceux donnés ci-dessous.
|
||||||
|
Les autres tests peuvent ajouter des éléments, c'edt pourquoi on utilise issubset().
|
||||||
|
"""
|
||||||
|
headers = api_headers
|
||||||
|
assert {
|
||||||
|
"admin_api",
|
||||||
|
"admin",
|
||||||
|
"lecteur_api",
|
||||||
|
"other",
|
||||||
|
"test",
|
||||||
|
"u_AA",
|
||||||
|
"u_BB",
|
||||||
|
"u_CC",
|
||||||
|
"u_DD",
|
||||||
|
"u_TAPI",
|
||||||
|
}.issubset({u["user_name"] for u in GET("/users/query", headers=headers)})
|
||||||
|
assert {
|
||||||
|
"AA",
|
||||||
|
"BB",
|
||||||
|
"CC",
|
||||||
|
"DD",
|
||||||
|
"TAPI",
|
||||||
|
}.issubset({d["acronym"] for d in GET("/departements", headers=headers)})
|
||||||
|
assert 1 in (
|
||||||
|
formsemestre["semestre_id"]
|
||||||
|
for formsemestre in GET("/formsemestres/query", headers=headers)
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user