diff --git a/app.py b/app.py index 98c87d8..0910991 100644 --- a/app.py +++ b/app.py @@ -15,6 +15,7 @@ import datetime as dti import pytz import json import os +import traceback from flask import Flask from flask import render_template @@ -295,8 +296,11 @@ def free_rooms(api = False, rq = None) : try : free_rooms = ro.getrooms(date, depts, ignore_list) except ValueError as err : - return render_template("error.html", error="Le serveur Unistra a rencontré une erreur ! Veuillez réessayer plus tard.") - #return render_template("error.html", error="Le serveur Unistra a rencontré une erreur ! Détails de l'erreur : " + str(''.join(traceback.format_exception(None, err, err.__traceback__)))) + errdetails = str(''.join(traceback.format_exception(None, err, err.__traceback__))) + if GLOBAL_CONTEXT["DEBUG"] : + print(errdetails) + return render_template("error.html", + error="Le serveur Unistra a rencontré une erreur ! Veuillez réessayer plus tard.") # Création d'un dictionnaire avec les infos des salles : frooms_disp = dict() # Mise en forme des infos pour la page Web diff --git a/objects.py b/objects.py index 89ebe2f..6f846a8 100644 --- a/objects.py +++ b/objects.py @@ -42,7 +42,16 @@ class Room : end : datetime.datetime Salle occupée : heure de fin de la prochaine période de disponibilité. - Salle libre : heure de fin de disponibilité. + Salle libre : heure de fin de disponibilité (inutilisé s'il n'y en a + pas (vaut alors la date du jour à 23:59:59)). + + nostart : bool + Indique si la salle a un début de disponibilité ('False' dans le cas + des salles libres). + + noend : bool + Indique si la salle a une fin de disponibilité ('False' dans le cas + où la salle est dispo pour le reste de la journée). is_free : bool Indique si la salle est libre ('True') ou non ('False'). @@ -55,10 +64,13 @@ class Room : Le nom du département auquel la salle appartient. """ - def __init__(self, name, start, end, is_free, dept_name="DEFAULT DEPT") : + def __init__(self, name, start, end, nostart, noend, is_free, + dept_name="DEFAULT DEPT") : self.name = name self.start = start self.end = end + self.nostart = nostart + self.noend = noend self.is_free = is_free self.id = self.getId(name) self.dept_name = dept_name diff --git a/rooms_get.py b/rooms_get.py index 68390f8..34e9f66 100644 --- a/rooms_get.py +++ b/rooms_get.py @@ -17,7 +17,7 @@ Created on Thu Feb 24 08:51:58 2022 # Modules : import requests import icalendar -# import ics as icalendar +import ics import pytz import os import shutil @@ -36,6 +36,9 @@ CACHE_TTL = 5 # Nombres maximum de fichier dans le cache : CACHE_SIZE = 10 +# Flag pour utiliser le cache : +NO_CACHE = False + # Globales : last_cache_init = -999 @@ -111,7 +114,7 @@ def sched_get(date, link, enddate = None, nocache = False) : Returns ------- - bytes + str Le texte du résultat de la requête. """ @@ -140,7 +143,13 @@ def sched_get(date, link, enddate = None, nocache = False) : finallink = finallink.replace("$YEAR2$", year1) if nocache : - return requests.get(finallink).content + # Utilisation du module 'ics' pour le tri du calendrier dans l'ordre + # chronologique : + result = requests.get(finallink).text + cal = ics.Calendar(result) + cal.events = sorted(cal.events) + result = cal.serialize() + return result else : # Vérifie la TTL : elapsed = time.time() - last_cache_init @@ -155,12 +164,17 @@ def sched_get(date, link, enddate = None, nocache = False) : cachepath = os.path.join(CACHE_DIR, trim(finallink)) if os.path.isfile(cachepath) : result = "" - with open(cachepath,'rb') as f : + with open(cachepath,'r') as f : result = f.read() return result - else: - result = requests.get(finallink).content - with open(cachepath,'wb') as f : + else : + result = requests.get(finallink).text + # Utilisation du module 'ics' pour le tri du calendrier dans l'ordre + # chronologique : + cal = ics.Calendar(result) + cal.events = sorted(cal.events) + result = cal.serialize() + with open(cachepath,'w') as f : f.write(result) return result @@ -221,52 +235,57 @@ def getrooms(datet, depts, ignore_list) : # Marge de temps (en mois) pour le début du calendrier. # Certaines salles ne sont pas utilisées tous les jours, - # donc on télécharge l'EDT d'un mois complet pour être tranquille. + # donc on télécharge l'EDT du reste du mois et du suivant + # pour être tranquille. margintime = 1 - # Récupération des calendriers correspondants aux liens des départements, + # Récupération du calendrier de chaque département, # sur une période de 'margintime' mois : cals = list() # Liste des EDT des départements choisis for d in depts : if datet.month < 12 : result = sched_get(datet, d.link, - datet.replace(month = datet.month + margintime)) + datet.replace(month = datet.month + margintime), + NO_CACHE) else : result = sched_get(datet, d.link, - datet.replace(month = 1, year = datet.year + 1)) + datet.replace(month = 1, year = datet.year + 1), + NO_CACHE) + # # Utilisation du module 'ics' pour le tri du calendrier dans l'ordre + # # chronologique : + # cal = ics.Calendar(result) + # cal.events = sorted(cal.events) cals.append(icalendar.Calendar.from_ical(result)) # cals.append(icalendar.Calendar(result.decode("utf-8"))) # Parcours de ces calendriers : dept_index = 0 for cal in cals : - # Première boucle pour la liste des salles + déterminer les occupées : for comp in cal.walk() : # Événements if comp.name == "VEVENT" : # Récupération des infos : - roomname = str(comp.get("location")) - datestart = comp.decoded("dtstart") - dateend = comp.decoded("dtend") - roomname = str(comp.get("location")) + evtloc = str(comp.get("location")) + evtstart = comp.decoded("dtstart") + evtend = comp.decoded("dtend") # Contient le nom de toutes les salles indiquées # dans la section "LOCATION" : rnamelist = list() # Séparation des salles multiples, le cas échéant : - if "," in roomname : - rnamelist = roomname.split(",") + if "," in evtloc : + rnamelist = evtloc.split(",") else : - rnamelist.append(roomname) + rnamelist.append(evtloc) - for rname in rnamelist : - rname = rname.strip() - if rname not in ignore_list : + for roomname in rnamelist : + roomname = roomname.strip() + if roomname not in ignore_list : # Création d'une nouvelle salle # si elle n'existe pas déjà : exists = False for room in total_rooms : - if room.name == rname : + if room.name == roomname : exists = True r = room @@ -277,28 +296,45 @@ def getrooms(datet, depts, ignore_list) : # - L'heure de fin de la prochaine période # de disponibilité est aujourd'hui à 23:59. # - La salle est libre. - r = Room(rname, + r = Room(roomname, datet.replace(hour = 0, minute = 0, second = 0), datet.replace(hour = 23, minute = 59, second = 59), True, + True, + True, depts[dept_index].name ) # Si l'événement se passe aujourd'hui : - if datestart.day == datet.day and \ - datestart.month == datet.month and \ - datestart.year == datet.year : - if rname == "Grand Amphi MAI Frenkel" : - print(r.start.hour, r.end.hour, datestart.hour+2, dateend.hour+2) + if evtstart.day == datet.day and \ + evtstart.month == datet.month and \ + evtstart.year == datet.year : # Si l'événement se passe maintenant # (salle occupée maintenant) : - if datestart.timestamp() <= datet.timestamp() and \ - dateend.timestamp() > datet.timestamp() : + if evtstart.timestamp() <= datet.timestamp() and \ + evtend.timestamp() > datet.timestamp() : r.is_free = False + r.nostart = False # L'heure de début de la prochaine dispo est - # la fin de l'événement, - # si différente de la fin de dispo : - r.start = dateend + # la fin de l'événement : + r.start = evtend + # Si l'événement se passe prochainement + # (salle occupée à l'occasion de cet événement) + # et que le début de l'événement est avant la date + # de fin de dispo actuelle (on cherche la date la + # plus proche de maintenant) : + elif evtstart.timestamp() > datet.timestamp() and \ + evtstart.timestamp() < r.end.timestamp() : + if evtstart.timestamp() == r.start.timestamp() : + r.nostart = False + # Dans ce cas, l'événement en cours suit + # celui qui a défini le début de dispo + # de la salle. Alors, c'est la fin de cet + # événement qui marque le début de la dispo. + r.start = evtend + else : + r.noend = False + r.end = evtstart # Réglage du fuseau horaire : r.start = r.start.astimezone(pytz.timezone('Europe/Paris')) @@ -307,53 +343,6 @@ def getrooms(datet, depts, ignore_list) : if not exists : total_rooms.append(r) - # Deuxième boucle, pour déterminer les périodes de dispo : - for comp in cal.walk() : - if comp.name == "VEVENT" : - # Récupération des infos : - roomname = str(comp.get("location")) - datestart = comp.decoded("dtstart") - dateend = comp.decoded("dtend") - roomname = str(comp.get("location")) - - # Contient le nom de toutes les salles indiquées - # dans la section "LOCATION" : - rnamelist = list() - - # Séparation des salles multiples, le cas échéant : - if "," in roomname : - rnamelist = roomname.split(",") - else : - rnamelist.append(roomname) - - for rname in rnamelist : - rname = rname.strip() - if rname not in ignore_list : - # Recherche de la salle : - for room in total_rooms : - if room.name == rname : - r = room - - # Si l'événement se passe aujourd'hui : - if datestart.day == datet.day and \ - datestart.month == datet.month and \ - datestart.year == datet.year : - if rname == "Grand Amphi MAI Frenkel" : - print(r.start.hour, r.end.hour, datestart.hour+2, dateend.hour+2) - # Si l'événement se passe prochainement - # (salle occupée à l'occasion de cet événement) : - if datestart.timestamp() > datet.timestamp() : - if datestart.timestamp() == r.start.timestamp() : - r.start = dateend - elif datestart.timestamp() < r.end.timestamp() : - r.end = datestart - - # Réglage du fuseau horaire : - r.start = r.start.astimezone(pytz.timezone('Europe/Paris')) - r.end = r.end.astimezone(pytz.timezone('Europe/Paris')) - dept_index += 1 - - return total_rooms \ No newline at end of file diff --git a/static/style.css b/static/style.css index ae3008c..f8a8201 100644 --- a/static/style.css +++ b/static/style.css @@ -262,12 +262,12 @@ footer { display:flex; flex-wrap: wrap; } - .room-collumn{ + .room-column{ width: 50%; flex-grow: 1; } } -.room-collumn{ +.room-column{ margin-bottom: 10px; } diff --git a/templates/free-rooms.html b/templates/free-rooms.html index 5ac1eae..54aa865 100644 --- a/templates/free-rooms.html +++ b/templates/free-rooms.html @@ -35,7 +35,7 @@ {% if favs: %}
{% if favs_free_rooms|length>0: %} -
+

Favoris disponibles maintenant

@@ -45,7 +45,7 @@
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %} - {% if not(room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59) : %} + {% if not(room.noend) : %}

Jusqu'à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})

{% endif %}
@@ -60,7 +60,7 @@
{% endif %} {% if favs_soon_rooms|length>0: %} -
+

Favoris disponibles prochainement

@@ -70,7 +70,7 @@
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %} - {% if room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59 : %} + {% if room.noend : %}

À {{ frooms_disp[room.name]["start"] }} (dans {{ frooms_disp[room.name]["rtime"] }})

{% else %}

De {{ frooms_disp[room.name]["start"] }} à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})

@@ -90,7 +90,7 @@ {% endif %}
{% if free_rooms|length>0 %} -
+

Disponibles maintenant

@@ -100,7 +100,7 @@
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %} - {% if not(room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59) : %} + {% if not room.noend : %}

Jusqu'à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})

{% endif %}
@@ -115,7 +115,7 @@
{% endif %} {% if soon_rooms|length>0 %} -
+

Disponibles prochainement

@@ -125,7 +125,7 @@
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %} - {% if room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59 : %} + {% if room.noend : %}

À {{ frooms_disp[room.name]["start"] }} (dans {{ frooms_disp[room.name]["rtime"] }})

{% else %}

De {{ frooms_disp[room.name]["start"] }} à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})