Skip to content

Commit 624bd9a

Browse files
committed
add new group - create project access
1 parent 1e8db5c commit 624bd9a

6 files changed

Lines changed: 93 additions & 6 deletions

File tree

app/middleware/acl.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ const SPECIAL_CASES = [
3434
PUT: [{name: 'admin'}, {name: 'manager'}, {name: 'variant-text edit access'}],
3535
DELETE: [{name: 'admin'}, {name: 'manager'}, {name: 'variant-text edit access'}],
3636
},
37+
{
38+
path: pathToRegexp('/api/user/search'),
39+
GET: [{name: 'admin'}, {name: 'manager'}, {name: 'create project access'}],
40+
},
3741
{
3842
path: pathToRegexp('/api/user/:user'),
3943
GET: [{name: 'admin'}, {name: 'manager'}, {name: 'report assignment access'}],
@@ -50,7 +54,7 @@ const SPECIAL_CASES = [
5054
POST: [{name: 'admin'}, {name: 'manager'}, {name: 'create report access'}],
5155
},
5256
{ // TODO double check these permissions
53-
path: pathToRegexp('/api/reports/:report/observed-variant-annotation'),
57+
path: pathToRegexp('/api/reports/:report/observed-variant-annotations'),
5458
POST: [{name: 'admin'}, {name: 'manager'}, {name: 'create report access'}],
5559
PUT: [{name: 'admin'}, {name: 'manager'}, {name: 'create report access'}],
5660
},
@@ -92,11 +96,11 @@ const SPECIAL_CASES = [
9296
},
9397
{
9498
path: pathToRegexp('/api/project'),
95-
POST: [{name: 'admin'}],
99+
POST: [{name: 'admin'}, {name: 'manager'}, {name: 'create project access'}],
96100
},
97101
{
98102
path: pathToRegexp('/api/project/:project'),
99-
PUT: [{name: 'admin'}],
103+
PUT: [{name: 'admin'}, {name: 'manager'}, {name: 'create project access'}],
100104
DELETE: [{name: 'admin'}],
101105
},
102106
{

app/routes/project/project.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ const db = require('../../models');
77
const logger = require('../../log');
88

99
const projectMiddleware = require('../../middleware/project');
10-
const {hasMasterAccess} = require('../../libs/helperFunctions');
10+
const {hasMasterAccess, hasAccess} = require('../../libs/helperFunctions');
11+
12+
const CREATE_PROJECT_ACCESS = ['admin', 'manager', 'create project access'];
1113

1214
const schemaGenerator = require('../../schemas/schemaGenerator');
1315
const validateAgainstSchema = require('../../libs/validateAgainstSchema');
@@ -115,6 +117,12 @@ router.route('/')
115117
}
116118
})
117119
.post(async (req, res) => {
120+
if (!hasAccess(req.user, CREATE_PROJECT_ACCESS)) {
121+
return res.status(HTTP_STATUS.FORBIDDEN).json({
122+
error: {message: 'You do not have the correct permissions to create a project'},
123+
});
124+
}
125+
118126
try {
119127
// validate request against the model
120128
validateAgainstSchema(createSchema, req.body);
@@ -135,6 +143,11 @@ router.route('/')
135143
return res.status(HTTP_STATUS.CONFLICT).json({error: {message: 'Project already exists'}});
136144
}
137145

146+
await db.models.userProject.findOrCreate({
147+
where: {project_id: result.id, user_id: req.user.id},
148+
defaults: {project_id: result.id, user_id: req.user.id},
149+
});
150+
138151
return res.status(HTTP_STATUS.CREATED).json(result.view('public'));
139152
} catch (error) {
140153
logger.error(`Error while trying to find/create project ${error}`);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const {v4: uuidv4} = require('uuid');
2+
3+
const createProjectGroup = 'create project access';
4+
5+
module.exports = {
6+
up: async (queryInterface) => {
7+
await queryInterface.sequelize.query(
8+
// eslint-disable-next-line no-multi-str
9+
`INSERT INTO user_groups (name, created_at, updated_at, ident)\
10+
VALUES('${createProjectGroup}',\
11+
'${new Date().toLocaleString()}',\
12+
'${new Date().toLocaleString()}',\
13+
'${uuidv4()}');`,
14+
);
15+
},
16+
17+
down: async (queryInterface) => {
18+
await queryInterface.sequelize.query(`
19+
DELETE FROM user_groups WHERE name = '${createProjectGroup}'
20+
`);
21+
},
22+
};

seeders/constants/user_groups.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,11 @@
6464
"ident": "2841d7dd-80a4-47e1-abcf-f22fa9fbe187",
6565
"name": "create report access",
6666
"description": null
67+
},
68+
{
69+
"id": 53,
70+
"ident": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
71+
"name": "create project access",
72+
"description": null
6773
}
6874
]

test/middleware/acl.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,36 @@ describe('Testing ACL methods', () => {
213213
expect(res.status).not.toHaveBeenCalledWith(FORBIDDEN);
214214
});
215215

216+
test('Special case for create project with create project access', async () => {
217+
req.user.groups = [{name: 'create project access'}];
218+
req.originalUrl = '/api/project';
219+
req.method = 'POST';
220+
221+
await Acl(req, res, () => {});
222+
223+
expect(res.status).not.toHaveBeenCalledWith(FORBIDDEN);
224+
});
225+
226+
test('Create project is forbidden without create project access', async () => {
227+
req.user.groups = [{name: 'hello'}];
228+
req.originalUrl = '/api/project';
229+
req.method = 'POST';
230+
231+
await Acl(req, res, () => {});
232+
233+
expect(res.status).toHaveBeenCalledWith(FORBIDDEN);
234+
});
235+
236+
test('User search allows create project access', async () => {
237+
req.user.groups = [{name: 'create project access'}];
238+
req.originalUrl = '/api/user/search';
239+
req.method = 'GET';
240+
241+
await Acl(req, res, () => {});
242+
243+
expect(res.status).not.toHaveBeenCalledWith(FORBIDDEN);
244+
});
245+
216246
test('Special case (matching route and method) where the user is not allowed to edit', async () => {
217247
req.originalUrl = '/api/template/fsddfds';
218248
req.method = 'PUT';

test/routes/project/project.test.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const CONFIG = require('../../../app/config');
88
const {listen} = require('../../../app');
99

1010
CONFIG.set('env', 'test');
11-
const {username, managerUsername, password} = CONFIG.get('testing');
11+
const {username, managerUsername, bioinformaticianUsername, password} = CONFIG.get('testing');
1212

1313
const LONGER_TIMEOUT = 100000;
1414

@@ -112,14 +112,26 @@ describe('/project', () => {
112112
.send({name: 'new-project-test-project01'})
113113
.expect(HTTP_STATUS.CREATED);
114114

115+
const createdProject = await db.models.project.findOne({
116+
where: {ident: res.body.ident},
117+
});
118+
const requestUser = await db.models.user.findOne({
119+
where: {username},
120+
});
121+
const userProjectBinding = await db.models.userProject.findOne({
122+
where: {project_id: createdProject.id, user_id: requestUser.id},
123+
});
124+
125+
expect(userProjectBinding).not.toBeNull();
126+
115127
// Remove test project from db
116128
await db.models.project.destroy({where: {ident: res.body.ident}, force: true});
117129
});
118130

119131
test('/ - 403 forbidden to non-admin', async () => {
120132
await request
121133
.post('/api/project')
122-
.auth(managerUsername, password)
134+
.auth(bioinformaticianUsername, password)
123135
.type('json')
124136
.send({name: 'new-project-test-project02'})
125137
.expect(HTTP_STATUS.FORBIDDEN);

0 commit comments

Comments
 (0)