diff --git a/db.py b/db.py new file mode 100644 index 0000000000000000000000000000000000000000..9cc7b5d273db4a589cc3eef117aa391be9733576 --- /dev/null +++ b/db.py @@ -0,0 +1,102 @@ +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 + +def query(operation, *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': + if 'db' not in g: + g.db = sqlite3.connect(config['SQLITE_DB']) + 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 [] + return request.db.fetchall() + +@app.teardown_request +def commit_db(*args): + if hasattr(request, 'db'): + request.db.close() + g.db.commit() + +def searchquery(text, columns, match, tables, suffix, *suffixparams): + params = [] + subexprs = [] + words = text.split(' ') + prio = len(words)+1 + for word in words: + if word == '' or word.isspace(): + continue + matchexpr = ' OR '.join(['%s LIKE ?'%column for column in match]) + subexprs.append('SELECT %s, %s AS _prio FROM %s WHERE %s'%(columns, str(prio), tables, matchexpr)) + params += ['%'+word+'%']*len(match) + prio -= 1 + if subexprs == []: + return [] + expr = 'SELECT *,SUM(_prio) AS _score FROM (%s) AS _tmp %s'%(' UNION '.join(subexprs), suffix) + 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 + 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']): + groups = [e.cn.value for e in conn.entries] + conn.unbind() + 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 + 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) + e = conn.entries[0] + return {'uid': user, 'givenName': e.givenName.value, 'sn':e.sn.value} + else: + return notldap[user][2] + diff --git a/run.py b/run.py new file mode 100644 index 0000000000000000000000000000000000000000..c49f8a2c367ffda696e4ac77f5de08146c68b7eb --- /dev/null +++ b/run.py @@ -0,0 +1,4 @@ +from server import * + +if __name__ == '__main__': + app.run(threaded=True) diff --git a/server.py b/server.py index 8138ac56e92f9f45d055ce96e643d03cc991a591..5f8326cefd0701462f1487376f482f4a6c43dd2b 100755 --- a/server.py +++ b/server.py @@ -23,6 +23,7 @@ if __name__ == '__main__': config['DEBUG'] = True config.from_pyfile('config.py', silent=True) app.jinja_env.globals['videoprefix'] = config['VIDEOPREFIX'] +mod_endpoints = [] if config['DB_ENGINE'] == 'sqlite': created = not os.path.exists(config['SQLITE_DB']) @@ -128,6 +129,7 @@ def ismod(*args): app.jinja_env.globals['ismod'] = ismod def mod_required(func): + mod_endpoints.append(func.__name__) @wraps(func) def decorator(*args, **kwargs): if not ismod(): @@ -135,9 +137,20 @@ def mod_required(func): return redirect(url_for('login', ref=request.url)) else: return func(*args, **kwargs) + print(decorator.__name__) return decorator +app.jinja_env.globals['navbar'] = [] +def register_navbar(name, icon=None): + def wrapper(func): + endpoint = func.__name__ + app.jinja_env.globals['navbar'].append((endpoint, name, icon, + not endpoint in mod_endpoints)) + return func + return wrapper + @app.route('/') +@register_navbar('Home', icon='home') def index(): return render_template('index.html', latestvideos=query(''' SELECT lectures.*, max(videos.time_updated) AS lastvidtime, courses.short, courses.downloadable, courses.title AS coursetitle @@ -151,6 +164,7 @@ def index(): ''', ismod())) @app.route('/videos') +@register_navbar('Videos', icon='film') def videos(): courses = query('SELECT * FROM courses WHERE (? OR (visible AND listed))', ismod()) for course in courses: @@ -162,6 +176,7 @@ def videos(): return render_template('videos.html', courses=courses, groupedby=groupedby) @app.route('/faq') +@register_navbar('FAQ', icon='question-sign') def faq(): return render_template('faq.html') @@ -288,6 +303,8 @@ def auth(): # For use with nginx auth_request @app.route('/schedule') +@register_navbar('Drehplan', 'calendar') +@mod_required def schedule(): start = date.today() - timedelta(days=date.today().weekday()+7*20) days = [{'date': start, 'lectures': [], 'atonce':0 }] diff --git a/templates/base.html b/templates/base.html index 54bc736f0e18fc9523b94771c9ad48428736aa36..7a3abd5c36ebf59a57d4eef3f66786e202372e17 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,11 +1,3 @@ -{% set navigation_bar = [ -('/', 'index', 'Home', 'home', false), -('/videos', 'videos', 'Videos', 'film', false), -('/faq', 'faq', 'FAQ', 'question-sign', false), -('/schedule', 'schedule', 'Drehplan', 'calendar', true) -] -%} -{% set active_page = active_page|default('none') -%} - {% set page_border = page_border|default(1) -%} <!DOCTYPE html> @@ -54,11 +46,11 @@ <div class="row"> <div class="col-xs-12 col-sm-8"> <ul class="nav nav-pills"> - {% for href, id, caption, gly, modonly in navigation_bar %} - {% if (not modonly) or (modonly and ismod()) %} - <li{% if id == active_page %} class="active"{% endif %}> - <a href="{{ href|e }}">{% if gly != '' %}<span class="glyphicon glyphicon-{{ gly }}"></span> {% endif %}{{ caption }}</a> - </li> + {% 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> + </li> {% endif %} {% endfor %} <li class="navbar-right"> diff --git a/templates/faq.html b/templates/faq.html index 737585aead498893a878a5be8e17060290258425..29519ca87fa48d5038d48af279539c32a38ee4bd 100644 --- a/templates/faq.html +++ b/templates/faq.html @@ -1,6 +1,5 @@ {% from 'macros.html' import preview %} {% extends "base.html" %} -{% set active_page = "faq" %} {% block content %} <div class="alert alert-warning alert-dismissible" role="alert" id="kontakt"> Unter <a href="mailto:video@fsmpi.rwth-aachen.de">video@fsmpi.rwth-aachen.de</a> stehen wir für alle Fragen bereit. diff --git a/templates/index.html b/templates/index.html index 32134c5b18e6380c8dbd0ab5c05d3c9c04a382ce..6ad3b970f053ecfb6b719257d8f2cdf56c109eec 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,6 +1,5 @@ {% from 'macros.html' import preview %} {% extends "base.html" %} -{% set active_page = "index" %} {% set page_border = 0 %} {% block content %} <div class="row"> diff --git a/templates/videos.html b/templates/videos.html index 2c03083c7cc9ef96df3ba03483a3725babdfe288..5be235c5c7c368eec17d0c4d39f53285c1905218 100644 --- a/templates/videos.html +++ b/templates/videos.html @@ -1,6 +1,4 @@ {% from 'macros.html' import course_list_item %} -{% set active_page = 'videos' -%} - {% extends "base.html" %} {% block content %} <div class="row">