diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py index 8e35b4081efe2adb6b0e100ac3a45ff4eacff723..53d68f9630f719d9c128bf50f7c50970f4348e0d 100644 --- a/app/scodoc/sco_etud.py +++ b/app/scodoc/sco_etud.py @@ -655,7 +655,7 @@ def log_unknown_etud(): 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 ou bien cherche dans les argumenst de la requête courante: 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 +# 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={}): """Creation d'un étudiant. génère aussi évenement et "news". diff --git a/app/scodoc/sco_formsemestre.py b/app/scodoc/sco_formsemestre.py index 2cb9d67704a12e1e193590551cace0208dd697c2..e65a920590ecfbf41442a87ba2ff1d4f4c6b52b7 100644 --- a/app/scodoc/sco_formsemestre.py +++ b/app/scodoc/sco_formsemestre.py @@ -95,6 +95,8 @@ _formsemestreEditor = ndb.EditableTable( def get_formsemestre(formsemestre_id, raise_soft_exc=False): "list ONE formsemestre" + if formsemestre_id in g.stored_get_formsemestre: + return g.stored_get_formsemestre[formsemestre_id] if not isinstance(formsemestre_id, int): raise ValueError("formsemestre_id must be an integer !") 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 !") else: raise ValueError(f"semestre {formsemestre_id} inconnu !") + g.stored_get_formsemestre[formsemestre_id] = sems[0] return sems[0] diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index fe8decb0076c79a41d5e74b44132fd64b6a7f502..5aa948e43214aa8f410b7ab21f0fc5afa08fca85 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -337,7 +337,7 @@ def formsemestre_status_menubar(sem): submenu.append( { "title": "%s" % partition["partition_name"], - "endpoint": "scolar.affectGroups", + "endpoint": "scolar.affect_groups", "args": {"partition_id": partition["partition_id"]}, "enabled": enabled, } @@ -507,7 +507,7 @@ def formsemestre_page_title(): h = f"""<div class="formsemestre_page_title"> <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', scodoc_dept=g.scodoc_dept, formsemestre_id=sem['formsemestre_id'])}" >{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') if sco_groups.sco_permissions_check.can_change_groups(formsemestre_id): H.append( - f""" (<a href="{url_for("scolar.affectGroups", + f""" (<a href="{url_for("scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=partition["partition_id"]) }" class="stdlink">créer</a>)""" diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py index 6512f1feb5370fef27fc7abc07e09a8b576a14d1..0a776813c083cbcb513ae10a9ffb2e41ce976b1c 100644 --- a/app/scodoc/sco_groups.py +++ b/app/scodoc/sco_groups.py @@ -492,6 +492,8 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD """ from app.scodoc import sco_formsemestre + cnx = ndb.GetDBConnexion() + t0 = time.time() partition = get_partition(partition_id) formsemestre_id = partition["formsemestre_id"] @@ -500,6 +502,7 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD nt = sco_cache.NotesTableCache.get(formsemestre_id) # > inscrdict etuds_set = set(nt.inscrdict) # Build XML: + t1 = time.time() doc = Element("ajax-response") x_response = Element("response", type="object", id="MyUpdater") doc.append(x_response) @@ -513,7 +516,8 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD ) x_response.append(x_group) 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( Element( "etud", @@ -540,6 +544,7 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD doc.append(x_group) for etudid in etuds_set: 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( Element( "etud", @@ -550,7 +555,8 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD 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: data = sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING) response = make_response(data) @@ -911,7 +917,7 @@ def editPartitionForm(formsemestre_id=None): H.append(", ".join(lg)) H.append( f"""</td><td><a class="stdlink" href="{ - url_for("scolar.affectGroups", + url_for("scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=p["partition_id"]) }">répartir</a></td> @@ -1173,7 +1179,7 @@ def group_set_name(group_id, group_name, redirect=1): if redirect: return flask.redirect( url_for( - "scolar.affectGroups", + "scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=group["partition_id"], ) @@ -1216,7 +1222,7 @@ def group_rename(group_id): elif tf[0] == -1: return flask.redirect( url_for( - "scolar.affectGroups", + "scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=group["partition_id"], ) @@ -1236,7 +1242,7 @@ def groups_auto_repartition(partition_id=None): formsemestre_id = partition["formsemestre_id"] # renvoie sur page édition groupes 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): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") diff --git a/app/scodoc/sco_groups_edit.py b/app/scodoc/sco_groups_edit.py index 75eb12b496465898cd345d8bf2bfe8740b422fd8..bc41969006695ceb847c1f694d69552f9c66670e 100644 --- a/app/scodoc/sco_groups_edit.py +++ b/app/scodoc/sco_groups_edit.py @@ -27,70 +27,33 @@ """Formulaires gestion des groupes """ +from flask import render_template from app.scodoc import html_sco_header from app.scodoc import sco_groups 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. 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) formsemestre_id = partition["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") - - H = [ - html_sco_header.sco_header( + return render_template( + "scolar/affect_groups.html", + sco_header=html_sco_header.sco_header( page_title="Affectation aux groupes", javascripts=["js/groupmgr.js"], cssstyles=["css/groups.css"], ), - """<h2 class="formsemestre">Affectation aux groupes de %s</h2><form id="sp">""" - % partition["partition_name"], - ] - - H += [ - """</select></form>""", - """<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"/> - -<input type="button" onClick="submitGroups( target='gmsg' );" value="Enregistrer ces groupes" /> - -<input type="button" onClick="document.location = 'formsemestre_status?formsemestre_id=%s'" value="Annuler" /> -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) + sco_footer=html_sco_header.sco_footer(), + partition=partition, + partitions_list=sco_groups.get_partitions_list( + formsemestre_id, with_default=False + ), + formsemestre_id=formsemestre_id, + ) diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py index 4fb8c57acc9c6d67f41da937bbcb72be857bae18..cc91728485e411f174df660fd4ddf9880ea26cf3 100644 --- a/app/scodoc/sco_inscr_passage.py +++ b/app/scodoc/sco_inscr_passage.py @@ -390,7 +390,7 @@ def formsemestre_inscr_passage( ): # il y a au moins une vraie partition H.append( 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"]) }">Répartir les groupes de {partition["partition_name"]}</a></li> """ diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index c2ac6691e762a4f73918d7ce37f09c127f51bfd4..a263ac79972ac95e4cbba9582b9df6143bf4bfdb 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -315,7 +315,7 @@ def _make_table_notes( rows.append( { - "code": code, + "code": str(code), # INE, NIP ou etudid "_code_td_attrs": 'style="padding-left: 1em; padding-right: 2em;"', "etudid": etudid, "nom": etud["nom"].upper(), @@ -376,7 +376,9 @@ def _make_table_notes( if anonymous_listing: rows.sort(key=lambda x: x["code"]) 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: if len(evals) > 1: diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py index 649358a6d382d0af2ac99a3c0667f1aa345492ec..c91ccf6d3d5a10e42074cdc30626ec061515dae6 100644 --- a/app/scodoc/sco_synchro_etuds.py +++ b/app/scodoc/sco_synchro_etuds.py @@ -271,7 +271,7 @@ def formsemestre_synchro_etuds( if partitions: # il y a au moins une vraie partition H.append( f"""<li><a class="stdlink" href="{ - url_for("scolar.affectGroups", + url_for("scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=partitions[0]["partition_id"] )}">Répartir les groupes de {partitions[0]["partition_name"]}</a></li> diff --git a/app/static/js/groupmgr.js b/app/static/js/groupmgr.js index 7d16adc9b1e346c0d72b47a5abcc7452351dd985..de0e512d7b1d5e9a8695704fa04d0161ff9fe30c 100644 --- a/app/static/js/groupmgr.js +++ b/app/static/js/groupmgr.js @@ -402,7 +402,7 @@ function GotoAnother() { if (groups_unsaved) { alert("Enregistrez ou annulez vos changement avant !"); } 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; } diff --git a/app/templates/scolar/affect_groups.html b/app/templates/scolar/affect_groups.html new file mode 100644 index 0000000000000000000000000000000000000000..4d17847e67464d21422275e9f4624befccc2f232 --- /dev/null +++ b/app/templates/scolar/affect_groups.html @@ -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"/> + +<input type="button" onClick="submitGroups( target='gmsg' );" value="Enregistrer ces groupes" /> + +<input type="button" + onClick="document.location = '{{ url_for( 'notes.formsemestre_status', scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id) }}'" + value="Annuler" /> É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 }} diff --git a/app/views/__init__.py b/app/views/__init__.py index a2dae02fe74fa02c397c9b678bb23af725448027..9dbefc44513de034d68f263a27a8c9f3474c7931 100644 --- a/app/views/__init__.py +++ b/app/views/__init__.py @@ -30,6 +30,9 @@ def start_scodoc_request(): if current_user.is_authenticated: current_user.last_seen = datetime.datetime.utcnow() 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 diff --git a/app/views/scolar.py b/app/views/scolar.py index ab02fa3130517a6ad59f2e5ecf1be91adaec469d..3e5f3c3d469cd6f8227f5dd800d30d086029913e 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -651,8 +651,8 @@ def formChangeCoordonnees(etudid): # --- Gestion des groupes: sco_publish( - "/affectGroups", - sco_groups_edit.affectGroups, + "/affect_groups", + sco_groups_edit.affect_groups, Permission.ScoView, methods=["GET", "POST"], )