news page, and ability to add or delete news from global manage page, by auto level 0 accounts only

merge-requests/208/head
fatchan 5 years ago
parent 8f113d8308
commit 883020cfe9
  1. 6
      controllers/forms.js
  2. 36
      controllers/forms/addnews.js
  3. 27
      controllers/forms/deletenews.js
  4. 4
      controllers/pages.js
  5. 31
      db/news.js
  6. 6
      gulp/res/css/style.css
  7. 11
      helpers/build.js
  8. 5
      helpers/paramconverter.js
  9. 2
      helpers/posting/quotes.js
  10. 38
      models/forms/addnews.js
  11. 18
      models/forms/deletenews.js
  12. 14
      models/pages/globalmanage.js
  13. 16
      models/pages/news.js
  14. 1
      schedules.js
  15. 1
      views/includes/navbar.pug
  16. 16
      views/mixins/newspost.pug
  17. 24
      views/pages/globalmanage.pug
  18. 12
      views/pages/news.pug

@ -35,6 +35,8 @@ const express = require('express')
, removeBansController = require(__dirname+'/forms/removebans.js')
, globalActionController = require(__dirname+'/forms/globalactions.js')
, actionController = require(__dirname+'/forms/actions.js')
, addNewsController = require(__dirname+'/forms/addnews.js')
, deleteNewsController = require(__dirname+'/forms/deletenews.js')
, uploadBannersController = require(__dirname+'/forms/uploadbanners.js')
, deleteBannersController = require(__dirname+'/forms/deletebanners.js')
, boardSettingsController = require(__dirname+'/forms/boardsettings.js')
@ -79,6 +81,10 @@ router.post('/board/:board/deletebanners', csrf, Boards.exists, calcPerms, banCh
router.post('/global/unban', csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, removeBansController);
router.post('/board/:board/unban', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, removeBansController);
//news
router.post('/global/addnews', csrf, calcPerms, isLoggedIn, hasPerms(0), addNewsController);
router.post('/global/deletenews', csrf, calcPerms, isLoggedIn, hasPerms(0), paramConverter, deleteNewsController);
//delete board
router.post('/board/:board/deleteboard', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), deleteBoardController);
router.post('/global/deleteboard', csrf, calcPerms, isLoggedIn, hasPerms(1), deleteBoardController);

@ -0,0 +1,36 @@
'use strict';
const addNews = require(__dirname+'/../../models/forms/addnews.js')
module.exports = async (req, res, next) => {
const errors = [];
if (!req.body.message || req.body.message.length === 0) {
errors.push('Missing message');
}
if (req.body.message.length > 10000) {
errors.push('Message must be 10000 characters or less');
}
if (!req.body.title || req.body.title.length === 0) {
errors.push('Missing title');
}
if (req.body.title.length > 50) {
errors.push('Title must be 50 characters or less');
}
if (errors.length > 0) {
return res.status(400).render('message', {
'title': 'Bad request',
'errors': errors,
'redirect': '/globalmanage.html'
});
}
try {
await addNews(req, res, next);
} catch (err) {
return next(err);
}
}

@ -0,0 +1,27 @@
'use strict';
const deleteNews = require(__dirname+'/../../models/forms/deletenews.js');
module.exports = async (req, res, next) => {
const errors = [];
if (!req.body.checkednews || req.body.checkednews.length === 0 || req.body.checkednews.length > 10) {
errors.push('Must select 1-10 newsposts delete');
}
if (errors.length > 0) {
return res.status(400).render('message', {
'title': 'Bad request',
'errors': errors,
'redirect': `/${req.params.board}/manage.html`
})
}
try {
await deleteNews(req, res, next);
} catch (err) {
return next(err);
}
}

@ -21,6 +21,7 @@ const express = require('express')
, catalog = require(__dirname+'/../models/pages/catalog.js')
, banners = require(__dirname+'/../models/pages/banners.js')
, randombanner = require(__dirname+'/../models/pages/randombanner.js')
, news = require(__dirname+'/../models/pages/news.js')
, captchaPage = require(__dirname+'/../models/pages/captchapage.js')
, captcha = require(__dirname+'/../models/pages/captcha.js')
, thread = require(__dirname+'/../models/pages/thread.js');
@ -52,6 +53,9 @@ router.get('/create.html', isLoggedIn, csrf, create);
//registration page
router.get('/register.html', register);
//news page
router.get('/news.html', news);
//captcha page
router.get('/captcha.html', captchaPage);

@ -0,0 +1,31 @@
'use strict';
const Mongo = require(__dirname+'/db.js')
, db = Mongo.client.db('jschan').collection('news');
module.exports = {
find: () => {
return db.find({}).sort({
'_id': -1
}).toArray();
},
insertOne: (news) => {
return db.insertOne(news);
},
deleteMany: (ids) => {
return db.deleteMany({
'_id': {
'$in': ids
}
})
},
deleteAll: () => {
return db.deleteMany({});
},
}

@ -153,6 +153,9 @@ pre {
.mv-10 {
margin: 10px 0;
}
.mv-5 {
margin: 5px 0;
}
.mv-0 {
margin: 0 auto;
}
@ -326,9 +329,8 @@ table {
width: 600px;
}
th {
.table-head, th {
background: var(--label-color);
/*text-align: left;*/
}
td, th {

@ -5,6 +5,7 @@ const Mongo = require(__dirname+'/../db/db.js')
, Posts = require(__dirname+'/../db/posts.js')
, Files = require(__dirname+'/../db/files.js')
, Boards = require(__dirname+'/../db/boards.js')
, News = require(__dirname+'/../db/news.js')
, formatSize = require(__dirname+'/files/formatsize.js')
, uploadDirectory = require(__dirname+'/files/uploadDirectory.js')
, render = require(__dirname+'/render.js');
@ -102,6 +103,16 @@ module.exports = {
console.timeEnd(label);
},
buildNews: async () => {
const label = '/news.html';
console.time(label);
const news = await News.find();
await render('news.html', 'news.pug', {
news
});
console.timeEnd(label);
},
buildHomepage: async () => {
const label = '/index.html';
console.time(label);

@ -1,7 +1,7 @@
'use strict';
const { ObjectId } = require(__dirname+'/../db/db.js')
, allowedArrays = new Set(['checkedposts', 'globalcheckedposts', 'checkedbans', 'checkedbanners']) //only these can be arrays, since express bodyparser will output arrays
, allowedArrays = new Set(['checkednews', 'checkedposts', 'globalcheckedposts', 'checkedbans', 'checkedbanners']) //only these can be arrays, since express bodyparser will output arrays
, trimFields = ['uri', 'moderators', 'filters', 'announcement', 'description', 'message',
'name', 'subject', 'email', 'password', 'default_name', 'report_reason', 'ban_reason'] //trim if we dont want filed with whitespace
, numberFields = ['filter_mode', 'captcha_mode', 'tph_trigger', 'tph_trigger_action', 'reply_limit',
@ -55,6 +55,9 @@ module.exports = (req, res, next) => {
if (req.body.globalcheckedposts) {
req.body.globalcheckedposts = req.body.globalcheckedposts.map(ObjectId)
}
if (req.body.checkednews) {
req.body.checkednews = req.body.checkednews.map(ObjectId)
}
//convert checked bans to mongoid
if (req.body.checkedbans) {
req.body.checkedbans = req.body.checkedbans.map(ObjectId)

@ -18,7 +18,7 @@ module.exports = async (board, text, thread) => {
const postQueryOrs = []
const boardQueryIns = []
const crossQuoteMap = {};
if (quotes) {
if (quotes && board) {
const quoteIds = [...new Set(quotes.map(q => { return Number(q.substring(8)) }))];
postQueryOrs.push({
'board': board,

@ -0,0 +1,38 @@
'use strict';
const News = require(__dirname+'/../../db/news.js')
, uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js')
, { buildNews } = require(__dirname+'/../../helpers/build.js')
, linkQuotes = require(__dirname+'/../../helpers/posting/quotes.js')
, simpleMarkdown = require(__dirname+'/../../helpers/posting/markdown.js')
, escape = require(__dirname+'/../../helpers/posting/escape.js')
, sanitizeOptions = require(__dirname+'/../../helpers/posting/sanitizeoptions.js')
, sanitize = require('sanitize-html');
module.exports = async (req, res, next) => {
const escaped = escape(req.body.message);
const styled = simpleMarkdown(escaped);
const quoted = (await linkQuotes(null, styled, null)).quotedMessage;
const sanitized = sanitize(quoted, sanitizeOptions.after);
const post = {
'title': req.body.title,
'message': {
'raw': req.body.message,
'markdown': sanitized
},
'date': new Date(),
};
await News.insertOne(post);
await buildNews();
return res.render('message', {
'title': 'Success',
'message': 'Added newspost',
'redirect': '/globalmanage.html'
});
}

@ -0,0 +1,18 @@
'use strict';
const News = require(__dirname+'/../../db/news.js')
, { buildNews } = require(__dirname+'/../../helpers/build.js')
module.exports = async (req, res, next) => {
await News.deleteMany(req.body.checkednews);
await buildNews();
return res.render('message', {
'title': 'Success',
'message': 'Deleted news',
'redirect': '/globalmanage.html'
});
}

@ -1,15 +1,18 @@
'use strict';
const Posts = require(__dirname+'/../../db/posts.js')
, Bans = require(__dirname+'/../../db/bans.js');
, Bans = require(__dirname+'/../../db/bans.js')
, News = require(__dirname+'/../../db/news.js');
module.exports = async (req, res, next) => {
let reports;
let bans;
let reports, bans, news;
try {
reports = await Posts.getGlobalReports();
bans = await Bans.getGlobalBans();
[ reports, bans, news ] = await Promise.all([
Posts.getGlobalReports(),
Bans.getGlobalBans(),
News.find()
]);
} catch (err) {
return next(err)
}
@ -19,6 +22,7 @@ module.exports = async (req, res, next) => {
csrf: req.csrfToken(),
reports,
bans,
news,
});
}

@ -0,0 +1,16 @@
'use strict';
const { buildNews } = require(__dirname+'/../../helpers/build.js')
, uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js');
module.exports = async (req, res, next) => {
try {
await buildNews();
} catch (err) {
return next(err);
}
return res.sendFile(`${uploadDirectory}html/news.html`);
}

@ -37,7 +37,6 @@ async function deleteCaptchas() {
console.log('Starting schedules');
await buildHomepage();
setInterval(async () => {
try {
await buildHomepage();

@ -1,5 +1,6 @@
nav.navbar#top
a.nav-item(href='/') Home
a.nav-item(href='/news.html') News
a.nav-item(href=`/${board ? board._id+'/' : 'global'}manage.html`) Manage
a.nav-item(href='/create.html') Create
a.nav-item.right(href='/logout') Logout

@ -0,0 +1,16 @@
mixin newspost(post, globalmanage=false)
.table-container.flex-center.mv-5
.anchor(id=post._id)
table.table-body
tr.table-head
th
if globalmanage === true
input.left.post-check(type='checkbox', name='checkednews[]' value=post._id)
a.left(href=`#${post._id}`) #{post.title}
p.right.no-m-p #{post.date.toLocaleString()}
tr.table-row
td
if globalmanage === true
p.no-m-p #{`${post.message.raw.substring(0,50)}...`}
else
pre.post-message.no-m-p !{post.message.markdown}

@ -1,6 +1,7 @@
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/newspost.pug
block head
title Manage
@ -8,6 +9,29 @@ block head
block content
h1.board-title Global Management
hr(size=1)
h4.no-m-p Add News:
section.form-wrapper.flexleft.mv-10
form.form-post(action=`/forms/global/addnews`, enctype='application/x-www-form-urlencoded', method='POST')
input(type='hidden' name='_csrf' value=csrf)
section.row
.label Title
input(type='text' name='title' required)
section.row
.label Message
textarea(name='message' placeholder='supports post styling' required)
input(type='submit', value='submit')
hr(size=1)
if news.length > 0
h4.no-m-p Delete News:
section.form-wrapper.flexleft.mv-10
form.form-post(action=`/forms/global/deletenews`, enctype='application/x-www-form-urlencoded', method='POST')
input(type='hidden' name='_csrf' value=csrf)
each post in news
+newspost(post, true)
if news.length === 1
.anchor
input(type='submit', value='delete')
hr(size=1)
h4.no-m-p Delete board:
section.form-wrapper.flexleft.mv-10
form.form-post(action=`/forms/global/deleteboard`, enctype='application/x-www-form-urlencoded', method='POST')

@ -0,0 +1,12 @@
extends ../layout.pug
include ../mixins/newspost.pug
block head
title News
block content
h1.board-title News
if news.length === 0
p.text-center No news.
each post in news
+newspost(post)
Loading…
Cancel
Save