From 9a143ffbbcb6b6b1212fd79d33369f75f75753f6 Mon Sep 17 00:00:00 2001 From: Alexander Olofsson <alexander.olofsson@liu.se> Date: Mon, 11 Dec 2017 12:35:11 +0100 Subject: [PATCH] Working on some per-user limits --- client/App.vue | 4 ++-- client/ExternalUser.vue | 7 ++++--- client/models/user.js | 12 ++++++++++++ server/auth.js | 2 +- server/db.js | 2 +- server/users.js | 40 ++++++++++++++++++++++++++++++++++++++-- 6 files changed, 58 insertions(+), 9 deletions(-) diff --git a/client/App.vue b/client/App.vue index 22b8317..69b03da 100644 --- a/client/App.vue +++ b/client/App.vue @@ -28,11 +28,11 @@ <h4>Add external users</h4> <p>Employees and students are allowed to create external users for collaboration with actors outside of Linköpings University.<br/> This application will track and allow creation of such external users, up to a number configurable by the administrators.<br/></p> - <button class="btn btn-success" @click="showCreationForm = !showCreationForm">New External User</button> + <button class="btn btn-success" :disabled="external.length >= user.user_limit" @click="showCreationForm = !showCreationForm">New External User</button> </div> </transition> - <h2 class="mt-4 mb-3">Existing external users:</h2> + <h2 class="mt-4 mb-3">Existing external users: ({{ external.length }}/{{ user.user_limit }})</h2> <hr/> <transition name="fade" mode="out-in"> <ul class="list-unstyled" is="transition-group" name="flip-list" v-if="external"> diff --git a/client/ExternalUser.vue b/client/ExternalUser.vue index 52432c1..7660f40 100644 --- a/client/ExternalUser.vue +++ b/client/ExternalUser.vue @@ -3,12 +3,13 @@ <img v-bind:src="user.avatar_url" class="d-flex align-self-center mr-3 rounded-circle user-avatar" alt="Avatar"/> <div class="media-body"> <h4 class="mt-0">{{ user.name }}</h4> - <p class="text-muted"><a v-bind:href="user.web_url">@{{ user.username }}</a> - Created at {{ user.created_at | readable_date }}</p> + <p class="text-muted"><a v-bind:href="user.web_url">@{{ user.username }}</a> - {{ user.state }} - Created at {{ user.created_at | readable_date }}</p> <!-- Read if current user is an admin, show advanced features --> <template v-if="false"> - <a href="#" @click.prevent="user.http.fetch()" class="btn btn-sm btn-primary" title="Reload User Data"><i class="fa fa-cog"></i></a> - <a href="#" @click.prevent="user.http.destroy()" class="btn btn-sm btn-danger" title="Remove User"><i class="fa fa-eraser"></i></a> + <a href="#" @click.prevent="user.http.fetch()" class="btn btn-sm btn-outline-primary" title="Reload User Data"><i class="fa fa-cog"></i></a> + <a href="#" @click.prevent="user.state == 'blocked' ? user.http.unblock() : user.http.block()" class="btn btn-sm btn-outline-warning" :title="user.state == 'blocked' ? 'Unblock' : 'Block'"><i class="fa" :class="{ 'fa-lock': user.state != 'blocked', 'fa-unlock': user.state == 'blocked' }"></i></a> + <a href="#" @click.prevent="user.http.destroy()" class="btn btn-sm btn-outline-danger" title="Remove User"><i class="fa fa-eraser"></i></a> </template> </div> </li> diff --git a/client/models/user.js b/client/models/user.js index b6c26e1..b1be20a 100644 --- a/client/models/user.js +++ b/client/models/user.js @@ -35,6 +35,18 @@ var User = module.exports = { } }, update: false, + block: { + method: 'POST', + route: '{id}/block', + apply: true, + data: false, + }, + unblock: { + method: 'POST', + route: '{id}/unblock', + apply: true, + data: false, + } } }, }; diff --git a/server/auth.js b/server/auth.js index 68fecbd..9eba839 100644 --- a/server/auth.js +++ b/server/auth.js @@ -40,7 +40,7 @@ router.get('/', (req, res) => { console.log('GET: /auth'); if (req.user) { - res.send(req.user._json); + res.send(Object.assign({}, req.user._json, { user_limit: config.external_limit })); } else { res.status(401).send({ message: 'Not authenticated' }); } diff --git a/server/db.js b/server/db.js index 62bc830..47620d8 100644 --- a/server/db.js +++ b/server/db.js @@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS external_users ( user_id INTEGER NOT NULL, owner_id INTEGER NOT NULL, username VARCHAR(256) NOT NULL, - active BOOLEAN DEFAULT TRUE, + state VARCHAR(16) DEFAULT 'active', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); diff --git a/server/users.js b/server/users.js index 533d985..f869370 100644 --- a/server/users.js +++ b/server/users.js @@ -13,6 +13,26 @@ const axios = require('axios').create({ } }); +router.get('/audit', async (req, res) => { + console.log('GET: /users/audit'); + + try { + const queryText = 'SELECT * FROM audit_events WHERE user_id = $1'; + console.log('> DB Query:'); + console.log(queryText); + const dbResponse = await db.query(queryText, [req.user.id]); + console.log('> DB Response:'); + console.log(dbResponse); + var rows = dbResponse.rows; + + res.send(rows); + } catch(err) { + console.log("> DB Error:"); + console.log(err); + return res.status(500).send({ 'message': "Database error occured" }); + } +}); + router.get('/', async (req, res) => { console.log('GET: /users'); @@ -25,7 +45,7 @@ router.get('/', async (req, res) => { console.log(dbResponse); var rows = dbResponse.rows; - res.send(rows.map((row) => row.id)); + res.send(rows.map((row) => row.user_id)); } catch(err) { console.log("> DB Error:"); console.log(err); @@ -40,6 +60,22 @@ router.post('/', async (req, res) => { .filter( key => !['admin', 'skip_confirmation'].includes(key) ) .reduce( (rs, key) => (rs[key] = req.body[key], rs), {} ); + try { + const queryText = 'SELECT * FROM external_users WHERE owner_id = $1'; + console.log('> DB Query:'); + console.log(queryText); + const dbResponse = await db.query(queryText, [req.user.id]); + console.log('> DB Response:'); + console.log(dbResponse); + + if (dbResponse.rowCount >= config.external_limit) { + return res.status(400).send({ 'message': 'External user limit reached' }); + } + } catch(err) { + console.log("> DB Error:"); + console.log(err); + return res.status(500).send({ 'message': "Database error occured" }); + } // TODO: Apply further validation on input // XXX Make sure user is allowed to create @@ -71,7 +107,7 @@ router.post('/', async (req, res) => { const queryText = 'INSERT INTO audit_events(event, user_id, message) VALUES($1, $2, $3)'; console.log('> DB Query:'); console.log(queryText); - const auditresp = await db.query(queryText, ['user.create', req.user.id, `Created account: ${dbResponse.name} <${dbResponse.email}>, username: ${dbResponse.username}`]); + const auditresp = await db.query(queryText, ['user.create', req.user.id, `Created account: ${data.name} <${data.email}>, username: ${data.username}`]); console.log('> DB Response:'); console.log(auditresp); } catch(err) { -- GitLab