ScoDoc/sco_find_etud.py

392 lines
13 KiB
Python

# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2021 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
#
##############################################################################
"""Recherche d'étudiants
"""
from types import ListType
import xml.dom.minidom
import sco_utils as scu
import notesdb as ndb
from notes_log import log
from gen_tables import GenTable
import scolars
import sco_formsemestre
import sco_groups
from sco_permissions import ScoView
def form_search_etud(
context,
REQUEST=None,
dest_url=None,
parameters=None,
parameters_keys=None,
title="Rechercher un étudiant par nom : ",
add_headers=False, # complete page
):
"form recherche par nom"
H = []
if title:
H.append("<h2>%s</h2>" % title)
H.append(
"""<form action="search_etud_in_dept" method="POST">
<b>%s</b>
<input type="text" name="expnom" id="search-student" width="12" spellcheck="false" value="">
<input type="submit" value="Chercher">
<br/>(entrer une partie du nom)
"""
% title
)
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:
for key in parameters_keys.split(","):
v = REQUEST.form.get(key, False)
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 (
context.sco_header(REQUEST, page_title="Choix d'un étudiant")
+ "\n".join(H)
+ context.sco_footer(REQUEST)
)
else:
return "\n".join(H)
def search_etud_in_dept(context, expnom="", REQUEST=None):
"""Page recherche d'un etudiant.
Affiche la fiche de l'étudiant, ou, si la recherche donne plusieurs résultats, la liste des étudianst
correspondants.
Appelée par boite de recherche barre latérale gauche.
Args:
expnom: string, regexp sur le nom ou un code_nip ou un etudid
"""
dest_url = "ficheEtud"
if len(expnom) > 1:
etuds = context.getEtudInfo(filled=1, etudid=expnom, REQUEST=REQUEST)
if len(etuds) != 1:
if scu.is_valid_code_nip(expnom):
etuds = search_etuds_infos(context, code_nip=expnom, REQUEST=REQUEST)
else:
etuds = search_etuds_infos(context, expnom=expnom, REQUEST=REQUEST)
else:
etuds = [] # si expnom est trop court, n'affiche rien
if len(etuds) == 1:
# va directement a la destination
return context.ficheEtud(etudid=etuds[0]["etudid"], REQUEST=REQUEST)
H = [
context.sco_header(
page_title="Recherche d'un étudiant",
no_side_bar=True,
init_qtip=True,
javascripts=["js/etud_info.js"],
REQUEST=REQUEST,
),
"""<h2>%d résultats pour "%s": choisissez un étudiant:</h2>"""
% (len(etuds), expnom),
form_search_etud(
context,
dest_url=dest_url,
REQUEST=REQUEST,
title="Autre recherche",
),
]
if len(etuds) > 0:
# Choix dans la liste des résultats:
for e in etuds:
target = dest_url + "?etudid=%s&" % e["etudid"]
e["_nomprenom_target"] = target
e["inscription_target"] = target
e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"])
sco_groups.etud_add_group_infos(context, e, e["cursem"])
tab = GenTable(
columns_ids=("nomprenom", "code_nip", "inscription", "groupes"),
titles={
"nomprenom": "Etudiant",
"code_nip": "NIP",
"inscription": "Inscription",
"groupes": "Groupes",
},
rows=etuds,
html_sortable=True,
html_class="table_leftalign",
preferences=context.get_preferences(),
)
H.append(tab.html())
if len(etuds) > 20: # si la page est grande
H.append(
form_search_etud(
context,
dest_url=dest_url,
REQUEST=REQUEST,
title="Autre recherche",
)
)
else:
H.append('<h2 id="title-no-result" style="color: red;">Aucun résultat pour "%s".</h2>' % expnom)
H.append(
"""<p class="help">La recherche porte sur tout ou partie du NOM ou du NIP de l'étudiant</p>"""
)
return "\n".join(H) + context.sco_footer(REQUEST)
# Was chercheEtudsInfo()
def search_etuds_infos(context, expnom=None, code_nip=None, REQUEST=None):
"""recherche les étudiants correspondants à expnom ou au code_nip
et ramene liste de mappings utilisables en DTML.
"""
may_be_nip = scu.is_valid_code_nip(expnom)
cnx = context.GetDBConnexion()
if expnom and not may_be_nip:
expnom = scu.strupper(expnom) # les noms dans la BD sont en uppercase
etuds = scolars.etudident_list(cnx, args={"nom": expnom}, test="~")
else:
code_nip = code_nip or expnom
if code_nip:
etuds = scolars.etudident_list(cnx, args={"code_nip": code_nip})
else:
etuds = []
context.fillEtudsInfo(etuds)
return etuds
def search_etud_by_name(context, term, REQUEST=None):
"""Recherche noms étudiants par début du nom, pour autocomplete
Accepte aussi un début de code NIP (au moins 6 caractères)
Renvoie une liste de nom en JSON
"""
may_be_nip = scu.is_valid_code_nip(term)
# term = scu.strupper(term) # conserve les accents
term = term.upper()
if (
not scu.ALPHANUM_EXP.match(
term.decode(scu.SCO_ENCODING)
) # n'autorise pas les caractères spéciaux
and not may_be_nip
):
data = []
else:
if may_be_nip:
r = ndb.SimpleDictFetch(
context,
"SELECT nom, prenom, code_nip FROM identite WHERE code_nip LIKE %(beginning)s ORDER BY nom",
{"beginning": term + "%"},
)
data = [
{
"label": "%s %s %s"
% (x["code_nip"], x["nom"], scolars.format_prenom(x["prenom"])),
"value": x["code_nip"],
}
for x in r
]
else:
r = ndb.SimpleDictFetch(
context,
"SELECT etudid, nom, prenom FROM identite WHERE nom LIKE %(beginning)s ORDER BY nom",
{"beginning": term + "%"},
)
data = [
{
"label": "%s %s" % (x["nom"], scolars.format_prenom(x["prenom"])),
"value": x["etudid"],
}
for x in r
]
# log(data)
return scu.sendJSON(REQUEST, data)
# ---------- Recherche sur plusieurs département
def form_search_etud_in_accessible_depts(context, REQUEST):
"""Form recherche etudiants pour page accueil ScoDoc"""
authuser = REQUEST.AUTHENTICATED_USER
# present form only to authenticated users
if not authuser.has_role("Authenticated"):
return ""
return """<form action="table_etud_in_accessible_depts" method="POST">
<b>Chercher étudiant:</b>
<input type="text" name="expnom" width="12" spellcheck="false" value="">
<input type="submit" value="Chercher">
<br/>(entrer une partie du nom ou le code NIP, cherche dans tous les départements autorisés)
"""
def can_view_dept(context, REQUEST):
"""True if auth user can access (View) this context"""
authuser = REQUEST.AUTHENTICATED_USER
return authuser.has_permission(ScoView, context)
def search_etud_in_accessible_depts(context, expnom=None, code_nip=None, REQUEST=None):
"""
context est le ZScoDoc
result is a list of (sorted) etuds, one list per dept.
"""
result = []
accessible_depts = []
deptList = context._list_depts() # definis dans Zope
for dept in deptList:
# log('%s searching %s' % (str(REQUEST.AUTHENTICATED_USER),dept))
if can_view_dept(dept, REQUEST):
if expnom or code_nip:
accessible_depts.append(dept.Scolarite.DeptId())
etuds = search_etuds_infos(
dept.Scolarite, expnom=expnom, code_nip=code_nip, REQUEST=REQUEST
)
else:
etuds = []
result.append(etuds)
return result, accessible_depts
def table_etud_in_accessible_depts(context, expnom=None, REQUEST=None):
"""
Page avec table étudiants trouvés, dans tous les departements.
Attention: nous sommes ici au niveau de ScoDoc, pas dans un département
"""
result, accessible_depts = search_etud_in_accessible_depts(
context, expnom=expnom, REQUEST=REQUEST
)
H = [
"""<div class="table_etud_in_accessible_depts">""",
"""<h3>Recherche multi-département de "<tt>%s</tt>"</h3>""" % expnom,
]
for etuds in result:
if etuds:
DeptId = etuds[0]["dept"]
# H.append('<h3>Département %s</h3>' % DeptId)
dest_url = DeptId + "/Scolarite/ficheEtud"
for e in etuds:
target = dest_url + "?etudid=%s" % e["etudid"]
e["_nomprenom_target"] = target
e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"])
tab = GenTable(
titles={"nomprenom": "Etudiants en " + DeptId},
columns_ids=("nomprenom",),
rows=etuds,
html_sortable=True,
html_class="table_leftalign",
)
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(
"""<p>(recherche menée dans le%s département%s: %s)</p><p>
<a href=".." class="stdlink">Retour à l'accueil</a></p>"""
% (ss, ss, ", ".join(accessible_depts))
)
H.append("</div>")
return (
context.scodoc_top_html_header(REQUEST, page_title="Choix d'un étudiant")
+ "\n".join(H)
+ context.standard_html_footer(REQUEST)
)
def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
"""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
"""
result, _ = search_etud_in_accessible_depts(
context, code_nip=code_nip, REQUEST=REQUEST
)
T = []
for etuds in result:
if etuds:
DeptId = etuds[0]["dept"]
for e in etuds:
for sem in e["sems"]:
T.append(
{
"dept": DeptId,
"etudid": e["etudid"],
"code_nip": e["code_nip"],
"civilite_str": e["civilite_str"],
"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",
"nom",
"prenom",
"formsemestre_id",
"date_debut_iso",
"date_fin_iso",
)
tab = GenTable(columns_ids=columns_ids, rows=T)
return tab.make_page(
context, format=format, with_html_headers=False, REQUEST=REQUEST, publish=True
)