Skip to content
Snippets Groups Projects
Commit a13befd0 authored by Andreas Valder's avatar Andreas Valder
Browse files

Merge branch 'master' of git.fsmpi.rwth-aachen.de:videoagwebsite/videoagwebsite

parents 5494fc2e d04b45a2
No related branches found
No related tags found
No related merge requests found
...@@ -2,5 +2,11 @@ ...@@ -2,5 +2,11 @@
config.py config.py
__pycache__ __pycache__
*.sqlite *.sqlite
files
files/* files/*
static/500.html static/500.html
nginx.err.log
nginx.log
nginx.pid
nginx.conf
uwsgi.sock
...@@ -7,27 +7,31 @@ Hinweis: diese Variante startet eine lokale Testversion der Website, es sind nic ...@@ -7,27 +7,31 @@ Hinweis: diese Variante startet eine lokale Testversion der Website, es sind nic
1. Repo Clonen 1. Repo Clonen
2. Verzeichnis betreten 2. Verzeichnis betreten
3. (optional) config.py.example anpassen und als config.py neu speichern 3. (optional) config.py.example anpassen und als config.py neu speichern
(Achtung: per default werden keine Beispieldaten initialisiert und auch kein useraccount 4. Schauen, ob alle Dependencies erfüllt sind (siehe weiter unten)
SQLITE_INIT_DATA sollte also wenigstens beim ersten Durchlauf True sein)
4. Schauen ob alle Dependencies erfüllt sind (siehe weiter unten)
5. `./run.py` ausführen 5. `./run.py` ausführen
6. unter [http://localhost:5000](http://localhost:5000) ist die Website verfügbar 6. Unter [http://localhost:5000](http://localhost:5000) ist die Website verfügbar
7. Moderatorlogin mit user: `videoag` Passwort: `videoag` 7. Moderatorlogin mit user: `videoag` Passwort: `videoag`
Alternativ, insbesondere zum Testen der Zugriffsbeschränkungen: Siehe `nginx.example.conf`.
### Zum Mitmachen: ### Zum Mitmachen:
1. Repo zum User clonen, dafür den "Clone-Button auf der Website verwenden 1. Repo für den eigenen User forken, dafür den "Fork-Button" auf der Website verwenden
2. Weiter mit 'Zum Testen' 2. Sicherstellen, dass der Upstream richtig konfiguriert ist:
3. Änderungen machen [Link](https://help.github.com/articles/configuring-a-remote-for-a-fork/)
4. ins eigene Repo pushen Origin stellt hier euren User da, Upstream das Original der Gruppe videoagwebsite
5. Pull-Request an uns, dazu unter "Merge-Requests" einmal auf "New Merge Request" und das Private Repo auswählen. 3. Erstellt euch eine eigene Branch, diese könnt ihr nennen wie ihr wollt, entweder nach der Änderung oder eurem Namen (git branch username), danach switched ihr in diese Branch (git checkout username)
3. Die Initialisierung ist unter "Zum Testen" bereits erklärt worden
3. Änderungen machen, committen, upstream mergen (git fetch upstream; git merge upstream/master)
4. Ins eigene Repo pushen (git push)
5. Pull-Request an uns, dazu unter "Merge-Requests" einmal auf "New Merge Request" und das Private Repo auswählen; oder ihr geht auf euer privates repo, da taucht dann eine Benachrichtigung über einen möglichen Merge-Request auf
6. Warten 6. Warten
7. Wir mergen die Änderungen 7. Wir mergen die Änderungen
### Abhängigkeiten ### Abhängigkeiten
Notwendig: Notwendig:
* python3 * python (Version 3)
* flask
* sqlite * sqlite
* python-flask
* python-requests (wird vom L2P und vom Kalenderimport verwendet, kann nicht optional eingebunden werden) * python-requests (wird vom L2P und vom Kalenderimport verwendet, kann nicht optional eingebunden werden)
Optional (wird für einzelne Features benötigt): Optional (wird für einzelne Features benötigt):
...@@ -37,4 +41,4 @@ Optional (wird für einzelne Features benötigt): ...@@ -37,4 +41,4 @@ Optional (wird für einzelne Features benötigt):
* python-mysql-connector (wenn MySQL als Datenbank verwendet werden soll) * python-mysql-connector (wenn MySQL als Datenbank verwendet werden soll)
Kurzform unter Ubuntu: Kurzform unter Ubuntu:
sudo apt install python3 python3-pip sqlite python3-requests python3-lxml python-ldap python3-icalendar; pip3 install --upgrade pip; pip3 install Flask python-mysql-connector sudo apt install python3 python3-flask sqlite python3-requests python3-lxml python3-ldap3 python3-icalendar python3-mysql.connector
# Defaults for development ,do not use in production! # Defaults for development ,do not use in production!
DEBUG = False DEBUG = False
SERVER_IP = 'localhost'
VIDEOPREFIX = 'https://videoag.fsmpi.rwth-aachen.de' VIDEOPREFIX = 'https://videoag.fsmpi.rwth-aachen.de'
VIDEOMOUNT = [{'mountpoint': 'files/protected/', 'prefix':'protected/'},{'mountpoint':'files/pub/','prefix':'pub/' }, {'mountpoint':'files/vpnonline/','prefix':'vpnonline/' }] VIDEOMOUNT = [{'mountpoint': 'files/protected/', 'prefix':'protected/'},{'mountpoint':'files/pub/','prefix':'pub/' }, {'mountpoint':'files/vpnonline/','prefix':'vpnonline/' }]
#SECRET_KEY = 'something random' #SECRET_KEY = 'something random'
...@@ -16,7 +17,7 @@ DB_DATA = 'db_example.sql' ...@@ -16,7 +17,7 @@ DB_DATA = 'db_example.sql'
DB_ENGINE = 'sqlite' DB_ENGINE = 'sqlite'
SQLITE_DB = 'db.sqlite' SQLITE_DB = 'db.sqlite'
SQLITE_INIT_SCHEMA = True SQLITE_INIT_SCHEMA = True
SQLITE_INIT_DATA = False SQLITE_INIT_DATA = True
#JOBS_API_KEY = 'something random' #JOBS_API_KEY = 'something random'
......
# Debug-only nginx config for this website
#
# Requires system-wide installation of nginx (for /etc/nginx/*)
#
# 1. Start nginx
# nginx -c nginx.conf.example -p .
# 2. Start uwsgi
# uwsgi -s uwsgi.sock --manage-script-name --mount /=server:app --plugin python --enable-threads
# 3. Visit http://localhost:5000/
pid nginx.pid;
error_log nginx.err.log;
events {
worker_connections 768;
}
http {
access_log nginx.log;
client_body_in_file_only off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server {
#listen 5000;
#listen [::]:5000;
listen localhost:5000;
error_page 502 /static/500.html;
location /static/ {
root .;
}
location /files/ {
auth_request /auth;
# For use with sshfs (recommended)
#alias /mnt/videoag/srv/videoag/released/;
# For use without sshfs
proxy_pass https://videoag.fsmpi.rwth-aachen.de/;
proxy_set_header Host "videoag.fsmpi.rwth-aachen.de";
}
location / {
include /etc/nginx/uwsgi_params;
uwsgi_param REQUEST_URI $uri;
uwsgi_param HTTP_X_ORIGINAL_URI $request_uri;
uwsgi_param HTTP_X_REAL_IP $remote_addr;
uwsgi_pass unix:uwsgi.sock;
}
}
}
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
from server import * from server import *
if __name__ == '__main__': if __name__ == '__main__':
app.run(threaded=True) app.run(threaded=True, host=config['SERVER_IP'])
...@@ -71,7 +71,10 @@ def mod_required(func): ...@@ -71,7 +71,10 @@ def mod_required(func):
return func(*args, **kwargs) return func(*args, **kwargs)
return decorator return decorator
csrf_endpoints = []
def csrf_protect(func): def csrf_protect(func):
csrf_endpoints.append(func.__name__)
@wraps(func) @wraps(func)
def decorator(*args, **kwargs): def decorator(*args, **kwargs):
if '_csrf_token' in request.values: if '_csrf_token' in request.values:
...@@ -79,13 +82,19 @@ def csrf_protect(func): ...@@ -79,13 +82,19 @@ def csrf_protect(func):
elif request.get_json() and ('_csrf_token' in request.get_json()): elif request.get_json() and ('_csrf_token' in request.get_json()):
token = request.get_json()['_csrf_token'] token = request.get_json()['_csrf_token']
else: else:
token = none token = None
if not ('_csrf_token' in session) or (session['_csrf_token'] != token ) or not token: if not ('_csrf_token' in session) or (session['_csrf_token'] != token ) or not token:
return 'csrf test failed', 403 return 'csrf test failed', 403
else: else:
return func(*args, **kwargs) return func(*args, **kwargs)
return decorator return decorator
@app.url_defaults
def csrf_inject(endpoint, values):
if endpoint not in csrf_endpoints or not session['_csrf_token']:
return
values['_csrf_token'] = session['_csrf_token']
def evalperm(perms): def evalperm(perms):
cperms = [] cperms = []
lperms = [] lperms = []
...@@ -107,6 +116,8 @@ def evalperm(perms): ...@@ -107,6 +116,8 @@ def evalperm(perms):
@app.template_filter() @app.template_filter()
def checkperm(perms, username=None, password=None): def checkperm(perms, username=None, password=None):
if ismod():
return True
perms = evalperm(perms) perms = evalperm(perms)
for perm in perms: for perm in perms:
if perm['type'] == 'public': if perm['type'] == 'public':
...@@ -492,7 +503,7 @@ def auth(): # For use with nginx auth_request ...@@ -492,7 +503,7 @@ def auth(): # For use with nginx auth_request
return 'Internal Server Error', 500 return 'Internal Server Error', 500
url = request.headers['X-Original-Uri'].lstrip(config['VIDEOPREFIX']) url = request.headers['X-Original-Uri'].lstrip(config['VIDEOPREFIX'])
ip = request.headers.get('X-Real-IP', '') ip = request.headers.get('X-Real-IP', '')
if url.endswith('jpg'): if url.endswith('jpg') or ismod():
return "OK", 200 return "OK", 200
perms = query('''SELECT videos.path, videos.id AS vid, perm.* perms = query('''SELECT videos.path, videos.id AS vid, perm.*
FROM videos FROM videos
...@@ -500,10 +511,9 @@ def auth(): # For use with nginx auth_request ...@@ -500,10 +511,9 @@ def auth(): # For use with nginx auth_request
JOIN courses ON (lectures.course_id = courses.id) JOIN courses ON (lectures.course_id = courses.id)
LEFT JOIN perm ON (videos.id = perm.video_id OR lectures.id = perm.lecture_id OR courses.id = perm.course_id) LEFT JOIN perm ON (videos.id = perm.video_id OR lectures.id = perm.lecture_id OR courses.id = perm.course_id)
WHERE videos.path = ? WHERE videos.path = ?
AND (? OR (courses.visible AND lectures.visible AND videos.visible)) AND (courses.visible AND lectures.visible AND videos.visible)
ORDER BY perm.video_id DESC, perm.lecture_id DESC, perm.course_id DESC''', ORDER BY perm.video_id DESC, perm.lecture_id DESC, perm.course_id DESC''',
url, ismod()) url)
if not perms: if not perms:
return "Not allowed", 403 return "Not allowed", 403
auth = request.authorization auth = request.authorization
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
</div> </div>
<div class="row panel-body"> <div class="row panel-body">
<div class="col-xs-12"> <div class="col-xs-12">
Es ist ein Fehler aufgetreten. Es ist ein interner Fehler aufgetreten.
Eventuell tritt dieser nur vorübergehend auf, versuche es doch einfach in ein paar Minuten noch einmal.
Sollte das Problem länger bestehen, schreib uns bitte eine Mail an <a href="mailto:video@fsmpi.rwth-aachen.de">video@fsmpi.rwth-aachen.de</a>.
Wir werden uns dann so schnellst möglich darum kümmern.
</div> </div>
</div> </div>
</div> </div>
......
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
{ {
html:true, html:true,
title:'Login für Moderatoren', title:'Login für Moderatoren',
content:'<form method="post" action="{{url_for('login', ref=request.url)}}"><input autofocus placeholder="User" name="user" type="text"><br><input placeholder="Password" name="password" type="password"><br><input type="submit" value="Login"></form>' content:'<form method="post" action="{{url_for('login', ref=request.values.get('ref', request.url))}}"><input autofocus placeholder="User" name="user" type="text"><br><input placeholder="Password" name="password" type="password"><br><input type="submit" value="Login"></form>'
} }
) )
</script> </script>
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
</div> </div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title">Videos{% if ismod() %} <a class="btn btn-default" style="margin-right: 5px;" href="{{ url_for('create', table='lectures', time=datetime.now(), title='Noch kein Titel', visible='0', course_id=course.id, ref=request.url, _csrf_token=session['_csrf_token']) }}">Neuer Termin</a><a class="btn btn-default" style="margin-right: 5px;" href="{{url_for('import_from', id=course['id'])}}">Campus Import</a>{% endif %} <a class="fa fa-rss-square pull-right" aria-hidden="true" href="{{url_for('feed', handle=course.handle)}}" style="text-decoration: none"></a> </h1> <h1 class="panel-title">Videos{% if ismod() %} <a class="btn btn-default" style="margin-right: 5px;" href="{{ url_for('create', table='lectures', time=datetime.now(), title='Noch kein Titel', visible='0', course_id=course.id, ref=request.url) }}">Neuer Termin</a><a class="btn btn-default" style="margin-right: 5px;" href="{{url_for('import_from', id=course['id'])}}">Campus Import</a>{% endif %} <a class="fa fa-rss-square pull-right" aria-hidden="true" href="{{url_for('feed', handle=course.handle)}}" style="text-decoration: none"></a> </h1>
</div> </div>
<ul class="list-group lectureslist"> <ul class="list-group lectureslist">
{% for l in lectures %} {% for l in lectures %}
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
</li> </li>
{% if ismod() %} {% if ismod() %}
<li> <li>
<a class="btn btn-default" href="{{ url_for('create', table='courses', handle='new'+(randint(0,1000)|string), title='Neue Veranstaltung', responsible=session.user.givenName, ref=request.url, _csrf_token=session['_csrf_token']) }}">Neue Veranstaltung</a> {% set newhandle = 'new'+(randint(0,1000)|string) %}
<a class="btn btn-default" href="{{ url_for('create', table='courses', handle=newhandle, title='Neue Veranstaltung', responsible=session.user.givenName, ref=url_for('course', handle=newhandle)) }}">Neue Veranstaltung</a>
</li> </li>
{% endif %} {% endif %}
<li class="dropdown" style="padding-right: 0px"> <li class="dropdown" style="padding-right: 0px">
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
<div class="col-xs-12"> <div class="col-xs-12">
<ul class="list-inline pull-right"> <ul class="list-inline pull-right">
<li style="padding-right: 0px;"> <li style="padding-right: 0px;">
<a class="btn btn-default" href="{{ url_for('create', table='announcements', text='Neue Ankündigung', time_publish=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0), time_expire=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)+timedelta(days=7), ref=request.url, _csrf_token=session['_csrf_token']) }}">Neue Ankündigung</a> <a class="btn btn-default" href="{{ url_for('create', table='announcements', text='Neue Ankündigung', time_publish=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0), time_expire=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)+timedelta(days=7), ref=request.url) }}">Neue Ankündigung</a>
</li> </li>
</ul> </ul>
</div> </div>
......
{% macro preview(lecture) %} {% macro preview(lecture) %}
<li class="list-group-item"> <li class="list-group-item">
<a class="hidden-xs" href="{{url_for('lecture', id=lecture['id'])}}" title="{{ lecture.course.title }}" style="color: #000"> <a href="{{url_for('lecture', id=lecture['id'])}}" title="{{ lecture.course.title }}" style="color: #000">
<div class="hidden-xs">
<div class="row"> <div class="row">
<img class="col-xs-4" style="max-height: 100px; width: auto;" src="{{ config.VIDEOPREFIX }}/{{ lecture['titlefile'] }}" alt="Vorschaubild" onerror="this.src='{{url_for('static',filename='no-thumbnail.png')}}'; this.onerror=''; "> <img class="col-xs-4" style="max-height: 100px; width: auto;" src="{{ config.VIDEOPREFIX }}/{{ lecture['titlefile'] }}" alt="Vorschaubild" onerror="this.src='{{url_for('static',filename='no-thumbnail.png')}}'; this.onerror=''; ">
<div class="col-xs-4"> <div class="col-xs-4">
...@@ -8,7 +9,7 @@ ...@@ -8,7 +9,7 @@
<span>{% if ismod() %}ID: {{lecture.id}}{% endif %}</span><br> <span>{% if ismod() %}ID: {{lecture.id}}{% endif %}</span><br>
<span>{{ lecture['time'] }}</span> <span>{{ lecture['time'] }}</span>
{% if lecture['speaker'] %} {% if lecture['speaker'] %}
<div class="small">Gehalten von {{ lecture['speaker'] }} </div> <div class="small">Gehalten von {{ lecture['speaker']|safe }} </div>
{% endif %} {% endif %}
</div> </div>
<div class="col-xs-4"> <div class="col-xs-4">
...@@ -16,8 +17,8 @@ ...@@ -16,8 +17,8 @@
<p style="font-style: italic; color: #777;">{{ lecture['comment']|fixnl|safe }}</p> <p style="font-style: italic; color: #777;">{{ lecture['comment']|fixnl|safe }}</p>
</div> </div>
</div> </div>
</a> </div>
<a class="visible-xs" href="{{url_for('lecture', id=lecture['id'])}}" title="{{ lecture.course.title }}" style="color: #000"> <div class="visible-xs">
<ul class="list-unstyled"> <ul class="list-unstyled">
<li> <li>
<img style="width: 100%;" src="{{ config.VIDEOPREFIX }}/{{ lecture['titlefile'] }}" alt="Vorschaubild" onerror="this.src='{{url_for('static',filename='no-thumbnail.png')}}'; this.onerror=''; "> <img style="width: 100%;" src="{{ config.VIDEOPREFIX }}/{{ lecture['titlefile'] }}" alt="Vorschaubild" onerror="this.src='{{url_for('static',filename='no-thumbnail.png')}}'; this.onerror=''; ">
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
<p style="font-style: italic; color: #777;">{{ lecture['comment']|fixnl|safe }}</p> <p style="font-style: italic; color: #777;">{{ lecture['comment']|fixnl|safe }}</p>
</li> </li>
</ul> </ul>
</div>
</a> </a>
</li> </li>
...@@ -60,7 +62,7 @@ $('#videoplayer').css("width"); ...@@ -60,7 +62,7 @@ $('#videoplayer').css("width");
<div class="row"> <div class="row">
{% if show_semester %} {% if show_semester %}
<span class="col-xs-2 col-md-1"> <span class="col-xs-2 col-md-1">
{{ course.semester }} {{ course.semester|semester }}
</span> </span>
<span class="col-xs-10 col-md-6"> <span class="col-xs-10 col-md-6">
{% else %} {% else %}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment