ip on post and reports, ability to dismiss reports. report and management improvements

merge-requests/208/head
fatchan 5 years ago
parent 03e3b2e742
commit 4ab5f786ba
  1. 33
      controllers/forms.js
  2. 6
      db-models/boards.js
  3. 26
      db-models/posts.js
  4. 6
      helpers/has-perms.js
  5. 5
      models/forms/delete-post.js
  6. 31
      models/forms/dismiss-report.js
  7. 9
      models/forms/report-post.js
  8. 1
      models/pages/home.js
  9. 22
      static/css/style.css
  10. 3
      views/includes/boardheader.pug
  11. 15
      views/includes/deletefooter.pug
  12. 2
      views/includes/postform.pug
  13. 10
      views/mixins/post.pug
  14. 5
      views/pages/board.pug
  15. 19
      views/pages/manage.pug
  16. 7
      views/pages/thread.pug

@ -6,8 +6,9 @@ const express = require('express')
, Posts = require(__dirname+'/../db-models/posts.js')
, Trips = require(__dirname+'/../db-models/trips.js')
, makePost = require(__dirname+'/../models/forms/make-post.js')
, deletePost = require(__dirname+'/../models/forms/delete-post.js')
, reportPost = require(__dirname+'/../models/forms/report-post.js')
, deletePosts = require(__dirname+'/../models/forms/delete-post.js')
, reportPosts = require(__dirname+'/../models/forms/report-post.js')
, dismissReports = require(__dirname+'/../models/forms/dismiss-report.js')
, loginAccount = require(__dirname+'/../models/forms/login.js')
, registerAccount = require(__dirname+'/../models/forms/register.js')
, numberConverter = require(__dirname+'/../helpers/number-converter.js');
@ -117,6 +118,9 @@ router.post('/board/:board', Boards.exists, numberConverter, (req, res, next) =>
if (req.body.subject && req.body.subject.length > 50) {
errors.push('Subject must be 50 characters or less');
}
if (req.body.email && req.body.email.length > 50) {
errors.push('Email must be 50 characters or less');
}
if (req.body.password && req.body.password.length > 50) {
errors.push('Password must be 50 characters or less');
}
@ -138,17 +142,20 @@ router.post('/board/:board/posts', Boards.exists, numberConverter, (req, res, ne
const errors = [];
if (!req.body.checked || req.body.checked.length === 0 || req.body.checked.length > 10) {
errors.push('Must select 1-10 posts')
}
if (req.body.password && req.body.password.length > 50) {
errors.push('Password must be 50 characters or less');
}
if (req.body.report && req.body.report.length > 50) {
if (req.body.reason && req.body.reason.length > 50) {
errors.push('Report must be 50 characters or less');
}
if (req.body.password && req.body.report) {
errors.push('Can only report or delete, not both');
if (!(req.body.report || req.body.delete || req.body.dismiss)) {
errors.push('Must select an action')
}
if (!req.body.checked || req.body.checked.length === 0 || req.body.checked.length > 10) { //10 for now just for _some_ limit
errors.push('Must select 1-10 posts')
if (req.body.report && (!req.body.reason || req.body.reason.length === 0)) {
errors.push('Reports must have a reason')
}
if (errors.length > 0) {
@ -159,16 +166,16 @@ router.post('/board/:board/posts', Boards.exists, numberConverter, (req, res, ne
})
}
//we checked to make sure there are not both, so...
if (req.body.report) {
//if theres a report reason, handle reports
reportPost(req, res);
reportPosts(req, res);
} else if (req.body.delete) {
deletePosts(req, res);
} else {
//otherwise, must be delete request which
//for authed users DOES NOT requoie passwrd
deletePost(req, res);
dismissReports(req, res);
}
});
module.exports = router;

@ -49,7 +49,11 @@ module.exports = {
|| res.locals.board.moderators.includes(req.session.user.username)) {
return next();
}
return res.redirect('/login');
return res.status(403).render('message', {
'title': 'Forbidden',
'message': 'You do not have permission to manage this board',
'redirect': '/login'
});
},

@ -19,6 +19,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'ip': 0,
'reports': 0
}
}).sort({
@ -34,6 +35,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'ip': 0,
'reports': 0
}
}).sort({
@ -48,7 +50,8 @@ module.exports = {
getPages: (board) => {
return db.countDocuments({
'board': board
'board': board,
'thread': null
});
},
@ -63,6 +66,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'ip': 0,
'reports': 0
}
}),
@ -89,6 +93,7 @@ module.exports = {
'projection': {
'salt': 0 ,
'password': 0,
'ip': 0,
'reports': 0
}
}).sort({
@ -107,6 +112,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'ip': 0,
'reports': 0
}
}).toArray();
@ -130,6 +136,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'ip': 0,
'reports': 0
}
});
@ -157,6 +164,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'ip': 0,
'reports': 0
}
}).toArray();
@ -166,7 +174,7 @@ module.exports = {
insertOne: async (board, data) => {
// bump thread if name not sage
if (data.thread !== null && data.name !== 'sage') {
if (data.thread !== null && data.email !== 'sage') {
await db.updateOne({
'postId': data.thread,
'board': board
@ -204,6 +212,19 @@ module.exports = {
});
},
dismissReports: (board, ids) => {
return db.updateMany({
'postId': {
'$in': ids
},
'board': board
}, {
'$set': {
'reports': []
}
});
},
getReports: (board) => {
return db.find({
'reports.0': {
@ -214,6 +235,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'ip': 0,
}
}).toArray();
},

@ -3,7 +3,7 @@
module.exports = (req, res) => {
return req.session.authenticated //if the user is authed
&& req.session.user //if the user is logged in
&& (req.session.user.authLevel > 1
|| res.locals.board.owner == req.session.user.username
|| res.locals.board.moderators.includes(req.session.user.username));
&& (req.session.user.authLevel > 1 //and is not a regular user
|| res.locals.board.owner == req.session.user.username //or us board owner
|| res.locals.board.moderators.includes(req.session.user.username)); //or is board moderator
}

@ -5,10 +5,11 @@ const path = require('path')
, fs = require('fs')
, unlink = util.promisify(fs.unlink)
, uploadDirectory = require(__dirname+'/../../helpers/uploadDirectory.js')
, deletePerms = require(__dirname+'/../../helpers/delete-perms.js')
, hasPerms = require(__dirname+'/../../helpers/has-perms.js')
, Posts = require(__dirname+'/../../db-models/posts.js');
module.exports = async (req, res) => {
//get all posts that were checked
let posts;
try {
@ -19,7 +20,7 @@ module.exports = async (req, res) => {
}
//if user is not logged in OR if lgoged in but not authed, filter the posts by passwords that are not null
if (!deletePerms(req, res)) {
if (!hasPerms(req, res)) {
// filter posts by password only if NOT board moderator or owner
posts = posts.filter(post => {
// only include posts that have a password and that matches

@ -0,0 +1,31 @@
'use strict';
const Posts = require(__dirname+'/../../db-models/posts.js')
, hasPerms = require(__dirname+'/../../helpers/has-perms.js');
module.exports = async (req, res) => {
if (!hasPerms(req, res)) {
return res.status(403).render('message', {
'title': 'Forbidden',
'message': `You are not authorised to dismiss reports.`,
'redirect': `/${req.params.board}`
});
}
try {
//dismiss reports from all checked posts
await Posts.dismissReports(req.params.board, req.body.checked);
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
//hooray!
return res.render('message', {
'title': 'Success',
'message': `Dismissed report(s) successfully`,
'redirect': `/${req.params.board}/manage`
});
}

@ -4,9 +4,16 @@ const Posts = require(__dirname+'/../../db-models/posts.js');
module.exports = async (req, res) => {
const ip = req.headers['x-real-ip'] || req.connection.remoteAddress;
const report = {
'reason': req.body.reason,
'date': new Date(),
'ip': ip
}
try {
//push the report to all checked posts
await Posts.reportMany(req.params.board, req.body.checked, req.body.report);
await Posts.reportMany(req.params.board, req.body.checked, report);
} catch (err) {
console.error(err);
return res.status(500).render('error');

@ -3,6 +3,7 @@
const Boards = require(__dirname+'/../../db-models/boards.js');
module.exports = async (req, res, next) => {
//get a list of boards
let boards;
try {

@ -9,6 +9,21 @@ body {
margin: 0;
}
.spoiler {
background: black;
}
.spoiler:hover {
color: white;
}
.post-mode {
background-color: red;
color: white;
font-weight: bold;
text-align: center;
}
.reports {
background: #fca!important;
border-color: #c97!important;
@ -54,7 +69,7 @@ input, textarea {
margin: 10px 0;
}
.delete-wrapper {
.action-wrapper {
align-items: center;
/*flex-direction: row;*/
}
@ -121,6 +136,11 @@ input textarea {
margin: 0;
}
.no-decoration {
text-decoration: none;
color: white;
}
.board-description {
text-align:center;
margin: 0;

@ -0,0 +1,3 @@
a.no-decoration(href=`/${board._id}`)
h1.board-title /#{board._id}/ - #{board.name}
h4.board-description #{board.description}

@ -1,5 +1,12 @@
section.delete-wrapper
p Report OR delete selected posts
input#report(type='report', name='report', placeholder='report reason' autocomplete='off')
input#password(type='password', name='password', placeholder='password (for deletion)' autocomplete='off')
section.action-wrapper
span
label
input.post-check(type='checkbox', name='delete' value=1)
| Delete
input#password(type='password', name='password', placeholder='deletion password' autocomplete='off')
span
label
input.post-check(type='checkbox', name='report' value=1)
| Report
input#report(type='text', name='reason', placeholder='report reason' autocomplete='off')
input(type='submit', value='submit')

@ -8,6 +8,8 @@ section.form-wrapper
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='password (for deletion)' autocomplete='off' maxlength='50')

@ -4,7 +4,11 @@ mixin post(board, post, truncate)
input.post-check(type='checkbox', name='checked[]' value=post.postId)
if post.subject
span.post-subject #{post.subject}
span.post-name #{post.name}
if post.email
a(href=`mailto:${post.email}`)
span.post-name #{post.name}
else
span.post-name #{post.name}
span #{post.date.toLocaleString()}
span.user-id(style=`background: #${post.userId}`) #{post.userId}
span: a(href=`/${board._id}/thread/${post.thread ? post.thread : post.postId}#${post.postId}`) ##{post.postId}
@ -39,4 +43,6 @@ mixin post(board, post, truncate)
blockquote.post-message !{post.message}
if post.reports
each report in post.reports
span.reports.post-container #{report}
.reports.post-container
span Date: #{report.date.toLocaleString()}
span Reason: #{report.reason}

@ -5,9 +5,10 @@ block head
title /#{board._id}/ - Recent Posts
block content
h1.board-title /#{board._id}/ - #{board.name}
h4.board-description #{board.description}
include ../includes/boardheader.pug
hr(size=1)
include ../includes/postform.pug
.post-mode Posting mode: Thread
hr(size=1)
form(action='/forms/board/'+board._id+'/posts' method='POST' enctype='application/x-www-form-urlencoded')
input(type='hidden' name='_csrf' value=csrf)

@ -5,9 +5,9 @@ block head
title Login
block content
h1.board-title /#{board._id}/ - #{board.name}
h4.board-description Management Panel
include ../includes/boardheader.pug
hr(size=1)
h4.board-description Management Panel
form(action='/forms/board/'+board._id+'/posts' method='POST' enctype='application/x-www-form-urlencoded')
input(type='hidden' name='_csrf' value=csrf)
if posts.length === 0
@ -17,6 +17,15 @@ block content
section.thread
+post(board, post)
hr(size=1)
section.delete-wrapper
input(type='submit', value='delete')
section.action-wrapper
span
label
input.post-check(type='checkbox', name='delete' value=1)
| Delete
span
label
input.post-check(type='checkbox', name='dismiss' value=1)
| Dismiss
input(type='submit', value='submit')

@ -10,9 +10,10 @@ block head
meta(property='og:image', content=thread.files.length > 0 ? '/img/'+thread.files[0].filename : '')
block content
a(href='/'+board._id) Back to /#{board._id}/
include ../includes/boardheader.pug
hr(size=1)
include ../includes/postform.pug
.post-mode Posting mode: Reply [#[a.no-decoration(href=`/${board._id}`) Go Back]]
hr(size=1)
form(action='/forms/board/'+board._id+'/posts' method='POST' enctype='application/x-www-form-urlencoded')
input(type='hidden' name='_csrf' value=csrf)
@ -22,7 +23,3 @@ block content
+post(board, post)
hr(size=1)
include ../includes/deletefooter.pug

Loading…
Cancel
Save