diff --git a/Dockerfile b/Dockerfile index 0ef90096a6d4f2eb29e7daa0a82508e2055371b1..733ef29a558d165adc43df7532ac63616bf7faa0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,26 +12,11 @@ RUN npm run $NPM_BUILD_COMMAND # Second stage: Server to deliver files -FROM node:alpine - -# Port 8080 can be used as non root -EXPOSE 8080 - -# Create user with home directory and no password -RUN adduser -Dh /admintool admintool -USER admintool -WORKDIR /admintool - -# Install http server -RUN npm install --no-save http-server +FROM nginx:1.15-alpine # Copy files from first stage -COPY --from=build /index.html /admintool/ -COPY --from=build /dist /admintool/dist - -# Serve index.html for every file which is not found on the server -# Hotfix for direct links -RUN ln index.html 404.html +COPY --from=build /index.html /var/www/ +COPY --from=build /dist /var/www/dist -# Run server (-g will automatically serve the gzipped files if possible) -CMD ["/admintool/node_modules/.bin/http-server", "-g", "/admintool"] +# Copy nginx configuration +COPY nginx.conf /etc/nginx/conf.d/default.conf diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000000000000000000000000000000000000..f32d94d360c47c673f8dde4a269ad6253e41107d --- /dev/null +++ b/nginx.conf @@ -0,0 +1,9 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + root /var/www/; + index index.html; + + try_files $uri /index.html =404; +} diff --git a/src/auth.js b/src/auth.js index 2a263636c8e9cce24ecf132616ba9bd211848409..1fd9dad9bd1df35b4c2f8994672e2b94274e65e5 100644 --- a/src/auth.js +++ b/src/auth.js @@ -11,9 +11,14 @@ const APISession = { token: '', // user admins are a very special case as the permissions on the resource can only // be seen by requesting users and check whether you see their membership - isUserAdmin: false + isUserAdmin: false, }; +const amivapi = axios.create({ + baseURL: apiUrl, + headers: { 'Content-Type': 'application/json' }, +}); + // OAuth Handler const oauth = new ClientOAuth2({ clientId: oAuthID, @@ -21,18 +26,13 @@ const oauth = new ClientOAuth2({ redirectUri: `${ownUrl}/oauthcallback`, }); -export function resetSession() { +function resetSession() { APISession.authenticated = false; APISession.token = ''; localStorage.remove('token'); window.location.replace(oauth.token.getUri()); } -const amivapi = axios.create({ - baseURL: apiUrl, - headers: { 'Content-Type': 'application/json' }, -}); - function checkToken(token) { // check if a token is still valid return new Promise((resolve, reject) => { @@ -88,6 +88,26 @@ export function getSession() { }); } +export function deleteSession() { + return new Promise((resolve, reject) => { + getSession().then((api) => { + api.get(`sessions/${APISession.token}`).then((response) => { + if (response.status === 200) { + api.delete( + `sessions/${response.data._id}`, + { headers: { 'If-Match': response.data._etag } }, + ).then((deleteResponse) => { + if (deleteResponse.status === 204) { + resetSession(); + resolve(deleteResponse.data); + } else reject(); + }).catch(reject); + } else reject(); + }).catch(reject); + }); + }); +} + export class ResourceHandler { /* Handler to get and manipulate resource items * diff --git a/src/events/editEvent.js b/src/events/editEvent.js index 41729f4a4de2ea1e1b034a970566faec976725a1..63f71a6f7f86a2ced714d04a986552a5a030da38 100644 --- a/src/events/editEvent.js +++ b/src/events/editEvent.js @@ -71,10 +71,8 @@ export default class newEvent extends EditView { type: 'string', enum: ['Omnivor', 'Vegi', 'Vegan', 'Other'], }; - additionalFields.properties.specialFood = { - 'Special Food Requirements': { - type: 'string', - }, + additionalFields.properties['Special Food Requirements'] = { + type: 'string', }; additionalFields.required.push('Food'); } diff --git a/src/index.js b/src/index.js index 6d3d4feb7e65ca97e62295bf31fcf6bc849ed9f4..dc63d456948c31fa427c8437a06e6834de1b8186 100644 --- a/src/index.js +++ b/src/index.js @@ -42,5 +42,3 @@ m.route(root, '/events', { '/newjoboffer': layoutWith(JobItem), '/joboffers/:id': layoutWith(JobItem), }); - -m.route.prefix(''); diff --git a/src/layout.js b/src/layout.js index f24392bd7ec18707e5a39b1aca9fbbb3eb1a7589..760ca105ee600f18c562a60afe5465acd10d0a1b 100644 --- a/src/layout.js +++ b/src/layout.js @@ -9,11 +9,12 @@ import { ToolbarTitle, Dialog, SVG, + Button, IconButton, } from 'polythene-mithril'; import { styler } from 'polythene-core-css'; import { icons } from './views/elements'; -import { resetSession } from './auth'; +import { deleteSession } from './auth'; import { colors } from './style'; const layoutStyle = [ @@ -109,7 +110,11 @@ export class Layout { style: { color: '#ffffff' }, })), m(ToolbarTitle, { text: 'AMIV Admintools' }), - m('a', { onclick: resetSession }, 'Logout'), + m(Button, { + className: 'red-row-button', + label: 'logout', + events: { onclick: deleteSession }, + }), ]), m( 'div.mdc-typography.wrapper-sidebar', diff --git a/src/users/editUser.js b/src/users/editUser.js index 7f2587cd3ea8302954ca2737f4e60163c139652f..edde0dde2e3c1926039b248e45bb822eef70b515 100644 --- a/src/users/editUser.js +++ b/src/users/editUser.js @@ -16,6 +16,11 @@ export default class UserEdit extends EditView { m(RadioGroup, { name: 'Membership', buttons: [ + { + value: 'none', + label: 'No Member', + defaultChecked: this.data.membership === 'none', + }, { value: 'regular', label: 'Regular AMIV Member', @@ -27,9 +32,9 @@ export default class UserEdit extends EditView { defaultChecked: this.data.membership === 'extraordinary', }, { - value: 'honory', + value: 'honorary', label: 'Honorary Member', - defaultChecked: this.data.membership === 'honory', + defaultChecked: this.data.membership === 'honorary', }, ], onChange: ({ value }) => { this.data.membership = value; },