Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
W
website
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Deploy
Releases
Container registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Video AG Infrastruktur
website
Compare revisions
live_sources to master
Compare revisions
Changes are shown as if the
source
revision was being merged into the
target
revision.
Learn more about comparing revisions.
Source
videoaginfra/website
Select target project
No results found
master
Select Git revision
Branches
bootstrap4
intros
master
modules
postgres_integration
s3compatible
6 results
Swap
Target
romank/website
Select target project
jannik/website
vincent/website
dominic/website
romank/website
videoaginfra/website
5 results
live_sources
Select Git revision
Branches
bootstrap4
forbid-save-as
intros
live_sources
master
modules
moodle-integration
patch-double-tap-seek
patch_datum_anzeigen
patch_raum_anzeigen
upload-via-token
11 results
Show changes
Only incoming changes from source
Include changes to target since source was created
Compare
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
timetable.py
+106
-105
106 additions, 105 deletions
timetable.py
with
106 additions
and
105 deletions
timetable.py
View file @
d64b9f99
from
server
import
*
from
datetime
import
time
@register_navbar
(
'
personalisierter Drehplan
'
,
icon
=
'
calendar
'
,
userendpoint
=
True
,
endpoint
=
'
timetable_user
'
)
@register_navbar
(
'
Drehplan
'
,
icon
=
'
calendar
'
)
@app.route
(
'
/internal/timetable
'
)
@app.route
(
'
/internal/user/<int:user>/timetable
'
,
endpoint
=
'
timetable_user
'
)
@mod_required
def
timetable
(
user
=
None
):
if
'
kw
'
not
in
request
.
args
:
if
'
date
'
in
request
.
args
:
thisweekmonday
=
datetime
.
now
()
thisweekmonday
-=
timedelta
(
days
=
thisweekmonday
.
weekday
())
def
get_monday
(
day
):
return
day
-
timedelta
(
days
=
day
.
weekday
())
def
get_week_offset
(
value
):
if
value
is
None
:
return
0
day
=
None
for
pattern
in
[
'
%d-%m-%Y-1
'
,
'
%Y-W%W-%w
'
]:
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
"
)
day
=
datetime
.
strptime
(
value
+
'
-1
'
,
pattern
)
except
ValueError
:
datesweekmonday
=
None
pass
if
day
is
not
None
:
break
if
day
is
None
:
return
0
return
int
((
get_monday
(
day
)
-
get_monday
(
datetime
.
now
())).
days
/
7
)
if
not
datesweekmonday
:
kw
=
0
else
:
datesweekmonday
-=
timedelta
(
days
=
datesweekmonday
.
weekday
())
kw
=
int
((
datesweekmonday
.
date
()
-
thisweekmonday
.
date
()).
days
/
7
)
else
:
kw
=
0
else
:
kw
=
int
(
request
.
args
[
'
kw
'
])
try
:
start
=
date
.
today
()
-
timedelta
(
days
=
date
.
today
().
weekday
()
-
7
*
kw
)
except
:
start
=
date
.
today
()
-
timedelta
(
days
=
date
.
today
().
weekday
())
weekofyear
=
'
{}-W{:02d}
'
.
format
(
datetime
.
today
().
year
,
datetime
.
today
().
isocalendar
()[
1
])
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
s
=
datetime
.
combine
(
i
[
'
date
'
],
time
(
0
,
0
))
e
=
datetime
.
combine
(
i
[
'
date
'
],
time
(
23
,
59
))
i
[
'
lectures
'
]
=
[]
for
l
in
query
(
'''
SELECT lectures.*, courses.short,
"
course
"
AS sep, courses.*
def
query_lectures_on_day
(
start
,
end
):
# What we want to match:
# lecture.time <= end AND lecture.time+lecture.duration >= start
# But there is no SQL statement that does this and is compatible with both sqlite
# and mysql, so we approximate the "lecture.time+lecture.duration" part
rows
=
query
(
'''
SELECT lectures.*, courses.short,
\'
course
\'
AS sep, courses.*
FROM lectures
JOIN courses ON (lectures.course_id = courses.id)
WHERE time < ? AND time > ? AND NOT norecording AND NOT external
ORDER BY time ASC
'''
,
i
[
'
date
'
]
+
timedelta
(
weeks
=
2
),
i
[
'
date
'
]
-
timedelta
(
weeks
=
2
)):
# we can not use the where clause of sql to match against the time, because sqlite and mysql use a different syntax -.-
# we still use it to only get the lectures for a 3 week periode
if
not
l
[
'
time
'
]:
l
[
'
time
'
]
=
datetime
.
fromtimestamp
(
0
)
if
((
l
[
'
time
'
]
<
e
)
and
(
l
[
'
time
'
]
>
s
))
or
((
l
[
'
time
'
]
+
timedelta
(
minutes
=
l
[
'
duration
'
])
<
e
)
and
(
l
[
'
time
'
]
+
timedelta
(
minutes
=
l
[
'
duration
'
])
>
s
)):
# 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
)
WHERE time <= ? AND time > ?
ORDER BY time ASC
'''
,
end
,
start
-
timedelta
(
weeks
=
2
))
lectures
=
[]
for
lecture
in
rows
:
if
lecture
[
'
time
'
]
+
timedelta
(
minutes
=
lecture
[
'
duration
'
])
>=
start
:
lectures
.
append
(
lecture
)
return
lectures
oldtime
=
l
[
'
time
'
]
l
[
'
time
'
]
=
max
(
s
,
l
[
'
time
'
])
l
[
'
duration
'
]
=
(
min
(
e
,
oldtime
+
timedelta
(
minutes
=
l
[
'
duration
'
]))
-
l
[
'
time
'
]
).
total_seconds
()
/
60
# 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
))
# create sweepline input array
sweeplinetupels
=
[(
l
[
'
time
'
],
True
,
l
)
for
l
in
i
[
'
lectures
'
]]
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
)
'''
Use a sweepline algorithm to find overlapping lectures
sweeplinetupels
=
sorted
(
tmp
,
key
=
lambda
t
:(
t
[
0
],
t
[
1
]))
for
l
in
sweeplinetupels
:
if
l
[
1
]:
For each day the item
'
maxcol
'
will be the number of columns required to display
the overlapping lectures. For each lecture the item
'
timetable_col
'
will be the
index of the column the lecture is going to be rendered in.
'''
def
timetable_sweepline
(
days
):
earliest_start
=
time
(
23
,
59
)
latest_end
=
time
(
0
,
0
)
for
day
in
days
:
sweeplinetupels
=
[(
lecture
[
'
time
'
].
time
(),
True
,
lecture
)
for
lecture
in
day
[
'
lectures
'
]]
sweeplinetupels
+=
[(
lecture
[
'
time_end
'
].
time
(),
False
,
lecture
)
for
lecture
in
day
[
'
lectures
'
]]
maxcol
=
0
curcol
=
0
freecol
=
[]
sweeplinetupels
.
sort
(
key
=
lambda
row
:
row
[:
2
])
for
timestamp
,
is_start
,
lecture
in
sweeplinetupels
:
if
is_start
:
curcol
+=
1
if
curcol
>
maxcol
:
maxcol
=
curcol
if
len
(
freecol
)
==
0
:
freecol
.
append
(
maxcol
)
l
[
2
][
'
timetable_col
'
]
=
freecol
.
pop
()
if
earlieststart
>
l
[
0
].
time
():
earlieststart
=
l
[
0
].
time
()
maxcol
=
max
(
maxcol
,
curcol
)
if
freecol
:
lecture
[
'
timetable_col
'
]
=
freecol
.
pop
()
else
:
lecture
[
'
timetable_col
'
]
=
maxcol
earliest_start
=
min
(
earliest_start
,
timestamp
)
else
:
curcol
-=
1
freecol
.
append
(
l
[
2
][
'
timetable_col
'
])
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
))
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
)
freecol
.
append
(
lecture
[
'
timetable_col
'
])
latest_end
=
max
(
latest_end
,
timestamp
)
day
[
'
maxcol
'
]
=
max
(
maxcol
,
1
)
return
earliest_start
,
latest_end
@register_navbar
(
'
personalisierter Drehplan
'
,
icon
=
'
calendar
'
,
userendpoint
=
True
,
endpoint
=
'
timetable_user
'
)
@register_navbar
(
'
Drehplan
'
,
icon
=
'
calendar
'
)
@app.route
(
'
/internal/timetable
'
)
@app.route
(
'
/internal/user/<int:user>/timetable
'
,
endpoint
=
'
timetable_user
'
)
@mod_required
def
timetable
(
user
=
None
):
if
'
kw
'
in
request
.
args
:
week_offset
=
int
(
request
.
args
[
'
kw
'
])
else
:
week_offset
=
get_week_offset
(
request
.
args
.
get
(
'
date
'
,
None
))
start_day
=
date
.
today
()
-
timedelta
(
days
=
date
.
today
().
weekday
()
-
7
*
week_offset
)
days
=
[{
'
date
'
:
start_day
,
'
lectures
'
:
[],
'
atonce
'
:
0
,
'
index
'
:
0
}]
for
i
in
range
(
1
,
7
):
days
.
append
({
'
date
'
:
days
[
i
-
1
][
'
date
'
]
+
timedelta
(
days
=
1
),
'
atonce
'
:
0
,
'
index
'
:
i
,
'
lectures
'
:
[]})
for
day
in
days
:
start
=
datetime
.
combine
(
day
[
'
date
'
],
time
(
0
,
0
))
end
=
datetime
.
combine
(
day
[
'
date
'
],
time
(
23
,
59
))
day
[
'
lectures
'
]
=
[]
for
lecture
in
query_lectures_on_day
(
start
,
end
):
lecture
[
'
time_end
'
]
=
lecture
[
'
time
'
]
+
timedelta
(
minutes
=
lecture
[
'
duration
'
])
# "Crop" lecture's timespan to start/end of day
lecture
[
'
time
'
]
=
max
(
start
,
lecture
[
'
time
'
])
lecture
[
'
time_end
'
]
=
min
(
end
,
lecture
[
'
time_end
'
])
# Ensure length > 0
lecture
[
'
time_end
'
]
=
max
(
lecture
[
'
time_end
'
],
lecture
[
'
time
'
]
+
timedelta
(
minutes
=
1
))
lecture
[
'
duration
'
]
=
int
((
lecture
[
'
time_end
'
]
-
lecture
[
'
time
'
]).
total_seconds
()
/
60
)
# Filter on responsible user if a user parameter was given
lecture
[
'
responsible
'
]
=
query
(
'''
SELECT users.*
FROM responsible
JOIN users ON (responsible.user_id = users.id AND responsible.course_id = ?)
ORDER BY users.realname ASC
'''
,
lecture
[
'
course_id
'
])
if
len
(
lecture
[
'
responsible
'
])
==
0
:
lecture
[
'
responsible
'
]
=
[{
"
realname
"
:
"
Niemand
"
,
"
id
"
:
-
1
}]
if
not
user
or
user
in
[
r
[
'
id
'
]
for
r
in
lecture
[
'
responsible
'
]]:
day
[
'
lectures
'
].
append
(
lecture
)
earliest_start
,
latest_end
=
timetable_sweepline
(
days
)
start
=
min
(
earliest_start
,
time
(
8
,
0
))
end
=
max
(
latest_end
,
time
(
19
,
0
))
blocks
=
[]
for
i
in
range
(
start
.
hour
*
4
,
min
(
int
((
60
*
end
.
hour
/
15
)
/
4
)
*
4
+
5
,
24
*
4
)):
timestamp
=
i
*
15
blocks
.
append
(
time
(
int
(
timestamp
/
60
),
timestamp
%
60
))
weekofyear
=
'
{}-W{:02d}
'
.
format
(
datetime
.
today
().
year
,
datetime
.
today
().
isocalendar
()[
1
])
return
render_template
(
'
timetable.html
'
,
days
=
days
,
blocks
=
blocks
,
kw
=
week_offset
,
weekofyear
=
weekofyear
,
user
=
query
(
'
SELECT * FROM users WHERE id = ?
'
,
user
)[
0
]
if
user
else
None
)
This diff is collapsed.
Click to expand it.
Prev
1
…
7
8
9
10
11
Next