Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Edit user permissions #7309

Merged
merged 11 commits into from
Jul 27, 2017
2 changes: 2 additions & 0 deletions packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"Add_custom_oauth": "Add custom oauth",
"Add_Domain": "Add Domain",
"Add_manager": "Add manager",
"Add_role": "Add Role",
"Add_user": "Add user",
"Add_User": "Add User",
"Add_users": "Add users",
Expand Down Expand Up @@ -1329,6 +1330,7 @@
"Select_an_avatar": "Select an avatar",
"Select_file": "Select file",
"Select_service_to_login": "Select a service to login to load your picture or upload one directly from your computer",
"Select_role": "Select a Role",
"Select_user": "Select user",
"Select_users": "Select users",
"Selected_agents": "Selected agents",
Expand Down
4 changes: 4 additions & 0 deletions packages/rocketchat-theme/client/imports/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -3524,6 +3524,10 @@ body:not(.is-cordova) {
& #password {
width: 70%;
}

& #roleSelect {
width: 70%;
}
}

& nav {
Expand Down
18 changes: 18 additions & 0 deletions packages/rocketchat-theme/client/imports/chip.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.chip-container {
list-style-type: none;
margin: 15px;
}

.chip-container li {
display: inline-block;
background-color: #dddddd;
border-radius: 10px;
padding: 2px 8px 2px 2px;
margin: 1px 0;
cursor: pointer;
}

.chip-container li .icon-plus-circled {
opacity: 0.5;
font-size: 0.8rem;
}
1 change: 1 addition & 0 deletions packages/rocketchat-theme/client/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
@import 'imports/keyframes.css';
@import 'imports/forms.css';
@import 'imports/base.css';
@import 'imports/chip.css';
@import 'imports/rtl.css';

25 changes: 19 additions & 6 deletions packages/rocketchat-ui-flextab/client/tabs/userEdit.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,28 @@ <h3>{{_ "Add_User"}}</h3>
</label>
</div>
{{/if}}
{{#unless user}}
<div class="input-line">
<label for="role">{{_ "Role"}}</label>
<select id="role">
{{#each role}}
<option value="{{_id}}" selected="{{selectUserRole}}">{{name}}</option>
<div class="input-line" data="{{this}}">
<label for="role">{{_ "Add_Role"}}</label>
{{#let roles=role}}
<select id="roleSelect" {{disabled role}}>
<option value="placeholder" disabled selected>{{_ "Select_role"}}</option>
{{#each roles}}
<option value="{{_id}}">{{name}}</option>
{{/each}}
</select>
{{/let}}
<button id="addRole" class="button" {{disabled role}}>{{_ 'Add_role'}}</button>

<fieldset>
<ul class="chip-container current-user-roles">
{{#each userRoles}}
<li class="remove-role" title="{{this}}"><i class="icon-cancel-circled"></i>{{this}}</li>
{{/each}}
</ul>
</fieldset>
</div>

{{#unless user}}
<div class="input-line">
<label for="joinDefaultChannels">
<input type="checkbox" id="joinDefaultChannels" value="1" checked="true">
Expand Down
59 changes: 49 additions & 10 deletions packages/rocketchat-ui-flextab/client/tabs/userEdit.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import toastr from 'toastr';

Template.userEdit.helpers({

disabled(cursor) {
return cursor.count() === 0 ? 'disabled' : '';
},
canEditOrAdd() {
return (Template.instance().user && RocketChat.authz.hasAtLeastOnePermission('edit-other-user-info')) || (!Template.instance().user && RocketChat.authz.hasAtLeastOnePermission('create-user'));
},
Expand All @@ -14,13 +18,12 @@ Template.userEdit.helpers({
},

role() {
return RocketChat.models.Roles.find({}, { sort: { description: 1, _id: 1 } });
const roles = Template.instance().roles.get();
return RocketChat.models.Roles.find({_id: {$nin:roles}, scope: 'Users'}, { sort: { description: 1, _id: 1 } });
},

selectUserRole() {
if (this._id === 'user') {
return 'selected';
}
userRoles() {
return Template.instance().roles.get();
},

name() {
Expand All @@ -32,26 +35,50 @@ Template.userEdit.events({
'click .cancel'(e, t) {
e.stopPropagation();
e.preventDefault();
return t.cancel(t.find('form'));
Template.instance().roles.set([]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use t instead of Template.instance(), right?

t.cancel(t.find('form'));
},

'click .remove-role'(e) {
e.stopPropagation();
e.preventDefault();
let roles = Template.instance().roles.get();
roles = roles.filter(el => el !== this.valueOf());
Template.instance().roles.set(roles);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can add a second parameter (t) on this event and use that here instead of Template.instance()

$(`[title=${ this }]`).remove();
},

'click #randomPassword'(e) {
e.stopPropagation();
e.preventDefault();
return $('#password').val(Random.id());
$('#password').val(Random.id());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

},

'submit form'(e, t) {
'click #addRole'(e, instance) {
e.stopPropagation();
e.preventDefault();
if ($('#roleSelect').find(':selected').is(':disabled')) {
return;
}
const userRoles = [...instance.roles.get()];
userRoles.push($('#roleSelect').val());
instance.roles.set(userRoles);
$('#roleSelect').val('placeholder');
},

return t.save(e.currentTarget);
'submit form'(e, t) {
e.stopPropagation();
e.preventDefault();
t.save(e.currentTarget);
}
});


Template.userEdit.onCreated(function() {
let userData;
this.user = this.data != null ? this.data.user : undefined;
this.roles = this.user ? new ReactiveVar(this.user.roles) : new ReactiveVar([]);


const { tabBar } = Template.currentData();

Expand All @@ -75,7 +102,15 @@ Template.userEdit.onCreated(function() {
userData.requirePasswordChange = this.$('#changePassword:checked').length > 0;
userData.joinDefaultChannels = this.$('#joinDefaultChannels:checked').length > 0;
userData.sendWelcomeEmail = this.$('#sendWelcomeEmail:checked').length > 0;
if (this.$('#role').val()) { userData.roles = [this.$('#role').val()]; }
const roleSelect = this.$('.remove-role').toArray();

if (roleSelect.length > 0) {
const notSorted = roleSelect.map(role => {
return role.title;
});
//Remove duplicate strings from the array
userData.roles = notSorted.filter((el, index) => notSorted.indexOf(el) === index);
}
return userData;
};

Expand All @@ -93,6 +128,10 @@ Template.userEdit.onCreated(function() {
errors.push('Email');
}

if (!userData.roles) {
errors.push('Roles');
}

for (const error of Array.from(errors)) {
toastr.error(TAPi18n.__('error-the-field-is-required', { field: TAPi18n.__(error) }));
}
Expand Down
8 changes: 7 additions & 1 deletion tests/end-to-end/ui/11-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,13 @@ describe('[Administration]', () => {
});

it('it should show the role dropdown', () => {
flexTab.usersAddUserRole.isVisible().should.be.true;
flexTab.usersAddUserRoleList.waitForVisible(5000);
flexTab.usersAddUserRoleList.isVisible().should.be.true;
});

it('ít should show the add role button', () => {
flexTab.usersAddUserRoleButton.waitForVisible(5000);
flexTab.usersAddUserRoleButton.isVisible().should.be.true;
});

it('it should show the join default channel checkbox', () => {
Expand Down
1 change: 1 addition & 0 deletions tests/end-to-end/ui/13-permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ describe('[Permissions]', () => {
flexTab.usersAddUserVerifiedCheckbox.click();
flexTab.usersAddUserPassword.setValue(password);
flexTab.usersAddUserChangePasswordCheckbox.click();
flexTab.addRole('user');
flexTab.usersButtonSave.click();
});

Expand Down
13 changes: 12 additions & 1 deletion tests/pageobjects/flex-tab.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ class FlexTab extends Page {
get usersAddUserName() { return browser.element('#name'); }
get usersAddUserUsername() { return browser.element('#username'); }
get usersAddUserEmail() { return browser.element('#email'); }
get usersAddUserRoleList() { return browser.element('#roleSelect'); }
get usersAddUserPassword() { return browser.element('#password'); }
get usersAddUserRole() { return browser.element('#role'); }
get usersAddUserRoleButton() { return browser.element('#addRole'); }
get usersAddUserVerifiedCheckbox() { return browser.element('#verified'); }
get usersAddUserChangePasswordCheckbox() { return browser.element('#changePassword'); }
get usersAddUserDefaultChannelCheckbox() { return browser.element('#joinDefaultChannels'); }
Expand Down Expand Up @@ -122,6 +123,16 @@ class FlexTab extends Page {
this.removeUserBtn.click();
}

addRole(role) {
this.usersAddUserRoleList.waitForVisible(5000);
this.usersAddUserRoleList.click();
browser.waitForVisible(`option[value=${ role }]`, 5000);
browser.click(`option[value=${ role }]`);
this.usersAddUserRoleButton.waitForVisible(5000);
this.usersAddUserRoleButton.click();
browser.waitForVisible(`.remove-role=${ role }`);
}

operateFlexTab(desiredTab, desiredState) {
//desiredState true=open false=closed
switch (desiredTab) {
Expand Down