ScoDoc/app/scodoc/sco_find_etud.py

458 lines
15 KiB
Python
Raw Permalink Normal View History

2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2023-12-31 23:04:06 +01:00
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# 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
#
##############################################################################
"""Recherche d'étudiants
"""
2021-08-01 10:16:16 +02:00
import flask
2021-08-22 13:24:36 +02:00
from flask import url_for, g, request
2021-07-28 09:51:18 +02:00
from flask_login import current_user
2020-09-26 16:19:37 +02:00
2021-08-13 00:34:58 +02:00
import app
2024-05-20 15:51:33 +02:00
from app.models import Departement, Identite
import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_etud
from app.scodoc import sco_groups
2022-02-26 20:11:22 +01:00
from app.scodoc.sco_exceptions import ScoException
from app.scodoc.sco_permissions import Permission
from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu
2020-09-26 16:19:37 +02:00
def form_search_etud(
dest_url=None,
parameters=None,
parameters_keys=None,
2021-08-13 00:34:58 +02:00
title="Rechercher un étudiant par nom : ",
2020-09-26 16:19:37 +02:00
add_headers=False, # complete page
):
"form recherche par nom"
H = []
H.append(
2024-05-20 15:51:33 +02:00
f"""<form action="{
url_for("scolar.search_etud_in_dept", scodoc_dept=g.scodoc_dept)
}" method="POST">
2021-07-13 14:53:14 +02:00
<b>{title}</b>
<input type="text" name="expnom" class="in-expnom" width="12" spellcheck="false" value="">
2020-09-26 16:19:37 +02:00
<input type="submit" value="Chercher">
<br>(entrer une partie du nom)
2020-09-26 16:19:37 +02:00
"""
)
if dest_url:
H.append('<input type="hidden" name="dest_url" value="%s"/>' % dest_url)
if parameters:
for param in parameters.keys():
H.append(
'<input type="hidden" name="%s" value="%s"/>'
% (param, parameters[param])
)
H.append(
'<input type="hidden" name="parameters_keys" value="%s"/>'
% (",".join(parameters.keys()))
)
elif parameters_keys:
2021-08-22 14:23:58 +02:00
if request.method == "POST":
vals = request.form
elif request.method == "GET":
vals = request.args
else:
vals = {}
2020-09-26 16:19:37 +02:00
for key in parameters_keys.split(","):
2021-08-22 13:24:36 +02:00
v = vals.get(key, False)
2020-09-26 16:19:37 +02:00
if v:
H.append('<input type="hidden" name="%s" value="%s"/>' % (key, v))
H.append(
'<input type="hidden" name="parameters_keys" value="%s"/>' % parameters_keys
)
H.append("</form>")
if add_headers:
return (
html_sco_header.sco_header(page_title="Choix d'un étudiant")
2020-09-26 16:19:37 +02:00
+ "\n".join(H)
+ html_sco_header.sco_footer()
2020-09-26 16:19:37 +02:00
)
else:
return "\n".join(H)
2024-05-20 15:51:33 +02:00
def search_etuds_infos_from_exp(expnom: str = "") -> list[Identite]:
2023-10-23 23:50:13 +02:00
"""Cherche étudiants, expnom peut être, dans cet ordre:
2024-05-20 15:51:33 +02:00
un etudid (int), un code NIP, ou une partie d'un nom (case insensitive).
2023-10-23 23:50:13 +02:00
"""
if not isinstance(expnom, int) and len(expnom) <= 1:
return [] # si expnom est trop court, n'affiche rien
try:
etudid = int(expnom)
except ValueError:
etudid = None
if etudid is not None:
2024-05-20 15:51:33 +02:00
etud = Identite.query.filter_by(dept_id=g.scodoc_dept_id, id=etudid).first()
if etud:
return [etud]
2023-10-23 23:50:13 +02:00
expnom_str = str(expnom)
if scu.is_valid_code_nip(expnom_str):
2024-05-20 15:51:33 +02:00
etuds = Identite.query.filter_by(
dept_id=g.scodoc_dept_id, code_nip=expnom_str
).all()
if etuds:
return etuds
return (
Identite.query.filter_by(dept_id=g.scodoc_dept_id)
.filter(Identite.nom.op("~*")(expnom_str))
.all()
)
2023-10-23 23:50:13 +02:00
2021-08-22 14:23:58 +02:00
def search_etud_in_dept(expnom=""):
2021-02-18 08:07:21 +01:00
"""Page recherche d'un etudiant.
2020-09-26 16:19:37 +02:00
2021-07-28 09:51:18 +02:00
Affiche la fiche de l'étudiant, ou, si la recherche donne plusieurs résultats,
la liste des étudiants correspondants.
2021-08-22 14:23:58 +02:00
Appelée par:
- boite de recherche barre latérale gauche.
- choix d'un étudiant à inscrire (en POST avec dest_url et parameters_keys)
2020-09-26 16:19:37 +02:00
2021-02-18 08:07:21 +01:00
Args:
expnom: string, regexp sur le nom ou un code_nip ou un etudid
"""
2023-10-23 23:50:13 +02:00
etuds = search_etuds_infos_from_exp(expnom)
2021-02-18 08:07:21 +01:00
2021-08-22 14:23:58 +02:00
if request.method == "POST":
vals = request.form
elif request.method == "GET":
vals = request.args
else:
vals = {}
url_args = {"scodoc_dept": g.scodoc_dept}
if "dest_url" in vals:
endpoint = vals["dest_url"]
2021-08-22 14:23:58 +02:00
else:
endpoint = "scolar.fiche_etud"
if "parameters_keys" in vals:
2021-08-22 14:23:58 +02:00
for key in vals["parameters_keys"].split(","):
url_args[key] = vals[key]
2020-09-26 16:19:37 +02:00
if len(etuds) == 1:
2021-06-14 18:08:52 +02:00
# va directement a la fiche
2024-05-20 15:51:33 +02:00
url_args["etudid"] = etuds[0].id
2021-08-22 14:23:58 +02:00
return flask.redirect(url_for(endpoint, **url_args))
2021-02-18 08:07:21 +01:00
H = [
2021-06-13 19:12:20 +02:00
html_sco_header.sco_header(
2021-02-18 08:07:21 +01:00
page_title="Recherche d'un étudiant",
2021-09-09 08:03:43 +02:00
no_side_bar=False,
2021-02-18 08:07:21 +01:00
init_qtip=True,
javascripts=["js/etud_info.js"],
2021-08-22 14:23:58 +02:00
)
]
if len(etuds) == 0 and len(etuds) <= 1:
H.append("""<h2>chercher un étudiant:</h2>""")
else:
H.append(
f"""<h2>{len(etuds)} résultats pour "<tt>{expnom}</tt>": choisissez un étudiant:</h2>"""
)
H.append(
2021-02-18 08:07:21 +01:00
form_search_etud(
2021-08-22 14:23:58 +02:00
dest_url=endpoint,
parameters=vals.get("parameters"),
parameters_keys=vals.get("parameters_keys"),
2021-02-18 08:07:21 +01:00
title="Autre recherche",
2021-08-22 14:23:58 +02:00
)
)
2020-09-26 16:19:37 +02:00
if len(etuds) > 0:
# Choix dans la liste des résultats:
2024-05-20 15:51:33 +02:00
rows = []
e: Identite
2020-09-26 16:19:37 +02:00
for e in etuds:
2024-05-20 15:51:33 +02:00
url_args["etudid"] = e.id
2021-08-22 14:23:58 +02:00
target = url_for(endpoint, **url_args)
2024-05-20 15:51:33 +02:00
cur_inscription = e.inscription_courante()
inscription = (
e.inscription_descr().get("inscription_str", "")
if cur_inscription
else ""
)
groupes = (
", ".join(
gr.group_name
for gr in sco_groups.get_etud_formsemestre_groups(
e, cur_inscription.formsemestre
)
)
if cur_inscription
else ""
)
rows.append(
{
"code_nip": e.code_nip or "",
"etudid": e.id,
"inscription": inscription,
"inscription_target": target,
"groupes": groupes,
"nomprenom": e.nomprenom,
"_nomprenom_target": target,
"_nomprenom_td_attrs": f'id="{e.id}" class="etudinfo"',
}
2022-03-05 12:47:08 +01:00
)
2020-09-26 16:19:37 +02:00
tab = GenTable(
columns_ids=("nomprenom", "code_nip", "inscription", "groupes"),
titles={
"nomprenom": "Étudiant",
2020-09-26 16:19:37 +02:00
"code_nip": "NIP",
"inscription": "Inscription",
"groupes": "Groupes",
},
2024-05-20 15:51:33 +02:00
rows=rows,
2020-09-26 16:19:37 +02:00
html_sortable=True,
html_class="table_leftalign",
preferences=sco_preferences.SemPreferences(),
table_id="search_etud_in_dept",
2020-09-26 16:19:37 +02:00
)
H.append(tab.html())
if len(etuds) > 20: # si la page est grande
H.append(
form_search_etud(
2021-08-22 14:23:58 +02:00
dest_url=endpoint,
parameters=vals.get("parameters"),
parameters_keys=vals.get("parameters_keys"),
2020-09-26 16:19:37 +02:00
title="Autre recherche",
)
)
else:
2024-05-20 15:51:33 +02:00
H.append(f'<h2 style="color: red;">Aucun résultat pour "{expnom}".</h2>')
2020-09-26 16:19:37 +02:00
H.append(
2024-05-20 15:51:33 +02:00
"""<p class="help">La recherche porte sur tout ou partie du NOM ou du NIP
de l'étudiant. Saisir au moins deux caractères.</p>"""
2020-09-26 16:19:37 +02:00
)
return "\n".join(H) + html_sco_header.sco_footer()
2020-09-26 16:19:37 +02:00
# Was chercheEtudsInfo()
2024-05-20 15:51:33 +02:00
def search_etuds_infos(expnom=None, code_nip=None) -> list[dict]:
2020-09-26 16:19:37 +02:00
"""recherche les étudiants correspondants à expnom ou au code_nip
2021-01-01 18:40:47 +01:00
et ramene liste de mappings utilisables en DTML.
2020-09-26 16:19:37 +02:00
"""
2021-02-04 20:02:44 +01:00
may_be_nip = scu.is_valid_code_nip(expnom)
2021-06-15 13:59:56 +02:00
cnx = ndb.GetDBConnexion()
2020-09-26 16:19:37 +02:00
if expnom and not may_be_nip:
expnom = expnom.upper() # les noms dans la BD sont en uppercase
2022-02-26 20:11:22 +01:00
try:
etuds = sco_etud.etudident_list(cnx, args={"nom": expnom}, test="~")
except ScoException:
etuds = []
2020-09-26 16:19:37 +02:00
else:
code_nip = code_nip or expnom
if code_nip:
etuds = sco_etud.etudident_list(cnx, args={"code_nip": str(code_nip)})
2020-09-26 16:19:37 +02:00
else:
etuds = []
sco_etud.fill_etuds_info(etuds)
2020-09-26 16:19:37 +02:00
return etuds
2021-08-31 08:21:30 +02:00
def search_etud_by_name(term: str) -> list:
2020-09-26 16:19:37 +02:00
"""Recherche noms étudiants par début du nom, pour autocomplete
Accepte aussi un début de code NIP (au moins 6 caractères)
2021-08-31 08:21:30 +02:00
Renvoie une liste de dicts
{ "label" : "<nip> <nom> <prenom>", "value" : etudid }
2020-09-26 16:19:37 +02:00
"""
2021-02-04 20:02:44 +01:00
may_be_nip = scu.is_valid_code_nip(term)
# term = term.upper() # conserve les accents
2020-09-26 16:19:37 +02:00
term = term.upper()
if (
2021-07-12 15:13:10 +02:00
not scu.ALPHANUM_EXP.match(term) # n'autorise pas les caractères spéciaux
2020-09-26 16:19:37 +02:00
and not may_be_nip
):
data = []
else:
if may_be_nip:
2021-02-03 22:00:41 +01:00
r = ndb.SimpleDictFetch(
"""SELECT nom, prenom, code_nip
FROM identite
2021-09-09 08:03:43 +02:00
WHERE
2023-10-23 23:50:13 +02:00
dept_id = %(dept_id)s
2024-05-24 15:37:07 +02:00
AND code_nip ILIKE %(beginning)s
2021-09-09 08:03:43 +02:00
ORDER BY nom
""",
2021-09-09 08:03:43 +02:00
{"beginning": term + "%", "dept_id": g.scodoc_dept_id},
2020-09-26 16:19:37 +02:00
)
data = [
{
"label": "%s %s %s"
% (x["code_nip"], x["nom"], scu.format_prenom(x["prenom"])),
2020-09-26 16:19:37 +02:00
"value": x["code_nip"],
}
for x in r
]
else:
2021-02-03 22:00:41 +01:00
r = ndb.SimpleDictFetch(
2021-08-31 08:21:30 +02:00
"""SELECT id AS etudid, nom, prenom
FROM identite
2023-10-23 23:50:13 +02:00
WHERE
dept_id = %(dept_id)s
2024-05-24 15:37:07 +02:00
AND nom ILIKE %(beginning)s
ORDER BY nom
""",
2021-09-09 08:03:43 +02:00
{"beginning": term + "%", "dept_id": g.scodoc_dept_id},
2020-09-26 16:19:37 +02:00
)
data = [
{
"label": "%s %s" % (x["nom"], scu.format_prenom(x["prenom"])),
2021-02-16 22:07:56 +01:00
"value": x["etudid"],
2020-09-26 16:19:37 +02:00
}
for x in r
]
2021-08-31 08:21:30 +02:00
return data
2020-09-26 16:19:37 +02:00
# ---------- Recherche sur plusieurs département
2021-07-28 09:51:18 +02:00
def search_etud_in_accessible_depts(expnom=None, code_nip=None):
2020-09-26 16:19:37 +02:00
"""
result is a list of (sorted) etuds, one list per dept.
"""
result = []
accessible_depts = []
depts = Departement.query.filter_by(visible=True).all()
2021-06-21 11:22:55 +02:00
for dept in depts:
if current_user.has_permission(Permission.ScoView, dept=dept.acronym):
2020-09-26 16:19:37 +02:00
if expnom or code_nip:
accessible_depts.append(dept.acronym)
app.set_sco_dept(dept.acronym)
2021-07-28 09:51:18 +02:00
etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip)
2020-09-26 16:19:37 +02:00
else:
etuds = []
result.append(etuds)
return result, accessible_depts
2021-07-28 09:51:18 +02:00
def table_etud_in_accessible_depts(expnom=None):
2020-09-26 16:19:37 +02:00
"""
Page avec table étudiants trouvés, dans tous les departements.
Attention: nous sommes ici au niveau de ScoDoc, pas dans un département
"""
2021-07-28 09:51:18 +02:00
result, accessible_depts = search_etud_in_accessible_depts(expnom=expnom)
2020-09-26 16:19:37 +02:00
H = [
f"""<div class="table_etud_in_accessible_depts">
<h3>Recherche multi-département de "<tt>{expnom}</tt>"</h3>
""",
2020-09-26 16:19:37 +02:00
]
for etuds in result:
if etuds:
dept_id = etuds[0]["dept"]
2020-09-26 16:19:37 +02:00
# H.append('<h3>Département %s</h3>' % DeptId)
for e in etuds:
e["_nomprenom_target"] = url_for(
"scolar.fiche_etud", scodoc_dept=dept_id, etudid=e["etudid"]
)
e["_nomprenom_td_attrs"] = f"""id="{e['etudid']}" class="etudinfo" """
2020-09-26 16:19:37 +02:00
tab = GenTable(
titles={"nomprenom": "Étudiants en " + dept_id},
2020-09-26 16:19:37 +02:00
columns_ids=("nomprenom",),
rows=etuds,
html_sortable=True,
html_class="table_leftalign",
table_id="etud_in_accessible_depts",
2020-09-26 16:19:37 +02:00
)
H.append('<div class="table_etud_in_dept">')
H.append(tab.html())
H.append("</div>")
if len(accessible_depts) > 1:
ss = "s"
else:
ss = ""
H.append(
2023-10-23 23:50:13 +02:00
f"""<p>(recherche menée dans le{ss} département{ss}:
2021-07-28 09:51:18 +02:00
{", ".join(accessible_depts)})
</p>
<p>
<a href="{url_for("scodoc.index")}" class="stdlink">Retour à l'accueil</a>
</p>
</div>
"""
2020-09-26 16:19:37 +02:00
)
return (
html_sco_header.scodoc_top_html_header(page_title="Choix d'un étudiant")
2020-09-26 16:19:37 +02:00
+ "\n".join(H)
2021-06-13 18:29:53 +02:00
+ html_sco_header.standard_html_footer()
2020-09-26 16:19:37 +02:00
)
def search_inscr_etud_by_nip(code_nip, fmt="json"):
2020-09-26 16:19:37 +02:00
"""Recherche multi-departement d'un étudiant par son code NIP
Seuls les départements accessibles par l'utilisateur sont cherchés.
Renvoie une liste des inscriptions de l'étudiants dans tout ScoDoc:
code_nip, nom, prenom, civilite_str, dept, formsemestre_id, date_debut_sem, date_fin_sem
2020-09-26 16:19:37 +02:00
"""
result, _ = search_etud_in_accessible_depts(code_nip=code_nip)
2020-09-26 16:19:37 +02:00
rows = []
2020-09-26 16:19:37 +02:00
for etuds in result:
if etuds:
dept_id = etuds[0]["dept"]
2020-09-26 16:19:37 +02:00
for e in etuds:
for sem in e["sems"]:
rows.append(
2020-09-26 16:19:37 +02:00
{
"dept": dept_id,
2020-09-26 16:19:37 +02:00
"etudid": e["etudid"],
"code_nip": e["code_nip"],
"civilite_str": e["civilite_str"],
2020-09-26 16:19:37 +02:00
"nom": e["nom"],
"prenom": e["prenom"],
"formsemestre_id": sem["formsemestre_id"],
"date_debut_iso": sem["date_debut_iso"],
"date_fin_iso": sem["date_fin_iso"],
}
)
columns_ids = (
"dept",
"etudid",
"code_nip",
"civilite_str",
2020-09-26 16:19:37 +02:00
"nom",
"prenom",
"formsemestre_id",
"date_debut_iso",
"date_fin_iso",
)
tab = GenTable(columns_ids=columns_ids, rows=rows, table_id="inscr_etud_by_nip")
2020-09-26 16:19:37 +02:00
return tab.make_page(fmt=fmt, with_html_headers=False, publish=True)