#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Thu Feb 24 08:51:58 2022 @author: antoine """ ################ ### UniSquat ### ################ """ Indique toutes les salles disponibles dans les différents départements de l'Université de Strasbourg. """ # Modules : import requests import icalendar import datetime import os # Fonctions : def room(name, start, end, is_free): """ Retourne un dictionnaire contenant le nom, la prochaine date à laquelle elle est occupée, ainsi que la prochaine date à laquelle elle est libre. Parameters ---------- name : str Le nom de la salle. start : datetime.datetime Salle occupée : heure de début de la prochaine période de disponibilité. Salle libre : inutilisé (vaut la date du jour à 00:00). end : datetime.datetime Salle occupée : heure de fin de la prochaine période de disponibilité. Salle libre : heure de fin de disponibilité. is_free : bool Indique si la salle est libre ('True') ou non ('False'). Returns ------- dict Un dictionnaire contenant ces 4 informations, avec le même nom en clef. """ # return {"name":name, "occupied_at":occupied_at, "free_at":free_at, "free":free_at.timestamp() > occupied_at.timestamp()} return {"name":name, "start":start, "end":end, "is_free":is_free} def sched_get(date, enddate = None, link = None) : """ Récupère l'emploi du temps de toutes les salles (pour le moment, juste de l'UFR) sur ADE depuis le site de l'Unistra. Parameters ---------- date : datetime.datetime() Date du calendrier à télécharger (date de début si une date de fin 'enddate' est indiquée). Optionnels: link: Un lien vers lequel effectuer la recherche, des informations seront remplacées : $YEAR$ : l'année $MONTH$ : le mois $DAY$ : le jour Par défaut, sera un lien des salles de l'UFR. enddate : datetime.datetime() Date de fin du calendrier à télécharger (par défaut, il s'agit de la date de début). Returns ------- bytes Le texte du résultat de la requête. """ if not link: link = "https://adecons.unistra.fr/jsp/custom/modules/plannings/anonymous_cal.jsp?resources=30626&projectId=8&calType=ical&firstDate=$YEAR1$-$MONTH1$-$DAY1$&lastDate=$YEAR2$-$MONTH2$-$DAY2$" day1 = str(date.day) month1 = str(date.month) year1 = str(date.year) finallink = link.replace("$DAY1$", day1) finallink = finallink.replace("$MONTH1$", month1) finallink = finallink.replace("$YEAR1$", year1) if enddate != None : day2 = str(enddate.day) month2 = str(enddate.month) year2 = str(enddate.year) finallink = finallink.replace("$DAY2$", day2) finallink = finallink.replace("$MONTH2$", month2) finallink = finallink.replace("$YEAR2$", year2) else : finallink = finallink.replace("$DAY2$", day1) finallink = finallink.replace("$MONTH2$", month1) finallink = finallink.replace("$YEAR2$", year1) r = requests.get(finallink) return r.content def getrooms(datet, links=[],min_occur=3) : """ Crée une liste de toutes les salles, avec des informations si elles sont libres ou non. Parameters ---------- datet : datetime.datetime() Date au format datetime. Optionnels: links : list, par défaut vide liste des liens à consulter ( si est vide, ping l'ufr ) min_occur : nombre, par défaut à 3 Nombre minimum de fois qu'une salle doit être mentionnée pour être comptée ( permet d'éviter le flood de salles qui n'existe que pour les évals ) Returns ------- total_rooms : dict Dictionnaire des salles, indexées par leur nom. Toutes les salles mentionnées dans le fichier, avec des informations. """ # Récupération des informations sur l'EDT téléchargé : cals = [] for i in links : cals.append(icalendar.Calendar.from_ical(sched_get(datet, link = i)) if len(links) == 0 : # Par défaut, ne mets pas de lien, ce qui retourne celui de l'UFR cals = [icalendar.Calendar.from_ical(sched_get(datet))] total_rooms = {} rooms_count = {} # default_hour_margin = 2 margintime = datetime.timedelta(weeks = 4) year_cals = [] for i in links : # Récupérer les liens mentionnés, sur une période de quatres semaines result = sched_get(datet, datet + margintime, links) year_cals.append(icalendar.Calendar.from_ical(result)) if len(links) == 0 : # Par défaut, ne mets pas de lien, ce qui retourne celui de l'UFR year_cals = [icalendar.Calendar.from_ical(sched_get(datet,datet+margintime))] # Ajout de toutes les salles contenues dans le calendrier de l'année scolaire : for cal in year_cals : # Bâtiments for comp in cal.walk() : # Événements if comp.name == "VEVENT" : # Ajout de la salle dans le dictionnaire, si elle n'y est pas : roomname = str(comp.get("location")) if roomname not in total_rooms.keys() : start = datet.replace(hour = 0, minute = 0, second=0) # Par défaut, l'heure de début de disponibilité est aujourd'hui à 00:00 end = datet.replace(hour = 23, minute = 59, second = 59) # Par défaut, l'heure de fin de la prochaine période disponibilité est aujourd'hui à 23:59 is_free = True # Par défaut, la salle est libre total_rooms[roomname] = room(roomname, start, end, is_free) rooms_count[roomname] = 1 else: rooms_count[roomname]+=1 # Ajout des infos supplémentaires sur les salles (heures de début-fin de dispo, indicateur de dispo), s'il y en a : # Première boucle, pour déterminer les salles occupées : for cal in cals : # Bâtiments for comp in cal.walk() : # Événements if comp.name == "VEVENT" : # Récupération des infos : datestart = comp.decoded("dtstart") dateend = comp.decoded("dtend") roomname = str(comp.get("location")) # L'événement se passe maintenant (salle occupée maintenant) : if datestart.timestamp() <= datet.timestamp() and dateend.timestamp() > datet.timestamp() : start = dateend # L'heure de début de la prochaine période de disponibilité est la fin de l'événement end = datet.replace(hour = 23, minute = 59, second = 59) # Par défaut, l'heure de fin de la prochaine période disponibilité est aujourd'hui à 23:59 is_free = False total_rooms[roomname] = room(roomname, start, end, is_free) # Deuxième boucle, pour ajouter les heures de dispos des salles : for cal in cals : # Bâtiments for comp in cal.walk() : # Événements if comp.name == "VEVENT" : # Récupération des infos : datestart = comp.decoded("dtstart") dateend = comp.decoded("dtend") roomname = str(comp.get("location")) # L'événement se passe prochainement (salle occupée à l'occasion de cet événement) : if datestart.timestamp() > datet.timestamp() : if roomname not in total_rooms.keys() : # La salle est forcément libre, car les salles occupées sont déjà toutes enregistrées : start = datet.replace(hour = 0, minute = 0, second=0) # Par défaut, l'heure de début de disponibilité est aujourd'hui à 00:00 end = datestart # L'heure de fin de disponibilité est le début de l'événement is_free = True total_rooms[roomname] = room(roomname, start, end, is_free) elif datestart.timestamp() < total_rooms[roomname]["end"].timestamp() : if datestart.timestamp() == total_rooms[roomname]["start"].timestamp() : start = dateend end = total_rooms[roomname]["end"] else : start = total_rooms[roomname]["start"] end = datestart is_free = total_rooms[roomname]["is_free"] total_rooms[roomname] = room(roomname, start, end, is_free) # Dans les autres cas, l'événement est passé, donc on l'ignore et on passe au suivant. # # On ignore si c'est avant la date actuelle (avec une valeur loin dans le futur) # if datestart.timestamp() < datet.timestamp() : # datestart = datet + datetime.timedelta(hours = default_hour_margin) # Par défaut, si il n'y a rien de précisé pour sa prochaine occupation, elle sera occupée dans 1 ans # if dateend.timestamp() < datet.timestamp() : # dateend = datestart + datetime.timedelta(hours = default_hour_margin) # Par défaut, si il n'y a rien de précisé pour sa prochaine occupation, elle sera occupée dans 1 an après son occupation # Enregistrement dans le dictionnaire : # Plus nécessaire, car on ne s'occupe plus des événements passés : # if roomname in total_rooms.keys() : # if datestart.timestamp() > total_rooms[roomname]["occupied_at"].timestamp() : # occupied_at = total_rooms[roomname]["occupied_at"] # if dateend.timestamp() > total_rooms[roomname]["free_at"].timestamp() : # free_at = total_rooms[roomname]["free_at"] # Filtrer les salles qui ne sont mentionnées qu'un certain nombre de fois # Et qui n'ont pas de virgule dans le nom for roomname in rooms_count.keys(): if rooms_count[roomname]