timetable.py 4.45 KB
Newer Older
Andreas Valder's avatar
Andreas Valder committed
1
from server import *
Andreas Valder's avatar
Andreas Valder committed
2
from datetime import time
Andreas Valder's avatar
Andreas Valder committed
3

4
@register_navbar('personalisierter Drehplan', icon='calendar', userendpoint=True, endpoint='timetable_user')
Andreas Valder's avatar
Andreas Valder committed
5
@register_navbar('Drehplan', icon='calendar')
6
7
@app.route('/internal/timetable')
@app.route('/internal/user/<int:user>/timetable', endpoint='timetable_user')
Andreas Valder's avatar
Andreas Valder committed
8
@mod_required
Andreas Valder's avatar
Andreas Valder committed
9
def timetable(user=None):
Andreas Valder's avatar
Andreas Valder committed
10
	if 'kw' not in request.args:
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
		if 'date' in request.args:
			thisweekmonday = datetime.now()
			thisweekmonday -= timedelta(days=thisweekmonday.weekday())

			try:
				datesweekmonday = datetime.strptime(request.args['date'], '%d-%m-%Y')
			except ValueError:
				datesweekmonday = None
			if not datesweekmonday:
				try:
					datesweekmonday = datetime.strptime(request.args['date'] + '-1', "%Y-W%W-%w")
				except ValueError:
					datesweekmonday = None

			if not datesweekmonday:
				kw = 0
				weekofyear = str(datetime.today().year) + "-W" + str(datetime.today().isocalendar()[1])
			else:
				datesweekmonday -= timedelta(days=datesweekmonday.weekday())
				kw = int((datesweekmonday.date() - thisweekmonday.date()).days/7)
		else:
			kw=0
Andreas Valder's avatar
Andreas Valder committed
33
34
	else:
		kw=int(request.args['kw'])
Andreas Valder's avatar
Andreas Valder committed
35
36
37
38
	try:
		start = date.today() - timedelta(days=date.today().weekday() -7*kw)
	except:
		start = date.today() - timedelta(days=date.today().weekday())
Andreas Valder's avatar
Andreas Valder committed
39
	weekofyear = str(start.year) + "-W" + str(start.isocalendar()[1])
Andreas Valder's avatar
Andreas Valder committed
40
41
42
43
44
45
46
	days = [{'date': start, 'lectures': [], 'atonce':0, 'index': 0 }]
	earlieststart=time(23,59)
	latestend=time(0,0)
	for i in range(1,7):
		days.append({'date': days[i-1]['date'] + timedelta(days=1), 'atonce':0, 'index': i, 'lectures':[] })
	for i in days:
		# date and times are burning in sqlite
47
		s = datetime.combine(i['date'],time(0,0))
Andreas Valder's avatar
Andreas Valder committed
48
		e = datetime.combine(i['date'],time(23,59))
49
50
		i['lectures'] = []
		for l in query ('''
51
					SELECT lectures.*, courses.short, "course" AS sep, courses.*
Andreas Valder's avatar
Andreas Valder committed
52
53
					FROM lectures 
					JOIN courses ON (lectures.course_id = courses.id) 
54
					WHERE time < ? AND time > ? AND NOT norecording AND NOT external
Andreas Valder's avatar
Andreas Valder committed
55
					ORDER BY time ASC''', i['date']+timedelta(weeks=2), i['date']-timedelta(weeks=2)):
56
			# we can not use the where clause of sql to match against the time, because sqlite and mysql use a different syntax -.-
Andreas Valder's avatar
Andreas Valder committed
57
			# we still use it to only get the lectures for a 3 week periode
Andreas Valder's avatar
Andreas Valder committed
58
59
			if not l['time']:
				l['time'] = datetime.fromtimestamp(0)
60
			if ((l['time'] < e) and (l['time'] > s)) or ((l['time'] + timedelta(minutes=l['duration']) < e) and (l['time'] + timedelta(minutes=l['duration'])> s)):
Andreas Valder's avatar
Andreas Valder committed
61
62
63
64
65
66
67
68
69
70
				# filter on responsible user if a user parameter was given
				l['responsible'] = query('''SELECT users.*
						FROM responsible
						JOIN users ON (responsible.user_id = users.id AND responsible.course_id = ?)
						ORDER BY users.realname ASC''', l['course_id'])
				if len(l['responsible']) == 0:
					l['responsible'] = [{"realname": "Niemand", "id": -1}]
				if not user or user in [ r['id'] for r in l['responsible'] ]:
					i['lectures'].append(l)

71
72
73
				oldtime = l['time']
				l['time'] = max(s,l['time'])
				l['duration'] = ( min(e,oldtime + timedelta(minutes=l['duration'])) - l['time'] ).total_seconds()/60
Andreas Valder's avatar
Andreas Valder committed
74
75
76
77
78
79
80
		# sweepline to find out how many lectures overlap
		maxcol=0;
		curcol=0;
		freecol=[];
		for l in i['lectures']:
			# who the hell inserts lectures with zero length?!?!?
			l['time_end'] = l['time']+timedelta(minutes=max(l['duration'],1))
Andreas Valder's avatar
Andreas Valder committed
81
		# create sweepline input array
82
		sweeplinetupels = [(l['time'],True,l) for l in i['lectures']]
Andreas Valder's avatar
Andreas Valder committed
83
84
85
86
87
88
89
90
91
92
93
94
		sweeplinetupels += [(l['time_end'],False,l) for l in i['lectures']]
		tmp = []
		for x in sweeplinetupels:
			unique = True
			for y in tmp:
				if x[0] == y[0] and x[1] == y[1] and x[2]['short'] == y[2]['short']:
					unique = False
			if unique:
				tmp.append(x)

		sweeplinetupels = sorted(tmp, key=lambda t:(t[0],t[1]))
		for l in sweeplinetupels:
Andreas Valder's avatar
Andreas Valder committed
95
96
97
98
99
100
			if l[1]:
				curcol += 1
				if curcol > maxcol:
					maxcol = curcol
				if len(freecol) == 0:
					freecol.append(maxcol)
Andreas Valder's avatar
Andreas Valder committed
101
				l[2]['timetable_col'] = freecol.pop()
Andreas Valder's avatar
Andreas Valder committed
102
103
104
105
				if earlieststart > l[0].time():
					earlieststart = l[0].time()
			else:
				curcol -= 1
Andreas Valder's avatar
Andreas Valder committed
106
				freecol.append(l[2]['timetable_col'])
Andreas Valder's avatar
Andreas Valder committed
107
108
109
110
111
112
113
114
115
				if latestend < l[0].time():
					latestend = l[0].time()
		i['maxcol'] = max(maxcol,1)
	times=[]
	s = min(earlieststart,time(8,0))
	e = max(latestend,time(19,0))
	for i in range(s.hour*4,min(int((60*e.hour/15)/4)*4+5,24*4)):
		t = i*15
		times.append(time(int(t/60),t%60))
Andreas Valder's avatar
Andreas Valder committed
116
	return render_template('timetable.html',days=days,times=times,kw=kw, weekofyear=weekofyear, user=query('SELECT * FROM users WHERE id = ?', user)[0] if user else None)