mirror of https://gitgud.io/fatchan/jschan.git
Merge pull request #13 from fatchan/bans
add bans + numerous other improvementsmerge-requests/208/head
commit
530dd7d1c5
64 changed files with 1257 additions and 590 deletions
@ -1,7 +1,7 @@ |
||||
|
||||
'use strict'; |
||||
|
||||
const Mongo = require(__dirname+'/../helpers/db.js') |
||||
const Mongo = require(__dirname+'/db.js') |
||||
, db = Mongo.client.db('jschan').collection('accounts') |
||||
, bcrypt = require('bcrypt'); |
||||
|
@ -0,0 +1,66 @@ |
||||
|
||||
'use strict'; |
||||
|
||||
const Mongo = require(__dirname+'/db.js') |
||||
, db = Mongo.client.db('jschan').collection('bans'); |
||||
|
||||
module.exports = { |
||||
|
||||
db, |
||||
|
||||
find: (ip, board) => { |
||||
return db.find({ |
||||
'ip': ip, |
||||
'board': { |
||||
'$in': [board, null] |
||||
} |
||||
}).toArray(); |
||||
}, |
||||
|
||||
findMany: (board, ids) => { |
||||
return db.find({ |
||||
'_id': { |
||||
'$in': ids |
||||
}, |
||||
'board': board |
||||
}).toArray(); |
||||
}, |
||||
|
||||
getAllBans: () => { |
||||
return db.find({}).toArray(); |
||||
}, |
||||
|
||||
getGlobalBans: () => { |
||||
return db.find({ |
||||
'board': null |
||||
}).toArray(); |
||||
}, |
||||
|
||||
getBoardBans: (board) => { |
||||
return db.find({ |
||||
'board': board, |
||||
}).toArray(); |
||||
}, |
||||
|
||||
removeMany: (board, ids) => { |
||||
return db.deleteMany({ |
||||
'board': board, |
||||
'_id': { |
||||
'$in': ids |
||||
} |
||||
}) |
||||
}, |
||||
|
||||
insertOne: (ban) => { |
||||
return db.insertOne(ban); |
||||
}, |
||||
|
||||
insertMany: (bans) => { |
||||
return db.insertMany(bans); |
||||
}, |
||||
|
||||
deleteAll: () => { |
||||
return db.deleteMany({}); |
||||
}, |
||||
|
||||
} |
@ -1,6 +1,6 @@ |
||||
'use strict'; |
||||
|
||||
const Mongo = require(__dirname+'/../helpers/db.js') |
||||
const Mongo = require(__dirname+'/db.js') |
||||
, db = Mongo.client.db('jschan').collection('tripcodes'); |
||||
|
||||
module.exports = { |
@ -0,0 +1,20 @@ |
||||
'use strict'; |
||||
|
||||
const Bans = require(__dirname+'/../db/bans.js') |
||||
, hasPerms = require(__dirname+'/hasperms.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
if (!hasPerms(req, res)) { |
||||
const ip = req.headers['x-real-ip'] || req.connection.remoteAddress; |
||||
const bans = await Bans.find(ip, res.locals.board ? res.locals.board._id : null); |
||||
if (bans && bans.length > 0) { |
||||
//TODO: show posts banned for, expiry, etc
|
||||
return res.status(403).render('ban', { |
||||
bans: bans |
||||
}); |
||||
} |
||||
} |
||||
next(); |
||||
|
||||
} |
@ -1,6 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = (req, res, next) => { |
||||
if (req.session.authenticated === true) return next() |
||||
res.redirect('/login') |
||||
} |
@ -1,9 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
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 //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
|
||||
} |
@ -0,0 +1,16 @@ |
||||
'use strict'; |
||||
|
||||
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 //and is not a regular user
|
||||
|| ( |
||||
res.locals.board |
||||
&& ( |
||||
res.locals.board.owner == req.session.user.username //and board owner
|
||||
|| res.locals.board.moderators.includes(req.session.user.username) //or board mod
|
||||
) |
||||
) |
||||
) |
||||
} |
@ -0,0 +1,16 @@ |
||||
'use strict'; |
||||
|
||||
const hasPerms = require(__dirname+'/hasperms.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
if (!hasPerms(req, res)) { |
||||
return res.status(403).render('message', { |
||||
'title': 'Forbidden', |
||||
'message': 'You do not have permission to access this page', |
||||
'redirect': '/' |
||||
}); |
||||
} |
||||
next(); |
||||
|
||||
} |
@ -0,0 +1,8 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = (req, res, next) => { |
||||
if (req.session.authenticated === true) { |
||||
return next(); |
||||
} |
||||
res.redirect('/login'); |
||||
} |
@ -0,0 +1,45 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../db/posts.js') |
||||
, quoteRegex = />>\d+/gm; |
||||
|
||||
module.exports = async (board, text) => { |
||||
|
||||
//get the matches
|
||||
const matches = text.match(quoteRegex); |
||||
if (!matches) { |
||||
return text; |
||||
} |
||||
|
||||
//get all the Ids
|
||||
const quoteIds = matches.map(x => +x.substring(2)); |
||||
|
||||
//get all posts with those Ids
|
||||
const posts = await Posts.getPosts(board, quoteIds, false); |
||||
|
||||
//turn the result into a map of postId => threadId/postId
|
||||
const postThreadObject = {}; |
||||
let validQuotes = 0; |
||||
for (let i = 0; i < posts.length; i++) { |
||||
const post = posts[i]; |
||||
postThreadObject[post.postId] = post.thread || post.postId; |
||||
validQuotes++; |
||||
} |
||||
|
||||
//if none of the quotes were real, dont do a replace
|
||||
if (validQuotes === 0) { |
||||
return text; |
||||
} |
||||
|
||||
//then replace the quotes with only ones that exist
|
||||
text = text.replace(quoteRegex, (match) => { |
||||
const quotenum = +match.substring(2); |
||||
if (postThreadObject[quotenum]) { |
||||
return `<a class='quote' href='/${board}/thread/${postThreadObject[quotenum]}#${quotenum}'>>>${quotenum}</a>`; |
||||
} |
||||
return match; |
||||
}); |
||||
|
||||
return text; |
||||
|
||||
} |
@ -1,17 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
const Boards = require(__dirname+'/../../db-models/boards.js'); |
||||
|
||||
module.exports = async (req, res) => { |
||||
//get a list of boards
|
||||
let boards; |
||||
try { |
||||
boards = await Boards.find(); |
||||
} catch (err) { |
||||
console.error(err); |
||||
return res.status(500).json({ 'message': 'Error fetching from DB' }) |
||||
} |
||||
|
||||
//render the page
|
||||
res.json(boards) |
||||
} |
@ -1,20 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db-models/posts.js'); |
||||
|
||||
module.exports = async (req, res) => { |
||||
//get the recently bumped thread & preview posts
|
||||
let data; |
||||
try { |
||||
data = await Posts.getCatalog(req.params.board); |
||||
} catch (err) { |
||||
console.error(err); |
||||
return res.status(500).json({ 'message': 'Error fetching from DB' }); |
||||
} |
||||
|
||||
if (!data) { |
||||
return res.status(404).json({ 'message': 'Not found' }); |
||||
} |
||||
|
||||
return res.json(data) |
||||
} |
@ -1,20 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db-models/posts.js'); |
||||
|
||||
module.exports = async (req, res) => { |
||||
//get the recently bumped thread & preview posts
|
||||
let threads; |
||||
try { |
||||
threads = await Posts.getRecent(req.params.board, req.params.page || 1); |
||||
} catch (err) { |
||||
console.error(err); |
||||
return res.status(500).json({ 'message': 'Error fetching from DB' }); |
||||
} |
||||
|
||||
if (!threads || threads.lenth === 0) { |
||||
return res.status(404).json({ 'message': 'Not found' }); |
||||
} |
||||
|
||||
return res.json(threads); |
||||
} |
@ -1,20 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db-models/posts.js'); |
||||
|
||||
module.exports = async (req, res) => { |
||||
//get the recently bumped thread & preview posts
|
||||
let thread; |
||||
try { |
||||
thread = await Posts.getThread(req.params.board, req.params.id); |
||||
} catch (err) { |
||||
console.error(err); |
||||
return res.status(500).json({ 'message': 'Error fetching from DB' }); |
||||
} |
||||
|
||||
if (!thread) { |
||||
return res.status(404).json({ 'message': 'Not found' }); |
||||
} |
||||
|
||||
return res.json(thread) |
||||
} |
@ -0,0 +1,40 @@ |
||||
'use strict'; |
||||
|
||||
const uploadDirectory = require(__dirname+'/../../helpers/uploadDirectory.js') |
||||
, hasPerms = require(__dirname+'/../../helpers/hasperms.js') |
||||
, Bans = require(__dirname+'/../../db/bans.js') |
||||
, Posts = require(__dirname+'/../../db/posts.js'); |
||||
|
||||
module.exports = async (req, res, next, board, checkedPosts) => { |
||||
|
||||
const posts = checkedPosts; |
||||
|
||||
//if user is not logged in or if logged in but not authed, they cannot ban
|
||||
if (!hasPerms(req, res)) { |
||||
throw { |
||||
'status': 403, |
||||
'message': { |
||||
'title': 'Forbidden', |
||||
'message': 'You do not have permission to issue bans', |
||||
'redirect': `/${req.params.board}` |
||||
} |
||||
}; |
||||
} |
||||
|
||||
const bans = posts.map(post => { |
||||
return { |
||||
'ip': post.ip, |
||||
'reason': req.body.ban_reason || 'No reason specified', |
||||
'board': board, |
||||
'post': req.body.preserve_post ? post : null, |
||||
'issuer': req.session.user.username, |
||||
'date': new Date(), |
||||
'expireAt': new Date((new Date).getTime() + (72*1000*60*60)) // 72h ban
|
||||
} |
||||
}); |
||||
|
||||
const bannedIps = await Bans.insertMany(bans).then(result => result.insertedCount); |
||||
|
||||
return `Banned ${bannedIps} ips`; |
||||
|
||||
} |
@ -1,31 +1,23 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db-models/posts.js') |
||||
, hasPerms = require(__dirname+'/../../helpers/has-perms.js'); |
||||
const Posts = require(__dirname+'/../../db/posts.js') |
||||
, hasPerms = require(__dirname+'/../../helpers/hasperms.js'); |
||||
|
||||
module.exports = async (req, res) => { |
||||
module.exports = async (req, res, next) => { |
||||
|
||||
if (!hasPerms(req, res)) { |
||||
return res.status(403).render('message', { |
||||
'title': 'Forbidden', |
||||
'message': `You are not authorised to dismiss reports.`, |
||||
'redirect': `/${req.params.board}` |
||||
}); |
||||
throw { |
||||
'status': 403, |
||||
'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'); |
||||
} |
||||
const dismissedReports = await Posts.dismissReports(req.params.board, req.body.checkedposts).then(result => result.modifiedCount); |
||||
|
||||
//hooray!
|
||||
return res.render('message', { |
||||
'title': 'Success', |
||||
'message': `Dismissed report(s) successfully`, |
||||
'redirect': `/${req.params.board}/manage` |
||||
}); |
||||
return `Dismissed ${dismissedReports} reports successfully`; |
||||
|
||||
} |
||||
|
@ -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`; |
||||
|
||||
} |
@ -1,34 +1,9 @@ |
||||
'use strict'; |
||||
|
||||
const uuidv4 = require('uuid/v4') |
||||
, path = require('path') |
||||
, Posts = require(__dirname+'/../../db-models/posts.js') |
||||
const Posts = require(__dirname+'/../../db/posts.js'); |
||||
|
||||
module.exports = async (req, res, numFiles) => { |
||||
module.exports = async (req, res, next) => { |
||||
|
||||
// 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 |
||||
}); |
||||
} |
||||
throw new Error('Not implemented'); |
||||
|
||||
// sticky, lock, sage, spoiler, etc
|
||||
for (let i = 0; i < req.body.actions.length; i++) { |
||||
//TODO
|
||||
} |
||||
|
||||
const post = await Posts.updateOne(req.params.board, data) |
||||
const successRedirect = `/${req.params.board}/thread/${req.body.thread || post.insertedId}`; |
||||
|
||||
return res.redirect(successRedirect); |
||||
} |
||||
|
@ -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` |
||||
|
||||
} |
@ -0,0 +1,13 @@ |
||||
'use strict'; |
||||
|
||||
const Bans = require(__dirname+'/../../db/bans.js') |
||||
, { ObjectId } = require('mongodb'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
const banIds = req.body.checkedbans.map(ObjectId); |
||||
const removedBans = await Bans.removeMany(req.params.board, banIds).then(result => result.deletedCount); |
||||
|
||||
return `Removed ${removedBans} bans`; |
||||
|
||||
} |
@ -1,29 +1,20 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db-models/posts.js'); |
||||
const Posts = require(__dirname+'/../../db/posts.js'); |
||||
|
||||
module.exports = async (req, res) => { |
||||
module.exports = async (req, res, next) => { |
||||
|
||||
const ip = req.headers['x-real-ip'] || req.connection.remoteAddress; |
||||
const report = { |
||||
'reason': req.body.reason, |
||||
'reason': req.body.report_reason, |
||||
'date': new Date(), |
||||
'ip': ip |
||||
} |
||||
|
||||
try { |
||||
//push the report to all checked posts
|
||||
await Posts.reportMany(req.params.board, req.body.checked, report); |
||||
} catch (err) { |
||||
console.error(err); |
||||
return res.status(500).render('error'); |
||||
} |
||||
//push the report to all checked posts
|
||||
const reportedCount = await Posts.reportMany(req.params.board, req.body.checkedposts, report).then(result => result.modifiedCount); |
||||
|
||||
//hooray!
|
||||
return res.render('message', { |
||||
'title': 'Success', |
||||
'message': `Reported post(s) successfully`, |
||||
'redirect': `/${req.params.board}` |
||||
}); |
||||
return `Reported ${reportedCount} posts successfully` |
||||
|
||||
} |
||||
|
@ -1,23 +1,28 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db-models/posts.js'); |
||||
const Posts = require(__dirname+'/../../db/posts.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
//get the recently bumped thread & preview posts
|
||||
const page = req.query.p || 1; |
||||
let threads; |
||||
let pages; |
||||
try { |
||||
threads = await Posts.getRecent(req.params.board, req.params.page || 1); |
||||
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(); |
||||
} |
||||
threads = await Posts.getRecent(req.params.board, page); |
||||
} catch (err) { |
||||
console.error(err) |
||||
return next(); |
||||
return next(err); |
||||
} |
||||
|
||||
|
||||
//render the page
|
||||
res.render('board', { |
||||
csrf: req.csrfToken(), |
||||
threads: threads || [], |
||||
pages: pages |
||||
pages, |
||||
page, |
||||
}); |
||||
} |
||||
|
@ -0,0 +1,24 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db/posts.js') |
||||
, Bans = require(__dirname+'/../../db/bans.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
let reports; |
||||
let bans; |
||||
try { |
||||
reports = await Posts.getGlobalReports(); |
||||
bans = await Bans.getGlobalBans(); |
||||
} catch (err) { |
||||
return next(err) |
||||
} |
||||
|
||||
//render the page
|
||||
res.render('globalmanage', { |
||||
csrf: req.csrfToken(), |
||||
reports, |
||||
bans, |
||||
}); |
||||
|
||||
} |
@ -1,10 +1,11 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = (req, res) => { |
||||
module.exports = (req, res, next) => { |
||||
|
||||
//render the page
|
||||
res.render('login', { |
||||
csrf: req.csrfToken() |
||||
csrf: req.csrfToken(), |
||||
redirect: req.query.redirect, |
||||
}); |
||||
|
||||
} |
||||
|
@ -1,21 +1,24 @@ |
||||
'use strict'; |
||||
|
||||
const Posts = require(__dirname+'/../../db-models/posts.js'); |
||||
const Posts = require(__dirname+'/../../db/posts.js') |
||||
, Bans = require(__dirname+'/../../db/bans.js'); |
||||
|
||||
module.exports = async (req, res) => { |
||||
module.exports = async (req, res, next) => { |
||||
|
||||
let posts; |
||||
let reports; |
||||
let bans; |
||||
try { |
||||
posts = await Posts.getReports(req.params.board); |
||||
reports = await Posts.getReports(req.params.board); |
||||
bans = await Bans.getBoardBans(req.params.board); |
||||
} catch (err) { |
||||
console.error(err); |
||||
return res.status(500).render('error'); |
||||
return next(err) |
||||
} |
||||
|
||||
//render the page
|
||||
res.render('manage', { |
||||
csrf: req.csrfToken(), |
||||
posts: posts |
||||
reports, |
||||
bans, |
||||
}); |
||||
|
||||
} |
||||
|
@ -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') |
@ -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') |
||||
|
@ -0,0 +1,32 @@ |
||||
.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='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='dismiss' value=1) |
||||
| Dismiss Reports |
||||
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') |
||||
|
@ -1,3 +1,4 @@ |
||||
a.no-decoration(href=`/${board._id}`) |
||||
h1.board-title /#{board._id}/ - #{board.name} |
||||
h4.board-description #{board.description} |
||||
section.board-header |
||||
a.no-decoration(href=`/${board._id}`) |
||||
h1.board-title /#{board._id}/ - #{board.name} |
||||
h4.board-description #{board.description} |
||||
|
@ -1,15 +0,0 @@ |
||||
section.action-wrapper |
||||
span |
||||
label |
||||
input.post-check(type='checkbox', name='delete' value=1) |
||||
| Delete |
||||
label |
||||
input.post-check(type='checkbox', name='spoiler' value=1) |
||||
| Spoiler |
||||
input#password(type='password', name='password', placeholder='post password' autocomplete='off') |
||||
span |
||||
label |
||||
input.post-check(type='checkbox', name='report' value=1) |
||||
| Report |
||||
input#report(type='text', name='reason', placeholder='reason' autocomplete='off') |
||||
input(type='submit', value='submit') |
@ -1,5 +1,9 @@ |
||||
nav.navbar |
||||
a.nav-item(href='/') Home |
||||
a.nav-item(href='/login') Login |
||||
if board |
||||
a.nav-item(href=`/${board._id}/manage`) Manage Board |
||||
a.nav-item.right(href=`/${board._id}/manage`) Manage Board |
||||
a.nav-item.right(href=`/login?redirect=/${board._id}/`) Login |
||||
else |
||||
a.nav-item.right(href='/login') Login |
||||
a.nav-item.right(href='/register') Register |
||||
a.nav-item.right(href='/logout') Logout |
||||
|
@ -0,0 +1,6 @@ |
||||
span.pages Page: |
||||
- for(let i = 1; i <= pages; i++) |
||||
if i === page |
||||
span: a(href=`/${board._id}?p=${i}`) [#{i}] |
||||
else |
||||
span: a(href=`/${board._id}?p=${i}`) #{i} |
@ -1,25 +1,29 @@ |
||||
section.form-wrapper |
||||
form.form-post(action='/forms/board/'+board._id, 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(type='hidden' name='_csrf' value=csrf) |
||||
|
||||
input#title(type='text', name='subject', placeholder='subject' autocomplete='off' maxlength='50') |
||||
input(type='hidden' name='thread' value=thread != null ? thread.postId : null) |
||||
|
||||
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#title(type='text', name='subject', placeholder='subject' autocomplete='off' maxlength='50') |
||||
|
||||
input#password(type='password', name='password', placeholder='post password' autocomplete='off' maxlength='50') |
||||
input#name(type='text', name='name', placeholder='name' autocomplete='off' maxlength='50') |
||||
|
||||
textarea#message(name='message', rows='8', cols='50', placeholder='message' autocomplete='off' maxlength='2000') |
||||
input#name(type='text', name='email', placeholder='email' autocomplete='off' maxlength='50') |
||||
|
||||
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#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') |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,18 @@ |
||||
include ./post.pug |
||||
|
||||
mixin ban(ban) |
||||
.ban |
||||
input.post-check(type='checkbox', name='checkedbans[]' value=ban._id) |
||||
if ban.board |
||||
div Board: #[a(href=`/${ban.board}`) /#{ban.board}/] |
||||
else |
||||
div Global ban. |
||||
div Reason: #{ban.reason} |
||||
div Issuer: #{ban.issuer} |
||||
div Date: #{ban.date} |
||||
div Expiry: #{ban.expireAt} |
||||
if ban.post |
||||
span Post: |
||||
section.thread |
||||
+post(ban.post, false) |
||||
|
@ -0,0 +1,14 @@ |
||||
extends ../layout.pug |
||||
include ../mixins/ban.pug |
||||
|
||||
block head |
||||
title Banned! |
||||
|
||||
block content |
||||
h1.board-title Banned! |
||||
hr(size=1) |
||||
Bans currently in place against your IP: |
||||
hr(size=1) |
||||
for ban in bans |
||||
+ban(ban) |
||||
hr(size=1) |
@ -0,0 +1,35 @@ |
||||
extends ../layout.pug |
||||
include ../mixins/post.pug |
||||
include ../mixins/ban.pug |
||||
|
||||
block head |
||||
title Manage |
||||
|
||||
block content |
||||
h1.board-title Global Management |
||||
h4 All Reports: |
||||
form(action=`/forms/global/actions` method='POST' enctype='application/x-www-form-urlencoded') |
||||
input(type='hidden' name='_csrf' value=csrf) |
||||
if reports.length === 0 |
||||
p No reports. |
||||
hr(size=1) |
||||
else |
||||
for report in reports |
||||
section.thread |
||||
+post(report, false, false, true) |
||||
hr(size=1) |
||||
include ../includes/actionfooter_globalmanage.pug |
||||
hr(size=1) |
||||
h4 All Bans: |
||||
form(action=`/forms/global/unban` method='POST' enctype='application/x-www-form-urlencoded') |
||||
input(type='hidden' name='_csrf' value=csrf) |
||||
if bans.length === 0 |
||||
p No bans. |
||||
hr(size=1) |
||||
else |
||||
for ban in bans |
||||
section.thread |
||||
+ban(ban) |
||||
hr(size=1) |
||||
section.action-wrapper |
||||
input(type='submit', value='unban') |
@ -1,35 +1,36 @@ |
||||
extends ../layout.pug |
||||
include ../mixins/post.pug |
||||
include ../mixins/ban.pug |
||||
|
||||
block head |
||||
title Login |
||||
title Manage |
||||
|
||||
block content |
||||
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') |
||||
h4 Reports: |
||||
form(action=`/forms/board/${board._id}/actions` method='POST' enctype='application/x-www-form-urlencoded') |
||||
input(type='hidden' name='_csrf' value=csrf) |
||||
if posts.length === 0 |
||||
if reports.length === 0 |
||||
p No reports. |
||||
hr(size=1) |
||||
for post in posts |
||||
section.thread |
||||
+post(board, post) |
||||
else |
||||
for report in reports |
||||
section.thread |
||||
+post(report, false, true) |
||||
hr(size=1) |
||||
include ../includes/actionfooter_manage.pug |
||||
hr(size=1) |
||||
section.action-wrapper |
||||
span |
||||
label |
||||
input.post-check(type='checkbox', name='delete' value=1) |
||||
| Delete |
||||
span |
||||
label |
||||
input.post-check(type='checkbox', name='spoiler' value=1) |
||||
| Spoiler |
||||
span |
||||
label |
||||
input.post-check(type='checkbox', name='dismiss' value=1) |
||||
| Dismiss |
||||
input(type='submit', value='submit') |
||||
|
||||
|
||||
h4 Bans: |
||||
form(action=`/forms/board/${board._id}/unban` method='POST' enctype='application/x-www-form-urlencoded') |
||||
input(type='hidden' name='_csrf' value=csrf) |
||||
if bans.length === 0 |
||||
p No bans. |
||||
hr(size=1) |
||||
else |
||||
for ban in bans |
||||
section.thread |
||||
+ban(ban) |
||||
hr(size=1) |
||||
section.action-wrapper |
||||
input(type='submit', value='unban') |
||||
|
||||
|
Loading…
Reference in new issue