diff --git a/packages/rocketchat-api/server/v1/roles.js b/packages/rocketchat-api/server/v1/roles.js index 8ac315ef9c2..1172ae7f155 100644 --- a/packages/rocketchat-api/server/v1/roles.js +++ b/packages/rocketchat-api/server/v1/roles.js @@ -5,3 +5,47 @@ RocketChat.API.v1.addRoute('roles.list', { authRequired: true }, { return RocketChat.API.v1.success({ roles }); }, }); + +RocketChat.API.v1.addRoute('roles.create', { authRequired: true }, { + post() { + check(this.bodyParams, { + name: String, + scope: Match.Maybe(String), + description: Match.Maybe(String), + }); + + const roleData = { + name: this.bodyParams.name, + scope: this.bodyParams.scope, + description: this.bodyParams.description, + }; + + Meteor.runAsUser(this.userId, () => { + Meteor.call('authorization:saveRole', roleData); + }); + + return RocketChat.API.v1.success({ + role: RocketChat.models.Roles.findOneByIdOrName(roleData.name, { fields: RocketChat.API.v1.defaultFieldsToExclude }), + }); + }, +}); + +RocketChat.API.v1.addRoute('roles.addUserToRole', { authRequired: true }, { + post() { + check(this.bodyParams, { + roleName: String, + username: String, + roomId: Match.Maybe(String), + }); + + const user = this.getUserFromParams(); + + Meteor.runAsUser(this.userId, () => { + Meteor.call('authorization:addUserToRole', this.bodyParams.roleName, user.username, this.bodyParams.roomId); + }); + + return RocketChat.API.v1.success({ + role: RocketChat.models.Roles.findOneByIdOrName(this.bodyParams.roleName, { fields: RocketChat.API.v1.defaultFieldsToExclude }), + }); + }, +}); diff --git a/packages/rocketchat-authorization/server/models/Roles.js b/packages/rocketchat-authorization/server/models/Roles.js index b57261411af..c470f8c5664 100644 --- a/packages/rocketchat-authorization/server/models/Roles.js +++ b/packages/rocketchat-authorization/server/models/Roles.js @@ -63,6 +63,18 @@ class ModelRoles extends RocketChat.models._Base { } return true; } + + findOneByIdOrName(_idOrName, options) { + const query = { + $or: [{ + _id: _idOrName, + }, { + name: _idOrName, + }], + }; + + return this.findOne(query, options); + } } RocketChat.models.Roles = new ModelRoles('roles'); diff --git a/tests/data/api-data.js b/tests/data/api-data.js index 326ca57b7ad..090b204dc13 100644 --- a/tests/data/api-data.js +++ b/tests/data/api-data.js @@ -1,4 +1,5 @@ import { publicChannelName, privateChannelName } from '../data/channel.js'; +import { roleNameUsers, roleNameSubscriptions, roleScopeUsers, roleScopeSubscriptions, roleDescription } from '../data/role.js'; import { username, email, adminUsername, adminPassword } from '../data/user.js'; import supertest from 'supertest'; export const request = supertest('http://localhost:3000'); @@ -9,6 +10,12 @@ export const apiEmail = `api${ email }`; export const apiPublicChannelName = `api${ publicChannelName }`; export const apiPrivateChannelName = `api${ privateChannelName }`; +export const apiRoleNameUsers = `api${ roleNameUsers }`; +export const apiRoleNameSubscriptions = `api${ roleNameSubscriptions }`; +export const apiRoleScopeUsers = `${ roleScopeUsers }`; +export const apiRoleScopeSubscriptions = `${ roleScopeSubscriptions }`; +export const apiRoleDescription = `api${ roleDescription }`; + export const targetUser = {}; export const channel = {}; export const group = {}; diff --git a/tests/data/role.js b/tests/data/role.js new file mode 100644 index 00000000000..42d4e9deafe --- /dev/null +++ b/tests/data/role.js @@ -0,0 +1,5 @@ +export const roleNameUsers = `role-name-test-users-${ Date.now() }`; +export const roleNameSubscriptions = `role-name-test-subscriptions-${ Date.now() }`; +export const roleScopeUsers = 'Users'; +export const roleScopeSubscriptions = 'Subscriptions'; +export const roleDescription = `role-description-test-${ Date.now() }`; diff --git a/tests/end-to-end/api/13-roles.js b/tests/end-to-end/api/13-roles.js index 3f8bef752af..3c8fd7076fa 100644 --- a/tests/end-to-end/api/13-roles.js +++ b/tests/end-to-end/api/13-roles.js @@ -1,14 +1,26 @@ /* eslint-env mocha */ /* globals expect */ -import { getCredentials, api, request, credentials } from '../../data/api-data.js'; +import { + getCredentials, + api, + request, + credentials, + group, + login, + apiRoleNameUsers, + apiRoleNameSubscriptions, + apiRoleScopeUsers, + apiRoleDescription, + apiRoleScopeSubscriptions, +} from '../../data/api-data.js'; describe('[Roles]', function() { this.retries(0); before((done) => getCredentials(done)); - describe('GET [/roles]', () => { + describe('GET [/roles.list]', () => { it('should return all roles', (done) => { request.get(api('roles.list')) .set(credentials) @@ -20,4 +32,84 @@ describe('[Roles]', function() { .end(done); }); }); + + describe('POST [/roles.create]', () => { + it('should create a new role with Users scope', (done) => { + request.post(api('roles.create')) + .set(credentials) + .send({ + name: apiRoleNameUsers, + description: apiRoleDescription, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('role._id', apiRoleNameUsers); + expect(res.body).to.have.nested.property('role.name', apiRoleNameUsers); + expect(res.body).to.have.nested.property('role.scope', apiRoleScopeUsers); + expect(res.body).to.have.nested.property('role.description', apiRoleDescription); + }) + .end(done); + }); + + it('should create a new role with Subscriptions scope', (done) => { + request.post(api('roles.create')) + .set(credentials) + .send({ + name: apiRoleNameSubscriptions, + scope: apiRoleScopeSubscriptions, + description: apiRoleDescription, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('role._id', apiRoleNameSubscriptions); + expect(res.body).to.have.nested.property('role.name', apiRoleNameSubscriptions); + expect(res.body).to.have.nested.property('role.scope', apiRoleScopeSubscriptions); + expect(res.body).to.have.nested.property('role.description', apiRoleDescription); + }) + .end(done); + }); + }); + + describe('POST [/roles.addUserToRole]', () => { + it('should assign a role with User scope to an user', (done) => { + request.post(api('roles.addUserToRole')) + .set(credentials) + .send({ + roleName: apiRoleNameUsers, + username: login.user, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('role._id', apiRoleNameUsers); + expect(res.body).to.have.nested.property('role.name', apiRoleNameUsers); + expect(res.body).to.have.nested.property('role.scope', apiRoleScopeUsers); + }) + .end(done); + }); + + it('should assign a role with Subscriptions scope to an user', (done) => { + request.post(api('roles.addUserToRole')) + .set(credentials) + .send({ + roleName: apiRoleNameSubscriptions, + username: login.user, + roomId: group._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('role._id', apiRoleNameSubscriptions); + expect(res.body).to.have.nested.property('role.name', apiRoleNameSubscriptions); + expect(res.body).to.have.nested.property('role.scope', apiRoleScopeSubscriptions); + }) + .end(done); + }); + }); });