diff --git a/controllers/forms.js b/controllers/forms.js index e2df680e..ff9209e3 100644 --- a/controllers/forms.js +++ b/controllers/forms.js @@ -271,8 +271,8 @@ router.post('/board/:board/settings', csrf, Boards.exists, checkPermsMiddleware, if (typeof req.body.reply_limit === 'number' && (req.body.reply_limit < 1 || req.body.reply_limit > 1000)) { errors.push('Reply Limit must be from 1-1000'); } - if (typeof req.body.thread_limit === 'number' && (req.body.thread_limit < 1 || req.body.thread_limit > 250)) { - errors.push('Threads Limit must be 1-250'); + if (typeof req.body.thread_limit === 'number' && (req.body.thread_limit < 10 || req.body.thread_limit > 250)) { + errors.push('Threads Limit must be 10-250'); } if (typeof req.body.max_files === 'number' && (req.body.max_files < 0 || req.body.max_files > 3)) { errors.push('Max files must be 0-3'); diff --git a/db/posts.js b/db/posts.js index 4abc8ee8..4a5fd8c6 100644 --- a/db/posts.js +++ b/db/posts.js @@ -301,22 +301,20 @@ module.exports = { data.postId = postId; //insert the post itself - await db.insertOne(data); + const postMongoId = await db.insertOne(data).then(result => result.insertedId); //_id of post //add backlinks to the posts this post quotes - if (data.quotes.length > 0) { + if (data.thread && data.quotes.length > 0) { await db.updateMany({ - 'postId': { - '$in': data.quotes - }, - 'board': board + '_id': { + '$in': data.quotes.map(q => q._id) + } }, { '$push': { - 'backlinks': postId + 'backlinks': { _id: postMongoId, postId: postId } } }); } - return postId; }, @@ -377,9 +375,7 @@ module.exports = { }, deleteAll: (board) => { - return db.deleteMany({ - 'board': board - }); + return db.deleteMany(); }, exists: async (req, res, next) => { diff --git a/helpers/posting/quotes.js b/helpers/posting/quotes.js index bef95f2c..89348348 100644 --- a/helpers/posting/quotes.js +++ b/helpers/posting/quotes.js @@ -5,7 +5,7 @@ const Posts = require(__dirname+'/../../db/posts.js') , quoteRegex = />>\d+/g , crossQuoteRegex = />>>\/\w+\/\d*$/gm; -module.exports = async (board, text) => { +module.exports = async (board, text, thread) => { //get the matches const quotes = text.match(quoteRegex); @@ -66,29 +66,38 @@ module.exports = async (board, text) => { if (!postThreadIdMap[post.board]) { postThreadIdMap[post.board] = {}; } - postThreadIdMap[post.board][post.postId] = post.thread || post.postId; + postThreadIdMap[post.board][post.postId] = { + '_id': post._id, + 'thread': post.thread || post.postId, + 'postId': post.postId + }; } } //then replace the quotes with only ones that exist + const addedQuotes = new Set(); const threadQuotes = []; if (quotes && Object.keys(postThreadIdMap).length > 0) { text = text.replace(quoteRegex, (match) => { const quotenum = +match.substring(2); if (postThreadIdMap[board] && postThreadIdMap[board][quotenum]) { - threadQuotes.push(quotenum) - return `>>${quotenum}${postThreadIdMap[board][quotenum] === quotenum ? ' (OP) ' : ''}`; + if (!addedQuotes.has(postThreadIdMap[board][quotenum]._id) && postThreadIdMap[board][quotenum].thread === thread) { + threadQuotes.push(postThreadIdMap[board][quotenum]); + addedQuotes.add(postThreadIdMap[board][quotenum]._id); + } + return `>>${quotenum}${postThreadIdMap[board][quotenum].postId == thread ? ' (OP) ' : ''}`; } return match; }); } + if (crossQuotes) { text = text.replace(crossQuoteRegex, (match) => { const quote = match.split('/'); const quoteboard = quote[1]; const quotenum = +quote[2]; if (postThreadIdMap[quoteboard] && postThreadIdMap[quoteboard][quotenum]) { - return `>>>/${quoteboard}/${quotenum}`; + return `>>>/${quoteboard}/${quotenum}`; } else if (!quote[2]) { return `>>>/${quoteboard}/`; } @@ -96,6 +105,6 @@ module.exports = async (board, text) => { }); } - return { quotedMessage: text, threadQuotes: [...new Set(threadQuotes)] }; + return { quotedMessage: text, threadQuotes }; } diff --git a/models/forms/deletepost.js b/models/forms/deletepost.js index 468b84d8..5274e522 100644 --- a/models/forms/deletepost.js +++ b/models/forms/deletepost.js @@ -3,7 +3,7 @@ const uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js') , { remove } = require('fs-extra') , Mongo = require(__dirname+'/../../db/db.js') - , Posts = require(__dirname+'/../../db/posts.js'); + , Posts = require(__dirname+'/../../db/posts.js') module.exports = async (posts, board) => { @@ -38,13 +38,46 @@ module.exports = async (posts, board) => { //combine them all into one array, there may be duplicates but it shouldnt matter const allPosts = posts.concat(threadPosts); -//NOTE: this is where, when implemented, file ref counts would be decremented -//NOTE: this is where, when implemented, re-marking up posts that quoted deleted posts would be done -//could use a destructuring with Array.reduce when i need to get files array, backlinks array and mongoId array -//instead of doing 3 maps or big for loop + //get files for ref counting, backlinks for post re-markup, mongoids for deleting + const { postFiles, postBacklinks, postMongoIds } = allPosts.reduce((acc, post) => { + if (post.files.length > 0) { + acc.postFiles = acc.postFiles.concat(post.files); + } + if (post.backlinks.length > 0) { + acc.postBacklinks = acc.postBacklinks.concat(post.backlinks); + } + acc.postMongoIds.push(post._id); + return acc; + }, { postFiles: [], postBacklinks: [], postMongoIds: [] }); + + //is there a nicer way to do this + const bulkWrites = []; + for (let j = 0; j < allPosts.length; j++) { + const post = allPosts[j]; + for (let i = 0; i < post.quotes.length; i++) { + const quote = post.quotes[i]; + //remove the backlink to this post from any post that it quoted + bulkWrites.push({ + 'updateOne': { + 'filter': { + '_id': quote._id + }, + 'update': { + '$pull': { + 'backlinks': { + 'postId': post.postId + } + } + } + } + }); + } + } + await Posts.db.bulkWrite(bulkWrites); + +//TODO: remarkup to unlink quotes in posts that quote deleted posts +//TODO: file ref counting decrement, oncei implement counting in make post - //get all mongoids and delete posts from - const postMongoIds = allPosts.map(post => Mongo.ObjectId(post._id)); const deletedPosts = await Posts.deleteMany(postMongoIds).then(result => result.deletedCount); //hooray! diff --git a/models/forms/deletepostsfiles.js b/models/forms/deletepostsfiles.js index e2338f5a..71593a30 100644 --- a/models/forms/deletepostsfiles.js +++ b/models/forms/deletepostsfiles.js @@ -9,7 +9,7 @@ module.exports = async (posts, unlinkOnly) => { let fileNames = []; posts.forEach(post => { fileNames = fileNames.concat(post.files.map(x => x.filename)) - }) + }); if (fileNames.length === 0) { return { @@ -18,6 +18,7 @@ module.exports = async (posts, unlinkOnly) => { } if (unlinkOnly) { +//TODO: decrement ref counters when implemented return { message:`Unlinked ${fileNames.length} file(s) across ${posts.length} post(s)`, action:'$set', @@ -39,5 +40,4 @@ module.exports = async (posts, unlinkOnly) => { }; } - } diff --git a/models/forms/makepost.js b/models/forms/makepost.js index 24a11fcf..36745a3d 100644 --- a/models/forms/makepost.js +++ b/models/forms/makepost.js @@ -225,7 +225,7 @@ module.exports = async (req, res, next) => { let quotes = []; if (message && message.length > 0) { message = simpleMarkdown(message); - const { quotedMessage, threadQuotes } = await linkQuotes(req.params.board, message); + const { quotedMessage, threadQuotes } = await linkQuotes(req.params.board, message, req.body.thread || null); message = quotedMessage; quotes = threadQuotes; message = sanitize(message, sanitizeOptions); diff --git a/views/includes/navbar.pug b/views/includes/navbar.pug index d8cf23dc..6693c240 100644 --- a/views/includes/navbar.pug +++ b/views/includes/navbar.pug @@ -2,4 +2,4 @@ nav.navbar a.nav-item(href='/') Home a.nav-item.right(href='/logout') Logout a.nav-item.right(href=`/${board ? board._id+'/' : 'global'}manage.html`) Manage - a.nav-item.right(href=`/login.html${board ? '?goto=/'+board._id : ''}`) Login + //a.nav-item.right(href=`/login.html${board ? '?goto=/'+board._id : ''}`) Login diff --git a/views/mixins/post.pug b/views/mixins/post.pug index fb51def7..223db161 100644 --- a/views/mixins/post.pug +++ b/views/mixins/post.pug @@ -88,7 +88,7 @@ mixin post(post, truncate, manage=false, globalmanage=false) if post.backlinks && post.backlinks.length > 0 .replies Replies: each backlink in post.backlinks - a.quote(href=`/${post.board}/thread/${post.thread || post.postId}.html#${backlink}`) >>#{backlink} + a.quote(href=`/${post.board}/thread/${post.thread || post.postId}.html#${backlink.postId}`) >>#{backlink.postId} | if manage === true each report in post.reports diff --git a/views/pages/changepassword.pug b/views/pages/changepassword.pug index a0c0b0a8..e2b7f2f0 100644 --- a/views/pages/changepassword.pug +++ b/views/pages/changepassword.pug @@ -30,3 +30,5 @@ block content iframe.captcha(src='/captcha.html' width=200 height=110 scrolling='no') input#captcha(type='text', name='captcha', autocomplete='off' placeholder='captcha text' maxlength='6' required) input(type='submit', value='Change Password') + p: a(href='/login.html') Login + p: a(href='/register.html') Register diff --git a/views/pages/login.pug b/views/pages/login.pug index 24ded82f..17dfca1f 100644 --- a/views/pages/login.pug +++ b/views/pages/login.pug @@ -16,5 +16,6 @@ block content .required * input#password(type='password', name='password', maxlength='100' required) input(type='submit', value='submit') - p No account? #[a(href='/register.html') Register] + p: a(href='/register.html') Register + p: a(href='/changepassword.html') Change Password diff --git a/views/pages/register.pug b/views/pages/register.pug index 9ad73ebe..7e8d6b80 100644 --- a/views/pages/register.pug +++ b/views/pages/register.pug @@ -26,4 +26,5 @@ block content iframe.captcha(src='/captcha.html' width=200 height=110 scrolling='no') input#captcha(type='text', name='captcha', autocomplete='off' placeholder='captcha text' maxlength='6' required) input(type='submit', value='Register') - p Already have an account? #[a(href='/login.html') Login] + p: a(href='/login.html') Login + p: a(href='/changepassword.html') Change Password diff --git a/wipe.js b/wipe.js index 579b2b84..8b9ff485 100644 --- a/wipe.js +++ b/wipe.js @@ -1,7 +1,7 @@ 'use strict'; -const Mongo = require(__dirname+'/db/db.js') +const Mongo = require(__dirname+'/db/db.js'); (async () => { console.log('connecting to db...') @@ -16,13 +16,8 @@ const Mongo = require(__dirname+'/db/db.js') console.log('deleting accounts') await Accounts.deleteAll(); console.log('deleting posts') - await Posts.deleteAll('pol'); - await Posts.deleteAll('b'); - await Posts.deleteAll('t'); + await Posts.deleteAll(); console.log('deleting boards') - await Boards.deleteIncrement('pol'); - await Boards.deleteIncrement('b'); - await Boards.deleteIncrement('t'); await Boards.deleteAll(); console.log('deleting bans'); await Bans.deleteAll(); @@ -164,7 +159,7 @@ const Mongo = require(__dirname+'/db/db.js') }); console.log('creating admin account: admin:changeme'); await Accounts.insertOne('admin', 'changeme', 3); - Mongo.client.close() + Mongo.client.close(); console.log('done'); process.exit(0); })();