forked from ScoDoc/ScoDoc
RGPD: ViewEtudData. Implements #842
This commit is contained in:
parent
c6910fc76e
commit
81915b1522
@ -104,7 +104,8 @@ def etudiants_courants(long=False):
|
|||||||
or_(Departement.acronym == acronym for acronym in allowed_depts)
|
or_(Departement.acronym == acronym for acronym in allowed_depts)
|
||||||
)
|
)
|
||||||
if long:
|
if long:
|
||||||
data = [etud.to_dict_api() for etud in etuds]
|
restrict = not current_user.has_permission(Permission.ViewEtudData)
|
||||||
|
data = [etud.to_dict_api(restrict=restrict) for etud in etuds]
|
||||||
else:
|
else:
|
||||||
data = [etud.to_dict_short() for etud in etuds]
|
data = [etud.to_dict_short() for etud in etuds]
|
||||||
return data
|
return data
|
||||||
@ -138,8 +139,8 @@ def etudiant(etudid: int = None, nip: str = None, ine: str = None):
|
|||||||
404,
|
404,
|
||||||
message="étudiant inconnu",
|
message="étudiant inconnu",
|
||||||
)
|
)
|
||||||
|
restrict = not current_user.has_permission(Permission.ViewEtudData)
|
||||||
return etud.to_dict_api()
|
return etud.to_dict_api(restrict=restrict)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/etudiant/etudid/<int:etudid>/photo")
|
@bp.route("/etudiant/etudid/<int:etudid>/photo")
|
||||||
@ -251,7 +252,8 @@ def etudiants(etudid: int = None, nip: str = None, ine: str = None):
|
|||||||
query = query.join(Departement).filter(
|
query = query.join(Departement).filter(
|
||||||
or_(Departement.acronym == acronym for acronym in allowed_depts)
|
or_(Departement.acronym == acronym for acronym in allowed_depts)
|
||||||
)
|
)
|
||||||
return [etud.to_dict_api() for etud in query]
|
restrict = not current_user.has_permission(Permission.ViewEtudData)
|
||||||
|
return [etud.to_dict_api(restrict=restrict) for etud in query]
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/etudiants/name/<string:start>")
|
@bp.route("/etudiants/name/<string:start>")
|
||||||
@ -278,7 +280,11 @@ def etudiants_by_name(start: str = "", min_len=3, limit=32):
|
|||||||
)
|
)
|
||||||
etuds = query.order_by(Identite.nom, Identite.prenom).limit(limit)
|
etuds = query.order_by(Identite.nom, Identite.prenom).limit(limit)
|
||||||
# Note: on raffine le tri pour les caractères spéciaux et nom usuel ici:
|
# Note: on raffine le tri pour les caractères spéciaux et nom usuel ici:
|
||||||
return [etud.to_dict_api() for etud in sorted(etuds, key=attrgetter("sort_key"))]
|
restrict = not current_user.has_permission(Permission.ViewEtudData)
|
||||||
|
return [
|
||||||
|
etud.to_dict_api(restrict=restrict)
|
||||||
|
for etud in sorted(etuds, key=attrgetter("sort_key"))
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/etudiant/etudid/<int:etudid>/formsemestres")
|
@bp.route("/etudiant/etudid/<int:etudid>/formsemestres")
|
||||||
@ -543,7 +549,8 @@ def etudiant_create(force=False):
|
|||||||
# Note: je ne comprends pas pourquoi un refresh est nécessaire ici
|
# Note: je ne comprends pas pourquoi un refresh est nécessaire ici
|
||||||
# sans ce refresh, etud.__dict__ est incomplet (pas de 'nom').
|
# sans ce refresh, etud.__dict__ est incomplet (pas de 'nom').
|
||||||
db.session.refresh(etud)
|
db.session.refresh(etud)
|
||||||
r = etud.to_dict_api()
|
|
||||||
|
r = etud.to_dict_api(restrict=False) # pas de restriction, on vient de le créer
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
@ -590,5 +597,6 @@ def etudiant_edit(
|
|||||||
# Note: je ne comprends pas pourquoi un refresh est nécessaire ici
|
# Note: je ne comprends pas pourquoi un refresh est nécessaire ici
|
||||||
# sans ce refresh, etud.__dict__ est incomplet (pas de 'nom').
|
# sans ce refresh, etud.__dict__ est incomplet (pas de 'nom').
|
||||||
db.session.refresh(etud)
|
db.session.refresh(etud)
|
||||||
r = etud.to_dict_api()
|
restrict = not current_user.has_permission(Permission.ViewEtudData)
|
||||||
|
r = etud.to_dict_api(restrict=restrict)
|
||||||
return r
|
return r
|
||||||
|
@ -11,7 +11,7 @@ from operator import attrgetter, itemgetter
|
|||||||
|
|
||||||
from flask import g, make_response, request
|
from flask import g, make_response, request
|
||||||
from flask_json import as_json
|
from flask_json import as_json
|
||||||
from flask_login import login_required
|
from flask_login import current_user, login_required
|
||||||
|
|
||||||
import app
|
import app
|
||||||
from app import db
|
from app import db
|
||||||
@ -360,7 +360,8 @@ def formsemestre_etudiants(
|
|||||||
inscriptions = formsemestre.inscriptions
|
inscriptions = formsemestre.inscriptions
|
||||||
|
|
||||||
if long:
|
if long:
|
||||||
etuds = [ins.etud.to_dict_api() for ins in inscriptions]
|
restrict = not current_user.has_permission(Permission.ViewEtudData)
|
||||||
|
etuds = [ins.etud.to_dict_api(restrict=restrict) for ins in inscriptions]
|
||||||
else:
|
else:
|
||||||
etuds = [ins.etud.to_dict_short() for ins in inscriptions]
|
etuds = [ins.etud.to_dict_short() for ins in inscriptions]
|
||||||
# Ajout des groupes de chaque étudiants
|
# Ajout des groupes de chaque étudiants
|
||||||
|
@ -421,7 +421,7 @@ class Identite(models.ScoDocModel):
|
|||||||
return args_dict
|
return args_dict
|
||||||
|
|
||||||
def to_dict_short(self) -> dict:
|
def to_dict_short(self) -> dict:
|
||||||
"""Les champs essentiels"""
|
"""Les champs essentiels (aucune donnée perso protégée)"""
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
"civilite": self.civilite,
|
"civilite": self.civilite,
|
||||||
@ -494,16 +494,22 @@ class Identite(models.ScoDocModel):
|
|||||||
d["id"] = self.id # a été écrasé par l'id de adresse
|
d["id"] = self.id # a été écrasé par l'id de adresse
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def to_dict_api(self) -> dict:
|
def to_dict_api(self, restrict=False) -> dict:
|
||||||
"""Représentation dictionnaire pour export API, avec adresses et admission."""
|
"""Représentation dictionnaire pour export API, avec adresses et admission.
|
||||||
|
Si restrict, supprime les infos "personnelles" (boursier)
|
||||||
|
"""
|
||||||
e = dict(self.__dict__)
|
e = dict(self.__dict__)
|
||||||
e.pop("_sa_instance_state", None)
|
e.pop("_sa_instance_state", None)
|
||||||
admission = self.admission
|
admission = self.admission
|
||||||
e["admission"] = admission.to_dict() if admission is not None else None
|
e["admission"] = admission.to_dict() if admission is not None else None
|
||||||
e["adresses"] = [adr.to_dict() for adr in self.adresses]
|
e["adresses"] = [adr.to_dict(restrict=restrict) for adr in self.adresses]
|
||||||
e["dept_acronym"] = self.departement.acronym
|
e["dept_acronym"] = self.departement.acronym
|
||||||
e.pop("departement", None)
|
e.pop("departement", None)
|
||||||
e["sort_key"] = self.sort_key
|
e["sort_key"] = self.sort_key
|
||||||
|
if restrict:
|
||||||
|
# Met à None les attributs protégés:
|
||||||
|
for attr in self.protected_attrs:
|
||||||
|
e[attr] = None
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def inscriptions(self) -> list["FormSemestreInscription"]:
|
def inscriptions(self) -> list["FormSemestreInscription"]:
|
||||||
|
@ -62,7 +62,7 @@ def can_edit_etud_archive(authuser):
|
|||||||
|
|
||||||
|
|
||||||
def etud_list_archives_html(etud: Identite):
|
def etud_list_archives_html(etud: Identite):
|
||||||
"""HTML snippet listing archives"""
|
"""HTML snippet listing archives."""
|
||||||
can_edit = can_edit_etud_archive(current_user)
|
can_edit = can_edit_etud_archive(current_user)
|
||||||
etud_archive_id = etud.id
|
etud_archive_id = etud.id
|
||||||
L = []
|
L = []
|
||||||
|
@ -51,13 +51,14 @@ from app.models import (
|
|||||||
NotesNotes,
|
NotesNotes,
|
||||||
)
|
)
|
||||||
from app.scodoc.codes_cursus import UE_SPORT
|
from app.scodoc.codes_cursus import UE_SPORT
|
||||||
import app.scodoc.sco_utils as scu
|
|
||||||
from app.scodoc.sco_utils import ModuleType
|
|
||||||
from app.scodoc.sco_permissions import Permission
|
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import (
|
||||||
ScoValueError,
|
ScoValueError,
|
||||||
ScoInvalidIdType,
|
ScoInvalidIdType,
|
||||||
)
|
)
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
|
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import htmlutils
|
from app.scodoc import htmlutils
|
||||||
from app.scodoc import sco_archives_formsemestre
|
from app.scodoc import sco_archives_formsemestre
|
||||||
@ -109,7 +110,7 @@ def _build_menu_stats(formsemestre_id):
|
|||||||
"title": "Lycées d'origine",
|
"title": "Lycées d'origine",
|
||||||
"endpoint": "notes.formsemestre_etuds_lycees",
|
"endpoint": "notes.formsemestre_etuds_lycees",
|
||||||
"args": {"formsemestre_id": formsemestre_id},
|
"args": {"formsemestre_id": formsemestre_id},
|
||||||
"enabled": True,
|
"enabled": current_user.has_permission(Permission.ViewEtudData),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": 'Table "poursuite"',
|
"title": 'Table "poursuite"',
|
||||||
@ -336,6 +337,7 @@ def formsemestre_status_menubar(formsemestre: FormSemestre) -> str:
|
|||||||
formsemestre_id, fix_if_missing=True
|
formsemestre_id, fix_if_missing=True
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
"enabled": current_user.has_permission(Permission.ViewEtudData),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Vérifier inscriptions multiples",
|
"title": "Vérifier inscriptions multiples",
|
||||||
|
@ -52,7 +52,7 @@ from app.scodoc import sco_preferences
|
|||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc.sco_etud import etud_sort_key
|
from app.scodoc.sco_etud import etud_sort_key
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError, ScoPermissionDenied
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
JAVASCRIPTS = html_sco_header.BOOTSTRAP_MULTISELECT_JS + [
|
JAVASCRIPTS = html_sco_header.BOOTSTRAP_MULTISELECT_JS + [
|
||||||
@ -118,6 +118,16 @@ def groups_view(
|
|||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
<style>
|
||||||
|
div.multiselect-container.dropdown-menu {{
|
||||||
|
min-width: 180px;
|
||||||
|
}}
|
||||||
|
span.warning_unauthorized {{
|
||||||
|
color: pink;
|
||||||
|
font-style: italic;
|
||||||
|
margin-left: 12px;
|
||||||
|
}}
|
||||||
|
</style>
|
||||||
<div id="group-tabs">
|
<div id="group-tabs">
|
||||||
<!-- Menu choix groupe -->
|
<!-- Menu choix groupe -->
|
||||||
{form_groups_choice(groups_infos, submit_on_change=True)}
|
{form_groups_choice(groups_infos, submit_on_change=True)}
|
||||||
@ -474,15 +484,12 @@ def groups_table(
|
|||||||
"""
|
"""
|
||||||
from app.scodoc import sco_report
|
from app.scodoc import sco_report
|
||||||
|
|
||||||
# log(
|
can_view_etud_data = int(current_user.has_permission(Permission.ViewEtudData))
|
||||||
# "enter groups_table %s: %s"
|
|
||||||
# % (groups_infos.members[0]["nom"], groups_infos.members[0].get("etape", "-"))
|
|
||||||
# )
|
|
||||||
with_codes = int(with_codes)
|
with_codes = int(with_codes)
|
||||||
with_paiement = int(with_paiement)
|
with_paiement = int(with_paiement) and can_view_etud_data
|
||||||
with_archives = int(with_archives)
|
with_archives = int(with_archives) and can_view_etud_data
|
||||||
with_annotations = int(with_annotations)
|
with_annotations = int(with_annotations) and can_view_etud_data
|
||||||
with_bourse = int(with_bourse)
|
with_bourse = int(with_bourse) and can_view_etud_data
|
||||||
|
|
||||||
base_url_np = groups_infos.base_url + f"&with_codes={with_codes}"
|
base_url_np = groups_infos.base_url + f"&with_codes={with_codes}"
|
||||||
base_url = (
|
base_url = (
|
||||||
@ -527,6 +534,7 @@ def groups_table(
|
|||||||
if fmt != "html": # ne mentionne l'état que en Excel (style en html)
|
if fmt != "html": # ne mentionne l'état que en Excel (style en html)
|
||||||
columns_ids.append("etat")
|
columns_ids.append("etat")
|
||||||
columns_ids.append("email")
|
columns_ids.append("email")
|
||||||
|
if can_view_etud_data:
|
||||||
columns_ids.append("emailperso")
|
columns_ids.append("emailperso")
|
||||||
|
|
||||||
if fmt == "moodlecsv":
|
if fmt == "moodlecsv":
|
||||||
@ -616,7 +624,7 @@ def groups_table(
|
|||||||
+ "+".join(sorted(moodle_groupenames))
|
+ "+".join(sorted(moodle_groupenames))
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
filename = "etudiants_%s" % groups_infos.groups_filename
|
filename = f"etudiants_{groups_infos.groups_filename}"
|
||||||
|
|
||||||
prefs = sco_preferences.SemPreferences(groups_infos.formsemestre_id)
|
prefs = sco_preferences.SemPreferences(groups_infos.formsemestre_id)
|
||||||
tab = GenTable(
|
tab = GenTable(
|
||||||
@ -664,28 +672,33 @@ def groups_table(
|
|||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
if groups_infos.members:
|
if groups_infos.members:
|
||||||
Of = []
|
menu_options = []
|
||||||
options = {
|
options = {
|
||||||
|
"with_codes": "Affiche codes",
|
||||||
|
}
|
||||||
|
if can_view_etud_data:
|
||||||
|
options.update(
|
||||||
|
{
|
||||||
"with_paiement": "Paiement inscription",
|
"with_paiement": "Paiement inscription",
|
||||||
"with_archives": "Fichiers archivés",
|
"with_archives": "Fichiers archivés",
|
||||||
"with_annotations": "Annotations",
|
"with_annotations": "Annotations",
|
||||||
"with_codes": "Codes",
|
|
||||||
"with_bourse": "Statut boursier",
|
"with_bourse": "Statut boursier",
|
||||||
}
|
}
|
||||||
for option in options:
|
)
|
||||||
|
for option, label in options.items():
|
||||||
if locals().get(option, False):
|
if locals().get(option, False):
|
||||||
selected = "selected"
|
selected = "selected"
|
||||||
else:
|
else:
|
||||||
selected = ""
|
selected = ""
|
||||||
Of.append(
|
menu_options.append(
|
||||||
"""<option value="%s" %s>%s</option>"""
|
f"""<option value="{option}" {selected}>{label}</option>"""
|
||||||
% (option, selected, options[option])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
H.extend(
|
H.extend(
|
||||||
[
|
[
|
||||||
"""<span style="margin-left: 2em;"><select name="group_list_options" id="group_list_options" class="multiselect" multiple="multiple">""",
|
"""<span style="margin-left: 2em;">
|
||||||
"\n".join(Of),
|
<select name="group_list_options" id="group_list_options" class="multiselect" multiple="multiple">""",
|
||||||
|
"\n".join(menu_options),
|
||||||
"""</select></span>
|
"""</select></span>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
@ -701,6 +714,9 @@ def groups_table(
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
""",
|
""",
|
||||||
|
"""<span class="warning_unauthorized">accès aux données personnelles interdit</span>"""
|
||||||
|
if not can_view_etud_data
|
||||||
|
else "",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
H.append("</div></form>")
|
H.append("</div></form>")
|
||||||
@ -708,41 +724,45 @@ def groups_table(
|
|||||||
H.extend(
|
H.extend(
|
||||||
[
|
[
|
||||||
tab.html(),
|
tab.html(),
|
||||||
"<ul>",
|
f"""
|
||||||
'<li><a class="stdlink" href="%s&fmt=xlsappel">Feuille d\'appel Excel</a></li>'
|
<ul>
|
||||||
% (tab.base_url,),
|
<li><a class="stdlink" href="{tab.base_url}&fmt=xlsappel">Feuille d'appel Excel</a>
|
||||||
'<li><a class="stdlink" href="%s&fmt=xls">Table Excel</a></li>'
|
</li>
|
||||||
% (tab.base_url,),
|
<li><a class="stdlink" href="{tab.base_url}&fmt=xls">Table Excel</a>
|
||||||
'<li><a class="stdlink" href="%s&fmt=moodlecsv">Fichier CSV pour Moodle (groupe sélectionné)</a></li>'
|
</li>
|
||||||
% (tab.base_url,),
|
<li><a class="stdlink" href="{tab.base_url}&fmt=moodlecsv">Fichier CSV pour Moodle (groupe sélectionné)</a>
|
||||||
"""<li>
|
</li>
|
||||||
<a class="stdlink" href="export_groups_as_moodle_csv?formsemestre_id=%s">Fichier CSV pour Moodle (tous les groupes)</a>
|
<li>
|
||||||
|
<a class="stdlink" href="export_groups_as_moodle_csv?formsemestre_id={groups_infos.formsemestre_id}">
|
||||||
|
Fichier CSV pour Moodle (tous les groupes)</a>
|
||||||
<em>(voir le paramétrage pour modifier le format des fichiers Moodle exportés)</em>
|
<em>(voir le paramétrage pour modifier le format des fichiers Moodle exportés)</em>
|
||||||
</li>"""
|
</li>""",
|
||||||
% groups_infos.formsemestre_id,
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if amail_inst:
|
if amail_inst:
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a class="stdlink" href="mailto:?bcc=%s">Envoyer un mail collectif au groupe de %s (via %d adresses institutionnelles)</a></li>'
|
f"""<li>
|
||||||
% (
|
<a class="stdlink" href="mailto:?bcc={','.join(amail_inst)
|
||||||
",".join(amail_inst),
|
}">Envoyer un mail collectif au groupe de {groups_infos.groups_titles}
|
||||||
groups_infos.groups_titles,
|
(via {len(amail_inst)} adresses institutionnelles)</a>
|
||||||
len(amail_inst),
|
</li>"""
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if can_view_etud_data:
|
||||||
if amail_perso:
|
if amail_perso:
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a class="stdlink" href="mailto:?bcc=%s">Envoyer un mail collectif au groupe de %s (via %d adresses personnelles)</a></li>'
|
f"""<li>
|
||||||
% (
|
<a class="stdlink" href="mailto:?bcc={','.join(amail_perso)
|
||||||
",".join(amail_perso),
|
}">Envoyer un mail collectif au groupe de {groups_infos.groups_titles}
|
||||||
groups_infos.groups_titles,
|
(via {len(amail_perso)} adresses personnelles)</a>
|
||||||
len(amail_perso),
|
</li>"""
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
H.append("<li><em>Adresses personnelles non renseignées</em></li>")
|
H.append("<li><em>Adresses personnelles non renseignées</em></li>")
|
||||||
|
else:
|
||||||
|
H.append(
|
||||||
|
"""<li class="unauthorized">adresses mail personnelles protégées</li>"""
|
||||||
|
)
|
||||||
|
|
||||||
H.append("</ul>")
|
H.append("</ul>")
|
||||||
|
|
||||||
@ -772,6 +792,10 @@ def groups_table(
|
|||||||
filename = "liste_%s" % groups_infos.groups_filename
|
filename = "liste_%s" % groups_infos.groups_filename
|
||||||
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE)
|
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE)
|
||||||
elif fmt == "allxls":
|
elif fmt == "allxls":
|
||||||
|
if not can_view_etud_data:
|
||||||
|
raise ScoPermissionDenied(
|
||||||
|
"Vous n'avez pas la permission requise (ViewEtudData)"
|
||||||
|
)
|
||||||
# feuille Excel avec toutes les infos etudiants
|
# feuille Excel avec toutes les infos etudiants
|
||||||
if not groups_infos.members:
|
if not groups_infos.members:
|
||||||
return ""
|
return ""
|
||||||
@ -881,8 +905,9 @@ def tab_absences_html(groups_infos, etat=None):
|
|||||||
% groups_infos.groups_query_args,
|
% groups_infos.groups_query_args,
|
||||||
"""<li><a class="stdlink" href="trombino?%s&fmt=pdflist">Liste d'appel avec photos</a></li>"""
|
"""<li><a class="stdlink" href="trombino?%s&fmt=pdflist">Liste d'appel avec photos</a></li>"""
|
||||||
% groups_infos.groups_query_args,
|
% groups_infos.groups_query_args,
|
||||||
"""<li><a class="stdlink" href="groups_export_annotations?%s">Liste des annotations</a></li>"""
|
f"""<li><a class="stdlink" href="groups_export_annotations?{groups_infos.groups_query_args}">Liste des annotations</a></li>"""
|
||||||
% groups_infos.groups_query_args,
|
if authuser.has_permission(Permission.ViewEtudData)
|
||||||
|
else """<li class="unauthorized" title="non autorisé">Liste des annotations</li>""",
|
||||||
"</ul>",
|
"</ul>",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -901,14 +926,19 @@ def tab_absences_html(groups_infos, etat=None):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
# Lien pour ajout fichiers étudiants
|
# Lien pour ajout fichiers étudiants
|
||||||
if authuser.has_permission(Permission.EtudAddAnnotations):
|
text = "Télécharger des fichiers associés aux étudiants (e.g. dossiers d'admission)"
|
||||||
|
if authuser.has_permission(
|
||||||
|
Permission.EtudAddAnnotations
|
||||||
|
) and authuser.has_permission(Permission.ViewEtudData):
|
||||||
H.append(
|
H.append(
|
||||||
f"""<li><a class="stdlink" href="{
|
f"""<li><a class="stdlink" href="{
|
||||||
url_for('scolar.etudarchive_import_files_form',
|
url_for('scolar.etudarchive_import_files_form',
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
group_id=group_id
|
group_id=group_id
|
||||||
)}">Télécharger des fichiers associés aux étudiants (e.g. dossiers d'admission)</a></li>"""
|
)}">{text}</a></li>"""
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
H.append(f"""<li class="unauthorized" title="non autorisé">{text}</li>""")
|
||||||
|
|
||||||
H.append("</ul></div>")
|
H.append("</ul></div>")
|
||||||
return "".join(H)
|
return "".join(H)
|
||||||
|
@ -198,7 +198,9 @@ def fiche_etud(etudid=None):
|
|||||||
info["etudfoto"] = etud.photo_html()
|
info["etudfoto"] = etud.photo_html()
|
||||||
|
|
||||||
# Champ dépendant des permissions:
|
# Champ dépendant des permissions:
|
||||||
if current_user.has_permission(Permission.EtudChangeAdr):
|
if current_user.has_permission(
|
||||||
|
Permission.EtudChangeAdr
|
||||||
|
) and current_user.has_permission(Permission.ViewEtudData):
|
||||||
info[
|
info[
|
||||||
"modifadresse"
|
"modifadresse"
|
||||||
] = f"""<a class="stdlink" href="{
|
] = f"""<a class="stdlink" href="{
|
||||||
@ -406,9 +408,13 @@ def fiche_etud(etudid=None):
|
|||||||
|
|
||||||
# Fichiers archivés:
|
# Fichiers archivés:
|
||||||
info["fichiers_archive_htm"] = (
|
info["fichiers_archive_htm"] = (
|
||||||
|
""
|
||||||
|
if restrict_etud_data
|
||||||
|
else (
|
||||||
'<div class="fichetitre">Fichiers associés</div>'
|
'<div class="fichetitre">Fichiers associés</div>'
|
||||||
+ sco_archives_etud.etud_list_archives_html(etud)
|
+ sco_archives_etud.etud_list_archives_html(etud)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Devenir de l'étudiant:
|
# Devenir de l'étudiant:
|
||||||
has_debouche = True
|
has_debouche = True
|
||||||
@ -713,7 +719,8 @@ def menus_etud(etudid):
|
|||||||
"title": "Changer les données identité/admission",
|
"title": "Changer les données identité/admission",
|
||||||
"endpoint": "scolar.etudident_edit_form",
|
"endpoint": "scolar.etudident_edit_form",
|
||||||
"args": {"etudid": etud["etudid"]},
|
"args": {"etudid": etud["etudid"]},
|
||||||
"enabled": authuser.has_permission(Permission.EtudInscrit),
|
"enabled": authuser.has_permission(Permission.EtudInscrit)
|
||||||
|
and authuser.has_permission(Permission.ViewEtudData),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Copier dans un autre département...",
|
"title": "Copier dans un autre département...",
|
||||||
@ -748,7 +755,7 @@ def etud_info_html(etudid, with_photo="1", debug=False):
|
|||||||
with_photo = int(with_photo)
|
with_photo = int(with_photo)
|
||||||
etud = Identite.get_etud(etudid)
|
etud = Identite.get_etud(etudid)
|
||||||
|
|
||||||
photo_html = etud.photo_html(etud, title="fiche de " + etud.nomprenom)
|
photo_html = etud.photo_html(title="fiche de " + etud.nomprenom)
|
||||||
code_cursus, _ = sco_report.get_code_cursus_etud(
|
code_cursus, _ = sco_report.get_code_cursus_etud(
|
||||||
etud, formsemestres=etud.get_formsemestres(), prefix="S", separator=", "
|
etud, formsemestres=etud.get_formsemestres(), prefix="S", separator=", "
|
||||||
)
|
)
|
||||||
@ -758,17 +765,21 @@ def etud_info_html(etudid, with_photo="1", debug=False):
|
|||||||
<div class="eid_left">
|
<div class="eid_left">
|
||||||
<div class="eid_nom"><div><a class="stdlink" target="_blank" href="{
|
<div class="eid_nom"><div><a class="stdlink" target="_blank" href="{
|
||||||
url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||||
}">{etud["nomprenom"]}</a></div></div>
|
}">{etud.nomprenom}</a></div></div>
|
||||||
<div class="eid_info eid_bac">Bac: <span class="eid_bac">{bac_abbrev}</span></div>
|
<div class="eid_info eid_bac">Bac: <span class="eid_bac">{bac_abbrev}</span></div>
|
||||||
<div class="eid_info eid_parcours">{code_cursus}</div>
|
<div class="eid_info eid_parcours">{code_cursus}</div>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Informations sur l'etudiant dans le semestre courant:
|
# Informations sur l'etudiant dans le semestre courant:
|
||||||
formsemestre = None
|
|
||||||
if formsemestre_id: # un semestre est spécifié par la page
|
if formsemestre_id: # un semestre est spécifié par la page
|
||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
elif inscription_courante: # le semestre "en cours" pour l'étudiant
|
else:
|
||||||
formsemestre = inscription_courante.formsemestre
|
# le semestre "en cours" pour l'étudiant
|
||||||
|
inscription_courante = etud.inscription_courante()
|
||||||
|
formsemestre = (
|
||||||
|
inscription_courante.formsemestre if inscription_courante else None
|
||||||
|
)
|
||||||
|
|
||||||
if formsemestre:
|
if formsemestre:
|
||||||
groups = sco_groups.get_etud_groups(etudid, formsemestre.id)
|
groups = sco_groups.get_etud_groups(etudid, formsemestre.id)
|
||||||
grc = sco_groups.listgroups_abbrev(groups)
|
grc = sco_groups.listgroups_abbrev(groups)
|
||||||
|
@ -37,7 +37,11 @@ _SCO_PERMISSIONS = (
|
|||||||
# aussi pour demissions, diplomes:
|
# aussi pour demissions, diplomes:
|
||||||
(1 << 17, "EtudInscrit", "Inscrire des étudiants"),
|
(1 << 17, "EtudInscrit", "Inscrire des étudiants"),
|
||||||
# aussi pour archives:
|
# aussi pour archives:
|
||||||
(1 << 18, "EtudAddAnnotations", "Éditer les annotations"),
|
(
|
||||||
|
1 << 18,
|
||||||
|
"EtudAddAnnotations",
|
||||||
|
"Éditer les annotations (et fichiers) sur étudiants",
|
||||||
|
),
|
||||||
# inutilisée (1 << 19, "ScoEntrepriseView", "Voir la section 'entreprises'"),
|
# inutilisée (1 << 19, "ScoEntrepriseView", "Voir la section 'entreprises'"),
|
||||||
# inutilisée (1 << 20, "EntrepriseChange", "Modifier les entreprises"),
|
# inutilisée (1 << 20, "EntrepriseChange", "Modifier les entreprises"),
|
||||||
# XXX inutilisée ? (1 << 21, "EditPVJury", "Éditer les PV de jury"),
|
# XXX inutilisée ? (1 << 21, "EditPVJury", "Éditer les PV de jury"),
|
||||||
|
@ -172,6 +172,11 @@ form#group_selector {
|
|||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Text lien ou itms ,non autorisés pour l'utilisateur courant */
|
||||||
|
.unauthorized {
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----- bandeau haut ------ */
|
/* ----- bandeau haut ------ */
|
||||||
span.bandeaugtr {
|
span.bandeaugtr {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -3230,7 +3230,7 @@ sco_publish(
|
|||||||
sco_publish(
|
sco_publish(
|
||||||
"/formsemestre_etuds_lycees",
|
"/formsemestre_etuds_lycees",
|
||||||
sco_lycee.formsemestre_etuds_lycees,
|
sco_lycee.formsemestre_etuds_lycees,
|
||||||
Permission.ScoView,
|
Permission.ViewEtudData,
|
||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/scodoc_table_etuds_lycees",
|
"/scodoc_table_etuds_lycees",
|
||||||
|
@ -442,7 +442,7 @@ sco_publish(
|
|||||||
sco_publish(
|
sco_publish(
|
||||||
"/groups_export_annotations",
|
"/groups_export_annotations",
|
||||||
sco_groups_exports.groups_export_annotations,
|
sco_groups_exports.groups_export_annotations,
|
||||||
Permission.ScoView,
|
Permission.ViewEtudData,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -630,27 +630,27 @@ sco_publish("/fiche_etud", sco_page_etud.fiche_etud, Permission.ScoView)
|
|||||||
sco_publish(
|
sco_publish(
|
||||||
"/etud_upload_file_form",
|
"/etud_upload_file_form",
|
||||||
sco_archives_etud.etud_upload_file_form,
|
sco_archives_etud.etud_upload_file_form,
|
||||||
Permission.ScoView,
|
Permission.ViewEtudData,
|
||||||
methods=["GET", "POST"],
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/etud_delete_archive",
|
"/etud_delete_archive",
|
||||||
sco_archives_etud.etud_delete_archive,
|
sco_archives_etud.etud_delete_archive,
|
||||||
Permission.ScoView,
|
Permission.ViewEtudData,
|
||||||
methods=["GET", "POST"],
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/etud_get_archived_file",
|
"/etud_get_archived_file",
|
||||||
sco_archives_etud.etud_get_archived_file,
|
sco_archives_etud.etud_get_archived_file,
|
||||||
Permission.ScoView,
|
Permission.ViewEtudData,
|
||||||
)
|
)
|
||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/etudarchive_import_files_form",
|
"/etudarchive_import_files_form",
|
||||||
sco_archives_etud.etudarchive_import_files_form,
|
sco_archives_etud.etudarchive_import_files_form,
|
||||||
Permission.ScoView,
|
Permission.ViewEtudData,
|
||||||
methods=["GET", "POST"],
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -758,6 +758,8 @@ def doSuppressAnnotation(etudid, annotation_id):
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def form_change_coordonnees(etudid):
|
def form_change_coordonnees(etudid):
|
||||||
"edit coordonnees etudiant"
|
"edit coordonnees etudiant"
|
||||||
|
if not current_user.has_permission(Permission.ViewEtudData):
|
||||||
|
raise ScoPermissionDenied()
|
||||||
etud = Identite.get_etud(etudid)
|
etud = Identite.get_etud(etudid)
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
adrs = sco_etud.adresse_list(cnx, {"etudid": etudid})
|
adrs = sco_etud.adresse_list(cnx, {"etudid": etudid})
|
||||||
@ -1344,6 +1346,8 @@ def etudident_create_form():
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def etudident_edit_form():
|
def etudident_edit_form():
|
||||||
"formulaire edition individuelle etudiant"
|
"formulaire edition individuelle etudiant"
|
||||||
|
if not current_user.has_permission(Permission.ViewEtudData):
|
||||||
|
raise ScoPermissionDenied()
|
||||||
return _etudident_create_or_edit_form(edit=True)
|
return _etudident_create_or_edit_form(edit=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ from tests.api.tools_test_api import (
|
|||||||
BULLETIN_UES_UE_RESSOURCES_RESSOURCE_FIELDS,
|
BULLETIN_UES_UE_RESSOURCES_RESSOURCE_FIELDS,
|
||||||
BULLETIN_UES_UE_SAES_SAE_FIELDS,
|
BULLETIN_UES_UE_SAES_SAE_FIELDS,
|
||||||
ETUD_FIELDS,
|
ETUD_FIELDS,
|
||||||
|
ETUD_FIELDS_RESTRICTED,
|
||||||
FSEM_FIELDS,
|
FSEM_FIELDS,
|
||||||
verify_fields,
|
verify_fields,
|
||||||
verify_occurences_ids_etuds,
|
verify_occurences_ids_etuds,
|
||||||
@ -113,7 +114,7 @@ def test_etudiants_courant(api_headers):
|
|||||||
assert len(etudiants) == 16 # HARDCODED
|
assert len(etudiants) == 16 # HARDCODED
|
||||||
|
|
||||||
etud = etudiants[-1]
|
etud = etudiants[-1]
|
||||||
assert verify_fields(etud, ETUD_FIELDS) is True
|
assert verify_fields(etud, ETUD_FIELDS_RESTRICTED) is True
|
||||||
assert re.match(r"^\d{4}-\d\d-\d\d$", etud["date_naissance"])
|
assert re.match(r"^\d{4}-\d\d-\d\d$", etud["date_naissance"])
|
||||||
|
|
||||||
|
|
||||||
@ -131,7 +132,7 @@ def test_etudiant(api_headers):
|
|||||||
)
|
)
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
etud = r.json()
|
etud = r.json()
|
||||||
assert verify_fields(etud, ETUD_FIELDS) is True
|
assert verify_fields(etud, ETUD_FIELDS_RESTRICTED) is True
|
||||||
|
|
||||||
code_nip = r.json()["code_nip"]
|
code_nip = r.json()["code_nip"]
|
||||||
code_ine = r.json()["code_ine"]
|
code_ine = r.json()["code_ine"]
|
||||||
@ -183,7 +184,7 @@ def test_etudiants(api_headers):
|
|||||||
|
|
||||||
assert isinstance(etud, list)
|
assert isinstance(etud, list)
|
||||||
assert len(etud) == 1
|
assert len(etud) == 1
|
||||||
fields_ok = verify_fields(etud[0], ETUD_FIELDS)
|
fields_ok = verify_fields(etud[0], ETUD_FIELDS_RESTRICTED)
|
||||||
assert fields_ok is True
|
assert fields_ok is True
|
||||||
|
|
||||||
######### Test code nip #########
|
######### Test code nip #########
|
||||||
@ -964,8 +965,10 @@ def test_etudiant_create(api_headers):
|
|||||||
assert etud["admission"]["commentaire"] == args["admission"]["commentaire"]
|
assert etud["admission"]["commentaire"] == args["admission"]["commentaire"]
|
||||||
assert etud["admission"]["annee_bac"] == args["admission"]["annee_bac"]
|
assert etud["admission"]["annee_bac"] == args["admission"]["annee_bac"]
|
||||||
assert len(etud["adresses"]) == 1
|
assert len(etud["adresses"]) == 1
|
||||||
assert etud["adresses"][0]["villedomicile"] == args["adresses"][0]["villedomicile"]
|
# cette fois les données perso ne sont pas publiées
|
||||||
assert etud["adresses"][0]["emailperso"] == args["adresses"][0]["emailperso"]
|
# assert etud["adresses"][0]["villedomicile"] == args["adresses"][0]["villedomicile"]
|
||||||
|
# assert etud["adresses"][0]["emailperso"] == args["adresses"][0]["emailperso"]
|
||||||
|
|
||||||
# Edition
|
# Edition
|
||||||
etud = POST_JSON(
|
etud = POST_JSON(
|
||||||
f"/etudiant/etudid/{etudid}/edit",
|
f"/etudiant/etudid/{etudid}/edit",
|
||||||
@ -981,8 +984,8 @@ def test_etudiant_create(api_headers):
|
|||||||
assert etud["admission"]["commentaire"] == args["admission"]["commentaire"]
|
assert etud["admission"]["commentaire"] == args["admission"]["commentaire"]
|
||||||
assert etud["admission"]["annee_bac"] == args["admission"]["annee_bac"]
|
assert etud["admission"]["annee_bac"] == args["admission"]["annee_bac"]
|
||||||
assert len(etud["adresses"]) == 1
|
assert len(etud["adresses"]) == 1
|
||||||
assert etud["adresses"][0]["villedomicile"] == args["adresses"][0]["villedomicile"]
|
# assert etud["adresses"][0]["villedomicile"] == args["adresses"][0]["villedomicile"]
|
||||||
assert etud["adresses"][0]["emailperso"] == args["adresses"][0]["emailperso"]
|
# assert etud["adresses"][0]["emailperso"] == args["adresses"][0]["emailperso"]
|
||||||
etud = POST_JSON(
|
etud = POST_JSON(
|
||||||
f"/etudiant/etudid/{etudid}/edit",
|
f"/etudiant/etudid/{etudid}/edit",
|
||||||
{
|
{
|
||||||
|
@ -44,10 +44,13 @@ DEPARTEMENT_FIELDS = [
|
|||||||
"date_creation",
|
"date_creation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Champs "données personnelles"
|
||||||
|
ETUD_FIELDS_RESTRICTED = {
|
||||||
|
"boursier",
|
||||||
|
}
|
||||||
ETUD_FIELDS = {
|
ETUD_FIELDS = {
|
||||||
"admission",
|
"admission",
|
||||||
"adresses",
|
"adresses",
|
||||||
"boursier",
|
|
||||||
"civilite",
|
"civilite",
|
||||||
"code_ine",
|
"code_ine",
|
||||||
"code_nip",
|
"code_nip",
|
||||||
@ -60,7 +63,8 @@ ETUD_FIELDS = {
|
|||||||
"nationalite",
|
"nationalite",
|
||||||
"nom",
|
"nom",
|
||||||
"prenom",
|
"prenom",
|
||||||
}
|
} | ETUD_FIELDS_RESTRICTED
|
||||||
|
|
||||||
|
|
||||||
FORMATION_FIELDS = {
|
FORMATION_FIELDS = {
|
||||||
"dept_id",
|
"dept_id",
|
||||||
|
Loading…
Reference in New Issue
Block a user