236 lines
10 KiB
Python
236 lines
10 KiB
Python
#!/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 : # Choper les liens mentionné, sur une période de quatres mois
|
|
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'on pas de virgule dans le nom
|
|
for roomname in rooms_count.keys():
|
|
if rooms_count[roomname]<min_occur or "," in roomname:
|
|
del(total_rooms[roomname])
|
|
return total_rooms
|