Commit a49329a9 authored by Andreas Valder's avatar Andreas Valder
Browse files

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

parents e36154b5 d5189334
from server import *
import sqlite3
import re
import datetime
if config['DB_ENGINE'] == 'sqlite':
created = not os.path.exists(config['SQLITE_DB'])
......@@ -23,6 +24,25 @@ def dict_factory(cursor, row):
d[col[0].split('.')[-1]] = row[idx]
return d
# From sqlite3 module, but with error catching
def sqlite_convert_timestamp(val):
try:
datepart, timepart = val.split(b" ")
year, month, day = map(int, datepart.split(b"-"))
timepart_full = timepart.split(b".")
hours, minutes, seconds = map(int, timepart_full[0].split(b":"))
if len(timepart_full) == 2:
microseconds = int('{:0<6.6}'.format(timepart_full[1].decode()))
else:
microseconds = 0
val = datetime.datetime(year, month, day, hours, minutes, seconds, microseconds)
except:
val = None
return val
sqlite3.register_converter('datetime', sqlite_convert_timestamp)
sqlite3.register_converter('timestamp', sqlite_convert_timestamp)
def query(operation, *params):
if config['DB_ENGINE'] == 'mysql':
import mysql.connector
......@@ -33,7 +53,7 @@ def query(operation, *params):
request.db.execute(operation.replace('?', '%s'), params)
elif config['DB_ENGINE'] == 'sqlite':
if 'db' not in g:
g.db = sqlite3.connect(config['SQLITE_DB'])
g.db = sqlite3.connect(config['SQLITE_DB'], detect_types=sqlite3.PARSE_DECLTYPES)
g.db.row_factory = dict_factory
g.db.isolation_level = None
if not hasattr(request, 'db'):
......@@ -99,6 +119,8 @@ def ldapget(user):
conn = ldap3.Connection('ldaps://rumo.fsmpi.rwth-aachen.de', auto_bind=True)
conn.search("ou=users,dc=fsmpi,dc=rwth-aachen,dc=de", "(uid=%s)"%user,
attributes=ldap3.ALL_ATTRIBUTES)
if not conn.entries:
return {}
e = conn.entries[0]
return {'uid': user, 'givenName': e.givenName.value, 'sn':e.sn.value}
else:
......
#!/bin/python
from flask import Flask, g, request, url_for, redirect, session, render_template, flash
from werkzeug.routing import Rule
from functools import wraps
from datetime import date, timedelta, datetime, time
import threading
import os
app = Flask(__name__)
def timer_func():
with app.test_request_context():
pass # do something
timer = threading.Timer(60*60, timer_func)
timer.start()
timer = threading.Timer(0, timer_func)
timer.daemon = True
timer.start()
config = app.config
config['DB_SCHEMA'] = 'db_schema.sql'
config['DB_DATA'] = 'db_example.sql'
......@@ -22,14 +34,12 @@ config.from_pyfile('config.py', silent=True)
from db import query, searchquery, ldapauth, ldapget
app.jinja_env.globals['videoprefix'] = config['VIDEOPREFIX']
mod_endpoints = []
@app.template_global()
def ismod(*args):
return ('user' in session)
app.jinja_env.globals['ismod'] = ismod
def mod_required(func):
mod_endpoints.append(func.__name__)
@wraps(func)
......@@ -50,6 +60,28 @@ def register_navbar(name, icon=None):
return func
return wrapper
def render_endpoint(endpoint, flashtext=None, **kargs):
if flashtext:
flash(flashtext)
# request.endpoint is used for navbar highlighting
request.url_rule = Rule(request.path, endpoint=endpoint)
return app.view_functions[endpoint](**kargs)
def handle_errors(endpoint, text, code, *errors, **epargs):
def wrapper(func):
@wraps(func)
def decorator(*args, **kwargs):
try:
return func(*args, **kwargs)
except errors:
return render_endpoint(endpoint, text, **epargs), code
return decorator
return wrapper
@app.errorhandler(404)
def handle_not_found(e):
return render_endpoint('index', 'Diese Seite existiert nicht!'), 404
@app.route('/')
@register_navbar('Home', icon='home')
def index():
......@@ -72,16 +104,18 @@ def course():
if course['semester'] == '':
course['semester'] = 'zeitlos'
groupedby = request.args.get('groupedby')
if groupedby not in ['title','semester','organizer']:
if groupedby not in ['title', 'semester', 'organizer']:
groupedby = 'semester'
return render_template('course.html', courses=courses, groupedby=groupedby)
@app.route('/course/<id>')
def course_id(id):
courses = query('SELECT * FROM courses WHERE ((handle = ?) or id = ?) AND (? OR visible)', id, id, ismod())
if not courses:
flash('Diese Veranstaltung existiert nicht!')
return app.view_functions['course'](), 404
@app.route('/course/<int:numid>')
@handle_errors('course', 'Diese Veranstaltung existiert nicht!', 404, IndexError)
def course_id(numid=None, id=None):
if numid:
courses = query('SELECT * FROM courses WHERE id = ? AND (? OR visible)', numid, ismod())
else:
courses = query('SELECT * FROM courses WHERE handle = ? AND (? OR visible)', id, ismod())
lectures = query('SELECT * FROM lectures WHERE course_id = ? AND (? OR visible)', courses[0]['id'], ismod())
videos = query('''
SELECT videos.*, (videos.downloadable AND courses.downloadable) as downloadable, formats.description AS format_description
......@@ -100,18 +134,15 @@ def faq():
return render_template('faq.html')
@app.route('/play/<int:id>')
@handle_errors('course', 'Diese Vorlesung existiert nicht!', 404, IndexError)
def play(id):
lectures = query('SELECT * FROM lectures WHERE id = ? AND (? OR visible)', id, ismod())
videos = query('SELECT * FROM videos WHERE lecture_id = ? AND (? OR visible)', id, ismod())
if not lectures:
flash('Diese Vorlesung existiert nicht!')
return app.view_functions['course'](), 404
if not videos:
flash('Zu dieser Vorlesung wurden noch keine Videos veröffentlicht!')
courses = query('SELECT * FROM courses WHERE id = ? AND (? OR (visible AND listed))', lectures[0]['course_id'], ismod())
if not courses:
flash('Diese Veranstaltung existiert nicht!')
return app.view_functions['course'](), 404
return render_endpoint('course', 'Diese Veranstaltung existiert nicht!'), 404
return render_template('play.html', course=courses[0], lecture=lectures[0], videos=videos)
@app.route('/search')
......@@ -132,10 +163,15 @@ def login():
if request.method == 'GET':
return render_template('login.html')
user, groups = ldapauth(request.form.get('user'), request.form.get('password'))
if user and 'users' in groups:
session['user'] = ldapget(user)
else:
if not user or not 'users' in groups:
flash('Login fehlgeschlagen!')
return render_template('login.html')
session['user'] = ldapget(user)
dbuser = query('SELECT * FROM users WHERE name = ?', user)
if not dbuser:
query('INSERT INTO users (name, realname, fsacc, level, calendar_key, rfc6238) VALUES (?, ?, ?, 1, "", "")', user, session['user']['givenName'], user)
dbuser = query('SELECT * FROM users WHERE name = ?', user)
session['user']['dbid'] = dbuser[0]['id']
return redirect(request.values.get('ref', url_for('index')))
@app.route('/logout', methods=['GET', 'POST'])
......@@ -165,8 +201,7 @@ def edit():
assert table in tabs
assert column in tabs[table][2]
query('INSERT INTO changelog ("table",id_value,id_key,field,value_new,value_old,"when",who,executed) VALUES (?,?,?,?,?,(SELECT %s FROM %s WHERE %s = ?),?,?,1)'%(column,tabs[table][0],tabs[table][1]),table,id,tabs[table][1],column,val,id,datetime.now(),session['user']['givenName'])
query('UPDATE %s SET %s = ? WHERE %s = ?'%(tabs[table][0], column,
tabs[table][1]), val, id)
query('UPDATE %s SET %s = ? WHERE %s = ?'%(tabs[table][0], column,tabs[table][1]), val, id)
query('COMMIT')
return "OK", 200
......@@ -224,10 +259,9 @@ def schedule():
curcol=0;
freecol=[];
for l in i['lectures']:
l['time_asdate'] = datetime.strptime(l['time'],'%Y-%m-%d %H:%M:%S')
# who the hell inserts lectures with zero length?!?!?
l['end_asdate'] = l['time_asdate']+timedelta(minutes=max(l['duration'],1))
for l in sorted([(l['time_asdate'],True,l) for l in i['lectures']] + [(l['end_asdate'],False,l) for l in i['lectures']],key=lambda t:(t[0],t[1])):
l['time_end'] = l['time']+timedelta(minutes=max(l['duration'],1))
for l in sorted([(l['time'],True,l) for l in i['lectures']] + [(l['time_end'],False,l) for l in i['lectures']],key=lambda t:(t[0],t[1])):
if l[1]:
curcol += 1
if curcol > maxcol:
......@@ -262,4 +296,5 @@ def stats():
@register_navbar('Changelog', 'book')
@mod_required
def log():
return render_template('log.html', changelog=query('SELECT *, ( "table" || "." || id_value || "." ||field) as path FROM changelog ORDER BY "when" DESC LIMIT 50'))
changelog = query('SELECT *, ( "table" || "." || id_value || "." ||field) as path FROM changelog LEFT JOIN users ON (changelog.who = users.id) ORDER BY "when" DESC LIMIT 50')
return render_template('log.html', changelog=changelog)
......@@ -49,7 +49,7 @@
{% for endpoint, caption, gly, visible in navbar %}
{% if visible or ismod() %}
<li{% if endpoint == request.endpoint %} class="active"{% endif %}>
<a href="{{ url_for(endpoint)|e }}">{% if gly != '' %}<span class="glyphicon glyphicon-{{ gly }}"></span> {% endif %}{{ caption }}</a>
<a href="{{ url_for(endpoint) }}">{% if gly != '' %}<span class="glyphicon glyphicon-{{ gly }}"></span> {% endif %}{{ caption }}</a>
</li>
{% endif %}
{% endfor %}
......@@ -63,12 +63,12 @@
{
html:true,
title:'Login für Moderatoren',
content:'<form method="post" action="{{url_for('login')}}"><input placeholder="User" name="user" type="text"><br><input placeholder="Password" name="password" type="password"><br><input type="hidden" name="ref" value="{{ request.url|e }}"><input type="submit" value="Login"></form>'
content:'<form method="post" action="{{url_for('login', ref=request.url)}}"><input placeholder="User" name="user" type="text"><br><input placeholder="Password" name="password" type="password"><br><input type="submit" value="Login"></form>'
}
)
</script>
{% else %}
<a href="{{url_for('logout')}}?ref={{ request.url|urlencode }}">
<a href="{{url_for('logout', ref=request.url)}}">
{{ session.user.givenName }}
<span class="glyphicon glyphicon-log-out"></span>
</a>
......
......@@ -19,7 +19,11 @@
{% for i in changelog %}
<tr>
<td>{{i.when}}</td>
<td>{{i.who}}</td>
{% if i.realname %}
<td>{{i.realname}} ({{i.who}})</td>
{% else %}
<td>{{i.who}}</td>
{% endif %}
<td>{{i.path}}</td>
<td>"{{i.value_old}}"</td>
<td>"{{i.value_new}}"</td>
......
......@@ -2,7 +2,7 @@
<li class="list-group-item">
<a class="hidden-xs" href="{{url_for('play', id=lecture['id'])}}" title="{{ lecture['coursetitle'] }}">
<div class="row">
<img class="col-xs-4" src="{{ videoprefix }}/{{ lecture['titlefile'] }}" alt="Vorschaubild">
<img class="col-xs-4" src="{{ config.VIDEOPREFIX }}/{{ lecture['titlefile'] }}" alt="Vorschaubild">
<div class="col-xs-4">
<span style="color: #000;"><strong>{{ lecture['short'] }}</strong></span><br>
<span style="color: #000;">{{ lecture['time'] }}</span>
......@@ -18,7 +18,7 @@
</a>
<a class="visible-xs" href="{{url_for('play', id=lecture['id'])}}" title="{{ lecture['coursetitle'] }}">
<div class="row">
<img class="col-xs-12" src="{{ videoprefix }}/{{ lecture['titlefile'] }}" alt="Vorschaubild">
<img class="col-xs-12" src="{{ config.VIDEOPREFIX }}/{{ lecture['titlefile'] }}" alt="Vorschaubild">
</div>
<div class="row">
<div class="col-xs-12">
......@@ -53,7 +53,7 @@
<link rel="stylesheet" href="{{url_for('static', filename='mediaelementjs/mediaelementplayer.css')}}" />
<video class="mejs-player" width="640" height="360" style="width: 100%; height: 100%;">
{% for v in videos %}
<source type="video/mp4" src="{{ videoprefix }}/{{ v.path }}" />
<source type="video/mp4" src="{{ config.VIDEOPREFIX }}/{{ v.path }}" />
{% endfor %}
</video>
<script>
......@@ -67,7 +67,7 @@
{% macro course_list_item(course,show_semester=False) %}
<li class="list-group-item {% if (not course.visible) or (not course.listed) %}list-group-item-danger{% endif %}">
<div class="row">
<a href="{{url_for('course_id', id=course.handle)}}">
<a href="{{url_for('course_id', numid=course.id)}}">
{% if show_semester %}
<span class="col-xs-1">
{{ course.semester }}
......@@ -93,13 +93,13 @@
<button class="btn btn-primary dropdown-toggle {% if videos|length is equalto 0 %}disabled{% endif %}" type="button" data-toggle="dropdown">Download <span class="caret"></span></button>
<ul class="dropdown-menu">
{% for v in videos %}
{% if v.downloadable %} <li><a href="{{ videoprefix }}/{{v.path}}">{{ valuecheckbox(['videos',v.id,'visible'], v.visible) }} {{v.format_description}} ({{v.file_size|filesizeformat(true)}})</a></li>{% endif %}
{% if v.downloadable %} <li><a href="{{ config.VIDEOPREFIX }}/{{v.path}}">{{ valuecheckbox(['videos',v.id,'visible'], v.visible) }} {{v.format_description}} ({{v.file_size|filesizeformat(true)}})</a></li>{% endif %}
{% endfor %}
</ul>
<noscript>
<ul class="pull-right list-unstyled" style="margin-left:10px;">
{% for v in videos %}
<li><a href="{{ videoprefix }}/{{v.path}}">{{v.format_description}} ({{v.file_size|filesizeformat(true)}})</a></li>
<li><a href="{{ config.VIDEOPREFIX }}/{{v.path}}">{{v.format_description}} ({{v.file_size|filesizeformat(true)}})</a></li>
{% endfor %}
</ul>
</noscript>
......
......@@ -11,7 +11,7 @@
</div>
<div class="panel-body">
<p class="col-xs-12" style="padding: 0px;">
<span><a href="{{url_for('course_id', id=course.handle)}}" class="btn btn-default" >Zur Veranstaltungsseite</a><span>
<span><a href="{{url_for('course_id', numid=course.id)}}#lecture-{{lecture.id}}" class="btn btn-default" >Zur Veranstaltungsseite</a><span>
<span class="pull-right">
<span>{{ video_embed_btn(lecture.id) }}</span>
<span>{{ video_download_btn(videos) }}</span>
......
......@@ -21,15 +21,15 @@
{% if ((loop.index - 1) is divisibleby 4) %} <td rowspan="4" style="vertical-align: top;">{{ t.strftime("%H:%M") }}</td> {% endif %}
{% for d in days if (d.index < 5) or (d.lectures|length) > 0 %}
{% for i in range(1,d.maxcol+1) %}
{% for l in d.lectures|selectattr('schedule_col','equalto',i) if (((l.time_asdate.time() > t) and (l.time_asdate.time() < times[time_loop.index+1])) != (l.time_asdate.time() == t ) ) %}
{% for l in d.lectures|selectattr('schedule_col','equalto',i) if (((l.time.time() > t) and (l.time.time() < times[time_loop.index+1])) != (l.time.time() == t ) ) %}
<td rowspan="{{l.duration / 15}}" style="background: lightgrey;">
<p class="small">
<strong><a href="{{url_for('course_id', id=l['course_id'])}}#lecture-{{l.id}}">{{l.short}}</a></strong><br>
{{l.time_asdate.strftime("%H:%M")}} - {{l.end_asdate.strftime("%H:%M")}}<br>
<strong><a href="{{url_for('course_id', numid=l['course_id'])}}#lecture-{{l.id}}">{{l.short}}</a></strong><br>
{{l.time.strftime("%H:%M")}} - {{l.time_end.strftime("%H:%M")}}<br>
{{l.place}}</p>
</td>
{% else %}
{% for l in d.lectures|selectattr('schedule_col','equalto',i) if (l.time_asdate.time() < t) and (l.end_asdate.time() > t) %}
{% for l in d.lectures|selectattr('schedule_col','equalto',i) if (l.time.time() < t) and (l.time_end.time() > t) %}
{% else %}
<td></td>
{% endfor %}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment