diff --git a/app/controllers/admin/link.js b/app/controllers/admin/link.js index 48ff9a8..ecd4d44 100644 --- a/app/controllers/admin/link.js +++ b/app/controllers/admin/link.js @@ -7,6 +7,8 @@ const DTP_COMPONENT_NAME = 'admin:link'; const express = require('express'); +const multer = require('multer'); + const { SiteController, SiteError } = require('../../../lib/site-lib'); class LinkController extends SiteController { @@ -17,6 +19,8 @@ class LinkController extends SiteController { async start ( ) { const router = express.Router(); + const upload = multer({ dest: `/tmp/${this.dtp.config.domainKey}/uploads`}); + router.use(async (req, res, next) => { res.locals.currentView = 'admin'; res.locals.adminView = 'link'; @@ -25,7 +29,7 @@ class LinkController extends SiteController { router.param('linkId', this.populateLinkId.bind(this)); - router.post('/:linkId', this.postUpdateLink.bind(this)); + router.post('/:linkId', upload.none(), this.postUpdateLink.bind(this)); router.get('/:linkId', this.getLinkView.bind(this)); router.get('/', this.getIndex.bind(this)); @@ -49,19 +53,29 @@ class LinkController extends SiteController { } } - async postUpdateLink (req, res, next) { - const { link: linkService } = this.dtp.services; + async postUpdateLink (req, res) { + const { link: linkService, displayEngine: displayEngineService } = this.dtp.services; try { + const displayList = displayEngineService.createDisplayList('update-link'); + await linkService.update(res.locals.link, req.body); - res.redirect('/admin/link'); + + displayList.showNotification( + `Link ${res.locals.link.label} updated successfully`, + 'success', 'bottom-center', 2000, + ); + res.status(200).json({ success: true, displayList }); } catch (error) { this.log.error('failed to update link', { linkId: res.locals.link._id, error }); - return next(error); + return res.status(error.statusCode || 500).json({ + success: false, + message: error.message, + }); } } async getLinkView (req, res) { - res.render('admin/link/view'); + res.render('admin/link/editor'); } async getIndex (req, res, next) { diff --git a/app/controllers/admin/user.js b/app/controllers/admin/user.js index 138377f..a98dda8 100644 --- a/app/controllers/admin/user.js +++ b/app/controllers/admin/user.js @@ -27,6 +27,7 @@ class UserController extends SiteController { router.param('userId', this.populateUserId.bind(this)); router.post('/:userId', this.postUpdateUser.bind(this)); + router.get('/:userId', this.getUserView.bind(this)); router.get('/', this.getHomeView.bind(this)); @@ -53,8 +54,15 @@ class UserController extends SiteController { } } - async getUserView (req, res) { - res.render('admin/user/form'); + async getUserView (req, res, next) { + const { link: linkService } = this.dtp.services; + try { + res.locals.userLinks = await linkService.getForUser(res.locals.userAccount); + res.render('admin/user/form'); + } catch (error) { + this.log.error('failed to display user view', { error }); + return next(error); + } } async getHomeView (req, res, next) { diff --git a/app/controllers/link.js b/app/controllers/link.js index f87d3b8..4d75252 100644 --- a/app/controllers/link.js +++ b/app/controllers/link.js @@ -52,7 +52,12 @@ class LinkController extends SiteController { this.postUpdateLink.bind(this), ); - router.post('/', authRequired, upload.none(), this.postCreateLink.bind(this)); + router.post('/', + limiterService.create(limiterService.config.link.postCreateLink), + authRequired, + upload.none(), + this.postCreateLink.bind(this), + ); router.delete('/:linkId', authRequired, this.deleteLink.bind(this)); } diff --git a/app/views/admin/link/editor.pug b/app/views/admin/link/editor.pug new file mode 100644 index 0000000..b9ca8ec --- /dev/null +++ b/app/views/admin/link/editor.pug @@ -0,0 +1,11 @@ +extends ../layouts/main +block content + + form(method="POST", action=`/admin/link/${link._id}`, onsubmit="return dtp.app.submitForm(event, 'update link');").uk-form + .uk-margin + label(for="label").uk-form-label Label + input(id="label", name="label", type="text", placeholder="Enter link label", value= link.label).uk-input + .uk-margin + label(for="href").uk-form-label URL + input(id="href", name="href", type="url", placeholder="Enter link URL", value= link.href).uk-input + button(type="submit").uk-button.uk-button-primary Update Link \ No newline at end of file diff --git a/app/views/admin/user/form.pug b/app/views/admin/user/form.pug index c78f5eb..cc4ed50 100644 --- a/app/views/admin/user/form.pug +++ b/app/views/admin/user/form.pug @@ -1,44 +1,64 @@ extends ../layouts/main block content - .uk-margin - .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") + .uk-card.uk-card-secondary.uk-card-small + .uk-card-header + .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 - label(for="bio").uk-form-label Bio - textarea(id="bio", name="bio", rows="4", placeholder= "Enter profile bio").uk-textarea.uk-resize-vertical= userAccount.bio - - .uk-margin - div(uk-grid) - div(class="uk-width-1-1 uk-width-1-2@m") - fieldset - legend Flags + .uk-card-body + 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).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 + label(for="bio").uk-form-label.sr-only Bio + textarea(id="bio", name="bio", rows="4", placeholder= "Enter profile bio").uk-textarea.uk-resize-vertical= userAccount.bio - 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-create-links", name="canCreateLinks", type="checkbox", checked= userAccount.permissions.canCreateLinks) - | Can Create Links + 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-create-links", name="canCreateLinks", type="checkbox", checked= userAccount.permissions.canCreateLinks) + | Can Create Links + .uk-card-footer + button(type="submit").uk-button.uk-button-primary Update User + + div(class="uk-width-1-1 uk-width-1-3@l") - button(type="submit").uk-button.uk-button-primary Update User \ No newline at end of file + .uk-card.uk-card-secondary.uk-card-small + .uk-card-header + h4.uk-card-title #{userAccount.displayName || userAccount.username}'s Links + .uk-card-body + ul.uk-list + each link in userLinks + li + div(uk-grid).uk-grid-small + .uk-width-expand + a(href= link.href)= link.label + .uk-width-auto + a(href=`/admin/link/${link._id}`).uk-button.uk-button-default.uk-button-small + +renderButtonIcon('fa-pen', 'Edit') \ No newline at end of file diff --git a/client/less/site/button.less b/client/less/site/button.less index 8115954..e1f6060 100644 --- a/client/less/site/button.less +++ b/client/less/site/button.less @@ -6,17 +6,20 @@ a.dtp-link-button { font-size: 14px; text-transform: uppercase; + text-decoration: none; text-align: center; background: none; outline: none; - border: solid 2px #1e87f0; - color: #c8c8c8; + border: solid 2px @global-primary-background; + color: @global-color; - transition: background-color 0.2s; + transition: background-color 0.2s, color 0.2s; &:hover { - background-color: #1e87f0; + background-color: @global-primary-background; + color: @global-inverse-color; + text-decoration: none; } } diff --git a/config/limiter.js b/config/limiter.js index b9dde9f..47e64d1 100644 --- a/config/limiter.js +++ b/config/limiter.js @@ -113,6 +113,11 @@ module.exports = { expire: ONE_MINUTE, message: 'You are sorting links too quickly', }, + postCreateLink: { + total: 10, + expire: ONE_MINUTE, + message: 'You are creating links too quickly', + }, }, /*