refactor admin user settings away from standard user settings

It was possible for Users to grant themselves flags and permissions.
These operations now require Admin privileges, and are only implemented
by services.user.updateForAdmin. The services.user.update method no
longer has any logic to alter flags and/or permissions.
master
rob 3 years ago
parent 929a8875ef
commit 4f1c8cb245

@ -47,15 +47,23 @@ class UserController extends SiteController {
async postUpdateUser (req, res, next) { async postUpdateUser (req, res, next) {
const { user: userService } = this.dtp.services; const { user: userService } = this.dtp.services;
try { try {
await userService.update(res.locals.userAccount, req.body); await userService.updateForAdmin(res.locals.userAccount, req.body);
res.redirect('/admin/user'); res.redirect('/admin/user');
} catch (error) { } catch (error) {
return next(error); return next(error);
} }
} }
async getUserView (req, res) { async getUserView (req, res, error) {
res.render('admin/user/form'); const { comment: commentService } = this.dtp.services;
try {
res.locals.pagination = this.getPaginationParameters(req, 20);
res.locals.recentComments = await commentService.getForAuthor(res.locals.userAccount, res.locals.pagination);
res.render('admin/user/form');
} catch (error) {
this.log.error('failed to produce user view', { error });
return next(error);
}
} }
async getHomeView (req, res, next) { async getHomeView (req, res, next) {

@ -20,6 +20,8 @@ const UserPermissionsSchema = new Schema({
canChat: { type: Boolean, default: true, required: true }, canChat: { type: Boolean, default: true, required: true },
canComment: { type: Boolean, default: true, required: true }, canComment: { type: Boolean, default: true, required: true },
canReport: { type: Boolean, default: true, required: true }, canReport: { type: Boolean, default: true, required: true },
canAuthorPages: { type: Boolean, default: false, required: true },
canAuthorPosts: { type: Boolean, default: false, required: true },
}); });
const UserSchema = new Schema({ const UserSchema = new Schema({

@ -99,6 +99,8 @@ class UserService {
canChat: true, canChat: true,
canComment: true, canComment: true,
canReport: true, canReport: true,
canAuthorPages: false,
canAuthorPosts: false,
}; };
this.log.info('creating new user account', { email: userDefinition.email }); this.log.info('creating new user account', { email: userDefinition.email });
@ -112,6 +114,10 @@ class UserService {
} }
async update (user, userDefinition) { async update (user, userDefinition) {
if (!user.flags.canLogin) {
throw SiteError(403, 'Invalid user account operation');
}
// strip characters we don't want to allow in username // strip characters we don't want to allow in username
userDefinition.username = striptags(userDefinition.username.trim().replace(/[^A-Za-z0-9\-_]/gi, '')); userDefinition.username = striptags(userDefinition.username.trim().replace(/[^A-Za-z0-9\-_]/gi, ''));
const username_lc = userDefinition.username.toLowerCase(); const username_lc = userDefinition.username.toLowerCase();
@ -120,6 +126,28 @@ class UserService {
userDefinition.bio = striptags(userDefinition.bio.trim()); userDefinition.bio = striptags(userDefinition.bio.trim());
this.log.info('updating user', { userDefinition }); this.log.info('updating user', { userDefinition });
await User.updateOne(
{ _id: user._id },
{
$set: {
username: userDefinition.username,
username_lc,
displayName: userDefinition.displayName,
bio: userDefinition.bio,
},
},
);
}
async updateForAdmin (user, userDefinition) {
// strip characters we don't want to allow in username
userDefinition.username = striptags(userDefinition.username.trim().replace(/[^A-Za-z0-9\-_]/gi, ''));
const username_lc = userDefinition.username.toLowerCase();
userDefinition.displayName = striptags(userDefinition.displayName.trim());
userDefinition.bio = striptags(userDefinition.bio.trim());
this.log.info('updating user for admin', { userDefinition });
await User.updateOne( await User.updateOne(
{ _id: user._id }, { _id: user._id },
{ {
@ -134,6 +162,8 @@ class UserService {
'permissions.canChat': userDefinition.canChat === 'on', 'permissions.canChat': userDefinition.canChat === 'on',
'permissions.canComment': userDefinition.canComment === 'on', 'permissions.canComment': userDefinition.canComment === 'on',
'permissions.canReport': userDefinition.canReport === 'on', 'permissions.canReport': userDefinition.canReport === 'on',
'permissions.canAuthorPages': userDefinition.canAuthorPages === 'on',
'permissions.canAuthorPosts': userDefinition.canAuthorPosts === 'on',
}, },
}, },
); );

@ -1,43 +1,74 @@
extends ../layouts/main extends ../layouts/main
block content block content
.uk-margin include ../../comment/components/comment-review
.uk-text-large= userAccount.displayName || userAccount.email
div= userAccount.username div(uk-grid).uk-grid-small
div(class="uk-width-1-1 uk-width-2-3@l")
form(method="POST", action=`/admin/user/${userAccount._id}`).uk-form form(method="POST", action=`/admin/user/${userAccount._id}`).uk-form
input(type="hidden", name="username", value= userAccount.username) input(type="hidden", name="username", value= userAccount.username)
input(type="hidden", name="displayName", value= userAccount.displayName) input(type="hidden", name="displayName", value= userAccount.displayName)
.uk-margin .uk-card.uk-card-secondary.uk-card-small
div(uk-grid) .uk-card-header
div(class="uk-width-1-1 uk-width-1-2@m") if userAccount.displayName
fieldset .uk-text-large= userAccount.displayName
legend Flags div
a(href=`mailto:${userAccount.email}`)= userAccount.email
div
a(href=`/user/${userAccount._id}`) @#{userAccount.username}
.uk-card-body
.uk-margin .uk-margin
div(uk-grid).uk-grid-small label(for="bio").uk-form-label.sr-only Bio
label textarea(id="bio", name="bio", rows="4", placeholder= "Bio is empty", disabled= !userAccount.bio || (userAccount.bio.length === 0)).uk-textarea.uk-resize-vertical= userAccount.bio
input(id="is-admin", name="isAdmin", type="checkbox", checked= userAccount.flags.isAdmin)
| Admin
label
input(id="is-moderator", name="isModerator", type="checkbox", checked= userAccount.flags.isModerator)
| Moderator
div(class="uk-width-1-1 uk-width-1-2@m")
fieldset
legend Permissions
.uk-margin .uk-margin
div(uk-grid).uk-grid-small div(uk-grid)
label div(class="uk-width-1-1 uk-width-1-2@m")
input(id="can-login", name="canLogin", type="checkbox", checked= userAccount.permissions.canLogin) fieldset
| Can Login legend Flags
label .uk-margin
input(id="can-chat", name="canChat", type="checkbox", checked= userAccount.permissions.canChat) div(uk-grid).uk-grid-small
| Can Chat label
label input(id="is-admin", name="isAdmin", type="checkbox", checked= userAccount.flags.isAdmin)
input(id="can-comment", name="canComment", type="checkbox", checked= userAccount.permissions.canComment) | Admin
| Can Comment label
label input(id="is-moderator", name="isModerator", type="checkbox", checked= userAccount.flags.isModerator)
input(id="can-report", name="canReport", type="checkbox", checked= userAccount.permissions.canReport) | Moderator
| Can Report
div(class="uk-width-1-1 uk-width-1-2@m")
button(type="submit").uk-button.uk-button-primary Update User fieldset
legend Permissions
.uk-margin
div(uk-grid).uk-grid-small
label
input(id="can-login", name="canLogin", type="checkbox", checked= userAccount.permissions.canLogin)
| Can Login
label
input(id="can-chat", name="canChat", type="checkbox", checked= userAccount.permissions.canChat)
| Can Chat
label
input(id="can-comment", name="canComment", type="checkbox", checked= userAccount.permissions.canComment)
| Can Comment
label
input(id="can-report", name="canReport", type="checkbox", checked= userAccount.permissions.canReport)
| Can Report
label
input(id="can-author-pages", name="canAuthorPages", type="checkbox", checked= userAccount.permissions.canAuthorPages)
| Can Author Pages
label
input(id="can-author-posts", name="canAuthorPosts", type="checkbox", checked= userAccount.permissions.canAuthorPosts)
| Can Author Posts
button(type="submit").uk-button.dtp-button-primary.uk-display-block.uk-width-1-1 Update User
div(class="uk-width-1-1 uk-width-1-3@l")
.uk-card.uk-card-secondary.uk-card-small
.uk-card-header
h4.uk-card-title #{userAccount.displayName || userAccount.username}'s Comments
.uk-card-body
ul.uk-list.uk-list-divider
each comment in recentComments
li
+renderCommentReview(comment)

@ -20,13 +20,13 @@ block content
} }
.uk-margin .uk-margin
+renderFileUploadImage( +renderFileUploadImage(
`/user/${user._id}/header-image`, `/user/${user._id}/profile-photo`,
'header-image-upload', 'profile-picture-upload',
'header-image-file', 'profile-picture-file',
'header-image-picture', 'site-profile-picture',
`/img/default-header.png`, `/img/default-member.png`,
user.header, currentProfile,
{ aspectRatio: 1400 / 400 }, { aspectRatio: 1 },
) )
div(class="uk-width-1-1 uk-width-expand@m") div(class="uk-width-1-1 uk-width-expand@m")

Loading…
Cancel
Save