NOW I REMEMBER why i didnt do that before: make backlinks delete properly based on quotes from database.

merge-requests/208/head
fatchan 5 years ago
parent cb2fe7c3b5
commit dc3005a3db
  1. 4
      controllers/forms.js
  2. 18
      db/posts.js
  3. 21
      helpers/posting/quotes.js
  4. 47
      models/forms/deletepost.js
  5. 4
      models/forms/deletepostsfiles.js
  6. 2
      models/forms/makepost.js
  7. 2
      views/includes/navbar.pug
  8. 2
      views/mixins/post.pug
  9. 2
      views/pages/changepassword.pug
  10. 3
      views/pages/login.pug
  11. 3
      views/pages/register.pug
  12. 11
      wipe.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)) { 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'); 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)) { if (typeof req.body.thread_limit === 'number' && (req.body.thread_limit < 10 || req.body.thread_limit > 250)) {
errors.push('Threads Limit must be 1-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)) { 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'); errors.push('Max files must be 0-3');

@ -301,22 +301,20 @@ module.exports = {
data.postId = postId; data.postId = postId;
//insert the post itself //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 //add backlinks to the posts this post quotes
if (data.quotes.length > 0) { if (data.thread && data.quotes.length > 0) {
await db.updateMany({ await db.updateMany({
'postId': { '_id': {
'$in': data.quotes '$in': data.quotes.map(q => q._id)
}, }
'board': board
}, { }, {
'$push': { '$push': {
'backlinks': postId 'backlinks': { _id: postMongoId, postId: postId }
} }
}); });
} }
return postId; return postId;
}, },
@ -377,9 +375,7 @@ module.exports = {
}, },
deleteAll: (board) => { deleteAll: (board) => {
return db.deleteMany({ return db.deleteMany();
'board': board
});
}, },
exists: async (req, res, next) => { exists: async (req, res, next) => {

@ -5,7 +5,7 @@ const Posts = require(__dirname+'/../../db/posts.js')
, quoteRegex = />>\d+/g , quoteRegex = />>\d+/g
, crossQuoteRegex = />>>\/\w+\/\d*$/gm; , crossQuoteRegex = />>>\/\w+\/\d*$/gm;
module.exports = async (board, text) => { module.exports = async (board, text, thread) => {
//get the matches //get the matches
const quotes = text.match(quoteRegex); const quotes = text.match(quoteRegex);
@ -66,29 +66,38 @@ module.exports = async (board, text) => {
if (!postThreadIdMap[post.board]) { if (!postThreadIdMap[post.board]) {
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 //then replace the quotes with only ones that exist
const addedQuotes = new Set();
const threadQuotes = []; const threadQuotes = [];
if (quotes && Object.keys(postThreadIdMap).length > 0) { if (quotes && Object.keys(postThreadIdMap).length > 0) {
text = text.replace(quoteRegex, (match) => { text = text.replace(quoteRegex, (match) => {
const quotenum = +match.substring(2); const quotenum = +match.substring(2);
if (postThreadIdMap[board] && postThreadIdMap[board][quotenum]) { if (postThreadIdMap[board] && postThreadIdMap[board][quotenum]) {
threadQuotes.push(quotenum) if (!addedQuotes.has(postThreadIdMap[board][quotenum]._id) && postThreadIdMap[board][quotenum].thread === thread) {
return `<a class='quote' href='/${board}/thread/${postThreadIdMap[board][quotenum]}.html#${quotenum}'>&gt;&gt;${quotenum}</a>${postThreadIdMap[board][quotenum] === quotenum ? ' <small>(OP)</small> ' : ''}`; threadQuotes.push(postThreadIdMap[board][quotenum]);
addedQuotes.add(postThreadIdMap[board][quotenum]._id);
}
return `<a class='quote' href='/${board}/thread/${postThreadIdMap[board][quotenum].thread}.html#${quotenum}'>&gt;&gt;${quotenum}</a>${postThreadIdMap[board][quotenum].postId == thread ? ' <small>(OP)</small> ' : ''}`;
} }
return match; return match;
}); });
} }
if (crossQuotes) { if (crossQuotes) {
text = text.replace(crossQuoteRegex, (match) => { text = text.replace(crossQuoteRegex, (match) => {
const quote = match.split('/'); const quote = match.split('/');
const quoteboard = quote[1]; const quoteboard = quote[1];
const quotenum = +quote[2]; const quotenum = +quote[2];
if (postThreadIdMap[quoteboard] && postThreadIdMap[quoteboard][quotenum]) { if (postThreadIdMap[quoteboard] && postThreadIdMap[quoteboard][quotenum]) {
return `<a class='quote' href='/${quoteboard}/thread/${postThreadIdMap[quoteboard][quotenum]}.html#${quotenum}'>&gt;&gt;&gt;/${quoteboard}/${quotenum}</a>`; return `<a class='quote' href='/${quoteboard}/thread/${postThreadIdMap[quoteboard][quotenum].thread}.html#${quotenum}'>&gt;&gt;&gt;/${quoteboard}/${quotenum}</a>`;
} else if (!quote[2]) { } else if (!quote[2]) {
return `<a class='quote' href='/${quoteboard}/index.html'>&gt;&gt;&gt;/${quoteboard}/</a>`; return `<a class='quote' href='/${quoteboard}/index.html'>&gt;&gt;&gt;/${quoteboard}/</a>`;
} }
@ -96,6 +105,6 @@ module.exports = async (board, text) => {
}); });
} }
return { quotedMessage: text, threadQuotes: [...new Set(threadQuotes)] }; return { quotedMessage: text, threadQuotes };
} }

@ -3,7 +3,7 @@
const uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js') const uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js')
, { remove } = require('fs-extra') , { remove } = require('fs-extra')
, Mongo = require(__dirname+'/../../db/db.js') , Mongo = require(__dirname+'/../../db/db.js')
, Posts = require(__dirname+'/../../db/posts.js'); , Posts = require(__dirname+'/../../db/posts.js')
module.exports = async (posts, board) => { 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 //combine them all into one array, there may be duplicates but it shouldnt matter
const allPosts = posts.concat(threadPosts); const allPosts = posts.concat(threadPosts);
//NOTE: this is where, when implemented, file ref counts would be decremented //get files for ref counting, backlinks for post re-markup, mongoids for deleting
//NOTE: this is where, when implemented, re-marking up posts that quoted deleted posts would be done const { postFiles, postBacklinks, postMongoIds } = allPosts.reduce((acc, post) => {
//could use a destructuring with Array.reduce when i need to get files array, backlinks array and mongoId array if (post.files.length > 0) {
//instead of doing 3 maps or big for loop 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); const deletedPosts = await Posts.deleteMany(postMongoIds).then(result => result.deletedCount);
//hooray! //hooray!

@ -9,7 +9,7 @@ module.exports = async (posts, unlinkOnly) => {
let fileNames = []; let fileNames = [];
posts.forEach(post => { posts.forEach(post => {
fileNames = fileNames.concat(post.files.map(x => x.filename)) fileNames = fileNames.concat(post.files.map(x => x.filename))
}) });
if (fileNames.length === 0) { if (fileNames.length === 0) {
return { return {
@ -18,6 +18,7 @@ module.exports = async (posts, unlinkOnly) => {
} }
if (unlinkOnly) { if (unlinkOnly) {
//TODO: decrement ref counters when implemented
return { return {
message:`Unlinked ${fileNames.length} file(s) across ${posts.length} post(s)`, message:`Unlinked ${fileNames.length} file(s) across ${posts.length} post(s)`,
action:'$set', action:'$set',
@ -39,5 +40,4 @@ module.exports = async (posts, unlinkOnly) => {
}; };
} }
} }

@ -225,7 +225,7 @@ module.exports = async (req, res, next) => {
let quotes = []; let quotes = [];
if (message && message.length > 0) { if (message && message.length > 0) {
message = simpleMarkdown(message); 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; message = quotedMessage;
quotes = threadQuotes; quotes = threadQuotes;
message = sanitize(message, sanitizeOptions); message = sanitize(message, sanitizeOptions);

@ -2,4 +2,4 @@ nav.navbar
a.nav-item(href='/') Home a.nav-item(href='/') Home
a.nav-item.right(href='/logout') Logout a.nav-item.right(href='/logout') Logout
a.nav-item.right(href=`/${board ? board._id+'/' : 'global'}manage.html`) Manage 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

@ -88,7 +88,7 @@ mixin post(post, truncate, manage=false, globalmanage=false)
if post.backlinks && post.backlinks.length > 0 if post.backlinks && post.backlinks.length > 0
.replies Replies: .replies Replies:
each backlink in post.backlinks each backlink in post.backlinks
a.quote(href=`/${post.board}/thread/${post.thread || post.postId}.html#${backlink}`) &gt;&gt;#{backlink} a.quote(href=`/${post.board}/thread/${post.thread || post.postId}.html#${backlink.postId}`) &gt;&gt;#{backlink.postId}
| |
if manage === true if manage === true
each report in post.reports each report in post.reports

@ -30,3 +30,5 @@ block content
iframe.captcha(src='/captcha.html' width=200 height=110 scrolling='no') 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#captcha(type='text', name='captcha', autocomplete='off' placeholder='captcha text' maxlength='6' required)
input(type='submit', value='Change Password') input(type='submit', value='Change Password')
p: a(href='/login.html') Login
p: a(href='/register.html') Register

@ -16,5 +16,6 @@ block content
.required * .required *
input#password(type='password', name='password', maxlength='100' required) input#password(type='password', name='password', maxlength='100' required)
input(type='submit', value='submit') 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

@ -26,4 +26,5 @@ block content
iframe.captcha(src='/captcha.html' width=200 height=110 scrolling='no') 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#captcha(type='text', name='captcha', autocomplete='off' placeholder='captcha text' maxlength='6' required)
input(type='submit', value='Register') 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

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const Mongo = require(__dirname+'/db/db.js') const Mongo = require(__dirname+'/db/db.js');
(async () => { (async () => {
console.log('connecting to db...') console.log('connecting to db...')
@ -16,13 +16,8 @@ const Mongo = require(__dirname+'/db/db.js')
console.log('deleting accounts') console.log('deleting accounts')
await Accounts.deleteAll(); await Accounts.deleteAll();
console.log('deleting posts') console.log('deleting posts')
await Posts.deleteAll('pol'); await Posts.deleteAll();
await Posts.deleteAll('b');
await Posts.deleteAll('t');
console.log('deleting boards') console.log('deleting boards')
await Boards.deleteIncrement('pol');
await Boards.deleteIncrement('b');
await Boards.deleteIncrement('t');
await Boards.deleteAll(); await Boards.deleteAll();
console.log('deleting bans'); console.log('deleting bans');
await Bans.deleteAll(); await Bans.deleteAll();
@ -164,7 +159,7 @@ const Mongo = require(__dirname+'/db/db.js')
}); });
console.log('creating admin account: admin:changeme'); console.log('creating admin account: admin:changeme');
await Accounts.insertOne('admin', 'changeme', 3); await Accounts.insertOne('admin', 'changeme', 3);
Mongo.client.close() Mongo.client.close();
console.log('done'); console.log('done');
process.exit(0); process.exit(0);
})(); })();

Loading…
Cancel
Save