diff --git a/configs/main.js.example b/configs/main.js.example index 225db252..b8d43514 100644 --- a/configs/main.js.example +++ b/configs/main.js.example @@ -316,10 +316,13 @@ module.exports = { unlistedLocal: false, //board hidden from on-site board list and frontpage unlistedWebring: false, //board hidden from webring captchaMode: 0, //0=disabled, 1=for threads, 2=for all posts - tphTrigger: 0, //numebr of threads in an hour before trigger action is activated - pphTrigger: 0, //number of posts in an hour before ^ - triggerAction: 0, //0=nothing, 1=captcha enable for threads, 2=captcha enable for all posts, 3=lock board - resetTrigger: false, //reset captcha/lock settings back to original at the end of hour + tphTrigger: 10, //numebr of threads in an hour before trigger action is activated + pphTrigger: 50, //number of posts in an hour before ^ + //0=none, 1=captcha enable for threads, 2=captcha enable for all posts, 3=lock board + tphTriggerAction: 1, + pphTriggerAction: 2, + captchaReset: 0, + lockReset: 0, forceAnon: false, //disable name and subject, only allow sage email sageOnlyEmail: false, //only allow sage email early404: true, //delete threads beyond the first 1/3 of pages with less than 5 replies diff --git a/controllers/forms/boardsettings.js b/controllers/forms/boardsettings.js index a92e403a..3c9b0f3b 100644 --- a/controllers/forms/boardsettings.js +++ b/controllers/forms/boardsettings.js @@ -111,12 +111,6 @@ module.exports = async (req, res, next) => { if (typeof req.body.captcha_mode === 'number' && (req.body.captcha_mode < 0 || req.body.captcha_mode > 2)) { errors.push('Invalid captcha mode'); } - if (typeof req.body.tph_trigger === 'number' && (req.body.tph_trigger < 0 || req.body.tph_trigger > 10000)) { - errors.push('Invalid tph trigger threshold'); - } - if (typeof req.body.tph_trigger_action === 'number' && (req.body.tph_trigger_action < 0 || req.body.tph_trigger_action > 4)) { - errors.push('Invalid tph trigger action'); - } if (typeof req.body.filter_mode === 'number' && (req.body.filter_mode < 0 || req.body.filter_mode > 2)) { errors.push('Invalid filter mode'); } @@ -130,6 +124,25 @@ module.exports = async (req, res, next) => { errors.push('Invalid code theme'); } + if (typeof req.body.tph_trigger === 'number' && (req.body.tph_trigger < 0 || req.body.tph_trigger > 10000)) { + errors.push('Invalid tph trigger threshold'); + } + if (typeof req.body.tph_trigger_action === 'number' && (req.body.tph_trigger_action < 0 || req.body.tph_trigger_action > 4)) { + errors.push('Invalid tph trigger action'); + } + if (typeof req.body.pph_trigger === 'number' && (req.body.pph_trigger < 0 || req.body.pph_trigger > 10000)) { + errors.push('Invalid pph trigger threshold'); + } + if (typeof req.body.pph_trigger_action === 'number' && (req.body.pph_trigger_action < 0 || req.body.pph_trigger_action > 4)) { + errors.push('Invalid pph trigger action'); + } + if (typeof req.body.lock_reset === 'number' && (req.body.lock_reset < 0 || req.body.lock_reset > 2)) { + errors.push('Invalid trigger reset lock'); + } + if (typeof req.body.captcha_reset === 'number' && (req.body.captcha_reset < 0 || req.body.captcha_reset > 2)) { + errors.push('Invalid trigger reset captcha'); + } + if (errors.length > 0) { return dynamicResponse(req, res, 400, 'message', { 'title': 'Bad request', diff --git a/db/boards.js b/db/boards.js index 0505182f..eaa0ca51 100644 --- a/db/boards.js +++ b/db/boards.js @@ -291,15 +291,11 @@ module.exports = { }, { '$project': { '_id': 1, - 'lockMode': { - 'new': '$settings.lockMode', - 'old': '$preTriggerMode.lockMode' - }, - 'captchaMode': { - 'new': '$settings.captchaMode', - 'old': '$preTriggerMode.captchaMode' - }, - 'threadLimit': '$settings.threadLimit' + 'lockMode': '$settings.lockMode', + 'lockReset': '$settings.lockReset', + 'captchaMode': '$settings.captchaMode', + 'captchaReset': '$settings.captchaReset', + 'threadLimit': '$settings.threadLimit', } } ]).toArray(); diff --git a/helpers/paramconverter.js b/helpers/paramconverter.js index 0980bcdb..2ec08b88 100644 --- a/helpers/paramconverter.js +++ b/helpers/paramconverter.js @@ -5,7 +5,8 @@ const { ObjectId } = require(__dirname+'/../db/db.js') 'checkedreports', 'checkedbans', 'checkedbanners', 'checkedaccounts', 'countries']) //only these should be arrays, since express bodyparser can output arrays , trimFields = ['tags', 'uri', 'moderators', 'filters', 'announcement', 'description', 'message', 'name', 'subject', 'email', 'postpassword', 'password', 'default_name', 'report_reason', 'ban_reason', 'log_message', 'custom_css'] //trim if we dont want filed with whitespace - , numberFields = ['filter_mode', 'lock_mode', 'message_r9k_mode', 'file_r9k_mode', 'captcha_mode', 'tph_trigger', 'pph_trigger', 'trigger_action', 'bump_limit', 'reply_limit', 'move_to_thread',, 'postId', + , numberFields = ['lock_reset', 'captcha_reset', 'filter_mode', 'lock_mode', 'message_r9k_mode', 'file_r9k_mode', 'captcha_mode', + 'tph_trigger', 'pph_trigger', 'pph_trigger_action', 'tph_trigger_action', 'bump_limit', 'reply_limit', 'move_to_thread', 'postId', 'max_files', 'thread_limit', 'thread', 'max_thread_message_length', 'max_reply_message_length', 'min_thread_message_length', 'min_reply_message_length', 'auth_level'] //convert these to numbers before they hit our routes , banDurationRegex = /^(?[\d]+y)?(?[\d]+mo)?(?[\d]+w)?(?[\d]+d)?(?[\d]+h)?(?[\d]+m)?(?[\d]+s)?$/ , timeUtils = require(__dirname+'/timeutils.js') diff --git a/helpers/tasks.js b/helpers/tasks.js index ef150fa9..b2d03825 100644 --- a/helpers/tasks.js +++ b/helpers/tasks.js @@ -236,6 +236,7 @@ module.exports = { if (triggeredBoards.length === 0) { return; //no label is no triggers } +//console.log(triggeredBoards); await cache.del('triggered'); const triggerModes = await Boards.triggerModes(triggeredBoards); const bulkWrites = triggerModes.map(p => { @@ -246,22 +247,26 @@ module.exports = { }, 'update': { '$set': { - 'settings.lockMode': p.lockMode.old, - 'settings.captchaMode': p.captchaMode.old + /* reset=0 is "no change", the options go from 0-2, and get reset to 0 or 1, + so if >0, we subtract 1 otherwise no change */ + 'settings.lockMode': (p.lockReset > 0 ? p.lockReset-1 : p.lockMode), + 'settings.captchaMode': (p.captchaReset > 0 ? p.captchaReset-1 : p.captchaMode), } } } } - }) + }); +//console.log(bulkWrites); await Boards.db.bulkWrite(bulkWrites); const promises = []; triggerModes.forEach(async (p) => { await cache.del(`board:${p._id}`); - if (p.captchaMode.old < p.captchaMode.new) { - if (p.captchaMode.old === 2) { +//console.log(p, p.captchaReset > 0 && p.captchaReset-1 < p.captchaMode); + if (p.captchaReset > 0 && p.captchaReset-1 < p.captchaMode) { + if (p.captchaReset-1 <= 1) { promises.push(remove(`${uploadDirectory}/html/${p._id}/thread/`)); } - if (p.captchaMode.old === 0) { + if (p.captchaReset-1 === 0) { buildQueue.push({ 'task': 'buildBoardMultiple', 'options': { @@ -282,7 +287,6 @@ module.exports = { await Promise.all(promises); const end = process.hrtime(start); debugLogs && console.log(timeDiffString(label, end)); - }, buildChangePassword: async () => { diff --git a/migrations/index.js b/migrations/index.js index 5f41c8cb..4e052b4e 100644 --- a/migrations/index.js +++ b/migrations/index.js @@ -16,4 +16,5 @@ module.exports = { '0.0.13': require(__dirname+'/migration-0.0.13.js'), //add r9k mode (files) '0.0.14': require(__dirname+'/migration-0.0.14.js'), //add option for disable .onion file posts to board settings '0.0.15': require(__dirname+'/migration-0.0.15.js'), //messages r9k option + '0.0.16': require(__dirname+'/migration-0.0.16.js'), //separate tph/pph triggers } diff --git a/migrations/migration-0.0.16.js b/migrations/migration-0.0.16.js new file mode 100644 index 00000000..e61b00ba --- /dev/null +++ b/migrations/migration-0.0.16.js @@ -0,0 +1,25 @@ +'use strict'; + +module.exports = async(db, redis) => { + console.log('Allow tph/pph separate triggers and resets'); + await db.collection('boards').updateMany({}, { + '$rename': { + 'settings.triggerAction' : 'settings.pphTriggerAction', + } + }); + await db.collection('boards').updateMany({}, { + '$unset': { + 'settings.resetTrigger' : '', + 'preTriggerMode': '', + } + }); + await db.collection('boards').updateMany({}, { + '$set': { + 'settings.tphTriggerAction' : 0, + 'settings.captchaReset' : 0, + 'settings.lockReset' : 0, + } + }); + console.log('Cleared boards cache'); + await redis.deletePattern('board:*'); +}; diff --git a/models/forms/changeboardsettings.js b/models/forms/changeboardsettings.js index cac5b3ce..a7e57b74 100644 --- a/models/forms/changeboardsettings.js +++ b/models/forms/changeboardsettings.js @@ -93,11 +93,13 @@ module.exports = async (req, res, next) => { 'forceReplyFile': booleanSetting(req.body.force_reply_file), 'forceThreadSubject': booleanSetting(req.body.force_thread_subject), 'disableReplySubject': booleanSetting(req.body.disable_reply_subject), - 'resetTrigger': booleanSetting(req.body.reset_trigger), 'captchaMode': numberSetting(req.body.captcha_mode, oldSettings.captchaMode), 'tphTrigger': numberSetting(req.body.tph_trigger, oldSettings.tphTrigger), + 'tphTriggerAction': numberSetting(req.body.tph_trigger_action, oldSettings.tphTriggerAction), 'pphTrigger': numberSetting(req.body.pph_trigger, oldSettings.pphTrigger), - 'triggerAction': numberSetting(req.body.trigger_action, oldSettings.triggerAction), + 'pphTriggerAction': numberSetting(req.body.pph_trigger_action, oldSettings.pphTriggerAction), + 'captchaReset': numberSetting(req.body.captcha_reset, oldSettings.captchaReset), + 'lockReset': numberSetting(req.body.lock_reset, oldSettings.lockReset), 'threadLimit': numberSetting(req.body.thread_limit, oldSettings.threadLimit), 'replyLimit': numberSetting(req.body.reply_limit, oldSettings.replyLimit), 'bumpLimit': numberSetting(req.body.bump_limit, oldSettings.bumpLimit), @@ -134,10 +136,6 @@ module.exports = async (req, res, next) => { await Boards.updateOne(req.params.board, { '$set': { 'settings': newSettings, - 'preTriggerMode': { - 'lockMode': newSettings.lockMode, - 'captchaMode': newSettings.captchaMode - } } }); diff --git a/models/forms/makepost.js b/models/forms/makepost.js index ad5805de..b2cbdfb6 100644 --- a/models/forms/makepost.js +++ b/models/forms/makepost.js @@ -47,9 +47,9 @@ module.exports = async (req, res, next) => { let redirect = `/${req.params.board}/` let salt = null; let thread = null; - const { filterBanDuration, filterMode, filters, blockedCountries, resetTrigger, + const { filterBanDuration, filterMode, filters, blockedCountries, threadLimit, ids, userPostSpoiler, + lockReset, captchaReset, pphTrigger, tphTrigger, tphTriggerAction, pphTriggerAction, maxFiles, sageOnlyEmail, forceAnon, replyLimit, disableReplySubject, - threadLimit, ids, userPostSpoiler, pphTrigger, tphTrigger, triggerAction, captchaMode, lockMode, allowedFileTypes, flags, fileR9KMode, messageR9KMode } = res.locals.board.settings; if (res.locals.permLevel >= 4 && res.locals.country @@ -463,41 +463,42 @@ module.exports = async (req, res, next) => { const postId = await Posts.insertOne(res.locals.board, data, thread); - let enableCaptcha = false; - if (triggerAction > 0 //if trigger is enabled - && (tphTrigger > 0 || pphTrigger > 0) //and has a threshold > 0 - && ((triggerAction < 3 && captchaMode < triggerAction) //and its triggering captcha and captcha isnt on - || (triggerAction === 3 && lockMode < 1) //or triggering locking and board isnt locked - || (triggerAction === 4 && lockMode < 2))) { - //read stats to check number threads in past hour - const hourPosts = await Stats.getHourPosts(res.locals.board._id); - if (hourPosts //if stats exist for this hour and its above either trigger - && (tphTrigger > 0 && hourPosts.tph >= tphTrigger) - || (pphTrigger > 0 && hourPosts.pph > pphTrigger)) { - //update in memory for other stuff done e.g. rebuilds - const update = { - '$set': { - 'preTriggerMode': { - lockMode, - captchaMode + let enableCaptcha = false; //make this returned from some function, refactor and move the next section to another file + const pphTriggerActive = (pphTriggerAction > 0 && pphTrigger > 0); + const tphTriggerActive = (tphTriggerAction > 0 && tphTrigger > 0); + if (pphTriggerAction || tphTriggerActive) { //if a trigger is enabled + const triggerUpdate = { + '$set': {}, + }; + //and a setting needs to be updated + const pphTriggerUpdate = (pphTriggerAction < 3 && captchaMode < pphTriggerAction) + || (pphTriggerAction === 3 && lockMode < 1) + || (pphTriggerAction === 4 && lockMode < 2); + const tphTriggerUpdate = (tphTriggerAction < 3 && captchaMode < tphTriggerAction) + || (tphTriggerAction === 3 && lockMode < 1) + || (tphTriggerAction === 4 && lockMode < 2); + if (tphTriggerUpdate || pphTriggerUpdate) { + const hourPosts = await Stats.getHourPosts(res.locals.board._id); + const calcTriggerMode = (update, trigger, triggerAction, stat) => { //todo: move this somewhere else + if (trigger > 0 && stat >= trigger) { + //update in memory for other stuff done e.g. rebuilds + if (triggerAction < 3) { + res.locals.board.settings.captchaMode = triggerAction; + update['$set']['settings.captchaMode'] = triggerAction; + enableCaptcha = true; //todo make this also returned after moving/refactoring this + } else { + res.locals.board.settings.lockMode = triggerAction-2; + update['$set']['settings.lockMode'] = triggerAction-2; } + return true; } - }; - if (triggerAction < 3) { - res.locals.board.settings.captchaMode = triggerAction; - update['$set']['settings.captchaMode'] = triggerAction; - enableCaptcha = true; - } else if (triggerAction === 3) { - res.locals.board.settings.lockMode = 1; - update['$set']['settings.lockMode'] = 1; - } else if (triggerAction === 4) { - res.locals.board.settings.lockMode = 2; - update['$set']['settings.lockMode'] = 2; + return false; } - //set it in the db - await Boards.updateOne(res.locals.board._id, update); - if (resetTrigger) { - //mark the board as being triggered so we can return it to old mode after on schedule + const updatedPphTrigger = pphTriggerUpdate && calcTriggerMode(triggerUpdate, pphTrigger, pphTriggerAction, hourPosts.pph); + const updatedTphTrigger = tphTriggerUpdate && calcTriggerMode(triggerUpdate, tphTrigger, tphTriggerAction, hourPosts.tph); + if (updatedPphTrigger || updatedTphTrigger) { + //set it in the db + await Boards.updateOne(res.locals.board._id, triggerUpdate); await cache.sadd('triggered', res.locals.board._id); } } diff --git a/package.json b/package.json index 5a87e774..4ed1c71e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jschan", "version": "0.0.1", - "migrateVersion": "0.0.15", + "migrateVersion": "0.0.16", "description": "", "main": "server.js", "dependencies": { diff --git a/views/pages/managesettings.pug b/views/pages/managesettings.pug index f246bf39..0904c2ec 100644 --- a/views/pages/managesettings.pug +++ b/views/pages/managesettings.pug @@ -206,24 +206,40 @@ block content option(value='0', selected=board.settings.captchaMode === 0) No Captcha option(value='1', selected=board.settings.captchaMode === 1) Captcha for new thread option(value='2', selected=board.settings.captchaMode === 2) Captcha for all posts - .row - .label TPH Trigger Threshold - input(type='number', name='tph_trigger', value=board.settings.tphTrigger) .row .label PPH Trigger Threshold input(type='number', name='pph_trigger', value=board.settings.pphTrigger) .row - .label TPH/PPH Trigger Action - select(name='trigger_action') - option(value='0', selected=board.settings.triggerAction === 0) Do nothing - option(value='1', selected=board.settings.triggerAction === 1) Enable captcha for new thread - option(value='2', selected=board.settings.triggerAction === 2) Enable captcha for all posts - option(value='3', selected=board.settings.triggerAction === 3) Lock thread creation - option(value='4', selected=board.settings.triggerAction === 4) Lock board + .label PPH Trigger Action + select(name='pph_trigger_action') + option(value='0', selected=board.settings.pphTriggerAction === 0) Do nothing + option(value='1', selected=board.settings.pphTriggerAction === 1) Enable captcha for new thread + option(value='2', selected=board.settings.pphTriggerAction === 2) Enable captcha for all posts + option(value='3', selected=board.settings.pphTriggerAction === 3) Lock thread creation + option(value='4', selected=board.settings.pphTriggerAction === 4) Lock board .row - .label Auto Reset Trigger - label.postform-style.ph-5 - input(type='checkbox', name='reset_trigger', value='true' checked=board.settings.resetTrigger) + .label TPH Trigger Threshold + input(type='number', name='tph_trigger', value=board.settings.tphTrigger) + .row + .label TPH Trigger Action + select(name='tph_trigger_action') + option(value='0', selected=board.settings.tphTriggerAction === 0) Do nothing + option(value='1', selected=board.settings.tphTriggerAction === 1) Enable captcha for new thread + option(value='2', selected=board.settings.tphTriggerAction === 2) Enable captcha for all posts + option(value='3', selected=board.settings.tphTriggerAction === 3) Lock thread creation + option(value='4', selected=board.settings.tphTriggerAction === 4) Lock board + .row + .label Trigger Reset Lock Mode + select(name='lock_reset') + option(value='0', selected=board.settings.lockReset === 0) No change + option(value='1', selected=board.settings.lockReset === 1) Unlock board + option(value='2', selected=board.settings.lockReset === 2) Lock thread creation + .row + .label Trigger Reset Captcha Mode + select(name='captcha_reset') + option(value='0', selected=board.settings.captchaReset === 0) No change + option(value='1', selected=board.settings.captchaReset === 1) Captcha disbaled + option(value='2', selected=board.settings.captchaReset === 2) Captcha for new thread .row .label Early 404 label.postform-style.ph-5