diff --git a/app/models/events.py b/app/models/events.py index e499dc74a..f8fd64ceb 100644 --- a/app/models/events.py +++ b/app/models/events.py @@ -232,7 +232,9 @@ class ScolarNews(db.Model): ) # Transforme les URL en URL absolues - base = scu.ScoURL() + base = url_for("scolar.index_html", scodoc_dept=g.scodoc_dept)[ + : -len("/index_html") + ] txt = re.sub('href=/.*?"', 'href="' + base + "/", txt) # Transforme les liens HTML en texte brut: 'texte' devient 'texte: url' diff --git a/app/scodoc/html_sco_header.py b/app/scodoc/html_sco_header.py index 18d7ad9f5..6362d4db3 100644 --- a/app/scodoc/html_sco_header.py +++ b/app/scodoc/html_sco_header.py @@ -30,7 +30,7 @@ import html -from flask import g, render_template +from flask import g, render_template, url_for from flask import request from flask_login import current_user @@ -163,7 +163,7 @@ def sco_header( params = { "page_title": page_title or sco_version.SCONAME, "no_side_bar": no_side_bar, - "ScoURL": scu.ScoURL(), + "ScoURL": url_for("scolar.index_html", scodoc_dept=g.scodoc_dept), "encoding": scu.SCO_ENCODING, "titrebandeau_mkup": "" + titrebandeau + "", "authuser": current_user.user_name, @@ -220,7 +220,7 @@ def sco_header( """ ) diff --git a/app/scodoc/html_sidebar.py b/app/scodoc/html_sidebar.py index b9bab9041..bbe441e2f 100755 --- a/app/scodoc/html_sidebar.py +++ b/app/scodoc/html_sidebar.py @@ -102,25 +102,33 @@ def sidebar_common(): Accueil
{current_user.user_name}
déconnexion
{sidebar_dept()}

Scolarité

- Semestres
- Formations
+ Semestres
+ Formations
""" ] if current_user.has_permission(Permission.AbsChange): H.append( - f""" Assiduité
""" + f""" Assiduité
""" ) if current_user.has_permission( Permission.UsersAdmin ) or current_user.has_permission(Permission.UsersView): H.append( - f"""Utilisateurs
""" + f"""Utilisateurs
""" ) if current_user.has_permission(Permission.EditPreferences): diff --git a/app/scodoc/sco_edit_formation.py b/app/scodoc/sco_edit_formation.py index df748eb6c..1a951e996 100644 --- a/app/scodoc/sco_edit_formation.py +++ b/app/scodoc/sco_edit_formation.py @@ -58,21 +58,20 @@ def formation_delete(formation_id=None, dialog_confirmed=False): html_sco_header.sco_header(page_title="Suppression d'une formation"), f"""

Suppression de la formation {formation.titre} ({formation.acronyme})

""", ] - - sems = sco_formsemestre.do_formsemestre_list({"formation_id": formation_id}) - if sems: + formsemestres = formation.formsemestres.all() + if formsemestres: H.append( """

Impossible de supprimer cette formation, car les sessions suivantes l'utilisent:

Revenir

' % scu.NotesURL() + f""" +

Revenir

""" ) else: if not dialog_confirmed: @@ -85,14 +84,16 @@ def formation_delete(formation_id=None, dialog_confirmed=False):

""", OK="Supprimer cette formation", - cancel_url=scu.NotesURL(), + cancel_url=url_for("notes.index_html", scodoc_dept=g.scodoc_dept), parameters={"formation_id": formation_id}, ) else: do_formation_delete(formation_id) H.append( f"""

OK, formation supprimée.

-

continuer

""" +

continuer

""" ) H.append(html_sco_header.sco_footer()) @@ -252,7 +253,7 @@ def formation_edit(formation_id=None, create=False): if tf[0] == 0: return "\n".join(H) + tf[1] + html_sco_header.sco_footer() elif tf[0] == -1: - return flask.redirect(scu.NotesURL()) + return flask.redirect(url_for("notes.index_html", scodoc_dept=g.scodoc_dept)) else: # check unicity : constraint UNIQUE(acronyme,titre,version) if create: diff --git a/app/scodoc/sco_evaluations.py b/app/scodoc/sco_evaluations.py index 06e0258d1..0b6b0c62c 100644 --- a/app/scodoc/sco_evaluations.py +++ b/app/scodoc/sco_evaluations.py @@ -541,7 +541,9 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, fmt="html"): scodoc_dept=g.scodoc_dept, moduleimpl_id=e.moduleimpl.id, ), - "module_titre": e.moduleimpl.module.abbrev or e.moduleimpl.module.titre, + "module_titre": e.moduleimpl.module.abbrev + or e.moduleimpl.module.titre + or "", "responsable_id": e.moduleimpl.responsable_id, "responsable_nomplogin": sco_users.user_info( e.moduleimpl.responsable_id diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py index 6ee355137..c2f375f3e 100644 --- a/app/scodoc/sco_formsemestre_edit.py +++ b/app/scodoc/sco_formsemestre_edit.py @@ -1431,18 +1431,25 @@ Ceci n'est possible que si : def formsemestre_delete2(formsemestre_id, dialog_confirmed=False): """Delete a formsemestre (confirmation)""" + formsemestre = FormSemestre.get_formsemestre(formsemestre_id) # Confirmation dialog if not dialog_confirmed: return scu.confirm_dialog( - """

Vous voulez vraiment supprimer ce semestre ???

(opération irréversible)

""", + """

Vous voulez vraiment supprimer ce semestre ???

+

(opération irréversible)

+ """, dest_url="", - cancel_url="formsemestre_status?formsemestre_id=%s" % formsemestre_id, - parameters={"formsemestre_id": formsemestre_id}, + cancel_url=url_for( + "notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre.id, + ), + parameters={"formsemestre_id": formsemestre.id}, ) # Bon, s'il le faut... - do_formsemestre_delete(formsemestre_id) + do_formsemestre_delete(formsemestre.id) flash("Semestre supprimé !") - return flask.redirect(scu.ScoURL()) + return flask.redirect(url_for("scolar.index_html", scodoc_dept=g.scodoc_dept)) def formsemestre_has_decisions_or_compensations( diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index ca2e5a8ca..08657c16d 100755 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -634,7 +634,7 @@ def formsemestre_description_table( "UE": modimpl.module.ue.acronyme, "_UE_td_attrs": ue_info.get("_UE_td_attrs", ""), "Code": modimpl.module.code or "", - "Module": modimpl.module.abbrev or modimpl.module.titre, + "Module": modimpl.module.abbrev or modimpl.module.titre or "", "_Module_class": "scotext", "Inscrits": mod_nb_inscrits, "Responsable": sco_users.user_info(modimpl.responsable_id)["nomprenom"], diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py index ba99209a8..d8fa049e1 100644 --- a/app/scodoc/sco_page_etud.py +++ b/app/scodoc/sco_page_etud.py @@ -180,7 +180,7 @@ def fiche_etud(etudid=None): ) else: info["etat_civil"] = "" - info["ScoURL"] = scu.ScoURL() + info["ScoURL"] = url_for("scolar.index_html", scodoc_dept=g.scodoc_dept) info["authuser"] = current_user if restrict_etud_data: info["info_naissance"] = "" diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py index ffebb4699..fa8197f3f 100644 --- a/app/scodoc/sco_preferences.py +++ b/app/scodoc/sco_preferences.py @@ -2260,16 +2260,17 @@ class BasePreferences: before_table="
{title}", after_table="
", ) + dest_url = url_for("scolar.index_html", scodoc_dept=g.scodoc_dept) if tf[0] == 0: return "\n".join(H) + tf[1] + html_sco_header.sco_footer() - elif tf[0] == -1: - return flask.redirect(scu.ScoURL()) # cancel - else: - for pref in self.prefs_definition: - self.prefs[None][pref[0]] = tf[2][pref[0]] - self.save() - flash("Préférences modifiées") - return flask.redirect(scu.ScoURL()) + if tf[0] == -1: + return flask.redirect(dest_url) # cancel + # + for pref in self.prefs_definition: + self.prefs[None][pref[0]] = tf[2][pref[0]] + self.save() + flash("Préférences modifiées") + return flask.redirect(dest_url) def build_tf_form(self, categories: list[str] = None, formsemestre_id: int = None): """Build list of elements for TrivialFormulator. @@ -2433,10 +2434,12 @@ function set_global_pref(el, pref_name) { before_table="
{title}", after_table="
", ) - dest_url = ( - scu.NotesURL() - + "/formsemestre_status?formsemestre_id=%s" % self.formsemestre_id + dest_url = url_for( + "notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, + formsemestre_id=self.formsemestre_id, ) + if tf[0] == 0: return "\n".join(H) + tf[1] + html_sco_header.sco_footer() elif tf[0] == -1: @@ -2482,7 +2485,9 @@ function set_global_pref(el, pref_name) { request.base_url + "?formsemestre_id=" + str(self.formsemestre_id) ) elif destination == "global": - return flask.redirect(scu.ScoURL() + "/edit_preferences") + return flask.redirect( + url_for("scolar.edit_preferences", scodoc_dept=g.scodoc_dept) + ) # diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 5bbf11790..614d2852b 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -785,51 +785,6 @@ BULLETINS_VERSIONS_BUT = BULLETINS_VERSIONS | { "butcourt": "Version courte spéciale BUT" } -# ----- Support for ScoDoc7 compatibility - - -def ScoURL(): - """base URL for this sco instance. - e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite - = page accueil département - """ - return url_for("scolar.index_html", scodoc_dept=g.scodoc_dept)[ - : -len("/index_html") - ] - - -def NotesURL(): - """URL of Notes - e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite/Notes - = url de base des méthodes de notes - (page accueil programmes). - """ - return url_for("notes.index_html", scodoc_dept=g.scodoc_dept)[: -len("/index_html")] - - -def AbsencesURL(): - """URL of Absences""" - return url_for("absences.index_html", scodoc_dept=g.scodoc_dept)[ - : -len("/index_html") - ] - - -def AssiduitesURL(): - """URL of Assiduités""" - return url_for("assiduites.bilan_dept", scodoc_dept=g.scodoc_dept)[ - : -len("/BilanDept") - ] - - -def UsersURL(): - """URL of Users - e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite/Users - = url de base des requêtes ZScoUsers - et page accueil users - """ - return url_for("users.index_html", scodoc_dept=g.scodoc_dept)[: -len("/index_html")] - - # ---- Simple python utilities diff --git a/app/static/css/assiduites.css b/app/static/css/assiduites.css index 5da0e5d97..088df3f66 100644 --- a/app/static/css/assiduites.css +++ b/app/static/css/assiduites.css @@ -485,6 +485,10 @@ cursor: pointer; } +.mass-selection em { + margin-left: 16px; +} + .fieldsplit { display: flex; justify-content: flex-start; diff --git a/app/static/js/assiduites.js b/app/static/js/assiduites.js index 4fa75afab..a269db1a0 100644 --- a/app/static/js/assiduites.js +++ b/app/static/js/assiduites.js @@ -425,7 +425,7 @@ async function getModuleImpl(assiduite) { return res.json(); }) .then((data) => { - moduleimpls[id] = `${data.module.code} ${data.module.abbrev}`; + moduleimpls[id] = `${data.module.code} ${data.module.abbrev || ''}`; return moduleimpls[id]; }) .catch((_) => { diff --git a/app/templates/assiduites/pages/signal_assiduites_diff.j2 b/app/templates/assiduites/pages/signal_assiduites_diff.j2 index c201f1bcc..474c6db5e 100644 --- a/app/templates/assiduites/pages/signal_assiduites_diff.j2 +++ b/app/templates/assiduites/pages/signal_assiduites_diff.j2 @@ -67,7 +67,7 @@ text-align: center; border: 1px solid #ddd; } - + .cell, .header { border: 1px solid #ddd; padding: 10px; @@ -111,7 +111,7 @@ display: flex; gap: 4px; } - + .pointer{ cursor: pointer; } @@ -220,7 +220,7 @@ async function nouvellePeriode(period = null) { let periodeDiv = document.createElement("div"); periodeDiv.classList.add("cell", "header"); periodeDiv.id = `periode-${periodId}`; - + const periodP = document.createElement("p"); periodP.textContent = `Plage du ${date} de ${debut} à ${fin}`; @@ -402,12 +402,12 @@ function sauvegarderAssiduites() { await nouvellePeriode(periode); } - // Si il y n'a pas d'erreur, on affiche un message de succès + // Si il n'y a pas d'erreur, on affiche un message de succès if (data.errors.length == 0) { const span = document.createElement("span"); - span.textContent = "Les assiduités ont bien été sauvegardées."; + span.textContent = "Le relevé d'assiduité a été enregistré."; openAlertModal( - "Sauvegarde des assiduités", + "Enregistrement de l'assiduité", span, null, "var(--color-present)" @@ -597,7 +597,7 @@ main(); - + - diff --git a/app/templates/assiduites/pages/signal_assiduites_group.j2 b/app/templates/assiduites/pages/signal_assiduites_group.j2 index bb665b4b4..68e8e6fa3 100644 --- a/app/templates/assiduites/pages/signal_assiduites_group.j2 +++ b/app/templates/assiduites/pages/signal_assiduites_group.j2 @@ -25,7 +25,7 @@ setupTimeLine(()=>{creerTousLesEtudiants(etuds)}) {% endif %} - + const nonWorkDays = [{{ nonworkdays| safe }}]; const readOnly = {{ readonly }}; @@ -61,7 +61,7 @@ $('#date').on('change', async function(d) { // On vérifie si la date est un jour travaillé dateCouranteEstTravaillee(); - + await recupAssiduites(etuds, $("#date").datepicker("getDate")); @@ -87,7 +87,7 @@ await recupAssiduites(etuds, $("#date").datepicker("getDate")); } creerTousLesEtudiants(etuds); - + // affichage ou non des PDP afficherPDP(localStorage.getItem("scodoc-etud-pdp") == "true" ) } @@ -168,9 +168,10 @@ + Les saisies ci-dessous sont enregistrées au fur et à mesure. {% endif %} - +

@@ -181,7 +182,7 @@ {% include "assiduites/widgets/alert.j2" %} {% include "assiduites/widgets/prompt.j2" %} {% include "assiduites/widgets/conflict.j2" %} - + diff --git a/app/templates/scolar/partition_editor.j2 b/app/templates/scolar/partition_editor.j2 index 4c5a44144..a9de162e5 100644 --- a/app/templates/scolar/partition_editor.j2 +++ b/app/templates/scolar/partition_editor.j2 @@ -237,7 +237,7 @@ span.calendarEdit { Afficher sur bulletins et tableaux

diff --git a/app/views/absences.py b/app/views/absences.py index 75e61f67b..546d39343 100644 --- a/app/views/absences.py +++ b/app/views/absences.py @@ -181,7 +181,7 @@ def add_billets_absence_form(etudid): if tf[0] == 0: return "\n".join(H) + tf[1] + html_sco_header.sco_footer() elif tf[0] == -1: - return flask.redirect(scu.ScoURL()) + return flask.redirect(url_for("scolar.index_html", scodoc_dept=g.scodoc_dept)) else: e = tf[2]["begin"].split("/") begin = e[2] + "-" + e[1] + "-" + e[0] + " 00:00:00" @@ -407,7 +407,7 @@ def process_billet_absence_form(billet_id: int): return "\n".join(H) + "
" + tf[1] + F + html_sco_header.sco_footer() elif tf[0] == -1: - return flask.redirect(scu.ScoURL()) + return flask.redirect(url_for("scolar.index_html", scodoc_dept=g.scodoc_dept)) else: n = _ProcessBilletAbsence(billet, tf[2]["estjust"], tf[2]["description"]) if tf[2]["estjust"]: diff --git a/app/views/notes.py b/app/views/notes.py index 2e0323632..c6d512f0c 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -685,7 +685,7 @@ def module_clone(): # @bp.route("/") -@bp.route("/index_html") +@bp.route("/index_html", alias=True) @scodoc @permission_required(Permission.ScoView) def index_html(): @@ -807,7 +807,7 @@ def formation_import_xml_form(): { html_sco_header.sco_footer() } """ elif tf[0] == -1: - return flask.redirect(scu.NotesURL()) + return flask.redirect(url_for("notes.index_html", scodoc_dept=g.scodoc_dept)) else: formation_id, _, _ = sco_formations.formation_import_xml( tf[2]["xmlfile"].read() diff --git a/app/views/scolar.py b/app/views/scolar.py index 6e6b32142..ab113a005 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -340,8 +340,8 @@ def showEtudLog(etudid, fmt="html"): # ---------- PAGE ACCUEIL (listes) -------------- -@bp.route("/", alias=True) -@bp.route("/index_html") +@bp.route("/") +@bp.route("/index_html", alias=True) @scodoc @permission_required(Permission.ScoView) @scodoc7func @@ -1954,7 +1954,7 @@ def etudident_delete(etudid: int = -1, dialog_confirmed=False): for formsemestre_id in formsemestre_ids_to_inval: sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre_id) flash("Étudiant supprimé !") - return flask.redirect(scu.ScoURL()) + return flask.redirect(url_for("scolar.index_html", scodoc_dept=g.scodoc_dept)) @bp.route("/check_group_apogee") @@ -2148,7 +2148,7 @@ def form_students_import_excel(formsemestre_id=None): ) else: sem = None - dest_url = scu.ScoURL() + dest_url = url_for("scolar.index_html", scodoc_dept=g.scodoc_dept) if sem and not sem["etat"]: raise ScoValueError("Modification impossible: semestre verrouille") H = [ @@ -2183,13 +2183,15 @@ def form_students_import_excel(formsemestre_id=None): ) else: H.append( - """ + f"""

Pour inscrire directement les étudiants dans un semestre de formation, il suffit d'indiquer le code de ce semestre - (qui doit avoir été créé au préalable). Cliquez ici pour afficher les codes + (qui doit avoir été créé au préalable). + Cliquez ici pour afficher les codes

""" - % (scu.ScoURL()) ) H.append("""
  1. """) @@ -2414,9 +2416,11 @@ def form_students_import_infos_admissions(formsemestre_id=None): return "\n".join(H) + tf[1] + help_text + F elif tf[0] == -1: return flask.redirect( - scu.ScoURL() - + "/formsemestre_status?formsemestre_id=" - + str(formsemestre_id) + url_for( + "notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre_id, + ) ) else: return sco_import_etuds.students_import_admission( diff --git a/app/views/users.py b/app/views/users.py index be505bb19..459c76b7f 100644 --- a/app/views/users.py +++ b/app/views/users.py @@ -132,7 +132,7 @@ class Mode(IntEnum): @bp.route("/") -@bp.route("/index_html") +@bp.route("/index_html", alias=True) @scodoc @permission_required(Permission.UsersView) @scodoc7func @@ -605,7 +605,7 @@ def create_user_form(user_name=None, edit=0, all_roles=True): if tf[0] == 0: return "\n".join(H) + "\n" + tf[1] + F elif tf[0] == -1: - return flask.redirect(scu.UsersURL()) + return flask.redirect(url_for("users.index_html", scodoc_dept=g.scodoc_dept)) else: vals = tf[2] roles = set(vals["roles"]).intersection(editable_roles_strings) @@ -1080,28 +1080,28 @@ def change_password(user_name, password, password2): # # ici page simplifiee car on peut ne plus avoir # le droit d'acceder aux feuilles de style - H.append( - """

    Changement effectué !

    -

    Ne notez pas ce mot de passe, mais mémorisez le !

    -

    Rappel: il est interdit de communiquer son mot de passe à - un tiers, même si c'est un collègue de confiance !

    -

    Si vous n'êtes pas administrateur, le système va vous redemander - votre login et nouveau mot de passe au prochain accès. -

    """ - ) - return ( - f""" - + return f""" + Mot de passe changé -

    Mot de passe changé !

    + +

    Mot de passe changé !

    +

    Changement effectué

    +

    Ne notez pas ce mot de passe, mais mémorisez le !

    +

    Rappel: il est interdit de communiquer son mot de passe à + un tiers, même si c'est un collègue de confiance !

    +

    Si vous n'êtes pas administrateur, le système va vous redemander + votre login et nouveau mot de passe au prochain accès. +

    + Continuer + + """ - + "\n".join(H) - + f'Continuer' - ) + return html_sco_header.sco_header() + "\n".join(H) + F