To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit 1e2deb32 authored by Alexander Dietmüller's avatar Alexander Dietmüller
Browse files

Frontend: Talk to backend and display courses in sidebar

parent a830b71e
......@@ -6,13 +6,13 @@
main {
display: inline-block;
vertical-align: top;
width: 70%;
width: 60%;
}
aside {
display: inline-block;
vertical-align: top;
width: 25%;
width: 35%;
margin-right: 5%;
}
</style>
......
import PvkList from './PvkList';
const m = require('mithril');
const { Courses, UserCourses } = require('./api.js');
module.exports = {
oninit() { Courses.load(); },
view() {
<<<<<<< HEAD
return m('div', [m(PvkList)]);
=======
// return m('div', 'Hellooo!');
return m('ul', [
Courses.list.map(course =>
m('li', [
m('p', `${course.lecture.title}, ${course.assistant}`),
m(
'button',
{ onclick() { UserCourses.select(course); } },
'Add Course',
),
])),
]);
// m('button', { onclick() { Courses.select(); } }, 'Add Course');
>>>>>>> Frontend: Talk to backend and display courses in sidebar
},
};
......@@ -80,7 +80,8 @@ const LoginPage = {
const SidebarHeader = {
view() {
return [
m('h1', 'PVK Tool Demo'),
m('header', m('img', { src: '/home/alex/contractor/contractor/static/logo.svg' })),
// m('h1', 'PVK Tool Demo'),
m('p', `Hello, ${Session.user.name}`),
m('button', { onclick: logout }, 'Logout'),
Session.admin ? [
......
import m from 'mithril';
import { apiUrl } from './api';
class Pvk {
constructor() {
......@@ -11,7 +10,7 @@ class Pvk {
// request is needed to force mithrijs to update shared objects
m.request({
method: 'GET',
url: `${apiUrl}`,
// url: `${apiUrl}`,
}).then(() => {
this.list = [{
lecture: {
......
// User Sidebar
import Pvk from './Pvk';
const m = require('mithril');
const { UserCourses } = require('./api.js');
function courseView(course) {
return m('li', `${course.lecture.title}, ${course.assistant}`);
}
function asList(courses) { return courses.map(courseView); }
module.exports = {
oninit() { UserCourses.load(); },
view() {
return [
m('h2', 'Your Courses'),
m('p', 'You are not signed up for anything yet.'),
m('p', `Amnt of Pvks: ${Pvk.list.length}`),
m('h1', 'Selected Courses'),
UserCourses.selected.length ? [
asList(UserCourses.selected),
m('button', { onclick() { UserCourses.reserve(); } }, 'reserve'),
] : m('p', 'No courses selected.'),
m('h1', 'Reserved Courses'),
UserCourses.reserved.length ? [
asList(UserCourses.reserved),
m('button', { onclick() { UserCourses.pay(); } }, 'Pay'),
] : m('p', 'No courses reserved.'),
m('h1', 'Accepted Courses'),
UserCourses.accepted.length ? [
asList(UserCourses.accepted),
] : m('p', 'No courses accepted.'),
];
},
};
......@@ -3,11 +3,15 @@
const m = require('mithril');
const ls = require('local-storage');
const apiUrl = 'https://amiv-api.ethz.ch';
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; },
......@@ -43,7 +47,7 @@ const Session = {
// Login and request user data along with the session
return m.request({
method: 'POST',
url: `${apiUrl}/sessions?embedded={"user": 1}`,
url: `${amivApiUrl}/sessions?embedded={"user": 1}`,
data: { username, password },
}).then((data) => {
// Session data
......@@ -71,7 +75,7 @@ const Session = {
if (this.data.token) {
return m.request({
method: 'DELETE',
url: `${apiUrl}/sessions/${this.data._id}`,
url: `${amivApiUrl}/sessions/${this.data._id}`,
headers: {
Authorization: `Token ${this.data.token}`,
'If-Match': this.data._etag,
......@@ -83,7 +87,7 @@ const Session = {
// Token already no valid anymore, clear session
this.clear();
} else {
throw err;
throw err._error;
}
});
}
......@@ -99,7 +103,7 @@ const Session = {
});
m.request({
method: 'GET',
url: `${apiUrl}/groups?${query}`,
url: `${amivApiUrl}/groups?${query}`,
headers: { Authorization: `Token ${token}` },
}).then((data) => {
if (data._meta.total !== 0) {
......@@ -112,7 +116,7 @@ const Session = {
});
return m.request({
method: 'GET',
url: `${apiUrl}/groupmemberships?${query}`,
url: `${amivApiUrl}/groupmemberships?${query}`,
headers: { Authorization: `Token ${token}` },
});
}
......@@ -132,7 +136,95 @@ const Session = {
},
};
// Request to the PVK backend
function request({
resource, method = 'GET', id = '', data = {}, query = {},
}) {
// Parse query such that the backend understands it
const parsedQuery = {};
Object.keys(query).forEach((key) => {
parsedQuery[key] = JSON.stringify(query[key]);
});
const queryString = m.buildQueryString(parsedQuery);
// Send the request
return m.request({
method,
data,
url: `${pvkApiUrl}/${resource}/${id}?${queryString}`,
headers: { Authorization: `Token ${Session.data.token}` },
}).catch((err) => {
// If the error is 401, the token is invalid -> auto log out
if (err._error.code === 401) { Session.clear(); }
// Actual error information is in the '_error' field, pass this on
throw err._error;
});
}
// Generic PVK resource
class Resource {
constructor(name, query = {}) {
this.name = name;
this.list = [];
this.query = query;
}
load() {
return request({ resource: this.name, query: this.query }).then((data) => {
// Fill own list
this.list = data._items;
// Pass on data
return data;
});
}
}
const UserCourses = {
resources: {
selections: new Resource(
'selections',
{ where: { nethz: Session.user.nethz } },
),
signups: new Resource(
'signups',
{ where: { nethz: Session.user.nethz } },
),
},
load() {
this.resources.selections.load().then(() => {
// We are only interested in one the first (and single) element
this.resources.selections.list = this.resources.selections.list[0] || [];
});
this.resources.signups.load();
},
get selected() { return this.resources.selections.list; },
get reserved() {
return this.resources.signups.list.filter(({ status }) =>
status === 'reserved');
},
get accepted() {
return this.resources.signups.list.filter(({ status }) =>
status === 'accepted');
},
// TODO(Alex)
select() {},
reserve() {},
pay() {},
};
const Courses = new Resource('courses', { embedded: { lecture: 1 } });
module.exports = {
Session,
apiUrl,
request,
UserCourses,
Courses,
};
......@@ -41,6 +41,7 @@ frontend development. Here's how:
-e MONGO_HOST="mongodb" \
pvk
```
The `--link` and `-e` make sure the backend can access the db container.
And now the backend is available at port 80, ready to use!
......
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