From d36fe9d81bd10c435052238b3706b482783889dd Mon Sep 17 00:00:00 2001
From: Moritz Schneider <scmoritz@student.ethz.ch>
Date: Thu, 15 Dec 2016 14:59:43 +0100
Subject: [PATCH] added newer version of amivcore library Fixed issue #20

---
 index.html           |    5 +
 lib/amiv/amivcore.js |  811 ++++++++------
 lib/amiv/spec.json   | 2459 ++++++++++++++++++++++--------------------
 tools/events.tool    |   79 +-
 4 files changed, 1764 insertions(+), 1590 deletions(-)

diff --git a/index.html b/index.html
index 0a9e75a..0827856 100644
--- a/index.html
+++ b/index.html
@@ -30,6 +30,11 @@
 
 	<script src="lib/jquery/jquery-2.2.2.min.js"></script>
 	<script src="lib/bootstrap/js/bootstrap.min.js"></script>
+	<script>
+	  // set the api url for the amivcore js library
+	  var api_url_config = "https://amiv-apidev.vsos.ethz.ch";
+	  var spec_url_config = "lib/amiv/spec.json";
+	</script>
 	<script src="lib/amiv/amivcore.js"></script>
 	<script src="lib/cust/main.js"></script>
 
diff --git a/lib/amiv/amivcore.js b/lib/amiv/amivcore.js
index 019d539..453ad2e 100644
--- a/lib/amiv/amivcore.js
+++ b/lib/amiv/amivcore.js
@@ -1,359 +1,452 @@
-(function(window) {
-    'use strict';
-    // Library NameSpace
-    var lns = 'amivcore'
-
-    function libgen() {
-        // Lib to returned
-        var lib = {};
-
-        // Core
-        var core = {
-            // Important vars n' stuff
-            lib: {
-                api_url: 'https://amiv-apidev.vsos.ethz.ch',
-                // api_url: 'http://192.168.1.100',
-                spec_url: 'lib/amiv/spec.json',
-                //spec_url: 'https://nicco.io/amiv/docs/spec.json',
-                authenticated: false,
-                ready: false,
-                req_time_out: 5000,
-                on_interval: 100,
-                auth_interval: 5000,
-                auth_allowed_fails: 5,
-                auth_fails: 0,
-                show_errors: false,
-            },
-            // Header Setup
-            header: {
-                req: {
-                    'get': ['Content-Type', 'Authorization'],
-                    'post': ['Content-Type', 'Authorization'],
-                    'put': ['Content-Type', 'Authorization', 'If-Match'],
-                    'patch': ['Content-Type', 'Authorization', 'If-Match'],
-                    'delete': ['Content-Type', 'Authorization', 'If-Match'],
-                },
-                make: {
-                    'Content-Type': function() {
-                        return 'application/json'
-                    },
-                    'Authorization': function() {
-                        if (get('cur_token') != null)
-                            return 'Basic ' + btoa(get('cur_token') + ':');
-                        return '';
-                    },
-                    'If-Match': function() {
-                        return null;
-                    }
-                }
-            },
-            adapter: {
-                'none': function(ret) {
-                    return ret;
-                },
-                'string': function(strg) {
-                    return String(strg);
-                },
-                'integer': function(int) {
-                    return parseInt(int);
-                },
-                'boolean': function(bool) {
-                    return (String(bool).trim().toLowerCase() == 'true' || bool === true || bool === 1)
-                },
-                'datetime': function(dt) {
-                    var tmp = new Date(dt);
-                    return new Date(dt).toISOString().split('.')[0]+"Z";
-                }
-            }
-        }
-
-        // Utility empty function for no callback
-        function dummy() {};
-
-        //Save and get into localStorage
-        function set(cname, cvalue, exdays) {
-            window.localStorage.setItem('glob-' + cname, cvalue);
-        }
-
-        function get(cname) {
-            return window.localStorage.getItem('glob-' + cname);
-        }
-
-        // Make Request
-        function req(attr, callback) {
-            callback = callback || function(msg) {
-                console.log(msg);
-            };
-            $.ajax({
-                url: core.lib.api_url + attr.path,
-                data: attr.data,
-                method: attr.method,
-                dataType: 'json',
-                timeout: core.lib.req_time_out,
-                headers: attr.headers,
-                error: function(res) {
-                    if (core.lib.show_errors) console.log(res);
-                    callback(res);
-                },
-            }).done(function(res) {
-                callback(res);
-            });
-        }
-
-        function makeFunc(domain, m) {
-            return function(attr, callback) {
-                attr = attr || {};
-                var curLib = {}
-                for (var curAttr in attr['data']) {
-                    var curAttrType = lib.getParamType(domain, curAttr);
-                    if (core.adapter.hasOwnProperty(curAttrType))
-                        curLib[curAttr] = core.adapter[lib.getParamType(domain, curAttr)](attr['data'][curAttr]);
-                    else
-                        curLib[curAttr] = attr['data'][curAttr];
-                }
-                //curLib[curAttr] = attr['data'][curAttr];
-
-                var hdr = {};
-                for (var curHdr in attr['header'])
-                    hdr[curHdr] = attr['header'][curHdr];
-
-                var curPath = '/' + domain;
-                var curLink = curPath;
-                if (attr['id'] != undefined) {
-                    curPath += '/' + attr['id'];
-                    curLink += '/{_id}';
-                }
-
-                if (get('cur_token') != null)
-                    hdr['Authorization'] = 'Basic ' + btoa(get('cur_token') + ':');
-
-                if (m != 'GET') {
-                    if (m == 'POST' || m == 'PUT')
-                        for (var param in lib[domain]['methods'][m][curLink]['params'])
-                            if (lib[domain]['methods'][m][curLink]['params'][param]['required'] == true)
-                                if (curLib[lib[domain]['methods'][m][curLink]['params'][param]['name']] == undefined)
-                                    return 'Error: Missing ' + lib[domain]['methods'][m][curLink]['params'][param]['name'];
-                    hdr['Content-Type'] = 'application/json';
-                    curLib = JSON.stringify(curLib);
-                }
-                req({
-                    path: curPath,
-                    method: m,
-                    data: curLib,
-                    headers: hdr,
-                }, callback);
-                return true;
-            };
-        }
-
-        $.ajax({
-            url: core.lib.spec_url,
-            dataType: 'json',
-            timeout: 5000,
-            success: function(d) {
-                var data = d['domains'];
-                for (var domain in data) {
-                    lib[domain] = {};
-                    lib[domain].methods = [];
-                    for (var p in data[domain]['paths']) {
-                        for (var m in data[domain]['paths'][p]) {
-                            if (lib[domain].methods[m] == undefined) lib[domain].methods[m] = {};
-                            lib[domain].methods[m][p] = data[domain]['paths'][p][m];
-                        }
-                    }
-                    for (var m in lib[domain]['methods']) {
-                        lib[domain][m] = makeFunc(domain, m);
-                    }
-                }
-                checkAuth();
-            },
-            error: function(d) {
-                console.log('Cannot reach initialization spec: ' + core.lib.spec_url);
-                console.log(d);
-            }
-        });
-
-        function checkAuth(exec_once) {
-            exec_once = exec_once || false;
-            if (get('cur_token') != null) {
-                lib.sessions.GET({
-                    data: {
-                        where: 'token==["' + get('cur_token') + '"]'
-                    }
-                }, function(res) {
-                    if (res !== undefined && res.hasOwnProperty('_items') && res['_items'].length > 0) {
-                        core.lib.authenticated = true;
-                        core.lib.auth_fails = 0;
-                    } else {
-                        core.lib.auth_allowed_fails++;
-                        if (core.lib.auth_fails > core.lib.auth_allowed_fails)
-                            core.lib.authenticated = false;
-                    }
-                    core.lib.ready = true;
-                    // if (!exec_once)
-                    //     setTimeout(checkAuth, core.lib.auth_interval);
-                });
-            } else {
-                core.lib.authenticated = false;
-                core.lib.ready = true;
-                if (!exec_once)
-                    setTimeout(checkAuth, core.lib.auth_interval);
-            }
-        }
-
-        // Get parameter type
-        lib.getParamType = function(dom, param) {
-            var tmp = 'none';
-            try {
-                if (Array.isArray(lib[dom].methods.POST['/' + dom].params))
-                    lib[dom].methods.POST['/' + dom].params.forEach(function(cur) {
-                        if (cur.name == param) {
-                            tmp = cur.type;
-                        }
-                    });
-
-            } catch (e) {}
-            return tmp;
-        }
-
-        // Get the etag
-        lib.getEtag = function(curDomain, curId, callback) {
-            return lib[curDomain].GET({
-                id: curId
-            }, function(res) {
-                callback(res['_etag']);
-            });
-        }
-
-        // Returns whether user is logged in
-        lib.authenticated = function() {
-            return core.lib.authenticated;
-        }
-
-        // Login function
-        lib.login = function(curUser, curPass, callback) {
-            callback = callback || dummy;
-            req({
-                path: '/sessions/',
-                method: 'POST',
-                data: JSON.stringify({
-                    username: curUser.toLowerCase(),
-                    password: curPass
-                }),
-                headers: {
-                    'Content-Type': 'application/json',
-                },
-            }, function(msg) {
-                var reqVar = ['token', 'user_id', 'id'];
-                for (var i in reqVar) {
-                    lib['cur_' + reqVar[i]] = msg[reqVar[i]];
-                }
-                if (msg['_status'] == 'OK') {
-                    set('cur_token_id', msg['id'], 1);
-                    set('cur_token', msg['token'], 1);
-                    set('cur_user_id', parseInt(msg['user_id']), 1);
-                    checkAuth();
-                    callback(true);
-                } else {
-                    set('cur_token_id', null);
-                    set('cur_token', null);
-                    set('cur_user_id', null);
-                    callback(false);
-                }
-            });
-        }
-
-        // Logout
-        lib.logout = function() {
-            // Deleting token from api and unsetting the vars
-            lib.sessions.DELETE({
-                id: get('cur_token_id')
-            }, function(res) {
-                set('cur_token', null);
-                set('cur_token_id', null);
-                set('cur_user_id', null);
-                checkAuth();
-            });
-        }
-
-        // Get info about the current user
-        lib.user = function(attr, callback) {
-            callback = callback || dummy;
-            lib.users.GET({
-                id: get('cur_user_id')
-            }, function(res) {
-                if (typeof attr === 'object') {
-                    var ret = {};
-                    for (var key in attr)
-                        ret[attr[key]] = res[attr[key]];
-                    callback(ret);
-                } else {
-                    callback(res[attr]);
-                }
-            });
-        }
-
-        // Get the necessary field for specific requests
-        lib.getRequiredFields = function(domain, type, wId) {
-            var curTree;
-            var resAttr = {};
-            if (wId)
-                curTree = lib[domain]['methods'][type]['/' + domain + '/{_id}']['params'];
-            else
-                curTree = lib[domain]['methods'][type]['/' + domain]['params'];
-            if (curTree.length == 0) return false;
-            else {
-                for (var i = 0; i < curTree.length; i++)
-                    if (curTree[i].required == true)
-                        resAttr[curTree[i].name] = curTree[i];
-            }
-            return resAttr;
-        }
-
-        //On function
-        lib.on = function(trigger, callback) {
-            if (callback) {
-                lib.on_mem[trigger].callback = callback;
-                lib.on_mem[trigger].func();
-            }
-        }
-        lib.on_mem = {
-            ready: {
-                func: function() {
-                    if (core.lib.ready)
-                        lib.on_mem.ready.callback();
-                    else setTimeout(function() {
-                        lib.on_mem.ready.func();
-                    }, core.lib.on_interval);
-                }
-            },
-            login: {
-                func: function() {
-                    if (core.lib.authenticated && !lib.on_mem.login.prev)
-                        lib.on_mem.login.callback();
-                    lib.on_mem.login.prev = core.lib.authenticated;
-                    setTimeout(lib.on_mem.login.func, core.lib.on_interval);
-                },
-                prev: false,
-            },
-            logout: {
-                func: function() {
-                    if (!core.lib.authenticated && lib.on_mem.logout.prev)
-                        lib.on_mem.logout.callback();
-                    lib.on_mem.logout.prev = core.lib.authenticated;
-                    setTimeout(lib.on_mem.logout.func, core.lib.on_interval);
-                },
-                prev: false,
-            },
-        }
-
-        return lib;
-    }
-
-    if (typeof(window[lns]) === 'undefined') {
-        window[lns] = libgen();
-    } else {
-        console.log(lns + ' already defined, please solve conflict');
-    }
-
-})(window);
+(function(window) {
+    'use strict';
+    // Library NameSpace
+    var lns = 'amivcore'
+
+    function libgen() {
+        // Lib to returned
+        var lib = {};
+
+        // Core
+        var core = {
+            // Important vars n' stuff
+            lib: {
+                api_url: api_url_config,
+                spec_url: spec_url_config,
+                authenticated: false,
+                ready: false,
+                req_time_out: 5000,
+                on_interval: 100,
+                auth_interval: 5000,
+                auth_allowed_fails: 5,
+                auth_fails: 0,
+                show_errors: false,
+            },
+            // Header Setup
+            header: {
+                req: {
+                    'get': ['Content-Type', 'Authorization'],
+                    'post': ['Content-Type', 'Authorization'],
+                    'patch': ['Content-Type', 'Authorization', 'If-Match'],
+                    'delete': ['Content-Type', 'Authorization', 'If-Match'],
+                },
+                make: {
+                    'Content-Type': function() {
+                        return 'application/json'
+                    },
+                    'Authorization': function() {
+                        if (get('cur_token') != null)
+                            return 'Basic ' + btoa(get('cur_token') + ':');
+                        return '';
+                    },
+                    'If-Match': function() {
+                        return null;
+                    }
+                }
+            },
+            adapter: {
+                'none': function(ret) {
+                    return ret;
+                },
+                'string': function(strg) {
+                    return String(strg);
+                },
+                'integer': function(int) {
+                    return parseInt(int);
+                },
+                'boolean': function(bool) {
+                    return (String(bool).trim().toLowerCase() == 'true' || bool === true || bool === 1)
+                },
+                'datetime': function(dt) {
+                    var tmp = new Date(dt);
+		    // send an iso string without the milis, thats what the api expects
+		    return new Date(dt).toISOString().split('.')[0]+"Z";
+                }
+            }
+        }
+
+        /**
+	 *  Utility empty function for no callback
+	 *  @constructor
+	 */
+        function dummy() {};
+
+        /** 
+	 * Save and get into localStorage
+	 * @constructor
+	 * @param {string} cname
+	 * @param {string} cvalue
+	 */
+        function set(cname, cvalue, exdays) {
+            window.localStorage.setItem('glob-' + cname, cvalue);
+        }
+
+	/**
+	 * Get from LocalStorage
+	 * @constructor
+	 * @param {string} cname
+	 */
+        function get(cname) {
+            return window.localStorage.getItem('glob-' + cname);
+        }
+
+	/**
+	 * Remove variable in localStorage
+	 * @param {string} cname
+	 */
+	function remove(cname) {
+	    if (window.localStorage.getItem('gloc-' + cname) === null)
+		window.localStorage.removeItem('glob-' + cname);
+	}
+
+        /** 
+	 * Make general request with all request parameters in attr
+	 * @constructor
+	 * @param {} attr - all request parameters (attr.path, attr.data, attr.method ...)
+	 * @param {} callback
+	 */
+        function req(attr, callback) {
+            callback = callback || function(msg) {
+                console.log(msg);
+            };
+	    // put the json object into form-data
+	    var form = new FormData();
+	    console.log(attr);
+	    for (var key in attr['data'])
+		form.append(key, attr['data'][key]);
+            $.ajax({
+                url: core.lib.api_url + attr.path,
+                data: form,
+                method: attr.method,
+                dataType: "json",
+		contentType: false,
+		processData: false,
+                timeout: core.lib.req_time_out,
+                headers: attr.headers,
+                error: function(res) {
+                    if (core.lib.show_errors) console.log(res);
+                    callback(res);
+                },
+            }).done(function(res) {
+                callback(res);
+            });
+        }
+
+	/**
+	 * Make Function
+	 * @constructor
+	 * @param {string} domain
+	 * @param {string} m - method
+	 */
+        function makeFunc(domain, m) {
+            return function(attr, callback) {
+                attr = attr || {}; // if attr does not exist use empty object
+                var curLib = {}
+                for (var curAttr in attr['data']) {
+                    var curAttrType = lib.getParamType(domain, curAttr);
+                    if (core.adapter.hasOwnProperty(curAttrType))
+                        curLib[curAttr] = core.adapter[lib.getParamType(domain, curAttr)](attr['data'][curAttr]);
+                    else
+                        curLib[curAttr] = attr['data'][curAttr];
+                }
+                //curLib[curAttr] = attr['data'][curAttr];
+
+                var hdr = {};
+                for (var curHdr in attr['header'])
+                    hdr[curHdr] = attr['header'][curHdr];
+
+                var curPath = '/' + domain;
+                var curLink = curPath;
+                if (attr['id'] != undefined) {
+                    curPath += '/' + attr['id'];
+                    curLink += '/{_id}';
+                }
+
+                if (get('cur_token') != null)
+                    hdr['Authorization'] = 'Basic ' + btoa(get('cur_token') + ':');
+
+                if (m != 'GET') {
+                    if (m == 'POST' || m == 'PUT')
+                        for (var param in lib[domain]['methods'][m][curLink]['params'])
+                            if (lib[domain]['methods'][m][curLink]['params'][param]['required'] == true)
+                                if (curLib[lib[domain]['methods'][m][curLink]['params'][param]['name']] == undefined)
+                                    return 'Error: Missing ' + lib[domain]['methods'][m][curLink]['params'][param]['name'];
+                    // hdr['Content-Type'] = 'application/json';
+                    // curLib = JSON.stringify(curLib);
+                }
+                req({
+                    path: curPath,
+                    method: m,
+                    data: curLib,
+                    headers: hdr,
+                }, callback);
+                return true;
+            };
+        }
+
+	/**
+	 * Read spec.json and set all needed parameters
+	 * @constructor
+	 */
+        $.ajax({
+            url: core.lib.spec_url,
+            dataType: 'json',
+            timeout: core.lib.req_time_out,
+            success: function(d) {
+                var data = d['domains'];
+                for (var domain in data) {
+                    lib[domain] = {};
+                    lib[domain].methods = [];
+                    for (var p in data[domain]['paths']) {
+                        for (var m in data[domain]['paths'][p]) {
+                            if (lib[domain].methods[m] == undefined) lib[domain].methods[m] = {};
+                            lib[domain].methods[m][p] = data[domain]['paths'][p][m];
+                        }
+                    }
+                    for (var m in lib[domain]['methods']) {
+                        lib[domain][m] = makeFunc(domain, m);
+                    }
+                }
+                checkAuth();
+            },
+            error: function(d) {
+                console.log('Cannot reach initialization spec: ' + core.lib.spec_url);
+                console.error(d);
+            }
+        });
+
+	/**
+	 * Check Authentication
+	 * @constructor
+	 * @param {} exec_once
+	 */
+        function checkAuth(exec_once) {
+            exec_once = exec_once || false;
+            if (get('cur_token') != null) {
+                lib.sessions.GET({
+                    data: {
+                        where: 'token==["' + get('cur_token') + '"]'
+                    }
+                }, function(res) {
+                    if (res !== undefined && res.hasOwnProperty('_items') && res['_items'].length > 0) {
+                        core.lib.authenticated = true;
+                        core.lib.auth_fails = 0;
+                    } else {
+                        core.lib.auth_allowed_fails++;
+                        if (core.lib.auth_fails > core.lib.auth_allowed_fails)
+                            core.lib.authenticated = false;
+                    }
+                    core.lib.ready = true;
+                    if (!exec_once)
+                        setTimeout(checkAuth, core.lib.auth_interval);
+                });
+            } else {
+                core.lib.authenticated = false;
+                core.lib.ready = true;
+                if (!exec_once)
+                    setTimeout(checkAuth, core.lib.auth_interval);
+            }
+        }
+
+        /** 
+	 * Get parameter type
+	 * @constructor
+	 * @param {string} dom
+	 * @param {string} param
+	 * @example 
+	 * // returns type of field "_id" of resource "users"
+	 * amivcore.getParamType("users", "_id")
+	 */
+        lib.getParamType = function(dom, param) {
+            var tmp = 'none';
+            try {
+                if (Array.isArray(lib[dom].methods.POST['/' + dom].params))
+                    lib[dom].methods.POST['/' + dom].params.forEach(function(cur) {
+                        if (cur.name == param) {
+                            tmp = cur.type;
+                        }
+                    });
+
+            } catch (e) {}
+            return tmp;
+        }
+
+        /** 
+	 * Get the etag
+	 * @constructor
+	 * @param {} curDomain
+	 * @param {} curId
+	 * @param {} callback
+	 * @example 
+	 * amivcore.getEtag("users", amivcore.cur_user, function(res) {
+	 *     console.log(res);
+	 * });
+	 */
+        lib.getEtag = function(curDomain, curId, callback) {
+            return lib[curDomain].GET({
+                id: curId
+            }, function(res) {
+                callback(res['_etag']);
+            });
+        }
+
+        /** 
+	 * Returns whether user is logged in
+	 * @constructor
+	 */
+        lib.authenticated = function() {
+            return core.lib.authenticated;
+        }
+
+        /**
+	 *  Login function
+	 *  @constructor
+	 *  @param {} curUser
+	 *  @param {} curPass
+	 *  @param {} callback
+	 */
+        lib.login = function(curUser, curPass, callback) {
+            callback = callback || dummy;
+            req({
+                path: '/sessions/',
+                method: 'POST',
+                data: JSON.stringify({
+                    username: curUser.toLowerCase(),
+                    password: curPass
+                }),
+                headers: {
+                    'Content-Type': 'application/json',
+                },
+            }, function(msg) {
+                var reqVar = ['token', 'user', '_id'];
+                for (var i in reqVar) {
+                    lib['cur_' + reqVar[i]] = msg[reqVar[i]];
+                }
+                if (msg['_status'] == 'OK') {
+                    set('cur_token_id', msg['_id'], 1);
+                    set('cur_token', msg['token'], 1);
+                    set('cur_user_id', msg['user'], 1);
+                    callback(true);
+                } else {
+                    remove('cur_token_id');
+                    remove('cur_token');
+                    remove('cur_user_id');
+                    callback(false);
+                }
+            });
+        }
+
+        /** 
+	 * Logout
+	 * @constructor
+	 */
+        lib.logout = function() {
+            // Deleting token from api and unsetting the vars
+            lib.sessions.DELETE({
+                id: get('cur_token_id')
+            }, function(res) {
+                remove('cur_token');
+                remove('cur_token_id');
+                remove('cur_user_id');
+            });
+        }
+
+        /**
+	 * Get info about the current user
+	 * @constructor
+	 * @param {} attr
+	 * @param {} callback
+	 */
+        lib.user = function(attr, callback) {
+            callback = callback || dummy;
+            lib.users.GET({
+                id: get('cur_user_id')
+            }, function(res) {
+                if (typeof attr === 'object') {
+                    var ret = {};
+                    for (var key in attr)
+                        ret[attr[key]] = res[attr[key]];
+                    callback(ret);
+                } else {
+                    callback(res[attr]);
+                }
+            });
+        }
+
+        /**
+	 * Get the necessary field for specific requests
+	 * @constructor
+	 * @param {} domain - resource eg. "/users"
+	 * @param {} type - HTTP request type eg. "PATCH"
+	 * @param {boolean} wId - with id eg. "/users/$id"
+	 * @example
+	 * amivcore.getRequiredFields("users", "POST", false)
+	 */
+        lib.getRequiredFields = function(domain, type, wId) {
+            var curTree;
+            var resAttr = {};
+            if (wId)
+                curTree = lib[domain]['methods'][type]['/' + domain + '/{_id}']['params'];
+            else
+                curTree = lib[domain]['methods'][type]['/' + domain]['params'];
+            if (curTree.length == 0) return false;
+            else {
+                for (var i = 0; i < curTree.length; i++)
+                    if (curTree[i].required == true)
+                        resAttr[curTree[i].name] = curTree[i];
+            }
+            return resAttr;
+        }
+
+        /**
+	 * On function
+	 * @constructor
+	 * @param {} trigger
+	 * @param {} callback
+	 */
+        lib.on = function(trigger, callback) {
+            if (callback) {
+                lib.on_mem[trigger].callback = callback;
+                lib.on_mem[trigger].func();
+            }
+        }
+        lib.on_mem = {
+            ready: {
+                func: function() {
+                    if (core.lib.ready)
+                        lib.on_mem.ready.callback();
+                    else setTimeout(function() {
+                        lib.on_mem.ready.func();
+                    }, core.lib.on_interval);
+                }
+            },
+            login: {
+                func: function() {
+                    if (core.lib.authenticated && !lib.on_mem.login.prev)
+                        lib.on_mem.login.callback();
+                    lib.on_mem.login.prev = core.lib.authenticated;
+                    setTimeout(lib.on_mem.login.func, core.lib.on_interval);
+                },
+                prev: false,
+            },
+            logout: {
+                func: function() {
+                    if (!core.lib.authenticated && lib.on_mem.logout.prev)
+                        lib.on_mem.logout.callback();
+                    lib.on_mem.logout.prev = core.lib.authenticated;
+                    setTimeout(lib.on_mem.logout.func, core.lib.on_interval);
+                },
+                prev: false,
+            },
+        }
+
+        return lib;
+    }
+
+    if (typeof(window[lns]) === 'undefined') {
+        window[lns] = libgen();
+    } else {
+        console.log(lns + ' already defined, please solve conflict');
+    }
+
+})(window);
diff --git a/lib/amiv/spec.json b/lib/amiv/spec.json
index 1191dc5..bed55ec 100644
--- a/lib/amiv/spec.json
+++ b/lib/amiv/spec.json
@@ -1,1797 +1,1890 @@
-  {
-  "api_name": "API",
+{
   "domains": {
-    "events": {
+    "purchases": {
       "paths": {
-        "/events/{_id}": {
-          "DELETE": {
-            "label": "Delete a Event",
+        "/purchases": {
+          "POST": {
             "params": [
               {
-                "type": "string",
+                "unique": false,
+                "name": "timestamp",
+                "nullable": false,
+                "required": true,
+                "type": "datetime"
+              },
+              {
+                "not_patchable_unless_admin": true,
+                "name": "product",
+                "nullable": false,
                 "required": true,
+                "allowed": [
+                  "beer",
+                  "coffee"
+                ],
+                "unique": false,
+                "type": "string",
+                "maxlength": 6
+              },
+              {
+                "required": false,
+                "type": "objectid",
                 "name": "_id"
+              },
+              {
+                "name": "user",
+                "nullable": false,
+                "required": true,
+                "data_relation": {
+                  "field": "_id",
+                  "resource": "users",
+                  "embeddable": true
+                },
+                "unique": false,
+                "type": "objectid"
               }
-            ]
+            ],
+            "label": "Create a Purchase"
           },
           "GET": {
-            "label": "Retrieve a Event",
+            "params": [],
+            "label": "Retrieve all purchases"
+          }
+        },
+        "/purchases/{_id}": {
+          "GET": {
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               }
-            ]
-          },
+            ],
+            "label": "Retrieve a Purchase"
+          }
+        }
+      },
+      "description": {
+        "fields": {},
+        "general": "A beer machine or kaffi machine transaction. Users should be able to get beer or kaffi, if their last timestamp is older than one day and they are AMIV members. This resource is used to log their purchases."
+      }
+    },
+    "users": {
+      "paths": {
+        "/users/{_id}": {
           "PATCH": {
-            "label": "Update a Event",
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               },
               {
+                "not_patchable_unless_admin": true,
+                "name": "legi",
                 "nullable": true,
-                "maxlength": 500,
-                "type": "string",
                 "required": false,
-                "name": "catchphrase_de"
+                "maxlength": 8,
+                "unique": true,
+                "type": "string"
               },
               {
-                "nullable": true,
-                "maxlength": 500,
-                "type": "string",
                 "required": false,
-                "name": "catchphrase_en"
+                "type": "objectid",
+                "name": "_id"
               },
               {
-                "nullable": true,
+                "not_patchable_unless_admin": true,
+                "name": "firstname",
+                "nullable": false,
+                "required": true,
                 "maxlength": 50,
                 "type": "string",
-                "required": false,
-                "name": "location"
+                "empty": false
+              },
+              {
+                "not_patchable_unless_admin": true,
+                "name": "lastname",
+                "nullable": false,
+                "required": true,
+                "maxlength": 50,
+                "type": "string",
+                "empty": false
               },
               {
+                "name": "rfid",
                 "nullable": true,
                 "required": false,
-                "later_than": "time_start",
-                "dependencies": [
-                  "time_start"
-                ],
-                "name": "time_end",
-                "type": "datetime"
+                "maxlength": 6,
+                "unique": true,
+                "type": "string",
+                "empty": false
               },
               {
-                "readonly": true,
-                "type": "integer",
+                "nullable": true,
+                "name": "phone",
+                "maxlength": 20,
                 "required": false,
-                "name": "signup_count"
+                "type": "string",
+                "empty": false
               },
               {
-                "nullable": false,
-                "type": "boolean",
+                "not_patchable_unless_admin": true,
+                "name": "membership",
                 "required": true,
-                "name": "show_announce"
+                "allowed": [
+                  "none",
+                  "regular",
+                  "extraordinary",
+                  "honorary"
+                ],
+                "unique": false,
+                "type": "string",
+                "maxlength": 13
               },
               {
-                "nullable": false,
-                "type": "boolean",
-                "required": true,
-                "name": "show_infoscreen"
+                "not_patchable_unless_admin": true,
+                "name": "nethz",
+                "nullable": true,
+                "default": null,
+                "required": false,
+                "maxlength": 30,
+                "unique": true,
+                "type": "string",
+                "empty": false
               },
               {
-                "nullable": true,
-                "type": "integer",
+                "not_patchable_unless_admin": true,
+                "name": "gender",
                 "required": true,
-                "min": 0,
-                "requires_if_not_null": [
-                  "time_register_start",
-                  "time_register_end",
-                  "allow_email_signup"
+                "allowed": [
+                  "male",
+                  "female"
                 ],
-                "name": "spots"
+                "unique": false,
+                "type": "string",
+                "maxlength": 6
               },
               {
                 "nullable": true,
-                "maxlength": 100,
-                "required": false,
-                "dependencies": [
-                  "catchphrase_de",
-                  "description_de"
+                "not_patchable_unless_admin": true,
+                "name": "department",
+                "allowed": [
+                  "itet",
+                  "mavt"
                 ],
-                "name": "title_de",
+                "required": false,
                 "type": "string"
               },
               {
+                "name": "password",
                 "nullable": true,
-                "maxlength": 100,
+                "default": null,
                 "required": false,
-                "dependencies": [
-                  "catchphrase_en",
-                  "description_en"
-                ],
-                "name": "title_en",
-                "type": "string"
+                "maxlength": 100,
+                "type": "string",
+                "empty": false
               },
               {
-                "type": "media",
-                "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "img_poster"
+                "regex": "^.+@.+$",
+                "name": "email",
+                "required": true,
+                "maxlength": 100,
+                "unique": true,
+                "type": "string"
               },
               {
-                "nullable": true,
-                "min": 0,
-                "type": "integer",
                 "required": false,
-                "name": "price"
-              },
+                "type": "boolean",
+                "name": "send_newsletter",
+                "nullable": true
+              }
+            ],
+            "label": "Update a User"
+          },
+          "DELETE": {
+            "params": [
               {
-                "nullable": true,
-                "maxlength": 10000,
+                "required": true,
                 "type": "string",
-                "required": false,
-                "name": "description_de"
-              },
+                "name": "_id"
+              }
+            ],
+            "label": "Delete a User"
+          },
+          "GET": {
+            "params": [
               {
-                "type": "media",
+                "required": true,
+                "type": "string",
+                "name": "_id"
+              }
+            ],
+            "label": "Retrieve a User"
+          }
+        },
+        "/users/{nethz}": {
+          "GET": {
+            "params": [
+              {
+                "not_patchable_unless_admin": true,
+                "name": "nethz",
+                "nullable": true,
+                "default": null,
                 "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "img_banner"
-              },
+                "maxlength": 30,
+                "unique": true,
+                "type": "string",
+                "empty": false
+              }
+            ],
+            "label": "Retrieve a User"
+          }
+        },
+        "/users": {
+          "POST": {
+            "params": [
               {
-                "type": "media",
+                "not_patchable_unless_admin": true,
+                "name": "legi",
+                "nullable": true,
                 "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "img_thumbnail"
+                "maxlength": 8,
+                "unique": true,
+                "type": "string"
               },
               {
-                "type": "objectid",
                 "required": false,
+                "type": "objectid",
                 "name": "_id"
               },
               {
+                "not_patchable_unless_admin": true,
+                "name": "firstname",
                 "nullable": false,
-                "depends_any": [
-                  "title_de",
-                  "title_en"
-                ],
                 "required": true,
-                "name": "show_website",
-                "type": "boolean"
+                "maxlength": 50,
+                "type": "string",
+                "empty": false
               },
               {
-                "nullable": true,
-                "only_if_not_null": "spots",
-                "type": "json_schema",
-                "required": false,
-                "name": "additional_fields"
+                "not_patchable_unless_admin": true,
+                "name": "lastname",
+                "nullable": false,
+                "required": true,
+                "maxlength": 50,
+                "type": "string",
+                "empty": false
               },
               {
+                "name": "rfid",
                 "nullable": true,
-                "type": "datetime",
                 "required": false,
-                "name": "time_start"
+                "maxlength": 6,
+                "unique": true,
+                "type": "string",
+                "empty": false
               },
               {
                 "nullable": true,
-                "type": "datetime",
+                "name": "phone",
+                "maxlength": 20,
                 "required": false,
-                "name": "time_register_start"
+                "type": "string",
+                "empty": false
               },
-
               {
-                "nullable": true,
-                "type": "datetime",
-                "required": false,
-                "name": "time_advertising_start"
+                "not_patchable_unless_admin": true,
+                "name": "membership",
+                "required": true,
+                "allowed": [
+                  "none",
+                  "regular",
+                  "extraordinary",
+                  "honorary"
+                ],
+                "unique": false,
+                "type": "string",
+                "maxlength": 13
               },
               {
+                "not_patchable_unless_admin": true,
+                "name": "nethz",
                 "nullable": true,
-                "type": "datetime",
+                "default": null,
                 "required": false,
-                "name": "time_advertising_end"
+                "maxlength": 30,
+                "unique": true,
+                "type": "string",
+                "empty": false
               },
-
-
               {
-                "nullable": true,
-                "maxlength": 10000,
+                "not_patchable_unless_admin": true,
+                "name": "gender",
+                "required": true,
+                "allowed": [
+                  "male",
+                  "female"
+                ],
+                "unique": false,
                 "type": "string",
-                "required": false,
-                "name": "description_en"
+                "maxlength": 6
               },
               {
-                "nullable": false,
-                "type": "boolean",
+                "nullable": true,
+                "not_patchable_unless_admin": true,
+                "name": "department",
+                "allowed": [
+                  "itet",
+                  "mavt"
+                ],
                 "required": false,
-                "name": "allow_email_signup"
+                "type": "string"
               },
               {
+                "name": "password",
                 "nullable": true,
+                "default": null,
                 "required": false,
-                "later_than": "time_register_start",
-                "dependencies": [
-                  "time_register_start"
-                ],
-                "name": "time_register_end",
-                "type": "datetime"
+                "maxlength": 100,
+                "type": "string",
+                "empty": false
+              },
+              {
+                "regex": "^.+@.+$",
+                "name": "email",
+                "required": true,
+                "maxlength": 100,
+                "unique": true,
+                "type": "string"
               },
               {
-                "type": "media",
                 "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "img_infoscreen"
+                "type": "boolean",
+                "name": "send_newsletter",
+                "nullable": true
               }
-            ]
+            ],
+            "label": "Create a User"
+          },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all users"
           }
+        }
+      },
+      "description": {
+        "methods": {
+          "GET": "Authorization is required for most of the fields"
         },
-        "/events": {
-          "GET": {
-            "label": "Retrieve all events",
-            "params": []
+        "general": "In general, the user data will be generated from LDAP-Data. However, one might change the RFID-Number or the membership-status. Extraordinary members may not have a LDAP-Account and can therefore access all given fields."
+      }
+    },
+    "sessions": {
+      "paths": {
+        "/sessions/{_id}": {
+          "DELETE": {
+            "params": [
+              {
+                "required": true,
+                "type": "string",
+                "name": "_id"
+              }
+            ],
+            "label": "Delete a Session"
           },
+          "GET": {
+            "params": [
+              {
+                "required": true,
+                "type": "string",
+                "name": "_id"
+              }
+            ],
+            "label": "Retrieve a Session"
+          }
+        },
+        "/sessions": {
           "POST": {
-            "label": "Create a Event",
             "params": [
               {
-                "nullable": true,
-                "maxlength": 500,
+                "name": "username",
+                "nullable": false,
+                "required": true,
                 "type": "string",
-                "required": false,
-                "name": "catchphrase_de"
+                "empty": false
               },
               {
-                "nullable": true,
-                "maxlength": 500,
-                "type": "string",
+                "readonly": true,
                 "required": false,
-                "name": "catchphrase_en"
+                "type": "string",
+                "name": "token"
               },
               {
-                "nullable": true,
-                "maxlength": 50,
+                "name": "password",
+                "nullable": false,
+                "required": true,
                 "type": "string",
-                "required": false,
-                "name": "location"
+                "empty": false
               },
               {
-                "nullable": true,
+                "readonly": true,
+                "name": "user",
+                "data_relation": {
+                  "field": "_id",
+                  "cascade_delete": true,
+                  "resource": "users",
+                  "embeddable": true
+                },
                 "required": false,
-                "later_than": "time_start",
-                "dependencies": [
-                  "time_start"
-                ],
-                "name": "time_end",
-                "type": "datetime"
+                "type": "objectid"
               },
               {
-                "readonly": true,
-                "type": "integer",
                 "required": false,
-                "name": "signup_count"
-              },
+                "type": "objectid",
+                "name": "_id"
+              }
+            ],
+            "label": "Create a Session"
+          },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all sessions"
+          }
+        }
+      },
+      "description": {
+        "methods": {
+          "POST": "Login and aquire a login token. Post the fields 'username' and 'password', the response will contain the token. 'username' can be either nethz, mail, or user_id",
+          "GET": "Check token(s)."
+        },
+        "general": "A session is used to authenticate a user after he provided login data. A POST to /session will return a token you can use in an Authorization header: token <yourtoken>"
+      }
+    },
+    "groupmemberships": {
+      "paths": {
+        "/groupmemberships": {
+          "POST": {
+            "params": [
               {
-                "nullable": false,
-                "type": "boolean",
-                "required": true,
-                "name": "show_announce"
+                "required": false,
+                "type": "objectid",
+                "name": "_id"
               },
               {
-                "nullable": false,
-                "type": "boolean",
+                "self_enrollment_required": true,
+                "name": "group",
+                "data_relation": {
+                  "field": "_id",
+                  "cascade_delete": true,
+                  "resource": "groups",
+                  "embeddable": true
+                },
                 "required": true,
-                "name": "show_infoscreen"
+                "type": "objectid"
               },
               {
-                "nullable": true,
-                "type": "integer",
-                "required": true,
-                "min": 0,
-                "requires_if_not_null": [
-                  "time_register_start",
-                  "time_register_end",
-                  "allow_email_signup"
+                "name": "user",
+                "unique_combination": [
+                  "group"
                 ],
-                "name": "spots"
+                "required": true,
+                "only_self_or_moderator": true,
+                "data_relation": {
+                  "field": "_id",
+                  "cascade_delete": true,
+                  "resource": "users",
+                  "embeddable": true
+                },
+                "type": "objectid"
               },
-
               {
-                "nullable": true,
-                "type": "integer",
                 "required": false,
-                "min": 0,
-                "max": 10,
-                "name": "priority"
-              },
-
+                "type": "datetime",
+                "name": "expiry"
+              }
+            ],
+            "label": "Create a Groupmembership"
+          },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all groupmemberships"
+          }
+        },
+        "/groupmemberships/{_id}": {
+          "DELETE": {
+            "params": [
               {
-                "nullable": true,
-                "maxlength": 100,
-                "required": false,
-                "dependencies": [
-                  "catchphrase_de",
-                  "description_de"
-                ],
+                "required": true,
+                "type": "string",
+                "name": "_id"
+              }
+            ],
+            "label": "Delete a Groupmembership"
+          },
+          "GET": {
+            "params": [
+              {
+                "required": true,
+                "type": "string",
+                "name": "_id"
+              }
+            ],
+            "label": "Retrieve a Groupmembership"
+          }
+        }
+      },
+      "description": {
+        "general": "Assignment of registered users to groups."
+      }
+    },
+    "joboffers": {
+      "paths": {
+        "/joboffers": {
+          "POST": {
+            "params": [
+              {
+                "dependencies": "description_de",
                 "name": "title_de",
+                "required_if_not": "title_en",
+                "required": false,
                 "type": "string"
               },
               {
-                "nullable": true,
-                "maxlength": 100,
                 "required": false,
-                "dependencies": [
-                  "catchphrase_en",
-                  "description_en"
-                ],
-                "name": "title_en",
-                "type": "string"
+                "type": "objectid",
+                "name": "_id"
               },
               {
-                "type": "media",
                 "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "img_poster"
+                "type": "string",
+                "name": "company",
+                "maxlength": 30
               },
               {
-                "nullable": true,
-                "min": 0,
-                "type": "integer",
+                "dependencies": "description_en",
+                "name": "title_en",
+                "required_if_not": "title_de",
                 "required": false,
-                "name": "price"
+                "type": "string"
               },
               {
-                "nullable": true,
-                "maxlength": 10000,
-                "type": "string",
                 "required": false,
-                "name": "description_de"
+                "type": "datetime",
+                "name": "time_end"
               },
               {
-                "type": "media",
                 "required": false,
+                "type": "string",
+                "name": "description_en"
+              },
+              {
+                "name": "logo",
                 "filetype": [
                   "png",
                   "jpeg"
                 ],
-                "name": "img_banner"
+                "required": true,
+                "type": "media"
               },
               {
-                "type": "media",
+                "default": false,
                 "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "img_thumbnail"
+                "type": "boolean",
+                "name": "show_website"
               },
               {
-                "type": "objectid",
                 "required": false,
-                "name": "_id"
+                "type": "string",
+                "name": "description_de"
               },
               {
-                "nullable": false,
-                "depends_any": [
-                  "title_de",
-                  "title_en"
-                ],
+                "name": "pdf",
+                "filetype": [
+                  "pdf"
+                ],
                 "required": true,
-                "name": "show_website",
-                "type": "boolean"
+                "type": "media"
+              }
+            ],
+            "label": "Create a Joboffer"
+          },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all joboffers"
+          }
+        },
+        "/joboffers/{_id}": {
+          "PATCH": {
+            "params": [
+              {
+                "required": true,
+                "type": "string",
+                "name": "_id"
               },
               {
-                "nullable": true,
-                "only_if_not_null": "spots",
-                "type": "json_schema",
+                "dependencies": "description_de",
+                "name": "title_de",
+                "required_if_not": "title_en",
                 "required": false,
-                "name": "additional_fields"
+                "type": "string"
               },
               {
-                "nullable": true,
-                "type": "datetime",
                 "required": false,
-                "name": "time_start"
+                "type": "objectid",
+                "name": "_id"
               },
               {
-                "nullable": true,
-                "type": "datetime",
                 "required": false,
-                "name": "time_register_start"
+                "type": "string",
+                "name": "company",
+                "maxlength": 30
               },
-
-
               {
-                "nullable": true,
-                "type": "datetime",
+                "dependencies": "description_en",
+                "name": "title_en",
+                "required_if_not": "title_de",
                 "required": false,
-                "name": "time_advertising_start"
+                "type": "string"
               },
               {
-                "nullable": true,
-                "type": "datetime",
                 "required": false,
-                "name": "time_advertising_end"
+                "type": "datetime",
+                "name": "time_end"
               },
-
-
               {
-                "nullable": true,
-                "maxlength": 10000,
-                "type": "string",
                 "required": false,
+                "type": "string",
                 "name": "description_en"
               },
               {
-                "nullable": false,
-                "type": "boolean",
-                "required": false,
-                "name": "allow_email_signup"
+                "name": "logo",
+                "filetype": [
+                  "png",
+                  "jpeg"
+                ],
+                "required": true,
+                "type": "media"
               },
               {
-                "nullable": true,
+                "default": false,
                 "required": false,
-                "later_than": "time_register_start",
-                "dependencies": [
-                  "time_register_start"
-                ],
-                "name": "time_register_end",
-                "type": "datetime"
+                "type": "boolean",
+                "name": "show_website"
               },
               {
-                "type": "media",
                 "required": false,
+                "type": "string",
+                "name": "description_de"
+              },
+              {
+                "name": "pdf",
                 "filetype": [
-                  "png",
-                  "jpeg"
+                  "pdf"
                 ],
-                "name": "img_infoscreen"
+                "required": true,
+                "type": "media"
+              }
+            ],
+            "label": "Update a Joboffer"
+          },
+          "DELETE": {
+            "params": [
+              {
+                "required": true,
+                "type": "string",
+                "name": "_id"
+              }
+            ],
+            "label": "Delete a Joboffer"
+          },
+          "GET": {
+            "params": [
+              {
+                "required": true,
+                "type": "string",
+                "name": "_id"
               }
-            ]
+            ],
+            "label": "Retrieve a Joboffer"
           }
         }
       },
       "description": {
-        "fields": {
-          "additional_fields": "must be provided in form of a JSON-Schema. You can add here fields you want to know from people signing up going further than their email-address",
-          "spots": "For no limit, set to '0'. If no signup required, set to '-1'. Otherwise just provide an integer.",
-          "allow_email_signup": "If False, only AMIV-Members can sign up for this event",
-          "price": "Price of the event as Integer in Rappen."
-        },
-        "methods": {
-          "GET": "You are always allowed, even without session, to view AMIV-Events"
-        },
-        "general": "An Event is basically everything happening in the AMIV. All time fields have the format YYYY-MM-DDThh:mmZ, e.g. 2014-12-20T11:50:06Z"
+        "fields": {},
+        "general": "A Job Offer posts repositoryUsers can post a job offer with the necessarycontent to fill out a job offer advertisement"
       }
     },
-    "groups": {
+    "eventsignups": {
       "paths": {
-        "/groups": {
-          "GET": {
-            "label": "Retrieve all groups",
-            "params": []
-          },
-          "POST": {
-            "label": "Create a Group",
+        "/eventsignups/{_id}": {
+          "PATCH": {
             "params": [
               {
-                "type": "list",
-                "required": false,
-                "unique_elements": true,
-                "schema": {
-                  "regex": "^.+@.+$",
-                  "maxlength": 100,
-                  "type": "string"
-                },
-                "name": "forward_to"
+                "required": true,
+                "type": "string",
+                "name": "_id"
               },
               {
-                "nullable": true,
-                "propertyschema": {
-                  "api_resources": true,
-                  "type": "string"
-                },
-                "valueschema": {
-                  "allowed": [
-                    "read",
-                    "readwrite"
-                  ],
-                  "type": "string"
-                },
                 "required": false,
-                "name": "permissions",
-                "type": "dict"
+                "type": "json_event_field",
+                "name": "additional_fields",
+                "nullable": true
               },
               {
-                "type": "objectid",
+                "readonly": true,
+                "name": "confirmed",
+                "nullable": true,
                 "required": false,
-                "name": "_id"
+                "type": "boolean"
               },
               {
-                "nullable": true,
-                "type": "objectid",
-                "required": false,
+                "signup_requirements": true,
+                "name": "event",
+                "unique_combination": [
+                  "user",
+                  "email"
+                ],
+                "required": true,
+                "not_patchable": true,
                 "data_relation": {
                   "field": "_id",
-                  "resource": "users"
+                  "resource": "events",
+                  "embeddable": true
                 },
-                "name": "moderator"
+                "type": "objectid"
               },
               {
-                "unique_elements_for_resource": true,
+                "name": "user",
+                "nullable": false,
                 "required": false,
-                "name": "receive_from",
-                "unique_elements": true,
-                "schema": {
-                  "regex": "[a-z0-9_\\.-]+",
-                  "maxlength": 100,
-                  "type": "string"
+                "not_patchable": true,
+                "data_relation": {
+                  "field": "_id",
+                  "resource": "users",
+                  "embeddable": true
                 },
-                "type": "list"
+                "only_self_enrollment_for_event": true,
+                "type": "objectid"
               },
               {
-                "type": "boolean",
                 "required": false,
-                "default": false,
-                "name": "allow_self_enrollment"
+                "type": "objectid",
+                "name": "_id"
               },
               {
-                "type": "boolean",
+                "regex": "^.+@.+$",
+                "name": "email",
+                "email_signup_must_be_allowed": true,
+                "nullable": false,
                 "required": false,
-                "default": false,
-                "name": "has_zoidberg_share"
-              },
-              {
+                "not_patchable": true,
                 "maxlength": 100,
-                "unique": true,
-                "type": "string",
-                "required": true,
-                "empty": false,
-                "name": "name"
+                "type": "string"
               }
-            ]
-          }
-        },
-        "/groups/{_id}": {
+            ],
+            "label": "Update a Eventsignup"
+          },
           "DELETE": {
-            "label": "Delete a Group",
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               }
-            ]
+            ],
+            "label": "Delete a Eventsignup"
           },
           "GET": {
-            "label": "Retrieve a Group",
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               }
-            ]
-          },
-          "PATCH": {
-            "label": "Update a Group",
+            ],
+            "label": "Retrieve a Eventsignup"
+          }
+        },
+        "/eventsignups": {
+          "POST": {
             "params": [
               {
-                "type": "string",
-                "required": true,
-                "name": "_id"
-              },
-              {
-                "type": "list",
                 "required": false,
-                "unique_elements": true,
-                "schema": {
-                  "regex": "^.+@.+$",
-                  "maxlength": 100,
-                  "type": "string"
-                },
-                "name": "forward_to"
+                "type": "json_event_field",
+                "name": "additional_fields",
+                "nullable": true
               },
               {
+                "readonly": true,
+                "name": "confirmed",
                 "nullable": true,
-                "propertyschema": {
-                  "api_resources": true,
-                  "type": "string"
-                },
-                "valueschema": {
-                  "allowed": [
-                    "read",
-                    "readwrite"
-                  ],
-                  "type": "string"
-                },
-                "required": false,
-                "name": "permissions",
-                "type": "dict"
-              },
-              {
-                "type": "objectid",
                 "required": false,
-                "name": "_id"
+                "type": "boolean"
               },
               {
-                "nullable": true,
-                "type": "objectid",
-                "required": false,
+                "signup_requirements": true,
+                "name": "event",
+                "unique_combination": [
+                  "user",
+                  "email"
+                ],
+                "required": true,
+                "not_patchable": true,
                 "data_relation": {
                   "field": "_id",
-                  "resource": "users"
+                  "resource": "events",
+                  "embeddable": true
                 },
-                "name": "moderator"
+                "type": "objectid"
               },
               {
-                "unique_elements_for_resource": true,
+                "name": "user",
+                "nullable": false,
                 "required": false,
-                "name": "receive_from",
-                "unique_elements": true,
-                "schema": {
-                  "regex": "[a-z0-9_\\.-]+",
-                  "maxlength": 100,
-                  "type": "string"
+                "not_patchable": true,
+                "data_relation": {
+                  "field": "_id",
+                  "resource": "users",
+                  "embeddable": true
                 },
-                "type": "list"
+                "only_self_enrollment_for_event": true,
+                "type": "objectid"
               },
               {
-                "type": "boolean",
                 "required": false,
-                "default": false,
-                "name": "allow_self_enrollment"
+                "type": "objectid",
+                "name": "_id"
               },
               {
-                "type": "boolean",
+                "regex": "^.+@.+$",
+                "name": "email",
+                "email_signup_must_be_allowed": true,
+                "nullable": false,
                 "required": false,
-                "default": false,
-                "name": "has_zoidberg_share"
-              },
-              {
+                "not_patchable": true,
                 "maxlength": 100,
-                "unique": true,
-                "type": "string",
-                "required": true,
-                "empty": false,
-                "name": "name"
+                "type": "string"
               }
-            ]
+            ],
+            "label": "Create a Eventsignup"
+          },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all eventsignups"
           }
         }
       },
       "description": {
         "fields": {
-          "permissions": "permissions the group grants. has to be according to the jsonschema available at /notyetavailable",
-          "allow_self_enrollment": "If true, the group can be seen by all users and they can subscribe themselves",
-          "has_zoidberg_share": "If the group has a share in the amiv storage"
+          "additional_fields": "Data-schema depends on 'additional_fields' from the mapped event. Please provide in json-format.",
+          "email": "For registered users, this is just a projection of your general email-address. External users need to provide their email here.",
+          "user": "Provide either user or email."
         },
-        "general": "This resource describes the different teams in AMIV.A group can grant API permissions and can be reached with several addresses. To see the addresses of this group, see /groupaddressesTo see the members, have a look at '/groupmembers'. To see the addresses messages are forwarded to, see /groupforwards"
+        "methods": {
+          "PATCH": "Only additional_fields can be changed"
+        },
+        "general": "You can signup here for an existing event inside of the registration-window. External Users can only sign up to public events."
       }
     },
-    "sessions": {
+    "groups": {
       "paths": {
-        "/sessions": {
-          "DELETE": {
-            "label": "Delete all sessions",
-            "params": []
-          },
-          "GET": {
-            "label": "Retrieve all sessions",
-            "params": []
-          },
+        "/groups": {
           "POST": {
-            "label": "Create a Session",
             "params": [
               {
-                "nullable": false,
-                "empty": false,
+                "name": "name",
                 "required": true,
-                "name": "username",
-                "type": "string"
+                "maxlength": 100,
+                "unique": true,
+                "type": "string",
+                "empty": false
               },
               {
-                "readonly": true,
-                "type": "objectid",
+                "default": false,
+                "required": false,
+                "type": "boolean",
+                "name": "has_zoidberg_share"
+              },
+              {
+                "default": false,
                 "required": false,
+                "type": "boolean",
+                "name": "allow_self_enrollment"
+              },
+              {
+                "name": "moderator",
                 "data_relation": {
-                  "cascade_delete": true,
                   "field": "_id",
-                  "embeddable": true,
                   "resource": "users"
                 },
-                "name": "user"
+                "nullable": true,
+                "required": false,
+                "type": "objectid"
+              },
+              {
+                "name": "forward_to",
+                "unique_elements": true,
+                "required": false,
+                "type": "list",
+                "schema": {
+                  "regex": "^.+@.+$",
+                  "type": "string",
+                  "maxlength": 100
+                }
+              },
+              {
+                "name": "receive_from",
+                "unique_elements": true,
+                "unique_elements_for_resource": true,
+                "required": false,
+                "type": "list",
+                "schema": {
+                  "regex": "[a-z0-9_\\.-]+",
+                  "type": "string",
+                  "maxlength": 100
+                }
               },
               {
+                "required": false,
                 "type": "objectid",
+                "name": "_id"
+              },
+              {
+                "propertyschema": {
+                  "api_resources": true,
+                  "type": "string"
+                },
+                "name": "permissions",
+                "nullable": true,
                 "required": false,
+                "type": "dict",
+                "valueschema": {
+                  "type": "string",
+                  "allowed": [
+                    "read",
+                    "readwrite"
+                  ]
+                }
+              }
+            ],
+            "label": "Create a Group"
+          },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all groups"
+          }
+        },
+        "/groups/{_id}": {
+          "PATCH": {
+            "params": [
+              {
+                "required": true,
+                "type": "string",
                 "name": "_id"
               },
               {
-                "readonly": true,
+                "name": "name",
+                "required": true,
+                "maxlength": 100,
+                "unique": true,
                 "type": "string",
+                "empty": false
+              },
+              {
+                "default": false,
                 "required": false,
-                "name": "token"
+                "type": "boolean",
+                "name": "has_zoidberg_share"
               },
               {
-                "nullable": false,
-                "empty": false,
-                "required": true,
-                "name": "password",
-                "type": "string"
+                "default": false,
+                "required": false,
+                "type": "boolean",
+                "name": "allow_self_enrollment"
+              },
+              {
+                "name": "moderator",
+                "data_relation": {
+                  "field": "_id",
+                  "resource": "users"
+                },
+                "nullable": true,
+                "required": false,
+                "type": "objectid"
+              },
+              {
+                "name": "forward_to",
+                "unique_elements": true,
+                "required": false,
+                "type": "list",
+                "schema": {
+                  "regex": "^.+@.+$",
+                  "type": "string",
+                  "maxlength": 100
+                }
+              },
+              {
+                "name": "receive_from",
+                "unique_elements": true,
+                "unique_elements_for_resource": true,
+                "required": false,
+                "type": "list",
+                "schema": {
+                  "regex": "[a-z0-9_\\.-]+",
+                  "type": "string",
+                  "maxlength": 100
+                }
+              },
+              {
+                "required": false,
+                "type": "objectid",
+                "name": "_id"
+              },
+              {
+                "propertyschema": {
+                  "api_resources": true,
+                  "type": "string"
+                },
+                "name": "permissions",
+                "nullable": true,
+                "required": false,
+                "type": "dict",
+                "valueschema": {
+                  "type": "string",
+                  "allowed": [
+                    "read",
+                    "readwrite"
+                  ]
+                }
               }
-            ]
-          }
-        },
-        "/sessions/{_id}": {
+            ],
+            "label": "Update a Group"
+          },
           "DELETE": {
-            "label": "Delete a Session",
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               }
-            ]
+            ],
+            "label": "Delete a Group"
           },
           "GET": {
-            "label": "Retrieve a Session",
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               }
-            ]
+            ],
+            "label": "Retrieve a Group"
+          }
+        },
+        "/groups/{name}": {
+          "GET": {
+            "params": [
+              {
+                "name": "name",
+                "required": true,
+                "maxlength": 100,
+                "unique": true,
+                "type": "string",
+                "empty": false
+              }
+            ],
+            "label": "Retrieve a Group"
           }
         }
       },
       "description": {
-        "methods": {
-          "GET": "Check token(s).",
-          "POST": "Login and aquire a login token. Post the fields 'username' and 'password', the response will contain the token. username can be either nethz, mail, or user_id"
+        "fields": {
+          "has_zoidberg_share": "If the group has a share in the amiv storage",
+          "allow_self_enrollment": "If true, the group can be seen by all users and they can subscribe themselves",
+          "permissions": "permissions the group grants. has to be according to the jsonschema available at /notyetavailable"
         },
-        "general": "A session is used to authenticate a user after he  provided login data. A POST to /session will return a token you can use in an Authorization header: token <yourtoken>"
+        "general": "This resource describes the different teams in AMIV.A group can grant API permissions and can be reached with several addresses. To see the addresses of this group, see /groupaddressesTo see the members, have a look at '/groupmembers'. To see the addresses messages are forwarded to, see /groupforwards"
       }
     },
-    "joboffers": {
+    "studydocuments": {
       "paths": {
-        "/joboffers/{_id}": {
-          "DELETE": {
-            "label": "Delete a Joboffer",
+        "/studydocuments/{_id}": {
+          "PATCH": {
             "params": [
               {
-                "type": "string",
                 "required": true,
-                "name": "_id"
-              }
-            ]
-          },
-          "GET": {
-            "label": "Retrieve a Joboffer",
-            "params": [
-              {
                 "type": "string",
-                "required": true,
                 "name": "_id"
-              }
-            ]
-          },
-          "PATCH": {
-            "label": "Update a Joboffer",
-            "params": [
+              },
               {
-                "type": "string",
+                "name": "files",
                 "required": true,
-                "name": "_id"
+                "type": "list",
+                "schema": {
+                  "type": "media"
+                }
               },
               {
                 "nullable": true,
-                "type": "string",
+                "name": "author",
+                "maxlength": 100,
                 "required": false,
-                "name": "description_en"
+                "type": "string"
               },
               {
-                "type": "objectid",
+                "nullable": true,
+                "name": "professor",
+                "maxlength": 100,
                 "required": false,
-                "name": "_id"
+                "type": "string"
               },
               {
-                "type": "media",
+                "name": "title",
+                "maxlength": 100,
                 "required": false,
-                "filetype": [
-                  "pdf"
-                ],
-                "name": "pdf"
+                "type": "string",
+                "empty": false
               },
               {
-                "nullable": true,
-                "maxlength": 30,
-                "type": "string",
-                "depends_any": [
-                  "title_de",
-                  "title_en"
+                "allowed": [
+                  "1",
+                  "2",
+                  "3",
+                  "4",
+                  "5+"
                 ],
-                "required": true,
-                "name": "company"
+                "name": "semester",
+                "nullable": true,
+                "required": false,
+                "type": "string"
               },
               {
+                "readonly": true,
+                "name": "uploader",
+                "data_relation": {
+                  "field": "_id",
+                  "resource": "users"
+                },
                 "nullable": true,
-                "type": "string",
                 "required": false,
-                "name": "title_de"
+                "type": "objectid"
               },
               {
+                "allowed": [
+                  "itet",
+                  "mavt",
+                  "arch",
+                  "baug",
+                  "bsse",
+                  "infk",
+                  "matl",
+                  "biol",
+                  "chab",
+                  "math",
+                  "phys",
+                  "erdw",
+                  "usys",
+                  "hest",
+                  "mtec",
+                  "gess"
+                ],
+                "name": "department",
                 "nullable": true,
-                "type": "string",
                 "required": false,
-                "name": "title_en"
+                "type": "string"
               },
               {
                 "nullable": true,
-                "type": "datetime",
+                "name": "lecture",
+                "maxlength": 100,
                 "required": false,
-                "name": "time_end"
+                "type": "string"
               },
               {
-                "type": "media",
                 "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "logo"
+                "type": "integer",
+                "name": "course_year"
               },
               {
-                "nullable": true,
-                "unique": false,
-                "type": "string",
                 "required": false,
-                "name": "description_de"
+                "type": "objectid",
+                "name": "_id"
+              },
+              {
+                "required": false,
+                "type": "string",
+                "name": "type",
+                "allowed": [
+                  "exams",
+                  "cheat sheets",
+                  "lecture documents",
+                  "exercises"
+                ]
               }
-            ]
-          }
-        },
-        "/joboffers": {
-          "GET": {
-            "label": "Retrieve all joboffers",
-            "params": []
+            ],
+            "label": "Update a Studydocument"
           },
-          "POST": {
-            "label": "Create a Joboffer",
+          "DELETE": {
             "params": [
               {
-                "nullable": true,
+                "required": true,
                 "type": "string",
-                "required": false,
-                "name": "description_en"
-              },
+                "name": "_id"
+              }
+            ],
+            "label": "Delete a Studydocument"
+          },
+          "GET": {
+            "params": [
               {
-                "type": "objectid",
-                "required": false,
+                "required": true,
+                "type": "string",
                 "name": "_id"
+              }
+            ],
+            "label": "Retrieve a Studydocument"
+          }
+        },
+        "/studydocuments": {
+          "POST": {
+            "params": [
+              {
+                "name": "files",
+                "required": true,
+                "type": "list",
+                "schema": {
+                  "type": "media"
+                }
               },
               {
-                "type": "media",
+                "nullable": true,
+                "name": "author",
+                "maxlength": 100,
                 "required": false,
-                "filetype": [
-                  "pdf"
-                ],
-                "name": "pdf"
+                "type": "string"
               },
               {
                 "nullable": true,
-                "maxlength": 30,
+                "name": "professor",
+                "maxlength": 100,
+                "required": false,
+                "type": "string"
+              },
+              {
+                "name": "title",
+                "maxlength": 100,
+                "required": false,
                 "type": "string",
-                "depends_any": [
-                  "title_de",
-                  "title_en"
+                "empty": false
+              },
+              {
+                "allowed": [
+                  "1",
+                  "2",
+                  "3",
+                  "4",
+                  "5+"
                 ],
-                "required": true,
-                "name": "company"
+                "name": "semester",
+                "nullable": true,
+                "required": false,
+                "type": "string"
               },
               {
+                "readonly": true,
+                "name": "uploader",
+                "data_relation": {
+                  "field": "_id",
+                  "resource": "users"
+                },
                 "nullable": true,
-                "type": "string",
                 "required": false,
-                "name": "title_de"
+                "type": "objectid"
               },
               {
+                "allowed": [
+                  "itet",
+                  "mavt",
+                  "arch",
+                  "baug",
+                  "bsse",
+                  "infk",
+                  "matl",
+                  "biol",
+                  "chab",
+                  "math",
+                  "phys",
+                  "erdw",
+                  "usys",
+                  "hest",
+                  "mtec",
+                  "gess"
+                ],
+                "name": "department",
                 "nullable": true,
-                "type": "string",
                 "required": false,
-                "name": "title_en"
+                "type": "string"
               },
               {
                 "nullable": true,
-                "type": "datetime",
+                "name": "lecture",
+                "maxlength": 100,
                 "required": false,
-                "name": "time_end"
+                "type": "string"
               },
               {
-                "type": "media",
                 "required": false,
-                "filetype": [
-                  "png",
-                  "jpeg"
-                ],
-                "name": "logo"
+                "type": "integer",
+                "name": "course_year"
               },
               {
-                "nullable": true,
-                "unique": false,
-                "type": "string",
                 "required": false,
-                "name": "description_de"
+                "type": "objectid",
+                "name": "_id"
+              },
+              {
+                "required": false,
+                "type": "string",
+                "name": "type",
+                "allowed": [
+                  "exams",
+                  "cheat sheets",
+                  "lecture documents",
+                  "exercises"
+                ]
               }
-            ]
+            ],
+            "label": "Create a Studydocument"
+          },
+          "DELETE": {
+            "params": [],
+            "label": "Delete all studydocuments"
+          },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all studydocuments"
           }
         }
       },
       "description": {
-        "fields": {},
-        "general": "A Job Offer posts repositoryUsers can post a job offer with the necessarycontent to fill out a job offer advertisement"
+        "fields": {
+          "semester": "Study-Semester as an Integer starting with first semester Bachelor.",
+          "course_year": "Course Year",
+          "uploader": "Read-only field describing which AMIV member uploaded the files",
+          "author": "Original author of the uploaded files(Prof, Assistant, copyright owner)"
+        },
+        "general": "Study-documents are basically all documents that are connected to a course. All metadata is optional and intended to help finding the file. There are no strict categories, as those do not work well for courses available to many departements and aiming at all levels of experience."
       }
     },
-    "studydocuments": {
+    "events": {
       "paths": {
-        "/studydocuments": {
-          "DELETE": {
-            "label": "Delete all studydocuments",
-            "params": []
-          },
-          "GET": {
-            "label": "Retrieve all studydocuments",
-            "params": []
-          },
+        "/events": {
           "POST": {
-            "label": "Create a Studydocument",
             "params": [
               {
+                "name": "title_de",
+                "required_if_not": "title_en",
                 "nullable": true,
-                "maxlength": 100,
-                "type": "string",
                 "required": false,
-                "name": "lecture"
+                "dependencies": [
+                  "catchphrase_de",
+                  "description_de"
+                ],
+                "maxlength": 100,
+                "type": "string"
               },
               {
+                "name": "time_register_start",
                 "nullable": true,
-                "type": "integer",
+                "only_if_not_null": "spots",
                 "required": false,
-                "name": "semester"
+                "dependencies": [
+                  "time_register_end"
+                ],
+                "type": "datetime",
+                "earlier_than": "time_register_end"
               },
               {
-                "type": "list",
-                "required": true,
-                "schema": {
-                  "type": "media"
-                },
-                "name": "files"
+                "readonly": true,
+                "required": false,
+                "type": "integer",
+                "name": "signup_count"
               },
               {
-                "nullable": true,
-                "maxlength": 4,
-                "type": "string",
+                "filetype": [
+                  "png",
+                  "jpeg"
+                ],
                 "required": false,
-                "name": "department"
+                "type": "media",
+                "name": "img_thumbnail"
               },
               {
+                "dependencies": [
+                  "time_start"
+                ],
+                "name": "time_end",
                 "nullable": true,
-                "maxlength": 5,
-                "type": "string",
+                "later_than": "time_start",
                 "required": false,
-                "name": "coursesemester"
+                "type": "datetime"
               },
               {
-                "nullable": true,
-                "maxlength": 100,
-                "type": "string",
+                "name": "allow_email_signup",
+                "nullable": false,
+                "default": false,
+                "only_if_not_null": "spots",
                 "required": false,
-                "name": "professor"
+                "type": "boolean"
               },
               {
                 "nullable": true,
-                "maxlength": 100,
-                "type": "string",
+                "dependencies": [
+                  "time_register_start",
+                  "time_register_end"
+                ],
+                "name": "spots",
+                "min": 0,
                 "required": false,
-                "name": "author"
+                "type": "integer"
               },
               {
+                "name": "description_de",
                 "nullable": true,
-                "maxlength": 100,
-                "type": "string",
                 "required": false,
-                "name": "name"
+                "type": "string",
+                "maxlength": 10000
               },
               {
+                "name": "time_register_end",
                 "nullable": true,
-                "readonly": true,
-                "data_relation": {
-                  "field": "_id",
-                  "resource": "users"
-                },
+                "later_than": "time_register_start",
                 "required": false,
-                "name": "uploader",
-                "type": "objectid"
+                "dependencies": [
+                  "time_register_start"
+                ],
+                "type": "datetime",
+                "only_if_not_null": "spots"
               },
               {
-                "type": "objectid",
+                "filetype": [
+                  "png",
+                  "jpeg"
+                ],
                 "required": false,
-                "name": "_id"
+                "type": "media",
+                "name": "img_banner"
               },
               {
+                "dependencies": [
+                  "time_end"
+                ],
+                "name": "time_start",
                 "nullable": true,
-                "maxlength": 30,
-                "type": "string",
                 "required": false,
-                "name": "type"
-              }
-            ]
-          }
-        },
-        "/studydocuments/{_id}": {
-          "DELETE": {
-            "label": "Delete a Studydocument",
-            "params": [
-              {
-                "type": "string",
-                "required": true,
-                "name": "_id"
-              }
-            ]
-          },
-          "GET": {
-            "label": "Retrieve a Studydocument",
-            "params": [
+                "type": "datetime",
+                "earlier_than": "time_end"
+              },
               {
+                "name": "catchphrase_en",
+                "nullable": true,
+                "required": false,
                 "type": "string",
-                "required": true,
-                "name": "_id"
-              }
-            ]
-          },
-          "PATCH": {
-            "label": "Update a Studydocument",
-            "params": [
+                "maxlength": 500
+              },
               {
-                "type": "string",
+                "name": "priority",
+                "min": 0,
+                "default": 5,
+                "max": 10,
                 "required": true,
-                "name": "_id"
+                "type": "integer"
               },
               {
                 "nullable": true,
-                "maxlength": 100,
-                "type": "string",
+                "name": "location",
+                "maxlength": 50,
                 "required": false,
-                "name": "lecture"
+                "type": "string"
               },
               {
-                "nullable": true,
-                "type": "integer",
+                "name": "show_infoscreen",
+                "nullable": false,
+                "default": false,
                 "required": false,
-                "name": "semester"
-              },
-              {
-                "type": "list",
-                "required": true,
-                "schema": {
-                  "type": "media"
-                },
-                "name": "files"
+                "type": "boolean"
               },
               {
+                "name": "additional_fields",
                 "nullable": true,
-                "maxlength": 4,
-                "type": "string",
+                "only_if_not_null": "spots",
                 "required": false,
-                "name": "department"
+                "type": "json_schema"
               },
               {
-                "nullable": true,
-                "maxlength": 5,
-                "type": "string",
+                "filetype": [
+                  "png",
+                  "jpeg"
+                ],
                 "required": false,
-                "name": "coursesemester"
+                "type": "media",
+                "name": "img_infoscreen"
               },
               {
                 "nullable": true,
-                "maxlength": 100,
-                "type": "string",
+                "name": "price",
+                "min": 0,
                 "required": false,
-                "name": "professor"
+                "type": "integer"
               },
               {
+                "name": "title_en",
+                "required_if_not": "title_de",
                 "nullable": true,
-                "maxlength": 100,
-                "type": "string",
                 "required": false,
-                "name": "author"
+                "dependencies": [
+                  "catchphrase_en",
+                  "description_en"
+                ],
+                "maxlength": 100,
+                "type": "string"
               },
               {
+                "name": "description_en",
                 "nullable": true,
-                "maxlength": 100,
-                "type": "string",
                 "required": false,
-                "name": "name"
+                "type": "string",
+                "maxlength": 10000
               },
               {
-                "nullable": true,
-                "readonly": true,
-                "data_relation": {
-                  "field": "_id",
-                  "resource": "users"
-                },
-                "required": false,
-                "name": "uploader",
-                "type": "objectid"
+                "name": "time_advertising_end",
+                "nullable": false,
+                "later_than": "time_advertising_start",
+                "required": true,
+                "type": "datetime"
               },
               {
-                "type": "objectid",
+                "filetype": [
+                  "png",
+                  "jpeg"
+                ],
                 "required": false,
-                "name": "_id"
+                "type": "media",
+                "name": "img_poster"
               },
               {
-                "nullable": true,
-                "maxlength": 30,
-                "type": "string",
+                "name": "show_announce",
+                "nullable": false,
+                "default": false,
                 "required": false,
-                "name": "type"
-              }
-            ]
-          }
-        }
-      },
-      "description": {
-        "fields": {
-          "author": "Original author of the uploaded files(Prof, Assistant, copyright owner)",
-          "semester": "Study-Semester as an Integer starting with first semester Bachelor.",
-          "uploader": "Read-only field describing which AMIV member uploaded the files",
-          "coursesemester": "Course Semester as Enum(HS/FS)+Integer"
-        },
-        "general": "Study-documents are basically all documents that are connected to a course. All metadata is optional and intended to help finding the file. There are no strict categories, as those do not work well for courses available to many departements and aiming at all levels of experience."
-      }
-    },
-    "users": {
-      "paths": {
-        "/users/{nethz}": {
-          "GET": {
-            "label": "Retrieve a User",
-            "params": [
+                "type": "boolean"
+              },
               {
-                "nullable": true,
-                "maxlength": 30,
-                "default": null,
-                "unique": true,
-                "type": "string",
+                "name": "time_advertising_start",
+                "nullable": false,
+                "required": true,
+                "type": "datetime",
+                "earlier_than": "time_advertising_end"
+              },
+              {
+                "name": "show_website",
+                "nullable": false,
+                "default": false,
                 "required": false,
-                "not_patchable_unless_admin": true,
-                "empty": false,
-                "name": "nethz"
-              }
-            ]
-          }
-        },
-        "/users/{_id}": {
-          "DELETE": {
-            "label": "Delete a User",
-            "params": [
+                "type": "boolean"
+              },
               {
+                "name": "catchphrase_de",
+                "nullable": true,
+                "required": false,
                 "type": "string",
-                "required": true,
-                "name": "_id"
-              }
-            ]
-          },
-          "GET": {
-            "label": "Retrieve a User",
-            "params": [
+                "maxlength": 500
+              },
               {
-                "type": "string",
-                "required": true,
+                "required": false,
+                "type": "objectid",
                 "name": "_id"
               }
-            ]
+            ],
+            "label": "Create a Event"
           },
+          "GET": {
+            "params": [],
+            "label": "Retrieve all events"
+          }
+        },
+        "/events/{_id}": {
           "PATCH": {
-            "label": "Update a User",
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               },
               {
+                "name": "title_de",
+                "required_if_not": "title_en",
                 "nullable": true,
-                "maxlength": 30,
-                "default": null,
-                "unique": true,
-                "type": "string",
                 "required": false,
-                "not_patchable_unless_admin": true,
-                "empty": false,
-                "name": "nethz"
-              },
-              {
+                "dependencies": [
+                  "catchphrase_de",
+                  "description_de"
+                ],
                 "maxlength": 100,
-                "unique": true,
-                "type": "string",
-                "required": true,
-                "regex": "^.+@.+$",
-                "name": "email"
+                "type": "string"
               },
               {
+                "name": "time_register_start",
                 "nullable": true,
-                "empty": false,
-                "maxlength": 20,
+                "only_if_not_null": "spots",
                 "required": false,
-                "name": "phone",
-                "type": "string"
-              },
-              {
-                "not_patchable_unless_admin": true,
-                "allowed": [
-                  "male",
-                  "female"
+                "dependencies": [
+                  "time_register_end"
                 ],
-                "unique": false,
-                "type": "string",
-                "required": true,
-                "maxlength": 6,
-                "name": "gender"
+                "type": "datetime",
+                "earlier_than": "time_register_end"
               },
               {
-                "type": "objectid",
+                "readonly": true,
                 "required": false,
-                "name": "_id"
+                "type": "integer",
+                "name": "signup_count"
               },
               {
-                "nullable": false,
-                "maxlength": 50,
-                "type": "string",
-                "required": true,
-                "not_patchable_unless_admin": true,
-                "empty": false,
-                "name": "firstname"
+                "filetype": [
+                  "png",
+                  "jpeg"
+                ],
+                "required": false,
+                "type": "media",
+                "name": "img_thumbnail"
               },
               {
+                "dependencies": [
+                  "time_start"
+                ],
+                "name": "time_end",
                 "nullable": true,
-                "maxlength": 8,
-                "unique": true,
-                "type": "string",
+                "later_than": "time_start",
                 "required": false,
-                "not_patchable_unless_admin": true,
-                "name": "legi"
+                "type": "datetime"
               },
               {
-                "nullable": true,
-                "not_patchable_unless_admin": true,
+                "name": "allow_email_signup",
+                "nullable": false,
+                "default": false,
+                "only_if_not_null": "spots",
                 "required": false,
-                "allowed": [
-                  "itet",
-                  "mavt"
-                ],
-                "name": "department",
-                "type": "string"
+                "type": "boolean"
               },
               {
                 "nullable": true,
-                "type": "boolean",
+                "dependencies": [
+                  "time_register_start",
+                  "time_register_end"
+                ],
+                "name": "spots",
+                "min": 0,
                 "required": false,
-                "name": "send_newsletter"
+                "type": "integer"
               },
               {
+                "name": "description_de",
                 "nullable": true,
-                "maxlength": 100,
-                "default": null,
-                "type": "string",
                 "required": false,
-                "empty": false,
-                "name": "password"
+                "type": "string",
+                "maxlength": 10000
               },
               {
-                "nullable": false,
-                "maxlength": 50,
-                "type": "string",
-                "required": true,
-                "not_patchable_unless_admin": true,
-                "empty": false,
-                "name": "lastname"
+                "name": "time_register_end",
+                "nullable": true,
+                "later_than": "time_register_start",
+                "required": false,
+                "dependencies": [
+                  "time_register_start"
+                ],
+                "type": "datetime",
+                "only_if_not_null": "spots"
               },
               {
-                "maxlength": 13,
-                "allowed": [
-                  "none",
-                  "regular",
-                  "extraordinary",
-                  "honorary"
+                "filetype": [
+                  "png",
+                  "jpeg"
                 ],
-                "unique": false,
-                "type": "string",
-                "required": true,
-                "not_patchable_unless_admin": true,
-                "name": "membership"
+                "required": false,
+                "type": "media",
+                "name": "img_banner"
               },
               {
+                "dependencies": [
+                  "time_end"
+                ],
+                "name": "time_start",
                 "nullable": true,
-                "maxlength": 6,
-                "unique": true,
-                "type": "string",
                 "required": false,
-                "empty": false,
-                "name": "rfid"
-              }
-            ]
-          }
-        },
-        "/users": {
-          "GET": {
-            "label": "Retrieve all users",
-            "params": []
-          },
-          "POST": {
-            "label": "Create a User",
-            "params": [
+                "type": "datetime",
+                "earlier_than": "time_end"
+              },
               {
+                "name": "catchphrase_en",
                 "nullable": true,
-                "maxlength": 30,
-                "default": null,
-                "unique": true,
-                "type": "string",
                 "required": false,
-                "not_patchable_unless_admin": true,
-                "empty": false,
-                "name": "nethz"
+                "type": "string",
+                "maxlength": 500
               },
               {
-                "maxlength": 100,
-                "unique": true,
-                "type": "string",
+                "name": "priority",
+                "min": 0,
+                "default": 5,
+                "max": 10,
                 "required": true,
-                "regex": "^.+@.+$",
-                "name": "email"
+                "type": "integer"
               },
               {
                 "nullable": true,
-                "empty": false,
-                "maxlength": 20,
+                "name": "location",
+                "maxlength": 50,
                 "required": false,
-                "name": "phone",
                 "type": "string"
               },
               {
-                "not_patchable_unless_admin": true,
-                "allowed": [
-                  "male",
-                  "female"
-                ],
-                "unique": false,
-                "type": "string",
-                "required": true,
-                "maxlength": 6,
-                "name": "gender"
+                "name": "show_infoscreen",
+                "nullable": false,
+                "default": false,
+                "required": false,
+                "type": "boolean"
               },
               {
-                "type": "objectid",
+                "name": "additional_fields",
+                "nullable": true,
+                "only_if_not_null": "spots",
                 "required": false,
-                "name": "_id"
+                "type": "json_schema"
               },
               {
-                "nullable": false,
-                "maxlength": 50,
-                "type": "string",
-                "required": true,
-                "not_patchable_unless_admin": true,
-                "empty": false,
-                "name": "firstname"
+                "filetype": [
+                  "png",
+                  "jpeg"
+                ],
+                "required": false,
+                "type": "media",
+                "name": "img_infoscreen"
               },
               {
                 "nullable": true,
-                "maxlength": 8,
-                "unique": true,
-                "type": "string",
+                "name": "price",
+                "min": 0,
                 "required": false,
-                "not_patchable_unless_admin": true,
-                "name": "legi"
+                "type": "integer"
               },
               {
+                "name": "title_en",
+                "required_if_not": "title_de",
                 "nullable": true,
-                "not_patchable_unless_admin": true,
                 "required": false,
-                "allowed": [
-                  "itet",
-                  "mavt"
-                ],
-                "name": "department",
+                "dependencies": [
+                  "catchphrase_en",
+                  "description_en"
+                ],
+                "maxlength": 100,
                 "type": "string"
               },
               {
+                "name": "description_en",
                 "nullable": true,
-                "type": "boolean",
                 "required": false,
-                "name": "send_newsletter"
-              },
-              {
-                "nullable": true,
-                "maxlength": 100,
-                "default": null,
                 "type": "string",
-                "required": false,
-                "empty": false,
-                "name": "password"
+                "maxlength": 10000
               },
               {
+                "name": "time_advertising_end",
                 "nullable": false,
-                "maxlength": 50,
-                "type": "string",
+                "later_than": "time_advertising_start",
                 "required": true,
-                "not_patchable_unless_admin": true,
-                "empty": false,
-                "name": "lastname"
+                "type": "datetime"
               },
               {
-                "maxlength": 13,
-                "allowed": [
-                  "none",
-                  "regular",
-                  "extraordinary",
-                  "honorary"
+                "filetype": [
+                  "png",
+                  "jpeg"
                 ],
-                "unique": false,
-                "type": "string",
-                "required": true,
-                "not_patchable_unless_admin": true,
-                "name": "membership"
-              },
-              {
-                "nullable": true,
-                "maxlength": 6,
-                "unique": true,
-                "type": "string",
                 "required": false,
-                "empty": false,
-                "name": "rfid"
-              }
-            ]
-          }
-        }
-      },
-      "description": {
-        "methods": {
-          "GET": "Authorization is required for most of the fields"
-        },
-        "general": "In general, the user data will be generated from LDAP-Data. However, one might change the RFID-Number or the membership-status. Extraordinary members may not have a LDAP-Account and can therefore access all given fields."
-      }
-    },
-    "purchases": {
-      "paths": {
-        "/purchases": {
-          "GET": {
-            "label": "Retrieve all purchases",
-            "params": []
-          },
-          "POST": {
-            "label": "Create a Purchase",
-            "params": [
-              {
-                "type": "objectid",
-                "required": false,
-                "name": "_id"
+                "type": "media",
+                "name": "img_poster"
               },
               {
+                "name": "show_announce",
                 "nullable": false,
-                "unique": false,
-                "required": true,
-                "name": "timestamp",
-                "type": "datetime"
+                "default": false,
+                "required": false,
+                "type": "boolean"
               },
               {
+                "name": "time_advertising_start",
                 "nullable": false,
-                "not_patchable_unless_admin": true,
-                "allowed": [
-                  "beer",
-                  "coffee"
-                ],
-                "unique": false,
-                "type": "string",
                 "required": true,
-                "maxlength": 6,
-                "name": "product"
+                "type": "datetime",
+                "earlier_than": "time_advertising_end"
               },
               {
+                "name": "show_website",
                 "nullable": false,
-                "data_relation": {
-                  "field": "_id",
-                  "embeddable": true,
-                  "resource": "users"
-                },
-                "unique": false,
-                "type": "objectid",
-                "required": true,
-                "name": "user"
-              }
-            ]
-          }
-        },
-        "/purchases/{_id}": {
-          "GET": {
-            "label": "Retrieve a Purchase",
-            "params": [
-              {
-                "type": "string",
-                "required": true,
-                "name": "_id"
-              }
-            ]
-          }
-        }
-      },
-      "description": {
-        "fields": {},
-        "general": "A beer machine or kaffi machine transaction. Users should be able to get beer or kaffi, if their last timestamp is older than one day and they are AMIV members. This resource is used to log their purchases."
-      }
-    },
-    "groupmemberships": {
-      "paths": {
-        "/groupmemberships": {
-          "GET": {
-            "label": "Retrieve all groupmemberships",
-            "params": []
-          },
-          "POST": {
-            "label": "Create a Groupmembership",
-            "params": [
-              {
-                "self_enrollment_required": true,
-                "data_relation": {
-                  "cascade_delete": true,
-                  "field": "_id",
-                  "embeddable": true,
-                  "resource": "groups"
-                },
-                "required": true,
-                "name": "group",
-                "type": "objectid"
-              },
-              {
-                "type": "objectid",
+                "default": false,
                 "required": false,
-                "name": "_id"
+                "type": "boolean"
               },
               {
-                "data_relation": {
-                  "cascade_delete": true,
-                  "field": "_id",
-                  "embeddable": true,
-                  "resource": "users"
-                },
-                "type": "objectid",
-                "required": true,
-                "only_self_or_moderator": true,
-                "unique_combination": [
-                  "group"
-                ],
-                "name": "user"
-              }
-            ]
-          }
-        },
-        "/groupmemberships/{_id}": {
-          "DELETE": {
-            "label": "Delete a Groupmembership",
-            "params": [
-              {
-                "type": "string",
-                "required": true,
-                "name": "_id"
-              }
-            ]
-          },
-          "GET": {
-            "label": "Retrieve a Groupmembership",
-            "params": [
-              {
-                "type": "string",
-                "required": true,
-                "name": "_id"
-              }
-            ]
-          }
-        }
-      },
-      "description": {
-        "general": "Assignment of registered users to groups."
-      }
-    },
-    "eventsignups": {
-      "paths": {
-        "/eventsignups": {
-          "GET": {
-            "label": "Retrieve all eventsignups",
-            "params": []
-          },
-          "POST": {
-            "label": "Create a Eventsignup",
-            "params": [
-              {
+                "name": "catchphrase_de",
                 "nullable": true,
-                "type": "json_event_field",
                 "required": false,
-                "name": "additional_fields"
-              },
-              {
-                "nullable": false,
-                "email_signup_must_be_allowed": true,
-                "maxlength": 100,
                 "type": "string",
-                "required": false,
-                "regex": "^.+@.+$",
-                "not_patchable": true,
-                "name": "email"
+                "maxlength": 500
               },
               {
-                "nullable": true,
-                "readonly": true,
-                "type": "boolean",
-                "required": false,
-                "name": "confirmed"
-              },
-              {
-                "nullable": false,
-                "data_relation": {
-                  "field": "_id",
-                  "embeddable": true,
-                  "resource": "users"
-                },
-                "type": "objectid",
-                "only_self_enrollment_for_event": true,
                 "required": false,
-                "not_patchable": true,
-                "name": "user"
-              },
-              {
                 "type": "objectid",
-                "required": false,
                 "name": "_id"
-              },
-              {
-                "data_relation": {
-                  "field": "_id",
-                  "embeddable": true,
-                  "resource": "events"
-                },
-                "signup_requirements": true,
-                "type": "objectid",
-                "required": true,
-                "not_patchable": true,
-                "unique_combination": [
-                  "user",
-                  "email"
-                ],
-                "name": "event"
               }
-            ]
-          }
-        },
-        "/eventsignups/{_id}": {
+            ],
+            "label": "Update a Event"
+          },
           "DELETE": {
-            "label": "Delete a Eventsignup",
             "params": [
               {
-                "type": "string",
                 "required": true,
+                "type": "string",
                 "name": "_id"
               }
-            ]
+            ],
+            "label": "Delete a Event"
           },
           "GET": {
-            "label": "Retrieve a Eventsignup",
             "params": [
               {
-                "type": "string",
                 "required": true,
-                "name": "_id"
-              }
-            ]
-          },
-          "PATCH": {
-            "label": "Update a Eventsignup",
-            "params": [
-              {
                 "type": "string",
-                "required": true,
-                "name": "_id"
-              },
-              {
-                "nullable": true,
-                "type": "json_event_field",
-                "required": false,
-                "name": "additional_fields"
-              },
-              {
-                "nullable": false,
-                "email_signup_must_be_allowed": true,
-                "maxlength": 100,
-                "type": "string",
-                "required": false,
-                "regex": "^.+@.+$",
-                "not_patchable": true,
-                "name": "email"
-              },
-              {
-                "nullable": true,
-                "readonly": true,
-                "type": "boolean",
-                "required": false,
-                "name": "confirmed"
-              },
-              {
-                "nullable": false,
-                "data_relation": {
-                  "field": "_id",
-                  "embeddable": true,
-                  "resource": "users"
-                },
-                "type": "objectid",
-                "only_self_enrollment_for_event": true,
-                "required": false,
-                "not_patchable": true,
-                "name": "user"
-              },
-              {
-                "type": "objectid",
-                "required": false,
                 "name": "_id"
-              },
-              {
-                "data_relation": {
-                  "field": "_id",
-                  "embeddable": true,
-                  "resource": "events"
-                },
-                "signup_requirements": true,
-                "type": "objectid",
-                "required": true,
-                "not_patchable": true,
-                "unique_combination": [
-                  "user",
-                  "email"
-                ],
-                "name": "event"
               }
-            ]
+            ],
+            "label": "Retrieve a Event"
           }
         }
       },
       "description": {
         "fields": {
-          "additional_fields": "Data-schema depends on 'additional_fields' from the mapped event. Please provide in json-format.",
-          "email": "For registered users, this is just a projection of your general email-address. External users need to provide their email here.",
-          "user": "Provide either user or email."
+          "additional_fields": "must be provided in form of a JSON-Schema. You can add here fields you want to know from people signing up going further than their email-address",
+          "price": "Price of the event as Integer in Rappen.",
+          "allow_email_signup": "If False, only AMIV-Members can sign up for this event",
+          "spots": "For no limit, set to '0'. If no signup required, set to '-1'. Otherwise just provide an integer."
         },
         "methods": {
-          "PATCH": "Only additional_fields can be changed"
+          "GET": "You are always allowed, even without session, to view AMIV-Events"
         },
-        "general": "You can signup here for an existing event inside of the registration-window. External Users can only sign up to public events."
+        "general": "An Event is basically everything happening in the AMIV. All time fields have the format YYYY-MM-DDThh:mmZ, e.g. 2014-12-20T11:50:06Z"
       }
     }
   },
+  "api_name": "API",
   "base": "http:///",
   "server_name": null
-}
\ No newline at end of file
+}
diff --git a/tools/events.tool b/tools/events.tool
index f57a492..f10fe6d 100644
--- a/tools/events.tool
+++ b/tools/events.tool
@@ -471,9 +471,12 @@
             var newEvent = {
                 data: {}
             };
-            newEvent["data"]["title_de"] = setNullIfEmpty($("#title_de").val());
-            newEvent["data"]["description_de"] = setNullIfEmpty($("#description_de").val());
-            newEvent["data"]["catchphrase_de"] = setNullIfEmpty($("#catchphrase_de").val());
+	    if ($("#title_de") !== "")
+		newEvent["data"]["title_de"] = $("#title_de").val();
+	    if ($("#description_de") !== "")
+		newEvent["data"]["description_de"] = $("#description_de").val();
+	    if ($("#catchphrase_de") !== "")
+		newEvent["data"]["catchphrase_de"] = $("#catchphrase_de").val();
 
             if (!($("#time_start").data("DateTimePicker").date() == null)) {
                 newEvent["data"]["time_start"] = $("#time_start").data("DateTimePicker").date().toISOString().split('.')[0]+"Z";
@@ -517,38 +520,35 @@
                 }
                 newEvent["data"]["allow_email_signup"] = $("#allow_email_signup").is(':checked');
             } else {
-                newEvent["data"]["spots"] = null;
             }
 
            
+	    if ($("#location").val() !== "")
+		newEvent["data"]["location"] = $("#location").val();
 
-            newEvent["data"]["location"] = setNullIfEmpty($("#location").val());
-
-            if (!($("#price").val() === "")) {
+            if (!($("#price").val() === ""))
                 newEvent["data"]["price"] = Math.floor((parseFloat($("#price").val()) * 100));
-            }
 
             newEvent["data"]["show_website"] = $("#show_website").is(':checked');
             newEvent["data"]["show_infoscreen"] = $("#show_infoscreen").is(':checked');
             newEvent["data"]["show_announce"] = $("#show_announce").is(':checked');
-            newEvent["data"]["priority"] = (parseInt($("#priority").val()));
-            newEvent["data"]["additional_fields"] = setNullIfEmpty($("#additional_fields").val());
-
-            newEvent["data"]["title_en"] = setNullIfEmpty($("#title_en").val());
-            newEvent["data"]["description_en"] = setNullIfEmpty($("#description_en").val());
-            newEvent["data"]["catchphrase_en"] = setNullIfEmpty($("#catchphrase_en").val());
-
-            console.log(newEvent);
-
-            form = new FormData();
-            // for (data in newEvent.data){
-            //     form.append(data, newEvent['data'][data]);
-            // }
-            var imageData = ['img_infoscreen', 'img_thumbnail', 'img_poster', 'img_banner'];
+            newEvent["data"]["priority"] = parseInt($("#priority").val());
+	    if ($("#additional_fields").val() !== "")
+		newEvent["data"]["additional_fields"] = $("#additional_fields").val();
+
+	    if ($("#title_en").val !== "")
+		newEvent["data"]["title_en"] = $("#title_en").val();
+	    if ($("#description_en").val !== "")
+		newEvent["data"]["description_en"] = $("#description_en").val();
+	    if ($("#catchphrase_en").val !== "")
+		newEvent["data"]["catchphrase_en"] = $("#catchphrase_en").val();
+
+	    var imageData = ['img_infoscreen', 'img_thumbnail', 'img_poster', 'img_banner'];
             for (i = 0; i < imageData.length; i++){
                 if ($('#' + imageData[i])[0].files[0] != undefined)
-                    form.append(imageData[i], $('#' + imageData[i])[0].files[0]);
+                    newEvent["data"][imageData[i]] = $('#' + imageData[i])[0].files[0];
             }
+            console.log(newEvent);
 
             console.log(JSON.stringify(newEvent));
             if(isNew) {
@@ -558,7 +558,10 @@
                     else {
                         console.log(ret);
                         curEventData = ret;
-                        events.uploadCallback(form);
+			tools.log('Event Added', 's');
+                        $('#event-modal').modal('hide');
+                        $("#event-modal-form").trigger('reset');
+                        events.get();
                     }
                 });
             } 
@@ -571,35 +574,15 @@
                     if (!ret.hasOwnProperty('_status') || ret['_status'] != 'OK')
                         tools.log(JSON.stringify(ret.responseJSON['_issues']), 'e');
                     else {
-                        events.uploadCallback(form);
-                    }
-                });
-            }  
-            console.log(response);
-        },
-
-        //images need to be uploaded seperately after POSTing using PATCH
-        uploadCallback: function(form){
-            amivcore.getEtag('events', curEventData._id, function(ret){
-                $.ajax({
-                    url: events.API_url + '/events/' + curEventData._id,
-                    headers: {'Authorization':'amivroot', 'If-Match': ret},
-                    data: form,
-                    type: 'PATCH',
-                    // THIS MUST BE DONE FOR FILE UPLOADING
-                    contentType: false,
-                    processData: false,
-                    // ... Other options like success and etc
-                    success: function(data){
-                        console.log(data);
-                        tools.log('Event Added', 's');
+			console.log(ret);
+                        curEventData = ret;
+			tools.log('Event Added', 's');
                         $('#event-modal').modal('hide');
                         $("#event-modal-form").trigger('reset');
                         events.get();
                     }
                 });
-            });
-                
+            }
         }
     }
 
-- 
GitLab