diff --git a/app/scodoc/sco_edt_cal.py b/app/scodoc/sco_edt_cal.py index 1fce5d26..91e3d656 100644 --- a/app/scodoc/sco_edt_cal.py +++ b/app/scodoc/sco_edt_cal.py @@ -30,6 +30,7 @@ Lecture et conversion des ics. """ + from datetime import timezone import glob import os @@ -229,7 +230,7 @@ def translate_calendar( heure_deb=event["heure_deb"], heure_fin=event["heure_fin"], moduleimpl_id=modimpl.id, - jour=event["jour"], + day=event["jour"], ) if modimpl and group else None diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index c8687abd..2bd32f2b 100755 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -832,7 +832,7 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str: diff --git a/app/scodoc/sco_gen_cal.py b/app/scodoc/sco_gen_cal.py index 54a66e9d..3b4a9ca4 100644 --- a/app/scodoc/sco_gen_cal.py +++ b/app/scodoc/sco_gen_cal.py @@ -54,11 +54,11 @@ class Jour: """ return self.date.isocalendar()[0:2] == datetime.date.today().isocalendar()[0:2] - def get_date(self) -> str: + def get_date(self, fmt=scu.DATE_FMT) -> str: """ - Renvoie la date du jour au format "dd/mm/yyyy" + Renvoie la date du jour au format fmt ou "dd/mm/yyyy" par défaut """ - return self.date.strftime(scu.DATE_FMT) + return self.date.strftime(fmt) def get_html(self): """ @@ -93,12 +93,22 @@ class Calendrier: Représente un calendrier Permet d'obtenir les informations sur les jours et générer une représentation html + + highlight: str + -> ["jour", "semaine", "mois"] + permet de mettre en valeur lors du passage de la souris """ - def __init__(self, date_debut: datetime.date, date_fin: datetime.date): + def __init__( + self, + date_debut: datetime.date, + date_fin: datetime.date, + highlight: str = None, + ): self.date_debut = date_debut self.date_fin = date_fin self.jours: dict[str, list[Jour]] = {} + self.highlight: str = highlight def _get_dates_between(self) -> list[datetime.date]: """ @@ -130,11 +140,13 @@ class Calendrier: month = scu.MONTH_NAMES_ABBREV[date.month - 1] # Ajouter le jour à la liste correspondante au mois if month not in organized: - organized[month] = [] + organized[month] = {} # semaine {22: []} jour: Jour = self.instanciate_jour(date) - - organized[month].append(jour) + semaine = date.strftime("%G-W%V") + if semaine not in organized[month]: + organized[month][semaine] = [] + organized[month][semaine].append(jour) self.jours = organized @@ -150,4 +162,53 @@ class Calendrier: get_html Renvoie le code html du calendrier """ self.organize_by_month() - return render_template("calendrier.j2", calendrier=self.jours) + return render_template( + "calendrier.j2", calendrier=self.jours, highlight=self.highlight + ) + + +class JourChoix(Jour): + """ + Représente un jour dans le calendrier pour choisir une date + """ + + def get_html(self): + return "" + + +class CalendrierChoix(Calendrier): + """ + Représente un calendrier pour choisir une date + """ + + def instanciate_jour(self, date: datetime.date) -> Jour: + return JourChoix(date) + + +def calendrier_choix_date( + date_debut: datetime.date, + date_fin: datetime.date, + url: str, + mode: str = "jour", + titre: str = "Choisir une date", +): + """ + Permet d'afficher un calendrier pour choisir une date et renvoyer sur une url. + + mode : str + - "jour" -> ajoutera "&day=yyyy-mm-dd" à l'url (ex: 2024-05-30) + - "semaine" -> ajoutera "&week=yyyy-Www" à l'url (ex : 2024-W22) + + titre : str + - texte à afficher au dessus du calendrier + """ + + calendrier: CalendrierChoix = CalendrierChoix(date_debut, date_fin, highlight=mode) + + return render_template( + "choix_date.j2", + calendrier=calendrier.get_html(), + url=url, + titre=titre, + mode=mode, + ) diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py index 80454b43..8c032996 100644 --- a/app/scodoc/sco_groups_view.py +++ b/app/scodoc/sco_groups_view.py @@ -983,7 +983,7 @@ def form_choix_jour_saisie_hebdo(groups_infos, moduleimpl_id=None): "assiduites.signal_assiduites_group", scodoc_dept=g.scodoc_dept, group_ids=",".join(map(str,groups_infos.group_ids)), - jour=datetime.date.today().isoformat(), + day=datetime.date.today().isoformat(), formsemestre_id=groups_infos.formsemestre_id, moduleimpl_id="" if moduleimpl_id is None else moduleimpl_id ) diff --git a/app/scodoc/sco_moduleimpl_status.py b/app/scodoc/sco_moduleimpl_status.py index e7386d78..0588cc98 100644 --- a/app/scodoc/sco_moduleimpl_status.py +++ b/app/scodoc/sco_moduleimpl_status.py @@ -346,7 +346,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None): f""" - {% for mois,jours in calendrier.items() %} -
+ {% for mois,semaines in calendrier.items() %} +

{{mois}}

-
- {% for jour in jours %} -
+ {% for semaine in semaines %} +
+ {% for jour in semaines[semaine] %} +
{{jour.get_nom()}}
{{jour.get_html() | safe}} @@ -12,6 +13,7 @@
{% endfor %}
+ {% endfor %}
{% endfor %}
@@ -84,5 +86,8 @@ border-left: solid 3px var(--couleur); border-right: solid 3px var(--couleur); } + .highlight:hover{ + border: solid 3px yellow; + } \ No newline at end of file diff --git a/app/templates/choix_date.j2 b/app/templates/choix_date.j2 new file mode 100644 index 00000000..a8c4d0a4 --- /dev/null +++ b/app/templates/choix_date.j2 @@ -0,0 +1,62 @@ +{% extends "sco_page.j2" %} +{% block styles %} + {{super()}} + + +{% endblock %} + + +{% block app_content %} +
+

{{titre}}

+ {{calendrier | safe}} +
+ + +{% endblock app_content %} + +{% block scripts %} +{{ super() }} + + + +{% endblock scripts %} diff --git a/app/views/assiduites.py b/app/views/assiduites.py index 3cb16e83..d3115f9c 100644 --- a/app/views/assiduites.py +++ b/app/views/assiduites.py @@ -894,63 +894,6 @@ def calendrier_assi_etud(): ) -@bp.route("/choix_date", methods=["GET", "POST"]) -@scodoc -@permission_required(Permission.AbsChange) -def choix_date() -> str: - """ - choix_date Choix de la date pour la saisie des assiduités - - Route utilisée uniquement si la date courante n'est pas dans le semestre - concerné par la requête vers une des pages suivantes : - - saisie_assiduites_group - """ - formsemestre_id = request.args.get("formsemestre_id") - formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) - - group_ids = request.args.get("group_ids") - moduleimpl_id = request.args.get("moduleimpl_id") - form = ChoixDateForm(request.form) - - if form.validate_on_submit(): - if form.cancel.data: - return redirect(url_for("scodoc.index")) - # Vérifier si date dans semestre - ok: bool = False - try: - date: datetime.date = datetime.datetime.strptime( - form.date.data, scu.DATE_FMT - ).date() - if date < formsemestre.date_debut or date > formsemestre.date_fin: - form.set_error( - "La date sélectionnée n'est pas dans le semestre.", form.date - ) - else: - ok = True - except ValueError: - form.set_error("Date invalide", form.date) - - if ok: - return redirect( - url_for( - "assiduites.signal_assiduites_group", - scodoc_dept=g.scodoc_dept, - formsemestre_id=formsemestre_id, - group_ids=group_ids, - moduleimpl_id=moduleimpl_id, - jour=date.isoformat(), - ) - ) - - return render_template( - "assiduites/pages/choix_date.j2", - form=form, - sco=ScoData(formsemestre=formsemestre), - deb=formsemestre.date_debut.strftime(scu.DATE_FMT), - fin=formsemestre.date_fin.strftime(scu.DATE_FMT), - ) - - @bp.route("/signal_assiduites_group") @scodoc @permission_required(Permission.AbsChange) @@ -965,7 +908,7 @@ def signal_assiduites_group(): # formsemestre_id est optionnel si modimpl est indiqué formsemestre_id: int = request.args.get("formsemestre_id", -1) moduleimpl_id: int = request.args.get("moduleimpl_id") - date: str = request.args.get("jour", datetime.date.today().isoformat()) + date: str = request.args.get("day", datetime.date.today().isoformat()) heures: list[str] = [ request.args.get("heure_deb", ""), request.args.get("heure_fin", ""), @@ -1028,14 +971,23 @@ def signal_assiduites_group(): if real_date < formsemestre.date_debut or real_date > formsemestre.date_fin: # Si le jour est hors semestre, renvoyer vers choix date - return redirect( - url_for( - "assiduites.choix_date", - formsemestre_id=formsemestre_id, - group_ids=group_ids, - moduleimpl_id=moduleimpl_id, + flash( + "La date sélectionnée n'est pas dans le semestre. Choisissez une autre date." + ) + + return sco_gen_cal.calendrier_choix_date( + formsemestre.date_debut, + formsemestre.date_fin, + url=url_for( + "assiduites.signal_assiduites_group", scodoc_dept=g.scodoc_dept, - ) + formsemestre_id=formsemestre_id, + group_ids=",".join(group_ids), + moduleimpl_id=moduleimpl_id, + day="placeholder", + ), + mode="jour", + titre="Choix de la date", ) # --- Restriction en fonction du moduleimpl_id --- @@ -2038,7 +1990,23 @@ def signal_assiduites_hebdo(): # les chaines sont triables par ordre alphanumérique croissant # et produiront le même ordre que les dates par ordre chronologique croissant if week < fs_deb_iso8601 or week > fs_fin_iso8601: - raise ScoValueError("Semaine hors du semestre", dest_url=request.referrer) + flash( + "La semaine n'est pas dans le semestre, choisissez la semaine sur laquelle saisir l'assiduité" + ) + return sco_gen_cal.calendrier_choix_date( + date_debut=formsemestre.date_debut, + date_fin=formsemestre.date_fin, + url=url_for( + "assiduites.signal_assiduites_hebdo", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre_id, + group_ids=group_ids, + moduleimpl_id=moduleimpl_id, + week="placeholder", + ), + mode="semaine", + titre="Choix de la semaine", + ) # Vérification des groupes group_ids = group_ids.split(",") if group_ids != "" else []