Commit aced3754 authored by Andreas Valder's avatar Andreas Valder Committed by Andreas Valder
Browse files

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

parents 9fa646eb 0f2a3cb3
from server import *
import sqlite3
import re
if config['DB_ENGINE'] == 'sqlite':
created = not os.path.exists(config['SQLITE_DB'])
db = sqlite3.connect(config['SQLITE_DB'])
cur = db.cursor()
if config['SQLITE_INIT_SCHEMA']:
cur.executescript(open(config['DB_SCHEMA']).read())
if config['SQLITE_INIT_DATA'] and created:
cur.executescript(open(config['DB_DATA']).read())
db.commit()
db.close()
# Row wrapper for sqlite
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
if type(row[idx]) == str:
d[col[0].split('.')[-1]] = row[idx].replace('\\n','\n').replace('\\r','\r')
else:
d[col[0].split('.')[-1]] = row[idx]
return d
# From sqlite3 module, but with error catching
def 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":"))
val = datetime(year, month, day, hours, minutes, seconds, 0)
except ValueError:
val = None
return val
sqlite3.register_converter('datetime', convert_timestamp)
sqlite3.register_converter('timestamp', convert_timestamp)
def query(operation, *params):
_params = []
for p in params:
if isinstance(p, datetime):
p = p.replace(microsecond=0)
_params.append(p)
params = _params
if config['DB_ENGINE'] == 'mysql':
import mysql.connector
if 'db' not in g or not g.db.is_connected():
g.db = mysql.connector.connect(user=config['MYSQL_USER'], password=config['MYSQL_PASSWD'], host=config['MYSQL_HOST'], database=config['MYSQL_DB'])
if not hasattr(request, 'db'):
request.db = g.db.cursor(dictionary=True)
request.db.execute(operation.replace('?', '%s'), params)
elif config['DB_ENGINE'] == 'sqlite':
import sqlite3
# From sqlite3 module, but with error catching
def 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":"))
val = datetime(year, month, day, hours, minutes, seconds, 0)
except ValueError:
val = None
return val
sqlite3.register_converter('datetime', convert_timestamp)
sqlite3.register_converter('timestamp', convert_timestamp)
if config['DB_ENGINE'] == 'sqlite':
created = not os.path.exists(config['SQLITE_DB'])
db = sqlite3.connect(config['SQLITE_DB'])
cur = db.cursor()
if config['SQLITE_INIT_SCHEMA']:
cur.executescript(open(config['DB_SCHEMA']).read())
if config['SQLITE_INIT_DATA'] and created:
cur.executescript(open(config['db_data']).read())
db.commit()
db.close()
def get_dbcursor():
if 'db' not in g:
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'):
request.db = g.db.cursor()
request.db.execute(operation, params)
else:
return []
try:
rows = request.db.fetchall()
except:
rows = []
if not rows and request.db.lastrowid != None:
return request.db.lastrowid
return rows
return request.db
def fix_query(operation, params):
params = [(p.replace(microsecond=0) if isinstance(p, datetime) else p) for p in params]
return operation, params
elif config['DB_ENGINE'] == 'mysql':
import mysql.connector
def get_dbcursor():
if 'db' not in g or not g.db.is_connected():
g.db = mysql.connector.connect(user=config['MYSQL_USER'], password=config['MYSQL_PASSWD'], host=config['MYSQL_HOST'], database=config['MYSQL_DB'])
if not hasattr(request, 'db'):
request.db = g.db.cursor()
return request.db
def fix_query(operation, params):
operation = operation.replace('?', '%s')
params = [(p.replace(microsecond=0) if isinstance(p, datetime) else p) for p in params]
return operation, params
def query(operation, *params, delim="sep"):
operation, params = fix_query(operation, params)
cur = get_dbcursor()
cur.execute(operation, params)
rows = cur.fetchall()
res = []
for row in rows:
res.append({})
ptr = res[-1]
for col, desc in zip(row, cur.description):
name = desc[0].split('.')[-1]
if name == delim:
ptr = res[-1][col] = {}
continue
if type(col) == str:
col = col.replace('\\n', '\n').replace('\\r', '\r')
ptr[name] = col
return res
def modify(operation, *params):
operation, params = fix_query(operation, params)
cur = get_dbcursor()
cur.execute(operation, params)
return cur.lastrowid
@app.teardown_request
def commit_db(*args):
......@@ -94,15 +106,11 @@ def searchquery(text, columns, match, tables, suffix, *suffixparams):
return query(expr, *params, *suffixparams)
LDAP_USERRE = re.compile(r'[^a-z0-9]')
notldap = {
'videoag':('videoag', ['users','videoag'], {'uid': 'videoag', 'givenName': 'Video', 'sn': 'Geier'}),
'gustav':('passwort', ['users'], {'uid': 'gustav', 'givenName': 'Gustav', 'sn': 'Geier'})
}
def ldapauth(user, password):
user = LDAP_USERRE.sub(r'', user.lower())
if 'LDAP_HOST' in config:
import ldap3
if 'LDAP_HOST' in config:
import ldap3
def ldapauth(user, password):
user = LDAP_USERRE.sub(r'', user.lower())
try:
conn = ldap3.Connection(config['LDAP_HOST'], 'uid=%s,ou=users,dc=fsmpi,dc=rwth-aachen,dc=de'%user, password, auto_bind=True)
if conn.search("ou=groups,dc=fsmpi,dc=rwth-aachen,dc=de", "(&(cn=*)(memberUid=%s))"%user, attributes=['cn']):
......@@ -111,14 +119,9 @@ def ldapauth(user, password):
return user, groups
except ldap3.core.exceptions.LDAPBindError:
pass
elif config.get('DEBUG') and user in notldap and password == notldap[user][0]:
return user, notldap[user][1]
return None, []
def ldapget(user):
user = LDAP_USERRE.sub(r'', user.lower())
if 'LDAP_HOST' in config:
import ldap3
def ldapget(user):
user = LDAP_USERRE.sub(r'', user.lower())
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)
......@@ -126,6 +129,19 @@ def ldapget(user):
return {}
e = conn.entries[0]
return {'uid': user, 'givenName': e.givenName.value, 'sn':e.sn.value}
else:
return notldap[user][2]
else:
notldap = {
'videoag':('videoag', ['users','videoag'], {'uid': 'videoag', 'givenName': 'Video', 'sn': 'Geier'}),
'gustav':('passwort', ['users'], {'uid': 'gustav', 'givenName': 'Gustav', 'sn': 'Geier'})
}
def ldapauth(user, password):
user = LDAP_USERRE.sub(r'', user.lower())
if config.get('DEBUG') and user in notldap and password == notldap[user][0]:
return user, notldap[user][1]
return None, []
def ldapget(user):
user = LDAP_USERRE.sub(r'', user.lower())
return notldap[user][2]
......@@ -20,25 +20,22 @@ def feed(handle=None):
course['atomid'] = gen_atomid('Video AG, courses['+str(course['id'])+']: '+course['handle'])
id = course['id']
entries = query('''
SELECT lectures.*, videos.file_size, videos.path, videos.id AS video_id, videos.hash,
videos.time_created AS video_created, videos.time_updated AS video_updated,
courses.title AS course_title, courses.handle AS course_handle, courses.semester, courses.organizer AS course_organizer, courses.short as course_short,
formats.description AS format_description, formats.prio
SELECT lectures.*, "video" AS sep, videos.*, formats.description AS format_description, formats.prio, "course" AS sep, courses.*
FROM lectures
JOIN courses ON (courses.id = lectures.course_id)
JOIN videos ON (lectures.id = videos.lecture_id)
JOIN formats ON (formats.id = videos.video_format)
WHERE ((? IS NULL AND courses.listed) OR course_id = ?) AND courses.visible AND lectures.visible AND videos.visible
ORDER BY video_created DESC, prio ASC
ORDER BY videos.time_created DESC, prio ASC
LIMIT 100''',
course['id'], course['id'])
updated = max(course['time_updated'], course['time_created'], key=fixdate)
for entry in entries:
entry['updated'] = max(entry['video_created'], entry['video_updated'], entry['time_created'], entry['time_updated'], key=fixdate)
if len(entry['hash']) != 32:
entry['updated'] = max(entry['video']['time_created'], entry['video']['time_updated'], entry['time_created'], entry['time_updated'], key=fixdate)
if len(entry['video']['hash']) != 32:
entry['atomid'] = gen_atomid('Video AG, videos['+str(entry['video_id'])+']')
else:
entry['atomid'] = 'urn:md5:'+(entry['hash'].upper())
entry['atomid'] = 'urn:md5:'+(entry['video']['hash'].upper())
updated = max(updated, entry['updated'], key=fixdate)
course['updated'] = updated
return Response(render_template('feed.atom', course=course, entries=entries), 200, {'Content-Type': 'application/atom+xml'})
......
......@@ -17,7 +17,7 @@ def import_from(source=None, id=None):
for i in campus:
if i.startswith('new'):
if campus[i]['url'] != '':
query('INSERT INTO import_campus (url, type, course_id, last_checked, changed) VALUES (?, ?, ?, ?, 1)',campus[i]['url'],campus[i]['type'],id,datetime.now())
modify('INSERT INTO import_campus (url, type, course_id, last_checked, changed) VALUES (?, ?, ?, ?, 1)',campus[i]['url'],campus[i]['type'],id,datetime.now())
else:
if campus[i]['url'] != '':
query('UPDATE import_campus SET url = ?, `type` = ? WHERE (course_id = ?) AND (id = ?)', campus[i]['url'],campus[i]['type'],id,int(i))
......
......@@ -34,7 +34,7 @@ if config['DEBUG']:
if not config.get('SECRET_KEY', None):
config['SECRET_KEY'] = os.urandom(24)
from db import query, searchquery, ldapauth, ldapget, convert_timestamp
from db import query, modify, searchquery, ldapauth, ldapget
mod_endpoints = []
......@@ -132,8 +132,8 @@ def fixnl(s):
def index():
start = date.today() - timedelta(days=1)
end = start + timedelta(days=7)
upcomming = query ('''
SELECT lectures.*,courses.short, courses.title AS course_title
upcomming = query('''
SELECT lectures.*, "course" AS sep, courses.*
FROM lectures
JOIN courses ON (lectures.course_id = courses.id)
WHERE (time > ?) AND (time < ?) and lectures.visible and courses.visible and courses.listed
......@@ -141,13 +141,13 @@ def index():
for i in upcomming:
i['date'] = i['time'].date()
latestvideos=query('''
SELECT lectures.*, max(videos.time_updated) AS lastvidtime, courses.short, courses.downloadable, courses.title AS coursetitle
SELECT lectures.*, "course" AS sep, courses.*
FROM lectures
LEFT JOIN videos ON (videos.lecture_id = lectures.id)
LEFT JOIN courses on (courses.id = lectures.course_id)
WHERE (? OR (courses.visible AND courses.listed AND lectures.visible AND videos.visible))
GROUP BY videos.lecture_id
ORDER BY lastvidtime DESC
ORDER BY MAX(videos.time_updated) DESC
LIMIT 6 ''',ismod())
featured = query('SELECT * FROM featured WHERE NOT deleted AND (? OR visible)', ismod())
return render_template('index.html', latestvideos=latestvideos, upcomming=upcomming, featured=featured)
......@@ -238,7 +238,7 @@ def login():
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)
modify('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')))
......@@ -262,7 +262,7 @@ def edit(prefix="", ignore=[]):
'chapters': ('chapters', 'id', ['time', 'text', 'visible', 'deleted']),
'announcements': ('announcements', 'id', ['text', 'internal', 'level', 'visible', 'deleted'])
}
query('BEGIN')
modify('BEGIN')
if request.is_json:
changes = request.get_json().items()
else:
......@@ -270,21 +270,19 @@ def edit(prefix="", ignore=[]):
for key, val in changes:
if key in ignore:
continue
print('edit:', key, val)
key = prefix+key
print (key,val)
table, id, column = key.split('.', 2)
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 = ?, time_updated = ? WHERE %s = ?'%(tabs[table][0], column, tabs[table][1]), val, datetime.now(), id)
query('COMMIT')
modify('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'])
modify('UPDATE %s SET %s = ?, time_updated = ? WHERE %s = ?'%(tabs[table][0], column, tabs[table][1]), val, datetime.now(), id)
modify('COMMIT')
return "OK", 200
@app.route('/newcourse', methods=['GET', 'POST'])
@mod_required
def new_course():
id = query('''
id = modify('''
INSERT INTO courses_data
(visible, title, short, handle, organizer, subject, created_by, time_created,
time_updated, semester, settings, description, internal, responsible, feed_url)
......@@ -299,7 +297,7 @@ def new_course():
@app.route('/newlecture/<courseid>', methods=['GET', 'POST'])
@mod_required
def new_lecture(courseid):
id = query('''
id = modify('''
INSERT INTO lectures_data
(course_id, visible, drehplan, title, comment, internal, speaker, place,
time, time_created, time_updated, jumplist, titlefile)
......@@ -347,7 +345,7 @@ def auth(): # For use with nginx auth_request
if not types[0] or allowed or ismod() or \
(auth and check_mod(*ldapauth(auth.username, auth.password))):
return 'OK', 200
query('INSERT INTO log VALUES (?, "", ?, "video", ?, ?)', ip, datetime.now(), videos[0]['id'], url)
modify('INSERT INTO log VALUES (?, "", ?, "video", ?, ?)', ip, datetime.now(), videos[0]['id'], url)
elif 'password' in types:
return Response("Login required", 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
return "Not allowed", 403
......@@ -378,7 +376,7 @@ def suggest_chapter(lectureid):
submitter = None
if not ismod():
submitter = request.environ['REMOTE_ADDR']
id = query('INSERT INTO chapters (lecture_id, time, text, time_created, time_updated, created_by, submitted_by) VALUES (?, ?, ?, ?, ?, ?, ?)',
id = modify('INSERT INTO chapters (lecture_id, time, text, time_created, time_updated, created_by, submitted_by) VALUES (?, ?, ?, ?, ?, ?, ?)',
lectureid, time, text, datetime.now(), datetime.now(), session.get('user', {'dbid':None})['dbid'], submitter)
if 'ref' in request.values:
return redirect(request.values['ref'])
......@@ -387,7 +385,7 @@ def suggest_chapter(lectureid):
@app.route('/newpsa', methods=['POST', 'GET'])
@mod_required
def new_announcement():
id = query('INSERT INTO announcements (text, internal, time_created, time_updated, created_by) VALUES ("Neue Ankündigung", "", ?, ?, ?)',
id = modify('INSERT INTO announcements (text, internal, time_created, time_updated, created_by) VALUES ("Neue Ankündigung", "", ?, ?, ?)',
datetime.now(), datetime.now(), session.get('user', {'dbid':None})['dbid'])
if 'ref' in request.values:
return redirect(request.values['ref'])
......@@ -396,7 +394,7 @@ def new_announcement():
@app.route('/newfeatured', methods=['POST', 'GET'])
@mod_required
def new_featured():
id = query('INSERT INTO featured (time_created, time_updated, created_by) VALUES (?, ?, ?)',
id = modify('INSERT INTO featured (time_created, time_updated, created_by) VALUES (?, ?, ?)',
datetime.now(), datetime.now(), session.get('user', {'dbid':None})['dbid'])
if 'ref' in request.values:
return redirect(request.values['ref'])
......
{% macro summary(entry) %}
{% if not course.handle %}
Veranstaltung: <a href="{{ url_for('course', handle=entry.course_handle) }}">{{entry.course_title}}</a><br>
{% if entry.course_organizer %}
Veranstalter: {{ entry.course_organizer }}<br>
Veranstaltung: <a href="{{ url_for('course', handle=entry.course.handle) }}">{{entry.course.title}}</a><br>
{% if entry.course.organizer %}
Veranstalter: {{ entry.course.organizer }}<br>
{% endif %}
{% endif %}
{% if entry.speaker %}
......@@ -42,10 +42,10 @@ Veranstalter: {{ course.organizer }}<br>
{% for entry in entries %}
<entry>
<title>{% if not course.handle %}{{ entry.course_short }} {% if entry.semester %}({{ entry.semester|semester }}){% endif %}, {% endif %}{{ entry.time|date }}: {{ entry.title }}</title>
{% if not course.handle and entry.course_organizer %}
<title>{% if not course.handle %}{{ entry.course.short }} {% if entry.course.semester %}({{ entry.course.semester|semester }}){% endif %}, {% endif %}{{ entry.time|date }}: {{ entry.title }}</title>
{% if not course.handle and entry.course.organizer %}
<author>
<name>{{ entry.course_organizer }}</name>
<name>{{ entry.course.organizer }}</name>
</author>
{% endif %}
{% if entry.speaker %}
......@@ -54,7 +54,7 @@ Veranstalter: {{ course.organizer }}<br>
</author>
{% endif %}
<link rel="alternate" href="{{ url_for('lecture', id=entry.id, _external=True) }}"/>
<link rel="enclosure" href="{{ url_for('files', filename=entry.path, _external=True)}}" length="{{ entry.file_size }}"/>
<link rel="enclosure" href="{{ url_for('files', filename=entry.video.path, _external=True)}}" length="{{ entry.video.file_size }}"/>
<id>{{ entry.atomid }}</id>
<updated>{{ entry.updated|rfc3339 }}</updated>
<summary type="html">{{ summary(entry)|e }}</summary>
......
......@@ -77,7 +77,7 @@
<strong>{{ g.grouper|date }}</strong>
{% for i in g.list %}
<li class="list-group-item list-group-item-condensed">
{{i.time|time}} {{i.place}} <a href="{{url_for('course', id=i.course_id)}}">{{i.course_title}}</a>: <a href="{{url_for('course', id=i.course_id)}}#lecture-{{i.id}}">{{i.title}}</a>
{{i.time|time}} {{i.place}} <a href="{{url_for('course', id=i.course_id)}}">{{i.course.title}}</a>: <a href="{{url_for('course', id=i.course_id)}}#lecture-{{i.id}}">{{i.title}}</a>
</li>
{% endfor %}
......
{% macro preview(lecture) %}
<li class="list-group-item">
<a class="hidden-xs" href="{{url_for('lecture', id=lecture['id'])}}" title="{{ lecture['coursetitle'] }}" style="color: #000">
<a class="hidden-xs" href="{{url_for('lecture', id=lecture['id'])}}" title="{{ lecture.course.title }}" style="color: #000">
<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=''; ">
<div class="col-xs-4">
<span><strong>{{ lecture['short'] }}</strong></span><br>
<span><strong>{{ lecture.course.short }}</strong></span><br>
<span>{{ lecture['time'] }}</span>
{% if lecture['speaker'] %}
<div class="small">Gehalten von {{ lecture['speaker'] }} </div>
......@@ -16,13 +16,13 @@
</div>
</div>
</a>
<a class="visible-xs" href="{{url_for('lecture', id=lecture['id'])}}" title="{{ lecture['coursetitle'] }}" style="color: #000">
<a class="visible-xs" href="{{url_for('lecture', id=lecture['id'])}}" title="{{ lecture.course.title }}" style="color: #000">
<ul class="list-unstyled">
<li>
<img style="width: 100%;" src="{{ config.VIDEOPREFIX }}/{{ lecture['titlefile'] }}" alt="Vorschaubild" onerror="this.src='{{url_for('static',filename='no-thumbnail.png')}}'; this.onerror=''; ">
</li>
<li>
<strong>{{ lecture['short'] }}</strong> {{ lecture['time'] }}
<strong>{{ lecture.course.short }}</strong> {{ lecture['time'] }}
</li>
{% if lecture['speaker'] %}
<li>
......
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