14 changed files with 421 additions and 16 deletions
@ -0,0 +1,138 @@ |
|||||
|
// admin/attachment.js
|
||||
|
// Copyright (C) 2022 DTP Technologies, LLC
|
||||
|
// License: Apache-2.0
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
const express = require('express'); |
||||
|
|
||||
|
const { SiteController } = require('../../../lib/site-lib'); |
||||
|
|
||||
|
class AttachmentAdminController extends SiteController { |
||||
|
|
||||
|
constructor (dtp) { |
||||
|
super(dtp, module.exports); |
||||
|
} |
||||
|
|
||||
|
async start ( ) { |
||||
|
const router = express.Router(); |
||||
|
router.use(async (req, res, next) => { |
||||
|
res.locals.currentView = 'admin'; |
||||
|
res.locals.adminView = 'attachment'; |
||||
|
return next(); |
||||
|
}); |
||||
|
|
||||
|
router.param('attachmentId', this.populateAttachmentId.bind(this)); |
||||
|
|
||||
|
router.post('/:attachmentId', this.postUpdateAttachment.bind(this)); |
||||
|
|
||||
|
router.get('/create', this.getAttachmentEditor.bind(this)); |
||||
|
router.get('/:attachmentId', this.getAttachmentEditor.bind(this)); |
||||
|
|
||||
|
router.get('/', this.getDashboard.bind(this)); |
||||
|
|
||||
|
router.delete('/:attachmentId', this.deleteAttachment.bind(this)); |
||||
|
|
||||
|
return router; |
||||
|
} |
||||
|
|
||||
|
async populateAttachmentId (req, res, next, attachmentId) { |
||||
|
const { |
||||
|
attachment: attachmentService, |
||||
|
logan: loganService, |
||||
|
} = this.dtp.services; |
||||
|
try { |
||||
|
res.locals.attachment = await attachmentService.getById(attachmentId); |
||||
|
return next(); |
||||
|
} catch (error) { |
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'error', |
||||
|
event: 'populateAttachmentId', |
||||
|
message: `failed to populate attachment: ${error.message}`, |
||||
|
data: { attachmentId, error }, |
||||
|
}); |
||||
|
return next(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async postUpdateAttachment (req, res, next) { |
||||
|
const { |
||||
|
attachment: attachmentService, |
||||
|
logan: loganService, |
||||
|
} = this.dtp.services; |
||||
|
try { |
||||
|
await attachmentService.update(res.locals.attachment, req.body); |
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'info', |
||||
|
event: 'postUpdateAttachment', |
||||
|
data: { |
||||
|
attachment: { |
||||
|
_id: res.locals.attachment._id, |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
res.redirect('/admin/attachment'); |
||||
|
} catch (error) { |
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'error', |
||||
|
event: 'postUpdateAttachment', |
||||
|
message: `failed to update attachment: ${error.message}`, |
||||
|
data: { error }, |
||||
|
}); |
||||
|
return next(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async getAttachmentEditor (req, res) { |
||||
|
res.render('admin/attachment/editor'); |
||||
|
} |
||||
|
|
||||
|
async getDashboard (req, res, next) { |
||||
|
const { attachment: attachmentService } = this.dtp.services; |
||||
|
try { |
||||
|
res.locals.pagination = this.getPaginationParameters(req, 20); |
||||
|
res.locals.attachments = await attachmentService.getRecent(res.locals.pagination); |
||||
|
res.render('admin/attachment/index'); |
||||
|
} catch (error) { |
||||
|
return next(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async deleteAttachment (req, res) { |
||||
|
const { |
||||
|
attachment: attachmentService, |
||||
|
logan: loganService, |
||||
|
} = this.dtp.services; |
||||
|
try { |
||||
|
const displayList = this.createDisplayList('delete-attachment'); |
||||
|
await attachmentService.remove(res.locals.attachment); |
||||
|
displayList.reload(); |
||||
|
|
||||
|
res.status(200).json({ success: true, displayList }); |
||||
|
|
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'info', |
||||
|
event: 'deleteAttachment', |
||||
|
data: { attachment: { _id: res.locals.attachment._id } }, |
||||
|
}); |
||||
|
} catch (error) { |
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'error', |
||||
|
event: 'deleteAttachment', |
||||
|
message: `failed to delete attachment: ${error.message}`, |
||||
|
data: { error }, |
||||
|
}); |
||||
|
res.status(error.statusCode || 500).json({ |
||||
|
success: false, |
||||
|
message: error.message, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
name: 'adminAttachment', |
||||
|
slug: 'adminAttachment', |
||||
|
className: 'AttachmentAdminController', |
||||
|
create: async (dtp) => { return new AttachmentAdminController(dtp); }, |
||||
|
}; |
@ -0,0 +1,107 @@ |
|||||
|
// admin/image.js
|
||||
|
// Copyright (C) 2022 DTP Technologies, LLC
|
||||
|
// License: Apache-2.0
|
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
const express = require('express'); |
||||
|
|
||||
|
const { SiteController } = require('../../../lib/site-lib'); |
||||
|
|
||||
|
class ImageAdminController extends SiteController { |
||||
|
|
||||
|
constructor (dtp) { |
||||
|
super(dtp, module.exports); |
||||
|
} |
||||
|
|
||||
|
async start ( ) { |
||||
|
const router = express.Router(); |
||||
|
router.use(async (req, res, next) => { |
||||
|
res.locals.currentView = 'admin'; |
||||
|
res.locals.adminView = 'image'; |
||||
|
return next(); |
||||
|
}); |
||||
|
|
||||
|
router.param('imageId', this.populateImageId.bind(this)); |
||||
|
|
||||
|
router.get('/:imageId', this.getImageView.bind(this)); |
||||
|
|
||||
|
router.get('/', this.getDashboard.bind(this)); |
||||
|
|
||||
|
router.delete('/:imageId', this.deleteImage.bind(this)); |
||||
|
|
||||
|
return router; |
||||
|
} |
||||
|
|
||||
|
async populateImageId (req, res, next, imageId) { |
||||
|
const { |
||||
|
image: imageService, |
||||
|
logan: loganService, |
||||
|
} = this.dtp.services; |
||||
|
try { |
||||
|
res.locals.image = await imageService.getImageById(imageId); |
||||
|
return next(); |
||||
|
} catch (error) { |
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'error', |
||||
|
event: 'populateImageId', |
||||
|
message: `failed to populate image: ${error.message}`, |
||||
|
data: { imageId, error }, |
||||
|
}); |
||||
|
return next(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async getImageView (req, res) { |
||||
|
res.render('admin/image/view'); |
||||
|
} |
||||
|
|
||||
|
async getDashboard (req, res, next) { |
||||
|
const { image: imageService } = this.dtp.services; |
||||
|
try { |
||||
|
res.locals.pagination = this.getPaginationParameters(req, 20); |
||||
|
res.locals.images = await imageService.getRecentImages(res.locals.pagination); |
||||
|
res.render('admin/image/index'); |
||||
|
} catch (error) { |
||||
|
return next(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async deleteImage (req, res) { |
||||
|
const { |
||||
|
image: imageService, |
||||
|
logan: loganService, |
||||
|
} = this.dtp.services; |
||||
|
try { |
||||
|
const displayList = this.createDisplayList('delete-image'); |
||||
|
await imageService.deleteImage(res.locals.image); |
||||
|
displayList.reload(); |
||||
|
|
||||
|
res.status(200).json({ success: true, displayList }); |
||||
|
|
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'info', |
||||
|
event: 'deleteImage', |
||||
|
data: { image: { _id: res.locals.image._id } }, |
||||
|
}); |
||||
|
} catch (error) { |
||||
|
loganService.sendRequestEvent(module.exports, req, { |
||||
|
level: 'error', |
||||
|
event: 'deleteImage', |
||||
|
message: `failed to delete image: ${error.message}`, |
||||
|
data: { error }, |
||||
|
}); |
||||
|
res.status(error.statusCode || 500).json({ |
||||
|
success: false, |
||||
|
message: error.message, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
name: 'adminImage', |
||||
|
slug: 'adminImage', |
||||
|
className: 'ImageAdminController', |
||||
|
create: async (dtp) => { return new ImageAdminController(dtp); }, |
||||
|
}; |
@ -0,0 +1,21 @@ |
|||||
|
extends ../layouts/main |
||||
|
block content |
||||
|
|
||||
|
h1 Attachments |
||||
|
|
||||
|
if Array.isArray(attachments) && (attachments.length > 0) |
||||
|
ul.uk-list.uk-list-divider |
||||
|
each attachment in attachments |
||||
|
li |
||||
|
div(uk-grid).uk-grid-small.uk-flex-middle |
||||
|
.uk-width-expand |
||||
|
//- had to abort while writing the renderer for an attachment. |
||||
|
//- will be back to finish this and have an attachment browser/manager. |
||||
|
pre= JSON.stringify(attachment, null, 2) |
||||
|
|
||||
|
.uk-width-auto |
||||
|
button(type="button", data-attachment-id= attachment._id, onclick="return dtp.adminApp.deleteAttachment(event);").uk-button.dtp-button-danger.uk-border-rounded |
||||
|
span |
||||
|
i.fas.fa-trash |
||||
|
else |
||||
|
div There are no attachments. |
@ -0,0 +1,45 @@ |
|||||
|
extends ../layouts/main |
||||
|
block content |
||||
|
|
||||
|
include ../user/components/list-item |
||||
|
include ../../components/pagination-bar |
||||
|
|
||||
|
h1.uk-text-center Image Manager |
||||
|
|
||||
|
if Array.isArray(images.images) && (images.images.length > 0) |
||||
|
div(uk-grid).uk-flex-center |
||||
|
each image in images.images |
||||
|
.uk-width-medium |
||||
|
.uk-margin-small(uk-lightbox) |
||||
|
a(href=`/image/${image._id}`, data-type="image", data-caption=`id: ${image._id}`) |
||||
|
div |
||||
|
img(src= `/image/${image._id}`).responsive |
||||
|
|
||||
|
if image.owner |
||||
|
.uk-margin-small |
||||
|
+renderUserListItem(image.owner) |
||||
|
|
||||
|
.uk-margin-small.uk-text-center |
||||
|
button(type="button").uk-button.uk-button-default.uk-button-small.uk-border-rounded |
||||
|
span Image Menu |
||||
|
|
||||
|
div(uk-drop={ mode: 'click', pos: 'top-center' }).uk-card.uk-card-default.uk-card-small.uk-border-rounded |
||||
|
.uk-card-header |
||||
|
.uk-text-small.uk-text-muted.uk-text-center id:#{image._id} |
||||
|
.uk-card-body |
||||
|
ul.uk-nav.uk-dropdown-nav |
||||
|
li |
||||
|
a(href="#", data-image-id= image._id, onclick="dtp.adminApp.deleteImage(event);") |
||||
|
span |
||||
|
i.fas.fa-trash |
||||
|
span.uk-margin-small-left Delete image |
||||
|
li |
||||
|
a(href=`/admin/image/${image._id}/archive-user`).uk-text-truncate |
||||
|
span |
||||
|
i.fas.fa-file-archive |
||||
|
span.uk-margin-small-left Archive and ban #[span.uk-text-bold= image.owner.username] |
||||
|
|
||||
|
+renderPaginationBar('/admin/image', images.totalImageCount) |
||||
|
|
||||
|
else |
||||
|
.uk-text-center There are no images. |
Loading…
Reference in new issue