diff --git a/config.py.example b/config.py.example
index 27254fd575acc9c1fa6df3b8cd010a416665f876..53d80f9c653466db9f9c7732449abac8a5647123 100644
--- a/config.py.example
+++ b/config.py.example
@@ -19,3 +19,4 @@ SQLITE_INIT_SCHEMA = True
 SQLITE_INIT_DATA = False
 
 #LDAP_HOST = 'ldaps://rumo.fsmpi.rwth-aachen.de'
+#ICAL_URL = 'https://user:password@mail.fsmpi.rwth-aachen.de/SOGo/....ics'
diff --git a/db_schema.sql b/db_schema.sql
index f5e1fbf63a42173719aaa78d6c9d1106dd73e580..b0c5c1fb89e7483d133aad71ebe40184dc3209a9 100644
--- a/db_schema.sql
+++ b/db_schema.sql
@@ -84,19 +84,19 @@ CREATE TABLE IF NOT EXISTS `lectures_data` (
   `visible` INTEGER NOT NULL DEFAULT '1',
   `timed_release` datetime DEFAULT NULL,
   `use_timed_release` INTEGER NOT NULL DEFAULT '0',
-  `drehplan` varchar(10) NOT NULL,
+  `drehplan` varchar(10) NOT NULL DEFAULT '',
   `deleted` INTEGER NOT NULL DEFAULT '0',
-  `title` text NOT NULL,
-  `comment` text NOT NULL,
-  `internal` text NOT NULL,
-  `speaker` text NOT NULL,
-  `place` text NOT NULL,
+  `title` text NOT NULL DEFAULT '',
+  `comment` text NOT NULL DEFAULT '',
+  `internal` text NOT NULL DEFAULT '',
+  `speaker` text NOT NULL DEFAULT '',
+  `place` text NOT NULL DEFAULT '',
   `time` datetime NOT NULL,
   `duration` INTEGER NOT NULL DEFAULT '90',
   `time_created` datetime NOT NULL,
   `time_updated` datetime NOT NULL,
-  `jumplist` text NOT NULL,
-  `titlefile` varchar(255) NOT NULL
+  `jumplist` text NOT NULL DEFAULT '',
+  `titlefile` varchar(255) NOT NULL DEFAULT ''
 );
 CREATE TABLE IF NOT EXISTS `places` (
   `place` varchar(20) NOT NULL PRIMARY KEY,
diff --git a/meetings.py b/meetings.py
index 57b3e505b6720a7836918ad2371f01a928e13af9..0eb0195fcb04fceca2140f7de6f6665102e3bd97 100644
--- a/meetings.py
+++ b/meetings.py
@@ -21,6 +21,7 @@ def get_next_meeting():
 	event = sorted(meetings, key=lambda e: e['DTSTART'].dt)[0]
 	return str(event['UID']), event['DTSTART'].dt.replace(tzinfo=None)
 
+@sched_func(60*60)
 def update_meeting():
 	try:
 		uid, start = get_next_meeting()
diff --git a/server.py b/server.py
index dde9977c0cd31f880bf177c9086f4897a01e1342..fb2271c6ccf87d16799263143e8c889e3872afc5 100644
--- a/server.py
+++ b/server.py
@@ -7,6 +7,8 @@ import os
 import sys
 import hashlib
 import random
+import sched
+import time
 
 app = Flask(__name__)
 
@@ -16,15 +18,25 @@ app.add_template_global(random.randint, name='randint')
 app.add_template_global(datetime, name='datetime')
 app.add_template_global(timedelta, name='timedelta')
 
-def timer_func():
-	with app.test_request_context():
-		pass # do something
-	timer = threading.Timer(60*60, timer_func)
-	timer.start()
+scheduler = sched.scheduler()
+def run_scheduler():
+	time.sleep(1) # UWSGI does weird things on startup
+	while True:
+		scheduler.run()
 
-timer = threading.Timer(0, timer_func)
-timer.daemon = True
-timer.start()
+def sched_func(delay, priority=0, firstdelay=None, args=[], kargs={}):
+	if firstdelay == None:
+		firstdelay = random.randint(1, 120)
+	def wrapper(func):
+		def sched_wrapper():
+			with app.test_request_context():
+				func(*args, *kargs)
+			scheduler.enter(delay, priority, sched_wrapper)
+		scheduler.enter(firstdelay, priority, sched_wrapper)
+		return func
+	return wrapper
+
+threading.Thread(target=run_scheduler, daemon=True).start()
 
 config = app.config
 config.from_pyfile('config.py.example', silent=True)
@@ -257,13 +269,22 @@ def logout():
 tabs = {
 	'courses': ('courses_data', 'id', ['visible', 'listed', 'title', 'short',
 			'handle', 'organizer', 'subject', 'semester', 'downloadable',
-			'internal', 'responsible','deleted']),
+			'internal', 'responsible','deleted'],
+			['created_by', 'time_created', 'time_updated']),
 	'lectures': ('lectures_data', 'id', ['visible', 'title', 'comment',
-			'internal', 'speaker', 'place', 'time', 'duration', 'jumplist','deleted']),
-	'videos': ('videos_data', 'id', ['visible','deleted']),
-	'chapters': ('chapters', 'id', ['time', 'text', 'visible', 'deleted']),
-	'announcements': ('announcements', 'id', ['text', 'level', 'visible', 'deleted', 'time_publish', 'time_expire']),
-	'featured': ('featured', 'id', ['title', 'text', 'internal', 'visible', 'deleted'])
+			'internal', 'speaker', 'place', 'time', 'duration', 'jumplist','deleted'],
+			['course_id', 'time_created', 'time_updated']),
+	'videos': ('videos_data', 'id', ['visible','deleted'],
+			['created_by', 'time_created', 'time_updated']),
+	'chapters': ('chapters', 'id', ['time', 'text', 'visible', 'deleted'],
+			['created_by', 'time_created', 'time_updated']),
+	'announcements': ('announcements', 'id', ['text', 'level', 'visible',
+			'deleted', 'time_publish', 'time_expire'],
+			['created_by', 'time_created', 'time_updated']),
+	'featured': ('featured', 'id', ['title', 'text', 'internal', 'visible', 'deleted'],
+			['created_by', 'time_created', 'time_updated']),
+	'auth': ('auth', 'auth_id', ['auth_type', 'auth_user', 'auth_passwd'],
+			['course_id', 'lecture_id', 'video_id'])
 }
 
 @app.route('/edit', methods=['GET', 'POST'])
@@ -275,11 +296,9 @@ def edit(prefix='', ignore=[]):
 	if not prefix and 'prefix' in request.args:
 		prefix = request.args['prefix']
 	modify('BEGIN')
+	changes = request.values.items()
 	if request.is_json:
 		changes = request.get_json().items()
-	else:
-		changes = request.args.items()
-	created = {}
 	for key, val in changes:
 		if key in ignore:
 			continue
@@ -299,23 +318,25 @@ def edit(prefix='', ignore=[]):
 @mod_required
 def create(table):
 	assert table in tabs
-	id = modify('INSERT INTO %s (created_by, time_created, time_updated) VALUES (?, ?, ?)'%tabs[table][0],
-			session['user']['dbid'], datetime.now(), datetime.now())
-	edit(prefix=table+'.'+str(id)+'.')
-	if 'ref' in request.values:
-		return redirect(request.values['ref'])
-	return str(id), 200
-
-@app.route('/newlecture/<courseid>', methods=['GET', 'POST'])
-@mod_required
-def new_lecture(courseid):
-	id = modify('''
-		INSERT INTO lectures_data
-			(course_id, visible, drehplan, title, comment, internal, speaker, place,
-				time, time_created, time_updated, jumplist, titlefile)
-			VALUES (?, 0, "", "Noch kein Titel", "", "", "", "", ?, ?, ?, "", "")
-		''', courseid, datetime.now(), datetime.now(), datetime.now())
-	edit(prefix='lectures.'+str(id)+'.', ignore=['ref'])
+	defaults = {'created_by': session['user']['dbid'], 'time_created': datetime.now(), 'time_updated': datetime.now()}
+	columns = []
+	values = []
+	for column, val in defaults.items():
+		if column in tabs[table][3]:
+			columns.append(column)
+			values.append(val)
+	args = request.values
+	if request.is_json:
+		args = request.get_json()
+	for column, val in args.items():
+		if column == 'ref':
+			continue
+		assert column in tabs[table][2]+tabs[table][3]
+		assert column not in defaults
+		columns.append(column)
+		values.append(val)
+	id = modify('INSERT INTO %s (%s) VALUES (%s)'%(tabs[table][0],
+				','.join(columns), ','.join(['?']*len(values))), *values)
 	if 'ref' in request.values:
 		return redirect(request.values['ref'])
 	return str(id), 200
@@ -432,3 +453,5 @@ import feeds
 import importer
 import schedule
 import sorter
+if 'ICAL_URL' in config:
+	import meetings
diff --git a/templates/course.html b/templates/course.html
index 48c70f6fff3c0cd544dc26f55ca45e64d335b590..7d421e6b7852d714c96459f554f0bd1a59822002 100644
--- a/templates/course.html
+++ b/templates/course.html
@@ -38,7 +38,7 @@
 </div>
 <div class="panel panel-default">
 	<div class="panel-heading">
-		<h1 class="panel-title">Videos{% if ismod() %} <a class="btn btn-default" style="margin-right: 5px;" href="{{ url_for('new_lecture', courseid=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)}}"></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', 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)}}"></a> </h1>
 	</div>
 	<ul class="list-group lectureslist">
 		{% for l in lectures %}
diff --git a/templates/import_campus.html b/templates/import_campus.html
index 3240907f378a18c060308c0c9222f19ccd715e67..3a5819f6ec729836a183d4d439597b60f3d0854a 100644
--- a/templates/import_campus.html
+++ b/templates/import_campus.html
@@ -90,7 +90,7 @@
 								{{ valuedeletebtn(['lectures',i.id,'deleted']) }}
 							{% endif%}
 							{% if (i.type == 'import')  %}
-								<button class="btn btn-default newlecture" onclick="moderatorinterface.gethttp('{{ url_for('new_lecture', courseid=course.id, time=i.time, title=i.title, place=i.place) }}')">anlegen</a>
+								<button class="btn btn-default newlecture" onclick="moderatorinterface.gethttp('{{ url_for('create', table='lecture', course_id=course.id, time=i.time, title=i.title, place=i.place) }}')">anlegen</a>
 							{% endif%}
 						</span>
 					</span>