From 90da2a15228e6037431104ac5e092e9f34bdf7cc Mon Sep 17 00:00:00 2001 From: Maciej Ziarkowski Date: Thu, 15 Aug 2019 16:12:01 +0100 Subject: [PATCH] Add user delete API endpoint The deleted user username will be changed to 'deleted_' plus the 13 initial characters of the standard format user_id. Email, hashed password and API key are all cleared for the user. The endpoint is currently only available through /api/users/me and only allows a logged-in user to delete their own account. --- app/src/api/api.ts | 61 +++++++++++++++++++++++++----------- app/src/api/services/user.ts | 20 +++++++++++- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/app/src/api/api.ts b/app/src/api/api.ts index 2ab9ba3b..44b4ad07 100644 --- a/app/src/api/api.ts +++ b/app/src/api/api.ts @@ -1,7 +1,7 @@ import express from 'express'; import bodyParser from 'body-parser'; -import { authUser, createUser, getUserById, getNewUserAPIKey } from './services/user'; +import { authUser, createUser, getUserById, getNewUserAPIKey, deleteUser } from './services/user'; import { queryLocation } from './services/search'; import buildingsRouter from './routes/buildingsRouter'; @@ -45,6 +45,35 @@ server.post('/users', function (req, res) { }); }); +// GET own user info +server.route('/users/me') + .get(function (req, res) { + if (!req.session.user_id) { + res.send({ error: 'Must be logged in' }); + return + } + + getUserById(req.session.user_id).then(function (user) { + res.send(user); + }).catch(function (error) { + res.send(error); + }); + }) + .delete((req, res) => { + if (!req.session.user_id) { + return res.send({ error: 'Must be logged in' }); + } + console.log(`Deleting user ${req.session.user_id}`); + + deleteUser(req.session.user_id).then( + () => logout(req.session) + ).then(() => { + res.send({ success: true }); + }).catch(err => { + res.send({ error: err }); + }); + }) + // POST user auth server.post('/login', function (req, res) { authUser(req.body.username, req.body.password).then(function (user: any) { // TODO: remove any @@ -61,29 +90,23 @@ server.post('/login', function (req, res) { // POST user logout server.post('/logout', function (req, res) { - req.session.user_id = undefined; - req.session.destroy(function (err) { - if (err) { - console.error(err); - res.send({ error: 'Failed to end session' }) - } + logout(req.session).then(() => { res.send({ success: true }); + }).catch(err => { + console.error(err); + res.send({ error: 'Failed to end session'}); }); }); -// GET own user info -server.get('/users/me', function (req, res) { - if (!req.session.user_id) { - res.send({ error: 'Must be logged in' }); - return - } - - getUserById(req.session.user_id).then(function (user) { - res.send(user); - }).catch(function (error) { - res.send(error); +function logout(session) { + return new Promise((resolve, reject) => { + session.user_id = undefined; + session.destroy(err => { + if (err) return reject(err); + return resolve(); + }); }); -}); +} // POST generate API key server.post('/api/key', function (req, res) { diff --git a/app/src/api/services/user.ts b/app/src/api/services/user.ts index da7e2e5d..ec02b856 100644 --- a/app/src/api/services/user.ts +++ b/app/src/api/services/user.ts @@ -122,4 +122,22 @@ function authAPIUser(key) { }); } -export { getUserById, createUser, authUser, getNewUserAPIKey, authAPIUser } +function deleteUser(id) { + return db.none( + `UPDATE users + SET + email = null, + pass = null, + api_key = null, + username = concat('deleted_', cast(user_id as char(13))), + is_deleted = true, + deleted_on = now() at time zone 'utc' + WHERE user_id = $1 + `, [id] + ).catch((error) => { + console.error('Error:', error); + return {error: 'Database error'}; + }); +} + +export { getUserById, createUser, authUser, getNewUserAPIKey, authAPIUser, deleteUser }