From d5870187bc9fad9959df111df20aca80043159d0 Mon Sep 17 00:00:00 2001 From: fatchan Date: Tue, 16 Apr 2019 15:17:58 +0000 Subject: [PATCH] global and board bans/reports separated, improved action selection form --- controllers/forms.js | 119 +++++++++++++++++- db/bans.js | 6 + db/boards.js | 4 +- db/posts.js | 80 ++++++++---- helpers/number-converter.js | 5 + models/forms/delete-post.js | 18 ++- models/forms/dismiss-report.js | 4 +- models/forms/dismissglobalreport.js | 25 ++++ models/forms/globalreportpost.js | 23 ++++ models/forms/make-post.js | 1 + models/forms/report-post.js | 4 +- models/forms/spoiler-post.js | 19 +-- models/pages/board.js | 2 +- models/pages/globalmanage.js | 4 +- server.js | 2 +- static/css/style.css | 32 ++++- views/includes/actionfooter.pug | 31 +++++ views/includes/actionfooter_globalmanage.pug | 24 ++++ ...letefooter.pug => actionfooter_manage.pug} | 6 +- views/includes/postform.pug | 49 ++++---- views/mixins/post.pug | 14 ++- views/pages/board.pug | 2 +- views/pages/globalmanage.pug | 4 +- views/pages/manage.pug | 2 +- views/pages/thread.pug | 2 +- wipe.js | 9 ++ 26 files changed, 402 insertions(+), 89 deletions(-) create mode 100644 models/forms/dismissglobalreport.js create mode 100644 models/forms/globalreportpost.js create mode 100644 views/includes/actionfooter.pug create mode 100644 views/includes/actionfooter_globalmanage.pug rename views/includes/{deletefooter.pug => actionfooter_manage.pug} (90%) diff --git a/controllers/forms.js b/controllers/forms.js index 66d6df9a..5ebbff9f 100644 --- a/controllers/forms.js +++ b/controllers/forms.js @@ -12,7 +12,9 @@ const express = require('express') , deletePosts = require(__dirname+'/../models/forms/delete-post.js') , spoilerPosts = require(__dirname+'/../models/forms/spoiler-post.js') , reportPosts = require(__dirname+'/../models/forms/report-post.js') + , globalReportPosts = require(__dirname+'/../models/forms/globalreportpost.js') , dismissReports = require(__dirname+'/../models/forms/dismiss-report.js') + , dismissGlobalReports = require(__dirname+'/../models/forms/dismissglobalreport.js') , loginAccount = require(__dirname+'/../models/forms/login.js') , registerAccount = require(__dirname+'/../models/forms/register.js') , hasPerms = require(__dirname+'/../helpers/haspermsmiddleware.js') @@ -161,9 +163,11 @@ router.post('/board/:board/actions', Boards.exists, banCheck, numberConverter, a errors.push('Ban reason must be 50 characters or less'); } if (!(req.body.report + || req.body.global_report + || req.body.spoiler || req.body.delete || req.body.dismiss - || req.body.spoiler + || req.body.global_dismiss || req.body.ban || req.body.global_ban)) { errors.push('Invalid actions selected') @@ -191,24 +195,37 @@ router.post('/board/:board/actions', Boards.exists, banCheck, numberConverter, a const messages = []; try { + + // if getting global banned, board ban doesnt matter if (req.body.global_ban) { messages.push((await banPoster(req, res, next, null, posts))); } else if (req.body.ban) { messages.push((await banPoster(req, res, next, req.params.board, posts))); } + //ban before deleting if (req.body.delete) { messages.push((await deletePosts(req, res, next, posts))); } else { + // if it was getting deleted, we cant do any of these if (req.body.spoiler) { messages.push((await spoilerPosts(req, res, next, posts))); } + // cannot report and dismiss at same time if (req.body.report) { messages.push((await reportPosts(req, res, next))); } else if (req.body.dismiss) { messages.push((await dismissReports(req, res, next))); } + + // cannot report and dismiss at same time + if (req.body.global_report) { + messages.push((await globalReportPosts(req, res, next, posts))); + } else if (req.body.global_dismiss) { + messages.push((await dismissGlobalReports(req, res, next, posts))); + } } + } catch (err) { //something not right if (err.status) { @@ -268,13 +285,111 @@ router.post('/board/:board/unban', Boards.exists, banCheck, hasPerms, numberConv router.post('/global/actions', hasPerms, numberConverter, async(req, res, next) => { - //TODO + const errors = []; + + if (!req.body.globalcheckedposts || req.body.globalcheckedposts.length === 0 || req.body.globalcheckedposts.length > 10) { + errors.push('Must select 1-10 posts') + } + if (req.body.ban_reason && req.body.ban_reason.length > 50) { + errors.push('Ban reason must be 50 characters or less'); + } + if (!(req.body.spoiler + || req.body.delete + || req.body.global_dismiss + || req.body.global_ban)) { + errors.push('Invalid actions selected') + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': '/globalmanage' + }) + } + + const posts = await Posts.globalGetPosts(req.body.globalcheckedposts, true); + if (!posts || posts.length === 0) { + return res.status(404).render('message', { + 'title': 'Not found', + 'errors': 'Selected posts not found', + 'redirect': '/globalmanage' + }) + } + + const messages = []; + try { + + if (req.body.global_ban) { + messages.push((await banPoster(req, res, next, null, posts))); + } + + //ban before deleting + if (req.body.delete) { + messages.push((await deletePosts(req, res, next, posts))); + } else { + // if it was getting deleted, we cant do any of these + if (req.body.spoiler) { + messages.push((await spoilerPosts(req, res, next, posts))); + } + if (req.body.global_dismiss) { + messages.push((await dismissGlobalReports(req, res, next, posts))); + } + } + + } catch (err) { + //something not right + if (err.status) { + // return out special error + return res.status(err.status).render('message', err.message); + } + //some other error, use regular error handler + return next(err); + } + + return res.render('message', { + 'title': 'Success', + 'messages': messages, + 'redirect': `/${req.params.board}` + }); }); router.post('/global/unban', hasPerms, numberConverter, async(req, res, next) => { //TODO + const errors = []; + + if (!req.body.checkedbans || req.body.checkedbans.length === 0 || req.body.checkedbans.length > 10) { + errors.push('Must select 1-10 bans') + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': `/globalmanage` + }); + } + + const messages = []; + try { + messages.push((await removeBans(req, res, next))); + } catch (err) { + //something not right + if (err.status) { + // return out special error + return res.status(err.status).render('message', err.message); + } + //some other error, use regular error handler + return next(err); + } + + return res.render('message', { + 'title': 'Success', + 'messages': messages, + 'redirect': `/globalmanage` + }); }); diff --git a/db/bans.js b/db/bans.js index 8977968f..22fd57b1 100644 --- a/db/bans.js +++ b/db/bans.js @@ -30,6 +30,12 @@ module.exports = { return db.find({}).toArray(); }, + getGlobalBans: () => { + return db.find({ + 'board': null + }).toArray(); + }, + getBoardBans: (board) => { return db.find({ 'board': board, diff --git a/db/boards.js b/db/boards.js index b242bd28..81ee74a6 100644 --- a/db/boards.js +++ b/db/boards.js @@ -33,9 +33,9 @@ module.exports = { exists: async (req, res, next) => { - const board = await module.exports.findOne(req.params.board) + const board = await module.exports.findOne(req.params.board); if (!board) { - return res.status(404).render('404') + return res.status(404).render('404'); } res.locals.board = board; // can acces this in views or next route handlers next(); diff --git a/db/posts.js b/db/posts.js index a0788c6f..a8137378 100644 --- a/db/posts.js +++ b/db/posts.js @@ -40,7 +40,7 @@ module.exports = { } }).sort({ '_id': -1 - }).limit(3).toArray(); + }).limit(5).toArray(); thread.replies = replies.reverse(); })); @@ -172,6 +172,15 @@ module.exports = { }, + //takes array "ids" of mongo ids to get posts from any board + globalGetPosts: (ids) => { + return db.find({ + '_id': { + '$in': ids + }, + }).toArray(); + }, + insertOne: async (board, data) => { // bump thread if name not sage @@ -213,6 +222,27 @@ module.exports = { }); }, + globalReportMany: (ids, report) => { + return db.updateMany({ + '_id': { + '$in': ids + }, + }, { + '$push': { + 'globalreports': report + } + }); + }, + + getReports: (board) => { + return db.find({ + 'reports.0': { + '$exists': true + }, + 'board': board + }).toArray(); + }, + dismissReports: (board, ids) => { return db.updateMany({ 'postId': { @@ -226,58 +256,60 @@ module.exports = { }); }, - getReports: (board) => { + getGlobalReports: () => { return db.find({ - 'reports.0': { + 'globalreports.0': { '$exists': true - }, - 'board': board + } }, { 'projection': { 'salt': 0, 'password': 0, 'ip': 0, + 'reports': 0, } }).toArray(); }, - getAllReports: () => { - return db.find({ - 'reports.0': { - '$exists': true + dismissGlobalReports: (ids) => { + return db.updateMany({ + '_id': { + '$in': ids + }, + }, { + '$set': { + 'globalreports': [] } - }).toArray(); + }); }, deleteOne: (board, options) => { return db.deleteOne(options); }, - deleteMany: (board, ids) => { + deleteMany: (ids) => { return db.deleteMany({ - 'postId': { + '_id': { '$in': ids - }, - 'board': board + } }); }, - spoilerMany: (board, ids) => { + spoilerMany: (ids) => { - return db.updateMany({ - 'postId': { - '$in': ids - }, - 'board': board - }, { - '$set': { + return db.updateMany({ + '_id': { + '$in': ids + } + }, { + '$set': { 'spoiler': true } - }); + }); - }, + }, deleteAll: (board) => { return db.deleteMany({ diff --git a/helpers/number-converter.js b/helpers/number-converter.js index 6604e1ad..795cf377 100644 --- a/helpers/number-converter.js +++ b/helpers/number-converter.js @@ -1,5 +1,7 @@ 'use strict'; +const Mongo = require(__dirname+'/../db/db.js'); + module.exports = (req, res, next) => { //for body @@ -10,6 +12,9 @@ module.exports = (req, res, next) => { //syntax tries to convert all string to number req.body.checkedposts = req.body.checkedposts.map(Number); } + if (req.body.globalcheckedposts) { + req.body.globalcheckedposts = req.body.globalcheckedposts.map(Mongo.ObjectId) + } //and for params if (req.params.id) { diff --git a/models/forms/delete-post.js b/models/forms/delete-post.js index 85e08b00..c8552b82 100644 --- a/models/forms/delete-post.js +++ b/models/forms/delete-post.js @@ -6,6 +6,7 @@ const path = require('path') , unlink = util.promisify(fs.unlink) , uploadDirectory = require(__dirname+'/../../helpers/uploadDirectory.js') , hasPerms = require(__dirname+'/../../helpers/hasperms.js') + , Mongo = require(__dirname+'/../../db/db.js') , Posts = require(__dirname+'/../../db/posts.js'); module.exports = async (req, res, next, checkedPosts) => { @@ -33,12 +34,18 @@ module.exports = async (req, res, next, checkedPosts) => { } } - const threadIds = posts.filter(x => x.thread == null).map(x => x.postId); + //filter to threads, then get the board and thread for each + const boardThreads = posts.filter(x => x.thread == null).map(x => { + return { + board: x.board, + thread: x.postId + }; + }); //get posts from all threads let threadPosts = [] - await Promise.all(threadIds.map(async id => { - const currentThreadPosts = await Posts.getThreadPosts(req.params.board, id); + await Promise.all(boardThreads.map(async data => { + const currentThreadPosts = await Posts.getThreadPosts(data.board, data.thread); threadPosts = threadPosts.concat(currentThreadPosts); return; })) @@ -47,7 +54,8 @@ module.exports = async (req, res, next, checkedPosts) => { const allPosts = posts.concat(threadPosts) //delete posts from DB - const deletedPosts = await Posts.deleteMany(req.params.board, allPosts.map(x => x.postId)).then(result => result.deletedCount); + const postMongoIds = allPosts.map(post => Mongo.ObjectId(post._id)) + const deletedPosts = await Posts.deleteMany(postMongoIds).then(result => result.deletedCount); //get filenames from all the posts let fileNames = []; @@ -65,6 +73,6 @@ module.exports = async (req, res, next, checkedPosts) => { })); //hooray! - return `Deleted ${threadIds.length} threads and ${deletedPosts-threadIds.length} posts` + return `Deleted ${boardThreads.length} threads and ${deletedPosts-boardThreads.length} posts` } diff --git a/models/forms/dismiss-report.js b/models/forms/dismiss-report.js index fa4d1cd5..4fac5fb0 100644 --- a/models/forms/dismiss-report.js +++ b/models/forms/dismiss-report.js @@ -16,8 +16,8 @@ module.exports = async (req, res, next) => { }; } - await Posts.dismissReports(req.params.board, req.body.checkedposts); + const dismissedReports = await Posts.dismissReports(req.params.board, req.body.checkedposts).then(result => result.modifiedCount); - return `Dismissed report(s) successfully`; + return `Dismissed ${dismissedReports} reports successfully`; } diff --git a/models/forms/dismissglobalreport.js b/models/forms/dismissglobalreport.js new file mode 100644 index 00000000..3fbb1b2a --- /dev/null +++ b/models/forms/dismissglobalreport.js @@ -0,0 +1,25 @@ +'use strict'; + +const Mongo = require(__dirname+'/../../db/db.js') + , Posts = require(__dirname+'/../../db/posts.js') + , hasPerms = require(__dirname+'/../../helpers/hasperms.js'); + +module.exports = async (req, res, next, posts) => { + + if (!hasPerms(req, res)) { + throw { + 'status': 403, + 'message': { + 'title': 'Forbidden', + 'message': 'You are not authorised to dismiss global reports.', + 'redirect': '/' + } + }; + } + + const postMongoIds = posts.map(post => Mongo.ObjectId(post._id)) + const dismissedCount = await Posts.dismissGlobalReports(postMongoIds).then(result => result.modifiedCount); + + return `Dismissed ${dismissedCount} reports successfully`; + +} diff --git a/models/forms/globalreportpost.js b/models/forms/globalreportpost.js new file mode 100644 index 00000000..278f312c --- /dev/null +++ b/models/forms/globalreportpost.js @@ -0,0 +1,23 @@ +'use strict'; + +const Mongo = require(__dirname+'/../../db/db.js') + , Posts = require(__dirname+'/../../db/posts.js'); + +module.exports = async (req, res, next, posts) => { + + const ip = req.headers['x-real-ip'] || req.connection.remoteAddress; + const report = { + 'reason': req.body.report_reason, + 'date': new Date(), + 'ip': ip + } + + const ids = posts.map(p => Mongo.ObjectId(p._id)) + + //push the report to all checked posts + const reportedPosts = await Posts.globalReportMany(ids, report).then(result => result.modifiedCount); + + //hooray! + return `Global reported ${reportedPosts} posts successfully` + +} diff --git a/models/forms/make-post.js b/models/forms/make-post.js index 9839e99c..6ebd9709 100644 --- a/models/forms/make-post.js +++ b/models/forms/make-post.js @@ -168,6 +168,7 @@ module.exports = async (req, res, next, numFiles) => { 'files': files, 'salt': !req.body.thread ? salt : '', 'reports': [], + 'globalreports': [], 'spoiler': req.body.spoiler ? true : false, }; diff --git a/models/forms/report-post.js b/models/forms/report-post.js index c2866e35..49bb7efb 100644 --- a/models/forms/report-post.js +++ b/models/forms/report-post.js @@ -12,9 +12,9 @@ module.exports = async (req, res, next) => { } //push the report to all checked posts - await Posts.reportMany(req.params.board, req.body.checkedposts, report); + const reportedCount = await Posts.reportMany(req.params.board, req.body.checkedposts, report).then(result => result.modifiedCount); //hooray! - return `Reported post(s) successfully` + return `Reported ${reportedCount} posts successfully` } diff --git a/models/forms/spoiler-post.js b/models/forms/spoiler-post.js index f819ba2a..6dcabb93 100644 --- a/models/forms/spoiler-post.js +++ b/models/forms/spoiler-post.js @@ -6,6 +6,7 @@ const path = require('path') , unlink = util.promisify(fs.unlink) , uploadDirectory = require(__dirname+'/../../helpers/uploadDirectory.js') , hasPerms = require(__dirname+'/../../helpers/hasperms.js') + , Mongo = require(__dirname+'/../../db/db.js') , Posts = require(__dirname+'/../../db/posts.js'); module.exports = async (req, res, next, checkedPosts) => { @@ -13,17 +14,6 @@ module.exports = async (req, res, next, checkedPosts) => { //get all posts that were checked let posts = checkedPosts; - if (!posts || posts.length === 0) { - throw { - 'status': 400, - 'message': { - 'title': 'Bad requests', - 'message': 'No posts found', - 'redirect': `/${req.params.board}` - } - }; - } - //if user is not logged in OR if lgoged in but not authed, filter the posts by passwords that are not null if (!hasPerms(req, res)) { @@ -39,7 +29,7 @@ module.exports = async (req, res, next, checkedPosts) => { 'message': { 'title': 'Forbidden', 'message': 'Password did not match any selected posts', - 'redirect': `/${req.params.board}` + 'redirect': '/' } }; } @@ -56,13 +46,14 @@ module.exports = async (req, res, next, checkedPosts) => { 'message': { 'title': 'Conflict', 'message': 'Posts already spoilered', - 'redirect': `/${req.params.board}` + 'redirect': '/' } }; } // spoiler posts - const spoileredPosts = await Posts.spoilerMany(req.params.board, posts.map(x => x.postId)).then(result => result.modifiedCount); + const postMongoIds = posts.map(post => Mongo.ObjectId(post._id)); + const spoileredPosts = await Posts.spoilerMany(postMongoIds).then(result => result.modifiedCount); //hooray! return `Spoilered ${spoileredPosts} posts` diff --git a/models/pages/board.js b/models/pages/board.js index fa82182c..649ebae0 100644 --- a/models/pages/board.js +++ b/models/pages/board.js @@ -8,7 +8,7 @@ module.exports = async (req, res, next) => { let threads; let pages; try { - pages = Math.ceil((await Posts.getPages(req.params.board)) / 10); + pages = Math.ceil((await Posts.getPages(req.params.board)) / 10) || 1; if (page > pages) { return next(); } diff --git a/models/pages/globalmanage.js b/models/pages/globalmanage.js index 97daf7ae..f0dfa034 100644 --- a/models/pages/globalmanage.js +++ b/models/pages/globalmanage.js @@ -8,8 +8,8 @@ module.exports = async (req, res, next) => { let reports; let bans; try { - reports = await Posts.getAllReports(); - bans = await Bans.getAllBans(); + reports = await Posts.getGlobalReports(); + bans = await Bans.getGlobalBans(); } catch (err) { return next(err) } diff --git a/server.js b/server.js index 932e84b2..0bf0192d 100644 --- a/server.js +++ b/server.js @@ -53,7 +53,7 @@ const express = require('express') // use pug view engine app.set('view engine', 'pug'); app.set('views', path.join(__dirname, 'views/pages')); -// app.enable('view cache'); + app.enable('view cache'); // static files app.use('/css', express.static(__dirname + '/static/css')); diff --git a/static/css/style.css b/static/css/style.css index 04df4a8d..15e4b914 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -152,10 +152,40 @@ input, textarea { margin: 2px 0; } +.toggle-label:hover { + box-shadow: inset 0 0 100px 100px rgba(255,255,255,.25); +} + +.toggle-label { + background: #D6DAF0; + padding: 10px; + border-radius: 3px; + text-align: center; + border: 1px solid lightgray; + max-width: 100%; + box-sizing: border-box; + /*-webkit-appearance: button; + -moz-appearance: button; + appearance: button;*/ +} + +.toggle { + display: none; +} + +.toggle:checked + .form-post { + display: flex; +} + .form-post { display: flex; flex-direction: column; max-width: 100%; + margin-top: 10px; +} + +.togglable { + display: none; } .user-id { @@ -302,7 +332,7 @@ input textarea { } .nav-item:hover { - box-shadow: inset 0 0 100px 100px rgba(255,255,255,.1); + box-shadow: inset 0 0 100px 100px rgba(255,255,255,.25); } .footer { diff --git a/views/includes/actionfooter.pug b/views/includes/actionfooter.pug new file mode 100644 index 00000000..ec26a9b0 --- /dev/null +++ b/views/includes/actionfooter.pug @@ -0,0 +1,31 @@ +.action-wrapper + .actions Actions: + label + input.post-check(type='checkbox', name='delete' value=1) + | Delete + label + input.post-check(type='checkbox', name='spoiler' value=1) + | Spoiler Images + label + input#password(type='text', name='password', placeholder='post password' autocomplete='off') + label + input.post-check(type='checkbox', name='report' value=1) + | Report + label + input.post-check(type='checkbox', name='global_report' value=1) + | Global Report + label + input#report(type='text', name='report_reason', placeholder='report reason' autocomplete='off') + .actions Mod Actions: + label + input.post-check(type='checkbox', name='ban' value=1) + | Ban Poster + label + input.post-check(type='checkbox', name='global_ban' value=1) + | Global Ban Poster + label + input.post-check(type='checkbox', name='preserve_post' value=1) + | Show Post In Ban + label + input#report(type='text', name='ban_reason', placeholder='ban reason' autocomplete='off') + input(type='submit', value='submit') diff --git a/views/includes/actionfooter_globalmanage.pug b/views/includes/actionfooter_globalmanage.pug new file mode 100644 index 00000000..1d754996 --- /dev/null +++ b/views/includes/actionfooter_globalmanage.pug @@ -0,0 +1,24 @@ +.action-wrapper + .actions Actions: + label + input.post-check(type='checkbox', name='delete' value=1) + | Delete + label + input.post-check(type='checkbox', name='spoiler' value=1) + | Spoiler Images + label + input#report(type='text', name='report_reason', placeholder='report reason' autocomplete='off') + .actions Mod Actions: + label + input.post-check(type='checkbox', name='global_dismiss' value=1) + | Dismiss Global Reports + label + input.post-check(type='checkbox', name='global_ban' value=1) + | Global Ban Poster + label + input.post-check(type='checkbox', name='preserve_post' value=1) + | Show Post In Ban + label + input#report(type='text', name='ban_reason', placeholder='ban reason' autocomplete='off') + input(type='submit', value='submit') + diff --git a/views/includes/deletefooter.pug b/views/includes/actionfooter_manage.pug similarity index 90% rename from views/includes/deletefooter.pug rename to views/includes/actionfooter_manage.pug index b86e6ddf..7cbe4f2d 100644 --- a/views/includes/deletefooter.pug +++ b/views/includes/actionfooter_manage.pug @@ -2,15 +2,15 @@ .actions Actions: label input.post-check(type='checkbox', name='delete' value=1) - | Delete Post + | Delete label input.post-check(type='checkbox', name='spoiler' value=1) | Spoiler Images label input#password(type='text', name='password', placeholder='post password' autocomplete='off') label - input.post-check(type='checkbox', name='report' value=1) - | Report Post + input.post-check(type='checkbox', name='global_report' value=1) + | Global Report label input#report(type='text', name='report_reason', placeholder='report reason' autocomplete='off') .actions Mod Actions: diff --git a/views/includes/postform.pug b/views/includes/postform.pug index 4384dd1d..7277af5e 100644 --- a/views/includes/postform.pug +++ b/views/includes/postform.pug @@ -1,24 +1,29 @@ section.form-wrapper - form.form-post(action=`/forms/board/${board._id}/post`, enctype='multipart/form-data', method='POST') + label.toggle-label Show Post Form + input.toggle(type='checkbox') + form.form-post.togglable(action=`/forms/board/${board._id}/post`, enctype='multipart/form-data', method='POST') + + input(type='hidden' name='_csrf' value=csrf) + + input(type='hidden' name='thread' value=thread != null ? thread.postId : null) + + input#title(type='text', name='subject', placeholder='subject' autocomplete='off' maxlength='50') + + input#name(type='text', name='name', placeholder='name' autocomplete='off' maxlength='50') + + input#name(type='text', name='email', placeholder='email' autocomplete='off' maxlength='50') + + input#password(type='password', name='password', placeholder='post password' autocomplete='off' maxlength='50') + + textarea#message(name='message', rows='8', cols='50', placeholder='message' autocomplete='off' maxlength='2000') + + span + input#file(type='file', name='file' multiple) + label + input.post-check#spoiler(type='checkbox', name='spoiler', value='true') + | Spoiler + + input(type='submit', value='submit') + + - input(type='hidden' name='_csrf' value=csrf) - - input(type='hidden' name='thread' value=thread != null ? thread.postId : null) - - input#title(type='text', name='subject', placeholder='subject' autocomplete='off' maxlength='50') - - input#name(type='text', name='name', placeholder='name' autocomplete='off' maxlength='50') - - input#name(type='text', name='email', placeholder='email' autocomplete='off' maxlength='50') - - input#password(type='password', name='password', placeholder='post password' autocomplete='off' maxlength='50') - - textarea#message(name='message', rows='8', cols='50', placeholder='message' autocomplete='off' maxlength='2000') - - span - input#file(type='file', name='file' multiple) - label - input.post-check#spoiler(type='checkbox', name='spoiler', value='true') - | Spoiler - - input(type='submit', value='submit') diff --git a/views/mixins/post.pug b/views/mixins/post.pug index f3a8ea49..a4d31ba8 100644 --- a/views/mixins/post.pug +++ b/views/mixins/post.pug @@ -1,8 +1,11 @@ -mixin post(post, truncate, showreports) +mixin post(post, truncate, manage, globalmanage) article(id=post.postId class='post-container '+(post.thread ? '' : 'op')) header.post-info span - input.post-check(type='checkbox', name='checkedposts[]' value=post.postId) + if globalmanage + input.post-check(type='checkbox', name='globalcheckedposts[]' value=post._id) + else + input.post-check(type='checkbox', name='checkedposts[]' value=post.postId) if post.subject span.post-subject #{post.subject} if post.email @@ -45,8 +48,13 @@ mixin post(post, truncate, showreports) blockquote.post-message !{post.message} else blockquote.post-message !{post.message} - if showreports && post.reports + if manage === true each report in post.reports .reports.post-container span Date: #{report.date.toLocaleString()} span Reason: #{report.reason} + if globalmanage === true + each report in post.globalreports + .reports.post-container + span Date: #{report.date.toLocaleString()} + span Reason: #{report.reason} diff --git a/views/pages/board.pug b/views/pages/board.pug index 1fbf0369..daac336b 100644 --- a/views/pages/board.pug +++ b/views/pages/board.pug @@ -24,4 +24,4 @@ block content hr(size=1) include ../includes/pages.pug hr(size=1) - include ../includes/deletefooter.pug + include ../includes/actionfooter.pug diff --git a/views/pages/globalmanage.pug b/views/pages/globalmanage.pug index 36eb1444..faedc003 100644 --- a/views/pages/globalmanage.pug +++ b/views/pages/globalmanage.pug @@ -16,9 +16,9 @@ block content else for report in reports section.thread - +post(report, false, true) + +post(report, false, false, true) hr(size=1) - include ../includes/deletefooter.pug + include ../includes/actionfooter_globalmanage.pug hr(size=1) h4 All Bans: form(action=`/forms/global/unban` method='POST' enctype='application/x-www-form-urlencoded') diff --git a/views/pages/manage.pug b/views/pages/manage.pug index e0816182..f8236717 100644 --- a/views/pages/manage.pug +++ b/views/pages/manage.pug @@ -18,7 +18,7 @@ block content section.thread +post(report, false, true) hr(size=1) - include ../includes/deletefooter.pug + include ../includes/actionfooter_manage.pug hr(size=1) h4 Bans: form(action=`/forms/board/${board._id}/unban` method='POST' enctype='application/x-www-form-urlencoded') diff --git a/views/pages/thread.pug b/views/pages/thread.pug index 001ad2cd..465040f2 100644 --- a/views/pages/thread.pug +++ b/views/pages/thread.pug @@ -21,4 +21,4 @@ block content for post in thread.replies +post(post) hr(size=1) - include ../includes/deletefooter.pug + include ../includes/actionfooter.pug diff --git a/wipe.js b/wipe.js index 220ce56c..b9e39de3 100644 --- a/wipe.js +++ b/wipe.js @@ -66,6 +66,15 @@ const Mongo = require(__dirname+'/db/db.js') } } }); + await Posts.db.createIndex({ + 'globalreports.0': 1 + }, { + partialFilterExpression: { + 'globalreports.0': { + '$exists': true + } + } + }); await readdir('static/img/').then(async files => { await Promise.all(files.map(async file => { if (file != 'spoiler.png')