diff --git a/src/index.js b/src/index.js index 30a0b0410c1493fa0dc59f3c212a5e6e14a95f6d..3f734e3b40ba29d968de7d62267c6a4953130827 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,13 @@ // src/index.js const m = require('mithril'); -const Layout = require('./layout'); -const amiv = require('./amiv'); -const statuten = require('./amiv/statuten'); -const contact = require('./contact'); -const aufenthaltsraum = require('./amiv/aufenthaltsraum'); + +const Layout = require('./views/layout'); +const amiv = require('./views/amiv'); +const login = require('./views/login'); +const statuten = require('./views/amiv/statuten'); +const contact = require('./views/contact'); +const aufenthaltsraum = require('./views/amiv/aufenthaltsraum'); + m.route(document.body, '/', { '/': { @@ -27,4 +30,9 @@ m.route(document.body, '/', { return m(Layout, m(aufenthaltsraum)); }, }, + '/login': { + render() { + return m(Layout, m(login)); + }, + }, }); diff --git a/src/layout.js b/src/layout.js deleted file mode 100644 index c6ba9c1514e73237911eaa3c0828be0c490b6966..0000000000000000000000000000000000000000 --- a/src/layout.js +++ /dev/null @@ -1,16 +0,0 @@ -const m = require('mithril'); - -module.exports = { - view(vnode) { - return m('div', [ - m('nav', [ - m('a', { href: '/' }, 'AMIV'), - m('a', { href: '/events' }, 'Events'), - m('a', { href: '/studydocuments' }, 'Studienunterlagen'), - m('a', { href: '/jobs' }, 'Jobs'), - m('a', { href: '/profile' }, 'Profil'), - ]), - m('main', vnode.children), - ]); - }, -}; diff --git a/src/models/auth.js b/src/models/auth.js new file mode 100644 index 0000000000000000000000000000000000000000..198dde98e77eed15f3dacd4b9b15b5fa98560fe2 --- /dev/null +++ b/src/models/auth.js @@ -0,0 +1,106 @@ +const m = require('mithril'); +const Config = require('./config'); +const log = require('./log'); + +const auth = { + username: '', + token: '', + etag: '', + error: '', + id: '', + authenticated: false, + lastChecked: 0, + login(username, password) { + this.reloadLocalStorage(); + return m.request({ + method: 'POST', + url: `${Config.api_url}/sessions`, + data: { username, password }, + }).then((result) => { + const dt = new Date(); + log.log('logged in!'); + this.token = result.token; + this.etag = result._etag; + this.id = result._id; + this.authenticated = true; + this.username = username; + localStorage.setItem('token', result.token); + localStorage.setItem('username', username); + localStorage.setItem('id', result._id); + localStorage.setItem('etag', result._etag); + this.lastChecked = dt.getTime(); + m.route.set('/'); + }).catch((e) => { + this.error = e.message; + }); + }, + logout() { + this.reloadLocalStorage(); + this.authenticated = false; + return m.request({ + method: 'DELETE', + url: `${Config.api_url}/sessions/${this.id}`, + headers: { + Authorization: `Token ${this.token}`, + 'If-Match': this.etag, + }, + }).then(() => { + log.log('logged out!'); + this.token = ''; + this.authenticated = false; + this.error = ''; + localStorage.removeItem('token'); + localStorage.removeItem('username'); + localStorage.removeItem('id'); + localStorage.removeItem('etag'); + m.route.set('/login'); + }).catch((e) => { + this.error = e.message; + this.authenticated = false; + m.route.set('/login'); + }); + }, + checkLogin() { + const dt = new Date(); + auth.reloadLocalStorage(); + if (this.authenticated === true) { + log.log('no session found'); + m.route.set('/login'); + return new Promise(() => { }); + } + if (dt.getTime() > this.lastChecked + 5000) { + return m.request({ + method: 'GET', + url: `${Config.api_url}/sessions/${this.token}`, + }).then((result) => { + const dt2 = new Date(); + log.log('session is still valid!'); + this.authenticated = true; + this.etag = result._etag; + this.lastChecked = dt2.getTime(); + }).catch((e) => { + log.log('token is not valid'); + log.log(e); + this.authenticated = false; + localStorage.removeItem('session'); + localStorage.removeItem('username'); + localStorage.removeItem('id'); + localStorage.removeItem('etag'); + m.route.set('/login'); + }); + } + return new Promise(() => { }); + }, + reloadLocalStorage() { + log.log('checking stored session'); + if (localStorage.getItem('token') !== null) { + this.token = localStorage.token; + this.id = localStorage.id; + this.username = localStorage.username; + this.etag = localStorage.etag; + this.authenticated = true; + } + }, +}; + +module.exports = auth; diff --git a/src/config.js b/src/models/config.js similarity index 100% rename from src/config.js rename to src/models/config.js diff --git a/src/log.js b/src/models/log.js similarity index 100% rename from src/log.js rename to src/models/log.js diff --git a/src/amiv.js b/src/views/amiv.js similarity index 100% rename from src/amiv.js rename to src/views/amiv.js diff --git a/src/amiv/aufenthaltsraum.js b/src/views/amiv/aufenthaltsraum.js similarity index 100% rename from src/amiv/aufenthaltsraum.js rename to src/views/amiv/aufenthaltsraum.js diff --git a/src/amiv/statuten.js b/src/views/amiv/statuten.js similarity index 100% rename from src/amiv/statuten.js rename to src/views/amiv/statuten.js diff --git a/src/contact.js b/src/views/contact.js similarity index 100% rename from src/contact.js rename to src/views/contact.js diff --git a/src/views/layout.js b/src/views/layout.js new file mode 100644 index 0000000000000000000000000000000000000000..50c9acba081a86e91ae962c8f42d6834d0e8e8a1 --- /dev/null +++ b/src/views/layout.js @@ -0,0 +1,37 @@ +const m = require('mithril'); +const auth = require('../models/auth'); + +module.exports = { + oninit: auth.checkLogin, + view(vnode) { + if (auth.authenticated === false) { + return m('div', [ + m('nav', [ + m('a', { href: '/' }, 'AMIV'), + m('a', { href: '/#!/events' }, 'Events'), + m('a', { href: '/#!/studydocuments' }, 'Studienunterlagen'), + m('a', { href: '/#!/jobs' }, 'Jobs'), + m('a', { href: '/#!/login' }, 'Login'), + ]), + m('main', vnode.children), + ]); + } + return m('div', [ + m('nav', [ + m('a', { href: '/' }, 'AMIV'), + m('a', { href: '/#!/events' }, 'Events'), + m('a', { href: '/#!/studydocuments' }, 'Studienunterlagen'), + m('a', { href: '/#!/jobs' }, 'Jobs'), + m('a', { href: '/#!/profile' }, 'Profil'), + m('a', { + href: '#', + onclick: () => { + auth.logout(); + return false; + }, + }, 'Logout'), + ]), + m('main', vnode.children), + ]); + }, +}; diff --git a/src/views/login.js b/src/views/login.js new file mode 100644 index 0000000000000000000000000000000000000000..e1fd04b4b28237700de769e3f811be96bad3fa53 --- /dev/null +++ b/src/views/login.js @@ -0,0 +1,31 @@ +const m = require('mithril'); +const Auth = require('../models/auth'); + +module.exports = { + username: '', + password: '', + view() { + return m('div', [ + m( + 'form', { + onsubmit: (e) => { + e.preventDefault(); + Auth.login(this.username, this.password); + }, + }, + m('h3', 'Login'), [ + m('p', Auth.error), + m('input.input[type=text][placeholder=Username]', { + oninput: m.withAttr('value', (value) => { this.username = value; }), + value: this.username, + }), + m('input.input[placeholder=Password][type=password]', { + oninput: m.withAttr('value', (value) => { this.password = value; }), + value: this.password, + }), + m('button.button[type=submit]', 'Login'), + ], + ), + ]); + }, +};