Compare commits

..

No commits in common. "aa9d85f4bd16998768450951159daf91ef083755" and "ef44a71e39dd38148d2499438d12d404eae9b5b7" have entirely different histories.

21 changed files with 259 additions and 241 deletions

View File

@ -56,6 +56,7 @@ from app.models import (
)
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoTemporaryError
from app.scodoc import html_sco_header
from app.scodoc import htmlutils
from app.scodoc import sco_assiduites
from app.scodoc import sco_bulletins_generator
@ -959,21 +960,7 @@ def formsemestre_bulletinetud(
elif fmt == "pdfmail":
return ""
H = [
render_template(
"bul_head.j2",
etud=etud,
fmt=fmt,
formsemestre=formsemestre,
menu_autres_operations=make_menu_autres_operations(
etud=etud,
formsemestre=formsemestre,
endpoint="notes.formsemestre_bulletinetud",
version=version,
),
scu=scu,
time=time,
version=version,
),
_formsemestre_bulletinetud_header_html(etud, formsemestre, fmt, version),
bulletin,
render_template(
"bul_foot.j2",
@ -984,18 +971,10 @@ def formsemestre_bulletinetud(
inscription_courante=etud.inscription_courante(),
inscription_str=etud.inscription_descr()["inscription_str"],
),
html_sco_header.sco_footer(),
]
return render_template(
"sco_page.j2",
title=f"Bulletin de {etud.nomprenom}",
content="".join(H),
javascripts=[
"js/bulletin.js",
"libjs/d3.v3.min.js",
"js/radar_bulletin.js",
],
cssstyles=["css/radar_bulletin.css"],
)
return "".join(H)
def can_send_bulletin_by_mail(formsemestre_id):
@ -1333,3 +1312,38 @@ def make_menu_autres_operations(
},
]
return htmlutils.make_menu("Autres opérations", menu_items, alone=True)
def _formsemestre_bulletinetud_header_html(
etud,
formsemestre: FormSemestre,
fmt=None,
version=None,
):
H = [
html_sco_header.sco_header(
page_title=f"Bulletin de {etud.nomprenom}",
javascripts=[
"js/bulletin.js",
"libjs/d3.v3.min.js",
"js/radar_bulletin.js",
],
cssstyles=["css/radar_bulletin.css"],
),
render_template(
"bul_head.j2",
etud=etud,
fmt=fmt,
formsemestre=formsemestre,
menu_autres_operations=make_menu_autres_operations(
etud=etud,
formsemestre=formsemestre,
endpoint="notes.formsemestre_bulletinetud",
version=version,
),
scu=scu,
time=time,
version=version,
),
]
return "\n".join(H)

View File

@ -33,6 +33,7 @@ from flask_sqlalchemy.query import Query
from app import db
from app.models import Evaluation, FormSemestre, Identite, Assiduite
import app.scodoc.sco_utils as scu
from app.scodoc import html_sco_header
from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_groups

View File

@ -36,6 +36,7 @@ from app import db
from app.models import Departement, Identite
import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_etud
from app.scodoc import sco_groups
from app.scodoc.sco_exceptions import ScoException
@ -51,7 +52,7 @@ def form_search_etud(
title="Rechercher un étudiant par nom : ",
add_headers=False, # complete page
):
"form recherche par nom: utilisé pour choisir un étudiant à inscrire, par exemple"
"form recherche par nom"
H = []
H.append(
f"""<form action="{
@ -92,8 +93,10 @@ def form_search_etud(
H.append("</form>")
if add_headers:
return render_template(
"sco_page.j2", title="Choix d'un étudiant", content="\n".join(H)
return (
html_sco_header.sco_header(page_title="Choix d'un étudiant")
+ "\n".join(H)
+ html_sco_header.sco_footer()
)
else:
return "\n".join(H)

View File

@ -224,17 +224,23 @@ def menu_groups_choice(
groups_infos,
submit_on_change=False,
default_deselect_others=True,
html_export=True,
change_event=None, # XXX ???
):
"""Menu pour selection groupes
"""menu pour selection groupes
group_ids est la liste des groupes actuellement sélectionnés
et doit comporter au moins un élément, sauf si formsemestre_id est spécifié.
(utilisé pour retrouver le semestre et proposer la liste des autres groupes)
Si url_export :
Si html_export :
selecteur.value = &group_ids=xxx&group_ids=yyy...
sinon :
selecteur.value = [xxx, yyy, ...]
Si change_event :
met à jour l'événement onchange du selecteur
(attend du js, plus d'informations sur scu.MultiSelect.change_event)
"""
default_group_id = sco_groups.get_default_group(groups_infos.formsemestre_id)
n_members = len(sco_groups.get_group_members(default_group_id))
@ -272,6 +278,9 @@ def menu_groups_choice(
values=values, name="group_ids", html_id="group_ids_sel"
)
if html_export:
multi_select.export_format('return "&group_ids="+values.join("&group_ids=")')
if submit_on_change:
multi_select.change_event("submit_group_selector();")
@ -758,7 +767,7 @@ def groups_table(
name="options",
html_id="group_list_options",
)
multi_select.change_event("change_list_options(values);")
multi_select.change_event("change_list_options(event.target.value);")
H.extend(
# ;
[

View File

@ -31,13 +31,14 @@
import datetime
from operator import itemgetter
from flask import url_for, g, render_template, request
from flask import url_for, g, request
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app import db, log
from app.models import Formation, FormSemestre, GroupDescr, Identite
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_cache
from app.scodoc import codes_cursus
from app.scodoc import sco_etud
@ -309,7 +310,12 @@ def formsemestre_inscr_passage(
# -- check lock
if not formsemestre.etat:
raise ScoValueError("opération impossible: semestre verrouille")
H = []
H = [
html_sco_header.sco_header(
page_title="Passage des étudiants",
)
]
footer = html_sco_header.sco_footer()
etuds = [] if etuds is None else etuds
if isinstance(etuds, str):
# string, vient du form de confirmation
@ -448,9 +454,8 @@ def formsemestre_inscr_passage(
)
#
return render_template(
"sco_page.j2", title="Passage des étudiants", content="\n".join(H)
)
H.append(footer)
return "\n".join(H)
def _build_page(

View File

@ -628,7 +628,7 @@ def fiche_etud(etudid=None):
"""
)
return render_template(
"sco_page_dept.j2",
"sco_page.j2",
content=tmpl % info,
title=f"Fiche étudiant {etud.nomprenom}",
cssstyles=[

View File

@ -41,6 +41,7 @@ from app.models import FormSemestre, Identite
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc import html_sco_header
from app.scodoc import codes_cursus
from app.scodoc import sco_pv_dict
from app.scodoc import sco_etud

View File

@ -32,7 +32,8 @@ import datetime
import time
from xml.etree import ElementTree
from flask import abort, g, render_template, request, url_for
from flask import g, request
from flask import abort, url_for
from app import log
from app.but import bulletin_but
@ -43,12 +44,14 @@ from app.models import FormSemestre
from app.models.etudiants import Identite
import app.scodoc.sco_utils as scu
from app.scodoc import html_sco_header
from app.scodoc import sco_bulletins_json
from app.scodoc import sco_bulletins_xml
from app.scodoc import sco_cache
from app.scodoc import sco_evaluations
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_status
from app.scodoc import sco_preferences
from app.tables.recap import TableRecap
from app.tables.jury_recap import TableJury
@ -116,9 +119,15 @@ def formsemestre_recapcomplet(
)
H = [
# sco_formsemestre_status.formsemestre_status_head(
# formsemestre_id=formsemestre_id
# ),
html_sco_header.sco_header(
page_title=f"{formsemestre.sem_modalite()}: "
+ ("jury" if mode_jury else "moyennes"),
no_sidebar=True,
javascripts=["js/table_recap.js"],
),
sco_formsemestre_status.formsemestre_status_head(
formsemestre_id=formsemestre_id
),
]
if len(formsemestre.inscriptions) > 0:
H.append(
@ -264,17 +273,10 @@ def formsemestre_recapcomplet(
</div>
"""
)
H.append(html_sco_header.sco_footer())
# HTML or binary data ?
if len(H) > 1:
return render_template(
"sco_page.j2",
content="".join(H),
title=f"{formsemestre.sem_modalite()}: "
+ ("jury" if mode_jury else "moyennes"),
javascripts=["js/table_recap.js"],
formsemestre_id=formsemestre_id,
no_sidebar=True,
)
return "".join(H)
elif len(H) == 1:
return H[0]
else:

View File

@ -31,7 +31,7 @@ import time
import flask
from flask import g, render_template, url_for
from flask import g, url_for
from flask_login import current_user
from flask_sqlalchemy.query import Query
import psycopg2
@ -57,6 +57,7 @@ from app.scodoc.sco_exceptions import (
ScoInvalidParamError,
ScoValueError,
)
from app.scodoc import html_sco_header
from app.scodoc import htmlutils
from app.scodoc import sco_cache
from app.scodoc import sco_etud
@ -246,15 +247,14 @@ def do_evaluation_set_missing(
if len(invalids) > 0:
diag = f"Valeur {value} invalide ou hors barème"
if diag:
return render_template(
"sco_page.j2",
content=f"""
return f"""
{html_sco_header.sco_header()}
<h2>{diag}</h2>
<p><a href="{ dest_url }">
Recommencer</a>
</p>
""",
)
{html_sco_header.sco_footer()}
"""
# Confirm action
if not dialog_confirmed:
plural = len(valid_notes) > 1
@ -293,9 +293,8 @@ def do_evaluation_set_missing(
url=url,
max_frequency=30 * 60,
)
return render_template(
"sco_page.j2",
content=f"""
return f"""
{ html_sco_header.sco_header() }
<h2>{len(etudids_changed)} notes changées</h2>
<ul>
<li><a class="stdlink" href="{dest_url}">
@ -309,8 +308,8 @@ def do_evaluation_set_missing(
)}">Tableau de bord du module</a>
</li>
</ul>
""",
)
{ html_sco_header.sco_footer() }
"""
def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
@ -391,7 +390,7 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
url=status_url,
)
return render_template("sco_page.j2", content="\n".join(H))
return html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
def _check_inscription(
@ -641,17 +640,16 @@ def saisie_notes(evaluation_id: int, group_ids: list = None):
# Check access
# (admin, respformation, and responsable_id)
if not evaluation.moduleimpl.can_edit_notes(current_user):
return render_template(
"sco_page.j2",
content=f"""
return f"""
{html_sco_header.sco_header()}
<h2>Modification des notes impossible pour {current_user.user_name}</h2>
<p>(vérifiez que le semestre n'est pas verrouillé et que vous
avez l'autorisation d'effectuer cette opération)</p>
<p><a href="{ moduleimpl_status_url }">Continuer</a>
</p>
""",
)
{html_sco_header.sco_footer()}
"""
# Informations sur les groupes à afficher:
groups_infos = sco_groups_view.DisplayedGroupsInfos(
@ -668,6 +666,11 @@ def saisie_notes(evaluation_id: int, group_ids: list = None):
)
# HTML page:
H = [
html_sco_header.sco_header(
page_title=page_title,
javascripts=sco_groups_view.JAVASCRIPTS + ["js/saisie_notes.js"],
cssstyles=sco_groups_view.CSSSTYLES,
),
sco_evaluations.evaluation_describe(
evaluation_id=evaluation_id, link_saisie=False
),
@ -751,13 +754,9 @@ def saisie_notes(evaluation_id: int, group_ids: list = None):
</ul>
</div>"""
)
return render_template(
"sco_page.j2",
content="\n".join(H),
title=page_title,
javascripts=sco_groups_view.JAVASCRIPTS + ["js/saisie_notes.js"],
cssstyles=sco_groups_view.CSSSTYLES,
)
H.append(html_sco_header.sco_footer())
return "\n".join(H)
def get_sorted_etuds_notes(

View File

@ -31,7 +31,7 @@
import time
from operator import itemgetter
from flask import g, render_template, url_for
from flask import g, url_for
from flask_login import current_user
from app import db, log
@ -39,6 +39,7 @@ from app.models import Admission, Adresse, FormSemestre, Identite, ScolarNews
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc import html_sco_header
from app.scodoc import sco_cache
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
@ -117,6 +118,7 @@ def formsemestre_synchro_etuds(
""",
safe=True,
)
footer = html_sco_header.sco_footer()
base_url = url_for(
"notes.formsemestre_synchro_etuds",
scodoc_dept=g.scodoc_dept,
@ -166,7 +168,7 @@ def formsemestre_synchro_etuds(
suffix=scu.XLSX_SUFFIX,
)
H = []
H = [html_sco_header.sco_header(page_title="Synchronisation étudiants")]
if not submitted:
H += _build_page(
sem,
@ -298,9 +300,8 @@ def formsemestre_synchro_etuds(
"""
)
return render_template(
"sco_page.j2", title="Synchronisation des étudiants", content="\n".join(H)
)
H.append(footer)
return "\n".join(H)
def _build_page(

View File

@ -55,7 +55,7 @@ from pytz import timezone
import flask
from flask import g, render_template, request, Response
from flask import g, request, Response
from flask import flash, make_response
from flask_json import json_response
from werkzeug.http import HTTP_STATUS_CODES
@ -1527,6 +1527,8 @@ def confirm_dialog(
target_variable="dialog_confirmed",
):
"""HTML confirmation dialog: submit (POST) to same page or dest_url if given."""
from app.scodoc import html_sco_header
parameters = parameters or {}
# dialog de confirmation simple
parameters[target_variable] = 1
@ -1565,7 +1567,9 @@ def confirm_dialog(
if help_msg:
H.append('<p class="help">' + help_msg + "</p>")
if add_headers:
return render_template("sco_page.j2", content="\n".join(H))
return (
html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
)
else:
return "\n".join(H)

View File

@ -58,10 +58,6 @@ div.sco-app-content {
margin-right: 8px;
}
.space-before-18 {
margin-top: 18px;
}
div.scobox {
flex: 1 0 0;
/* Equal width for all boxes */
@ -2367,6 +2363,8 @@ span.eval_coef_ue {
margin-right: 2em;
}
span.eval_coef_ue_titre {}
/* Inscriptions modules/UE */
div.list_but_ue_inscriptions {
margin-top: 16px;
@ -4260,7 +4258,6 @@ div.apo_csv_status {
.form_apo_export input[type="submit"] {
-webkit-appearance: button;
appearance: button;
font-size: 150%;
font-weight: bold;
color: green;

View File

@ -23,14 +23,7 @@ function groups_view_url() {
urlParams.delete("group_ids");
// ajout des groupes selectionnes
var selected_groups = document.getElementById("group_ids_sel").value;
if (Array.isArray(selected_groups)) {
selected_groups.forEach((value) => {
urlParams.append("group_ids", value);
});
} else {
urlParams.set("group_ids", selected_groups);
}
url.search = urlParams.toString();
url.search = urlParams.toString() + selected_groups;
return url.href;
}
@ -68,13 +61,11 @@ function change_list_options(selected_options) {
// Menu choix groupe:
function toggle_visible_etuds() {
//
document.querySelectorAll(".etud_elem").forEach((element) => {
element.style.display = "none";
document.querySelectorAll('.etud_elem').forEach(element => {
element.style.display = 'none';
});
var qargs = "";
var selectedOptions = document.querySelectorAll(
"#group_ids_sel option:checked"
);
var selectedOptions = document.querySelectorAll("#group_ids_sel option:checked");
var qargs = "";
selectedOptions.forEach(function (opt) {
var group_id = opt.value;
@ -88,9 +79,7 @@ function toggle_visible_etuds() {
let input_eval = document.querySelectorAll("#formnotes_evaluation_id");
if (input_eval.length > 0) {
let evaluation_id = input_eval[0].value;
let menu_saisie_tableur_a = document.querySelector(
"#menu_saisie_tableur a"
);
let menu_saisie_tableur_a = document.querySelector("#menu_saisie_tableur a");
menu_saisie_tableur_a.setAttribute(
"href",
"saisie_notes_tableur?evaluation_id=" + evaluation_id + qargs

View File

@ -20,8 +20,7 @@
<multi-select>.values() => ["val1",...]
<multi-select>.values(["val1",...]) => // sélectionne les options correspondantes (ne vérifie pas les options "single")
<multi-select>.on((values) => {}) => // écoute le changement de valeur
<multi-select>.format((values)=>{}) // modifie les valeurs avant d'être envoyées / récupérées. values est un tableau des valeurs des options sélectionnées
<multi-select>.on("change", (values) => {}) => // écoute le changement de valeur
*/
class MultiSelect extends HTMLElement {
@ -248,6 +247,8 @@ class MultiSelect extends HTMLElement {
(checkbox) => checkbox.checked
);
const values = checkedBoxes.map((checkbox) => checkbox.value);
const opts = checkedBoxes.map((checkbox) => {
return this.querySelector(`option[value="${checkbox.value}"]`);
});
@ -262,21 +263,6 @@ class MultiSelect extends HTMLElement {
btn.textContent = `${checkedBoxes.length} sélections`;
}
this.dispatchEvent(new Event("change"));
// create a FormData object
const fd = new FormData();
const values = this._values();
// check if values is an array
if (Array.isArray(values)) {
values.forEach((value) => {
fd.append(this.name, value);
});
} else {
fd.append(this.name, values);
}
// update the form values
this._internals.setFormValue(fd);
}
_values(newValues = null) {
@ -298,6 +284,7 @@ class MultiSelect extends HTMLElement {
checkbox.checked = newValues.includes(checkbox.value);
});
this._internals.setFormValue(this._values());
this._updateSelect();
}
}
@ -311,9 +298,7 @@ class MultiSelect extends HTMLElement {
}
on(callback) {
this.addEventListener("change", () => {
callback(this._values());
});
this.addEventListener("change", callback);
}
format(callback) {

View File

@ -6,7 +6,7 @@
<h2>Système de gestion scolarité</h2>
<p>&copy; Emmanuel Viennet 2024</p>
<p>&copy; Emmanuel Viennet 2023</p>
<p>Version {{ version }}</p>

View File

@ -1,5 +1,6 @@
{# -*- mode: jinja-html -*- #}
{# L'en-tête des bulletins HTML #}
{# was _formsemestre_bulletinetud_header_html #}
<div class="bull_head">
<div class="bull_head_text">

View File

@ -23,6 +23,7 @@
id="feuille_emargement"
action="{{request.base_url}}"
method="post"
onsubmit="serializeGroupIds(event)"
>
{{ form.hidden_tag() }}
<div class="infos-button">Groupes&nbsp;: {{grp|safe}}</div>
@ -55,4 +56,24 @@
{% include "sco_timepicker.j2" %}
<script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script>
<script src="{{scu.STATIC_DIR}}/libjs/purl.js"></script>
<script>
function serializeGroupIds(event) {
// Dealing with multiselect
event.preventDefault();
var form = document.getElementById("feuille_emargement");
var groupIdsField = form.elements["group_ids"];
// Check if the group_ids field exists and is an array
if (groupIdsField && Array.isArray(groupIdsField.value)) {
// Convert the array to a comma-separated string
var serializedValue = groupIdsField.value.join(',');
// Replace the field's value with the serialized string
groupIdsField.value = serializedValue;
}
// Now submit the form
form.submit();
}
</script>
{% endblock scripts %}

View File

@ -24,7 +24,8 @@
#
##############################################################################
"""Vues assiduité"""
"""Vues assiduité
"""
import datetime
import json
@ -1166,7 +1167,7 @@ def signal_assiduites_group():
formsemestre_date_fin=str(formsemestre.date_fin),
formsemestre_id=formsemestre_id,
gr_tit=gr_tit,
grp=sco_groups_view.menu_groups_choice(groups_infos),
grp=sco_groups_view.menu_groups_choice(groups_infos, html_export=False),
minitimeline=_mini_timeline(),
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
nonworkdays=_non_work_days(),

View File

@ -41,11 +41,11 @@ def formulaire_feuille_appel(formsemestre_id: int):
group_ids: list[int] = request.args.getlist("group_ids")
data = {"group_ids": group_ids}
else:
group_ids_list = request.form.getlist("group_ids")
group_ids_str = request.form.get("group_ids")
try:
group_ids = [int(gid) for gid in group_ids_list if gid]
group_ids = [int(gid) for gid in group_ids_str.split(",") if gid]
except ValueError as exc:
log(f"formulaire_feuille_appel: group_ids invalide: {group_ids_list[:100]}")
log(f"formulaire_feuille_appel: group_ids invalide: {group_ids_str[:100]}")
raise ScoValueError("groupes invalides") from exc
data = {}
@ -81,6 +81,6 @@ def formulaire_feuille_appel(formsemestre_id: int):
sco_data=ScoData(formsemestre=formsemestre),
form=form,
group_name=groups_infos.groups_titles,
grp=menu_groups_choice(groups_infos),
grp=menu_groups_choice(groups_infos, html_export=False),
formsemestre_id=formsemestre_id,
)

View File

@ -30,7 +30,6 @@ Module notes: issu de ScoDoc7 / ZNotes.py
Emmanuel Viennet, 2021
"""
import html
from operator import itemgetter
import time
@ -42,7 +41,7 @@ from flask_login import current_user
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed
from wtforms.validators import DataRequired, Length
from wtforms import FileField, StringField, SubmitField
from wtforms import FileField, HiddenField, StringField, SubmitField
from app import db, log, send_scodoc_alarm
from app import models
@ -945,10 +944,10 @@ def edit_enseignants_form(moduleimpl_id):
modimpl.can_change_ens(raise_exc=True)
#
page_title = f"Enseignants du module {modimpl.module.titre or modimpl.module.code}"
title = f"""<h2>Enseignants du <a class="stdlink" href="{
title = f"""Enseignants du <a href="{
url_for("notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
}">module {modimpl.module.titre or modimpl.module.code}</a></h2>"""
}">module {modimpl.module.titre or modimpl.module.code}</a>"""
# Liste des enseignants avec forme pour affichage / saisie avec suggestion
userlist = sco_users.get_user_list()
uid2display = {} # uid : forme pour affichage = "NOM Prenom (login)"(login)"
@ -973,8 +972,7 @@ def edit_enseignants_form(moduleimpl_id):
</li>"""
)
H.append("</ul>")
F = f"""<div class="help space-before-18">
<p>Les enseignants d'un module ont le droit de
F = f"""<p class="help">Les enseignants d'un module ont le droit de
saisir et modifier toutes les notes des évaluations de ce module.
</p>
<p class="help">Pour changer le responsable du module, passez par la
@ -984,7 +982,6 @@ def edit_enseignants_form(moduleimpl_id):
}">Modification du semestre</a>",
accessible uniquement au responsable de la formation (chef de département)
</p>
</div>
"""
modform = [
@ -1021,7 +1018,7 @@ def edit_enseignants_form(moduleimpl_id):
return render_template(
"sco_page.j2",
title=page_title,
content=title + "\n".join(H) + tf[1] + F,
content=title + "\n".join(H) + tf[1],
javascripts=["libjs/AutoSuggest.js"],
cssstyles=["css/autosuggest_inquisitor.css"],
)
@ -1064,7 +1061,7 @@ def edit_enseignants_form(moduleimpl_id):
return render_template(
"sco_page.j2",
title=page_title,
content=title + "\n".join(H) + tf[1] + F,
content=title + "\n".join(H) + tf[1],
javascripts=["libjs/AutoSuggest.js"],
cssstyles=["css/autosuggest_inquisitor.css"],
)
@ -2570,6 +2567,7 @@ def check_sem_integrity(formsemestre_id, fix=False):
modimpl["mod"] = mod
H = [
html_sco_header.sco_header(),
"<p>formation_id=%s" % sem["formation_id"],
]
if bad_ue:
@ -2607,7 +2605,7 @@ def check_sem_integrity(formsemestre_id, fix=False):
else:
H.append("""<p class="alert">Problème détecté !</p>""")
return render_template("sco_page.j2", content="\n".join(H))
return "\n".join(H) + html_sco_header.sco_footer()
@bp.route("/check_form_integrity")

View File

@ -82,6 +82,7 @@ from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
from app.scodoc.gen_tables import GenTable
from app.scodoc import (
codes_cursus,
html_sco_header,
sco_import_etuds,
sco_archives_etud,
sco_bug_report,
@ -826,7 +827,9 @@ def form_change_coordonnees(etudid):
else:
adr = {} # no data for this student
H = [
f"""
f"""{html_sco_header.sco_header(
page_title=f"Changement coordonnées de {etud.nomprenom}"
)}
<h2>Changement des coordonnées de {etud.nomprenom}</h2>
<p>"""
]
@ -870,11 +873,7 @@ def form_change_coordonnees(etudid):
)
dest_url = url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)
if tf[0] == 0:
return render_template(
"sco_page_dept.j2",
title=f"Changement coordonnées de {etud.nomprenom}",
content="\n".join(H) + tf[1],
)
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
elif tf[0] == -1:
return flask.redirect(dest_url)
else:
@ -1005,14 +1004,17 @@ def students_groups_auto_assignment(formsemestre_id: int):
"""Répartition auto des groupes"""
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
H = [
html_sco_header.sco_header(
page_title="Répartition des groupes",
),
render_template(
"scolar/students_groups_auto_assignment.j2",
formsemestre=formsemestre,
),
html_sco_header.sco_footer(),
]
return render_template(
"sco_page.j2", title="Répartition des groupes", content="\n".join(H)
)
return "\n".join(H)
@bp.route("/create_partition_parcours", methods=["GET", "POST"])
@ -1047,17 +1049,15 @@ sco_publish("/etud_photo_html", sco_photos.etud_photo_html, Permission.ScoView)
def etud_photo_orig_page(etudid):
"Page with photo in orig. size"
etud = Identite.get_etud(etudid)
return render_template(
"sco_page_dept.j2",
title=f"Photo de {etud.nomprenom}",
content=f"""
return f"""{
html_sco_header.sco_header(etudid=etud.id, page_title=etud.nomprenom)
}
<h2>{etud.nomprenom}</h2>
<div>
<a href="{etud.url_fiche()}">{etud.photo_html(size='orig')}</a>
</div>
""",
sco=ScoData(etud=etud),
)
{html_sco_header.sco_footer()}
"""
@bp.route("/form_change_photo", methods=["GET", "POST"])
@ -1072,8 +1072,8 @@ def form_change_photo(etudid=None):
else:
photo_loc = "externe"
H = [
html_sco_header.sco_header(page_title="Changement de photo"),
f"""<h2>Changement de la photo de {etud.nomprenom}</h2>
<p>Photo actuelle ({photo_loc}):
{sco_photos.etud_photo_html(etudid=etud.id, title="photo actuelle")}
</p>
@ -1098,17 +1098,16 @@ def form_change_photo(etudid=None):
)
dest_url = url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id)
if tf[0] == 0:
return render_template(
"sco_page_dept.j2",
title="Changement de photo",
content="\n".join(H)
return (
"\n".join(H)
+ f"""
{tf[1]}
<div class=""><a class="stdlink" href="{
<p><a class="stdlink" href="{
url_for("scolar.form_suppress_photo",
scodoc_dept=g.scodoc_dept, etudid=etud.id)
}">Supprimer cette photo</a></div>
""",
}">Supprimer cette photo</a></p>
{html_sco_header.sco_footer()}
"""
)
elif tf[0] == -1:
return flask.redirect(dest_url)
@ -1121,9 +1120,7 @@ def form_change_photo(etudid=None):
return flask.redirect(dest_url)
else:
H.append(f"""<p class="warning">Erreur: {err_msg}</p>""")
return render_template(
"sco_page_dept.j2", title="Changement de photo", content="\n".join(H)
)
return "\n".join(H) + html_sco_header.sco_footer()
@bp.route("/form_suppress_photo", methods=["POST", "GET"])
@ -1194,11 +1191,12 @@ def _form_dem_of_def(
raise ScoValueError("Modification impossible: semestre verrouille")
nowdmy = time.strftime(scu.DATE_FMT)
#
header = html_sco_header.sco_header(
page_title=f"""{operation_name} de {etud.nomprenom} (du semestre {formsemestre.titre_mois()})"""
)
validations_descr = formsemestre.etud_validations_description_html(etudid)
return render_template(
"sco_page_dept.j2",
title=f"""{operation_name} de {etud.nomprenom} (du semestre {formsemestre.titre_mois()})""",
content=f"""
return f"""
{header}
<h2><font color="#FF0000">{operation_name} de</font> {etud.nomprenom} ({formsemestre.titre_mois()})</h2>
<form action="{operation_method}" method="get">
@ -1218,8 +1216,8 @@ def _form_dem_of_def(
formsemestre_id=formsemestre_id, etudid=etudid)
+ '">modifier ces décisions</a></p>') if validations_descr else ""}
</div>
""",
)
{html_sco_header.sco_footer()}
"""
@bp.route("/do_dem_etudiant")
@ -1407,7 +1405,8 @@ def _validate_date_naissance(val: str, field) -> bool:
def _etudident_create_or_edit_form(edit):
"Le formulaire HTML"
H = []
H = [html_sco_header.sco_header()]
F = html_sco_header.sco_footer()
vals = scu.get_request_args()
etudid = vals.get("etudid", None)
cnx = ndb.GetDBConnexion()
@ -1768,12 +1767,11 @@ def _etudident_create_or_edit_form(edit):
cancelbutton="Re-interroger Apogee",
initvalues=initvalues,
)
if tf[0] in (0, -1):
return render_template(
"sco_page_dept.j2",
content="\n".join(H) + tf[1] + "<p>" + A,
title="Création/édition d'étudiant",
)
if tf[0] == 0:
return "\n".join(H) + tf[1] + "<p>" + A + F
elif tf[0] == -1:
return "\n".join(H) + tf[1] + "<p>" + A + F
# return '\n'.join(H) + '<h4>annulation</h4>' + F
else:
# form submission
if edit:
@ -1785,14 +1783,13 @@ def _etudident_create_or_edit_form(edit):
)
nb_homonyms = len(homonyms)
if not ok:
return render_template(
"sco_page_dept.j2",
content="\n".join(H)
return (
"\n".join(H)
+ tf_error_message("Nom ou prénom invalide")
+ tf[1]
+ "<p>"
+ A,
title="Création/édition d'étudiant",
+ A
+ F
)
if not tf[2]["dont_check_homonyms"] and nb_homonyms > 0:
homonyms_html = f"""
@ -1804,10 +1801,7 @@ def _etudident_create_or_edit_form(edit):
</ul>
</div>
"""
return render_template(
"sco_page_dept.j2",
title="Création/édition d'étudiant",
content=(
return (
"\n".join(H)
+ tf_error_message(
"""Attention: il y a déjà un étudiant portant des noms et prénoms proches
@ -1820,7 +1814,7 @@ def _etudident_create_or_edit_form(edit):
+ "<p>"
+ A
+ homonyms_html
),
+ F
)
tf[2]["date_naissance"] = (
scu.convert_fr_date(tf[2]["date_naissance"])
@ -2179,6 +2173,7 @@ def form_students_import_excel(formsemestre_id=None):
if sem and not sem["etat"]:
raise ScoValueError("Modification impossible: semestre verrouille")
H = [
html_sco_header.sco_header(page_title="Import etudiants"),
"""<h2 class="formsemestre">Téléchargement d\'une nouvelle liste d\'etudiants</h2>
<div style="color: red">
<p>A utiliser pour importer de <b>nouveaux</b> étudiants (typiquement au
@ -2234,6 +2229,7 @@ def form_students_import_excel(formsemestre_id=None):
<li>"""
)
F = html_sco_header.sco_footer()
tf = TrivialFormulator(
request.base_url,
scu.get_request_args(),
@ -2289,11 +2285,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
% (t[0], t[1], t[4], ast)
)
if tf[0] == 0:
return render_template(
"sco_page.j2",
title="Import etudiants",
content="\n".join(H) + tf[1] + "</li></ol>" + "\n".join(S),
)
return "\n".join(H) + tf[1] + "</li></ol>" + "\n".join(S) + F
elif tf[0] == -1:
return flask.redirect(dest_url)
else:
@ -2353,13 +2345,14 @@ def import_generate_admission_sample(formsemestre_id):
def form_students_import_infos_admissions(formsemestre_id=None):
"formulaire import xls"
authuser = current_user
F = html_sco_header.sco_footer()
if not authuser.has_permission(Permission.EtudInscrit):
# autorise juste l'export
return render_template(
"sco_page.j2",
title="Export données admissions (Parcoursup ou autre)",
content=f"""
<h2 class="formsemestre">Téléchargement des informations sur l'admission
H = [
html_sco_header.sco_header(
page_title="Export données admissions (Parcoursup ou autre)",
),
f"""<h2 class="formsemestre">Téléchargement des informations sur l'admission
des étudiants</h2>
<p>
<a href="{ url_for('scolar.import_generate_admission_sample',
@ -2369,10 +2362,12 @@ def form_students_import_infos_admissions(formsemestre_id=None):
</p>
<p class="warning">Vous n'avez pas le droit d'importer les données</p>
""",
)
]
return "\n".join(H) + F
# On a le droit d'importer:
H = [
html_sco_header.sco_header(page_title="Import données admissions Parcoursup"),
f"""<h2 class="formsemestre">Téléchargement des informations sur l'admission des étudiants
depuis feuilles import Parcoursup</h2>
<div style="color: red">
@ -2456,11 +2451,7 @@ def form_students_import_infos_admissions(formsemestre_id=None):
)
if tf[0] == 0:
return render_template(
"sco_page.j2",
title="Import données admissions Parcoursup",
content="\n".join(H) + tf[1] + help_text,
)
return "\n".join(H) + tf[1] + help_text + F
elif tf[0] == -1:
return flask.redirect(
url_for(
@ -2591,15 +2582,13 @@ def sco_dump_and_send_db(message="", request_url="", traceback_str_base64=""):
Merci de contacter <a href="mailto:{scu.SCO_DEV_MAIL}">{scu.SCO_DEV_MAIL}</a>
"""
H = []
H = [html_sco_header.sco_header(page_title="Assistance technique")]
if status_code == requests.codes.OK: # pylint: disable=no-member
H.append(f"""<p>Opération effectuée.</p><p>{r_msg}</p>""")
else:
H.append(f"""<p class="warning">{r_msg}</p>""")
flash("Données envoyées au serveur d'assistance")
return render_template(
"sco_page_dept.j2", title="Assistance technique", content="\n".join(H)
)
return "\n".join(H) + html_sco_header.sco_footer()
# --- Report form (assistance)
@ -2627,14 +2616,12 @@ def sco_bug_report_form():
<a href="mailto:{scu.SCO_DEV_MAIL}">{scu.SCO_DEV_MAIL}</a>
"""
H = []
H = [html_sco_header.sco_header(page_title="Assistance technique")]
if r.status_code >= 200 and r.status_code < 300:
H.append(f"""<p>Opération effectuée.</p><p>{r_msg}</p>""")
else:
H.append(f"""<p class="warning">{r_msg}</p>""")
return render_template(
"sco_page_dept.j2", title="Assistance technique", content="\n".join(H)
)
return "\n".join(H) + html_sco_header.sco_footer()
return render_template(
"sco_bug_report.j2",