391 lines
14 KiB
Python
391 lines
14 KiB
Python
#!/usr/bin/env python3.6
|
|
from flask import make_response
|
|
from flask import render_template, url_for, redirect, request, send_from_directory
|
|
from flask_login import (login_user as loginUser, login_required as loginRequired,
|
|
logout_user as logoutUser, current_user as currentUser)
|
|
from sqlalchemy.exc import IntegrityError
|
|
from werkzeug.exceptions import HTTPException
|
|
import hashlib
|
|
import datetime
|
|
import time
|
|
|
|
import fetchDUALIS
|
|
import fetchRAPLA
|
|
from requesthelpers import *
|
|
from fetchRAPLA import *
|
|
from calendar_generation import getWeek, createCustomCalendar
|
|
from init import *
|
|
|
|
|
|
def initRoutes(app: Flask):
|
|
"""
|
|
Initialisiert die App-Routen. Nötig für Tests.
|
|
:param app:
|
|
"""
|
|
|
|
@app.route("/")
|
|
def index():
|
|
"""
|
|
Leitet den normalen Website-Aufruf zum Login weiter.
|
|
:return HTML:
|
|
"""
|
|
return redirect(url_for("login"))
|
|
|
|
@app.route("/dashboard")
|
|
@loginRequired
|
|
def welcome():
|
|
"""
|
|
Dashboard
|
|
:return HTML:
|
|
"""
|
|
if not currentUser.kurs:
|
|
return redirect(url_for("getKurs", next=url_for(request.endpoint)))
|
|
selectedPhase = request.args.get("sel")
|
|
if not selectedPhase:
|
|
selectedPhase = "theorie"
|
|
kurs = currentUser.kurs
|
|
name = currentUser.name
|
|
if selectedPhase == "theorie":
|
|
theorie = ""
|
|
praxis = "hidden"
|
|
else:
|
|
theorie = "hidden"
|
|
praxis = ""
|
|
return render_template('dashboard.html', kurs=kurs, name=name, theorie=theorie, praxis=praxis)
|
|
|
|
@app.route("/theorie/noten", methods=["GET", "POST"])
|
|
@loginRequired
|
|
async def displayNoten():
|
|
"""
|
|
Zeigt die Noten aus Dualis an. Hierfür ist ein aktives Token nötig.
|
|
:return HTML:
|
|
"""
|
|
dualisUser = Dualis.query.filter_by(uid=currentUser.id).first()
|
|
if request.method == "POST":
|
|
dualisUser.semester = request.form.get("sem")
|
|
db.session.commit()
|
|
if not dualisUser.semester:
|
|
return redirect(url_for("getSemester", next=url_for(request.endpoint)))
|
|
token = dualisUser.token
|
|
chosenSemester = dualisUser.semester
|
|
cookie = request.cookies.get("cnsc")
|
|
timeout = fetchDUALIS.timeOut(dualisUser, cookie, "displayNoten")
|
|
if timeout:
|
|
return timeout
|
|
semester = await getSemesterList(currentUser.id, token, cookie)
|
|
noten = await fetchDUALIS.getResults(token, cookie, chosenSemester)
|
|
return render_template("noten.html", noten=noten, semester=semester, sel=chosenSemester, s="n",
|
|
praxis="hidden")
|
|
|
|
@app.route("/plan", methods=["GET"])
|
|
@loginRequired
|
|
async def displayRapla():
|
|
"""
|
|
Zeigt den Stundenplan für eingeloggte User an. \n
|
|
TODO: Persönliche Filter, Notizen, Essensvorlieben etc. berücksichtigen.
|
|
:return HTML:
|
|
"""
|
|
if not currentUser.kurs:
|
|
return redirect(url_for("getKurs", next=url_for(request.endpoint)))
|
|
week = request.args.get("week")
|
|
if week and week!="today":
|
|
week = datetime.strptime(week, "%Y-%m-%d")
|
|
else:
|
|
week = "today"
|
|
samstag = request.args.get("samstag")
|
|
if not samstag:
|
|
samstag = False
|
|
events = await getWeek(week, fetchRAPLA.getIcal(uid=currentUser.id), samstag)
|
|
return render_template("plan-user.html", events=events[0], eventdays=events[1],
|
|
uid=currentUser.id, name=currentUser.name, prev=str(events[2])[:10],
|
|
next=str(events[3])[:10], mon=events[4], login=True, s="p", date=str(week)[:10],
|
|
praxis="hidden")
|
|
|
|
@app.route("/plan/<string:kurs>")
|
|
async def displayPlan(kurs: str):
|
|
"""
|
|
Zeigt den Stundenplan ohne Login an. \n
|
|
Präferenzen werden nicht berücksichtigt.
|
|
:param kurs:
|
|
:return HTML:
|
|
"""
|
|
week = request.args.get("week")
|
|
if week:
|
|
week = datetime.strptime(week, "%Y-%m-%d")
|
|
else:
|
|
week = "today"
|
|
try:
|
|
if currentUser.kurs == kurs.upper():
|
|
return redirect(url_for("displayRapla"))
|
|
except AttributeError:
|
|
pass
|
|
kurs = kurs.upper()
|
|
plan = fetchRAPLA.getIcal(kurs=kurs)
|
|
if plan:
|
|
samstag = request.args.get("samstag")
|
|
if not samstag:
|
|
samstag = False
|
|
events = await getWeek(week, plan, samstag)
|
|
return render_template("plan-anon.html", events=events[0], eventdays=events[1], kurs=kurs,
|
|
login=False, prev=str(events[2])[:10], next=str(events[3])[:10],
|
|
mon=events[4], praxis="hidden")
|
|
else:
|
|
return redirect(url_for("login"))
|
|
|
|
@app.route("/plan/restore")
|
|
@loginRequired
|
|
async def restoreVL():
|
|
events = HiddenVL.query.filter_by(uid=currentUser.id).all()
|
|
return render_template("restore-events.html", s="s", events=events, praxis="hidden")
|
|
|
|
@app.route("/plan/calendar/<int:uid>", methods=["GET"])
|
|
async def deliverCalendar(uid: int):
|
|
calstring = fetchRAPLA.getIcal(uid=uid)
|
|
return send_from_directory("calendars", calstring, as_attachment=False)
|
|
|
|
@app.route("/set-up")
|
|
def redKurs():
|
|
"""
|
|
Setup beginnt mit Kurs.
|
|
:return HTML:
|
|
"""
|
|
return redirect(url_for("getKurs"))
|
|
|
|
@app.route("/set-up/kurs")
|
|
@loginRequired
|
|
async def getKurs():
|
|
"""
|
|
Automatische Kurs-Auswahl. \n
|
|
Aktives Dualis-Token benötigt.
|
|
:return HTML:
|
|
"""
|
|
dualisUser = Dualis.query.filter_by(uid=currentUser.id).first()
|
|
if dualisUser:
|
|
cookie = request.cookies.get("cnsc")
|
|
timeout = fetchDUALIS.timeOut(dualisUser, cookie, "getKurs")
|
|
if timeout:
|
|
return timeout
|
|
dualisError = False
|
|
if not currentUser.kurs:
|
|
kurs = await fetchDUALIS.getKurs(dualisUser.token, cookie)
|
|
if kurs != 0:
|
|
if not fetchRAPLA.getIcal(kurs=kurs):
|
|
return render_template('kurs.html', detected=(kurs, dualisError), s="s",
|
|
theorie="hidden", praxis="hidden", file=False)
|
|
currentUser.kurs = kurs
|
|
db.session.commit()
|
|
else:
|
|
dualisError = True
|
|
else:
|
|
kurs = currentUser.kurs
|
|
currentUser.kurs = kurs
|
|
db.session.commit()
|
|
else:
|
|
dualisError = True
|
|
kurs = ""
|
|
return render_template('kurs.html', detected=(kurs, dualisError), s="s", theorie="hidden",
|
|
praxis="hidden", file=True)
|
|
|
|
@app.route("/set-up/semester")
|
|
@loginRequired
|
|
async def getSemester():
|
|
"""
|
|
Manuelle Semester-Auswahl.
|
|
:return HTML:
|
|
"""
|
|
token = Dualis.query.filter_by(uid=currentUser.id).first().token
|
|
cookie = request.cookies.get("cnsc")
|
|
semesterList = Semesterlist.query.filter_by(uid=currentUser.id).all()
|
|
if not semesterList:
|
|
semester = await semesterDualisToDB([], token, cookie)
|
|
else:
|
|
semester = await getSemesterList(currentUser.id, token, cookie)
|
|
return render_template("semester.html", semester=semester, s="s",
|
|
theorie="hidden", praxis="hidden")
|
|
|
|
@app.route("/set-up/semester", methods=["POST"])
|
|
@loginRequired
|
|
def setSemester():
|
|
"""
|
|
Speichern der Semester-Auswahl.
|
|
:return HTML:
|
|
"""
|
|
nextArg = request.args.get("next")
|
|
if not nextArg:
|
|
nextArg = url_for("welcome")
|
|
dualisUser = Dualis.query.filter_by(uid=currentUser.id).first()
|
|
dualisUser.semester = request.form.get("sem")
|
|
db.session.commit()
|
|
return redirect(nextArg)
|
|
|
|
@app.route("/set-up/rapla")
|
|
@loginRequired
|
|
def chooseRaplas():
|
|
"""
|
|
Manuelle Rapla-Auswahl.
|
|
:return HTML:
|
|
"""
|
|
raplas = getRaplas()
|
|
return render_template("rapla.html", raplas=raplas, s="s", theorie="hidden", praxis="hidden")
|
|
|
|
@app.route("/set-up/rapla", methods=["POST"])
|
|
@loginRequired
|
|
async def getRapla():
|
|
"""
|
|
Verarbeitet die Eingabe von chooseRaplas().
|
|
:return HTML:
|
|
"""
|
|
file = str(request.form.get("file"))
|
|
url = str(request.form.get("url"))
|
|
if file == url == "None":
|
|
return redirect(url_for("chooseRaplas"))
|
|
if file != "None":
|
|
loadUser(currentUser.id).kurs = file[5:-5]
|
|
db.session.commit()
|
|
elif url != "None":
|
|
file = await getNewRapla(url)
|
|
if type(file) is not int:
|
|
loadUser(currentUser.id).kurs = file[5:-5]
|
|
db.session.commit()
|
|
else:
|
|
return redirect(url_for("error", ecode=900))
|
|
return redirect(url_for("welcome"))
|
|
|
|
@app.route("/log-in")
|
|
def login():
|
|
"""
|
|
Login-Maske.
|
|
:return HTML:
|
|
"""
|
|
return render_template("login.html", theorie="hidden", praxis="hidden", s="s")
|
|
|
|
@app.route("/plan/delete", methods=["POST"])
|
|
@loginRequired
|
|
async def removeEvent():
|
|
day = request.args.get("day")
|
|
id = str(request.args.get("id"))
|
|
uid = currentUser.id
|
|
name = request.args.get("name")
|
|
idDB = HiddenVL(uid=uid, eventid=id, id=str(uid) + id, name=name)
|
|
db.session.add(idDB)
|
|
try:
|
|
db.session.commit()
|
|
except IntegrityError:
|
|
return redirect(url_for("displayRapla", week=day))
|
|
await createCustomCalendar(currentUser.id)
|
|
return redirect(url_for("displayRapla", week=day))
|
|
|
|
@app.route("/plan/restore/event")
|
|
@loginRequired
|
|
async def restoreEvent():
|
|
id = str(request.args.get("id"))
|
|
uid = currentUser.id
|
|
entry = HiddenVL.query.filter_by(id=str(uid) + id).first()
|
|
db.session.delete(entry)
|
|
db.session.commit()
|
|
await createCustomCalendar(currentUser.id)
|
|
return redirect(url_for("restoreVL"))
|
|
|
|
@app.route("/log-in", methods=["POST"])
|
|
async def login_post():
|
|
"""
|
|
Verarbeitet die Eingabe von login(). \n
|
|
Falls der User schon angelegt ist, wird das Passwort verglichen. \n
|
|
Falls nicht, wird ein neuer angelegt.
|
|
:return HTML:
|
|
"""
|
|
email = request.form.get("email")
|
|
password = request.form.get("password")
|
|
nextArg = request.args.get("next")
|
|
if nextArg:
|
|
success = make_response(redirect(nextArg))
|
|
else:
|
|
success = make_response(redirect(url_for("getKurs")))
|
|
|
|
user = User.query.filter_by(email=email).first()
|
|
tokenAndCookie = await fetchDUALIS.checkUser(email, password)
|
|
if tokenAndCookie[0] == -2:
|
|
return redirect(url_for("login", code=-2))
|
|
if user:
|
|
dualisUser = Dualis.query.filter_by(uid=user.id).first()
|
|
dualisUser.token = tokenAndCookie[0]
|
|
newCookie = tokenAndCookie[1]
|
|
dualisUser.token_created = time.time()
|
|
db.session.commit()
|
|
loginUser(user)
|
|
if user.kurs:
|
|
if not dualisUser.semester:
|
|
success = make_response(redirect(url_for("getSemester")))
|
|
elif not nextArg:
|
|
success = make_response(redirect(url_for("welcome")))
|
|
success.set_cookie("cnsc", value=newCookie, httponly=True, secure=True)
|
|
else:
|
|
hashedID = int(hashlib.sha1(email.encode("utf-8")).hexdigest(), 16) % (10 ** 8)
|
|
vorname = email.find(".") + 1
|
|
nachname = min(email[vorname:].find("."), email[vorname:].find("@"))
|
|
name = email[vorname:(vorname + nachname)].capitalize()
|
|
new_user = User(email=email, name=name, id=hashedID)
|
|
db.session.add(new_user)
|
|
db.session.commit()
|
|
cookie = tokenAndCookie[1]
|
|
|
|
newDualis = Dualis(uid=hashedID, token=tokenAndCookie[0], token_created=int(time.time()))
|
|
db.session.add(newDualis)
|
|
db.session.commit()
|
|
loginUser(new_user)
|
|
success.set_cookie("cnsc", value=cookie, httponly=True, secure=True)
|
|
return success
|
|
|
|
@app.route("/log-out")
|
|
@loginRequired
|
|
async def logout():
|
|
"""
|
|
Loggt den User aus.
|
|
:return Empty Token:
|
|
"""
|
|
cookie = request.cookies.get("cnsc")
|
|
dualisUser = Dualis.query.filter_by(uid=currentUser.id).first()
|
|
await fetchDUALIS.logOut(dualisUser.token, cookie)
|
|
dualisUser.token = None
|
|
db.session.commit()
|
|
logoutUser()
|
|
redirection = make_response(redirect(url_for("login", code=1, next=url_for("welcome"))))
|
|
redirection.set_cookie("cnsc", value="Logged out! Your temporary token "
|
|
"on our server and the cookie on your device have been deleted.",
|
|
httponly=True,
|
|
secure=True)
|
|
return redirection
|
|
|
|
@app.route("/error")
|
|
def error():
|
|
"""
|
|
Error Page für custom-Errors. \n
|
|
TODO: Funktion depreciaten. Ersetzen durch Errors auf den entsprechenden Seiten.
|
|
:return HTML:
|
|
"""
|
|
errorCode = request.args.get("ecode")
|
|
if errorCode == "900":
|
|
message = "Ungültige RAPLA-URL! Sicher, dass der Link zum DHBW-Rapla führt?"
|
|
elif errorCode == "899":
|
|
message = "Der Kalender wurde nicht gefunden! Sicher, dass der Link korrekt ist?"
|
|
else:
|
|
message = str(errorCode)
|
|
return render_template('display-message.html', message=message)
|
|
|
|
@app.route("/error")
|
|
@app.errorhandler(HTTPException)
|
|
def handle(e):
|
|
""""
|
|
HTTP-Exception-Handler
|
|
:param e:
|
|
:return HTML:
|
|
"""
|
|
return render_template('display-message.html', message=e)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
initRoutes(flaskApp)
|
|
flaskApp.run(host='0.0.0.0', port=2024, debug=True)
|
|
else:
|
|
initRoutes(flaskApp)
|