Compare commits

...

19 Commits

Author SHA1 Message Date
theo@manjaro b7f6096aaf Les favoris ont fini d'être développés 2022-06-16 13:48:10 +02:00
theo@manjaro b5820b29be Update d'emoji 2022-06-16 13:45:31 +02:00
theo@manjaro 0776a7c987 Désactivation du debug 2022-06-16 11:34:57 +02:00
theo@manjaro 462180986b Précision de la légèreté du front-end 2022-06-16 11:33:31 +02:00
theo@manjaro 5cd946bac5 Espace entre les différentes catégories de salles 2022-06-16 11:27:51 +02:00
theo@manjaro d296d65215 Affichage des salles plus cohérent 2022-06-16 11:20:40 +02:00
theo@manjaro 057d0f9c90 Affichage des salles légèrement plus compact 2022-06-16 10:54:36 +02:00
theo@manjaro 76da00161d Suppressions de règles CSS inutilisées 2022-06-16 10:51:30 +02:00
theo@manjaro b2517ab152 Un peu de padding à droite des titres 2022-06-16 10:45:22 +02:00
theo@manjaro f2fc7c8775 Mode multi-colonnes sur PC 2022-06-16 09:24:24 +02:00
theo@manjaro 0877cc8210 Les boutons ont une taille "normale" 2022-06-15 23:59:48 +02:00
theo@manjaro 104feb31b9 Affichage des salles lambda quand des favoris sont sélectionnés 2022-06-15 23:34:38 +02:00
theo@manjaro 17130f7c04 Ajout d'une liste de features 2022-06-15 22:03:03 +02:00
theo@manjaro 333d2bf3d7 Simple séléction de favoris 2022-06-15 21:48:25 +02:00
theo@manjaro a23d5735df Bouton pour retirer les favoris 2022-06-15 20:23:53 +02:00
theo@manjaro 4c567ebe56 Merge branch 'master' into devel 2022-06-15 20:07:45 +02:00
theo@manjaro 3efa3c36be Affichage des IDs dans les deux catégories d'affichage 2022-06-15 14:06:11 +02:00
theo@manjaro 2a03dde566 Filtrage selon les favoris 2022-06-15 13:52:16 +02:00
theo@manjaro 09975eb013 Ajout d'un ID généré à partir du nom de la salle 2022-06-15 12:46:22 +02:00
5 changed files with 214 additions and 58 deletions

View File

@ -5,6 +5,18 @@ C'est utile aux élèves qui cherchent un coin pour travailler ou manger, comme
Cette application dispose d'une interface Web fonctionnant avec Flask ( [voir la demo][homepage] ).
## Fonctionnalités
- 🔎 Visualiser les salles libres de plusieurs départements en même temps ( par exemple UFR de Math-Info et EOST )
- ⏰ Pour les salles bientôt occupées, l'heure d'occupation est précisée
- 🔄 Affiche également les salles qui sont bientôt libres, avec l'heure en question
- ⭐ Permet de sélectionner des salles comme favorites
* Ces favoris ne sont conservés que sur la page en question ( les favoris sélectionnés sont stockés dans l'URL )
* Ainsi, vous pouvez partager vos favoris simplement en partageant l'URL
- 🪶 Application légère pour l'utilisateur :
* Pas de JavaScript, tout les calculs sont fait coté serveur
* Pas de *Local Storage*, *Cookies* ou autres *bibliothèques CSS*
## Dépendances
Pour l'instant, ce programme utilise les modules suivants :

25
app.py
View File

@ -33,6 +33,7 @@ GLOBAL_CONTEXT = {} # Contexte constant pour les templates Jinja
GLOBAL_CONTEXT["SOURCE"] = "https://forge.chapril.org/Wantoo/UniSquat_Python" # Le lien du code source
GLOBAL_CONTEXT["CREDITSLINK"] = "https://forge.chapril.org/Wantoo" # Le lien de l'organisation
GLOBAL_CONTEXT["CREDITSNAME"] = "Wantoo" # Le nom de l'organisation
GLOBAL_CONTEXT["DEBUG"] = False # Fait en sorte que le logiciel soit un peu plus expressif
# Globales
logs = [] # Stoque les différentes requêtes faite sur la route /free_rooms/, sous la forme {"timestamp":timestamp,"depts":[]}
@ -148,6 +149,11 @@ def free_rooms() :
else :
time_uf = time_uf.split(":")
# Récupére les IDs des salles favorites
favs_ids = request.args.getlist("favs")
if favs_ids==None:
favs_ids = []
date = dti.datetime.now()
date_str = "" # Date affichée sur la page (si personnalisée)
@ -204,6 +210,7 @@ def free_rooms() :
"end":date_tools.hour_disp(r.end),
"rtime":remain_time_str}
change_date_str = "?"
i = 0
for v in dident_list:
@ -211,7 +218,23 @@ def free_rooms() :
if i<len(dident_list)-1:
change_date_str += "&"
i+=1
context = {"free_rooms":free_rooms, "frooms_disp":frooms_disp, "depts_str":depts_str, "dident_list":dident_list, "date_str":date_str, "change_date_str":change_date_str}
# Générer le lien pour enlever les favoris séléctionnés
nofavslink = "/app/free-rooms?"
for dept in dident_list:
nofavslink+="dept="+str(dept)+"&"
nofavslink = nofavslink[:-1] # Enlever le dernier &
# Trier les salles selon leurs catégories
favs_free_rooms = []
favs_soon_rooms = []
soon_rooms = []
final_rooms = []
for r in free_rooms:
[[soon_rooms,final_rooms],[favs_soon_rooms,favs_free_rooms]][r.id in favs_ids][r.is_free].append(r)
context = {"favs_free_rooms":favs_free_rooms, "favs_soon_rooms":favs_soon_rooms, "free_rooms":final_rooms, "soon_rooms":soon_rooms, "frooms_disp":frooms_disp, "depts_str":depts_str, "dident_list":dident_list, "date_str":date_str, "change_date_str":change_date_str, "favs":len(favs_ids)>0,"nofavslink":nofavslink}
# Crée un log de la date et des départements demandés ( pour des futures statistiques )
log = {}

View File

@ -15,6 +15,13 @@ Created on Sat May 7 17:29:11 2022
l'Université de Strasbourg.
"""
# Modules
import random # Nécessaire pour la génération d'ID des salles
# Constantes
ID_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" # Caractères disponibles pour la création d'ID
ID_LEN = 4 # Nombres de caractères composant l'ID
### Fichier contenant les classes des salles et des départements ###
@ -44,6 +51,9 @@ class Room :
count : int
Compte le nombre d'occurences de la salle dans l'emploi du temps;
id : string
Identifiant 'unique' ( avec un très faible risque de collision ) de la salle ( généré à partir de son nom )
"""
def __init__(self, name, start, end, is_free) :
@ -51,6 +61,14 @@ class Room :
self.start = start
self.end = end
self.is_free = is_free
self.id = self.getId(name)
def getId(self,name):
random.seed(name)
id = ""
for i in range(ID_LEN):
id+=random.choice(ID_CHARS)
return id # A peu près une chance sur 15 millions d'être unique, je considère ça viable
class Dept :

View File

@ -50,10 +50,6 @@ nav {
width: 50%;
}
#body {
margin: 10px;
}
p {
text-align: justify;
}
@ -69,6 +65,13 @@ main p {
flex-direction: column;
}
.room-row{
display: flex;
justify-content: space-between;
flex-direction: row;
align-items: center;
}
/* Style The Dropdown Button */
.dropbtn {
color: var(--fg);
@ -126,6 +129,7 @@ h1, h2, h3, h4 {
border-left: solid;
border-width: 5px;
padding-left: 5px;
padding-right: 5px;
background: var(--bg-dark);
display: inline-block;
border-color: var(--hl);
@ -145,18 +149,6 @@ header a {
text-decoration: none;
}
img {
margin: 10px;
align-self: flex-start;
max-width: 200px;
border-radius: 10px;
}
iframe {
max-width: 200px;
max-height: 500px;
}
ul {
margin-bottom: 5px;
}
@ -170,9 +162,10 @@ dt {
padding: 10px;
}
dt .details {
.details {
font-weight: normal;
font-size: 80%;
padding: 0px;
}
input[type="submit"], button, .button{
@ -211,6 +204,10 @@ input[type="checkbox"] {
height: 0px;
}
input[type=checkbox]:checked ~ .remove-check {
display: none;
}
.flex {
display: flex;
flex-wrap: wrap;
@ -238,11 +235,6 @@ input[type="checkbox"] + label {
box-shadow: 5px 5px black;
}
.done {
background: var(--bg-dark);
text-decoration: line-through;
}
input {
background: var(--bg-dark);
}
@ -260,6 +252,18 @@ footer {
color: var(--bg-light);
}
@media screen and (max-width: 769px) {
/* Medium devices (landscape tablets, 768px and up) */
@media only screen and (min-width: 1000px) {
.flex-pc{
display:flex;
flex-wrap: wrap;
}
.room-collumn{
width: 50%;
flex-grow: 1;
}
}
.room-collumn{
margin-bottom: 10px;
}

View File

@ -9,45 +9,144 @@
<body>
{% include "base.html" %}
<main>
Départements sélectionnés :
<b>{{ depts_str }}</b>
<div class="flex">
<p>
Départements sélectionnés : <br>
<b>{{ depts_str }}</b>
</p>
</div>
<div class="flex">
{% if date_str != "" : %}
<b>Le {{ date_str }}</b>
{% endif %}
</div>
<div class="flex">
<a class="button" href='/app/date-select{{change_date_str}}'>Choisir une date</a>
</div>
<h1>Disponibles maintenant</h1>
<div class="flex-container">
<ul>
{% for room in free_rooms : %}
{% if room.is_free : %}
<dt>{{ room.name }}
{% if not(room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59) : %}
<br><span class=details>Jusqu'à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</span>
{% endif %}
</dt>
{% endif %}
{% endfor %}
</ul>
</div>
<br>
<h1>Disponibles prochainement</h1>
<div class="flex-container">
<ul>
{% for room in free_rooms : %}
{% if not room.is_free : %}
<dt>{{ room.name }}
{% if room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59 : %}
<br><span class=details>À {{ frooms_disp[room.name]["start"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</span>
{% else %}
<br><span class=details>De {{ frooms_disp[room.name]["start"] }} à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</span>
{% endif %}
</dt>
{% endif %}
{% endfor %}
</ul>
</div>
{% if favs: %}
<div class="flex">
<a class="button" href="{{ nofavslink }}">Retirer les favoris</a>
</div>
{% endif %}
<form action="/app/free-rooms" method="get">
{% if favs: %}
<div class="flex-pc">
{% if favs_free_rooms|length>0: %}
<div class="room-collumn">
<br>
<h1>Favoris disponibles maintenant</h1>
<div class="flex-container">
<ul>
{% for room in favs_free_rooms : %}
<dt>
<div class="room-row">
<div>
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %}
{% if not(room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59) : %}
<p class=details>Jusqu'à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</p>
{% endif %}
</div>
<div>
<input class="fav" type="checkbox" id="{{ room.id }}" name="favs" value="{{ room.id }}" checked> <label style="width:30px;height:30px" for="{{ room.id }}"></label>
</div>
</div>
</dt>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% if favs_soon_rooms|length>0: %}
<div class="room-collumn">
<br>
<h1>Favoris disponibles prochainement</h1>
<div class="flex-container">
<ul>
{% for room in favs_soon_rooms: %}
<dt>
<div class="room-row">
<div>
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %}
{% if room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59 : %}
<p class=details>À {{ frooms_disp[room.name]["start"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</p>
{% else %}
<p class=details>De {{ frooms_disp[room.name]["start"] }} à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</p>
{% endif %}
</div>
<div>
<input class="fav" type="checkbox" id="{{ room.id }}" name="favs" value="{{ room.id }}" checked> <label style="width:30px;height:30px" for="{{ room.id }}"></label>
</div>
</div>
</dt>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
</div>
{% endif %}
<div class="flex-pc">
{% if free_rooms|length>0 %}
<div class="room-collumn">
<br>
<h1>Disponibles maintenant</h1>
<div class="flex-container">
<ul>
{% for room in free_rooms: %}
<dt>
<div class="room-row">
<div>
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %}
{% if not(room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59) : %}
<p class=details>Jusqu'à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</p>
{% endif %}
</div>
<div>
<input class="fav" type="checkbox" id="{{ room.id }}" name="favs" value="{{ room.id }}"> <label style="width:30px;height:30px" for="{{ room.id }}"></label>
</div>
</div>
</dt>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% if soon_rooms|length>0 %}
<div class="room-collumn">
<br>
<h1>Disponibles prochainement</h1>
<div class="flex-container">
<ul>
{% for room in soon_rooms: %}
<dt>
<div class="room-row">
<div>
{{ room.name }} {% if DEBUG :%}( {{ room.id }} ){% endif %}
{% if room.end.hour == 23 and room.end.minute == 59 and room.end.second == 59 : %}
<p class=details>À {{ frooms_disp[room.name]["start"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</p>
{% else %}
<p class=details>De {{ frooms_disp[room.name]["start"] }} à {{ frooms_disp[room.name]["end"] }} (dans {{ frooms_disp[room.name]["rtime"] }})</p>
{% endif %}
</div>
<div>
<input class="fav" type="checkbox" id="{{ room.id }}" name="favs" value="{{ room.id }}"> <label style="width:30px;height:30px" for="{{ room.id }}"></label>
</div>
</div>
</dt>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
</div>
<div class="flex">
{% for d in dident_list : %} <!-- Magie noire pour conserver les départements séléctionnés -->
<span style="display: none;"><input type="text" name="dept" value="{{ d }}"/></span>
{% endfor %}
<input type="submit" value="Valider les favoris">
</div>
</form>
</main>
{% include "footer.html" %}
</body>