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:
|
def html_link_fiche(self) -> str:
|
||||||
"lien vers la fiche"
|
"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:
|
def url_fiche(self) -> str:
|
||||||
"url de la fiche étudiant"
|
"url de la fiche étudiant"
|
||||||
@ -319,6 +319,8 @@ class Identite(db.Model, models.ScoDocModel):
|
|||||||
@cached_property
|
@cached_property
|
||||||
def sort_key(self) -> tuple:
|
def sort_key(self) -> tuple:
|
||||||
"clé pour tris par ordre alphabétique"
|
"clé pour tris par ordre alphabétique"
|
||||||
|
# Note: scodoc7 utilisait sco_etud.etud_sort_key, à mettre à jour
|
||||||
|
# si on modifie cette méthode.
|
||||||
return (
|
return (
|
||||||
scu.sanitize_string(
|
scu.sanitize_string(
|
||||||
self.nom_usuel or self.nom or "", remove_spaces=False
|
self.nom_usuel or self.nom or "", remove_spaces=False
|
||||||
|
@ -692,7 +692,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, link_saisie=True):
|
|||||||
'assiduites.etat_abs_date',
|
'assiduites.etat_abs_date',
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
group_ids=group_id,
|
group_ids=group_id,
|
||||||
desc=evaluation.description or "",
|
evaluation_id=evaluation.id,
|
||||||
date_debut=evaluation.date_debut.isoformat(),
|
date_debut=evaluation.date_debut.isoformat(),
|
||||||
date_fin=evaluation.date_fin.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.
|
"""Liste des etudiants d'un groupe.
|
||||||
Si etat, filtre selon l'état de l'inscription
|
Si etat, filtre selon l'état de l'inscription
|
||||||
Trié par nom_usuel (ou nom) puis prénom
|
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
|
req = """SELECT i.id as etudid, i.*, a.*, gm.*, ins.etat
|
||||||
FROM identite i, adresse a, group_membership gm,
|
FROM identite i, adresse a, group_membership gm,
|
||||||
|
@ -304,7 +304,7 @@ class DisplayedGroupsInfos:
|
|||||||
.groups_query_args : 'group_ids=xxx&group_ids=yyy'
|
.groups_query_args : 'group_ids=xxx&group_ids=yyy'
|
||||||
.base_url : url de la requete, avec les groupes, sans les autres paramètres
|
.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)
|
.formsemestre_id : semestre "principal" (en fait celui du 1er groupe de la liste)
|
||||||
.members
|
.members :
|
||||||
.groups_titles
|
.groups_titles
|
||||||
|
|
||||||
etat: filtrage selon l'état de l'inscription
|
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",
|
"endpoint": "assiduites.etat_abs_date",
|
||||||
"args": {
|
"args": {
|
||||||
"group_ids": group_id,
|
"group_ids": group_id,
|
||||||
"desc": evaluation.description or "",
|
"evaluation_id": evaluation.id,
|
||||||
"date_debut": evaluation.date_debut.isoformat()
|
"date_debut": evaluation.date_debut.isoformat()
|
||||||
if evaluation.date_debut
|
if evaluation.date_debut
|
||||||
else "",
|
else "",
|
||||||
|
@ -1012,10 +1012,7 @@ span.linktitresem {
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.linktitresem a:link {
|
span.linktitresem a:link,
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.linktitresem a:visited {
|
span.linktitresem a:visited {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
@ -1031,6 +1028,14 @@ a.stdlink:hover {
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.etudlink,
|
||||||
|
a.etud:visited {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
a.etudlink:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* a.link_accessible {} */
|
/* a.link_accessible {} */
|
||||||
a.link_unauthorized,
|
a.link_unauthorized,
|
||||||
a.link_unauthorized:visited {
|
a.link_unauthorized:visited {
|
||||||
|
@ -54,6 +54,7 @@ class RowEtud(tb.Row):
|
|||||||
super().__init__(table, etud.id, *args, **kwargs)
|
super().__init__(table, etud.id, *args, **kwargs)
|
||||||
self.etud = etud
|
self.etud = etud
|
||||||
self.target_url = etud.url_fiche()
|
self.target_url = etud.url_fiche()
|
||||||
|
self.target_title = "" # pour bulle aide sur lien
|
||||||
|
|
||||||
def add_etud_cols(self):
|
def add_etud_cols(self):
|
||||||
"""Ajoute colonnes étudiant: codes, noms"""
|
"""Ajoute colonnes étudiant: codes, noms"""
|
||||||
@ -81,7 +82,14 @@ class RowEtud(tb.Row):
|
|||||||
# formsemestre_id=res.formsemestre.id,
|
# formsemestre_id=res.formsemestre.id,
|
||||||
# etudid=etud.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(
|
self.add_cell(
|
||||||
"nom_disp",
|
"nom_disp",
|
||||||
"Nom",
|
"Nom",
|
||||||
@ -89,9 +97,20 @@ class RowEtud(tb.Row):
|
|||||||
"identite_detail",
|
"identite_detail",
|
||||||
data={"order": etud.sort_key},
|
data={"order": etud.sort_key},
|
||||||
target=self.target_url,
|
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]:
|
def etuds_sorted_from_ids(etudids) -> list[Identite]:
|
||||||
|
@ -524,7 +524,7 @@ class AssiDisplayOptions:
|
|||||||
self.show_module = to_bool(show_module)
|
self.show_module = to_bool(show_module)
|
||||||
|
|
||||||
def remplacer(self, **kwargs):
|
def remplacer(self, **kwargs):
|
||||||
"Positionnne options booléennes selon arguments"
|
"Positionne options booléennes selon arguments"
|
||||||
for k, v in kwargs.items():
|
for k, v in kwargs.items():
|
||||||
if k.startswith("show_"):
|
if k.startswith("show_"):
|
||||||
setattr(self, k, to_bool(v))
|
setattr(self, k, to_bool(v))
|
||||||
|
@ -1,37 +1,30 @@
|
|||||||
|
{% 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")}}
|
<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")}}
|
de {{date_debut.strftime("%H:%M")}} à {{date_fin.strftime("%H:%M")}}
|
||||||
</h2>
|
</h2>
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
Nom
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Présence
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
{% if evaluation %}
|
||||||
{% for etud in etudiants %}
|
<div>Assiduité lors de l'évaluation
|
||||||
<tr>
|
<a class="stdlink" href="{{
|
||||||
<td>
|
url_for('notes.evaluation_listenotes',
|
||||||
{{etud.nom | safe}}
|
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
|
||||||
</td>
|
}}"><em>{{evaluation.description or ''}}</em></a>
|
||||||
<td style="text-align: center;">
|
{% endif %}
|
||||||
{{etud.etat}}
|
<div>{{description}}</div>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
|
|
||||||
</table>
|
{{table.html()|safe}}
|
||||||
|
|
||||||
<style>
|
|
||||||
tr,
|
|
||||||
td {
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
|
|
||||||
}
|
</div>
|
||||||
</style>
|
{% endblock %}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
<div class="pageContent">
|
<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 }}
|
{{tableau | safe }}
|
||||||
</div>
|
</div>
|
||||||
{% endblock app_content %}
|
{% endblock app_content %}
|
@ -74,7 +74,7 @@
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (isCalendrier()) {
|
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 { }
|
} catch { }
|
||||||
});
|
});
|
||||||
|
@ -45,6 +45,7 @@ from app.models import (
|
|||||||
Departement,
|
Departement,
|
||||||
Evaluation,
|
Evaluation,
|
||||||
FormSemestre,
|
FormSemestre,
|
||||||
|
GroupDescr,
|
||||||
Identite,
|
Identite,
|
||||||
Justificatif,
|
Justificatif,
|
||||||
ModuleImpl,
|
ModuleImpl,
|
||||||
@ -53,6 +54,7 @@ from app.models import (
|
|||||||
from app.scodoc.codes_cursus import UE_STANDARD
|
from app.scodoc.codes_cursus import UE_STANDARD
|
||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
from app.models.assiduites import get_assiduites_justif
|
from app.models.assiduites import get_assiduites_justif
|
||||||
|
from app.tables.list_etuds import RowEtud, TableEtud
|
||||||
import app.tables.liste_assiduites as liste_assi
|
import app.tables.liste_assiduites as liste_assi
|
||||||
|
|
||||||
from app.views import assiduites_bp as bp
|
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
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def liste_assiduites_etud():
|
def liste_assiduites_etud():
|
||||||
@ -1011,18 +1013,59 @@ def visu_assiduites_group():
|
|||||||
).build()
|
).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")
|
@bp.route("/etat_abs_date")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def etat_abs_date():
|
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_debut_str = request.args.get("date_debut")
|
||||||
date_fin_str = request.args.get("date_fin")
|
date_fin_str = request.args.get("date_fin")
|
||||||
title = request.args.get("desc")
|
group_ids = request.args.getlist("group_ids", int)
|
||||||
group_ids: list[int] = request.args.get("group_ids", None)
|
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
|
# Vérification des dates
|
||||||
try:
|
try:
|
||||||
date_debut = datetime.datetime.fromisoformat(date_debut_str)
|
date_debut = datetime.datetime.fromisoformat(date_debut_str)
|
||||||
@ -1033,71 +1076,45 @@ def etat_abs_date():
|
|||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise ScoValueError("date_fin invalide") from exc
|
raise ScoValueError("date_fin invalide") from exc
|
||||||
|
|
||||||
# Vérification des groupes
|
# Les groupes:
|
||||||
if group_ids is None:
|
groups = [GroupDescr.query.get_or_404(group_id) for group_id in group_ids]
|
||||||
group_ids = []
|
# Les étudiants de tous les groupes sélectionnés, flat list
|
||||||
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
|
|
||||||
etuds = [
|
etuds = [
|
||||||
sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0]
|
etud for gr_etuds in [group.etuds for group in groups] for etud in gr_etuds
|
||||||
for m in groups_infos.members
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Récupération des assiduites des étudiants
|
# Récupération des assiduites des étudiants
|
||||||
assiduites: Assiduite = Assiduite.query.filter(
|
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
|
# Filtrage des assiduités en fonction des dates données
|
||||||
assiduites = scass.filter_by_date(
|
assiduites = scass.filter_by_date(
|
||||||
assiduites, Assiduite, date_debut, date_fin, False
|
assiduites, Assiduite, date_debut, date_fin, False
|
||||||
)
|
)
|
||||||
|
|
||||||
# Génération d'objet étudiant simplifié (nom+lien cal, etat_assiduite)
|
# Génération table
|
||||||
etudiants: list[dict] = []
|
table = TableEtud(row_class=RowEtudWithAssi)
|
||||||
for etud in etuds:
|
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
|
# 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 = ""
|
etat = ""
|
||||||
if assi is not None and assi.etat != scu.EtatAssiduite.PRESENT:
|
if assi is not None and assi.etat != scu.EtatAssiduite.PRESENT:
|
||||||
etat = scu.EtatAssiduite.inverse().get(assi.etat).name
|
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)
|
return render_template(
|
||||||
etudiant = {
|
"assiduites/pages/etat_abs_date.j2",
|
||||||
"nom": f"""<a href="{url_for(
|
date_debut=date_debut,
|
||||||
"assiduites.calendrier_etud",
|
date_fin=date_fin,
|
||||||
scodoc_dept=g.scodoc_dept,
|
evaluation=evaluation,
|
||||||
etudid=etud["etudid"])
|
etuds=etuds,
|
||||||
}"><font color="#A00000">{etud["nomprenom"]}</font></a>""",
|
group_title=", ".join(gr.get_nom_with_part("tous") for gr in groups),
|
||||||
"etat": etat,
|
sco=ScoData(),
|
||||||
}
|
table=table,
|
||||||
|
|
||||||
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 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")
|
@bp.route("/VisualisationAssiduitesGroupe")
|
||||||
@scodoc
|
@scodoc
|
||||||
|
Loading…
Reference in New Issue
Block a user