diff --git a/js/src/admin/components/PermissionGrid.js b/js/src/admin/components/PermissionGrid.js
index 62fa0fc1b..fb05ceb32 100644
--- a/js/src/admin/components/PermissionGrid.js
+++ b/js/src/admin/components/PermissionGrid.js
@@ -327,9 +327,29 @@ export default class PermissionGrid extends Component {
);
items.add(
- 'userEdit',
+ 'userEditCredentials',
{
icon: 'fas fa-user-cog',
+ label: app.translator.trans('core.admin.permissions.edit_users_credentials_label'),
+ permission: 'user.editCredentials',
+ },
+ 60
+ );
+
+ items.add(
+ 'userEditGroups',
+ {
+ icon: 'fas fa-users-cog',
+ label: app.translator.trans('core.admin.permissions.edit_users_groups_label'),
+ permission: 'user.editGroups',
+ },
+ 60
+ );
+
+ items.add(
+ 'userEdit',
+ {
+ icon: 'fas fa-address-card',
label: app.translator.trans('core.admin.permissions.edit_users_label'),
permission: 'user.edit',
},
diff --git a/js/src/common/models/User.js b/js/src/common/models/User.js
index 30bc0567b..42cbf673b 100644
--- a/js/src/common/models/User.js
+++ b/js/src/common/models/User.js
@@ -30,6 +30,8 @@ Object.assign(User.prototype, {
commentCount: Model.attribute('commentCount'),
canEdit: Model.attribute('canEdit'),
+ canEditCredentials: Model.attribute('canEditCredentials'),
+ canEditGroups: Model.attribute('canEditGroups'),
canDelete: Model.attribute('canDelete'),
avatarColor: null,
diff --git a/js/src/forum/components/EditUserModal.js b/js/src/forum/components/EditUserModal.js
index ad48261e4..9287f0f01 100644
--- a/js/src/forum/components/EditUserModal.js
+++ b/js/src/forum/components/EditUserModal.js
@@ -37,9 +37,10 @@ export default class EditUserModal extends Modal {
}
content() {
+ const fields = this.fields().toArray();
return (
-
{this.fields().toArray()}
+ {fields.length > 1 ?
{this.fields().toArray()}
: app.translator.trans('core.forum.edit_user.nothing_available')}
);
}
@@ -47,96 +48,112 @@ export default class EditUserModal extends Modal {
fields() {
const items = new ItemList();
- items.add(
- 'username',
-
-
-
-
,
- 40
- );
-
- if (app.session.user !== this.attrs.user) {
+ if (app.session.user.canEditCredentials()) {
items.add(
- 'email',
+ 'username',
-
-
-
-
- {!this.isEmailConfirmed() ? (
-
- {Button.component(
- {
- className: 'Button Button--block',
- loading: this.loading,
- onclick: this.activate.bind(this),
- },
- app.translator.trans('core.forum.edit_user.activate_button')
- )}
-
- ) : (
- ''
- )}
+
+
,
- 30
+ 40
);
- items.add(
- 'password',
-
-
-
-
- {this.setPassword() ? (
+ if (app.session.user !== this.attrs.user) {
+ items.add(
+ 'email',
+
+
+
+
+ {!this.isEmailConfirmed() && this.userIsAdmin(app.session.user) ? (
+
+ {Button.component(
+ {
+ className: 'Button Button--block',
+ loading: this.loading,
+ onclick: this.activate.bind(this),
+ },
+ app.translator.trans('core.forum.edit_user.activate_button')
+ )}
+
) : (
''
)}
-
-
,
- 20
- );
- }
+
,
+ 30
+ );
- items.add(
- 'groups',
-
-
-
- {Object.keys(this.groups)
- .map((id) => app.store.getById('groups', id))
- .map((group) => (
+ items.add(
+ 'password',
+
+
+
- ))}
-
-
,
- 10
- );
+ {this.setPassword() ? (
+
+ ) : (
+ ''
+ )}
+
+
,
+ 20
+ );
+ }
+ }
+
+ if (app.session.user.canEditGroups()) {
+ items.add(
+ 'groups',
+
+
+
+ {Object.keys(this.groups)
+ .map((id) => app.store.getById('groups', id))
+ .map((group) => (
+
+ ))}
+
+
,
+ 10
+ );
+ }
items.add(
'submit',
@@ -176,21 +193,26 @@ export default class EditUserModal extends Modal {
}
data() {
- const groups = Object.keys(this.groups)
- .filter((id) => this.groups[id]())
- .map((id) => app.store.getById('groups', id));
-
const data = {
- username: this.username(),
- relationships: { groups },
+ relationships: {},
};
- if (app.session.user !== this.attrs.user) {
- data.email = this.email();
+ if (this.attrs.user.canEditCredentials() && !this.nonAdminEditingAdmin()) {
+ data.username = this.username();
+
+ if (app.session.user !== this.attrs.user) {
+ data.email = this.email();
+ }
+
+ if (this.setPassword()) {
+ data.password = this.password();
+ }
}
- if (this.setPassword()) {
- data.password = this.password();
+ if (this.attrs.user.canEditGroups()) {
+ data.relationships.groups = Object.keys(this.groups)
+ .filter((id) => this.groups[id]())
+ .map((id) => app.store.getById('groups', id));
}
return data;
@@ -209,4 +231,15 @@ export default class EditUserModal extends Modal {
m.redraw();
});
}
+
+ nonAdminEditingAdmin() {
+ return this.userIsAdmin(this.attrs.user) && !this.userIsAdmin(app.session.user);
+ }
+
+ /**
+ * @internal @protected
+ */
+ userIsAdmin(user) {
+ return user.groups().some((g) => g.id() === Group.ADMINISTRATOR_ID);
+ }
}
diff --git a/js/src/forum/utils/UserControls.js b/js/src/forum/utils/UserControls.js
index b0aaedf41..8841df6a4 100644
--- a/js/src/forum/utils/UserControls.js
+++ b/js/src/forum/utils/UserControls.js
@@ -57,7 +57,7 @@ export default {
moderationControls(user) {
const items = new ItemList();
- if (user.canEdit()) {
+ if (user.canEdit() || user.canEditCredentials() || user.canEditGroups()) {
items.add(
'edit',