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")