forked from ScoDoc/ScoDoc
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)
|
||||
)
|
||||
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}:
|
||||
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)
|
||||
)
|
||||
group = query.first_or_404()
|
||||
if not group.partition.formsemestre.etat:
|
||||
return json_error(403, "formsemestre verrouillé")
|
||||
if etud in group.etuds:
|
||||
group.etuds.remove(etud)
|
||||
db.session.commit()
|
||||
@ -222,6 +226,8 @@ def partition_remove_etud(partition_id: int, etudid: int):
|
||||
if g.scodoc_dept:
|
||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||
partition = query.first_or_404()
|
||||
if not partition.formsemestre.etat:
|
||||
return json_error(403, "formsemestre verrouillé")
|
||||
groups = (
|
||||
GroupDescr.query.filter_by(partition_id=partition_id)
|
||||
.join(group_membership)
|
||||
@ -252,8 +258,10 @@ def group_create(partition_id: int):
|
||||
if g.scodoc_dept:
|
||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||
partition: Partition = query.first_or_404()
|
||||
if not partition.formsemestre.etat:
|
||||
return json_error(403, "formsemestre verrouillé")
|
||||
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
|
||||
group_name = data.get("group_name")
|
||||
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)
|
||||
)
|
||||
group: GroupDescr = query.first_or_404()
|
||||
if not group.partition.formsemestre.etat:
|
||||
return json_error(403, "formsemestre verrouillé")
|
||||
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
|
||||
log(f"deleting {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)
|
||||
)
|
||||
group: GroupDescr = query.first_or_404()
|
||||
if not group.partition.formsemestre.etat:
|
||||
return json_error(403, "formsemestre verrouillé")
|
||||
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
|
||||
group_name = data.get("group_name")
|
||||
if group_name is not None:
|
||||
@ -348,6 +360,8 @@ def partition_create(formsemestre_id: int):
|
||||
if g.scodoc_dept:
|
||||
query = query.filter_by(dept_id=g.scodoc_dept_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
|
||||
partition_name = data.get("partition_name")
|
||||
if partition_name is None:
|
||||
@ -396,6 +410,8 @@ def formsemestre_order_partitions(formsemestre_id: int):
|
||||
if g.scodoc_dept:
|
||||
query = query.filter_by(dept_id=g.scodoc_dept_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
|
||||
if not isinstance(partition_ids, int) and not all(
|
||||
isinstance(x, int) for x in partition_ids
|
||||
@ -433,6 +449,8 @@ def partition_order_groups(partition_id: int):
|
||||
if g.scodoc_dept:
|
||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||
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
|
||||
if not isinstance(group_ids, int) and not all(
|
||||
isinstance(x, int) for x in group_ids
|
||||
@ -474,6 +492,8 @@ def partition_edit(partition_id: int):
|
||||
if g.scodoc_dept:
|
||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||
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
|
||||
modified = False
|
||||
partition_name = data.get("partition_name")
|
||||
@ -532,6 +552,8 @@ def partition_delete(partition_id: int):
|
||||
if g.scodoc_dept:
|
||||
query = query.join(FormSemestre).filter_by(dept_id=g.scodoc_dept_id)
|
||||
partition: Partition = query.first_or_404()
|
||||
if not partition.formsemestre.etat:
|
||||
return json_error(403, "formsemestre verrouillé")
|
||||
if not partition.partition_name:
|
||||
return json_error(404, "ne peut pas supprimer la partition par défaut")
|
||||
is_parcours = partition.is_parcours()
|
||||
|
@ -63,51 +63,51 @@ class FormSemestre(db.Model):
|
||||
"False si verrouillé"
|
||||
modalite = db.Column(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
db.Boolean(), nullable=False, default=False, server_default="false"
|
||||
)
|
||||
"Si vrai, la moyenne générale indicative BUT n'est pas calculée"
|
||||
# semestres decales (pour gestion jurys):
|
||||
gestion_semestrielle = db.Column(
|
||||
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(
|
||||
db.String(SHORT_STR_LEN),
|
||||
default="white",
|
||||
server_default="white",
|
||||
nullable=False,
|
||||
)
|
||||
# autorise resp. a modifier semestre:
|
||||
"couleur fond bulletins HTML"
|
||||
resp_can_edit = db.Column(
|
||||
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(
|
||||
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(
|
||||
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 !
|
||||
# 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())
|
||||
"code element annee Apogee, eg 'VRT1A' ou 'V2INLA,V2INCA,...'"
|
||||
|
||||
# Relations:
|
||||
etapes = db.relationship(
|
||||
|
@ -4,4 +4,5 @@ markers =
|
||||
but_gb
|
||||
lemans
|
||||
lyon
|
||||
test_test
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.4.30"
|
||||
SCOVERSION = "9.4.31"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
@ -25,7 +25,7 @@ from app import models
|
||||
|
||||
from app.auth.models import User, Role, UserRole
|
||||
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 FormSemestre, FormSemestreInscription
|
||||
from app.models import GroupDescr
|
||||
@ -73,6 +73,7 @@ def make_shell_context():
|
||||
"ctx": app.test_request_context(),
|
||||
"current_app": flask.current_app,
|
||||
"current_user": current_user,
|
||||
"Departement": Departement,
|
||||
"db": db,
|
||||
"Evaluation": Evaluation,
|
||||
"flask": flask,
|
||||
|
@ -34,7 +34,11 @@ def test_list_users(api_admin_headers):
|
||||
|
||||
# Tous les utilisateurs, vus par SuperAdmin:
|
||||
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)
|
||||
all_users = []
|
||||
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"):
|
||||
headers = get_auth_headers(u["user_name"], "test")
|
||||
users_by_u = GET("/users/query", headers=headers)
|
||||
assert len(users_by_u) == 4 + i
|
||||
# explication: tous ont le droit de voir les 3 users de TAPI
|
||||
# (test, other et u_TAPI)
|
||||
assert len(users_by_u) == nb_TAPI + 1 + i
|
||||
# explication: tous ont le droit de voir les users de TAPI
|
||||
# plus l'utilisateur de chaque département jusqu'au leur
|
||||
# (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["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):
|
||||
@ -229,3 +236,10 @@ def test_modif_users_depts(api_admin_headers):
|
||||
ok = True
|
||||
assert ok
|
||||
# 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