From 4f1c8cb2450440ab90fcfe793ba58960cdd7d943 Mon Sep 17 00:00:00 2001 From: rob Date: Sat, 25 Dec 2021 12:30:40 -0500 Subject: [PATCH] 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. --- app/controllers/admin/user.js | 14 ++++- app/models/user.js | 2 + app/services/user.js | 30 ++++++++++ app/views/admin/user/form.pug | 107 ++++++++++++++++++++++------------ app/views/user/settings.pug | 14 ++--- 5 files changed, 119 insertions(+), 48 deletions(-) diff --git a/app/controllers/admin/user.js b/app/controllers/admin/user.js index 04ea8b1..56853ee 100644 --- a/app/controllers/admin/user.js +++ b/app/controllers/admin/user.js @@ -47,15 +47,23 @@ class UserController extends SiteController { async postUpdateUser (req, res, next) { const { user: userService } = this.dtp.services; try { - await userService.update(res.locals.userAccount, req.body); + await userService.updateForAdmin(res.locals.userAccount, req.body); res.redirect('/admin/user'); } catch (error) { return next(error); } } - async getUserView (req, res) { - res.render('admin/user/form'); + async getUserView (req, res, error) { + 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) { diff --git a/app/models/user.js b/app/models/user.js index 70142cc..a63dd69 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -20,6 +20,8 @@ const UserPermissionsSchema = new Schema({ canChat: { type: Boolean, default: true, required: true }, canComment: { 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({ diff --git a/app/services/user.js b/app/services/user.js index 39cdf2d..83e9be4 100644 --- a/app/services/user.js +++ b/app/services/user.js @@ -99,6 +99,8 @@ class UserService { canChat: true, canComment: true, canReport: true, + canAuthorPages: false, + canAuthorPosts: false, }; this.log.info('creating new user account', { email: userDefinition.email }); @@ -112,6 +114,10 @@ class UserService { } 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 userDefinition.username = striptags(userDefinition.username.trim().replace(/[^A-Za-z0-9\-_]/gi, '')); const username_lc = userDefinition.username.toLowerCase(); @@ -120,6 +126,28 @@ class UserService { userDefinition.bio = striptags(userDefinition.bio.trim()); 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( { _id: user._id }, { @@ -134,6 +162,8 @@ class UserService { 'permissions.canChat': userDefinition.canChat === 'on', 'permissions.canComment': userDefinition.canComment === 'on', 'permissions.canReport': userDefinition.canReport === 'on', + 'permissions.canAuthorPages': userDefinition.canAuthorPages === 'on', + 'permissions.canAuthorPosts': userDefinition.canAuthorPosts === 'on', }, }, ); diff --git a/app/views/admin/user/form.pug b/app/views/admin/user/form.pug index 9740cc0..626a5a3 100644 --- a/app/views/admin/user/form.pug +++ b/app/views/admin/user/form.pug @@ -1,43 +1,74 @@ extends ../layouts/main block content - .uk-margin - .uk-text-large= userAccount.displayName || userAccount.email - div= userAccount.username - - form(method="POST", action=`/admin/user/${userAccount._id}`).uk-form - input(type="hidden", name="username", value= userAccount.username) - input(type="hidden", name="displayName", value= userAccount.displayName) - .uk-margin - div(uk-grid) - div(class="uk-width-1-1 uk-width-1-2@m") - fieldset - legend Flags + include ../../comment/components/comment-review + + 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 + input(type="hidden", name="username", value= userAccount.username) + input(type="hidden", name="displayName", value= userAccount.displayName) + .uk-card.uk-card-secondary.uk-card-small + .uk-card-header + if userAccount.displayName + .uk-text-large= userAccount.displayName + div + a(href=`mailto:${userAccount.email}`)= userAccount.email + div + a(href=`/user/${userAccount._id}`) @#{userAccount.username} + + .uk-card-body .uk-margin - div(uk-grid).uk-grid-small - label - 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 + label(for="bio").uk-form-label.sr-only Bio + 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 + .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 - - button(type="submit").uk-button.uk-button-primary Update User \ No newline at end of file + div(uk-grid) + div(class="uk-width-1-1 uk-width-1-2@m") + fieldset + legend Flags + .uk-margin + div(uk-grid).uk-grid-small + label + 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 + 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) \ No newline at end of file diff --git a/app/views/user/settings.pug b/app/views/user/settings.pug index d3f7aee..918d4fb 100644 --- a/app/views/user/settings.pug +++ b/app/views/user/settings.pug @@ -20,13 +20,13 @@ block content } .uk-margin +renderFileUploadImage( - `/user/${user._id}/header-image`, - 'header-image-upload', - 'header-image-file', - 'header-image-picture', - `/img/default-header.png`, - user.header, - { aspectRatio: 1400 / 400 }, + `/user/${user._id}/profile-photo`, + 'profile-picture-upload', + 'profile-picture-file', + 'site-profile-picture', + `/img/default-member.png`, + currentProfile, + { aspectRatio: 1 }, ) div(class="uk-width-1-1 uk-width-expand@m")