Implemented SQL database

tablemaker not finished yet
This commit is contained in:
2023-10-13 15:52:07 +02:00
parent 8028921ed1
commit 1ae05ef75c
11 changed files with 347 additions and 233 deletions

100
data/classesdb.py Normal file

@ -0,0 +1,100 @@
from main import app, db
from copy import deepcopy
class Classes(db.Model):
id = db.Column(db.Integer, primary_key=True, nullable=False)
usr_id = db.Column(db.Integer, nullable=False)
day = db.Column(db.Integer, nullable=False)
timeslot = db.Column(db.Integer, nullable=False)
eventtype = db.Column(db.String(2), nullable=False)
abbrev = db.Column(db.String(11), nullable=False)
classname = db.Column(db.String(50), nullable=False)
roomname = db.Column(db.String(11), nullable=False)
color = db.Column(db.String(30), nullable=False)
priority = db.Column(db.Boolean, nullable=False)
def __repr_(self):
repr = "<id: " + str(self.id) + ", "
repr += "usr_id: " + str(self.usr_id) + ", "
repr += "day: " + str(self.day) + ", "
repr += "timeslot: " + str(self.timeslot) + ", "
repr += "eventtype: " + str(self.eventtype) + ", "
repr += "abbrev: " + str(self.abbrev) + ", "
repr += "classname: " + str(self.classname) + ", "
repr += "roomname: " + str(self.roomname) + ", "
repr += "color: " + str(self.color) + ">"
def set_classes_of(id: int, classes: [{}]) -> None:
with app.app_context():
# delete existing classes
db.session.execute(db.delete(Classes).where(Classes.usr_id == id))
# add new classes
for x in classes:
if len(x) != 8:
raise ValueError("Malformatted input")
day = x["day"]
timeslot = x["timeslot"]
eventtype = x["eventtype"]
abbrev = x["abbrev"]
classname = x["classname"]
roomname = x["roomname"]
color = x["color"]
priority = x["priority"]
db.session.add(Classes(usr_id=id, day=day, timeslot=timeslot, eventtype=eventtype, abbrev=abbrev, classname=classname,
roomname=roomname, color=color, priority=priority))
db.session.commit()
def get_classes_of(id: int) -> [{}]:
result = []
with app.app_context():
rows = db.session.execute(db.select(Classes.day, Classes.timeslot, Classes.eventtype, Classes.abbrev,
Classes.classname, Classes.roomname, Classes.color,
Classes.priority).distinct().where(Classes.usr_id==id)).all()
for x in rows:
mapping = x._mapping
row_map = {}
row_map["day"] = mapping["day"]
row_map["timeslot"] = mapping["timeslot"]
row_map["eventtype"] = mapping["eventtype"]
row_map["abbrev"] = mapping["abbrev"]
row_map["classname"] = mapping["classname"]
row_map["roomname"] = mapping["roomname"]
row_map["color"] = mapping["color"]
result.append(row_map)
return result
def get_grouped_classes_of(id: int) -> [{}]:
classes = get_classes_of(id)
processed = []
result = []
for day in range(5):
for timeslot in range(12):
for event in classes:
if event in processed:
continue
if classes != {}:
print((day, timeslot))
print(event)
print(processed)
if event["day"]==day and event["timeslot"]==timeslot:
print("bearbeite")
event_result = deepcopy(event)
event_result["eventlength"] = 0 # not =1 because the while loop will have at least one iteration
# check if events in following timeslots have same attributes
reference = deepcopy(event)
print("ref:" + str(reference))
print("proc:" + str(processed))
while reference in classes and reference not in processed:
# if so, interpret them as continuation of current element
event_result["eventlength"] += 1
# 1,5 stunden habe ich gebraucht um herauszufinden dass in die nächste Zeile
# ein deepcopy rein muss. so ein scheiss.
processed.append(deepcopy(reference))
reference["timeslot"] += 1
result.append(event_result)
print(result)
return result

BIN
data/data.db Normal file

Binary file not shown.

25
data/displaynamedb.py Normal file

@ -0,0 +1,25 @@
from main import app, db
class Displaynames(db.Model):
usr_id = db.Column(db.Integer, primary_key=True, nullable=False)
displayname = db.Column(db.String(30), nullable=False)
def __repr__(self):
return "<usr_id: " + str(self.usr_id) + ", name: " + str(self.name) + ">"
def set_name_of(id: int, displayname: str) -> None:
with app.app_context():
# delete existing dataset
db.session.execute(db.delete(Displaynames).where(Displaynames.usr_id == id))
# create new
db.session.add(Displaynames(usr_id=id, displayname=displayname))
db.session.commit()
def get_name_of(id: int) -> str | None:
with app.app_context():
name = db.session.execute(db.select(Displaynames.displayname).where(Displaynames.usr_id == id)).all()
try:
return name[0]._mapping["displayname"]
except IndexError:
return ""

@ -1 +1 @@
{"mongo": ["14"]}
{"mongo": [], "14": ["14"]}

51
data/permissionsdb.py Normal file

@ -0,0 +1,51 @@
from main import app, db
class Permissions(db.Model):
id = db.Column(db.Integer, primary_key=True, nullable=False)
bearer = db.Column(db.Integer, nullable=False)
subject = db.Column(db.Integer, nullable=False)
def __repr__(self):
return "<id: " + str(self.id) + ", bearer: " + str(self.bearer) + ", subject: " + str(self.subject) + ">"
def get_permissions_of(id: int) -> [int]:
with app.app_context():
result = []
for x in db.session.execute(db.select(Permissions.subject).distinct().where(Permissions.bearer==id)).all():
row_map = x._mapping
result.append(row_map["subject"])
return result
def get_permissions_for(id: int) -> [int]:
with app.app_context():
result = []
for x in db.session.execute(db.select(Permissions.bearer).distinct().where(Permissions.subject==id)).all():
row_map = x._mapping
result.append(row_map["bearer"])
return result
def set_permissions_of(id: int, ids: [int]) -> None:
with app.app_context():
# delete current permissions
db.session.execute(db.delete(Permissions).where(Permissions.bearer==id))
# remove duplicates from given list
to_add = list(set(ids))
# add new datasets
for x in to_add:
db.session.add(Permissions(bearer=id, subject=x))
db.session.commit()
def set_permissions_for(id: str, ids: [str]) -> None:
with app.app_context():
# delete current permissions
db.session.execute(db.delete(Permissions).where(Permissions.subject == id))
# remove duplicates from given list
to_add = list(set(ids))
# add new datasets
for x in to_add:
db.session.add(Permissions(bearer=x, subject=id))
db.session.commit()

@ -1 +1 @@
{"timetable_data": {"3": {"2": ["2", "VL", "12345678901", "01234567890123456780123456789012345678901234567890", "S3|11 R08", "rgb(255, 150, 113, .7)"], "4": ["2", "VL", "C++", "", "S1|05 R122", "rgb(0, 143, 122, .7)"], "9": ["1", "UE", "Softw. Eng.", "", "S3|06 R052", "rgb(217, 232, 238, .7)"], "10": ["2", "VL", "Leistungse.", "", "S3|06 R051", "rgb(0, 137, 186, .7)"]}, "1": {"2": ["2", "VL", "Elektr. MuA", "", "S3|11 R0012", "rgb(255, 199, 95, .7)"], "6": ["2", "UE", "Elektr. MuA", "", "S3|11 R0012", "rgb(255, 199, 95, .7)"], "0": ["2", "VL", "SDRT I", "", "S3|11 R08", "rgb(255, 150, 113, .7)"]}, "4": {"0": ["2", "UE", "Elektr. MuA", "", "S3|11 R0012", "rgb(255, 199, 95, .7)"], "6": ["2", "VL", "Leistungse.", "", "S3|06 R052", "rgb(0, 137, 186, .7)"]}, "2": {"8": ["2", "VL", "Softw. Eng.", "", "S3|06 R052", "rgb(217, 232, 238, .7)"]}}, "name": "Pedro"}
{"timetable_data": {"3": {"2": ["2", "VL", "12345678901", "01234567890123456780123456789012345678901234567890", "S3|11 R08", "rgb(255, 150, 113, .7)"], "4": ["2", "VL", "C++", "", "S1|05 R122", "rgb(0, 143, 122, .7)"], "9": ["1", "UE", "Softw. Eng.", "", "S3|06 R052", "rgb(217, 232, 238, .7)"], "10": ["2", "VL", "Leistungse.", "", "S3|06 R051", "rgb(0, 137, 186, .7)"]}, "1": {"2": ["2", "VL", "Elektr. MuA", "", "S3|11 R0012", "rgb(255, 199, 95, .7)"], "6": ["2", "UE", "Elektr. MuA", "", "S3|11 R0012", "rgb(255, 199, 95, .7)"], "0": ["2", "VL", "SDRT I", "", "S3|11 R08", "rgb(255, 150, 113, .7)"]}, "4": {"0": ["2", "UE", "Elektr. MuA", "", "S3|11 R0012", "rgb(255, 199, 95, .7)"], "6": ["2", "VL", "Leistungse.", "", "S3|06 R052", "rgb(0, 137, 186, .7)"]}, "2": {"8": ["2", "VL", "Softw. Eng.", "", "S3|06 R052", "rgb(217, 232, 238, .7)"]}}, "name": "Pedro Sipf"}

@ -1,42 +1,32 @@
import json
import permutil
from data import permissionsdb as pdb
from data import classesdb as cdb
from data import displaynamedb as ddb
# for given id: returns html of form elements which contain the users current classes
# each element of returned list contains html for one form line (one class)
def make_form_for(usr_id) -> [str]:
# list to return
result = []
# create json path
json_path = "data/timetables/" + usr_id + ".json"
# load data from json file
with open(json_path, 'r') as j:
json_file_content = json.loads(j.read())
if json_file_content == {}:
return ['<input type="text" class="input" name="usr-name" placeholder="dein Name" style="width: 200px">', ""]
usr_name = json_file_content["name"]
timetable_data = json_file_content["timetable_data"]
# set name
usr_name = ddb.get_name_of(usr_id)
result.append('<input type="text" class="input" value="' + usr_name +
'" name="usr-name" placeholder="dein Name" style="width: 200px">')
'" name="usr-name" placeholder="dein Name" maxlength="30" style="width: 300px">')
# set classes
lnr = 0
for day in timetable_data:
for timeslot in timetable_data[day]:
duration = timetable_data[day][timeslot][0]
event_type = timetable_data[day][timeslot][1]
name = timetable_data[day][timeslot][2]
room = timetable_data[day][timeslot][3]
color = timetable_data[day][timeslot][4]
abbrev = timetable_data[day][timeslot][5]
result.append(make_line(day, timeslot, duration, event_type, name, room, color, abbrev, str(lnr)))
lnr += 1
usr_classes = cdb.get_grouped_classes_of(usr_id)
for usr_class in usr_classes:
day = usr_class["day"]
timeslot = usr_class["timeslot"]
eventlength = usr_class["eventlength"]
eventtype = usr_class["eventtype"]
abbrev = usr_class["abbrev"]
classname = usr_class["classname"]
roomname = usr_class["roomname"]
color = usr_class["color"]
result.append(make_line(day, timeslot, eventlength, eventtype, abbrev, classname, roomname, color, str(lnr)))
lnr += 1
return result
@ -169,10 +159,10 @@ def get_color_name(color_code: str) -> str:
def make_permissionlist_of(id):
result = ""
first_it = True
for usr_id in permutil.get_permissions_for(id):
for usr_id in pdb.get_permissions_for(id):
if first_it:
result += usr_id
result += str(usr_id)
first_it = False
else:
result += (", " + usr_id)
result += (", " + str(usr_id))
return result

103
main.py

@ -1,17 +1,14 @@
import flask
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_pyoidc import OIDCAuthentication, provider_configuration
from flask_pyoidc.user_session import UserSession, UninitialisedSession
import os
import json
import formmaker
import permutil
import tablemaker
import util
from util import UnsafeInputError, LayoutError
@ -20,6 +17,13 @@ secrets = open("appsecret", "r").read().split("\n")
app = Flask(__name__)
app.config["SECRET_KEY"] = secrets[0]
db = SQLAlchemy()
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data/data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db.init_app(app)
oidcConfig = json.loads(open("oidc_config.json", "r").read())
oidcProviderConfig = provider_configuration.ProviderConfiguration(
@ -38,10 +42,49 @@ oidcProviderConfig = provider_configuration.ProviderConfiguration(
)
oidc = OIDCAuthentication({'default': oidcProviderConfig})
import formmaker
from data import permissionsdb as pdb
from data import displaynamedb as ddb
from data import classesdb as cdb
import tablemaker
import util
from util import UnsafeInputError, LayoutError
# TODO: Routes entfernen
@app.route('/dbtesta/')
def dbtesta():
db.session.add(Permissions(bearer="14", subject="14"))
db.session.commit()
return "fertig"
@app.route('/dbtestb/')
def dbtestb():
# db.session.execute(db.select(Permissions.bearer, Permissions.subject)).all() returnt liste von row-Objekten
print([x._mapping for x in db.session.execute(db.select(Permissions.bearer, Permissions.subject)).all()])
return "bla"
@app.route('/dbtestc/')
def dbtestc():
testa = {"day": 2, "timeslot": 4, "eventtype": "VL", "abbrev": "Mathe IV", "classname": "Mathematik IV für ET",
"roomname": "S1|01 A1", "color": "rgb(123, 123, 123, .5)", "priority": True}
testb = {"day": 2, "timeslot": 5, "eventtype": "VL", "abbrev": "Mathe IV", "classname": "Mathematik IV für ET",
"roomname": "S1|01 A1", "color": "rgb(123, 123, 123, .5)", "priority": True}
testc = {"day": 2, "timeslot": 5, "eventtype": "UE", "abbrev": "Mathe IV", "classname": "Mathematik IV für ET",
"roomname": "S1|03 R12", "color": "rgb(123, 123, 123, .5)", "priority": False}
testd = {"day": 2, "timeslot": 6, "eventtype": "UE", "abbrev": "Mathe IV", "classname": "Mathematik IV für ET",
"roomname": "S1|03 R12", "color": "rgb(123, 123, 123, .5)", "priority": False}
classes = [testa, testb, testc, testd]
cdb.set_classes_of(14, classes)
return ":)"
@app.route('/dbtestd/')
def dbtestd():
return cdb.get_grouped_classes_of(14)
@app.route('/')
def main():
# TODO: Optisch schön machen. 3 Buttons: View, Edit, und canvas (canvas: nur eigener sichtbar)
try:
id = UserSession(flask.session).id_token["sub"]
except UninitialisedSession:
@ -58,11 +101,6 @@ def edit():
# example id_token: {"aud": ["712189cb97dc69807261fe36dbd08ffd"], "exp": 1681505828, "iat": 1681502228, "iss": "https://account.omegazero.org", "nonce": "LJNDVdHDIvM0ZFLA", "sub": "2"}
id = UserSession(flask.session).id_token["sub"]
if not os.path.isfile("data/timetables/" + str(id) + ".json"):
with open("data/timetables/" + str(id) + ".json", 'w') as j:
j.write(json.dumps({}))
tempform = formmaker.make_form_for(id)
form = [id]
for x in tempform:
@ -104,7 +142,7 @@ def commit():
# name
try:
data["name"] = util.check_name(request.form.get("usr-name"))
ddb.set_name_of(id, util.check_name(request.form.get("usr-name")))
except UnsafeInputError as e:
input_errors.append(e)
@ -112,14 +150,17 @@ def commit():
try:
text = util.check_friends(request.form.get("usr-friends"))
friends = text.split(", ")
friends_int = []
for friend in friends:
friend.strip()
permutil.set_permissions_for(id, friends)
friends_int.append(int(friend))
pdb.set_permissions_for(id, friends)
except UnsafeInputError as e:
input_errors.append(e)
# timetable-data
data["timetable_data"] = {}
classes = []
occupied_slots = []
for lnr in range(int(request.form.get("highest-lnr"))+1):
# check if all empty
all_elements_none = True
@ -152,19 +193,32 @@ def commit():
# check if line fits into structure
try:
day, timeslot, duration, eventtype, abbrev, classname, roomname, color = util.check_timetable_structure(lnr, form_element_list, data)
try:
temp = data["timetable_data"][day]
except KeyError:
# day has no entry yet
data["timetable_data"][day] = {}
data["timetable_data"][day][timeslot] = [duration, eventtype, abbrev, classname, roomname, color]
day, timeslot, duration, eventtype, abbrev, classname, roomname, color = util.check_timetable_structure(lnr, form_element_list)
day, timeslot, duration = int(day), int(timeslot), int(duration)
# check if timetable already contains event which occupies timeslot
priority = True
for dur in range(duration):
if (day, timeslot+dur) in occupied_slots:
priority = False
occupied_slots.append((day, timeslot + dur))
# add data to class list
for dur in range(duration):
row = {
"day": day,
"timeslot": timeslot+dur,
"eventtype": eventtype,
"abbrev": abbrev,
"classname": classname,
"roomname": roomname,
"color": color,
"priority": priority
}
classes.append(row)
except LayoutError as e:
layout_errors.append(e)
if input_errors == [] and layout_errors == []:
with open("data/timetables/" + id + ".json", 'w') as j:
j.write(json.dumps(data))
cdb.set_classes_of(id, classes)
return flask.redirect(flask.url_for('main'))
else:
return handle(input_errors, layout_errors, request.form.get("form-content"))
@ -198,12 +252,13 @@ def view():
user_data = tablemaker.read_data(usr_id=id)
# get ids of other users whose timetables the requesting user has access to
permitted_ids = permutil.get_permissions_of(id)
permitted_ids = permdb.get_permissions_of(id)
# adds all of their [name, timetable-html] lists to other_user_data
other_user_data = []
for permitted_id in permitted_ids:
data_to_appaned = tablemaker.read_data(usr_id=permitted_id)
no_more_duplicates = False
# check if name of dataset to add already exists in list
while not no_more_duplicates:
no_more_duplicates = True
for person in other_user_data:

@ -1,46 +0,0 @@
import json
def get_permissions_of(id: str) -> [str]:
json_file_content = {}
with open("data/permissions.json", 'r') as j:
json_file_content = json.loads(j.read())
if id not in json_file_content.keys():
return []
return json_file_content[id]
def get_permissions_for(id: str) -> [str]:
with open("data/permissions.json", 'r') as j:
json_file_content = json.loads(j.read())
result = []
for x in json_file_content:
if id in json_file_content[x]:
result.append(x)
return result
def set_permissions_of(id: str, ids: [str]) -> None:
with open("data/permissions.json", 'r') as j:
json_file_content = json.loads(j.read())
json_file_content[id] = ids
with open("data/permissions.json", 'w') as j:
j.write(json.dumps(json_file_content))
def set_permissions_for(id: str, ids: [str]) -> None:
with open("data/permissions.json", 'r') as j:
json_file_content = json.loads(j.read())
for x in ids:
if x not in json_file_content:
json_file_content[x] = []
for x in json_file_content:
if x in ids:
if id not in json_file_content[x]:
json_file_content[x].append(id)
else:
if id in json_file_content[x]:
json_file_content[x].remove(id)
with open("data/permissions.json", 'w') as j:
j.write(json.dumps(json_file_content))

@ -1,72 +1,18 @@
import json
from data import displaynamedb as ddb
from data import classesdb as cdb
# For given user ID: returns their name and html for their timetable
def read_data(usr_id) -> [str, str]:
# ============= READ DATA =================================
# create json path
json_path = "data/timetables/" + usr_id + ".json"
# load data from json file
with open(json_path, 'r') as j:
json_file_content = json.loads(j.read())
if json_file_content == {}:
return ["", ""]
usr_name = json_file_content["name"]
timetable_data = json_file_content["timetable_data"]
# usr_timetable_data structure is as follows:
# {day: {timeslot: [length (#timeslots), event type, abbrev, name, room, color]}
# Wochentag und Zeitslot beginnen bei 0
# change key data type to int, so that organization works properly
old_day_keys = list(timetable_data.keys()).copy()
for day in old_day_keys:
old_timeslot_keys = list(timetable_data[day].keys()).copy()
for timeslot in old_timeslot_keys:
timetable_data[day][int(timeslot)] = timetable_data[day].pop(timeslot)
timetable_data[int(day)] = timetable_data.pop(day)
usr_name = ddb.get_name_of(usr_id)
classes = cdb.get_grouped_classes_of(usr_id)
# ========== ORGANIZE DATA ========================
# courses: dict for all cells that shall not be left empty {(col, row): [text, color, height modification factor]}
# height modification factor decides the rowspan of the cell, 0 means that cell will not be added at all
# the latter is required for overlapped cells when using rowspan>0
courses: {(int, int): [str]}
courses = {}
for day in timetable_data:
if day > 4:
raise ValueError
for timeslot in timetable_data[day]:
# Add course information (type, then name, then room)
[length, event_type, abbrev, name, room, color] = timetable_data[day][timeslot]
length = int(length)
# Change name to contain tooltip
if name != "":
name = '<span class="tooltip">' + abbrev + '<span class="tooltiptextwide">' + name + '</span></span>'
else:
name = abbrev
courses[(2*day, 2*timeslot)] = [event_type, color, length]
courses[(2*day)+1, 2*timeslot] = [name, color, 1 + (length-1)*2]
courses[(2*day)+1, (2*timeslot)+1 + (2*(length-1))] = [room, color, 1]
# Add cells with hmf=0 for timeslots with length >1
if length > 1:
for x in range(length):
if x >=1: # add hmf=0 cells only below course cell
courses[2 * day, 2 * (timeslot+x)] = [event_type, color, 0]
courses[(2 * day) + 1, 2 * (timeslot+x)] = [name, color, 0]
if x < length-1: # don't add hmf=0 cell where room cell will be placed
courses[(2 * day) + 1, 2 * (timeslot + x) + 1] = [name, color, 0]
# ========== GENERATE STRING ==================
# make html text from given data structure
html_text = '<table>'
# ============= CREATE TIMETABLE ============================
html_text = "<table>"
# First row
html_text += '<tr>'
@ -74,48 +20,36 @@ def read_data(usr_id) -> [str, str]:
html_text += '<td class="daybar", colspan="2">' + title + '</td>'
html_text += '</tr>'
cells_to_exclude = []
js_cycler_data = {} # {index: [{"type": ..., "abbrev": ..., "classname: ": ..., }]}
# Other Rows
for row in range(24):
html_text += '<tr>'
# Timeslot and Time columns
if row % 2 == 0:
html_text += '<td class="timeslots" rowspan="2">' + str(int((row+2) / 2))
html_text += '<td class="timeslots" rowspan="2">' + str(int((row + 2) / 2))
html_text += '</td> <td class="time">' + get_time(row) + '</td>'
else:
html_text += '<td class="time-lower">' + get_time(row) + '</td>'
# Course columns
for col in range(10):
exists_in_course_list = True
try:
temp = courses[(col, row)]
except KeyError:
exists_in_course_list = False
colkey, rowkey = colrow_to_keys(col, row)
even = (row % 2 == 0, col % 2 == 0)
# TODO: irgendwie diesen kram machen
if even == (True, True):
classes_here = get_classes_at(colkey, rowkey, classes)
html_text += '<td rowspan="' + + '"'
# TODO: Skripte zum wechseln hinzufügen
if exists_in_course_list:
[text, color, hmf] = courses.get((col, row))
if int(hmf) == 0: # if height modification factor is 0, cell will be left out
continue
if row % 2 == 0: # upper part of time row
if col % 2 == 0: # left side of date column
rowspan = int(hmf) * 2
html_text += '<td class="type" rowspan="' + str(rowspan) + '" style="background-color: ' + color + '">' + text + '</td>'
else: # right side of date column
rowspan = int(hmf) * 1
html_text += '<td class="name" rowspan="' + str(rowspan) + '" style="background-color: ' + color + '">' + text + '</td>'
else: # lower part of time row
if col % 2 == 0: # left side of date column
continue # do nothing, because space is taken up by two line high "type"-cell
else: # right side of date column
rowspan = int(hmf) * 1
html_text += '<td class="room" rowspan="' + str(rowspan) + '" style="background-color: ' + color + '">' + text + '</td>'
else:
if col % 2 == 0 and row % 2 == 0:
html_text += '<td class="empty" colspan="2" rowspan="2"></td>'
else:
continue
html_text += '</tr>'
# Bottom black line
html_text += '<tr>'
@ -126,6 +60,17 @@ def read_data(usr_id) -> [str, str]:
html_text += '</table>'
return [usr_name, html_text]
def colrow_to_keys(col: int, row: int) -> (int, int):
col -= 2
row -= 1
return int(col/2), int(row/2)
def get_classes_at(day: int, timeslot: int, classes: [{}]):
result = []
for x in classes:
if x["day"] == day and x["timeslot"] == timeslot:
result.append(x)
return result
def get_time(row: int) -> str:
if row not in range(24):

74
util.py

@ -1,4 +1,4 @@
import json
from data import displaynamedb as ddb
import os
import random
import string
@ -16,7 +16,9 @@ class LayoutError(Exception):
def check_name(input: str) -> str:
if input is None:
raise UnsafeInputError("Name: Feld ist leer (None)")
forbidden_char = check_chars(input, ["."])
if len(input) > 30:
raise UnsafeInputError("Name: Name zu lang (>30 Zeichen)")
forbidden_char = check_chars(input, ["."], False)
if forbidden_char != "":
raise UnsafeInputError("Name: Zeichen " + forbidden_char + " nicht zulässig")
return input
@ -27,7 +29,7 @@ def check_name(input: str) -> str:
def check_friends(input: str) -> str:
if input is None:
raise UnsafeInputError("Nutzer-IDs: Feld ist leer (None)")
forbidden_char = check_chars(input, [".", ","])
forbidden_char = check_chars(input, [","], True)
if forbidden_char != "":
raise UnsafeInputError("Nutzer-IDs: Zeichen " + forbidden_char + " nicht zulässig")
return input
@ -46,7 +48,7 @@ def check_timetable_input(input: str, form: str) -> str:
elif form.split("-")[0] == "classname":
if len(input) > 50:
raise UnsafeInputError(form_to_friendly(form) + ": Eingabe zu lang (>50 Zeichen)")
forbidden_char = check_chars(input, [".", ",", ":", "-", "#", "|", "!", "?", "/", "+"])
forbidden_char = check_chars(input, [".", ",", ":", "-", "#", "|", "!", "?", "/", "+"], False)
if forbidden_char != "":
raise UnsafeInputError(form_to_friendly(form) + ": Zeichen " + forbidden_char + " nicht zulässig")
return input
@ -67,14 +69,16 @@ def check_color_input(input: str, form: str) -> str:
# checks if prohibited characters are contained in string
# if so, returns prohibited character, if not: returns empty string
def check_chars(input: str, permitted_spec_chars: [str]) -> str:
def check_chars(input: str, permitted_spec_chars: [str], num_only: bool) -> str:
if input is None:
return ""
permitted_chars = [*string.ascii_letters]
permitted_chars = []
if not num_only:
permitted_chars += [*string.ascii_letters]
permitted_chars += ["ö", "ä", "ü", "Ö", "Ä", "Ü"] # ich lasse die reihenfolge so, um bendo zu nerven
permitted_chars += [*string.digits]
permitted_chars += [*string.whitespace]
permitted_chars += permitted_spec_chars
permitted_chars += ["ö", "ä", "ü", "Ö", "Ä", "Ü"] # ich lasse die reihenfolge so, um bendo zu nerven
for character in input:
if character not in permitted_chars:
return character
@ -84,7 +88,7 @@ def check_chars(input: str, permitted_spec_chars: [str]) -> str:
# checks if given new data line fits into existing timetable data
# if so: returns new data line, if not: raises LayoutError
def check_timetable_structure(lnr: int, new_line: [str], data: {}) -> [str]:
def check_timetable_structure(lnr: int, new_line: [str]) -> [str]:
day, timeslot, duration, eventtype, abbrev, classname, roomname, color = new_line
ls = "Zeile " + str(lnr+1) + ": "
@ -124,25 +128,26 @@ def check_timetable_structure(lnr: int, new_line: [str], data: {}) -> [str]:
raise LayoutError(ls+"Veranstaltungsdauer negativ")
# check if element collides with other element
try:
# print("Zeile: " + str(lnr))
# print(duration)
day_data = data["timetable_data"][day]
occupied_slots = []
for event in day_data.keys():
ev_duration = int(day_data[event][0])
for x in range(ev_duration):
occupied_slots.append(int(event)+x)
# print("Occupied: " + str(occupied_slots))
slots_to_check = []
for x in range(int(duration)):
slots_to_check.append(int(timeslot)+x)
# print("To Check: " + str(slots_to_check))
for slot in slots_to_check:
if slot in occupied_slots:
raise LayoutError(ls+"Kollision mit anderer Veranstaltung")
except KeyError:
pass
# not needed anymore
#try:
# # print("Zeile: " + str(lnr))
# # print(duration)
# day_data = data["timetable_data"][day]
# occupied_slots = []
# for event in day_data.keys():
# ev_duration = int(day_data[event][0])
# for x in range(ev_duration):
# occupied_slots.append(int(event)+x)
# # print("Occupied: " + str(occupied_slots))
# slots_to_check = []
# for x in range(int(duration)):
# slots_to_check.append(int(timeslot)+x)
# # print("To Check: " + str(slots_to_check))
# for slot in slots_to_check:
# if slot in occupied_slots:
# raise LayoutError(ls+"Kollision mit anderer Veranstaltung")
#except KeyError:
# pass
# everything is awesome
return new_line
@ -179,19 +184,8 @@ def generate_hello_string(id: str) -> str:
def get_name(id: str) -> str:
json_path = "data/timetables/" + id + ".json"
if not os.path.isfile(json_path):
return ""
with open(json_path, 'r') as j:
json_file_content = json.loads(j.read())
if json_file_content == {}:
return ""
try:
return json_file_content["name"]
except KeyError:
return ""
def get_name(id: int) -> str:
return ddb.get_name_of(id)
# randomly chooses a slogan image