Commit 19a1d6d0 authored by Alexander Dietmüller's avatar Alexander Dietmüller

Frontend: Refactoring.

parent da0b678e
const m = require('mithril');
const { courses, userCourses } = require('./api.js');
const { courses, userCourses } = require('./backend.js');
function isSelected(course) {
return userCourses.selected.some(sel => sel === course._id);
}
function isBusy() { return userCourses.resources.selections.isBusy() };
function isBusy() { return userCourses.resources.selections.isBusy(); }
module.exports = {
oninit() { courses.get(); },
......
......@@ -4,7 +4,7 @@
// Includes the generic login / logout
const m = require('mithril');
const { Session } = require('./api.js');
const session = require('./session.js');
let nethz = '';
let password = '';
......@@ -15,7 +15,7 @@ let busy = false;
function login() {
if (!busy && nethz && password) {
busy = true;
Session.login(nethz, password).then(() => {
session.login(nethz, password).then(() => {
nethz = '';
password = '';
error = '';
......@@ -29,7 +29,7 @@ function login() {
function logout() {
busy = true;
Session.logout().then(() => {
session.logout().then(() => {
busy = false;
error = '';
}).catch((err) => {
......@@ -82,9 +82,9 @@ const SidebarHeader = {
return [
m('header', m('img', { src: '/home/alex/contractor/contractor/static/logo.svg' })),
// m('h1', 'PVK Tool Demo'),
m('p', `Hello, ${Session.user.name}`),
m('p', `Hello, ${session.user.name}`),
m('button', { onclick: logout }, 'Logout'),
Session.admin ? [
session.admin ? [
m('br'),
m('a', { href: '/course', oncreate: m.route.link }, 'User Tools'),
m('br'),
......@@ -97,7 +97,7 @@ const SidebarHeader = {
module.exports = {
view(vnode) {
return Session.active() ? m('', [
return session.active() ? m('', [
m('aside', [m(SidebarHeader), m(vnode.attrs.sidebar)]),
m('main', m(vnode.attrs.content)),
]) : m(LoginPage);
......
// User Sidebar
const m = require('mithril');
const { userCourses } = require('./api.js');
const { userCourses } = require('./backend.js');
function courseView(course) {
return m('li', course);
......
// Api calls
const m = require('mithril');
const ls = require('local-storage');
const session = require('./session.js');
const amivApiUrl = 'https://amiv-api.ethz.ch';
const pvkApiUrl = `//${window.location.hostname}/api`;
const adminGroupName = 'PVK Admins';
const storedSession = ls('session');
// Session with AMIVAPI
const Session = {
// Quick check if session exists
active() { return this.data.token; },
// User data
user: storedSession ? storedSession.user : {},
// Session data
data: storedSession ? storedSession.data : {},
// Admin?
admin: storedSession ? storedSession.admin : false,
// Safe to local-storage
safe() {
ls('session', {
user: this.user,
data: this.data,
admin: this.admin,
});
},
// Remove all session data and clear local storage
clear() {
this.user = '';
this.data = '';
this.admin = false;
ls.remove('session');
},
// Login and Logout
login(username, password) {
// Login and request user data along with the session
return m.request({
method: 'POST',
url: `${amivApiUrl}/sessions?embedded={"user": 1}`,
data: { username, password },
}).then((data) => {
// Session data
this.data = {
token: data.token,
_id: data._id,
_etag: data._etag,
};
// User data
this.user = {
name: data.user.firstname,
nethz: data.user.nethz,
department: data.user.department,
_id: data.user._id,
};
// Check if admin
this.check_admin(data.token);
this.safe();
});
},
logout() {
if (this.data.token) {
return m.request({
method: 'DELETE',
url: `${amivApiUrl}/sessions/${this.data._id}`,
headers: {
Authorization: `Token ${this.data.token}`,
'If-Match': this.data._etag,
},
}).then(() => {
this.clear();
}).catch((err) => {
if (err._error.code === 401) {
// Token already no valid anymore, clear session
this.clear();
} else {
throw err._error;
}
});
}
// Otherwise nothing to do, return a promise that always resolves
return Promise.resolve();
},
check_admin(token) {
// First: Look for Admin Group
let query = m.buildQueryString({
projection: { _id: 1 },
where: { name: adminGroupName },
});
m.request({
method: 'GET',
url: `${amivApiUrl}/groups?${query}`,
headers: { Authorization: `Token ${token}` },
}).then((data) => {
if (data._meta.total !== 0) {
// Admin group exists and we have it's id, check membership
query = m.buildQueryString({
where: {
user: this.user._id,
group: data._items[0]._id,
},
});
return m.request({
method: 'GET',
url: `${amivApiUrl}/groupmemberships?${query}`,
headers: { Authorization: `Token ${token}` },
});
}
// Can't continue, return a promise that always rejects
return Promise.reject();
}).then((data) => {
if (data._meta.total !== 0) {
// User is admin!
this.admin = true;
this.safe();
}
}).catch(() => {
// User is no admin.
this.admin = false;
this.safe();
});
},
};
const pvkApiUrl = `//${window.location.hostname}/api`;
// Helper to filter temp out of list
......@@ -159,7 +29,7 @@ function request({
const allHeaders = Object.assign(
{},
{ Authorization: `Token ${Session.data.token}` },
{ Authorization: `Token ${session.data.token}` },
headers,
);
......@@ -171,7 +41,7 @@ function request({
headers: allHeaders,
}).catch((err) => {
// If the error is 401, the token is invalid -> auto log out
if (err._error.code === 401) { Session.clear(); }
if (err._error.code === 401) { session.clear(); }
// Pass on Error
throw err;
......@@ -219,6 +89,19 @@ class Resource {
});
}
getItem(id) {
return request({
resource: this.name,
id,
query: this.query,
}).then((data) => {
// Fill own list
this._items[data._id] = data;
// Pass on data
return data;
});
}
post(data) {
// Add data already to list of unprocessed items
this._items_new.push(data);
......@@ -297,11 +180,11 @@ const userCourses = {
resources: {
selections: new Resource(
'selections',
{ where: { nethz: Session.user.nethz } },
{ where: { nethz: session.user.nethz } },
),
signups: new Resource(
'signups',
{ where: { nethz: Session.user.nethz } },
{ where: { nethz: session.user.nethz } },
),
},
......@@ -342,7 +225,7 @@ const userCourses = {
// Otherwise create a new selection
return this.resources.selections.post({
nethz: Session.user.nethz,
nethz: session.user.nethz,
courses: [courseId],
});
},
......@@ -353,9 +236,7 @@ const userCourses = {
const selectionId = selection._id;
if (newSelection.length === 0) {
this.resources.selections.deleteItem(selectionId)
.then((res) => { console.log(res); })
.catch((err) => { console.log(err); });
this.resources.selections.deleteItem(selectionId);
} else {
this.resources.selections.patchItem(
selectionId,
......@@ -373,8 +254,6 @@ const courses = new Resource('courses', { embedded: { lecture: 1 } });
const lectures = new Resource('lectures');
module.exports = {
Session,
request,
userCourses,
courses,
lectures,
......
const m = require('mithril');
const { Session } = require('./api.js');
const session = require('./session.js');
const Layout = require('./Layout.js');
const UserSidebar = require('./UserSidebar.js');
......@@ -20,7 +20,7 @@ m.route(document.body, '/courses', {
'/admin': {
render() {
// If not admin, redirect to Courses
if (!Session.admin) { m.route.set('/course'); }
if (!session.admin) { m.route.set('/course'); }
return m(Layout, {
sidebar: AdminSidebar,
content: CourseOverview,
......
// Session with AMIVAPI
const m = require('mithril');
const ls = require('local-storage');
const adminGroupName = 'PVK Admins';
const amivApiUrl = 'https://amiv-api.ethz.ch';
const storedSession = ls('session');
module.exports = {
// Quick check if session exists
active() { return this.data.token; },
// User data
user: storedSession ? storedSession.user : {},
// Session data
data: storedSession ? storedSession.data : {},
// Admin?
admin: storedSession ? storedSession.admin : false,
// Safe to local-storage
safe() {
ls('session', {
user: this.user,
data: this.data,
admin: this.admin,
});
},
// Remove all session data and clear local storage
clear() {
this.user = '';
this.data = '';
this.admin = false;
ls.remove('session');
},
// Login and Logout
login(username, password) {
// Login and request user data along with the session
return m.request({
method: 'POST',
url: `${amivApiUrl}/sessions?embedded={"user": 1}`,
data: { username, password },
}).then((data) => {
// Session data
this.data = {
token: data.token,
_id: data._id,
_etag: data._etag,
};
// User data
this.user = {
name: data.user.firstname,
nethz: data.user.nethz,
department: data.user.department,
_id: data.user._id,
};
// Check if admin
this.check_admin(data.token);
this.safe();
});
},
logout() {
if (this.data.token) {
return m.request({
method: 'DELETE',
url: `${amivApiUrl}/sessions/${this.data._id}`,
headers: {
Authorization: `Token ${this.data.token}`,
'If-Match': this.data._etag,
},
}).then(() => {
this.clear();
}).catch((err) => {
if (err._error.code === 401) {
// Token already no valid anymore, clear session
this.clear();
} else {
throw err._error;
}
});
}
// Otherwise nothing to do, return a promise that always resolves
return Promise.resolve();
},
check_admin(token) {
// First: Look for Admin Group
let query = m.buildQueryString({
projection: { _id: 1 },
where: { name: adminGroupName },
});
m.request({
method: 'GET',
url: `${amivApiUrl}/groups?${query}`,
headers: { Authorization: `Token ${token}` },
}).then((data) => {
if (data._meta.total !== 0) {
// Admin group exists and we have it's id, check membership
query = m.buildQueryString({
where: {
user: this.user._id,
group: data._items[0]._id,
},
});
return m.request({
method: 'GET',
url: `${amivApiUrl}/groupmemberships?${query}`,
headers: { Authorization: `Token ${token}` },
});
}
// Can't continue, return a promise that always rejects
return Promise.reject();
}).then((data) => {
if (data._meta.total !== 0) {
// User is admin!
this.admin = true;
this.safe();
}
}).catch(() => {
// User is no admin.
this.admin = false;
this.safe();
});
},
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment