user_board: icon saisie absences + organisation par dept

This commit is contained in:
Emmanuel Viennet 2023-12-31 22:18:52 +01:00
parent f7d16900b1
commit 97eb18361f
3 changed files with 68 additions and 33 deletions

View File

@ -18,7 +18,7 @@ from operator import attrgetter
from flask_login import current_user from flask_login import current_user
from flask import flash, g, url_for from flask import abort, flash, g, url_for
from sqlalchemy.sql import text from sqlalchemy.sql import text
from sqlalchemy import func from sqlalchemy import func
@ -185,9 +185,14 @@ class FormSemestre(db.Model):
@classmethod @classmethod
def get_formsemestre( def get_formsemestre(
cls, formsemestre_id: int, dept_id: int = None cls, formsemestre_id: int | str, dept_id: int = None
) -> "FormSemestre": ) -> "FormSemestre":
""" "FormSemestre ou 404, cherche uniquement dans le département spécifié ou le courant""" """ "FormSemestre ou 404, cherche uniquement dans le département spécifié ou le courant"""
if not isinstance(formsemestre_id, int):
try:
formsemestre_id = int(formsemestre_id)
except (TypeError, ValueError):
abort(404, "formsemestre_id invalide")
if g.scodoc_dept: if g.scodoc_dept:
dept_id = dept_id if dept_id is not None else g.scodoc_dept_id dept_id = dept_id if dept_id is not None else g.scodoc_dept_id
if dept_id is not None: if dept_id is not None:
@ -385,13 +390,18 @@ class FormSemestre(db.Model):
return ues return ues
@classmethod @classmethod
def get_user_formsemestres_annee( def get_user_formsemestres_annee_by_dept(
cls, user: User cls, user: User
) -> tuple[list["FormSemestre"], defaultdict[int, list[ModuleImpl]]]: ) -> tuple[
defaultdict[int, list["FormSemestre"]], defaultdict[int, list[ModuleImpl]]
]:
"""Liste des formsemestres de l'année scolaire """Liste des formsemestres de l'année scolaire
dans lesquels user intervient (comme resp., resp. de module ou enseignant), dans lesquels user intervient (comme resp., resp. de module ou enseignant),
ainsi que la liste des modimpls concernés dans chaque formsemestre ainsi que la liste des modimpls concernés dans chaque formsemestre
Attention: les semestres et modimpls peuvent être de différents départements ! Attention: les semestres et modimpls peuvent être de différents départements !
Résultat:
{ dept_id : [ formsemestre, ... ] },
{ formsemestre_id : [ modimpl, ... ]}
""" """
debut_annee_scolaire = scu.date_debut_annee_scolaire() debut_annee_scolaire = scu.date_debut_annee_scolaire()
fin_annee_scolaire = scu.date_fin_annee_scolaire() fin_annee_scolaire = scu.date_fin_annee_scolaire()
@ -439,9 +449,11 @@ class FormSemestre(db.Model):
formsemestres.append(modimpl.formsemestre) formsemestres.append(modimpl.formsemestre)
ids.add(modimpl.formsemestre_id) ids.add(modimpl.formsemestre_id)
modimpls_by_formsemestre[modimpl.formsemestre_id].append(modimpl) modimpls_by_formsemestre[modimpl.formsemestre_id].append(modimpl)
# Tris # Tris et organisation par département
formsemestres_by_dept = defaultdict(lambda: [])
formsemestres.sort(key=lambda x: (x.departement.acronym,) + x.sort_key()) formsemestres.sort(key=lambda x: (x.departement.acronym,) + x.sort_key())
for formsemestre in formsemestres: for formsemestre in formsemestres:
formsemestres_by_dept[formsemestre.dept_id].append(formsemestre)
modimpls = modimpls_by_formsemestre[formsemestre.id] modimpls = modimpls_by_formsemestre[formsemestre.id]
if formsemestre.formation.is_apc(): if formsemestre.formation.is_apc():
key = lambda x: x.module.sort_key_apc() key = lambda x: x.module.sort_key_apc()
@ -449,7 +461,7 @@ class FormSemestre(db.Model):
key = lambda x: x.module.sort_key() key = lambda x: x.module.sort_key()
modimpls.sort(key=key) modimpls.sort(key=key)
return formsemestres, modimpls_by_formsemestre return formsemestres_by_dept, modimpls_by_formsemestre
def get_evaluations(self) -> list[Evaluation]: def get_evaluations(self) -> list[Evaluation]:
"Liste de toutes les évaluations du semestre, triées par module/numero" "Liste de toutes les évaluations du semestre, triées par module/numero"

View File

@ -65,9 +65,10 @@
<div class="tab-content"> <div class="tab-content">
<h2>Votre tableau de bord, {{user.get_nomcomplet()}}</h2> <h2>Votre tableau de bord, {{user.get_nomcomplet()}}</h2>
<h3>Vos modules</h3> {% for dept_id in formsemestres_by_dept %}
<h3>Modules dans le département {{ dept_names[dept_id] }}</h3>
<div class="ub-formsemestres"> <div class="ub-formsemestres">
{% for formsemestre in formsemestres %} {% for formsemestre in formsemestres_by_dept[dept_id] %}
<div class="ub-formsemestre"> <div class="ub-formsemestre">
<div class="ub-sem-titre">{{formsemestre.html_link_status()|safe}}</div> <div class="ub-sem-titre">{{formsemestre.html_link_status()|safe}}</div>
<div class="ub-sem-modimpls"> <div class="ub-sem-modimpls">
@ -83,6 +84,16 @@
scodoc_dept=formsemestre.departement.acronym, moduleimpl_id=modimpl.id) scodoc_dept=formsemestre.departement.acronym, moduleimpl_id=modimpl.id)
}}">{{modimpl.module.titre_str()}}</a> }}">{{modimpl.module.titre_str()}}</a>
</span> </span>
<span><a class="stdlink" href="{{
url_for(
'assiduites.signal_assiduites_group',
scodoc_dept=formsemestre.departement.acronym,
formsemestre_id=formsemestre.id,
moduleimpl_id=modimpl.id,
)}}"><img height="28px" src="{{scu.STATIC_DIR}}/icons/absences.svg"
title="saisir absences" alt="saisir absences"/>
</a>
</span>
</div> </div>
{% else %} {% else %}
<div class="empty">pas de modules</div> <div class="empty">pas de modules</div>
@ -91,6 +102,7 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% endfor %}
</div> </div>
{% endblock app_content %} {% endblock app_content %}

View File

@ -12,8 +12,9 @@ from app.decorators import (
scodoc, scodoc,
permission_required, permission_required,
) )
from app.models import FormSemestre from app.models import Departement, FormSemestre
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.views import scolar_bp as bp from app.views import scolar_bp as bp
from app.views import ScoData from app.views import ScoData
@ -25,13 +26,23 @@ from app.views import ScoData
def user_board(user_name: str): def user_board(user_name: str):
"""Tableau de bord utilisateur: liens vers ses objets""" """Tableau de bord utilisateur: liens vers ses objets"""
user = User.query.filter_by(user_name=user_name).first_or_404() user = User.query.filter_by(user_name=user_name).first_or_404()
formsemestres, modimpls_by_formsemestre = FormSemestre.get_user_formsemestres_annee( (
user formsemestres_by_dept,
) modimpls_by_formsemestre,
) = FormSemestre.get_user_formsemestres_annee_by_dept(user)
dept_names = {
dept_id: sco_preferences.get_preference("DeptName", dept_id=dept_id)
for dept_id in formsemestres_by_dept
}
dept_names_sorted = {
dept_id: dept_name
for (dept_id, dept_name) in sorted(dept_names.items(), key=lambda x: x[1])
}
# TODO: le calendrier avec ses enseignements # TODO: le calendrier avec ses enseignements
return render_template( return render_template(
"user_board/user_board.j2", "user_board/user_board.j2",
formsemestres=formsemestres, dept_names=dept_names_sorted,
formsemestres_by_dept=formsemestres_by_dept,
modimpls_by_formsemestre=modimpls_by_formsemestre, modimpls_by_formsemestre=modimpls_by_formsemestre,
sco=ScoData(), sco=ScoData(),
title=f"{user.get_prenomnom()}: tableau de bord", title=f"{user.get_prenomnom()}: tableau de bord",