forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -171,7 +171,7 @@ class Identite(db.Model, models.ScoDocModel):
|
||||
|
||||
def html_link_fiche(self) -> str:
|
||||
"lien vers la fiche"
|
||||
return f"""<a class="stdlink" href="{self.url_fiche()}">{self.nomprenom}</a>"""
|
||||
return f"""<a class="etudlink" href="{self.url_fiche()}">{self.nomprenom}</a>"""
|
||||
|
||||
def url_fiche(self) -> str:
|
||||
"url de la fiche étudiant"
|
||||
@ -319,6 +319,8 @@ class Identite(db.Model, models.ScoDocModel):
|
||||
@cached_property
|
||||
def sort_key(self) -> tuple:
|
||||
"clé pour tris par ordre alphabétique"
|
||||
# Note: scodoc7 utilisait sco_etud.etud_sort_key, à mettre à jour
|
||||
# si on modifie cette méthode.
|
||||
return (
|
||||
scu.sanitize_string(
|
||||
self.nom_usuel or self.nom or "", remove_spaces=False
|
||||
|
@ -334,9 +334,9 @@ def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
||||
|
||||
"""
|
||||
req = """SELECT E.id AS evaluation_id, E.*
|
||||
FROM notes_evaluation E, notes_moduleimpl MI
|
||||
WHERE MI.formsemestre_id = %(formsemestre_id)s
|
||||
and MI.id = E.moduleimpl_id
|
||||
FROM notes_evaluation E, notes_moduleimpl MI
|
||||
WHERE MI.formsemestre_id = %(formsemestre_id)s
|
||||
and MI.id = E.moduleimpl_id
|
||||
ORDER BY MI.id, numero desc, date_debut desc
|
||||
"""
|
||||
cnx = ndb.GetDBConnexion()
|
||||
@ -494,7 +494,7 @@ def formsemestre_evaluations_cal(formsemestre_id):
|
||||
</p>
|
||||
<ul>
|
||||
<li>en <span style=
|
||||
"background-color: {color_incomplete}">rouge</span>
|
||||
"background-color: {color_incomplete}">rouge</span>
|
||||
les évaluations passées auxquelles il manque des notes
|
||||
</li>
|
||||
<li>en <span style=
|
||||
@ -654,7 +654,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, link_saisie=True):
|
||||
can_edit = modimpl.can_edit_notes(current_user, allow_ens=False)
|
||||
|
||||
mod_descr = f"""<a class="stdlink" href="{url_for("notes.moduleimpl_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
moduleimpl_id=modimpl.id,
|
||||
)}">{modimpl.module.code or ""} {modimpl.module.abbrev or modimpl.module.titre or "?"}</a>
|
||||
<span class="resp">(resp. <a title="{resp_nomcomplet}">{resp_nomprenom}</a>)</span>
|
||||
@ -690,9 +690,9 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, link_saisie=True):
|
||||
H.append(
|
||||
f"""<span class="evallink"><a class="stdlink" href="{url_for(
|
||||
'assiduites.etat_abs_date',
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
group_ids=group_id,
|
||||
desc=evaluation.description or "",
|
||||
evaluation_id=evaluation.id,
|
||||
date_debut=evaluation.date_debut.isoformat(),
|
||||
date_fin=evaluation.date_fin.isoformat(),
|
||||
)
|
||||
|
@ -257,10 +257,11 @@ def get_sem_groups(formsemestre_id):
|
||||
)
|
||||
|
||||
|
||||
def get_group_members(group_id, etat=None):
|
||||
def get_group_members(group_id: int, etat=None) -> list[dict]:
|
||||
"""Liste des etudiants d'un groupe.
|
||||
Si etat, filtre selon l'état de l'inscription
|
||||
Trié par nom_usuel (ou nom) puis prénom
|
||||
Résultat: list de dict avec champs étudiant, adresse, group_membership
|
||||
"""
|
||||
req = """SELECT i.id as etudid, i.*, a.*, gm.*, ins.etat
|
||||
FROM identite i, adresse a, group_membership gm,
|
||||
|
@ -304,7 +304,7 @@ class DisplayedGroupsInfos:
|
||||
.groups_query_args : 'group_ids=xxx&group_ids=yyy'
|
||||
.base_url : url de la requete, avec les groupes, sans les autres paramètres
|
||||
.formsemestre_id : semestre "principal" (en fait celui du 1er groupe de la liste)
|
||||
.members
|
||||
.members :
|
||||
.groups_titles
|
||||
|
||||
etat: filtrage selon l'état de l'inscription
|
||||
|
@ -126,7 +126,7 @@ def moduleimpl_evaluation_menu(evaluation: Evaluation, nbnotes: int = 0) -> str:
|
||||
"endpoint": "assiduites.etat_abs_date",
|
||||
"args": {
|
||||
"group_ids": group_id,
|
||||
"desc": evaluation.description or "",
|
||||
"evaluation_id": evaluation.id,
|
||||
"date_debut": evaluation.date_debut.isoformat()
|
||||
if evaluation.date_debut
|
||||
else "",
|
||||
|
@ -1012,10 +1012,7 @@ span.linktitresem {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
span.linktitresem a:link {
|
||||
color: red;
|
||||
}
|
||||
|
||||
span.linktitresem a:link,
|
||||
span.linktitresem a:visited {
|
||||
color: red;
|
||||
}
|
||||
@ -1031,6 +1028,14 @@ a.stdlink:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.etudlink,
|
||||
a.etud:visited {
|
||||
color: red;
|
||||
}
|
||||
a.etudlink:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* a.link_accessible {} */
|
||||
a.link_unauthorized,
|
||||
a.link_unauthorized:visited {
|
||||
|
@ -54,6 +54,7 @@ class RowEtud(tb.Row):
|
||||
super().__init__(table, etud.id, *args, **kwargs)
|
||||
self.etud = etud
|
||||
self.target_url = etud.url_fiche()
|
||||
self.target_title = "" # pour bulle aide sur lien
|
||||
|
||||
def add_etud_cols(self):
|
||||
"""Ajoute colonnes étudiant: codes, noms"""
|
||||
@ -81,7 +82,14 @@ class RowEtud(tb.Row):
|
||||
# formsemestre_id=res.formsemestre.id,
|
||||
# etudid=etud.id,
|
||||
# )
|
||||
self.add_cell("civilite_str", "Civ.", etud.civilite_str, "identite_detail")
|
||||
self.add_cell(
|
||||
"civilite_str",
|
||||
"Civ.",
|
||||
etud.civilite_str,
|
||||
"identite_detail",
|
||||
target=self.target_url,
|
||||
target_attrs={"class": "discretelink", "title": self.target_title},
|
||||
)
|
||||
self.add_cell(
|
||||
"nom_disp",
|
||||
"Nom",
|
||||
@ -89,9 +97,20 @@ class RowEtud(tb.Row):
|
||||
"identite_detail",
|
||||
data={"order": etud.sort_key},
|
||||
target=self.target_url,
|
||||
target_attrs={"class": "etudinfo discretelink", "id": str(etud.id)},
|
||||
target_attrs={
|
||||
"class": "etudinfo discretelink",
|
||||
"id": str(etud.id),
|
||||
"title": self.target_title,
|
||||
},
|
||||
)
|
||||
self.add_cell(
|
||||
"prenom",
|
||||
"Prénom",
|
||||
etud.prenom,
|
||||
"identite_detail",
|
||||
target=self.target_url,
|
||||
target_attrs={"class": "discretelink", "title": self.target_title},
|
||||
)
|
||||
self.add_cell("prenom", "Prénom", etud.prenom, "identite_detail")
|
||||
|
||||
|
||||
def etuds_sorted_from_ids(etudids) -> list[Identite]:
|
||||
|
@ -524,7 +524,7 @@ class AssiDisplayOptions:
|
||||
self.show_module = to_bool(show_module)
|
||||
|
||||
def remplacer(self, **kwargs):
|
||||
"Positionnne options booléennes selon arguments"
|
||||
"Positionne options booléennes selon arguments"
|
||||
for k, v in kwargs.items():
|
||||
if k.startswith("show_"):
|
||||
setattr(self, k, to_bool(v))
|
||||
|
@ -1,37 +1,30 @@
|
||||
<h2>Présence du groupe {{group_title}} le {{date_debut.strftime("%d/%m/%Y")}}
|
||||
de {{date_debut.strftime("%H:%M")}} à {{date_fin.strftime("%H:%M")}}
|
||||
{% extends "sco_page.j2" %}
|
||||
|
||||
{% block styles %}
|
||||
{{super()}}
|
||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
{% block app_content %}
|
||||
<div class="tab-content">
|
||||
|
||||
<h2>Présence du groupe {{group_title}} le {{date_debut.strftime("%d/%m/%Y")}}
|
||||
de {{date_debut.strftime("%H:%M")}} à {{date_fin.strftime("%H:%M")}}
|
||||
</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Nom
|
||||
</th>
|
||||
<th>
|
||||
Présence
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for etud in etudiants %}
|
||||
<tr>
|
||||
<td>
|
||||
{{etud.nom | safe}}
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
{{etud.etat}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% if evaluation %}
|
||||
<div>Assiduité lors de l'évaluation
|
||||
<a class="stdlink" href="{{
|
||||
url_for('notes.evaluation_listenotes',
|
||||
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
|
||||
}}"><em>{{evaluation.description or ''}}</em></a>
|
||||
{% endif %}
|
||||
<div>{{description}}</div>
|
||||
|
||||
</table>
|
||||
{{table.html()|safe}}
|
||||
|
||||
<style>
|
||||
tr,
|
||||
td {
|
||||
background-color: #FFFFFF;
|
||||
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% block app_content %}
|
||||
<div class="pageContent">
|
||||
|
||||
<h2>Liste de l'assiduité et des justificatifs de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
||||
<h2>Liste de l'assiduité et des justificatifs de {{sco.etud.html_link_fiche()|safe}}</h2>
|
||||
{{tableau | safe }}
|
||||
</div>
|
||||
{% endblock app_content %}
|
||||
{% endblock app_content %}
|
||||
|
@ -74,7 +74,7 @@
|
||||
}
|
||||
try {
|
||||
if (isCalendrier()) {
|
||||
window.location = `ListeAssiduitesEtud?etudid=${etudid}&assiduite_id=${assiduité.assiduite_id}`
|
||||
window.location = `liste_assiduites_etud?etudid=${etudid}&assiduite_id=${assiduité.assiduite_id}`
|
||||
}
|
||||
} catch { }
|
||||
});
|
||||
@ -320,4 +320,4 @@
|
||||
.mini-timeline-block.invalid_justified {
|
||||
background-image: var(--motif-justi-invalide);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -45,6 +45,7 @@ from app.models import (
|
||||
Departement,
|
||||
Evaluation,
|
||||
FormSemestre,
|
||||
GroupDescr,
|
||||
Identite,
|
||||
Justificatif,
|
||||
ModuleImpl,
|
||||
@ -53,6 +54,7 @@ from app.models import (
|
||||
from app.scodoc.codes_cursus import UE_STANDARD
|
||||
from app.auth.models import User
|
||||
from app.models.assiduites import get_assiduites_justif
|
||||
from app.tables.list_etuds import RowEtud, TableEtud
|
||||
import app.tables.liste_assiduites as liste_assi
|
||||
|
||||
from app.views import assiduites_bp as bp
|
||||
@ -466,7 +468,7 @@ def _record_assiduite_etud(
|
||||
# ),
|
||||
|
||||
|
||||
@bp.route("/ListeAssiduitesEtud")
|
||||
@bp.route("/liste_assiduites_etud")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def liste_assiduites_etud():
|
||||
@ -1011,18 +1013,59 @@ def visu_assiduites_group():
|
||||
).build()
|
||||
|
||||
|
||||
class RowEtudWithAssi(RowEtud):
|
||||
"""Ligne de la table d'étudiants avec colonne Assiduité"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
table: TableEtud,
|
||||
etud: Identite,
|
||||
etat_assiduite: str,
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(table, etud, *args, **kwargs)
|
||||
self.etat_assiduite = etat_assiduite
|
||||
# remplace lien vers fiche par lien vers calendrier
|
||||
self.target_url = url_for(
|
||||
"assiduites.calendrier_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id
|
||||
)
|
||||
self.target_title = f"Calendrier de {etud.nomprenom}"
|
||||
|
||||
def add_etud_cols(self):
|
||||
"""Ajoute colonnes pour cet étudiant"""
|
||||
super().add_etud_cols()
|
||||
self.add_cell(
|
||||
"assi-type",
|
||||
"Présence",
|
||||
self.etat_assiduite,
|
||||
"assi-type",
|
||||
)
|
||||
self.classes += ["row-assiduite", self.etat_assiduite.lower()]
|
||||
|
||||
|
||||
@bp.route("/etat_abs_date")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
def etat_abs_date():
|
||||
"""date_debut, date_fin en ISO"""
|
||||
"""Tableau de l'état d'assiduité d'un ou plusieurs groupes
|
||||
sur la plage de dates date_debut, date_fin.
|
||||
group_ids=6573 : id de(s) groupe(s)
|
||||
date_debut, date_fin: format ISO
|
||||
evaluation_id: optionnel, évaluation concernée, pour titre et liens.
|
||||
date_debut, date_fin en ISO
|
||||
"""
|
||||
|
||||
# Récupération des paramètre de la requête
|
||||
# Récupération des paramètres de la requête
|
||||
date_debut_str = request.args.get("date_debut")
|
||||
date_fin_str = request.args.get("date_fin")
|
||||
title = request.args.get("desc")
|
||||
group_ids: list[int] = request.args.get("group_ids", None)
|
||||
|
||||
group_ids = request.args.getlist("group_ids", int)
|
||||
evaluation_id = request.args.get("evaluation_id")
|
||||
evaluation: Evaluation = (
|
||||
Evaluation.query.get_or_404(evaluation_id)
|
||||
if evaluation_id is not None
|
||||
else None
|
||||
)
|
||||
# Vérification des dates
|
||||
try:
|
||||
date_debut = datetime.datetime.fromisoformat(date_debut_str)
|
||||
@ -1033,71 +1076,45 @@ def etat_abs_date():
|
||||
except ValueError as exc:
|
||||
raise ScoValueError("date_fin invalide") from exc
|
||||
|
||||
# Vérification des groupes
|
||||
if group_ids is None:
|
||||
group_ids = []
|
||||
else:
|
||||
group_ids = group_ids.split(",")
|
||||
map(str, group_ids)
|
||||
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids)
|
||||
|
||||
# Récupération des étudiants des groupes
|
||||
# Les groupes:
|
||||
groups = [GroupDescr.query.get_or_404(group_id) for group_id in group_ids]
|
||||
# Les étudiants de tous les groupes sélectionnés, flat list
|
||||
etuds = [
|
||||
sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0]
|
||||
for m in groups_infos.members
|
||||
etud for gr_etuds in [group.etuds for group in groups] for etud in gr_etuds
|
||||
]
|
||||
|
||||
# Récupération des assiduites des étudiants
|
||||
assiduites: Assiduite = Assiduite.query.filter(
|
||||
Assiduite.etudid.in_([e["etudid"] for e in etuds])
|
||||
Assiduite.etudid.in_([etud.id for etud in etuds])
|
||||
)
|
||||
# Filtrage des assiduités en fonction des dates données
|
||||
assiduites = scass.filter_by_date(
|
||||
assiduites, Assiduite, date_debut, date_fin, False
|
||||
)
|
||||
|
||||
# Génération d'objet étudiant simplifié (nom+lien cal, etat_assiduite)
|
||||
etudiants: list[dict] = []
|
||||
for etud in etuds:
|
||||
# Génération table
|
||||
table = TableEtud(row_class=RowEtudWithAssi)
|
||||
for etud in sorted(etuds, key=lambda e: e.sort_key):
|
||||
# On récupère l'état de la première assiduité sur la période
|
||||
assi = assiduites.filter_by(etudid=etud["etudid"]).first()
|
||||
assi = assiduites.filter_by(etudid=etud.id).first()
|
||||
etat = ""
|
||||
if assi is not None and assi.etat != scu.EtatAssiduite.PRESENT:
|
||||
etat = scu.EtatAssiduite.inverse().get(assi.etat).name
|
||||
row = table.row_class(table, etud, etat)
|
||||
row.add_etud_cols()
|
||||
table.add_row(row)
|
||||
|
||||
# On génère l'objet simplifié (un dict)
|
||||
etudiant = {
|
||||
"nom": f"""<a href="{url_for(
|
||||
"assiduites.calendrier_etud",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
etudid=etud["etudid"])
|
||||
}"><font color="#A00000">{etud["nomprenom"]}</font></a>""",
|
||||
"etat": etat,
|
||||
}
|
||||
|
||||
etudiants.append(etudiant)
|
||||
|
||||
# On tri les étudiants
|
||||
etudiants = list(sorted(etudiants, key=lambda x: x["nom"]))
|
||||
|
||||
# Génération de l'HTML
|
||||
header: str = html_sco_header.sco_header(
|
||||
page_title=safehtml.html_to_safe_html(title),
|
||||
init_qtip=True,
|
||||
return render_template(
|
||||
"assiduites/pages/etat_abs_date.j2",
|
||||
date_debut=date_debut,
|
||||
date_fin=date_fin,
|
||||
evaluation=evaluation,
|
||||
etuds=etuds,
|
||||
group_title=", ".join(gr.get_nom_with_part("tous") for gr in groups),
|
||||
sco=ScoData(),
|
||||
table=table,
|
||||
)
|
||||
|
||||
return HTMLBuilder(
|
||||
header,
|
||||
render_template(
|
||||
"assiduites/pages/etat_abs_date.j2",
|
||||
etudiants=etudiants,
|
||||
group_title=groups_infos.groups_titles,
|
||||
date_debut=date_debut,
|
||||
date_fin=date_fin,
|
||||
),
|
||||
html_sco_header.sco_footer(),
|
||||
).build()
|
||||
|
||||
|
||||
@bp.route("/VisualisationAssiduitesGroupe")
|
||||
@scodoc
|
||||
|
Loading…
Reference in New Issue
Block a user