2022-02-24 17:21:25 +01:00
#!/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
2022-02-25 10:51:34 +01:00
import datetime
2022-02-26 23:49:19 +01:00
import os
2022-02-24 17:21:25 +01:00
# Fonctions :
2022-02-26 19:33:53 +01:00
def room ( name , start , end , is_free ) :
2022-02-25 10:51:34 +01:00
"""
2022-02-26 19:33:53 +01:00
Retourne un dictionnaire contenant le nom , la prochaine date à laquelle elle est occupée , ainsi que la prochaine date à laquelle elle est libre .
2022-02-26 15:26:34 +01:00
Parameters
- - - - - - - - - -
name : str
Le nom de la salle .
2022-02-26 19:33:53 +01:00
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
2022-03-15 18:53:50 +01:00
Indique si la salle est libre ( ' True ' ) ou non ( ' False ' ) .
2022-02-26 15:26:34 +01:00
Returns
- - - - - - -
dict
2022-02-26 19:33:53 +01:00
Un dictionnaire contenant ces 4 informations , avec le même nom en clef .
2022-02-26 15:26:34 +01:00
2022-02-25 10:51:34 +01:00
"""
2022-03-01 11:05:58 +01:00
2022-02-26 16:39:29 +01:00
# return {"name":name, "occupied_at":occupied_at, "free_at":free_at, "free":free_at.timestamp() > occupied_at.timestamp()}
2022-02-26 19:33:53 +01:00
return { " name " : name , " start " : start , " end " : end , " is_free " : is_free }
2022-02-25 10:51:34 +01:00
2022-02-26 15:26:34 +01:00
2022-02-26 19:33:53 +01:00
def sched_get ( date , enddate = None , link = None ) :
2022-02-24 17:21:25 +01:00
"""
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 ( )
2022-02-26 19:33:53 +01:00
Date du calendrier à télécharger ( date de début si une date de fin
' enddate ' est indiquée ) .
2022-02-24 17:21:25 +01:00
2022-02-25 15:19:14 +01:00
Optionnels :
link :
2022-02-26 15:26:34 +01:00
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.
2022-02-26 19:33:53 +01:00
enddate : datetime . datetime ( )
Date de fin du calendrier à télécharger ( par défaut , il s ' agit de
la date de début ) .
2022-02-25 15:19:14 +01:00
2022-02-24 17:21:25 +01:00
Returns
- - - - - - -
2022-02-26 15:26:34 +01:00
bytes
Le texte du résultat de la requête .
2022-02-24 17:21:25 +01:00
"""
2022-02-24 18:46:53 +01:00
2022-02-25 15:19:14 +01:00
if not link :
2022-02-26 19:33:53 +01:00
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$ "
2022-02-24 18:46:53 +01:00
2022-02-26 19:33:53 +01:00
day1 = str ( date . day )
month1 = str ( date . month )
year1 = str ( date . year )
2022-03-01 11:05:58 +01:00
2022-02-26 19:33:53 +01:00
finallink = link . replace ( " $DAY1$ " , day1 )
finallink = finallink . replace ( " $MONTH1$ " , month1 )
finallink = finallink . replace ( " $YEAR1$ " , year1 )
2022-03-01 11:05:58 +01:00
2022-02-26 19:33:53 +01:00
if enddate != None :
day2 = str ( enddate . day )
month2 = str ( enddate . month )
year2 = str ( enddate . year )
2022-03-01 11:05:58 +01:00
2022-02-26 19:33:53 +01:00
finallink = finallink . replace ( " $DAY2$ " , day2 )
finallink = finallink . replace ( " $MONTH2$ " , month2 )
finallink = finallink . replace ( " $YEAR2$ " , year2 )
2022-03-01 11:05:58 +01:00
2022-02-26 19:33:53 +01:00
else :
finallink = finallink . replace ( " $DAY2$ " , day1 )
finallink = finallink . replace ( " $MONTH2$ " , month1 )
finallink = finallink . replace ( " $YEAR2$ " , year1 )
2022-03-01 11:05:58 +01:00
2022-02-25 15:19:14 +01:00
r = requests . get ( finallink )
2022-02-24 18:46:53 +01:00
return r . content
2022-02-24 17:21:25 +01:00
2022-02-26 15:26:34 +01:00
2022-03-01 11:05:58 +01:00
def getrooms ( datet , links = [ ] , min_occur = 3 ) :
2022-02-24 17:21:25 +01:00
"""
2022-02-26 16:39:29 +01:00
Crée une liste de toutes les salles , avec des informations si elles sont libres ou non .
2022-02-24 17:21:25 +01:00
Parameters
- - - - - - - - - -
datet : datetime . datetime ( )
Date au format datetime .
2022-03-01 11:05:58 +01:00
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 )
2022-02-24 17:21:25 +01:00
Returns
- - - - - - -
2022-02-26 15:26:34 +01:00
total_rooms : dict
2022-02-26 16:39:29 +01:00
Dictionnaire des salles , indexées par leur nom .
2022-02-26 15:26:34 +01:00
Toutes les salles mentionnées dans le fichier , avec des informations .
2022-02-24 17:21:25 +01:00
"""
2022-02-24 18:46:53 +01:00
2022-02-24 17:21:25 +01:00
# Récupération des informations sur l'EDT téléchargé :
2022-02-25 15:19:14 +01:00
cals = [ ]
2022-02-26 19:33:53 +01:00
for i in links :
2022-03-15 18:53:50 +01:00
cals . append ( icalendar . Calendar . from_ical ( sched_get ( datet , link = i ) )
2022-02-26 19:33:53 +01:00
if len ( links ) == 0 : # Par défaut, ne mets pas de lien, ce qui retourne celui de l'UFR
2022-02-25 15:19:14 +01:00
cals = [ icalendar . Calendar . from_ical ( sched_get ( datet ) ) ]
2022-02-24 18:46:53 +01:00
2022-02-25 10:51:34 +01:00
total_rooms = { }
2022-03-01 11:05:58 +01:00
rooms_count = { }
2022-02-26 16:39:29 +01:00
# default_hour_margin = 2
2022-03-01 11:05:58 +01:00
2022-03-03 09:59:59 +01:00
margintime = datetime . timedelta ( weeks = 4 )
2022-02-26 19:33:53 +01:00
year_cals = [ ]
2022-03-15 18:53:50 +01:00
for i in links : # Récupérer les liens mentionnés, sur une période de quatres semaines
2022-03-03 09:59:59 +01:00
result = sched_get ( datet , datet + margintime , links )
2022-03-01 11:13:57 +01:00
year_cals . append ( icalendar . Calendar . from_ical ( result ) )
2022-02-26 19:33:53 +01:00
if len ( links ) == 0 : # Par défaut, ne mets pas de lien, ce qui retourne celui de l'UFR
2022-03-01 11:13:57 +01:00
year_cals = [ icalendar . Calendar . from_ical ( sched_get ( datet , datet + margintime ) ) ]
2022-03-01 11:05:58 +01:00
2022-02-26 19:33:53 +01:00
# 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 )
2022-03-01 11:05:58 +01:00
rooms_count [ roomname ] = 1
else :
rooms_count [ roomname ] + = 1
2022-02-26 19:33:53 +01:00
# Ajout des infos supplémentaires sur les salles (heures de début-fin de dispo, indicateur de dispo), s'il y en a :
2022-02-27 00:30:59 +01:00
# Première boucle, pour déterminer les salles occupées :
2022-02-26 16:39:29 +01:00
for cal in cals : # Bâtiments
for comp in cal . walk ( ) : # Événements
2022-02-25 15:19:14 +01:00
if comp . name == " VEVENT " :
2022-02-26 15:26:34 +01:00
# Récupération des infos :
2022-02-25 15:19:14 +01:00
datestart = comp . decoded ( " dtstart " )
dateend = comp . decoded ( " dtend " )
roomname = str ( comp . get ( " location " ) )
2022-03-01 11:05:58 +01:00
2022-02-27 00:30:59 +01:00
# L'événement se passe maintenant (salle occupée maintenant) :
2022-02-26 16:39:29 +01:00
if datestart . timestamp ( ) < = datet . timestamp ( ) and dateend . timestamp ( ) > datet . timestamp ( ) :
2022-02-26 19:33:53 +01:00
start = dateend # L'heure de début de la prochaine période de disponibilité est la fin de l'événement
2022-02-27 00:30:59 +01: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
2022-02-26 19:33:53 +01:00
is_free = False
total_rooms [ roomname ] = room ( roomname , start , end , is_free )
2022-03-01 11:05:58 +01:00
2022-02-27 00:30:59 +01:00
# 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 " ) )
2022-03-01 11:05:58 +01:00
2022-02-27 00:30:59 +01:00
# L'événement se passe prochainement (salle occupée à l'occasion de cet événement) :
if datestart . timestamp ( ) > datet . timestamp ( ) :
2022-02-26 16:39:29 +01:00
if roomname not in total_rooms . keys ( ) :
2022-02-27 00:30:59 +01:00
# La salle est forcément libre, car les salles occupées sont déjà toutes enregistrées :
2022-02-26 19:33:53 +01:00
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 ( ) :
2022-02-27 11:33:15 +01:00
if datestart . timestamp ( ) == total_rooms [ roomname ] [ " start " ] . timestamp ( ) :
2022-02-27 00:30:59 +01:00
start = dateend
end = total_rooms [ roomname ] [ " end " ]
else :
start = total_rooms [ roomname ] [ " start " ]
end = datestart
2022-02-26 19:33:53 +01:00
is_free = total_rooms [ roomname ] [ " is_free " ]
total_rooms [ roomname ] = room ( roomname , start , end , is_free )
2022-03-01 11:05:58 +01:00
2022-02-26 16:39:29 +01:00
# Dans les autres cas, l'événement est passé, donc on l'ignore et on passe au suivant.
2022-03-01 11:05:58 +01:00
2022-02-26 16:39:29 +01:00
# # 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
2022-03-01 11:05:58 +01:00
2022-02-26 16:39:29 +01:00
# Enregistrement dans le dictionnaire :
2022-03-01 11:05:58 +01:00
2022-02-26 16:39:29 +01:00
# Plus nécessaire, car on ne s'occupe plus des événements passés :
2022-03-01 11:05:58 +01:00
2022-02-26 16:39:29 +01:00
# 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"]
2022-03-01 11:05:58 +01:00
# Filtrer les salles qui ne sont mentionnées qu'un certain nombre de fois
2022-03-03 09:59:59 +01:00
# Et qui n'ont pas de virgule dans le nom
2022-03-01 11:05:58 +01:00
for roomname in rooms_count . keys ( ) :
if rooms_count [ roomname ] < min_occur or " , " in roomname :
del ( total_rooms [ roomname ] )
2022-02-25 10:51:34 +01:00
return total_rooms