forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -25,6 +25,7 @@ from app.but import bulletin_but_court
|
|||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models import (
|
from app.models import (
|
||||||
Admission,
|
Admission,
|
||||||
|
Adresse,
|
||||||
Departement,
|
Departement,
|
||||||
FormSemestreInscription,
|
FormSemestreInscription,
|
||||||
FormSemestre,
|
FormSemestre,
|
||||||
@ -513,6 +514,20 @@ def etudiant_create(force=False):
|
|||||||
400, f"{len(homonyms)} homonymes détectés. Vous pouvez utiliser /force."
|
400, f"{len(homonyms)} homonymes détectés. Vous pouvez utiliser /force."
|
||||||
)
|
)
|
||||||
etud = Identite.create_etud(**args)
|
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é:
|
# Poste une nouvelle dans le département concerné:
|
||||||
ScolarNews.add(
|
ScolarNews.add(
|
||||||
typ=ScolarNews.NEWS_INSCR,
|
typ=ScolarNews.NEWS_INSCR,
|
||||||
@ -522,4 +537,54 @@ def etudiant_create(force=False):
|
|||||||
dept_id=dept_o.id,
|
dept_id=dept_o.id,
|
||||||
)
|
)
|
||||||
db.session.commit()
|
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 db, log
|
||||||
from app import models
|
from app import models
|
||||||
|
from app.models.departements import Departement
|
||||||
from app.models.scolar_event import ScolarEvent
|
from app.models.scolar_event import ScolarEvent
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app.scodoc.sco_bac import Baccalaureat
|
from app.scodoc.sco_bac import Baccalaureat
|
||||||
@ -204,14 +205,22 @@ class Identite(db.Model, models.ScoDocModel):
|
|||||||
return cls.create_from_dict(args)
|
return cls.create_from_dict(args)
|
||||||
|
|
||||||
@classmethod
|
@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.
|
"""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)
|
(added to session but not flushed nor commited)
|
||||||
"""
|
"""
|
||||||
etud: Identite = super(cls, cls).create_from_dict(data)
|
if not "dept_id" in args:
|
||||||
if (data.get("admission_id", None) is None) and (
|
if "dept" in args:
|
||||||
data.get("admission", None) is None
|
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.admission = Admission()
|
||||||
etud.adresses.append(Adresse(typeadresse="domicile"))
|
etud.adresses.append(Adresse(typeadresse="domicile"))
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
@ -221,6 +230,14 @@ class Identite(db.Model, models.ScoDocModel):
|
|||||||
log(f"Identite.create {etud}")
|
log(f"Identite.create {etud}")
|
||||||
return 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
|
@property
|
||||||
def civilite_str(self) -> str:
|
def civilite_str(self) -> str:
|
||||||
"""returns civilité usuelle: 'M.' ou 'Mme' ou '' (pour le genre neutre,
|
"""returns civilité usuelle: 'M.' ou 'Mme' ou '' (pour le genre neutre,
|
||||||
@ -329,8 +346,6 @@ class Identite(db.Model, models.ScoDocModel):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def convert_dict_fields(cls, args: dict) -> dict:
|
def convert_dict_fields(cls, args: dict) -> dict:
|
||||||
"""Convert fields in the given dict. No other side effect.
|
"""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.
|
returns: dict to store in model's db.
|
||||||
"""
|
"""
|
||||||
# Les champs qui sont toujours stockés en majuscules:
|
# Les champs qui sont toujours stockés en majuscules:
|
||||||
@ -349,8 +364,6 @@ class Identite(db.Model, models.ScoDocModel):
|
|||||||
"code_ine",
|
"code_ine",
|
||||||
}
|
}
|
||||||
args_dict = {}
|
args_dict = {}
|
||||||
if not "dept_id" in args:
|
|
||||||
args["dept_id"] = g.scodoc_dept_id
|
|
||||||
for key, value in args.items():
|
for key, value in args.items():
|
||||||
if hasattr(cls, key) and not isinstance(getattr(cls, key, None), property):
|
if hasattr(cls, key) and not isinstance(getattr(cls, key, None), property):
|
||||||
# compat scodoc7 (mauvaise idée de l'époque)
|
# compat scodoc7 (mauvaise idée de l'époque)
|
||||||
|
@ -624,7 +624,7 @@ def create_etud(cnx, args: dict = None):
|
|||||||
ScolarNews.add(
|
ScolarNews.add(
|
||||||
typ=ScolarNews.NEWS_INSCR,
|
typ=ScolarNews.NEWS_INSCR,
|
||||||
text=f"Nouvel étudiant {etud.html_link_fiche()}",
|
text=f"Nouvel étudiant {etud.html_link_fiche()}",
|
||||||
url=etud["url"],
|
url=etud_dict["url"],
|
||||||
max_frequency=0,
|
max_frequency=0,
|
||||||
)
|
)
|
||||||
return etud_dict
|
return etud_dict
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.6.60"
|
SCOVERSION = "9.6.61"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ from tests.api.setup_test_api import (
|
|||||||
API_USER_ADMIN,
|
API_USER_ADMIN,
|
||||||
CHECK_CERTIFICATE,
|
CHECK_CERTIFICATE,
|
||||||
DEPT_ACRONYM,
|
DEPT_ACRONYM,
|
||||||
|
GET,
|
||||||
POST_JSON,
|
POST_JSON,
|
||||||
get_auth_headers,
|
get_auth_headers,
|
||||||
)
|
)
|
||||||
@ -934,6 +935,16 @@ def test_etudiant_create(api_headers):
|
|||||||
"nom": "Bach",
|
"nom": "Bach",
|
||||||
"dept": DEPT_ACRONYM,
|
"dept": DEPT_ACRONYM,
|
||||||
"civilite": "M",
|
"civilite": "M",
|
||||||
|
"admission": {
|
||||||
|
"commentaire": "test",
|
||||||
|
"annee_bac": 2024,
|
||||||
|
},
|
||||||
|
"adresses": [
|
||||||
|
{
|
||||||
|
"villedomicile": "Santa Teresa",
|
||||||
|
"emailperso": "XXX@2666.mx",
|
||||||
|
}
|
||||||
|
],
|
||||||
}
|
}
|
||||||
etud = POST_JSON(
|
etud = POST_JSON(
|
||||||
"/etudiant/create",
|
"/etudiant/create",
|
||||||
@ -941,3 +952,54 @@ def test_etudiant_create(api_headers):
|
|||||||
headers=admin_header,
|
headers=admin_header,
|
||||||
)
|
)
|
||||||
assert etud["nom"] == args["nom"].upper()
|
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