Skip to content

Commit

Permalink
feat(users): allow deleting users. Fixes MA-100 (#145)
Browse files Browse the repository at this point in the history
* feat(users): allow deleting users. Fixes MA-100

* chore: check if linked stuff is deleted as well
  • Loading branch information
serge1peshcoff authored Oct 16, 2020
1 parent 27adc50 commit 821cc08
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 10 deletions.
2 changes: 1 addition & 1 deletion lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ MemberRouter.put('/email', members.triggerEmailChange);
MemberRouter.put('/password', members.setUserPassword);
MemberRouter.get('/', members.getUser);
MemberRouter.put('/', members.updateUser);
// MemberRouter.delete('/', members.deleteUser);
MemberRouter.delete('/', members.deleteUser);

// Everything related to a specific body. Auth only (except for body details).
BodiesRouter.use(middlewares.maybeAuthorize, fetch.fetchBody);
Expand Down
20 changes: 11 additions & 9 deletions middlewares/members.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,17 @@ exports.updateUser = async (req, res) => {
});
};

// TODO: reimplement by not deleting, but anonymizing a user.
// exports.deleteUser = async (req, res) => {
// // TODO: check permissions
// await req.currentUser.destroy();
// return res.json({
// success: true,
// data: 'User is deleted.'
// });
// };
exports.deleteUser = async (req, res) => {
if (!req.permissions.hasPermission('delete:member')) {
return errors.makeForbiddenError(res, 'Permission delete:member is required, but not present.');
}

await req.currentUser.destroy();
return res.json({
success: true,
message: 'User is deleted.'
});
};

exports.setUserPassword = async (req, res) => {
if (!req.permissions.hasPermission('update:member') && req.user.id !== req.currentUser.id) {
Expand Down
107 changes: 107 additions & 0 deletions test/api/users-deleting.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
const { startServer, stopServer } = require('../../lib/server.js');
const { request } = require('../scripts/helpers');
const generator = require('../scripts/generator');
const { User, CircleMembership, BodyMembership } = require('../../models');

describe('User deleting', () => {
beforeAll(async () => {
await startServer();
});

afterAll(async () => {
await stopServer();
});

afterEach(async () => {
await generator.clearAll();
});

test('should return 404 if the user is not found', async () => {
const user = await generator.createUser({ superadmin: true });
const token = await generator.createAccessToken({}, user);

await generator.createPermission({ scope: 'global', action: 'delete', object: 'member' });

const res = await request({
uri: '/members/1337',
method: 'DELETE',
headers: { 'X-Auth-Token': token.value }
});

expect(res.statusCode).toEqual(404);
expect(res.body.success).toEqual(false);
expect(res.body).not.toHaveProperty('data');
expect(res.body).toHaveProperty('message');
});

test('should succeed if everything is okay', async () => {
const user = await generator.createUser({ superadmin: true });
const token = await generator.createAccessToken({}, user);

await generator.createPermission({ scope: 'global', action: 'delete', object: 'member' });

const res = await request({
uri: '/members/' + user.id,
method: 'DELETE',
headers: { 'X-Auth-Token': token.value }
});

expect(res.statusCode).toEqual(200);
expect(res.body.success).toEqual(true);
expect(res.body).not.toHaveProperty('errors');
expect(res.body).toHaveProperty('message');

const userFromDb = await User.findByPk(user.id);
expect(userFromDb).toEqual(null);
});

test('should fail if no permission', async () => {
const user = await generator.createUser();
const token = await generator.createAccessToken({}, user);

const otherUser = await generator.createUser();

const res = await request({
uri: '/members/' + otherUser.id,
method: 'DELETE',
headers: { 'X-Auth-Token': token.value }
});

expect(res.statusCode).toEqual(403);
expect(res.body.success).toEqual(false);
expect(res.body).not.toHaveProperty('data');
expect(res.body).toHaveProperty('message');
});

test('should delete linked things', async () => {
const user = await generator.createUser({ superadmin: true });
const token = await generator.createAccessToken({}, user);

await generator.createPermission({ scope: 'global', action: 'delete', object: 'member' });

const body = await generator.createBody();
const circle = await generator.createCircle();
await generator.createBodyMembership(body, user);
await generator.createCircleMembership(circle, user);

const res = await request({
uri: '/members/' + user.id,
method: 'DELETE',
headers: { 'X-Auth-Token': token.value }
});

expect(res.statusCode).toEqual(200);
expect(res.body.success).toEqual(true);
expect(res.body).not.toHaveProperty('errors');
expect(res.body).toHaveProperty('message');

const userFromDb = await User.findByPk(user.id);
expect(userFromDb).toEqual(null);

const bodyMembershipsCount = await BodyMembership.count({ where: { user_id: user.id } });
expect(bodyMembershipsCount).toEqual(0);

const circleMembershipsCount = await CircleMembership.count({ where: { user_id: user.id } });
expect(circleMembershipsCount).toEqual(0);
});
});

0 comments on commit 821cc08

Please sign in to comment.