Skip to content

Commit

Permalink
Merge remote-tracking branch 'rocket.chat/develop' into HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
SeRoNet Concourse committed Jun 30, 2021
2 parents 92b2406 + 1ad0e60 commit fd79be1
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 26 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ We're hiring developers, support people, and product managers all the time. Plea

## Get the Latest News

* Twitter - Follow [Rocket.Chat](https://twitter.com/RocketChat)
* Blog - Get the latest updates from the [Rocket.Chat blog](https://rocket.chat/blog/).
* Facebook - Follow [Rocket.Chat](https://www.facebook.com/RocketChatApp/)
* LinkedIn - Follow [Rocket.Chat](https://www.linkedin.com/company/rocket-chat/)
* Youtube - Follow [Rocket.Chat](https://www.youtube.com/channel/UCin9nv7mUjoqrRiwrzS5UVQ)
* Email - Subscribe to our [newsletter](https://rocket.chat/newsletter/)
* [Twitter](https://twitter.com/RocketChat)
* [Blog](https://rocket.chat/blog/)
* [Facebook](https://www.facebook.com/RocketChatApp/)
* [LinkedIn](https://www.linkedin.com/company/rocket-chat/)
* [Youtube](https://www.youtube.com/channel/UCin9nv7mUjoqrRiwrzS5UVQ)
* [Email Newsletter](https://rocket.chat/newsletter/)

Any other questions, mail us at [[email protected]]([email protected]). We’d love to meet you!

Expand Down
32 changes: 32 additions & 0 deletions app/api/server/v1/roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,35 @@ API.v1.addRoute('roles.update', { authRequired: true }, {
});
},
});

API.v1.addRoute('roles.delete', { authRequired: true }, {
post() {
check(this.bodyParams, {
roleId: String,
});

if (!hasPermission(this.userId, 'access-permissions')) {
throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed');
}

const role = Roles.findOneByIdOrName(this.bodyParams.roleId);

if (!role) {
throw new Meteor.Error('error-invalid-roleId', 'This role does not exist');
}

if (role.protected) {
throw new Meteor.Error('error-role-protected', 'Cannot delete a protected role');
}

const existingUsers = Roles.findUsersInRole(role._id, role.scope);

if (existingUsers && existingUsers.count() > 0) {
throw new Meteor.Error('error-role-in-use', 'Cannot delete role because it\'s in use');
}

Roles.remove(role._id);

return API.v1.success();
},
});
52 changes: 33 additions & 19 deletions app/ui/client/lib/chatMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import { hasAtLeastOnePermission } from '../../../authorization/client';
import { Messages, Rooms, ChatMessage, ChatSubscription } from '../../../models/client';
import { emoji } from '../../../emoji/client';
import { generateTriggerId } from '../../../ui-message/client/ActionManager';
import { imperativeModal } from '../../../../client/lib/imperativeModal';
import GenericModal from '../../../../client/components/GenericModal';


const messageBoxState = {
Expand Down Expand Up @@ -463,24 +465,7 @@ export class ChatMessages {
prid: { $exists: true },
});

modal.open({
title: t('Are_you_sure'),
text: room ? t('The_message_is_a_discussion_you_will_not_be_able_to_recover') : t('You_will_not_be_able_to_recover'),
type: 'warning',
showCancelButton: true,
confirmButtonColor: '#DD6B55',
confirmButtonText: t('Yes_delete_it'),
cancelButtonText: t('Cancel'),
html: false,
}, () => {
modal.open({
title: t('Deleted'),
text: t('Your_entry_has_been_deleted'),
type: 'success',
timer: 1000,
showConfirmButton: false,
});

const onConfirm = () => {
if (this.editing.id === message._id) {
this.clearEditing();
}
Expand All @@ -489,12 +474,41 @@ export class ChatMessages {

this.$input.focus();
done();
}, () => {

imperativeModal.open({
component: GenericModal,
props: {
title: t('Deleted'),
children: t('Your_entry_has_been_deleted'),
variant: 'success',
onConfirm: imperativeModal.close,
onClose: imperativeModal.close,
},
});

setTimeout(imperativeModal.close, 1000);
};

const onCloseModal = () => {
imperativeModal.close();
if (this.editing.id === message._id) {
this.clearEditing();
}
this.$input.focus();
done();
};

imperativeModal.open({
component: GenericModal,
props: {
title: t('Are_you_sure'),
children: room ? t('The_message_is_a_discussion_you_will_not_be_able_to_recover') : t('You_will_not_be_able_to_recover'),
variant: 'danger',
confirmText: t('Yes_delete_it'),
onConfirm,
onClose: onCloseModal,
onCancel: onCloseModal,
},
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ callbacks.add('afterSaveMessage', function(message, room) {
setPredictedVisitorAbandonmentTime(room);
}
return message;
}, callbacks.priority.HIGH, 'save-visitor-inactivity');
}, callbacks.priority.MEDIUM, 'save-visitor-inactivity'); // This hook priority should always be less than the priority of hook "save-last-visitor-message-timestamp" bcs, the room.v.lastMessage property set there is being used here for determinting visitor abandonment
75 changes: 75 additions & 0 deletions tests/end-to-end/api/13-roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ function createRole(name, scope, description) {
});
}

function addUserToRole(roleId, username) {
return new Promise((resolve) => {
request.post(api('roles.addUserToRole'))
.set(credentials)
.send({
roleName: roleId,
username,
})
.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', roleId);
})
.end((err, req) => {
resolve(req.body.role);
});
});
}

describe('[Roles]', function() {
this.retries(0);

Expand Down Expand Up @@ -310,4 +330,59 @@ describe('[Roles]', function() {
.end(done);
});
});

describe('POST [/roles.delete]', () => {
let roleWithUser;
let roleWithoutUser;
before(async () => {
roleWithUser = await createRole(`roleWithUser-${ Date.now() }`, 'Users');
roleWithoutUser = await createRole(`roleWithoutUser-${ Date.now() }`, 'Users');

await addUserToRole(roleWithUser._id, login.user);
});

it('should delete a role that it is not being used', (done) => {
request.post(api('roles.delete'))
.set(credentials)
.send({
roleId: roleWithoutUser._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});

it('should NOT delete a role that it is protected', (done) => {
request.post(api('roles.delete'))
.set(credentials)
.send({
roleId: 'admin',
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.nested.property('error', 'Cannot delete a protected role [error-role-protected]');
})
.end(done);
});

it('should NOT delete a role that it is being used', (done) => {
request.post(api('roles.delete'))
.set(credentials)
.send({
roleId: roleWithUser._id,
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.nested.property('error', 'Cannot delete role because it\'s in use [error-role-in-use]');
})
.end(done);
});
});
});

0 comments on commit fd79be1

Please sign in to comment.