allow board custom pages to be edited, like newspost editing

because rewriting the whole page can be annoying and you couldnt access the text without styling
also can change .html name, maybe that will get removed but it works atm.
still needs more tweaks and proper testing
jschan
Thomas Lynch 3 years ago
parent d7a3e55fb0
commit 52c189a153
  1. 1
      CHANGELOG.md
  2. 3
      controllers/forms.js
  3. 62
      controllers/forms/editcustompage.js
  4. 1
      controllers/forms/index.js
  5. 13
      controllers/pages.js
  6. 26
      db/custompages.js
  7. 2
      models/forms/addcustompage.js
  8. 58
      models/forms/editcustompage.js
  9. 2
      models/pages/globalmanage/editnews.js
  10. 1
      models/pages/globalmanage/index.js
  11. 1
      models/pages/index.js
  12. 26
      models/pages/manage/editcustompage.js
  13. 1
      models/pages/manage/index.js
  14. 6
      views/mixins/custompage.pug
  15. 2
      views/mixins/newspost.pug
  16. 27
      views/pages/editcustompage.pug
  17. 2
      views/pages/managecustompages.pug

@ -32,3 +32,4 @@
- Try to fallback thumbnail generation for video with horribly broken encoding
- Country blocklist now can actually fit all countries
- Make "auth level" text box into "account type" dropdown in accounts page, easier to understand
- Board owners can now edit custom pages

@ -28,7 +28,7 @@ const express = require('express')
addFlagsController, deleteFlagsController, boardSettingsController, transferController,
resignController, deleteAccountController, loginController, registerController, changePasswordController,
editAccountsController, globalSettingsController, createBoardController, makePostController,
editPostController, newCaptcha, blockBypass, logout } = require(__dirname+'/forms/index.js');
editCustomPageController, editPostController, newCaptcha, blockBypass, logout } = require(__dirname+'/forms/index.js');
//make new post
@ -57,6 +57,7 @@ router.post('/board/:board/addcustompages', useSession, sessionRefresh, csrf, Bo
router.post('/board/:board/deletecustompages', useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(2), deleteCustomPageController.paramConverter, deleteCustomPageController.controller); //delete banners
router.post('/board/:board/editbans', useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(3), editBansController.paramConverter, editBansController.controller); //edit bans
router.post('/board/:board/deleteboard', useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(config.get.deleteBoardPermLevel), deleteBoardController.controller); //delete board
router.post('/board/:board/editcustompage', useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(2), editCustomPageController.paramConverter, editCustomPageController.controller); //edit custom page
//global management forms
router.post('/global/editbans', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(1), editBansController.paramConverter, editBansController.controller); //remove bans

@ -0,0 +1,62 @@
'use strict';
const editCustomPage = require(__dirname+'/../../models/forms/editcustompage.js')
, { CustomPages } = require(__dirname+'/../../db/')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, paramConverter = require(__dirname+'/../../helpers/paramconverter.js')
, { checkSchema, lengthBody, numberBody, minmaxBody, numberBodyVariable,
inArrayBody, arrayInBody, existsBody } = require(__dirname+'/../../helpers/schema.js')
, config = require(__dirname+'/../../config.js');
module.exports = {
paramConverter: paramConverter({
trimFields: ['message', 'title', 'page'],
processMessageLength: true,
objectIdFields: ['page_id'],
}),
controller: async (req, res, next) => {
const { globalLimits } = config.get;
const errors = await checkSchema([
{ result: existsBody(req.body.page_id), expected: true, error: 'Missing page id' },
{ result: existsBody(req.body.message), expected: true, error: 'Missing message' },
{ result: existsBody(req.body.title), expected: true, error: 'Missing title' },
{ result: existsBody(req.body.page), expected: true, error: 'Missing .html name' },
{ result: () => {
if (req.body.page) {
return /[a-z0-9_-]+/.test(req.body.page);
}
return false;
} , expected: true, error: '.html name must contain a-z 0-9 _ - only' },
{ result: numberBody(res.locals.messageLength, 0, globalLimits.customPages.maxLength), expected: true, error: `Message must be ${globalLimits.customPages.maxLength} characters or less` },
{ result: lengthBody(req.body.title, 0, 50), expected: false, error: 'Title must be 50 characters or less' },
{ result: lengthBody(req.body.page, 0, 50), expected: false, error: '.html name must be 50 characters or less' },
{ result: async () => {
const existingPage = await CustomPages.findOne(req.params.board, req.body.page);
if (existingPage && existingPage.page === req.body.page) {
return existingPage._id === req.body.page_id;
}
return true;
}, expected: true, error: '.html name must be unique'},
]);
if (errors.length > 0) {
return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request',
'errors': errors,
'redirect': req.headers.referer || '/${req.params.board}/manage/custompages.html'
});
}
try {
await editCustomPage(req, res, next);
} catch (err) {
return next(err);
}
}
}

@ -11,6 +11,7 @@ module.exports = {
deleteCustomPageController: require(__dirname+'/deletecustompage.js'),
addNewsController: require(__dirname+'/addnews.js'),
editNewsController: require(__dirname+'/editnews.js'),
editCustomPageController: require(__dirname+'/editcustompage.js'),
deleteNewsController: require(__dirname+'/deletenews.js'),
uploadBannersController: require(__dirname+'/uploadbanners.js'),
deleteBannersController: require(__dirname+'/deletebanners.js'),

@ -16,16 +16,17 @@ const express = require('express')
, csrf = require(__dirname+'/../helpers/checks/csrfmiddleware.js')
, setMinimal = require(__dirname+'/../helpers/setminimal.js')
//page models
, { manageRecent, manageReports, manageAssets, manageSettings, manageBans,
, { manageRecent, manageReports, manageAssets, manageSettings, manageBans, editCustomPage,
manageBoard, manageThread, manageLogs, manageCatalog, manageCustomPages } = require(__dirname+'/../models/pages/manage/')
, { globalManageSettings, globalManageReports, globalManageBans, globalManageBoards,
, { globalManageSettings, globalManageReports, globalManageBans, globalManageBoards, editNews,
globalManageRecent, globalManageAccounts, globalManageNews, globalManageLogs } = require(__dirname+'/../models/pages/globalmanage/')
, { changePassword, blockBypass, home, register, login, create, editNews,
, { changePassword, blockBypass, home, register, login, create,
board, catalog, banners, randombanner, news, captchaPage, overboard, overboardCatalog,
captcha, thread, modlog, modloglist, account, boardlist, customPage } = require(__dirname+'/../models/pages/')
, threadParamConverter = paramConverter({ processThreadIdParam: true })
, logParamConverter = paramConverter({ processDateParam: true })
, newsParamConverter = paramConverter({ objectIdParams: ['newsid'] });
, newsParamConverter = paramConverter({ objectIdParams: ['newsid'] })
, custompageParamConverter = paramConverter({ objectIdParams: ['custompageid'] });
//homepage
router.get('/index.html', home);
@ -73,9 +74,9 @@ router.get('/globalmanage/accounts.html', useSession, sessionRefresh, isLoggedIn
router.get('/globalmanage/settings.html', useSession, sessionRefresh, isLoggedIn, calcPerms, hasPerms(0), csrf, globalManageSettings);
//edit pages
router.get('/editnews/:newsid([a-f0-9]{24}).html', useSession, sessionRefresh, isLoggedIn, calcPerms, hasPerms(0), csrf, newsParamConverter, editNews);
router.get('/globalmanage/editnews/:newsid([a-f0-9]{24}).html', useSession, sessionRefresh, isLoggedIn, calcPerms, hasPerms(0), csrf, newsParamConverter, editNews);
router.get('/:board/manage/editcustompage/:custompageid([a-f0-9]{24}).html', useSession, sessionRefresh, isLoggedIn, Boards.exists, calcPerms, hasPerms(2), csrf, custompageParamConverter, editCustomPage);
//TODO: edit post get endpoint
//TODO: edit board custom page get endpoint
//captcha
router.get('/captcha', geoAndTor, processIp, captcha); //get captcha image and cookie

@ -18,6 +18,7 @@ module.exports = {
.toArray();
},
//browsing board
findOne: (board, page) => {
return db.findOne({
'board': board,
@ -25,6 +26,14 @@ module.exports = {
});
},
//editing
findOneId: (id, board) => {
return db.findOne({
'_id': id,
'board': board,
});
},
boardCount: (board) => {
return db.countDocuments({
'board': board,
@ -35,7 +44,22 @@ module.exports = {
return db.insertOne(custompage);
},
updateOne: () => {},
findOneAndUpdate: (id, board, page, title, raw, markdown, edited) => {
return db.findOneAndUpdate({
'_id': id,
'board': board,
}, {
'$set': {
'page': page,
'title': title,
'message.raw': raw,
'message.markdown': markdown,
'edited': edited,
}
}, {
returnDocument: 'before',
});
},
deleteMany: (pages, board) => {
return db.deleteMany({

@ -20,7 +20,7 @@ module.exports = async (req, res, next) => {
'markdown': markdownMessage
},
'date': new Date(),
'edited': null, //unused currently
'edited': null,
};
const insertedCustomPage = await CustomPages.insertOne(post);

@ -0,0 +1,58 @@
'use strict';
const { CustomPages } = require(__dirname+'/../../db/')
, uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js')
, { remove } = require('fs-extra')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, buildQueue = require(__dirname+'/../../queue.js')
, { prepareMarkdown } = require(__dirname+'/../../helpers/posting/markdown.js')
, messageHandler = require(__dirname+'/../../helpers/posting/message.js');
module.exports = async (req, res, next) => {
const message = prepareMarkdown(req.body.message, false);
const { message: markdownPage } = await messageHandler(message, null, null, res.locals.permLevel);
const editedDate = new Date();
const oldPage = await CustomPages.findOneAndUpdate(req.body.page_id, req.params.board,
req.body.page, req.body.title, message, markdownPage, editedDate).then(res => res.value);
if (oldPage === null) {
return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request',
'errors': 'Custom page does not exist',
'redirect': req.headers.referer || '/${req.params.board}/manage/custompages.html'
});
}
await remove(`${uploadDirectory}/html/${req.params.board}/custompage/${oldPage.page}.html`);
const newPage = {
'_id': oldPage._id,
'board': req.params.board,
'page': req.body.page,
'title': req.body.title,
'message': {
'raw': message,
'markdown': markdownPage
},
'date': oldPage.date,
'edited': editedDate,
};
buildQueue.push({
'task': 'buildCustomPage',
'options': {
'board': res.locals.board,
'page': newPage.page,
'customPage': newPage,
}
});
return dynamicResponse(req, res, 200, 'message', {
'title': 'Success',
'message': 'Updated custom page',
'redirect': `/${req.params.board}/manage/custompages.html`,
});
}

@ -1,6 +1,6 @@
'use strict';
const { News } = require(__dirname+'/../../db/');
const { News } = require(__dirname+'/../../../db/');
module.exports = async (req, res, next) => {

@ -9,4 +9,5 @@ module.exports = {
globalManageNews: require(__dirname+'/news.js'),
globalManageAccounts: require(__dirname+'/accounts.js'),
globalManageSettings: require(__dirname+'/settings.js'),
editNews: require(__dirname+'/editnews.js'),
}

@ -22,5 +22,4 @@ module.exports = {
boardlist: require(__dirname+'/boardlist.js'),
overboard: require(__dirname+'/overboard.js'),
overboardCatalog: require(__dirname+'/overboardcatalog.js'),
editNews: require(__dirname+'/editnews.js'),
}

@ -0,0 +1,26 @@
'use strict';
const { CustomPages } = require(__dirname+'/../../../db/');
module.exports = async (req, res, next) => {
let customPage;
try {
customPage = await CustomPages.findOneId(req.params.custompageid, req.params.board);
} catch (err) {
return next(err)
}
if (!customPage) {
return next();
}
res
.set('Cache-Control', 'private, max-age=5')
.render('editcustompage', {
csrf: req.csrfToken(),
page: customPage,
board: res.locals.board,
});
}

@ -11,4 +11,5 @@ module.exports = {
manageCatalog: require(__dirname+'/catalog.js'),
manageThread: require(__dirname+'/thread.js'),
manageCustomPages: require(__dirname+'/custompages.js'),
editCustomPage: require(__dirname+'/editcustompage.js'),
}

@ -6,6 +6,7 @@ mixin custompage(page, manage=false)
if manage === true
input.left.post-check(type='checkbox', name='checkedcustompages' value=page.page)
a.left(href=`/${board._id}/custompage/${page.page}.html`) #{page.title}
a.right.ml-5(href=`/${board._id}/manage/editcustompage/${page._id}.html`) [Edit]
- const pageDate = new Date(page.date);
time.right.reltime(datetime=pageDate.toISOString()) #{pageDate.toLocaleString(undefined, {hourCycle:'h23'})}
tr
@ -14,3 +15,8 @@ mixin custompage(page, manage=false)
p.no-m-p #{`${page.message.raw.substring(0,50)}...`}
else
pre.post-message.no-m-p !{page.message.markdown}
if page.edited
small.right.cb.edited
| Last edited
- const pageEditDate = new Date(page.edited);
time.reltime(datetime=pageEditDate.toISOString()) #{pageEditDate.toLocaleString(undefined, {hourCycle:'h23'})}

@ -8,7 +8,7 @@ mixin newspost(post, globalmanage=false)
input.left.post-check(type='checkbox', name='checkednews' value=post._id)
a.left(href=`#${post._id}`) #{post.title}
if globalmanage === true
a.right.ml-5(href=`/editnews/${post._id}.html`) [Edit]
a.right.ml-5(href=`/globalmanage/editnews/${post._id}.html`) [Edit]
- const newsDate = new Date(post.date);
time.right.reltime(datetime=newsDate.toISOString()) #{newsDate.toLocaleString(undefined, {hourCycle:'h23'})}
tr

@ -0,0 +1,27 @@
extends ../layout.pug
block head
title Edit Custom Page
block content
h1.board-title Edit Custom Page
include ../includes/stickynav.pug
.form-wrapper.flex-center.mv-10
form.form-post(action=`/forms/board/${board._id}/editcustompage` method='POST')
input(type='hidden' name='_csrf' value=csrf)
input(type='hidden' name='page_id' value=page._id)
.row
.label .html name
input(type='text' name='page' pattern='[a-z0-9-_]+' title='a-z0-9-_ only' value=page.page required)
.table-container.flex-center.mv-5
table
tr
th
input.edit.left(type='text' name='title' value=page.title required)
- const pageDate = new Date(page.date);
time.right.reltime(datetime=pageDate.toISOString()) #{pageDate.toLocaleString(undefined, {hourCycle:'h23'})}
tr
td
textarea.edit.fw(name='message' rows='10' placeholder='Supports post styling' required) #{page.message.raw}
input(type='submit', value='save')

@ -27,7 +27,7 @@ block content
input(type='submit', value='submit')
if customPages.length > 0
hr(size=1)
h4.no-m-p Delete Custom Pages:
h4.no-m-p Manage Custom Pages:
.form-wrapper.flexleft
form.form-post(action=`/forms/board/${board._id}/deletecustompages`, enctype='application/x-www-form-urlencoded', method='POST')
input(type='hidden' name='_csrf' value=csrf)

Loading…
Cancel
Save