forked from ScoDoc/ScoDoc
API: create/edit etudiant, admission, adresse
This commit is contained in:
parent
2377918b54
commit
e634b50d56
@ -25,6 +25,7 @@ from app.but import bulletin_but_court
|
||||
from app.decorators import scodoc, permission_required
|
||||
from app.models import (
|
||||
Admission,
|
||||
Adresse,
|
||||
Departement,
|
||||
FormSemestreInscription,
|
||||
FormSemestre,
|
||||
@ -513,6 +514,20 @@ def etudiant_create(force=False):
|
||||
400, f"{len(homonyms)} homonymes détectés. Vous pouvez utiliser /force."
|
||||
)
|
||||
etud = Identite.create_etud(**args)
|
||||
db.session.flush()
|
||||
# --- Données admission
|
||||
admission_args = args.get("admission", None)
|
||||
if admission_args:
|
||||
etud.admission.from_dict(admission_args)
|
||||
# --- Adresse
|
||||
adresses = args.get("adresses", [])
|
||||
if adresses:
|
||||
# ne prend en compte que la première adresse
|
||||
# car si la base est concue pour avoir plusieurs adresses par étudiant,
|
||||
# l'application n'en gère plus qu'une seule.
|
||||
adresse = etud.adresses.first()
|
||||
adresse.from_dict(adresses[0])
|
||||
|
||||
# Poste une nouvelle dans le département concerné:
|
||||
ScolarNews.add(
|
||||
typ=ScolarNews.NEWS_INSCR,
|
||||
@ -522,4 +537,54 @@ def etudiant_create(force=False):
|
||||
dept_id=dept_o.id,
|
||||
)
|
||||
db.session.commit()
|
||||
return etud.to_dict_short()
|
||||
# Note: je ne comprends pas pourquoi un refresh est nécessaire ici
|
||||
# sans ce refresh, etud.__dict__ est incomplet (pas de 'nom').
|
||||
db.session.refresh(etud)
|
||||
r = etud.to_dict_api()
|
||||
return r
|
||||
|
||||
|
||||
@bp.route("/etudiant/<string:code_type>/<string:code>/edit", methods=["POST"])
|
||||
@scodoc
|
||||
@permission_required(Permission.EtudInscrit)
|
||||
def etudiant_edit(
|
||||
code_type: str = "etudid",
|
||||
code: str = None,
|
||||
):
|
||||
"""Edition des données étudiant (identité, admission, adresses)"""
|
||||
if code_type == "nip":
|
||||
query = Identite.query.filter_by(code_nip=code)
|
||||
elif code_type == "etudid":
|
||||
try:
|
||||
etudid = int(code)
|
||||
except ValueError:
|
||||
return json_error(404, "invalid etudid type")
|
||||
query = Identite.query.filter_by(id=etudid)
|
||||
elif code_type == "ine":
|
||||
query = Identite.query.filter_by(code_ine=code)
|
||||
else:
|
||||
return json_error(404, "invalid code_type")
|
||||
if g.scodoc_dept:
|
||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||
etud: Identite = query.first()
|
||||
#
|
||||
args = request.get_json(force=True) # may raise 400 Bad Request
|
||||
etud.from_dict(args)
|
||||
admission_args = args.get("admission", None)
|
||||
if admission_args:
|
||||
etud.admission.from_dict(admission_args)
|
||||
# --- Adresse
|
||||
adresses = args.get("adresses", [])
|
||||
if adresses:
|
||||
# ne prend en compte que la première adresse
|
||||
# car si la base est concue pour avoir plusieurs adresses par étudiant,
|
||||
# l'application n'en gère plus qu'une seule.
|
||||
adresse = etud.adresses.first()
|
||||
adresse.from_dict(adresses[0])
|
||||
|
||||
db.session.commit()
|
||||
# Note: je ne comprends pas pourquoi un refresh est nécessaire ici
|
||||
# sans ce refresh, etud.__dict__ est incomplet (pas de 'nom').
|
||||
db.session.refresh(etud)
|
||||
r = etud.to_dict_api()
|
||||
return r
|
||||
|
@ -15,6 +15,7 @@ from sqlalchemy import desc, text
|
||||
|
||||
from app import db, log
|
||||
from app import models
|
||||
from app.models.departements import Departement
|
||||
from app.models.scolar_event import ScolarEvent
|
||||
from app.scodoc import notesdb as ndb
|
||||
from app.scodoc.sco_bac import Baccalaureat
|
||||
@ -204,14 +205,22 @@ class Identite(db.Model, models.ScoDocModel):
|
||||
return cls.create_from_dict(args)
|
||||
|
||||
@classmethod
|
||||
def create_from_dict(cls, data) -> "Identite":
|
||||
def create_from_dict(cls, args) -> "Identite":
|
||||
"""Crée un étudiant à partir d'un dict, avec admission et adresse vides.
|
||||
If required dept_id or dept are not specified, set it to the current dept.
|
||||
args: dict with args in application.
|
||||
Les clés adresses et admission ne SONT PAS utilisées.
|
||||
(added to session but not flushed nor commited)
|
||||
"""
|
||||
etud: Identite = super(cls, cls).create_from_dict(data)
|
||||
if (data.get("admission_id", None) is None) and (
|
||||
data.get("admission", None) is None
|
||||
):
|
||||
if not "dept_id" in args:
|
||||
if "dept" in args:
|
||||
departement = Departement.query.filter_by(acronym=args["dept"]).first()
|
||||
if departement:
|
||||
args["dept_id"] = departement.id
|
||||
if not "dept_id" in args:
|
||||
args["dept_id"] = g.scodoc_dept_id
|
||||
etud: Identite = super().create_from_dict(args)
|
||||
if args.get("admission_id", None) is None:
|
||||
etud.admission = Admission()
|
||||
etud.adresses.append(Adresse(typeadresse="domicile"))
|
||||
db.session.flush()
|
||||
@ -221,6 +230,14 @@ class Identite(db.Model, models.ScoDocModel):
|
||||
log(f"Identite.create {etud}")
|
||||
return etud
|
||||
|
||||
@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."""
|
||||
return super().filter_model_attributes(
|
||||
data,
|
||||
excluded=(excluded or set()) | {"adresses", "admission", "departement"},
|
||||
)
|
||||
|
||||
@property
|
||||
def civilite_str(self) -> str:
|
||||
"""returns civilité usuelle: 'M.' ou 'Mme' ou '' (pour le genre neutre,
|
||||
@ -329,8 +346,6 @@ class Identite(db.Model, models.ScoDocModel):
|
||||
@classmethod
|
||||
def convert_dict_fields(cls, args: dict) -> dict:
|
||||
"""Convert fields in the given dict. No other side effect.
|
||||
If required dept_id is not specified, set it to the current dept.
|
||||
args: dict with args in application.
|
||||
returns: dict to store in model's db.
|
||||
"""
|
||||
# Les champs qui sont toujours stockés en majuscules:
|
||||
@ -349,8 +364,6 @@ class Identite(db.Model, models.ScoDocModel):
|
||||
"code_ine",
|
||||
}
|
||||
args_dict = {}
|
||||
if not "dept_id" in args:
|
||||
args["dept_id"] = g.scodoc_dept_id
|
||||
for key, value in args.items():
|
||||
if hasattr(cls, key) and not isinstance(getattr(cls, key, None), property):
|
||||
# compat scodoc7 (mauvaise idée de l'époque)
|
||||
|
@ -624,7 +624,7 @@ def create_etud(cnx, args: dict = None):
|
||||
ScolarNews.add(
|
||||
typ=ScolarNews.NEWS_INSCR,
|
||||
text=f"Nouvel étudiant {etud.html_link_fiche()}",
|
||||
url=etud["url"],
|
||||
url=etud_dict["url"],
|
||||
max_frequency=0,
|
||||
)
|
||||
return etud_dict
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.6.60"
|
||||
SCOVERSION = "9.6.61"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
@ -29,6 +29,7 @@ from tests.api.setup_test_api import (
|
||||
API_USER_ADMIN,
|
||||
CHECK_CERTIFICATE,
|
||||
DEPT_ACRONYM,
|
||||
GET,
|
||||
POST_JSON,
|
||||
get_auth_headers,
|
||||
)
|
||||
@ -934,6 +935,16 @@ def test_etudiant_create(api_headers):
|
||||
"nom": "Bach",
|
||||
"dept": DEPT_ACRONYM,
|
||||
"civilite": "M",
|
||||
"admission": {
|
||||
"commentaire": "test",
|
||||
"annee_bac": 2024,
|
||||
},
|
||||
"adresses": [
|
||||
{
|
||||
"villedomicile": "Santa Teresa",
|
||||
"emailperso": "XXX@2666.mx",
|
||||
}
|
||||
],
|
||||
}
|
||||
etud = POST_JSON(
|
||||
"/etudiant/create",
|
||||
@ -941,3 +952,54 @@ def test_etudiant_create(api_headers):
|
||||
headers=admin_header,
|
||||
)
|
||||
assert etud["nom"] == args["nom"].upper()
|
||||
assert etud["admission"]["commentaire"] == args["admission"]["commentaire"]
|
||||
assert etud["admission"]["annee_bac"] == args["admission"]["annee_bac"]
|
||||
assert len(etud["adresses"]) == 1
|
||||
assert etud["adresses"][0]["villedomicile"] == args["adresses"][0]["villedomicile"]
|
||||
assert etud["adresses"][0]["emailperso"] == args["adresses"][0]["emailperso"]
|
||||
etudid = etud["id"]
|
||||
# On recommence avec une nouvelle requête:
|
||||
etud = GET(f"/etudiant/etudid/{etudid}", headers=api_headers)
|
||||
assert etud["nom"] == args["nom"].upper()
|
||||
assert etud["admission"]["commentaire"] == args["admission"]["commentaire"]
|
||||
assert etud["admission"]["annee_bac"] == args["admission"]["annee_bac"]
|
||||
assert len(etud["adresses"]) == 1
|
||||
assert etud["adresses"][0]["villedomicile"] == args["adresses"][0]["villedomicile"]
|
||||
assert etud["adresses"][0]["emailperso"] == args["adresses"][0]["emailperso"]
|
||||
# Edition
|
||||
etud = POST_JSON(
|
||||
f"/etudiant/etudid/{etudid}/edit",
|
||||
{
|
||||
"civilite": "F",
|
||||
},
|
||||
headers=admin_header,
|
||||
)
|
||||
assert etud["civilite"] == "F"
|
||||
assert etud["nom"] == args["nom"].upper()
|
||||
assert etud["admission"]["commentaire"] == args["admission"]["commentaire"]
|
||||
assert etud["admission"]["annee_bac"] == args["admission"]["annee_bac"]
|
||||
assert len(etud["adresses"]) == 1
|
||||
assert etud["adresses"][0]["villedomicile"] == args["adresses"][0]["villedomicile"]
|
||||
assert etud["adresses"][0]["emailperso"] == args["adresses"][0]["emailperso"]
|
||||
etud = POST_JSON(
|
||||
f"/etudiant/etudid/{etudid}/edit",
|
||||
{
|
||||
"adresses": [
|
||||
{
|
||||
"villedomicile": "Barcelona",
|
||||
},
|
||||
],
|
||||
},
|
||||
headers=admin_header,
|
||||
)
|
||||
assert etud["adresses"][0]["villedomicile"] == "Barcelona"
|
||||
etud = POST_JSON(
|
||||
f"/etudiant/etudid/{etudid}/edit",
|
||||
{
|
||||
"admission": {
|
||||
"commentaire": "un nouveau commentaire",
|
||||
},
|
||||
},
|
||||
headers=admin_header,
|
||||
)
|
||||
assert etud["admission"]["commentaire"] == "un nouveau commentaire"
|
||||
|
Loading…
Reference in New Issue
Block a user