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():
{sidebar_dept()}
-
-
+
+
"""
]
if current_user.has_permission(Permission.AbsChange):
H.append(
- f"""
"""
+ f"""
"""
)
if current_user.has_permission(
Permission.UsersAdmin
) or current_user.has_permission(Permission.UsersView):
H.append(
- f"""
"""
+ f"""
"""
)
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:
"""
)
- for sem in sems:
- H.append(
- '- %(titremois)s
'
- % sem
- )
+ for formsemestre in formsemestres:
+ H.append(f"""- {formsemestre.html_link_status()}
""")
H.append(
- '
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 %}
-
+
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("""- """)
@@ -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