Dialogue affection groupe: template jinja2, début d'optimisation de XMLgetGroupsInPartition

This commit is contained in:
Emmanuel Viennet 2021-10-04 22:05:05 +02:00
parent 51bd6ba141
commit 54f0b87d39
12 changed files with 100 additions and 67 deletions

View File

@ -655,7 +655,7 @@ def log_unknown_etud():
def get_etud_info(etudid=False, code_nip=False, filled=False) -> list: def get_etud_info(etudid=False, code_nip=False, filled=False) -> list:
"""infos sur un etudiant (API). If not foud, returns empty list. """infos sur un etudiant (API). If not found, returns empty list.
On peut specifier etudid ou code_nip On peut specifier etudid ou code_nip
ou bien cherche dans les argumenst de la requête courante: ou bien cherche dans les argumenst de la requête courante:
etudid, code_nip, code_ine (dans cet ordre). etudid, code_nip, code_ine (dans cet ordre).
@ -671,6 +671,19 @@ def get_etud_info(etudid=False, code_nip=False, filled=False) -> list:
return etud return etud
# Optim par cache local, utilité non prouvée mais
# on s'oriente vers un cahce persistent dans Redis ou bien l'utilisation de NT
# def get_etud_info_filled_by_etudid(etudid, cnx=None) -> dict:
# """Infos sur un étudiant, avec cache local à la requête"""
# if etudid in g.stored_etud_info:
# return g.stored_etud_info[etudid]
# cnx = cnx or ndb.GetDBConnexion()
# etud = etudident_list(cnx, args={"etudid": etudid})
# fill_etuds_info(etud)
# g.stored_etud_info[etudid] = etud[0]
# return etud[0]
def create_etud(cnx, args={}): def create_etud(cnx, args={}):
"""Creation d'un étudiant. génère aussi évenement et "news". """Creation d'un étudiant. génère aussi évenement et "news".

View File

@ -95,6 +95,8 @@ _formsemestreEditor = ndb.EditableTable(
def get_formsemestre(formsemestre_id, raise_soft_exc=False): def get_formsemestre(formsemestre_id, raise_soft_exc=False):
"list ONE formsemestre" "list ONE formsemestre"
if formsemestre_id in g.stored_get_formsemestre:
return g.stored_get_formsemestre[formsemestre_id]
if not isinstance(formsemestre_id, int): if not isinstance(formsemestre_id, int):
raise ValueError("formsemestre_id must be an integer !") raise ValueError("formsemestre_id must be an integer !")
sems = do_formsemestre_list(args={"formsemestre_id": formsemestre_id}) sems = do_formsemestre_list(args={"formsemestre_id": formsemestre_id})
@ -104,6 +106,7 @@ def get_formsemestre(formsemestre_id, raise_soft_exc=False):
raise ScoValueError(f"semestre {formsemestre_id} inconnu !") raise ScoValueError(f"semestre {formsemestre_id} inconnu !")
else: else:
raise ValueError(f"semestre {formsemestre_id} inconnu !") raise ValueError(f"semestre {formsemestre_id} inconnu !")
g.stored_get_formsemestre[formsemestre_id] = sems[0]
return sems[0] return sems[0]

View File

@ -337,7 +337,7 @@ def formsemestre_status_menubar(sem):
submenu.append( submenu.append(
{ {
"title": "%s" % partition["partition_name"], "title": "%s" % partition["partition_name"],
"endpoint": "scolar.affectGroups", "endpoint": "scolar.affect_groups",
"args": {"partition_id": partition["partition_id"]}, "args": {"partition_id": partition["partition_id"]},
"enabled": enabled, "enabled": enabled,
} }
@ -507,7 +507,7 @@ def formsemestre_page_title():
h = f"""<div class="formsemestre_page_title"> h = f"""<div class="formsemestre_page_title">
<div class="infos"> <div class="infos">
<span class="semtitle"><a class="stdlink" title="%(session_id)s" <span class="semtitle"><a class="stdlink" title="{sem['session_id']}"
href="{url_for('notes.formsemestre_status', href="{url_for('notes.formsemestre_status',
scodoc_dept=g.scodoc_dept, formsemestre_id=sem['formsemestre_id'])}" scodoc_dept=g.scodoc_dept, formsemestre_id=sem['formsemestre_id'])}"
>{sem['titre']}</a><a >{sem['titre']}</a><a
@ -857,7 +857,7 @@ def _make_listes_sem(sem, with_absences=True):
H.append('<p class="help indent">Aucun groupe dans cette partition') H.append('<p class="help indent">Aucun groupe dans cette partition')
if sco_groups.sco_permissions_check.can_change_groups(formsemestre_id): if sco_groups.sco_permissions_check.can_change_groups(formsemestre_id):
H.append( H.append(
f""" (<a href="{url_for("scolar.affectGroups", f""" (<a href="{url_for("scolar.affect_groups",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
partition_id=partition["partition_id"]) partition_id=partition["partition_id"])
}" class="stdlink">créer</a>)""" }" class="stdlink">créer</a>)"""

View File

@ -492,6 +492,8 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD
""" """
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
cnx = ndb.GetDBConnexion()
t0 = time.time() t0 = time.time()
partition = get_partition(partition_id) partition = get_partition(partition_id)
formsemestre_id = partition["formsemestre_id"] formsemestre_id = partition["formsemestre_id"]
@ -500,6 +502,7 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > inscrdict nt = sco_cache.NotesTableCache.get(formsemestre_id) # > inscrdict
etuds_set = set(nt.inscrdict) etuds_set = set(nt.inscrdict)
# Build XML: # Build XML:
t1 = time.time()
doc = Element("ajax-response") doc = Element("ajax-response")
x_response = Element("response", type="object", id="MyUpdater") x_response = Element("response", type="object", id="MyUpdater")
doc.append(x_response) doc.append(x_response)
@ -513,7 +516,8 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD
) )
x_response.append(x_group) x_response.append(x_group)
for e in get_group_members(group["group_id"]): for e in get_group_members(group["group_id"]):
etud = sco_etud.get_etud_info(etudid=e["etudid"], filled=1)[0] etud = sco_etud.get_etud_info(etudid=e["etudid"], filled=True)[0]
# etud = sco_etud.get_etud_info_filled_by_etudid(e["etudid"], cnx)
x_group.append( x_group.append(
Element( Element(
"etud", "etud",
@ -540,6 +544,7 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD
doc.append(x_group) doc.append(x_group)
for etudid in etuds_set: for etudid in etuds_set:
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0] etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
# etud = sco_etud.get_etud_info_filled_by_etudid(etudid, cnx)
x_group.append( x_group.append(
Element( Element(
"etud", "etud",
@ -550,7 +555,8 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD
origin=comp_origin(etud, sem), origin=comp_origin(etud, sem),
) )
) )
log("XMLgetGroupsInPartition: %s seconds" % (time.time() - t0)) t2 = time.time()
log(f"XMLgetGroupsInPartition: {t2-t0} seconds ({t1-t0}+{t2-t1})")
# XML response: # XML response:
data = sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING) data = sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
response = make_response(data) response = make_response(data)
@ -911,7 +917,7 @@ def editPartitionForm(formsemestre_id=None):
H.append(", ".join(lg)) H.append(", ".join(lg))
H.append( H.append(
f"""</td><td><a class="stdlink" href="{ f"""</td><td><a class="stdlink" href="{
url_for("scolar.affectGroups", url_for("scolar.affect_groups",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
partition_id=p["partition_id"]) partition_id=p["partition_id"])
}">répartir</a></td> }">répartir</a></td>
@ -1173,7 +1179,7 @@ def group_set_name(group_id, group_name, redirect=1):
if redirect: if redirect:
return flask.redirect( return flask.redirect(
url_for( url_for(
"scolar.affectGroups", "scolar.affect_groups",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
partition_id=group["partition_id"], partition_id=group["partition_id"],
) )
@ -1216,7 +1222,7 @@ def group_rename(group_id):
elif tf[0] == -1: elif tf[0] == -1:
return flask.redirect( return flask.redirect(
url_for( url_for(
"scolar.affectGroups", "scolar.affect_groups",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
partition_id=group["partition_id"], partition_id=group["partition_id"],
) )
@ -1236,7 +1242,7 @@ def groups_auto_repartition(partition_id=None):
formsemestre_id = partition["formsemestre_id"] formsemestre_id = partition["formsemestre_id"]
# renvoie sur page édition groupes # renvoie sur page édition groupes
dest_url = url_for( dest_url = url_for(
"scolar.affectGroups", scodoc_dept=g.scodoc_dept, partition_id=partition_id "scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=partition_id
) )
if not sco_permissions_check.can_change_groups(formsemestre_id): if not sco_permissions_check.can_change_groups(formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")

View File

@ -27,70 +27,33 @@
"""Formulaires gestion des groupes """Formulaires gestion des groupes
""" """
from flask import render_template
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc.sco_exceptions import AccessDenied from app.scodoc.sco_exceptions import AccessDenied
def affectGroups(partition_id): def affect_groups(partition_id):
"""Formulaire affectation des etudiants aux groupes de la partition. """Formulaire affectation des etudiants aux groupes de la partition.
Permet aussi la creation et la suppression de groupes. Permet aussi la creation et la suppression de groupes.
""" """
# Ported from DTML and adapted to new group management (nov 2009) # réécrit pour 9.0.47 avec un template
partition = sco_groups.get_partition(partition_id) partition = sco_groups.get_partition(partition_id)
formsemestre_id = partition["formsemestre_id"] formsemestre_id = partition["formsemestre_id"]
if not sco_groups.sco_permissions_check.can_change_groups(formsemestre_id): if not sco_groups.sco_permissions_check.can_change_groups(formsemestre_id):
raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération") raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
return render_template(
H = [ "scolar/affect_groups.html",
html_sco_header.sco_header( sco_header=html_sco_header.sco_header(
page_title="Affectation aux groupes", page_title="Affectation aux groupes",
javascripts=["js/groupmgr.js"], javascripts=["js/groupmgr.js"],
cssstyles=["css/groups.css"], cssstyles=["css/groups.css"],
), ),
"""<h2 class="formsemestre">Affectation aux groupes de %s</h2><form id="sp">""" sco_footer=html_sco_header.sco_footer(),
% partition["partition_name"], partition=partition,
] partitions_list=sco_groups.get_partitions_list(
formsemestre_id, with_default=False
H += [ ),
"""</select></form>""", formsemestre_id=formsemestre_id,
"""<p>Faites glisser les étudiants d'un groupe à l'autre. Les modifications ne sont enregistrées que lorsque vous cliquez sur le bouton "<em>Enregistrer ces groupes</em>". Vous pouvez créer de nouveaux groupes. Pour <em>supprimer</em> un groupe, utiliser le lien "suppr." en haut à droite de sa boite. Vous pouvez aussi <a class="stdlink" href="groups_auto_repartition?partition_id=%(partition_id)s">répartir automatiquement les groupes</a>. )
</p>"""
% partition,
"""<div id="gmsg" class="head_message"></div>""",
"""<div id="ginfo"></div>""",
"""<div id="savedinfo"></div>""",
"""<form name="formGroup" id="formGroup" onSubmit="return false;">""",
"""<input type="hidden" name="partition_id" value="%s"/>""" % partition_id,
"""<input name="groupName" size="6"/>
<input type="button" onClick="createGroup();" value="Créer groupe"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" onClick="submitGroups( target='gmsg' );" value="Enregistrer ces groupes" />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" onClick="document.location = 'formsemestre_status?formsemestre_id=%s'" value="Annuler" />&nbsp;&nbsp;&nbsp;&nbsp;
Editer groupes de
<select name="other_partition_id" onchange="GotoAnother();">"""
% formsemestre_id,
]
for p in sco_groups.get_partitions_list(formsemestre_id, with_default=False):
H.append('<option value="%s"' % p["partition_id"])
if p["partition_id"] == partition_id:
H.append(" selected")
H.append(">%s</option>" % p["partition_name"])
H += [
"""</select>
</form>
<div id="groups">
</div>
<div style="clear: left; margin-top: 15px;">
<p class="help"></p>
</div>
</div>
""",
html_sco_header.sco_footer(),
]
return "\n".join(H)

View File

@ -390,7 +390,7 @@ def formsemestre_inscr_passage(
): # il y a au moins une vraie partition ): # il y a au moins une vraie partition
H.append( H.append(
f"""<li><a class="stdlink" href="{ f"""<li><a class="stdlink" href="{
url_for("scolar.affectGroups", url_for("scolar.affect_groups",
scodoc_dept=g.scodoc_dept, partition_id=partition["partition_id"]) scodoc_dept=g.scodoc_dept, partition_id=partition["partition_id"])
}">Répartir les groupes de {partition["partition_name"]}</a></li> }">Répartir les groupes de {partition["partition_name"]}</a></li>
""" """

View File

@ -315,7 +315,7 @@ def _make_table_notes(
rows.append( rows.append(
{ {
"code": code, "code": str(code), # INE, NIP ou etudid
"_code_td_attrs": 'style="padding-left: 1em; padding-right: 2em;"', "_code_td_attrs": 'style="padding-left: 1em; padding-right: 2em;"',
"etudid": etudid, "etudid": etudid,
"nom": etud["nom"].upper(), "nom": etud["nom"].upper(),
@ -376,7 +376,9 @@ def _make_table_notes(
if anonymous_listing: if anonymous_listing:
rows.sort(key=lambda x: x["code"]) rows.sort(key=lambda x: x["code"])
else: else:
rows.sort(key=lambda x: (x["nom"], x["prenom"])) # sort by nom, prenom rows.sort(
key=lambda x: (x["nom"] or "", x["prenom"] or "")
) # sort by nom, prenom
# Si module, ajoute moyenne du module: # Si module, ajoute moyenne du module:
if len(evals) > 1: if len(evals) > 1:

View File

@ -271,7 +271,7 @@ def formsemestre_synchro_etuds(
if partitions: # il y a au moins une vraie partition if partitions: # il y a au moins une vraie partition
H.append( H.append(
f"""<li><a class="stdlink" href="{ f"""<li><a class="stdlink" href="{
url_for("scolar.affectGroups", url_for("scolar.affect_groups",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
partition_id=partitions[0]["partition_id"] partition_id=partitions[0]["partition_id"]
)}">Répartir les groupes de {partitions[0]["partition_name"]}</a></li> )}">Répartir les groupes de {partitions[0]["partition_name"]}</a></li>

View File

@ -402,7 +402,7 @@ function GotoAnother() {
if (groups_unsaved) { if (groups_unsaved) {
alert("Enregistrez ou annulez vos changement avant !"); alert("Enregistrez ou annulez vos changement avant !");
} else } else
document.location = SCO_URL + '/affectGroups?partition_id=' + document.formGroup.other_partition_id.value; document.location = SCO_URL + '/affect_groups?partition_id=' + document.formGroup.other_partition_id.value;
} }

View File

@ -0,0 +1,43 @@
{{ sco_header|safe }}
<h2 class="formsemestre">Affectation aux groupes de {{ partition["partition_name"] }}</h2>
<p>Faites glisser les étudiants d'un groupe à l'autre. Les modifications ne
sont enregistrées que lorsque vous cliquez sur le bouton "<em>Enregistrer ces groupes</em>".
Vous pouvez créer de nouveaux groupes. Pour <em>supprimer</em> un groupe, utiliser le lien
"suppr." en haut à droite de sa boite.
Vous pouvez aussi <a class="stdlink"
href="{{ url_for('scolar.groups_auto_repartition', scodoc_dept=g.scodoc_dept, partition_id=partition['partition_id']) }}"
>répartir automatiquement les groupes</a>.
</p>
<div id="gmsg" class="head_message"></div>
<div id="ginfo"></div>
<div id="savedinfo"></div>
<form name="formGroup" id="formGroup" onSubmit="return false;">
<input type="hidden" name="partition_id" value="{{ partition['partition_id'] }}"/>
<input name="groupName" size="6"/>
<input type="button" onClick="createGroup();" value="Créer groupe"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" onClick="submitGroups( target='gmsg' );" value="Enregistrer ces groupes" />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button"
onClick="document.location = '{{ url_for( 'notes.formsemestre_status', scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id) }}'"
value="Annuler" />&nbsp;&nbsp;&nbsp;&nbsp;Éditer groupes de
<select name="other_partition_id" onchange="GotoAnother();">
{% for p in partitions_list %}
<option value="{{ p['id'] }}" {{"selected" if p["partition_id"] == partition_id }}>{{p["partition_name"]}}</option>
{% endfor %}
</select>
</form>
<div id="groups">
</div>
<div style="clear: left; margin-top: 15px;">
<p class="help"></p>
</div>
</div>
{{ sco_footer|safe }}

View File

@ -30,6 +30,9 @@ def start_scodoc_request():
if current_user.is_authenticated: if current_user.is_authenticated:
current_user.last_seen = datetime.datetime.utcnow() current_user.last_seen = datetime.datetime.utcnow()
db.session.commit() db.session.commit()
# caches locaux (durée de vie=la requête en cours)
g.stored_get_formsemestre = {}
# g.stored_etud_info = {} optim en cours, voir si utile
@scodoc_bp.teardown_app_request @scodoc_bp.teardown_app_request

View File

@ -651,8 +651,8 @@ def formChangeCoordonnees(etudid):
# --- Gestion des groupes: # --- Gestion des groupes:
sco_publish( sco_publish(
"/affectGroups", "/affect_groups",
sco_groups_edit.affectGroups, sco_groups_edit.affect_groups,
Permission.ScoView, Permission.ScoView,
methods=["GET", "POST"], methods=["GET", "POST"],
) )