diff --git a/db.py b/db.py index 2d6dddddc5f0611103ae5f4e7b0e4c62c3346209..bdbfb7b93ff1becb01b5e32d8f630d506ac3a8d6 100644 --- a/db.py +++ b/db.py @@ -103,7 +103,7 @@ def searchquery(text, columns, match, tables, suffix, *suffixparams): if subexprs == []: return [] expr = 'SELECT *,SUM(_prio) AS _score FROM (%s) AS _tmp %s'%(' UNION '.join(subexprs), suffix) - return query(expr, *params, *suffixparams) + return query(expr, *(list(params)+list(suffixparams))) LDAP_USERRE = re.compile(r'[^a-z0-9]') if 'LDAP_HOST' in config: diff --git a/l2pauth.py b/l2pauth.py index f1f1064e514dbd8d672c59f49129f445db92115a..6713debb739cd6c6802ca8e136d55b49822f13f6 100644 --- a/l2pauth.py +++ b/l2pauth.py @@ -43,6 +43,5 @@ def finish_oauth(): session['l2p_courses'] = [] for course in l2pget('viewAllCourseInfo', token['access_token'])['dataSet']: session['l2p_courses'].append(course['uniqueid']) - flash('Folgende Kurse wurden freigegeben: '+', '.join(session['l2p_courses'])) del session['oauthscope'] oauthget('token', refresh_token=token['refresh_token'], grant_type='invalidate') diff --git a/server.py b/server.py index 1b8e7acbe21409d7b13a46897392c428fcad5146..28e941557cc333d10bec0c8124542df846ab987e 100644 --- a/server.py +++ b/server.py @@ -31,7 +31,7 @@ def sched_func(delay, priority=0, firstdelay=None, args=[], kargs={}): def wrapper(func): def sched_wrapper(): with app.test_request_context(): - func(*args, *kargs) + func(*args, **kargs) scheduler.enter(delay, priority, sched_wrapper) scheduler.enter(firstdelay, priority, sched_wrapper) return func @@ -69,6 +69,72 @@ def mod_required(func): return func(*args, **kwargs) return decorator +def evalauth(auths): + cauths = [] + lauths = [] + vauths = [] + for auth in auths: + if auth['course_id']: + cauths.append(auth) + elif auth['lecture_id']: + lauths.append(auth) + elif auth['video_id']: + vauths.append(auth) + if vauths: + return vauths + elif lauths: + return lauths + elif cauths: + return cauths + return [{'auth_type': 'public'}] + +@app.template_filter() +def checkauth(auths, username=None, password=None): + auths = evalauth(auths) + for auth in auths: + if auth['auth_type'] == 'public': + return True + elif auth['auth_type'] == 'password': + if auth['auth_user'] == username and auth['auth_password'] == password: + return True + elif auth['auth_type'] == 'l2p': + if auth['auth_param'] in session.get('l2p_courses', []): + return True + elif auth['auth_type'] == 'rwth': + if session.get('rwthintern', False): + return True + return False + +@app.template_filter() +def authdescr(auths): + auths = evalauth(auths) + public = False + password = False + l2p_courses = [] + rwth_intern = False + for auth in auths: + if auth['auth_type'] == 'public': + public = True + elif auth['auth_type'] == 'password': + password = True + elif auth['auth_type'] == 'l2p': + l2p_courses.append(auth['auth_param']) + elif auth['auth_type'] == 'rwth': + rwth_intern = True + if public or not auths: + return 'public', 'Öffentlich verfügbar' + if rwth_intern: + if password: + return 'rwth', 'Nur für RWTH-Angehörige und Nutzer mit Passwort verfügbar' + return 'rwth', 'Nur für RWTH-Angehörige verfügbar' + if l2p_courses: + if password: + return 'l2p', 'Nur für Teilnehmer der Veranstaltung und Nutzer mit Passwort verfügbar' + return 'l2p', 'Nur für Teilnehmer der Veranstaltung verfügbar' + if password: + return 'password', 'Nur für Nutzer mit Passwort verfügbar' + return 'public', 'Öffentlich verfügbar' + app.jinja_env.globals['navbar'] = [] # iconlib can be 'bootstrap' # ( see: http://getbootstrap.com/components/#glyphicons ) @@ -233,12 +299,22 @@ def lecture(id): WHERE videos.lecture_id = ? AND (? OR videos.visible) ORDER BY formats.prio DESC ''', lecture['course_id'], lecture['id'], ismod()) + auths = query('SELECT auth.* FROM auth WHERE (auth.lecture_id = ? OR auth.course_id = ?)', + lecture['id'], lecture['course_id']) if not videos: flash('Zu dieser Vorlesung wurden noch keine Videos veröffentlicht!') - course = query('SELECT * FROM courses WHERE id = ? AND (? OR (visible AND listed))', lecture['course_id'], ismod()) + course = query('SELECT * FROM courses WHERE id = ? AND (? OR (visible AND listed))', lecture['course_id'], ismod())[0] if not course: return render_endpoint('course', 'Diese Veranstaltung existiert nicht!'), 404 chapters = query('SELECT * FROM chapters WHERE lecture_id = ? AND NOT deleted AND (? OR visible) ORDER BY time ASC', id, ismod()) + if not checkauth(auths): + mode, text = authdescr(auths) + if mode == 'rwth': + flash(text+'. <a target="_blank" href="'+url_for('start_rwthauth')+'">Hier authorisieren</a>.') + elif mode == 'l2p': + flash(text+'. <a target="_blank" href="'+url_for('start_l2pauth')+'">Hier authorisieren</a>.') + else: + flash(text+'.') return render_template('embed.html' if request.endpoint == 'embed' else 'lecture.html', course=course, lecture=lecture, videos=videos, chapters=chapters) @@ -365,7 +441,7 @@ def auth(): # For use with nginx auth_request ip = request.headers.get('X-Real-IP', '') if url.endswith('jpg'): return "OK", 200 - videos = query('''SELECT videos.path, videos.id, lectures.id AS lecture_id, courses.id AS course_id, auth.* + videos = query('''SELECT videos.path, videos.id, auth.* FROM videos JOIN lectures ON (videos.lecture_id = lectures.id) JOIN courses ON (lectures.course_id = courses.id) @@ -374,36 +450,23 @@ def auth(): # For use with nginx auth_request AND (? OR (courses.visible AND lectures.visible AND videos.visible)) ORDER BY auth.video_id DESC, auth.lecture_id DESC, auth.course_id DESC''', url, ismod()) + if not videos: return "Not allowed", 403 - allowed = False - types = [] auth = request.authorization - for video in videos: - if videos[0] and ((videos[0]['video_id'] and not video['video_id']) \ - or (videos[0]['lecture_id'] and not video['lecture_id'])): - break - types.append(video['auth_type']) - if video['auth_type'] == 'public': - allowed = True - break - elif video['auth_type'] == 'password': - if auth and video['auth_user'] == auth.username and video['auth_passwd'] == auth.password: - allowed = True - break - elif video['auth_type'] == 'l2p': - if video['auth_param'] in session.get('l2p_courses', []): - allowed = True - break - elif video['auth_type'] == 'rwth': - if session.get('rwthintern', False): - allowed = True - break - if not types[0] or allowed or ismod() or \ - (auth and check_mod(*ldapauth(auth.username, auth.password))): + username = password = None + if auth: + username = auth.username + password = auth.password + if checkauth(videos, username=username, password=password): return 'OK', 200 modify('INSERT INTO log VALUES (?, "", ?, "video", ?, ?)', ip, datetime.now(), videos[0]['id'], url) - elif 'password' in types: + password_auth = False + for video in videos: + if video['auth_type'] == 'password': + password_auth = True + break + if password_auth: return Response("Login required", 401, {'WWW-Authenticate': 'Basic realm="Login Required"'}) return "Not allowed", 403 diff --git a/templates/base.html b/templates/base.html index 0ecb0e4c1455c454da14f26b086eebf79d2dd143..d036b5d9435125c32153133958ecdad247c4a633 100644 --- a/templates/base.html +++ b/templates/base.html @@ -106,7 +106,7 @@ <div class="col-xs-12 col-md-offset-{{ page_border }} col-md-{{ 12-(2*page_border) }}"> {% endif %} {% for msg in get_flashed_messages() %} - <div class="hidden-print alert alert-danger" role="alert">{{ msg }}</div> + <div class="hidden-print alert alert-danger" role="alert">{{ msg|safe }}</div> {% endfor %} {% for msg in get_announcements(min_announcement_level) if (not request.cookies['alert-info-'+msg.id|string]) %} <div class="hidden-print alert alert-{{levels.get(msg.level, ('info', ''))[0]}}" role="alert"> diff --git a/templates/course.html b/templates/course.html index 25a5713dc567e1f0c28002b652dfbd1e4723a03a..dd83c7de5fb894a8d78b021dac7c1596c287ba96 100644 --- a/templates/course.html +++ b/templates/course.html @@ -20,7 +20,11 @@ <div class="col-xs-12"> <table class="table-top-aligned table-condensed"> <tbody> + {% if ismod() %} <tr><td>Semester:</td><td>{{ moderator_editor(['courses',course.id,'semester'], course.semester) }}</td></tr> + {% else %} + <tr><td>Semester:</td><td>{{ course.semester|semester(long=True) }}</td></tr> + {% endif %} <tr><td>Veranstalter:</td><td>{{ moderator_editor(['courses',course.id,'organizer'], course.organizer) }}</td></tr> <tr><td>Bemerkungen:</td><td>{{ moderator_editor(['courses',course.id,'description'], course.description) }}</td></tr> </tbody> diff --git a/templates/lecture.html b/templates/lecture.html index 84d07c6e05e3357309e87ff836d5607f1a4dcf42..76a45805df7b9a03e33484fc28fb6cc5deb45473 100644 --- a/templates/lecture.html +++ b/templates/lecture.html @@ -30,27 +30,29 @@ <div class="col-xs-12" style="padding: 0px"> {{ player(lecture, videos) }} </div> - <div class="col-xs-12" style="padding-top: 10px;"> - <p>Kapitel:</p> - <table class="table table-hover"> - <tr> - <th>Index</th> - <th>Start</th> - <th>Kapitel</th> - <th>Sichtbar</th> - <th></th> - </tr> - {% for c in chapters|sort(attribute='time') %} - <tr onclick="videojs('videoplayer').currentTime({{c['time']}})"> - <td>{{ loop.index }}</td> - <td>{{ vtttime(c['time']) }}</td> - <td>{{ moderator_editor(['chapters',c.id,'text'],c['text']) }}</td> - <td>{{ moderator_checkbox(['chapters',c.id,'visible'], c.visible) }}</td> - <td>{{ moderator_delete(['chapters',c.id,'deleted']) }}</td> - </tr> - {% endfor %} - </table> - </div> + {% if ismod() %} + <div class="col-xs-12" style="padding-top: 10px;"> + <p>Kapitel:</p> + <table class="table table-hover"> + <tr> + <th>Index</th> + <th>Start</th> + <th>Kapitel</th> + <th>Sichtbar</th> + <th></th> + </tr> + {% for c in chapters|sort(attribute='time') %} + <tr onclick="videojs('videoplayer').currentTime({{c['time']}})"> + <td>{{ loop.index }}</td> + <td>{{ vtttime(c['time']) }}</td> + <td>{{ moderator_editor(['chapters',c.id,'text'],c['text']) }}</td> + <td>{{ moderator_checkbox(['chapters',c.id,'visible'], c.visible) }}</td> + <td>{{ moderator_delete(['chapters',c.id,'deleted']) }}</td> + </tr> + {% endfor %} + </table> + </div> + {% endif %} </div> </div> </div>