1
0
forked from ScoDoc/ScoDoc

Cosmetic / templatification

This commit is contained in:
Emmanuel Viennet 2024-08-24 08:06:46 +02:00
parent d191fcd10e
commit 37c93c8524
31 changed files with 260 additions and 208 deletions

View File

@ -685,6 +685,7 @@ class GenTable:
javascripts=(), javascripts=(),
with_html_headers=True, with_html_headers=True,
publish=True, publish=True,
template="sco_page.j2",
): ):
""" """
Build page at given format Build page at given format
@ -703,7 +704,7 @@ class GenTable:
H.append(self.html()) H.append(self.html())
if with_html_headers: if with_html_headers:
return render_template( return render_template(
"sco_page.j2", template,
content="\n".join(H), content="\n".join(H),
title=page_title, title=page_title,
javascripts=javascripts, javascripts=javascripts,

View File

@ -36,7 +36,6 @@ from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre from app.models import FormSemestre
from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc.sco_exceptions import ScoPermissionDenied from app.scodoc.sco_exceptions import ScoPermissionDenied
from app.scodoc import html_sco_header
from app.scodoc import sco_bulletins_pdf from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_groups_view from app.scodoc import sco_groups_view
@ -123,18 +122,18 @@ def do_formsemestre_archive(
) )
if table_html: if table_html:
flash(f"Moyennes archivées le {date}", category="info") flash(f"Moyennes archivées le {date}", category="info")
data = "\n".join( data = render_template(
[ "sco_page.j2",
html_sco_header.sco_header( no_sidebar=True,
page_title=f"Moyennes archivées le {date}", title=f"Moyennes archivées le {date}",
no_sidebar=True, content="\n".join(
), [
f'<h2 class="fontorange">Valeurs archivées le {date}</h2>', f'<h2 class="fontorange">Valeurs archivées le {date}</h2>',
"""<style type="text/css">table.notes_recapcomplet tr { color: rgb(185,70,0); } """<style type="text/css">table.notes_recapcomplet tr { color: rgb(185,70,0); }
</style>""", </style>""",
table_html, table_html,
html_sco_header.sco_footer(), ]
] ),
) )
PV_ARCHIVER.store( PV_ARCHIVER.store(
archive_id, "Tableau_moyennes.html", data, dept_id=formsemestre.dept_id archive_id, "Tableau_moyennes.html", data, dept_id=formsemestre.dept_id
@ -254,7 +253,6 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
}">Paramétrage</a>" }">Paramétrage</a>"
(accessible à l'administrateur du département).</em> (accessible à l'administrateur du département).</em>
</p>""", </p>""",
html_sco_header.sco_footer(),
] ]
descr = [ descr = [

View File

@ -29,7 +29,7 @@
Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant
""" """
import http import http
from flask import url_for, g, request from flask import g, render_template, request, url_for
from app import log from app import log
from app.comp import res_sem from app.comp import res_sem
@ -40,7 +40,6 @@ import app.scodoc.notesdb as ndb
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
from app.scodoc.gen_tables import GenTable from app.scodoc.gen_tables import GenTable
from app.scodoc import safehtml from app.scodoc import safehtml
from app.scodoc import html_sco_header
from app.scodoc import sco_permissions_check from app.scodoc import sco_permissions_check
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc import sco_tag_module from app.scodoc import sco_tag_module
@ -78,6 +77,7 @@ def report_debouche_date(start_year=None, fmt="html"):
title="""<h2 class="formsemestre">Débouchés étudiants </h2>""", title="""<h2 class="formsemestre">Débouchés étudiants </h2>""",
fmt=fmt, fmt=fmt,
with_html_headers=True, with_html_headers=True,
template="sco_page_dept.j2",
) )
@ -226,14 +226,16 @@ def table_debouche_etudids(etudids, keep_numeric=True):
def report_debouche_ask_date(msg: str) -> str: def report_debouche_ask_date(msg: str) -> str:
"""Formulaire demande date départ""" """Formulaire demande date départ"""
return f"""{html_sco_header.sco_header()} return render_template(
"sco_page_dept.j2",
content=f"""
<h2>Table des débouchés des étudiants</h2> <h2>Table des débouchés des étudiants</h2>
<form method="GET"> <form method="GET">
{msg} {msg}
<input type="text" name="start_year" value="" size=10/> <input type="text" name="start_year" value="" size=10/>
</form> </form>
{html_sco_header.sco_footer()} """,
""" )
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
@ -323,11 +325,11 @@ def itemsuivi_set_date(itemsuivi_id, item_date):
return ("", 204) return ("", 204)
def itemsuivi_set_situation(object, value): def itemsuivi_set_situation(obj, value):
"""set situation""" """set situation"""
if not sco_permissions_check.can_edit_suivi(): if not sco_permissions_check.can_edit_suivi():
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 !")
itemsuivi_id = object itemsuivi_id = obj
situation = value.strip("-_ \t") situation = value.strip("-_ \t")
# log('itemsuivi_set_situation %s : %s' % (itemsuivi_id, situation)) # log('itemsuivi_set_situation %s : %s' % (itemsuivi_id, situation))
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()

View File

@ -29,7 +29,7 @@
(portage from DTML) (portage from DTML)
""" """
import flask import flask
from flask import flash, g, url_for, request from flask import flash, g, url_for, render_template, request
import sqlalchemy import sqlalchemy
from app import db from app import db
@ -54,7 +54,6 @@ def formation_delete(formation_id=None, dialog_confirmed=False):
formation: Formation = Formation.query.get_or_404(formation_id) formation: Formation = Formation.query.get_or_404(formation_id)
H = [ H = [
html_sco_header.sco_header(page_title="Suppression d'une formation"),
f"""<h2>Suppression de la formation {formation.titre} ({formation.acronyme})</h2>""", f"""<h2>Suppression de la formation {formation.titre} ({formation.acronyme})</h2>""",
] ]
formsemestres = formation.formsemestres.all() formsemestres = formation.formsemestres.all()
@ -85,6 +84,7 @@ def formation_delete(formation_id=None, dialog_confirmed=False):
OK="Supprimer cette formation", OK="Supprimer cette formation",
cancel_url=url_for("notes.index_html", scodoc_dept=g.scodoc_dept), cancel_url=url_for("notes.index_html", scodoc_dept=g.scodoc_dept),
parameters={"formation_id": formation_id}, parameters={"formation_id": formation_id},
template="sco_page_dept.j2",
) )
else: else:
do_formation_delete(formation_id) do_formation_delete(formation_id)
@ -95,8 +95,9 @@ def formation_delete(formation_id=None, dialog_confirmed=False):
}">continuer</a></p>""" }">continuer</a></p>"""
) )
H.append(html_sco_header.sco_footer()) return render_template(
return "\n".join(H) "sco_page-dept.j2", content="\n".join(H), title="Suppression d'une formation"
)
def do_formation_delete(formation_id): def do_formation_delete(formation_id):

View File

@ -51,7 +51,6 @@ from app.scodoc.sco_exceptions import (
ScoGenError, ScoGenError,
ScoNonEmptyFormationObject, ScoNonEmptyFormationObject,
) )
from app.scodoc import html_sco_header
from app.scodoc import codes_cursus from app.scodoc import codes_cursus
from app.scodoc import sco_edit_matiere from app.scodoc import sco_edit_matiere
from app.scodoc import sco_moduleimpl from app.scodoc import sco_moduleimpl
@ -208,8 +207,8 @@ def module_delete(module_id=None):
) )
H = [ H = [
html_sco_header.sco_header(page_title="Suppression d'un module"), f"""<h2>Suppression du module {module.titre or "<em>sans titre</em>"}
f"""<h2>Suppression du module {module.titre or "<em>sans titre</em>"} ({module.code})</h2>""", ({module.code})</h2>""",
] ]
dest_url = url_for( dest_url = url_for(
@ -227,7 +226,11 @@ def module_delete(module_id=None):
cancelbutton="Annuler", cancelbutton="Annuler",
) )
if tf[0] == 0: if tf[0] == 0:
return "\n".join(H) + tf[1] + html_sco_header.sco_footer() return render_template(
"sco_page_dept.j2",
title="Suppression d'un module",
content="\n".join(H) + tf[1],
)
elif tf[0] == -1: elif tf[0] == -1:
return flask.redirect(dest_url) return flask.redirect(dest_url)
else: else:
@ -372,16 +375,6 @@ def module_edit(
""" """
H = [ H = [
html_sco_header.sco_header(
page_title=page_title,
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css"],
javascripts=[
"libjs/jQuery-tagEditor/jquery.tag-editor.min.js",
"libjs/jQuery-tagEditor/jquery.caret.min.js",
"js/module_tag_editor.js",
"js/module_edit.js",
],
),
f"""<h2>{title}</h2>""", f"""<h2>{title}</h2>""",
render_template( render_template(
"scodoc/help/modules.j2", "scodoc/help/modules.j2",
@ -780,7 +773,7 @@ def module_edit(
scu.get_request_args(), scu.get_request_args(),
descr, descr,
html_foot_markup=( html_foot_markup=(
f"""<div class="sco_tag_module_edit"><span f"""<div class="scobox sco_tag_module_edit"><span
class="sco_tag_edit"><textarea data-module_id="{module_id}" class="module_tag_editor" class="sco_tag_edit"><textarea data-module_id="{module_id}" class="module_tag_editor"
>{','.join(sco_tag_module.module_tag_list(module_id))}</textarea></span></div> >{','.join(sco_tag_module.module_tag_list(module_id))}</textarea></span></div>
""" """
@ -793,8 +786,17 @@ def module_edit(
) )
# #
if tf[0] == 0: if tf[0] == 0:
return ( return render_template(
"\n".join(H) "sco_page_dept.j2",
title=page_title,
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css"],
javascripts=[
"libjs/jQuery-tagEditor/jquery.tag-editor.min.js",
"libjs/jQuery-tagEditor/jquery.caret.min.js",
"js/module_tag_editor.js",
"js/module_edit.js",
],
content="\n".join(H)
+ tf[1] + tf[1]
+ ( + (
f""" f"""
@ -805,8 +807,7 @@ def module_edit(
""" """
if not create if not create
else "" else ""
) ),
+ html_sco_header.sco_footer()
) )
elif tf[0] == -1: elif tf[0] == -1:
return flask.redirect( return flask.redirect(
@ -904,9 +905,6 @@ def module_table(formation_id):
raise ScoValueError("invalid formation !") raise ScoValueError("invalid formation !")
formation: Formation = Formation.query.get_or_404(formation_id) formation: Formation = Formation.query.get_or_404(formation_id)
H = [ H = [
html_sco_header.sco_header(
page_title=f"Liste des modules de {formation.titre}"
),
f"""<h2>Listes des modules dans la formation {formation.titre} ({formation.acronyme}</h2> f"""<h2>Listes des modules dans la formation {formation.titre} ({formation.acronyme}</h2>
<ul class="notes_module_list"> <ul class="notes_module_list">
""", """,
@ -926,8 +924,11 @@ def module_table(formation_id):
) )
H.append("</li>") H.append("</li>")
H.append("</ul>") H.append("</ul>")
H.append(html_sco_header.sco_footer()) return render_template(
return "\n".join(H) "sco_page_dept.j2",
title=f"Liste des modules de {formation.titre}",
content="\n".join(H),
)
def module_is_locked(module_id): def module_is_locked(module_id):

View File

@ -505,8 +505,11 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
else: else:
clone_form = "" clone_form = ""
return f""" return render_template(
{html_sco_header.sco_header(page_title=title, javascripts=["js/edit_ue.js"])} "sco_page_dept.j2",
title=title,
javascripts=["js/edit_ue.js"],
content=f"""
<h2>{title}, (formation {formation.acronyme}, version {formation.version})</h2> <h2>{title}, (formation {formation.acronyme}, version {formation.version})</h2>
<p class="help">Les UEs sont des groupes de modules dans une formation donnée, <p class="help">Les UEs sont des groupes de modules dans une formation donnée,
utilisés pour la validation (on calcule des moyennes par UE et applique des utilisés pour la validation (on calcule des moyennes par UE et applique des
@ -529,9 +532,8 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
<div id="bonus_description" class="scobox"></div> <div id="bonus_description" class="scobox"></div>
<div id="ue_list_code" class="sco_box sco_green_bg"></div> <div id="ue_list_code" class="sco_box sco_green_bg"></div>
""",
{html_sco_header.sco_footer()} )
"""
elif tf[0] == 1: elif tf[0] == 1:
if create: if create:
if not tf[2]["ue_code"]: if not tf[2]["ue_code"]:

View File

@ -486,7 +486,8 @@ def formsemestre_evaluations_cal(formsemestre_id):
<div class="cal_evaluations"> <div class="cal_evaluations">
{ cal_html } { cal_html }
</div> </div>
<p>soit {nb_evals} évaluations planifiées; <div class="scobox maxwidth">
<p>soit {nb_evals} évaluations planifiées&nbsp;:
</p> </p>
<ul> <ul>
<li>en <span style= <li>en <span style=
@ -508,6 +509,7 @@ def formsemestre_evaluations_cal(formsemestre_id):
) )
}" class="stdlink">voir les délais de correction</a> }" class="stdlink">voir les délais de correction</a>
</p> </p>
</div>
""", """,
) )

View File

@ -825,7 +825,7 @@ def excel_feuille_listeappel(
ws.append_blank_row() ws.append_blank_row()
# bas de page (date, serveur) # bas de page (date, serveur)
dt = time.strftime("%d/%m/%Y à %Hh%M") dt = time.strftime(scu.DATEATIME_FMT)
if server_name: if server_name:
dt += " sur " + server_name dt += " sur " + server_name
cell_2 = ws.make_cell(("Liste éditée le " + dt), style1i) cell_2 = ws.make_cell(("Liste éditée le " + dt), style1i)

View File

@ -174,7 +174,9 @@ def formation_table_recap(formation: Formation, fmt="html") -> Response:
preferences=sco_preferences.SemPreferences(), preferences=sco_preferences.SemPreferences(),
table_id="formation_table_recap", table_id="formation_table_recap",
) )
return tab.make_page(fmt=fmt, javascripts=["js/formation_recap.js"]) return tab.make_page(
fmt=fmt, javascripts=["js/formation_recap.js"], template="sco_page_dept.j2"
)
def export_recap_formations_annee_scolaire(annee_scolaire): def export_recap_formations_annee_scolaire(annee_scolaire):

View File

@ -149,6 +149,7 @@ def formsemestre_associate_new_version(
"formation_id": formation_id, "formation_id": formation_id,
"formsemestre_id": formsemestre_id, "formsemestre_id": formsemestre_id,
}, },
template="sco_page_dept.j2",
) )
elif request.method == "POST": elif request.method == "POST":
if formsemestre_id is not None: # pas dans le form car checkbox disabled if formsemestre_id is not None: # pas dans le form car checkbox disabled

View File

@ -60,7 +60,6 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_vdi import ApoEtapeVDI from app.scodoc.sco_vdi import ApoEtapeVDI
from app.scodoc import html_sco_header
from app.scodoc import codes_cursus from app.scodoc import codes_cursus
from app.scodoc import sco_edit_module from app.scodoc import sco_edit_module
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
@ -80,20 +79,20 @@ def _default_sem_title(formation):
def formsemestre_createwithmodules(): def formsemestre_createwithmodules():
"""Page création d'un semestre""" """Page création d'un semestre"""
H = [ H = ["""<h2>Mise en place d'un semestre de formation</h2>"""]
html_sco_header.sco_header(
page_title="Création d'un semestre",
javascripts=["libjs/AutoSuggest.js", "js/formsemestre_edit.js"],
cssstyles=["css/autosuggest_inquisitor.css"],
),
"""<h2>Mise en place d'un semestre de formation</h2>""",
]
r = do_formsemestre_createwithmodules() r = do_formsemestre_createwithmodules()
if isinstance(r, str): if not isinstance(r, str):
H.append(r)
else:
return r # response redirect return r # response redirect
return "\n".join(H) + html_sco_header.sco_footer()
H.append(r)
return render_template(
"sco_page_dept.j2",
title="Création d'un semestre",
content="\n".join(H),
javascripts=["libjs/AutoSuggest.js", "js/formsemestre_edit.js"],
cssstyles=["css/autosuggest_inquisitor.css"],
)
def formsemestre_editwithmodules(formsemestre_id: int): def formsemestre_editwithmodules(formsemestre_id: int):

View File

@ -802,7 +802,7 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str:
})</span></h3>""" })</span></h3>"""
) )
# #
H.append('<div class="sem-groups-abs">') H.append('<div class="sem-groups-abs space-before-18">')
disable_abs: str | bool = scass.has_assiduites_disable_pref(formsemestre) disable_abs: str | bool = scass.has_assiduites_disable_pref(formsemestre)
show_abs: str = "hidden" if disable_abs else "" show_abs: str = "hidden" if disable_abs else ""
@ -812,6 +812,8 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str:
groups = partition.groups.all() groups = partition.groups.all()
effectifs = {g.id: g.get_nb_inscrits() for g in groups} effectifs = {g.id: g.get_nb_inscrits() for g in groups}
partition_is_empty = sum(effectifs.values()) == 0 partition_is_empty = sum(effectifs.values()) == 0
if partition_is_empty and (partition.is_default() or partition.is_parcours()):
continue # inutile de montrer des partitions vides non éditables
H.append( H.append(
f""" f"""
<div class="sem-groups-partition"> <div class="sem-groups-partition">
@ -909,7 +911,9 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str:
) )
H.append("</div>") # /sem-groups-assi H.append("</div>") # /sem-groups-assi
if partition_is_empty and not partition.is_default(): if partition_is_empty and not (
partition.is_default() or partition.is_parcours()
):
H.append( H.append(
'<div class="help sem-groups-none">Aucun groupe peuplé dans cette partition' '<div class="help sem-groups-none">Aucun groupe peuplé dans cette partition'
) )
@ -924,41 +928,72 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str:
H.append("</div>") H.append("</div>")
H.append("</div>") # /sem-groups-partition H.append("</div>") # /sem-groups-partition
# Boite avec liens divers
autres_liens = []
if formsemestre.can_change_groups(): if formsemestre.can_change_groups():
H.append( autres_liens.append(
f"""<h4><a class="stdlink" f"""<a class="stdlink"
title="une partition est un ensemble de groupes: TD, TP, ..."
href="{url_for("scolar.partition_editor", href="{url_for("scolar.partition_editor",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id, formsemestre_id=formsemestre.id,
edit_partition=1) edit_partition=1)
}">Ajouter une partition</a></h4>""" }">Ajouter une partition</a>"""
) )
# --- Formulaire importation Assiduité excel (si autorisé) # --- Formulaire importation Assiduité excel (si autorisé)
if current_user.has_permission(Permission.AbsChange) and not disable_abs: if current_user.has_permission(Permission.AbsChange) and not disable_abs:
H.append( autres_liens.append(
f"""<p> f"""
<a class="stdlink" href="{url_for('assiduites.feuille_abs_formsemestre', <a class="stdlink" href="{url_for('assiduites.feuille_abs_formsemestre',
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id)}"> formsemestre_id=formsemestre.id)}">
Importation de l'assiduité depuis un fichier excel</a> Importation de l'assiduité depuis un fichier excel</a>
</p>""" """
) )
# --- Lien Traitement Justificatifs: # --- Lien Traitement Justificatifs:
if ( if (
current_user.has_permission(Permission.AbsJustifView) current_user.has_permission(Permission.AbsJustifView)
and current_user.has_permission(Permission.JustifValidate) and current_user.has_permission(Permission.JustifValidate)
and not disable_abs and not disable_abs
): ):
H.append( autres_liens.append(
f"""<p> f"""
<a class="stdlink" href="{url_for('assiduites.traitement_justificatifs', <a class="stdlink" href="{url_for('assiduites.traitement_justificatifs',
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id)}"> formsemestre_id=formsemestre.id)}">
Traitement des justificatifs d'absence</a> Traitement des justificatifs d'absence</a>
</p>""" """
)
# --- Lien pour mail aux enseignants
# Construit la liste de tous les enseignants de ce semestre:
mails_enseignants = set(u.email for u in formsemestre.responsables)
for modimpl in formsemestre.modimpls_sorted:
mails_enseignants.add(sco_users.user_info(modimpl.responsable_id)["email"])
mails_enseignants |= {u.email for u in modimpl.enseignants if u.email}
adrlist = list(mails_enseignants - {None, ""})
if adrlist:
autres_liens.append(
f"""
<a class="stdlink" href="mailto:?cc={','.join(adrlist)}">Courrier aux {
len(adrlist)} enseignants du semestre</a>
"""
)
# Met le tout en boite
if autres_liens:
H.append(
f"""
<div class="sem-groups-partition sem-groups-autres-liens">
<div class="sem-groups-none">
<ul>
<li>{'</li><li>'.join(autres_liens)}</li>
</ul>
</div>
</div>
"""
) )
H.append("</div>") H.append("</div>")
@ -1033,8 +1068,9 @@ def formsemestre_status_head(formsemestre_id: int = None, page_title: str = None
) )
if evals["last_modif"]: if evals["last_modif"]:
H.append( H.append(
" <em>(dernière note saisie le %s)</em>" f""" <em>(dernière note saisie le {
% evals["last_modif"].strftime("%d/%m/%Y à %Hh%M") evals["last_modif"].strftime(scu.DATEATIME_FMT)
})</em>"""
) )
H.append("</td></tr>") H.append("</td></tr>")
H.append("</table>") H.append("</table>")
@ -1073,12 +1109,6 @@ def formsemestre_status(formsemestre_id=None, check_parcours=True):
modimpls = formsemestre.modimpls_sorted modimpls = formsemestre.modimpls_sorted
nt = res_sem.load_formsemestre_results(formsemestre) nt = res_sem.load_formsemestre_results(formsemestre)
# Construit la liste de tous les enseignants de ce semestre:
mails_enseignants = set(u.email for u in formsemestre.responsables)
for modimpl in modimpls:
mails_enseignants.add(sco_users.user_info(modimpl.responsable_id)["email"])
mails_enseignants |= {u.email for u in modimpl.enseignants if u.email}
can_edit = formsemestre.can_be_edited_by(current_user) can_edit = formsemestre.can_be_edited_by(current_user)
can_change_all_notes = current_user.has_permission(Permission.EditAllNotes) or ( can_change_all_notes = current_user.has_permission(Permission.EditAllNotes) or (
current_user.id in [resp.id for resp in formsemestre.responsables] current_user.id in [resp.id for resp in formsemestre.responsables]
@ -1206,20 +1236,11 @@ def formsemestre_status(formsemestre_id=None, check_parcours=True):
) )
# --- LISTE DES ETUDIANTS # --- LISTE DES ETUDIANTS
H += [ H += [
'<div class="formsemestre-groupes">', '<div class="formsemestre-groupes space-before-24">',
_make_listes_sem(formsemestre), _make_listes_sem(formsemestre),
"</div>", "</div>",
] ]
# --- Lien mail enseignants:
adrlist = list(mails_enseignants - {None, ""})
if adrlist:
H.append(
f"""<p>
<a class="stdlink" href="mailto:?cc={','.join(adrlist)}">Courrier aux {
len(adrlist)} enseignants du semestre</a>
</p>"""
)
return render_template( return render_template(
"sco_page.j2", "sco_page.j2",
content="".join(H), content="".join(H),

View File

@ -583,6 +583,11 @@ def formsemestre_recap_parcours_table(
) )
is_cur = situation_etud_cursus.formsemestre_id == formsemestre.id is_cur = situation_etud_cursus.formsemestre_id == formsemestre.id
num_sem += 1 num_sem += 1
url_status = url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
)
dpv = sco_pv_dict.dict_pvjury(formsemestre.id, etudids=[etudid]) dpv = sco_pv_dict.dict_pvjury(formsemestre.id, etudids=[etudid])
pv = dpv["decisions"][0] pv = dpv["decisions"][0]
@ -642,7 +647,7 @@ def formsemestre_recap_parcours_table(
H.append( H.append(
f""" f"""
<td class="rcp_type_sem" style="background-color:{bgcolor};">{num_sem}{pm}</td> <td class="rcp_type_sem" style="background-color:{bgcolor};">{num_sem}{pm}</td>
<td class="datedebut">{formsemestre.mois_debut()}</td> <td class="datedebut"><a href="{url_status}">{formsemestre.mois_debut()}</a></td>
<td class="rcp_titre_sem"><a class="formsemestre_status_link" <td class="rcp_titre_sem"><a class="formsemestre_status_link"
href="{ href="{
url_for("notes.formsemestre_bulletinetud", scodoc_dept=g.scodoc_dept, url_for("notes.formsemestre_bulletinetud", scodoc_dept=g.scodoc_dept,
@ -724,8 +729,9 @@ def formsemestre_recap_parcours_table(
f"""Autre formation: {formsemestre.formation.formation_code}""" f"""Autre formation: {formsemestre.formation.formation_code}"""
) )
H.append( H.append(
'<td class="datefin">%s</td><td class="sem_info">%s</td>' f"""<td class="datefin"><a href="{url_status}">{formsemestre.mois_fin()}</a></td>
% (formsemestre.mois_fin(), sem_info.get(formsemestre.id, default_sem_info)) <td class="sem_info">{sem_info.get(formsemestre.id, default_sem_info)}</td>
"""
) )
# Moy Gen (sous le code decision) # Moy Gen (sous le code decision)
H.append( H.append(

View File

@ -65,7 +65,7 @@ def groups_export_annotations(group_ids, formsemestre_id=None, fmt="html"):
) )
annotations = groups_list_annotation(groups_infos.group_ids) annotations = groups_list_annotation(groups_infos.group_ids)
for annotation in annotations: for annotation in annotations:
annotation["date_str"] = annotation["date"].strftime("%d/%m/%Y à %Hh%M") annotation["date_str"] = annotation["date"].strftime(scu.DATEATIME_FMT)
if fmt == "xls": if fmt == "xls":
columns_ids = ("etudid", "nom", "prenom", "date", "comment") columns_ids = ("etudid", "nom", "prenom", "date", "comment")
else: else:

View File

@ -782,16 +782,21 @@ def groups_table(
[ [
tab.html(), tab.html(),
f""" f"""
<ul> <ul>
<li><a class="stdlink" href="{tab.base_url}&fmt=xls">Table Excel</a> <li><a class="stdlink" href="{tab.base_url}&fmt=xls">Table Excel
</li> groupe(s) {groups_infos.groups_titles}</a>
<li><a class="stdlink" href="{tab.base_url}&fmt=moodlecsv">Fichier CSV pour Moodle (groupe sélectionné)</a> </li>
</li> <li><a class="stdlink" href="{tab.base_url}&fmt=moodlecsv">Fichier CSV pour
<li> Moodle groupe(s) {groups_infos.groups_titles}</a>
<a class="stdlink" href="export_groups_as_moodle_csv?formsemestre_id={groups_infos.formsemestre_id}"> </li>
Fichier CSV pour Moodle (tous les groupes)</a> <li>
<em>(voir le paramétrage pour modifier le format des fichiers Moodle exportés)</em> <a class="stdlink" href="{{
</li>""", url_for('notes.export_groups_as_moodle_csv',
scodoc_dept=g.scodoc_dept, formsemestre_id=groups_infos.formsemestre_id)
}}">
Fichier CSV pour Moodle (tous les groupes)</a>
<em>(voir le paramétrage pour modifier le format des fichiers Moodle exportés)</em>
</li>""",
] ]
) )
if amail_inst: if amail_inst:

View File

@ -656,7 +656,7 @@ def _ligne_evaluation(
if etat["last_modif"]: if etat["last_modif"]:
H.append( H.append(
f"""<span class="mievr_lastmodif">(dernière modif le { f"""<span class="mievr_lastmodif">(dernière modif le {
etat["last_modif"].strftime("%d/%m/%Y à %Hh%M")})</span>""" etat["last_modif"].strftime(scu.DATEATIME_FMT)})</span>"""
) )
# #
H.append( H.append(

View File

@ -556,7 +556,7 @@ MONTH_NAMES = (
) )
DAY_NAMES = ("lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche") DAY_NAMES = ("lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche")
TIME_FMT = "%H:%M" # affichage des heures TIME_FMT = "%Hh%M" # affichage des heures
DATE_FMT = "%d/%m/%Y" # affichage des dates DATE_FMT = "%d/%m/%Y" # affichage des dates
DATEATIME_FMT = DATE_FMT + " à " + TIME_FMT DATEATIME_FMT = DATE_FMT + " à " + TIME_FMT
DATETIME_FMT = DATE_FMT + " " + TIME_FMT DATETIME_FMT = DATE_FMT + " " + TIME_FMT
@ -1339,7 +1339,7 @@ def format_telephone(n: str | None) -> str:
# #
def timedate_human_repr(): def timedate_human_repr():
"representation du temps courant pour utilisateur" "representation du temps courant pour utilisateur"
return time.strftime("%d/%m/%Y à %Hh%M") return time.strftime(DATEATIME_FMT)
def annee_scolaire_repr(year, month): def annee_scolaire_repr(year, month):
@ -1525,6 +1525,7 @@ def confirm_dialog(
help_msg=None, help_msg=None,
parameters: dict = None, parameters: dict = None,
target_variable="dialog_confirmed", target_variable="dialog_confirmed",
template="sco_page.j2",
): ):
"""HTML confirmation dialog: submit (POST) to same page or dest_url if given.""" """HTML confirmation dialog: submit (POST) to same page or dest_url if given."""
parameters = parameters or {} parameters = parameters or {}
@ -1565,7 +1566,7 @@ def confirm_dialog(
if help_msg: if help_msg:
H.append('<p class="help">' + help_msg + "</p>") H.append('<p class="help">' + help_msg + "</p>")
if add_headers: if add_headers:
return render_template("sco_page.j2", content="\n".join(H)) return render_template(template, content="\n".join(H))
else: else:
return "\n".join(H) return "\n".join(H)

View File

@ -55,13 +55,21 @@ div.container {
div.sco-app-content { div.sco-app-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-right: 8px; margin-right: 12px;
} }
.space-before-18 { .space-before-18 {
margin-top: 18px; margin-top: 18px;
} }
.space-before-24 {
margin-top: 24px;
}
div.scobox.maxwidth {
max-width: none;
}
div.scobox { div.scobox {
flex: 1 0 0; flex: 1 0 0;
/* Equal width for all boxes */ /* Equal width for all boxes */
@ -748,14 +756,14 @@ div.fiche_etud {
/* rgb(255,240,128); */ /* rgb(255,240,128); */
border: 1px solid gray; border: 1px solid gray;
width: 910px; width: 910px;
padding: 10px; padding: 24px 10px 10px 10px;
margin-top: 10px; margin-top: 10px;
} }
div.menus_etud { div.menus_etud {
position: absolute; position: absolute;
margin-left: 1px; margin-left: 10px;
margin-top: 1px; margin-top: 16px;
} }
div.fiche_etud h2 { div.fiche_etud h2 {
@ -2059,6 +2067,10 @@ ul.ue_inscr_list li.etud {
text-underline-offset: 3px; text-underline-offset: 3px;
} }
.sem-groups-autres-liens {
background-color: var(--sco-color-box-bg);
}
.sem-groups-list .stdlink, .sem-groups-list .stdlink,
.sem-groups-list .stdlink:visited { .sem-groups-list .stdlink:visited {
color: rgb(0, 0, 192); color: rgb(0, 0, 192);

View File

@ -45,7 +45,7 @@
<h2 style="color: crimson;">{{titre_form}}</h2> <h2 style="color: crimson;">{{titre_form}}</h2>
<div class="scobox"> <div class="scobox">
<div id="excel-content"> <div id="excel-content">
<p class="hint">Avertissement : le fichier doit respecter le format suivant</p> <p class="hint">Le fichier importé doit respecter le format suivant</p>
<ul> <ul>
<li> <li>
@ -53,12 +53,12 @@
</li> </li>
<li class="star">colonne B : Date de début</li> <li class="star">colonne B : Date de début</li>
<li class="star">colonne C : Date de fin</li> <li class="star">colonne C : Date de fin</li>
<li class="opt">colonne D : État (ABS,RET,PRE, ABS si vide)</li> <li class="opt">colonne D : État (ABS, RET, PRE), considéré ABSent si vide</li>
<li class="opt">colonne E : code du module</li> <li class="opt">colonne E : code du module</li>
</ul> </ul>
<p class="hint"><span class="opt"></span> : Colonne optionnelle, les cases peuvent être vides</p> <p class="hint"><span class="opt"></span> : Colonne optionnelle, les cases peuvent être vides</p>
<p class="hint"><span class="star"></span> : Formats autorisés : <p class="hint"><span class="star"></span> : Formats de dates autorisés :
<ul> <ul>
<li> <li>
<pre>aaaa-mm-jjThh:mm:ss</pre> <pre>aaaa-mm-jjThh:mm:ss</pre>
@ -73,21 +73,23 @@
<form action="" method="post" enctype="multipart/form-data"> <form action="" method="post" enctype="multipart/form-data">
<label for="type_identifiant">Type d'identifiant d'étudiant (etudid, ine, nip)</label> <label for="type_identifiant">Type d'identifiant d'étudiant (etudid, INE, NIP)</label>
<select name="type_identifiant" id="type_identifiant"> <select name="type_identifiant" id="type_identifiant">
<option value="etudid">ETUDID</option> <option value="etudid">etudid</option>
<option value="ine">INE</option> <option value="ine">INE</option>
<option value="nip">NIP</option> <option value="nip">NIP</option>
</select> </select>
<br> <div class="space-before-18">
<label for="file"> <label for="file">
Sélectionnez un fichier: Sélectionnez un fichier:
</label> </label>
<input id="file" type="file" name="file" <input id="file" type="file" name="file"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" /> accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" />
<br> </div>
<button type="submit">Importer</button> <div class="space-before-18">
<button type="submit">Importer</button>
</div>
</form> </form>
</div> </div>
</div> </div>

View File

@ -27,7 +27,7 @@
</span> </span>
</div> </div>
<div> <div>
<em>établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20)</em> <em>établi le {{time.strftime(scu.DATEATIME_FMT)}} (notes sur 20)</em>
<span class="rightjust"> <span class="rightjust">
<select name="version" onchange="self.location.href='{{ <select name="version" onchange="self.location.href='{{
url_for('notes.formsemestre_bulletinetud', url_for('notes.formsemestre_bulletinetud',

View File

@ -158,7 +158,7 @@
</div> </div>
<div id="footer"> <div id="footer">
Bulletin généré par ScoDoc le {{time.strftime("%d/%m/%Y à %Hh%M")}}. Explication des codes sur Bulletin généré par ScoDoc le {{time.strftime(scu.DATEATIME_FMT)}}. Explication des codes sur
<a href="https://scodoc.org/BUTCodesJury">https://scodoc.org/BUTCodesJury</a> <a href="https://scodoc.org/BUTCodesJury">https://scodoc.org/BUTCodesJury</a>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
{% extends "sco_page.j2" %} {% extends "sco_page_dept.j2" %}
{% block styles %} {% block styles %}
{{super()}} {{super()}}

View File

@ -1,5 +1,5 @@
{# -*- mode: jinja-html -*- #} {# -*- mode: jinja-html -*- #}
{% extends "base.j2" %} {% extends "sco_page_dept.j2" %}
{% import 'wtf.j2' as wtf %} {% import 'wtf.j2' as wtf %}
{% block app_content %} {% block app_content %}

View File

@ -1,5 +1,5 @@
{# -*- mode: jinja-html -*- #} {# -*- mode: jinja-html -*- #}
{% extends "sco_page.j2" %} {% extends "sco_page_dept.j2" %}
{% block styles %} {% block styles %}
{{super()}} {{super()}}
<link href="{{scu.STATIC_DIR}}/css/refcomp_parcours_niveaux.css" rel="stylesheet" type="text/css" /> <link href="{{scu.STATIC_DIR}}/css/refcomp_parcours_niveaux.css" rel="stylesheet" type="text/css" />

View File

@ -1,5 +1,5 @@
{# -*- mode: jinja-html -*- #} {# -*- mode: jinja-html -*- #}
{% extends "sco_page.j2" %} {% extends "sco_page_dept.j2" %}
{% import 'wtf.j2' as wtf %} {% import 'wtf.j2' as wtf %}
{% block app_content %} {% block app_content %}

View File

@ -51,7 +51,7 @@ une formation utilisant une autre version de référentiel, pensez à revalider
pour l'étudiant{{etud.ne}} {{etud.html_link_fiche()|safe}} pour l'étudiant{{etud.ne}} {{etud.html_link_fiche()|safe}}
<ul> <ul>
<li>DUT 120 spécialité {{formsemestre.formation.referentiel_competence.specialite_long}} <li>DUT 120 spécialité {{formsemestre.formation.referentiel_competence.specialite_long}}
enregistré le {{time.strftime("%d/%m/%Y à %Hh%M")}} enregistré le {{time.strftime(scu.DATEATIME_FMT)}}
</li> </li>
</ul> </ul>

View File

@ -1,5 +1,5 @@
{# Association d'ECTS à une UE par parcours #} {# Association d'ECTS à une UE par parcours #}
{% extends "sco_page.j2" %} {% extends "sco_page_dept.j2" %}
{% import 'wtf.j2' as wtf %} {% import 'wtf.j2' as wtf %}
{% block styles %} {% block styles %}
@ -23,18 +23,20 @@
<form method="POST"> <form method="POST">
{% for field in form %} {% for field in form %}
{% if field.name != 'csrf_token' %} {% if field.name != 'csrf_token' %}
<div> <div class="space-before-18">
<label for="{{ field.id }}">{{ field.label }}</label> <label for="{{ field.id }}">{{ field.label }}</label>
{{ field }} {{ field }}
{% for error in field.errors %} {% for error in field.errors %}
<div class="error-message">{{ error }}</div> <div class="error-message">{{ error }}</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{{ form.csrf_token }} {{ form.csrf_token }}
<input type="submit" name="submit" value="Enregistrer"> <div class="space-before-24">
<input type="submit" name="cancel" value="Annuler"> <input type="submit" name="submit" value="Enregistrer">
<input type="submit" name="cancel" value="Annuler">
</div>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -20,6 +20,7 @@
<div class="tab-content"> <div class="tab-content">
<h2>{{ title }}</h2> <h2>{{ title }}</h2>
<div class="scobox">
<p class="help"> <p class="help">
{{ explanation|safe }} {{ explanation|safe }}
</p> </p>
@ -46,5 +47,6 @@
<input type="submit" value="Générer"> <input type="submit" value="Générer">
</div> </div>
</form> </form>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,26 @@
{# -*- mode: jinja-html -*- #} {# -*- mode: jinja-html -*- #}
{% extends "sco_page_dept.j2" %}
{% block styles %}
{{super()}}
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/table_editor.css">
{% endblock %}
{% block app_content %}
<h2>Formation {{formation.titre}} ({{formation.acronyme}})
[version {{formation.version}}] code {{formation.formation_code}}
{% if read_only %}
{{scu.icontag("lock32_img", title="verrouillé")|safe}}
{% endif %}
</h2>
{% if read_only %}
<span class="warning">
Formation verrouilée car un ou plusieurs semestres verrouillés l'utilisent.
</span>
{% endif %}
<h2>{% if not read_only %}Édition des c{% else %}C{%endif%}oefficients des modules vers les UEs</h2> <h2>{% if not read_only %}Édition des c{% else %}C{%endif%}oefficients des modules vers les UEs</h2>
<div class="help"> <div class="help">
{% if not read_only %} {% if not read_only %}
@ -59,8 +81,11 @@
<div class="champs_coef_hors_parcours champs_legende"></div> <div class="champs_coef_hors_parcours champs_legende"></div>
<div class="help">module non associé au parcours de cette UE, le coef devrait être nul.</div> <div class="help">module non associé au parcours de cette UE, le coef devrait être nul.</div>
</div> </div>
{% endblock %}
{% block scripts %}
{{super()}}
<script src="{{scu.STATIC_DIR}}/js/table_editor.js"></script>
<script> <script>
var read_only = {{ "true" if read_only else "false"}}; var read_only = {{ "true" if read_only else "false"}};
$(function () { $(function () {
@ -113,3 +138,4 @@
return true; return true;
} }
</script> </script>
{% endblock %}

View File

@ -31,24 +31,18 @@ PN / Edition des coefs
Emmanuel Viennet, 2021 Emmanuel Viennet, 2021
""" """
from flask import url_for from flask import g, render_template, request, url_for
from flask import g, request
from flask_json import as_json from flask_json import as_json
from flask_login import current_user from flask_login import current_user
from flask.templating import render_template
from app.scodoc.codes_cursus import UE_SPORT
from app import db, models from app import db, models
from app.comp import moy_ue from app.comp import moy_ue
from app.decorators import scodoc, permission_required from app.decorators import scodoc, permission_required
from app.models import ApcParcours, Formation, Module from app.models import ApcParcours, Formation, Module
from app.views import notes_bp as bp from app.scodoc.codes_cursus import UE_SPORT
from app.scodoc import html_sco_header
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.views import notes_bp as bp
@bp.route("/table_modules_ue_coefs/<int:formation_id>") @bp.route("/table_modules_ue_coefs/<int:formation_id>")
@ -197,51 +191,23 @@ def edit_modules_ue_coefs():
formation_id=formation_id formation_id=formation_id
).first_or_404() ).first_or_404()
locked = formation.has_locked_sems(semestre_idx) locked = formation.has_locked_sems(semestre_idx)
if locked: return render_template(
lockicon = scu.icontag("lock32_img", title="verrouillé") "pn/form_modules_ue_coefs.j2",
else: formation=formation,
lockicon = "" data_source=url_for(
H = [ "notes.table_modules_ue_coefs",
html_sco_header.sco_header( scodoc_dept=g.scodoc_dept,
cssstyles=["css/table_editor.css"], formation_id=formation_id,
javascripts=[
"js/table_editor.js",
],
page_title=f"Coefs programme {formation.acronyme}",
),
f"""<h2>Formation {formation.titre} ({formation.acronyme})
[version {formation.version}] code {formation.formation_code}
{lockicon}
</h2>
""",
(
"""<span class="warning">Formation verrouilée car un ou plusieurs
semestres verrouillés l'utilisent.
</span>"""
if locked
else ""
),
render_template(
"pn/form_modules_ue_coefs.j2",
formation=formation,
data_source=url_for(
"notes.table_modules_ue_coefs",
scodoc_dept=g.scodoc_dept,
formation_id=formation_id,
semestre_idx=semestre_idx,
parcours_id=parcours_id,
),
data_save=url_for(
"notes.set_module_ue_coef",
scodoc_dept=g.scodoc_dept,
),
read_only=locked
or not current_user.has_permission(Permission.EditFormation),
semestre_idx=semestre_idx, semestre_idx=semestre_idx,
semestre_ids=range(1, formation.get_cursus().NB_SEM + 1),
parcours_id=parcours_id, parcours_id=parcours_id,
), ),
html_sco_header.sco_footer(), data_save=url_for(
] "notes.set_module_ue_coef",
scodoc_dept=g.scodoc_dept,
return "\n".join(H) ),
read_only=locked or not current_user.has_permission(Permission.EditFormation),
semestre_idx=semestre_idx,
semestre_ids=range(1, formation.get_cursus().NB_SEM + 1),
parcours_id=parcours_id,
title=f"Coefs programme {formation.acronyme}",
)

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.7.6" SCOVERSION = "9.7.7"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"