diff --git a/db_schema.sql b/db_schema.sql index bfcdd2cb7fac48530c4566617ad0644472a9cee9..71b31287516a33622eab6d97ed0ac78d83000b15 100644 --- a/db_schema.sql +++ b/db_schema.sql @@ -66,7 +66,8 @@ CREATE TABLE IF NOT EXISTS `courses_data` ( `coursechapters` INTEGER NOT NULL DEFAULT 0, `autopublish` INTEGER NOT NULL DEFAULT 0, `autovisible` INTEGER NOT NULL DEFAULT 0, - `profile` varchar(64) NOT NULL DEFAULT 'default' + `profile` varchar(64) NOT NULL DEFAULT 'default', + `login_info` text NOT NULL DEFAULT '' ); CREATE TABLE IF NOT EXISTS `filesizes` ( `path` varchar(255) NOT NULL PRIMARY KEY, diff --git a/edit.py b/edit.py index e0f8b43f70541c21a1a5a49fe2a57f3204a62a14..caee27000fe36dcfb527641c69e1a179f6614700 100644 --- a/edit.py +++ b/edit.py @@ -31,7 +31,9 @@ editable_tables = { #pylint: disable=invalid-name 'external': {'type': 'boolean', 'description': 'Soll die Veranstaltung nicht im Drehplan angezeigt werden?'}, 'coursechapters': {'type': 'boolean', 'description': 'Sollen auf der Kursseite die Kapitelmarker der Videos angezeigt werden?'}, 'autopublish': {'type': 'boolean', 'description': 'Sollen encodete Videos automatisch verschoben werden?'}, - 'autovisible': {'type': 'boolean', 'description': 'Sollen neue Videos automatisch sichtbar sein?'}}, + 'autovisible': {'type': 'boolean', 'description': 'Sollen neue Videos automatisch sichtbar sein?'}, + 'login_info': {'type': 'text', 'description': 'Zusätliche Informationen, die dem Nutzer angezeigt werden, wenn er sich anmelden muss.'} + }, 'creationtime_fields': ['created_by', 'time_created', 'time_updated']}, 'lectures': { 'table': 'lectures_data', @@ -48,7 +50,7 @@ editable_tables = { #pylint: disable=invalid-name 'jumplist': {'type': ''}, 'deleted': {'type': 'boolean'}, 'live': {'type': 'boolean', 'description': 'Ist ein Livestream geplant? Muss gesetzt sein damit der RTMP Stream zugeordnet wird.'}, - 'norecording': {'type': 'boolean', 'description:': 'Führt dazu, dass der Termin ausgegraut wird.'}, + 'norecording': {'type': 'boolean', 'description': 'Führt dazu, dass der Termin ausgegraut wird.'}, 'stream_settings': {'type': 'text'} }, 'creationtime_fields': ['course_id', 'time_created', 'time_updated']}, diff --git a/server.py b/server.py index a62ca2445c971fb06277703b3e8a1b252379f6f4..3485ffd92694c41d4246e177a3b5cac8666c3bef 100644 --- a/server.py +++ b/server.py @@ -321,11 +321,23 @@ def lecture(id, course=None, courseid=None): #pylint: disable=unused-argument,to if not courses: return render_endpoint('courses', '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()) - username = password = None + + password_set = False # Has the user set any username/password? + is_authorized = False # Is the user authenticated? + if request.authorization: - username = request.authorization.username - password = request.authorization.password - if not checkperm(perms, username=username, password=password): + password_set = True + if checkperm(perms, username=request.authorization.username, password=request.authorization.password): + is_authorized = True + elif 'auth_data' in session: + password_set = True + if checkperm_array(perms, session['auth_data']): + is_authorized = True + else: + if checkperm(perms): + is_authorized = True + + if not is_authorized: mode, text = permdescr(perms) if mode == 'rwth': flash(text+'. <a target="_blank" class="reloadonclose" href="'+url_for('start_rwthauth')+'">Hier authorisieren</a>.', category='player') @@ -350,7 +362,27 @@ def lecture(id, course=None, courseid=None): #pylint: disable=unused-argument,to else: flash(text+'.', category='player') return render_template('embed.html' if request.endpoint == 'embed' else 'lecture.html', - course=courses[0], lecture=lecture, videos=videos, chapters=chapters, seek=request.args.get('t')) + course=courses[0], lecture=lecture, videos=videos, chapters=chapters, seek=request.args.get('t'), + isAuthorized=is_authorized, permtypes=permtypes(perms), passwordSet=password_set) + +@app.route('/<course>/<int:id>/login', methods = ['POST']) +def sessionLogin(id, course): #pylint: disable=unused-argument,too-many-branches + if not 'auth_data' in session: + session['auth_data'] = {} + + if not "username" in request.form and not "password" in request.form: + return "Bad request", 400 + + lecture = query('SELECT * FROM lectures WHERE id = ? AND (? OR visible)', id, ismod())[0] + perms = query('SELECT perm.* FROM perm WHERE ((NOT perm.deleted) AND (perm.lecture_id = ? OR perm.course_id = ?))', + lecture['id'], lecture['course_id']) + + if checkperm(perms, username=request.form['username'], password=request.form['password']): + session['auth_data'][request.form['username']] = request.form['password'] + session.modified = True + + return redirect(url_for('lecture', course=course, id=id)) + @app.route('/search') @@ -470,12 +502,21 @@ def auth(): #pylint: disable=too-many-branches url_path) if not perms: return "Not found", 404 - auth = request.authorization - username = password = None - if auth: - username = auth.username - password = auth.password - if checkperm(perms, username=username, password=password): + + is_authorized = False + + if request.authorization: + if checkperm(perms, username=request.authorization.username, password=request.authorization.password): + is_authorized = True + elif 'auth_data' in session: + password_set = True + if checkperm_array(perms, session['auth_data']): + is_authorized = True + else: + if checkperm(perms): + is_authorized = True + + if is_authorized: try: if not url_path.startswith('pub/hls/'): modify('INSERT INTO log (id, `time`, `date`, video, source) VALUES (?, ?, ?, ?, 1)', diff --git a/template_helper.py b/template_helper.py index 663fead5f4de58fd8667114082c31ed87e1bef9d..0ec2aa9f69cb7aa6faf8d7d1be3263d5ef68e8d7 100644 --- a/template_helper.py +++ b/template_helper.py @@ -109,6 +109,25 @@ def checkperm(perms, username=None, password=None): #pylint: disable=too-many-br return True return False +def checkperm_array(perms, auth_data): + for username, password in auth_data.items(): + if checkperm(perms, username, password): + return True + + # Authentication can also be performed without username/password + if checkperm(perms): + return True + + return False + +def permtypes(perms): #pylint: disable=too-many-branches,too-many-return-statements + perms = evalperm(perms) + perm_set = set() + for perm in perms: + perm_set.add(perm['type']) + + return list(perm_set) + @app.template_filter() def permdescr(perms): #pylint: disable=too-many-branches,too-many-return-statements perms = evalperm(perms) diff --git a/templates/course.html b/templates/course.html index 2c1747418573e37f27e1e309da0cf14b73e9eb30..b1602bf0c5a5b5f8aa326a8dfc1044f34b8b9406 100644 --- a/templates/course.html +++ b/templates/course.html @@ -57,6 +57,7 @@ </select> </td></tr> <tr><td>Interne Bemerkungen:</td><td>{{ moderator_editor(['courses',course.id,'internal'], course.internal) }}</td></tr> + <tr><td>Login-Informationen:</td><td>{{ moderator_editor(['courses',course.id,'login_info'], course.login_info) }}</td></tr> </tbody> </table> </div> diff --git a/templates/lecture.html b/templates/lecture.html index cf38a3cface94f5f36884febcd7dbe8e92d757fb..981dbc3eea27ecde69d4ebe39ae374f01ff1aea3 100644 --- a/templates/lecture.html +++ b/templates/lecture.html @@ -1,4 +1,5 @@ {% from 'macros.html' import player %} +{% from 'macros.html' import authorize_helper %} {% from 'macros.html' import video_download_btn %} {% from 'macros.html' import video_embed_btn %} {% from 'macros.html' import vtttime %} @@ -20,7 +21,7 @@ {% block content %} <div class="panel panel-default"> <div class="panel-heading"> - <span class="panel-title"><strong><a href="{{url_for('course', handle=course.handle)}}#lecture-{{lecture.id}}">{{ course.title }}</a></strong>: {{ lecture.title}} ({{ lecture.time.date().strftime("%a, %d.%m.%Y")}})</span> + <span class="panel-title"><strong><a href="{{url_for('course', handle=course.handle)}}#lecture-{{lecture.id}}">{{ course.title }}</a></strong>: {{ lecture.title }} ({{ lecture.time.date().strftime("%a, %d.%m.%Y")}})</span> </div> <div class="panel-body"> <div class="row" style="padding: 0px;"> @@ -29,9 +30,13 @@ </div> </div> <div class="row"> + {% if isAuthorized %} <div class="col-xs-12" style="padding: 0px"> {{ player(lecture, videos, get_flashed_messages(category_filter=['player']), seek=seek) }} </div> + {% else %} + {{ authorize_helper(course.login_info, permtypes, passwordSet, lecture, course) }} + {% endif %} <div class="col-xs-12" style="padding-top: 15px;"> <button class="btn btn-default" id="hintnewchapter">{% if ismod() %}Neues Kapitel{% else %}Kapitelmarker vorschlagen{% endif %}</button> diff --git a/templates/macros.html b/templates/macros.html index fc101573a984ee6f76d66cbc72485eec7adf2627..8e2e7457774284d3f45adf7eb2cddc1a15fb10d0 100644 --- a/templates/macros.html +++ b/templates/macros.html @@ -161,6 +161,63 @@ $(function() { </script> {% endmacro %} +{% macro authorize_helper(login_info, permtypes, passwordSet, lecture, course) %} +<div class="col-xs-12" style="padding: 10px; background-color: black; color:white;"> + <h3 class="text-center mb2">Anmeldung erforderlich</h3> + {% if login_info %} + <p class="text-center">{{ login_info | safe }}</p> + {% endif %} + <div style="padding-bottom: 20px" class="container-fluid"> + <div class="row"> + {% if 'password' in permtypes %} + <div class="col-sm-4"> + <h4 class="text-center"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span> Benutzername/Passwort</h4> + {% if passwordSet %} + <p class="alert alert-warning">Das aktuell verwendete Passwort ist nicht gültig.</p> + {% endif %} + <form method="POST" action="{{url_for('sessionLogin', course=course.handle, id=lecture.id)}}"> + <div class="form-group"> + <label for="exampleInputEmail1">Benutzername</label> + <input type="text" class="form-control" id="username" name="username" placeholder=""> + </div> + <div class="form-group"> + <label for="exampleInputPassword1">Passwort</label> + <input type="password" class="form-control" id="password" name="password" placeholder=""> + </div> + <button type="submit" class="btn btn-default">Anmelden</button> + </form> + </div> + {% endif %} + {% if 'rwth' in permtypes %} + <div class="col-sm-4"> + <h4 class="text-center"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> RWTH</h4> + <p>Für RWTH-Angehörige und aus dem RWTH-Netz verfügbar</p> + <a href="{{ url_for('start_rwthauth') }}" class="btn btn-default">Anmelden</a> + </div> + {% endif %} + {% if 'l2p' in permtypes or 'moodle' in permtypes %} + <div class="col-sm-4"> + <h4 class="text-center"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> L2P/Moodle</h4> + <p>Für Teilnehmer der Veranstaltung verfügbar</p> + {% if 'l2p' in permtypes and not 'moodle' in permtypes %} + <a href="{{ url_for('start_l2pauth') }}" class="btn btn-default">Anmelden</a> + {% endif %} + {% if 'moodle' in permtypes and not 'l2p' in permtypes %} + <a href="{{ url_for('start_moodleauth') }}" class="btn btn-default">Anmelden</a> + {% endif %} + {% if 'moodle' in permtypes and 'l2p' in permtypes %} + <a href="{{ url_for('start_moodlel2pauth') }}" class="btn btn-default">Anmelden</a> + {% endif %} + </div> + {% endif %} + </div> + {% if 'l2p' not in permtypes and 'moodle' not in permtypes and 'rwth' not in permtypes and 'password' not in permtypes %} + <p class="alert alert-info" style="margin-top: 2em;">Nur für Fachschaftler verfügbar.</p> + {% endif %} + </div> +</div> +{% endmacro %} + {% macro course_list_item(course,show_semester=False) %} <li class="list-group-item list-group-item-condensed {% if (not course.visible) or (not course.listed) %}list-group-item-danger{% endif %}"> <div class="row">