board management section and post reports

merge-requests/208/head
fatchan 5 years ago
parent b42a7eafdf
commit f4f5d2c34f
  1. 25
      controllers/forms.js
  2. 60
      db-models/posts.js
  3. 34
      models/forms/edit-post.js
  4. 1
      models/forms/make-post.js
  5. 22
      models/forms/report-post.js
  6. 15
      models/pages/manage.js
  7. 13
      static/css/style.css
  8. 5
      views/includes/deletefooter.pug
  9. 2
      views/includes/navbar.pug
  10. 9
      views/mixins/post.pug
  11. 8
      views/pages/board.pug
  12. 17
      views/pages/manage.pug
  13. 2
      views/pages/message.pug
  14. 8
      views/pages/thread.pug
  15. 18
      wipe.js

@ -7,6 +7,7 @@ const express = require('express')
, 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')
, loginAccount = require(__dirname+'/../models/forms/login.js')
, registerAccount = require(__dirname+'/../models/forms/register.js')
, numberConverter = require(__dirname+'/../helpers/number-converter.js');
@ -132,16 +133,22 @@ router.post('/board/:board', Boards.exists, numberConverter, (req, res, next) =>
});
// delete post(s)
router.post('/board/:board/delete', Boards.exists, numberConverter, (req, res, next) => {
//report, delete, sticky, etc
router.post('/board/:board/posts', Boards.exists, numberConverter, (req, res, next) => {
const errors = [];
if (req.body.password && req.body.password.length > 50) {
errors.push('Password must be 50 characters or less')
errors.push('Password must be 50 characters or less');
}
if (req.body.report && req.body.report.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.checked || req.body.checked.length === 0 || req.body.checked.length > 10) { //10 for now just for _some_ limit
errors.push('Must check 1-10 boxes for posts to delete')
errors.push('Must select 1-10 posts')
}
if (errors.length > 0) {
@ -152,7 +159,15 @@ router.post('/board/:board/delete', Boards.exists, numberConverter, (req, res, n
})
}
deletePost(req, res);
//we checked to make sure there are not both, so...
if (req.body.report) {
//if theres a report reason, handle reports
reportPost(req, res);
} else {
//otherwise, must be delete request which
//for authed users DOES NOT requoie passwrd
deletePost(req, res);
}
});

@ -17,7 +17,8 @@ module.exports = {
},{
'projection': {
'salt': 0,
'password': 0
'password': 0,
'reports': 0
}
}).sort({
'bumped': -1
@ -31,6 +32,7 @@ module.exports = {
'projection': {
'salt': 0,
'password': 0,
'reports': 0
}
}).sort({
'_id': -1
@ -42,7 +44,7 @@ module.exports = {
},
getPages: async (board) => {
getPages: (board) => {
return db.collection(board).estimatedDocumentCount();
},
@ -55,7 +57,8 @@ module.exports = {
}, {
'projection': {
'salt': 0,
'password': 0
'password': 0,
'reports': 0
}
}),
module.exports.getThreadPosts(board, id)
@ -71,7 +74,7 @@ module.exports = {
},
getThreadPosts: async(board, id) => {
getThreadPosts: (board, id) => {
// all posts within a thread
return db.collection(board).find({
@ -79,7 +82,8 @@ module.exports = {
}, {
'projection': {
'salt': 0 ,
'password': 0
'password': 0,
'reports': 0
}
}).sort({
'_id': 1
@ -87,7 +91,7 @@ module.exports = {
},
getCatalog: async (board) => {
getCatalog: (board) => {
// get all threads for catalog
return db.collection(board).find({
@ -95,13 +99,14 @@ module.exports = {
}, {
'projection': {
'salt': 0,
'password': 0
'password': 0,
'reports': 0
}
}).toArray();
},
getPost: async (board, id, admin) => {
getPost: (board, id, admin) => {
// get a post
if (admin) {
@ -115,14 +120,15 @@ module.exports = {
}, {
'projection': {
'salt': 0,
'password': 0
'password': 0,
'reports': 0
}
});
},
//takes array "ids" of post ids
getPosts: async(board, ids, admin) => {
getPosts: (board, ids, admin) => {
if (admin) {
return db.collection(board).find({
@ -139,7 +145,8 @@ module.exports = {
}, {
'projection': {
'salt': 0,
'password': 0
'password': 0,
'reports': 0
}
}).toArray();
@ -169,11 +176,36 @@ module.exports = {
},
deleteOne: async (board, options) => {
reportMany: (board, ids, report) => {
return db.collection(board).updateMany({
'_id': {
'$in': ids
}
}, {
'$push': {
'reports': report
}
});
},
getReports: (board) => {
return db.collection(board).find({
'reports.0': {
'$exists': true
}
}, {
'projection': {
'salt': 0,
'password': 0,
}
}).toArray();
},
deleteOne: (board, options) => {
return db.collection(board).deleteOne(options);
},
deleteMany: async (board, ids) => {
deleteMany: (board, ids) => {
return db.collection(board).deleteMany({
'_id': {
@ -183,7 +215,7 @@ module.exports = {
},
deleteAll: async (board) => {
deleteAll: (board) => {
return db.collection(board).deleteMany({});
},

@ -0,0 +1,34 @@
'use strict';
const uuidv4 = require('uuid/v4')
, path = require('path')
, Posts = require(__dirname+'/../../db-models/posts.js')
module.exports = async (req, res, numFiles) => {
// get the post that we are trying to edit
let post;
try {
post = await Posts.getPost(req.params.board, req.body.id, true);
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
if (!thread || thread.thread != null) {
return res.status(400).render('message', {
'title': 'Bad request',
'message': 'Post does not exist.',
'redirect': redirect
});
}
// sticky, lock, sage, spoiler, etc
for (let i = 0; i < req.body.actions.length; i++) {
}
const post = await Posts.updateOne(req.params.board, data)
const successRedirect = `/${req.params.board}/thread/${req.body.thread || post.insertedId}`;
return res.redirect(successRedirect);
}

@ -164,6 +164,7 @@ module.exports = async (req, res, numFiles) => {
'userId': userId,
'files': files,
'salt': salt,
'reports': []
};
const post = await Posts.insertOne(req.params.board, data)

@ -0,0 +1,22 @@
'use strict';
const Posts = require(__dirname+'/../../db-models/posts.js');
module.exports = async (req, res) => {
try {
//push the report to all checked posts
await Posts.reportMany(req.params.board, req.body.checked, req.body.report);
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
//hooray!
return res.render('message', {
'title': 'Success',
'message': `Reported post(s) successfully`,
'redirect': `/${req.params.board}`
});
}

@ -1,10 +1,21 @@
'use strict';
module.exports = (req, res) => {
const Posts = require(__dirname+'/../../db-models/posts.js');
module.exports = async (req, res) => {
let posts;
try {
posts = await Posts.getReports(req.params.board);
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
//render the page
res.render('manage', {
csrf: req.csrfToken()
csrf: req.csrfToken(),
posts: posts
});
}

@ -9,6 +9,13 @@ body {
margin: 0;
}
.reports {
background: #fca!important;
border-color: #c97!important;
border-width: 1px 0;
border-style: solid none;
}
.redtext {
color: maroon;
}
@ -49,7 +56,7 @@ input, textarea {
.delete-wrapper {
align-items: center;
flex-direction: row;
/*flex-direction: row;*/
}
.form-post {
@ -129,7 +136,7 @@ input textarea {
max-width: 100%;
}
.post-container:target {
.post-container:target, .op:target {
outline: 1px dashed blue;
outline-offset: -1px;
}
@ -214,6 +221,8 @@ th, td {
hr {
color: lightgray;
/*border-top: 1px solid black;
background: lightgray;*/
}
@media only screen and (max-width: 800px) {

@ -0,0 +1,5 @@
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')
input(type='submit', value='submit')

@ -1,3 +1,5 @@
nav.navbar
a.nav-item(href='/') Home
a.nav-item(href='/login') Login
if board
a.nav-item(href=`/${board._id}/manage`) Manage Board

@ -7,10 +7,7 @@ mixin post(board, post, truncate)
span.post-name #{post.name}
span #{post.date.toLocaleString()}
span.user-id(style=`background: #${post.userId}`) #{post.userId}
if post.thread == null
span: a(href=`/${board._id}/thread/${post._id}`) ##{post._id}
else
span: a(href=`/${board._id}/thread/${post.thread}#${post._id}`) ##{post._id}
span: a(href=`/${board._id}/thread/${post.thread ? post.thread : post._id}#${post._id}`) ##{post._id}
if post.files.length > 0
.post-files
each file in post.files
@ -40,4 +37,6 @@ mixin post(board, post, truncate)
blockquote.post-message !{post.message}
else
blockquote.post-message !{post.message}
if post.reports
each report in post.reports
span.reports.post-container #{report}

@ -9,13 +9,13 @@ block content
h4.board-description #{board.description}
include ../includes/postform.pug
hr(size=1)
form(action='/forms/board/'+board._id+'/delete' method='POST' enctype='application/x-www-form-urlencoded')
form(action='/forms/board/'+board._id+'/posts' method='POST' enctype='application/x-www-form-urlencoded')
input(type='hidden' name='_csrf' value=csrf)
if threads.length === 0
p No posts.
hr(size=1)
for thread in threads
section.thread(id=thread._id)
section.thread
+post(board, thread, true)
for post in thread.replies
+post(board, post, true)
@ -25,6 +25,4 @@ block content
- for(let i = 0; i < pages; i++)
span: a(href=`/${board._id}/${i+1}`) #{i+1}
hr(size=1)
section.delete-wrapper
input#password(type='password', name='password', placeholder='password (for deletion)' autocomplete='off')
input(type='submit', value='delete')
include ../includes/deletefooter.pug

@ -1,7 +1,22 @@
extends ../layout.pug
include ../mixins/post.pug
block head
title Login
block content
p dummy manage page
h1.board-title /#{board._id}/ - #{board.name}
h4.board-description Management Panel
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)
if posts.length === 0
p No posts.
hr(size=1)
for post in posts
section.thread
+post(board, post)
hr(size=1)
section.delete-wrapper
input(type='submit', value='delete')

@ -1,7 +1,7 @@
extends ../layout.pug
block head
meta(http-equiv="refresh" content=`6;url=${redirect}`)
meta(http-equiv="refresh" content=`3;url=${redirect}`)
block content
h1 #{title}

@ -14,16 +14,14 @@ block content
hr(size=1)
include ../includes/postform.pug
hr(size=1)
form(action='/forms/board/'+board._id+'/delete' method='POST' enctype='application/x-www-form-urlencoded')
form(action='/forms/board/'+board._id+'/posts' method='POST' enctype='application/x-www-form-urlencoded')
input(type='hidden' name='_csrf' value=csrf)
section.thread(id=thread._id)
section.thread
+post(board, thread)
for post in thread.replies
+post(board, post)
hr(size=1)
section.delete-wrapper
input#password(type='password', name='password', placeholder='password (for deletion)' autocomplete='off')
input(type='submit', value='delete')
include ../includes/deletefooter.pug

@ -44,6 +44,24 @@ const Mongo = require(__dirname+'/helpers/db.js')
await Posts.db.collection('b').createIndex({"bumped": 1});
await Posts.db.collection('pol').createIndex({"thread": 1});
await Posts.db.collection('pol').createIndex({"bumped": 1});
await Posts.db.collection('pol').createIndex({
'reports.0': 1
}, {
partialFilterExpression: {
'reports.0': {
'$exists': true
}
}
});
await Posts.db.collection('b').createIndex({
'reports.0': 1
}, {
partialFilterExpression: {
'reports.0': {
'$exists': true
}
}
});
await readdir('static/img/').then(async files => {
await Promise.all(files.map(async file => {
unlink(path.join('static/img/', file));

Loading…
Cancel
Save