Merge branch 'trigger-changes' into new-dev

merge-requests/208/head
Thomas Lynch 4 years ago
commit ed58cf371e
  1. 12
      configs/main.js.example
  2. 25
      controllers/forms/boardsettings.js
  3. 14
      db/boards.js
  4. 3
      helpers/paramconverter.js
  5. 15
      helpers/tasks.js
  6. 1
      migrations/index.js
  7. 25
      migrations/migration-0.0.16.js
  8. 10
      models/forms/changeboardsettings.js
  9. 69
      models/forms/makepost.js
  10. 2
      package.json
  11. 42
      views/pages/managesettings.pug

@ -320,10 +320,14 @@ 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,
//0=dont change, 1=unlock board/disable captcha, 2=lock thread creation/enable captcha for thread creation
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

@ -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',

@ -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();

@ -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 = /^(?<YEAR>[\d]+y)?(?<MONTH>[\d]+mo)?(?<WEEK>[\d]+w)?(?<DAY>[\d]+d)?(?<HOUR>[\d]+h)?(?<MINUTE>[\d]+m)?(?<SECOND>[\d]+s)?$/
, timeUtils = require(__dirname+'/timeutils.js')

@ -246,22 +246,24 @@ 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 ? Math.min(p.lockReset-1, p.lockMode) : p.lockMode),
'settings.captchaMode': (p.captchaReset > 0 ? Math.min(p.captchaReset-1, p.captchaMode) : p.captchaMode),
}
}
}
}
})
});
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) {
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 +284,6 @@ module.exports = {
await Promise.all(promises);
const end = process.hrtime(start);
debugLogs && console.log(timeDiffString(label, end));
},
buildChangePassword: async () => {

@ -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
}

@ -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:*');
};

@ -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
}
}
});

@ -49,9 +49,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
@ -479,41 +479,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);
}
}

@ -1,7 +1,7 @@
{
"name": "jschan",
"version": "0.0.1",
"migrateVersion": "0.0.15",
"migrateVersion": "0.0.16",
"description": "",
"main": "server.js",
"dependencies": {

@ -215,24 +215,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 disabled
option(value='2', selected=board.settings.captchaReset === 2) Captcha for new thread
.row
.label Early 404
label.postform-style.ph-5

Loading…
Cancel
Save