2021-04-09 13:46:53 +02:00
|
|
|
import test from 'ava';
|
|
|
|
import { setupApp } from '../../helpers/test-helper';
|
|
|
|
import dbInit from '../../helpers/database-init';
|
|
|
|
import getLogger from '../../../fixtures/no-logger';
|
2021-04-22 23:40:52 +02:00
|
|
|
import User from '../../../../lib/types/user';
|
2021-04-09 13:46:53 +02:00
|
|
|
import UserStore from '../../../../lib/db/user-store';
|
|
|
|
import { AccessStore, IRole } from '../../../../lib/db/access-store';
|
|
|
|
import { RoleName } from '../../../../lib/services/access-service';
|
2021-04-27 20:47:11 +02:00
|
|
|
import EventStore from '../../../../lib/db/event-store';
|
2021-04-29 10:21:29 +02:00
|
|
|
import {
|
|
|
|
USER_CREATED,
|
|
|
|
USER_DELETED,
|
|
|
|
USER_UPDATED,
|
|
|
|
} from '../../../../lib/types/events';
|
2021-04-09 13:46:53 +02:00
|
|
|
|
|
|
|
let stores;
|
|
|
|
let db;
|
|
|
|
|
|
|
|
let userStore: UserStore;
|
2021-04-27 20:47:11 +02:00
|
|
|
let eventStore: EventStore;
|
2021-04-09 13:46:53 +02:00
|
|
|
let accessStore: AccessStore;
|
2021-04-16 10:45:15 +02:00
|
|
|
let editorRole: IRole;
|
2021-04-09 13:46:53 +02:00
|
|
|
let adminRole: IRole;
|
|
|
|
|
|
|
|
test.before(async () => {
|
|
|
|
db = await dbInit('user_admin_api_serial', getLogger);
|
|
|
|
stores = db.stores;
|
|
|
|
userStore = stores.userStore;
|
|
|
|
accessStore = stores.accessStore;
|
2021-04-27 20:47:11 +02:00
|
|
|
eventStore = stores.eventStore;
|
2021-04-09 13:46:53 +02:00
|
|
|
const roles = await accessStore.getRootRoles();
|
2021-04-16 10:45:15 +02:00
|
|
|
editorRole = roles.find(r => r.name === RoleName.EDITOR);
|
2021-04-09 13:46:53 +02:00
|
|
|
adminRole = roles.find(r => r.name === RoleName.ADMIN);
|
|
|
|
});
|
|
|
|
|
2021-04-16 15:29:23 +02:00
|
|
|
test.after.always(async () => {
|
2021-04-09 13:46:53 +02:00
|
|
|
await db.destroy();
|
|
|
|
});
|
|
|
|
|
|
|
|
test.afterEach.always(async () => {
|
|
|
|
const users = await userStore.getAll();
|
|
|
|
const deleteAll = users.map((u: User) => userStore.delete(u.id));
|
|
|
|
await Promise.all(deleteAll);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('returns empty list of users', async t => {
|
|
|
|
t.plan(1);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.get('/api/admin/user-admin')
|
|
|
|
.expect('Content-Type', /json/)
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
|
|
|
t.is(res.body.users.length, 0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('creates and returns all users', async t => {
|
|
|
|
t.plan(2);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
|
|
|
|
const createUserRequests = [...Array(20).keys()].map(i =>
|
|
|
|
request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email: `some${i}@getunleash.ai`,
|
|
|
|
name: `Some Name ${i}`,
|
2021-04-16 10:45:15 +02:00
|
|
|
rootRole: editorRole.id,
|
2021-04-09 13:46:53 +02:00
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json'),
|
|
|
|
);
|
|
|
|
|
|
|
|
await Promise.all(createUserRequests);
|
|
|
|
|
|
|
|
return request
|
|
|
|
.get('/api/admin/user-admin')
|
|
|
|
.expect('Content-Type', /json/)
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
|
|
|
t.is(res.body.users.length, 20);
|
2021-04-16 10:45:15 +02:00
|
|
|
t.is(res.body.users[2].rootRole, editorRole.id);
|
2021-04-09 13:46:53 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2021-04-16 10:45:15 +02:00
|
|
|
test.serial('creates editor-user without password', async t => {
|
2021-04-09 13:46:53 +02:00
|
|
|
t.plan(3);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email: 'some@getunelash.ai',
|
|
|
|
name: 'Some Name',
|
2021-04-16 10:45:15 +02:00
|
|
|
rootRole: editorRole.id,
|
2021-04-09 13:46:53 +02:00
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json')
|
|
|
|
.expect(201)
|
|
|
|
.expect(res => {
|
|
|
|
t.is(res.body.email, 'some@getunelash.ai');
|
2021-04-16 10:45:15 +02:00
|
|
|
t.is(res.body.rootRole, editorRole.id);
|
2021-04-09 13:46:53 +02:00
|
|
|
t.truthy(res.body.id);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('creates admin-user with password', async t => {
|
|
|
|
t.plan(6);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
const { body } = await request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email: 'some@getunelash.ai',
|
|
|
|
name: 'Some Name',
|
|
|
|
password: 'some-strange-pass-123-GH',
|
|
|
|
rootRole: adminRole.id,
|
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json')
|
|
|
|
.expect(201);
|
|
|
|
|
|
|
|
t.is(body.rootRole, adminRole.id);
|
|
|
|
|
|
|
|
const user = await userStore.get({ id: body.id });
|
|
|
|
t.is(user.email, 'some@getunelash.ai');
|
|
|
|
t.is(user.name, 'Some Name');
|
|
|
|
|
|
|
|
const passwordHash = userStore.getPasswordHash(body.id);
|
|
|
|
t.truthy(passwordHash);
|
|
|
|
|
|
|
|
const roles = await stores.accessStore.getRolesForUserId(body.id);
|
|
|
|
t.is(roles.length, 1);
|
|
|
|
t.is(roles[0].name, RoleName.ADMIN);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('requires known root role', async t => {
|
|
|
|
t.plan(0);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email: 'some@getunelash.ai',
|
|
|
|
name: 'Some Name',
|
|
|
|
rootRole: 'Unknown',
|
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json')
|
|
|
|
.expect(400);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('update user name', async t => {
|
|
|
|
t.plan(3);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
const { body } = await request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email: 'some@getunelash.ai',
|
|
|
|
name: 'Some Name',
|
2021-04-16 10:45:15 +02:00
|
|
|
rootRole: editorRole.id,
|
2021-04-09 13:46:53 +02:00
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json');
|
|
|
|
|
|
|
|
return request
|
|
|
|
.put(`/api/admin/user-admin/${body.id}`)
|
|
|
|
.send({
|
|
|
|
name: 'New name',
|
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json')
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
|
|
|
t.is(res.body.email, 'some@getunelash.ai');
|
|
|
|
t.is(res.body.name, 'New name');
|
|
|
|
t.is(res.body.id, body.id);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('should delete user', async t => {
|
|
|
|
t.plan(0);
|
|
|
|
|
2021-04-22 23:40:52 +02:00
|
|
|
const user = await userStore.insert({ email: 'some@mail.com' });
|
2021-04-09 13:46:53 +02:00
|
|
|
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request.delete(`/api/admin/user-admin/${user.id}`).expect(200);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('validator should require strong password', async t => {
|
|
|
|
t.plan(0);
|
|
|
|
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.post('/api/admin/user-admin/validate-password')
|
|
|
|
.send({ password: 'simple' })
|
|
|
|
.expect(400);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('validator should accept strong password', async t => {
|
|
|
|
t.plan(0);
|
|
|
|
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.post('/api/admin/user-admin/validate-password')
|
|
|
|
.send({ password: 'simple123-_ASsad' })
|
|
|
|
.expect(200);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('should change password', async t => {
|
|
|
|
t.plan(0);
|
|
|
|
|
2021-04-22 23:40:52 +02:00
|
|
|
const user = await userStore.insert({ email: 'some@mail.com' });
|
2021-04-09 13:46:53 +02:00
|
|
|
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.post(`/api/admin/user-admin/${user.id}/change-password`)
|
|
|
|
.send({ password: 'simple123-_ASsad' })
|
|
|
|
.expect(200);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('should search for users', async t => {
|
|
|
|
t.plan(2);
|
|
|
|
|
2021-04-22 23:40:52 +02:00
|
|
|
await userStore.insert({ email: 'some@mail.com' });
|
|
|
|
await userStore.insert({ email: 'another@mail.com' });
|
|
|
|
await userStore.insert({ email: 'another2@mail.com' });
|
2021-04-09 13:46:53 +02:00
|
|
|
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.get('/api/admin/user-admin/search?q=another')
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
|
|
|
t.is(res.body.length, 2);
|
|
|
|
t.true(res.body.some(u => u.email === 'another@mail.com'));
|
|
|
|
});
|
|
|
|
});
|
2021-04-23 10:58:47 +02:00
|
|
|
|
|
|
|
test.serial(
|
|
|
|
'Creates a user and includes inviteLink and emailConfigured',
|
|
|
|
async t => {
|
|
|
|
t.plan(5);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
return request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email: 'some@getunelash.ai',
|
|
|
|
name: 'Some Name',
|
|
|
|
rootRole: editorRole.id,
|
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json')
|
|
|
|
.expect(201)
|
|
|
|
.expect(res => {
|
|
|
|
t.is(res.body.email, 'some@getunelash.ai');
|
|
|
|
t.is(res.body.rootRole, editorRole.id);
|
|
|
|
t.truthy(res.body.inviteLink);
|
|
|
|
t.falsy(res.body.emailSent);
|
|
|
|
t.truthy(res.body.id);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
);
|
2021-04-27 20:47:11 +02:00
|
|
|
|
|
|
|
test.serial('generates USER_CREATED event', async t => {
|
|
|
|
t.plan(5);
|
|
|
|
const email = 'some@getunelash.ai';
|
|
|
|
const name = 'Some Name';
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
const { body } = await request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email,
|
|
|
|
name,
|
|
|
|
password: 'some-strange-pass-123-GH',
|
|
|
|
rootRole: adminRole.id,
|
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json')
|
|
|
|
.expect(201);
|
|
|
|
|
|
|
|
const events = await eventStore.getEvents();
|
|
|
|
|
2021-04-29 10:21:29 +02:00
|
|
|
t.is(events[0].type, USER_CREATED);
|
2021-04-27 20:47:11 +02:00
|
|
|
t.is(events[0].data.email, email);
|
|
|
|
t.is(events[0].data.name, name);
|
|
|
|
t.is(events[0].data.id, body.id);
|
|
|
|
t.falsy(events[0].data.password);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('generates USER_DELETED event', async t => {
|
|
|
|
t.plan(3);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
|
|
|
|
const user = await userStore.insert({ email: 'some@mail.com' });
|
|
|
|
await request.delete(`/api/admin/user-admin/${user.id}`);
|
|
|
|
|
|
|
|
const events = await eventStore.getEvents();
|
2021-04-29 10:21:29 +02:00
|
|
|
t.is(events[0].type, USER_DELETED);
|
2021-04-27 20:47:11 +02:00
|
|
|
t.is(events[0].data.id, user.id);
|
|
|
|
t.is(events[0].data.email, user.email);
|
|
|
|
});
|
|
|
|
|
|
|
|
test.serial('generates USER_UPDATED event', async t => {
|
|
|
|
t.plan(3);
|
|
|
|
const request = await setupApp(stores);
|
|
|
|
const { body } = await request
|
|
|
|
.post('/api/admin/user-admin')
|
|
|
|
.send({
|
|
|
|
email: 'some@getunelash.ai',
|
|
|
|
name: 'Some Name',
|
|
|
|
rootRole: editorRole.id,
|
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json');
|
|
|
|
|
|
|
|
await request
|
|
|
|
.put(`/api/admin/user-admin/${body.id}`)
|
|
|
|
.send({
|
|
|
|
name: 'New name',
|
|
|
|
})
|
|
|
|
.set('Content-Type', 'application/json');
|
|
|
|
|
|
|
|
const events = await eventStore.getEvents();
|
2021-04-29 10:21:29 +02:00
|
|
|
t.is(events[0].type, USER_UPDATED);
|
2021-04-27 20:47:11 +02:00
|
|
|
t.is(events[0].data.id, body.id);
|
|
|
|
t.is(events[0].data.name, 'New name');
|
|
|
|
});
|