# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""ScoDoc ficheEtud
Fiche description d'un étudiant et de son parcours
"""
from flask import abort, url_for, g, render_template, request
from flask_login import current_user
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app import log
from app.but import cursus_but
from app.models.etudiants import Identite, make_etud_args
from app.models.formsemestre import FormSemestre
from app.scodoc import html_sco_header
from app.scodoc import htmlutils
from app.scodoc import sco_archives_etud
from app.scodoc import sco_bac
from app.scodoc import codes_cursus
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_status
from app.scodoc import sco_groups
from app.scodoc import sco_cursus
from app.scodoc import sco_permissions_check
from app.scodoc import sco_photos
from app.scodoc import sco_users
from app.scodoc import sco_report
from app.scodoc import sco_etud
from app.scodoc.sco_bulletins import etud_descr_situation_semestre
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_formsemestre_validation import formsemestre_recap_parcours_table
from app.scodoc.sco_permissions import Permission
def _menu_scolarite(authuser, sem: dict, etudid: int):
"""HTML pour menu "scolarite" pour un etudiant dans un semestre.
Le contenu du menu depend des droits de l'utilisateur et de l'état de l'étudiant.
"""
locked = not sem["etat"]
if locked:
lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
return lockicon # no menu
if not authuser.has_permission(
Permission.ScoEtudInscrit
) and not authuser.has_permission(Permission.ScoEtudChangeGroups):
return "" # no menu
ins = sem["ins"]
args = {"etudid": etudid, "formsemestre_id": ins["formsemestre_id"]}
if ins["etat"] != "D":
dem_title = "Démission"
dem_url = "scolar.form_dem"
else:
dem_title = "Annuler la démission"
dem_url = "scolar.do_cancel_dem"
# Note: seul un etudiant inscrit (I) peut devenir défaillant.
if ins["etat"] != codes_cursus.DEF:
def_title = "Déclarer défaillance"
def_url = "scolar.form_def"
elif ins["etat"] == codes_cursus.DEF:
def_title = "Annuler la défaillance"
def_url = "scolar.do_cancel_def"
def_enabled = (
(ins["etat"] != "D")
and authuser.has_permission(Permission.ScoEtudInscrit)
and not locked
)
items = [
{
"title": dem_title,
"endpoint": dem_url,
"args": args,
"enabled": authuser.has_permission(Permission.ScoEtudInscrit)
and not locked,
},
{
"title": "Validation du semestre (jury)",
"endpoint": "notes.formsemestre_validation_etud_form",
"args": args,
"enabled": authuser.has_permission(Permission.ScoEtudInscrit)
and not locked,
},
{
"title": def_title,
"endpoint": def_url,
"args": args,
"enabled": def_enabled,
},
{
"title": "Inscrire à un module optionnel (ou au sport)",
"endpoint": "notes.formsemestre_inscription_option",
"args": args,
"enabled": authuser.has_permission(Permission.ScoEtudInscrit)
and not locked,
},
{
"title": "Désinscrire (en cas d'erreur)",
"endpoint": "notes.formsemestre_desinscription",
"args": args,
"enabled": authuser.has_permission(Permission.ScoEtudInscrit)
and not locked,
},
{
"title": "Inscrire à un autre semestre",
"endpoint": "notes.formsemestre_inscription_with_modules_form",
"args": {"etudid": etudid},
"enabled": authuser.has_permission(Permission.ScoEtudInscrit),
},
{
"title": "Enregistrer un semestre effectué ailleurs",
"endpoint": "notes.formsemestre_ext_create_form",
"args": args,
"enabled": authuser.has_permission(Permission.ScoImplement),
},
{
"title": "Affecter les notes manquantes",
"endpoint": "notes.formsemestre_note_etuds_sans_notes",
"args": args,
"enabled": authuser.has_permission(Permission.ScoEditAllNotes),
},
]
return htmlutils.make_menu(
"Scolarité", items, css_class="direction_etud", alone=True
)
def ficheEtud(etudid=None):
"fiche d'informations sur un etudiant"
authuser = current_user
cnx = ndb.GetDBConnexion()
if etudid:
try: # pour les bookmarks avec d'anciens ids...
etudid = int(etudid)
except ValueError:
raise ScoValueError("id invalide !") from ValueError
# la sidebar est differente s'il y a ou pas un etudid
# voir html_sidebar.sidebar()
g.etudid = etudid
args = make_etud_args(etudid=etudid)
etuds = sco_etud.etudident_list(cnx, args)
if not etuds:
log(f"ficheEtud: etudid={etudid!r} request.args={request.args!r}")
raise ScoValueError("Étudiant inexistant !")
etud_ = etuds[0] # transition: etud_ à éliminer et remplacer par etud
etudid = etud_["etudid"]
etud = Identite.get_etud(etudid)
sco_etud.fill_etuds_info([etud_])
#
info = etud_
if etud.prenom_etat_civil:
info["etat_civil"] = (
"
Etat-civil: "
+ etud.civilite_etat_civil_str
+ " "
+ etud.prenom_etat_civil
+ " "
+ etud.nom
+ "
"
)
else:
info["etat_civil"] = ""
info["ScoURL"] = scu.ScoURL()
info["authuser"] = authuser
info["info_naissance"] = info["date_naissance"]
if info["lieu_naissance"]:
info["info_naissance"] += " à " + info["lieu_naissance"]
if info["dept_naissance"]:
info["info_naissance"] += f" ({info['dept_naissance']})"
info["etudfoto"] = sco_photos.etud_photo_html(etud_)
if (
(not info["domicile"])
and (not info["codepostaldomicile"])
and (not info["villedomicile"])
):
info["domicile"] = "inconnue"
if info["paysdomicile"]:
pays = sco_etud.format_pays(info["paysdomicile"])
if pays:
info["paysdomicile"] = "(%s)" % pays
else:
info["paysdomicile"] = ""
if info["telephone"] or info["telephonemobile"]:
info["telephones"] = "
%s %s" % (
info["telephonestr"],
info["telephonemobilestr"],
)
else:
info["telephones"] = ""
# e-mail:
if info["email_default"]:
info["emaillink"] = ", ".join(
[
'%s' % (m, m)
for m in [etud_["email"], etud_["emailperso"]]
if m
]
)
else:
info["emaillink"] = "(pas d'adresse e-mail)"
# Champ dépendant des permissions:
if authuser.has_permission(Permission.ScoEtudChangeAdr):
info[
"modifadresse"
] = f"""modifier adresse"""
else:
info["modifadresse"] = ""
# Groupes:
sco_groups.etud_add_group_infos(
info,
info["cursem"]["formsemestre_id"] if info["cursem"] else None,
only_to_show=True,
)
# Parcours de l'étudiant
if info["sems"]:
info["last_formsemestre_id"] = info["sems"][0]["formsemestre_id"]
else:
info["last_formsemestre_id"] = ""
sem_info = {}
for sem in info["sems"]:
if sem["ins"]["etat"] != scu.INSCRIT:
formsemestre: FormSemestre = FormSemestre.query.get(sem["formsemestre_id"])
descr, _ = etud_descr_situation_semestre(
etudid,
formsemestre,
info["ne"],
show_date_inscr=False,
)
grlink = f"""{descr["situation"]}"""
else:
e = {"etudid": etudid}
sco_groups.etud_add_group_infos(
e,
sem["formsemestre_id"],
only_to_show=True,
)
grlinks = []
for partition in e["partitions"].values():
if partition["partition_name"]:
gr_name = partition["group_name"]
else:
gr_name = "tous"
grlinks.append(
f"""{gr_name}
"""
)
grlink = ", ".join(grlinks)
# infos ajoutées au semestre dans le parcours (groupe, menu)
menu = _menu_scolarite(authuser, sem, etudid)
if menu:
sem_info[sem["formsemestre_id"]] = (
"" + grlink + " | " + menu + " |
"
)
else:
sem_info[sem["formsemestre_id"]] = grlink
if info["sems"]:
Se = sco_cursus.get_situation_etud_cursus(etud_, info["last_formsemestre_id"])
info["liste_inscriptions"] = formsemestre_recap_parcours_table(
Se,
etudid,
with_links=False,
sem_info=sem_info,
with_all_columns=False,
a_url="Notes/",
)
info[
"link_bul_pdf"
] = f"""tous les bulletins"""
if authuser.has_permission(Permission.ScoEtudInscrit):
info[
"link_inscrire_ailleurs"
] = f"""inscrire à un autre semestre
éditer toutes décisions de jury
"""
else:
info["link_inscrire_ailleurs"] = ""
else:
# non inscrit
l = [f"""Étudiant{info["ne"]} non inscrit{info["ne"]}"""]
if authuser.has_permission(Permission.ScoEtudInscrit):
l.append(
f"""inscrire"""
)
l.append("")
info["liste_inscriptions"] = "\n".join(l)
info["link_bul_pdf"] = ""
info["link_inscrire_ailleurs"] = ""
# Liste des annotations
alist = []
annos = sco_etud.etud_annotations_list(cnx, args={"etudid": etudid})
for a in annos:
if not sco_permissions_check.can_suppress_annotation(a["id"]):
a["dellink"] = ""
else:
a["dellink"] = (
'
%s | '
% (
etudid,
a["id"],
scu.icontag(
"delete_img",
border="0",
alt="suppress",
title="Supprimer cette annotation",
),
)
)
author = sco_users.user_info(a["author"])
alist.append(
f"""Le {a['date']} par {author['prenomnom']} :
{a['comment']} | {a['dellink']}
"""
)
info["liste_annotations"] = "\n".join(alist)
# fiche admission
has_adm_notes = (
info["math"] or info["physique"] or info["anglais"] or info["francais"]
)
has_bac_info = (
info["bac"]
or info["specialite"]
or info["annee_bac"]
or info["rapporteur"]
or info["commentaire"]
or info["classement"]
or info["type_admission"]
)
if has_bac_info or has_adm_notes:
adm_tmpl = """
Informations admission
"""
if has_adm_notes:
adm_tmpl += """
Bac | Année | Rg |
Math | Physique | Anglais | Français |
%(bac)s (%(specialite)s) |
%(annee_bac)s |
%(classement)s |
%(math)s | %(physique)s | %(anglais)s | %(francais)s |
"""
adm_tmpl += """
Bac %(bac)s (%(specialite)s) obtenu en %(annee_bac)s
%(ilycee)s
"""
if info["type_admission"] or info["classement"]:
adm_tmpl += """"""
if info["type_admission"]:
adm_tmpl += """Voie d'admission: %(type_admission)s """
if info["classement"]:
adm_tmpl += """Rang admission: %(classement)s"""
if info["type_admission"] or info["classement"]:
adm_tmpl += "
"
if info["rap"]:
adm_tmpl += """%(rap)s
"""
adm_tmpl += """"""
else:
adm_tmpl = "" # pas de boite "info admission"
info["adm_data"] = adm_tmpl % info
# Fichiers archivés:
info["fichiers_archive_htm"] = (
'Fichiers associés
'
+ sco_archives_etud.etud_list_archives_html(etudid)
)
# Devenir de l'étudiant:
has_debouche = True
if sco_permissions_check.can_edit_suivi():
suivi_readonly = "0"
link_add_suivi = """
ajouter une ligne
"""
else:
suivi_readonly = "1"
link_add_suivi = ""
if has_debouche:
info[
"debouche_html"
] = """""" % (
suivi_readonly,
info["etudid"],
link_add_suivi,
)
else:
info["debouche_html"] = "" # pas de boite "devenir"
#
if info["liste_annotations"]:
info["tit_anno"] = 'Annotations
'
else:
info["tit_anno"] = ""
# Inscriptions
info[
"inscriptions_mkup"
] = f"""
Cursus
{info["liste_inscriptions"]}
{info["link_bul_pdf"]} {info["link_inscrire_ailleurs"]}
"""
#
if info["groupes"].strip():
info[
"groupes_row"
] = f"""
Groupes : | {info['groupes']} |
"""
else:
info["groupes_row"] = ""
info["menus_etud"] = menus_etud(etudid)
if info["boursier"]:
info["bourse_span"] = """boursier"""
else:
info["bourse_span"] = ""
# raccordement provisoire pour juillet 2022, avant refonte complète de cette fiche...
# info["but_infos_mkup"] = jury_but_view.infos_fiche_etud_html(etudid)
# XXX dev
info["but_cursus_mkup"] = ""
if info["sems"]:
last_sem = FormSemestre.query.get_or_404(info["sems"][0]["formsemestre_id"])
if last_sem.formation.is_apc():
but_cursus = cursus_but.EtudCursusBUT(etud, last_sem.formation)
info["but_cursus_mkup"] = render_template(
"but/cursus_etud.j2",
cursus=but_cursus,
scu=scu,
)
tmpl = """
%(nomprenom)s (%(inscription)s)
%(etat_civil)s
%(emaillink)s
|
%(etudfoto)s
|
Situation : | %(situation)s %(bourse_span)s |
%(groupes_row)s
Né%(ne)s le : | %(info_naissance)s |
Adresse : | %(domicile)s %(codepostaldomicile)s %(villedomicile)s %(paysdomicile)s
%(modifadresse)s
%(telephones)s
|
%(inscriptions_mkup)s
%(but_cursus_mkup)s
%(adm_data)s
%(fichiers_archive_htm)s
%(debouche_html)s
code NIP: %(code_nip)s
"""
header = html_sco_header.sco_header(
page_title="Fiche étudiant %(prenom)s %(nom)s" % info,
cssstyles=[
"libjs/jQuery-tagEditor/jquery.tag-editor.css",
"css/jury_but.css",
"css/cursus_but.css",
],
javascripts=[
"libjs/jinplace-1.2.1.min.js",
"js/ue_list.js",
"libjs/jQuery-tagEditor/jquery.tag-editor.min.js",
"libjs/jQuery-tagEditor/jquery.caret.min.js",
"js/recap_parcours.js",
"js/etud_debouche.js",
],
)
return header + tmpl % info + html_sco_header.sco_footer()
def menus_etud(etudid):
"""Menu etudiant (operations sur l'etudiant)"""
authuser = current_user
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
menuEtud = [
{
"title": etud["nomprenom"],
"endpoint": "scolar.ficheEtud",
"args": {"etudid": etud["etudid"]},
"enabled": True,
"helpmsg": "Fiche étudiant",
},
{
"title": "Changer la photo",
"endpoint": "scolar.form_change_photo",
"args": {"etudid": etud["etudid"]},
"enabled": authuser.has_permission(Permission.ScoEtudChangeAdr),
},
{
"title": "Changer les données identité/admission",
"endpoint": "scolar.etudident_edit_form",
"args": {"etudid": etud["etudid"]},
"enabled": authuser.has_permission(Permission.ScoEtudInscrit),
},
{
"title": "Supprimer cet étudiant...",
"endpoint": "scolar.etudident_delete",
"args": {"etudid": etud["etudid"]},
"enabled": authuser.has_permission(Permission.ScoEtudInscrit),
},
{
"title": "Voir le journal...",
"endpoint": "scolar.showEtudLog",
"args": {"etudid": etud["etudid"]},
"enabled": True,
},
]
return htmlutils.make_menu("Étudiant", menuEtud, alone=True)
def etud_info_html(etudid, with_photo="1", debug=False):
"""An HTML div with basic information and links about this etud.
Used for popups information windows.
"""
formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request()
with_photo = int(with_photo)
etuds = sco_etud.get_etud_info(filled=True)
if etuds:
etud = etuds[0]
else:
abort(404, "etudiant inconnu")
photo_html = sco_photos.etud_photo_html(etud, title="fiche de " + etud["nom"])
# experimental: may be too slow to be here
code_cursus, _ = sco_report.get_code_cursus_etud(etud, prefix="S", separator=", ")
bac = sco_bac.Baccalaureat(etud["bac"], etud["specialite"])
bac_abbrev = bac.abbrev()
H = f"""
Bac: {bac_abbrev}
{code_cursus}
"""
# Informations sur l'etudiant dans le semestre courant:
sem = None
if formsemestre_id: # un semestre est spécifié par la page
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
elif etud["cursem"]: # le semestre "en cours" pour l'étudiant
sem = etud["cursem"]
if sem:
groups = sco_groups.get_etud_groups(etudid, formsemestre_id)
grc = sco_groups.listgroups_abbrev(groups)
H += f"""
En S{sem["semestre_id"]}: {grc}
"""
H += "
" # fin partie gauche (eid_left)
if with_photo:
H += '
' + photo_html + ""
H += "
"
if debug:
return (
html_sco_header.standard_html_header()
+ H
+ html_sco_header.standard_html_footer()
)
else:
return H