################ ### UniSquat ### ################ """ Une application pour afficher les salles libres dans les différents départements de l'Université de Strasbourg. """ ### Fichier de l'interface Web Flask ### # Modules : import datetime as dti from flask import Flask from flask import render_template from flask import url_for from flask import request # Fichiers locaux : import date_tools import rooms_get as ro # Constantes : MAX_DEPT = 5 # Le maximum de départements qu'il est possible de sélectionner MAX_LOG_DAYS = 30 # Le nombre de jours pendant lesquels les logs sont conservés MAX_LOG_DEPT = 3 # Le nombre maximum affiché de départements qui ont été le plus cherché PING_WARN = 500 # Nombre d'utilisations à partir du quel un message d'avertissement est affiché 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":[]} app = Flask(__name__) # Fonctions : @app.route("/") def home() : """ Page d'accueil du site Web. Parameters ---------- None Returns ------- flask.render_template """ return render_template("index.html", **GLOBAL_CONTEXT) @app.route("/app") def select_dept() : """ Permet de sélectionner un ou plusieurs départements dans lesquels chercher des salles libres. Parameters ---------- None Returns ------- flask.render_template """ dept_filen = "data/dept_list.txt" dept_list = ro.get_depts(dept_filen) content = {"dept_list":dept_list} url_for("static", filename="style.css") return render_template("dept-select.html", **content, **GLOBAL_CONTEXT) @app.route("/stats") def stats(): """ Statistiques d'utilisation de l'instance Parameters ---------- None (utilise la variable globale 'log') Returns ------- flask.render_template """ # Compte le nombre de fois que les différents départements ont été cherchés pings = 0 counts = {} for log in logs: for dept in log["depts"]: pings+=1 if dept.name in counts.keys(): counts[dept.name]+=1 else: counts[dept.name]=1 sort = [ [x,counts[x]] for x in counts.keys() ] sort.sort(key = lambda x: x[1],reverse = True ) # Trie selon la valeur du deuxieme élément de la liste context = {"MAX_LOG_DAYS":MAX_LOG_DAYS,"PING_WARN":PING_WARN,"depts":sort[:MAX_LOG_DEPT],"nbping":pings} return render_template("stats.html",**context, **GLOBAL_CONTEXT) @app.route("/app/free-rooms", methods=["POST", "GET"]) def free_rooms() : """ Affiche les salles libres dans les départements sélectionnés dans la page des départements. Parameters ---------- None Returns ------- flask.render_template """ # Récupération des ID des départements depuis le formulaire : dident_list = request.args.getlist("dept") if len(dident_list)>MAX_DEPT: return render_template("error.html", error="Trop de départements sélectionnés ! Vous pouvez en sélectionner "+str(MAX_DEPT)+" au maximum.") if len(dident_list)==0: return render_template("error.html", error="Il faut choisir au moins un département !") # Récupération de l'éventuelle date personnalisée (depuis la page de sélection de date) : date_uf = request.args.get("date") if date_uf == None : date_uf = [""] else : date_uf = date_uf.split("-") time_uf = request.args.get("time") if time_uf == None : time_uf = [""] 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) if date_uf != [""] : date = date.replace(year = int(date_uf[0]), month = int(date_uf[1]), day = int(date_uf[2])) date_str += date_uf[2] + "/" + date_uf[1] + "/" + date_uf[0] if time_uf != [""] : date = date.replace(hour = int(time_uf[0]), minute = int(time_uf[1])) date_str += ", à " + time_uf[0] + ":" + time_uf[1] # Récupération de la liste des départements : dept_filen = "data/dept_list.txt" dept_list = ro.get_depts(dept_filen) # Vérifie qu'il n'y a pas de mauvais départements demandés for d in dident_list: try: int(d) except: return render_template("error.html", error="Identifiant de département invalide !", **GLOBAL_CONTEXT) if int(d) < 0 or int(d) >= len(dept_list) : return render_template("error.html", error="Identifiant de département invalide !", **GLOBAL_CONTEXT) dident_list.sort() # Récupération des départements choisis à partir des données du formulaire : i = 0 depts = list() depts_str = "" # Noms des départements pour l'affichage for d in dept_list : if i < len(dident_list) and d.ident == int(dident_list[i]) : depts.append(d) depts_str += d.name if (i + 1) < len(dident_list) : depts_str += ", " i += 1 ignore_list = ["salle non définie", "salle en Distanciel"] free_rooms = ro.getrooms(date, depts, ignore_list) frooms_disp = dict() # Mise en forme des infos pour la page Web i = 0 for r in free_rooms : remain_time_str = "" if r.is_free : remain_time_str = date_tools.remain_time(date, r.end) else : remain_time_str = date_tools.remain_time(date, r.start) frooms_disp[r.name] = {"start":date_tools.hour_disp(r.start), "end":date_tools.hour_disp(r.end), "rtime":remain_time_str} change_date_str = "?" i = 0 for v in dident_list: change_date_str += "dept="+str(v) if i0,"nofavslink":nofavslink} # Crée un log de la date et des départements demandés ( pour des futures statistiques ) log = {} log["timestamp"] = dti.datetime.now().timestamp() log["depts"] = depts logs.append(log) # Vide les logs vieux de MAX_LOG_DAYS while (log["timestamp"]-logs[0]["timestamp"])/(60*60*24)>MAX_LOG_DAYS: del(logs[0]) url_for("static", filename="style.css") return render_template("free-rooms.html", **context, **GLOBAL_CONTEXT) @app.route("/app/date-select", methods=["POST", "GET"]) def date_select() : """ Permet de sélectionner une date à laquelle chercher des salles libres. Parameters ---------- None. Returns ------- flask.render_template """ dident_list = request.args.getlist("dept") context = {"dident_list":dident_list} return render_template("date-select.html", **context, **GLOBAL_CONTEXT) @app.errorhandler(404) def error(e): """ Affiche la page d'erreur Parameters ---------- None. Returns ------- flask.render_template """ return render_template("error.html", error="Page non trouvée !", **GLOBAL_CONTEXT)