Implemented SQL database
tablemaker not finished yet
This commit is contained in:
100
data/classesdb.py
Normal file
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
BIN
data/data.db
Normal file
Binary file not shown.
25
data/displaynamedb.py
Normal file
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
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"}
|
54
formmaker.py
54
formmaker.py
@ -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
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:
|
||||
|
46
permutil.py
46
permutil.py
@ -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))
|
123
tablemaker.py
123
tablemaker.py
@ -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
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
|
||||
|
Reference in New Issue
Block a user