RAPLA-POC, LOGIN-Flow
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ set/
|
||||
VIRTUAL_ENV/
|
||||
calendars/
|
||||
.idea/
|
||||
calendars/list.json
|
||||
|
||||
66
app.py
66
app.py
@ -5,12 +5,13 @@ from flask_login import login_user, login_required, current_user, LoginManager,
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
import dualisauth
|
||||
import requesthelpers
|
||||
from fetchRAPLA import *
|
||||
from get_mysql import get_mysql
|
||||
import time
|
||||
from parseICAL import getWeek
|
||||
|
||||
|
||||
def create():
|
||||
@ -55,23 +56,42 @@ class Dualis(db.Model):
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template('index.html', headermessage='Header', message='DualHub')
|
||||
return redirect(url_for("login"))
|
||||
|
||||
|
||||
@app.route("/welcome")
|
||||
@login_required
|
||||
def welcome():
|
||||
d = Dualis.query.filter_by(uid=current_user.id).first()
|
||||
if not current_user.kurs:
|
||||
kurs = dualisauth.getKurs(d.token, d.cookie)
|
||||
current_user.kurs = kurs
|
||||
db.session.commit()
|
||||
else:
|
||||
kurs = current_user.kurs
|
||||
name = current_user.name
|
||||
return render_template('index.html', headermessage='DualHub', message="Hallo, "
|
||||
+ name + " (" + kurs + ")")
|
||||
|
||||
|
||||
@app.route("/backendpoc/set-up")
|
||||
@login_required
|
||||
def getKurs():
|
||||
d = Dualis.query.filter_by(uid=current_user.id).first()
|
||||
if d:
|
||||
e = False
|
||||
if not current_user.kurs:
|
||||
kurs = dualisauth.getKurs(d.token, d.cookie)
|
||||
if kurs != 0:
|
||||
current_user.kurs = kurs
|
||||
db.session.commit()
|
||||
else:
|
||||
e = True
|
||||
else:
|
||||
kurs = current_user.kurs
|
||||
current_user.kurs = kurs
|
||||
db.session.commit()
|
||||
else:
|
||||
e = True
|
||||
kurs = ""
|
||||
return render_template('kurs.html', detected=(kurs, e))
|
||||
|
||||
|
||||
|
||||
@app.route("/backendpoc/error<int:ecode>")
|
||||
def error(ecode):
|
||||
if ecode == 900:
|
||||
@ -91,7 +111,7 @@ def chooseRaplas():
|
||||
|
||||
|
||||
@login_required
|
||||
@app.route("/backendpoc/plan", methods=["POST"])
|
||||
@app.route("/backendpoc/rapla", methods=["POST"])
|
||||
def getRapla():
|
||||
file = str(request.form.get("file"))
|
||||
url = str(request.form.get("url"))
|
||||
@ -100,16 +120,25 @@ def getRapla():
|
||||
if file != "None":
|
||||
User.query.filter_by(id=current_user.id).first().kurs = file[5:-5]
|
||||
db.session.commit()
|
||||
return send_file("calendars/" + file)
|
||||
#return send_file("calendars/" + file)
|
||||
elif url != "None":
|
||||
file = getNewRapla(url)
|
||||
if type(file) is not int:
|
||||
User.query.filter_by(id=current_user.id).first().kurs = file[5:-5]
|
||||
db.session.commit()
|
||||
return send_file("calendars/" + file)
|
||||
#return send_file("calendars/" + file)
|
||||
else:
|
||||
return redirect(url_for("error", ecode=file + 900))
|
||||
return render_template("index.html")
|
||||
return redirect(url_for("welcome"))
|
||||
|
||||
@login_required
|
||||
@app.route("/backendpoc/plan", methods=["GET"])
|
||||
def displayRapla():
|
||||
samstag = request.args.get("samstag")
|
||||
if not samstag:
|
||||
samstag = False
|
||||
events = getWeek("today", "rapla"+current_user.kurs+".ical", samstag)
|
||||
return render_template("plan.html", events=events[0], eventdays=events[1])
|
||||
|
||||
|
||||
@app.route("/backendpoc/log-in")
|
||||
@ -127,21 +156,19 @@ def login_post():
|
||||
if n:
|
||||
success = redirect(n)
|
||||
else:
|
||||
success = redirect(url_for("welcome"))
|
||||
success = redirect(url_for("getKurs"))
|
||||
|
||||
user = User.query.filter_by(email=email).first()
|
||||
|
||||
if user:
|
||||
dualis = Dualis.query.filter_by(uid=user.id).first()
|
||||
if check_password_hash(user.password, password):
|
||||
if not dualisauth.checkLifetime(dualis.token_created):
|
||||
if not dualis.token or not dualisauth.checkLifetime(dualis.token_created):
|
||||
new_token = dualisauth.checkUser(email, password)
|
||||
dualis.token = new_token[0]
|
||||
dualis.cookie = requesthelpers.getCookie(new_token[1].cookies)
|
||||
dualis.token_created = time.time()
|
||||
db.session.commit()
|
||||
login_user(user)
|
||||
return success
|
||||
else:
|
||||
t = dualisauth.checkUser(email, password)
|
||||
if t[0] == -2:
|
||||
@ -153,6 +180,8 @@ def login_post():
|
||||
dualis.token_created = time.time()
|
||||
db.session.commit()
|
||||
login_user(user)
|
||||
if user.kurs:
|
||||
success = redirect(url_for("welcome"))
|
||||
return success
|
||||
|
||||
t = dualisauth.checkUser(email, password)
|
||||
@ -180,6 +209,11 @@ def login_post():
|
||||
|
||||
@app.route("/backendpoc/log-out")
|
||||
def logout():
|
||||
dualis = Dualis.query.filter_by(uid=current_user.id).first()
|
||||
dualisauth.logOut(dualis.token, dualis.cookie)
|
||||
dualis.cookie = None
|
||||
dualis.token = None
|
||||
db.session.commit()
|
||||
logout_user()
|
||||
return redirect(url_for("login", code=1))
|
||||
|
||||
|
||||
@ -29,22 +29,33 @@ def checkUser(email: str, password: str):
|
||||
return token, s
|
||||
|
||||
|
||||
def getKurs(token: str, cookie: int):
|
||||
headers["Cookie"] = "cnsc=" + str(cookie)
|
||||
def getKurs(token: int, cookie: str):
|
||||
try:
|
||||
headers["Cookie"] = "cnsc=" + cookie
|
||||
token = str(token)
|
||||
response = requests.request("GET",
|
||||
url + "?APPNAME=CampusNet&PRGNAME=COURSERESULTS&ARGUMENTS=-N" + token + ",-N000307,",
|
||||
headers=headers, data={})
|
||||
html = BeautifulSoup(response.text, 'lxml')
|
||||
link = html.body.find('a', attrs={'id': "Popup_details0001"})['href']
|
||||
response = requests.request("GET", url+link[21:], headers=headers, data={})
|
||||
response = requests.request("GET", url + link[21:], headers=headers, data={})
|
||||
html = BeautifulSoup(response.text, 'lxml')
|
||||
content = html.body.find('td', attrs={'class': 'level02'}).text
|
||||
start = content.find(" ")+4
|
||||
start = content.find(" ") + 4
|
||||
end = start + (content[start:].find(" "))
|
||||
kurs = content[start:end]
|
||||
except:
|
||||
kurs = 0
|
||||
return kurs
|
||||
|
||||
|
||||
def logOut(token: int, cookie: str):
|
||||
headers["Cookie"] = "cnsc=" + cookie
|
||||
response = requests.request("GET", url + "?APPNAME=CampusNet&PRGNAME=LOGOUT&ARGUMENTS=-N" + str(token) + ", -N001",
|
||||
headers=headers, data={})
|
||||
|
||||
|
||||
|
||||
def checkLifetime(timecode: float):
|
||||
if time.time() - timecode > 1800:
|
||||
return False
|
||||
|
||||
@ -2,6 +2,7 @@ import urllib.error
|
||||
from urllib.request import urlretrieve
|
||||
import icalendar
|
||||
import json
|
||||
import recurring_ical_events
|
||||
|
||||
|
||||
def parseURL(url: str):
|
||||
@ -37,9 +38,6 @@ def getNewRapla(url: str):
|
||||
except urllib.error.URLError:
|
||||
return -1
|
||||
|
||||
with open("calendars/rapla" + kurs + ".ical") as f:
|
||||
calendar = icalendar.Calendar.from_ical(f.read())
|
||||
# events = calendar.walk("VEVENT")
|
||||
file = open("calendars/list.json", "r+")
|
||||
jsoncal = json.load(file)
|
||||
jsoncal.update({kurs: "rapla" + kurs + ".ical"})
|
||||
|
||||
62
parseICAL.py
Normal file
62
parseICAL.py
Normal file
@ -0,0 +1,62 @@
|
||||
import icalendar
|
||||
import datetime
|
||||
import recurring_ical_events
|
||||
|
||||
|
||||
def getWeek(weekstart: datetime, file: str, showsat: bool):
|
||||
if weekstart == "today":
|
||||
start_date = datetime.date.today()
|
||||
else:
|
||||
start_date = weekstart
|
||||
start_date -= datetime.timedelta(days=start_date.weekday() % 7)
|
||||
end_date = start_date + datetime.timedelta(days=7)
|
||||
with open("calendars/" + file) as f:
|
||||
calendar = icalendar.Calendar.from_ical(f.read())
|
||||
events = recurring_ical_events.of(calendar).between(start_date, end_date)
|
||||
eventl = []
|
||||
for event in events:
|
||||
estart = event["DTSTART"].dt
|
||||
formstart = str(estart.hour) + ":" + str(estart.minute)
|
||||
eend = event["DTEND"].dt
|
||||
formend = str(eend.hour) + ":" + str(eend.minute)
|
||||
forml = [formstart, formend]
|
||||
for i in range(2):
|
||||
if len(forml[i]) != 5:
|
||||
if forml[i][-2] == ":":
|
||||
forml[i] = forml[i] + "0"
|
||||
if forml[i][1] == ":":
|
||||
forml[i] = "0" + forml[i]
|
||||
formstart = forml[0]
|
||||
formend = forml[1]
|
||||
eventdict = {
|
||||
"start": formstart,
|
||||
"end": formend,
|
||||
"dur": str(event["DTEND"].dt - event["DTSTART"].dt)[:-3],
|
||||
"name": event["SUMMARY"],
|
||||
"room": event["LOCATION"],
|
||||
"weekday": estart.weekday(),
|
||||
"day": estart.day
|
||||
}
|
||||
eventl += [eventdict]
|
||||
return eventl, daylist(start_date, showsat)
|
||||
|
||||
|
||||
shortnames = ["mon", "tue", "wed", "thu", "fri", "sat"]
|
||||
longnames = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]
|
||||
|
||||
|
||||
def daylist(weekstart: datetime, showsat: bool):
|
||||
weekday = weekstart
|
||||
dayl = []
|
||||
if showsat:
|
||||
r = 6
|
||||
else:
|
||||
r = 5
|
||||
for i in range(r):
|
||||
dayl += [{
|
||||
"day": weekday.day,
|
||||
"short": shortnames[i],
|
||||
"long": longnames[i],
|
||||
}]
|
||||
weekday += datetime.timedelta(days=1)
|
||||
return dayl
|
||||
133
static/cal.scss
Normal file
133
static/cal.scss
Normal file
@ -0,0 +1,133 @@
|
||||
:root {
|
||||
--numDays: 5;
|
||||
--numHours: 10;
|
||||
--timeHeight: 60px;
|
||||
--calBgColor: #fff1f8;
|
||||
--eventBorderColor: #f2d3d8;
|
||||
--eventColor1: #ffd6d1;
|
||||
--eventColor2: #fafaa3;
|
||||
--eventColor3: #e2f8ff;
|
||||
--eventColor4: #d1ffe6;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
grid-template-columns: auto 1fr;
|
||||
margin: 2rem;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: grid;
|
||||
grid-template-rows: repeat(var(--numHours), var(--timeHeight));
|
||||
}
|
||||
|
||||
.days {
|
||||
display: grid;
|
||||
grid-column: 2;
|
||||
gap: 5px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
}
|
||||
|
||||
.events {
|
||||
display: grid;
|
||||
grid-template-rows: repeat(var(--numHours), var(--timeHeight));
|
||||
border-radius: 5px;
|
||||
background: var(--calBgColor);
|
||||
}
|
||||
|
||||
// Place on Timeline
|
||||
.start-1000 {
|
||||
grid-row-start: 2;
|
||||
}
|
||||
|
||||
.start-1200 {
|
||||
grid-row-start: 4;
|
||||
}
|
||||
|
||||
.start-1300 {
|
||||
grid-row-start: 5;
|
||||
}
|
||||
|
||||
.start-1400 {
|
||||
grid-row-start: 6;
|
||||
}
|
||||
|
||||
.end-1200 {
|
||||
grid-row-end: 4;
|
||||
}
|
||||
|
||||
.end-1300 {
|
||||
grid-row-end: 5;
|
||||
}
|
||||
|
||||
.end-1500 {
|
||||
grid-row-end: 7;
|
||||
}
|
||||
|
||||
.end-1600 {
|
||||
grid-row-end: 8;
|
||||
}
|
||||
|
||||
.end-1700 {
|
||||
grid-row-end: 9;
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
.title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.event {
|
||||
border: 1px solid var(--eventBorderColor);
|
||||
border-radius: 5px;
|
||||
padding: 0.5rem;
|
||||
margin: 0 0.5rem;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.space,
|
||||
.date {
|
||||
height: 60px
|
||||
}
|
||||
|
||||
// Global / Etc
|
||||
|
||||
body {
|
||||
font-family: system-ui, sans-serif;
|
||||
}
|
||||
|
||||
.corp-fi {
|
||||
background: var(--eventColor1);
|
||||
}
|
||||
|
||||
.ent-law {
|
||||
background: var(--eventColor2);
|
||||
}
|
||||
|
||||
.writing {
|
||||
background: var(--eventColor3);
|
||||
}
|
||||
|
||||
.securities {
|
||||
background: var(--eventColor4);
|
||||
}
|
||||
|
||||
.date {
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.date-num {
|
||||
font-size: 3rem;
|
||||
font-weight: 600;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.date-day {
|
||||
display: inline;
|
||||
font-size: 3rem;
|
||||
font-weight: 100;
|
||||
}
|
||||
@ -10,7 +10,7 @@ body
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100px;
|
||||
width: 150px;
|
||||
height: 50px
|
||||
}
|
||||
|
||||
|
||||
22
templates/kurs.html
Normal file
22
templates/kurs.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kurs wählen</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
|
||||
<script async src="https://analytics.paulmartin.cloud/script.js" data-website-id="459fa66e-e255-4393-8e89-ead8b1572d0d"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% if not detected[1] %}
|
||||
<h1>Wir haben {{ detected[0] }} als deinen Kurs ermittelt. Falls er nicht stimmt, kannst du ihn unten auswählen.</h1>
|
||||
<form action={{ url_for("welcome") }}>
|
||||
<input type="submit" value="Der Kurs stimmt!">
|
||||
</form>
|
||||
{% else %}
|
||||
<h1>Dein Kurs konnte leider nicht ermittelt werden. Klicke den Button, um direkt zur Auswahl zu kommen.</h1>
|
||||
{% endif %}
|
||||
<form action={{ url_for("chooseRaplas") }}>
|
||||
<input type="submit" value="Manuell auswählen!">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
51
templates/plan.html
Normal file
51
templates/plan.html
Normal file
@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Vorlesungsplan</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='cal.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="calendar">
|
||||
<div class="timeline">
|
||||
<div class="spacer"></div>
|
||||
<div class="time-marker">08</div>
|
||||
<div class="time-marker">09</div>
|
||||
<div class="time-marker">10</div>
|
||||
<div class="time-marker">11</div>
|
||||
<div class="time-marker">12</div>
|
||||
<div class="time-marker">13</div>
|
||||
<div class="time-marker">14</div>
|
||||
<div class="time-marker">15</div>
|
||||
<div class="time-marker">16</div>
|
||||
<div class="time-marker">17</div>
|
||||
<div class="time-marker">18</div>
|
||||
<div class="time-marker">19</div>
|
||||
</div>
|
||||
<div class="days">
|
||||
{% for e in range (eventdays|length) %}
|
||||
<div class="day {{ eventdays[e]["short"] }}">
|
||||
<div class="date">
|
||||
<p class="date-num">{{ eventdays[e]["day"] }}</p>
|
||||
<p class="date-day">{{ eventdays[e]["long"] }}</p>
|
||||
</div>
|
||||
<div class="events">
|
||||
{% for i in events %}
|
||||
{% if i["weekday"] == e %}
|
||||
<div class="event start-{{ i["start"][:2]+i["start"][3:] }} end-{{ i["end"][:2]+i["end"][3:]}}">
|
||||
<p class="title">{{ i["name"] }}</p>
|
||||
<p class="room">{{ i["room"] }}</p>
|
||||
<p class="duration">{{ i["dur"] }}</p>
|
||||
<p class="time"> {{ i["start"] }} - {{ i["end"] }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user