mirror of https://gitgud.io/fatchan/jschan.git
ref #377, the fun begins
still a few things to do, see TODO (heh) mostly working how i imagined, with a few quirks. pretty happy with it.merge-requests/341/head
parent
0b01673e06
commit
d1f9c78258
136 changed files with 2255 additions and 1043 deletions
@ -0,0 +1,59 @@ |
||||
RANDOM SHIT DISREGARD |
||||
- [x] permission checks in helpers/checks/actionchecker.js |
||||
- [x] permission bypasses in helpers/schema.js, and edit controllers schema check perm levels to new Permissions.XXX |
||||
- [x] helpers/posting/markdown.js markdown permission levels, and in binded custom callback markdowns like diceroll, linkmatch, etc |
||||
- [x] remove permLevels, permLevels.markdown, the global settings for it, the controller code for checking it, and put a bit of the template into the migrations |
||||
- [x] helpers/decodequeryip.js for ip query decoding, and handle the iphashpermlevel stuff |
||||
- [x] make sure a valid permission always passed to markdown. make note about bug for moving, and permission on other posts when getting remarked. |
||||
- [x] helpers/posting/message.js, argument permlevel, and passing to markdown function (and other places like editing and moving!) |
||||
- [x] helpers/checks/spamcheck.js, for BYPASS_SPAMCHECKS |
||||
- [x] helpers/checks/bancheck.js, for BYPASS_BANS or BOARD_MANAGE_OWNER/GENERAL, for board bans |
||||
- [x] helpers/checks/calcpermsmiddleware.js, make it return the Permission instance, not return and set res.locals.permLevel |
||||
- [x] remove ipHashPermLevel, use the permission. remove from template.js, globalmanage, controller, etc |
||||
- [x] remove permLevel bypass in imagehash helper |
||||
- [x] helpers/posting/name.js, to emulate old "levels" for capcodes |
||||
- [x] per-board permissions page, to show a users permissions |
||||
- [x] global permissions page /permissions.html |
||||
- [x] remove authLevel from models/pages/account.js |
||||
- [x] update account.html, to show only the pages you are able to access in the quick links |
||||
- [x] redo whole permissions check in socketio.js, to use calcPerms (and hasPerms? or a separate check) |
||||
- [x] fix permissions check in views/mixins/managenav.pug, and make it all more like account.pug |
||||
- [x] remove unnecessary board_owner check in page controllers, since they inherit all othe board perms |
||||
- [x] link in board staff table, by clicking aand "edit" of the permission base64, to /board/manage/editstaff/username.html, |
||||
- [x] remove permissions fluff from FAQ, that shit doesnt need to be there |
||||
- [x] rename addModBoard removeModBoard, getOwnedOrModBoards, modBoards, rename mod to "staff" |
||||
- [x] db migration, modBoards to staffBoards |
||||
- [x] create db/boards addStaff method, unused yet, |
||||
- [x] update removeStaffBoard to handle staff object instead of moderators, change those db methods to be called "staff" not "moderators" |
||||
- [x] change board "moderators" array, rename "staff" and make it a map of {username:{permissions, dateAdded, etc}} |
||||
- [x] add forms to add and delete staff from a board, using new staff methods in db/boards and db/accounts |
||||
- [x] add new page /board/manage/editstaff/username.html accessible with MANAGE_BOARD_STAFF, showing the permissions for that user ON THAT BOARD (the board_ stuff only basically) |
||||
- [x] link in accounts table, by clicking and "edit" of the permission base64, to /globalmanage/editpermissions/account_id.html, |
||||
- [x] add permisions default template to newly created accounts under permissions. |
||||
- [x] finally remove authLevel from helpers/checks/calcperms.js once the data is in the db |
||||
- [x] update setting authLevel in db/accounts.js, since it should just be permissions data now |
||||
- [x] add permtemplates to accounts with migration, based on authlevel, then UNSET auth level |
||||
- [x] remove deleteBoardsPermLevel, use ther permission (permissions already checked on the endpoint, so remove from template.js, globalmanage, controller, etc |
||||
- [x] remove authLevelNames |
||||
- [x] controllers/forms/editstaff.js models/forms/editstaff.js |
||||
- [x] fix inheriting board staff perms in calcperms |
||||
- [x] adapt controllers/forms/editaccount.js models/forms/editaccount.js to ACCOUNTS, instead of STAFF! |
||||
- [x] do another grep for permLevel and authLevel, userBoardCreation, userAccountCreation, ipHashPermLevel, etc |
||||
- [x] add new setting "dont store raw ips" instead of based on "-1" ipHashPermLevel which is now removed. |
||||
- [x] remove "allow user board creation" and "allow user account creation" in global settings, since it should be part of editing the default/anon users permission template |
||||
- [x] make sure staff/acount adding and removing stays consistent |
||||
- [x] change bunch permLevel comparisons, esp in models/forms/makepost. to use the perms, or just a combo of some perm like manage_board_general/manage_global_general |
||||
- [x] finish migration |
||||
- [x] get permissions for multiple boards in account page, to show the proper links for staff and all the links can be available in "boards you own" vs "moderate", depending on their staff permissions |
||||
- [x] add some "edit" link and edit account "upgrade"-type buttons, like the local->global post history links (where permssions allow) |
||||
- [x] add some "friendly" permission names and descriptions for permissions.toJSON, mostly for frontend, and will be good for translation later |
||||
- [x] make permission class better, static allPermissions and permissionEntries |
||||
- [x] make BOs show up properly in edit staff, controller check to prevent editing them |
||||
- [~] make at least the ANON template editable with MANAGE_GLOBAL_ACCOUNTS. can store in globalsettings for now, since there are only the default 5 (for now) |
||||
- [~] implement showing "template name" or "custom", based on id a permission is one of the templates or not |
||||
- [ ] update nginx config |
||||
Improvements for later |
||||
- [ ] update jschan-docs. add a section about accounts, staff and permissions. |
||||
- [ ] !!explore options for permission changes applying to users when a template is updated. e.g. change the anon template to add the CREATE_BOARD, but an existing user (who does not have this permission) doesnt get it added to their account. I think use mongo $bitsAllSet+$bitsAllClear works for this (since the binary is stored), and then set the new permission binary. for missing ADDED permissions, inheriting from anon could be a good interim solution, but needs to be properly changed to handle the inverse properly. |
||||
- [ ] permission editing page to mass update or apply a change to multiple users just for specific permissions, not a full overwrite. maybe a page with options "dont change, set to false, set to true"? |
||||
- [ ] full on ability to add custom templates for roles, and |
@ -0,0 +1,48 @@ |
||||
'use strict'; |
||||
|
||||
const addStaff = require(__dirname+'/../../models/forms/addstaff.js') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, config = require(__dirname+'/../../config.js') |
||||
, { Accounts } = require(__dirname+'/../../db/') |
||||
, paramConverter = require(__dirname+'/../../helpers/paramconverter.js') |
||||
, { checkSchema, lengthBody, numberBody, minmaxBody, numberBodyVariable, |
||||
inArrayBody, arrayInBody, existsBody } = require(__dirname+'/../../helpers/schema.js'); |
||||
|
||||
module.exports = { |
||||
|
||||
paramConverter: paramConverter({ |
||||
trimFields: ['username'], |
||||
}), |
||||
|
||||
controller: async (req, res, next) => { |
||||
|
||||
const { globalLimits } = config.get; |
||||
|
||||
const errors = await checkSchema([ |
||||
{ result: existsBody(req.body.username), expected: true, error: 'Missing staff username' }, |
||||
{ result: lengthBody(req.body.username, 0, 50), expected: false, error: 'Username must be 50 characters or less' }, |
||||
{ result: (res.locals.board.owner === req.body.username), expected: false, blocking: true, error: 'User is already board owner' }, |
||||
{ result: (res.locals.board.staff[req.body.username] != null), expected: false, blocking: true, error: 'User is already staff' }, |
||||
{ result: async () => { |
||||
const numAccounts = await Accounts.countUsers([req.body.username]); |
||||
return numAccounts > 0; |
||||
}, expected: true, error: 'User does not exist' }, |
||||
]); |
||||
|
||||
if (errors.length > 0) { |
||||
return dynamicResponse(req, res, 400, 'message', { |
||||
'title': 'Bad request', |
||||
'errors': errors, |
||||
'redirect': req.headers.referer || `/${req.params.board}/manage/staff.html`, |
||||
}); |
||||
} |
||||
|
||||
try { |
||||
await addStaff(req, res, next); |
||||
} catch (err) { |
||||
return next(err); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,40 @@ |
||||
'use strict'; |
||||
|
||||
const deleteStaff = require(__dirname+'/../../models/forms/deletestaff.js') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, paramConverter = require(__dirname+'/../../helpers/paramconverter.js') |
||||
, { checkSchema, lengthBody, numberBody, minmaxBody, numberBodyVariable, |
||||
inArrayBody, arrayInBody, existsBody } = require(__dirname+'/../../helpers/schema.js'); |
||||
|
||||
module.exports = { |
||||
|
||||
paramConverter: paramConverter({ |
||||
allowedArrays: ['checkedstaff'], |
||||
}), |
||||
|
||||
controller: async (req, res, next) => { |
||||
|
||||
const errors = await checkSchema([ |
||||
{ result: lengthBody(req.body.checkedstaff, 1), expected: false, error: 'Must select at least one staff to delete' }, |
||||
{ result: existsBody(req.body.checkedstaff) && req.body.checkedstaff.some(s => !res.locals.board.staff[s]), expected: false, error: 'Invalid staff selection' }, |
||||
//not really necessary, but its a bit retarded to "delete yourself" as staff this way
|
||||
{ result: existsBody(req.body.checkedstaff) && req.body.checkedstaff.some(s => s === res.locals.user.username), expected: false, error: 'Resign from the accounts page instead' }, |
||||
]); |
||||
|
||||
if (errors.length > 0) { |
||||
return dynamicResponse(req, res, 400, 'message', { |
||||
'title': 'Bad request', |
||||
'errors': errors, |
||||
'redirect': req.headers.referer || `/${req.params.board}/manage/staff.html`, |
||||
}) |
||||
} |
||||
|
||||
try { |
||||
await deleteStaff(req, res, next); |
||||
} catch (err) { |
||||
return next(err); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,47 @@ |
||||
'use strict'; |
||||
|
||||
const editAccount = require(__dirname+'/../../models/forms/editaccount.js') |
||||
, { Accounts } = require(__dirname+'/../../db/') |
||||
, alphaNumericRegex = require(__dirname+'/../../helpers/checks/alphanumregex.js') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, paramConverter = require(__dirname+'/../../helpers/paramconverter.js') |
||||
, Permissions = require(__dirname+'/../../helpers/permissions.js') |
||||
, { checkSchema, lengthBody, numberBody, minmaxBody, numberBodyVariable, |
||||
inArrayBody, arrayInBody, existsBody } = require(__dirname+'/../../helpers/schema.js'); |
||||
|
||||
module.exports = { |
||||
|
||||
paramConverter: paramConverter({ |
||||
trimFields: ['username'], |
||||
}), |
||||
|
||||
controller: async (req, res, next) => { |
||||
|
||||
const errors = await checkSchema([ |
||||
{ result: existsBody(req.body.username), expected: true, error: 'Missing username' }, |
||||
{ result: lengthBody(req.body.username, 1, 50), expected: false, error: 'Username must be 50 characters or less' }, |
||||
{ result: alphaNumericRegex.test(req.body.username), expected: true, error: 'Username must contain a-z 0-9 only' }, |
||||
{ result: async () => { |
||||
res.locals.editingAccount = await Accounts.findOne(req.body.username); |
||||
return res.locals.editingAccount != null; |
||||
}, expected: true, error: 'Invalid account username' }, |
||||
{ result: (res.locals.user.username === req.body.username), expected: false, error: "You can't edit your own permissions" }, |
||||
]); |
||||
|
||||
if (errors.length > 0) { |
||||
return dynamicResponse(req, res, 400, 'message', { |
||||
'title': 'Bad request', |
||||
'errors': errors, |
||||
'redirect': req.headers.referer || `/${req.params.board}/manage/staff.html`, |
||||
}); |
||||
} |
||||
|
||||
try { |
||||
await editAccount(req, res, next); |
||||
} catch (err) { |
||||
return next(err); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,45 @@ |
||||
'use strict'; |
||||
|
||||
const editStaff = require(__dirname+'/../../models/forms/editstaff.js') |
||||
, { Accounts } = require(__dirname+'/../../db/') |
||||
, alphaNumericRegex = require(__dirname+'/../../helpers/checks/alphanumregex.js') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, paramConverter = require(__dirname+'/../../helpers/paramconverter.js') |
||||
, Permissions = require(__dirname+'/../../helpers/permissions.js') |
||||
, { checkSchema, lengthBody, numberBody, minmaxBody, numberBodyVariable, |
||||
inArrayBody, arrayInBody, existsBody } = require(__dirname+'/../../helpers/schema.js'); |
||||
|
||||
module.exports = { |
||||
|
||||
paramConverter: paramConverter({ |
||||
trimFields: ['username'], |
||||
}), |
||||
|
||||
controller: async (req, res, next) => { |
||||
|
||||
const errors = await checkSchema([ |
||||
{ result: existsBody(req.body.username), expected: true, error: 'Missing username' }, |
||||
{ result: lengthBody(req.body.username, 1, 50), expected: false, error: 'Username must be 50 characters or less' }, |
||||
{ result: alphaNumericRegex.test(req.body.username), expected: true, error: 'Username must contain a-z 0-9 only' }, |
||||
{ result: (res.locals.board.staff[req.body.username] != null), expected: true, error: 'Invalid staff username' }, |
||||
{ result: (req.body.username === res.locals.board.owner), expected: false, error: "You can't edit the permissions of the board owner" }, |
||||
{ result: (res.locals.user.username === req.body.username), expected: false, error: "You can't edit your own permissions" }, |
||||
]); |
||||
|
||||
if (errors.length > 0) { |
||||
return dynamicResponse(req, res, 400, 'message', { |
||||
'title': 'Bad request', |
||||
'errors': errors, |
||||
'redirect': req.headers.referer || `/${req.params.board}/manage/staff.html`, |
||||
}); |
||||
} |
||||
|
||||
try { |
||||
await editStaff(req, res, next); |
||||
} catch (err) { |
||||
return next(err); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -1,26 +1,34 @@ |
||||
'use strict'; |
||||
|
||||
const { Bans } = require(__dirname+'/../../db/') |
||||
, hasPerms = require(__dirname+'/hasperms.js') |
||||
, dynamicResponse = require(__dirname+'/../dynamic.js'); |
||||
, dynamicResponse = require(__dirname+'/../dynamic.js') |
||||
, Permissions = require(__dirname+'/../permissions.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
if (res.locals.permLevel > 1) {//global staff or admin bypass
|
||||
const bans = await Bans.find(res.locals.ip, res.locals.board ? res.locals.board._id : null); |
||||
if (bans && bans.length > 0) { |
||||
const globalBans = bans.filter(ban => { return ban.board === null }); |
||||
if (globalBans.length > 0 || (res.locals.permLevel >= 4 && globalBans.length !== bans.length)) { |
||||
//board staff bypass bans on their own board, but not global bans
|
||||
const unseenBans = bans.filter(b => !b.seen).map(b => b._id); |
||||
await Bans.markSeen(unseenBans); //mark bans as seen
|
||||
bans.forEach(ban => ban.seen = true); //mark seen as true in memory for user viewed ban page
|
||||
return res.status(403).render('ban', { |
||||
bans: bans, |
||||
}); |
||||
} |
||||
} |
||||
//bypass all bans, special permission
|
||||
if (res.locals.permissions.get(Permissions.BYPASS_BANS)) { |
||||
return next(); |
||||
} |
||||
next(); |
||||
|
||||
//fetch bans
|
||||
const banBoard = res.locals.board ? res.locals.board._id : null; //if no board, global bans or "null" board.
|
||||
let bans = await Bans.find(res.locals.ip, banBoard); |
||||
//board staff still bypass bans on their board by default
|
||||
if (res.locals.permissions.get(Permissions.MANAGE_BOARD_GENERAL)) { |
||||
//filter bans to leave only global bans remaining
|
||||
bans = bans.filter(ban => ban.board !== res.locals.board); |
||||
} |
||||
if (bans && bans.length > 0) { |
||||
const unseenBans = bans.filter(b => !b.seen).map(b => b._id); |
||||
await Bans.markSeen(unseenBans); //mark bans as seen
|
||||
bans.forEach(ban => ban.seen = true); //mark seen as true in memory for user viewed ban page
|
||||
//todo: make a dynamicresponse, handle in frontend modal.
|
||||
return res.status(403).render('ban', { |
||||
bans: bans, |
||||
}); |
||||
} |
||||
|
||||
next(); //no bans found
|
||||
|
||||
} |
||||
|
@ -0,0 +1,48 @@ |
||||
'use strict'; |
||||
|
||||
const Permissions = require(__dirname+'/../permissions.js') //needs rename
|
||||
, Permission = require(__dirname+'/../permission.js') |
||||
, PermissionTemplates = require(__dirname+'/../permtemplates.js'); |
||||
|
||||
module.exports = (req, res) => { |
||||
|
||||
let calculatedPermissions; |
||||
|
||||
if (req.session && res.locals && res.locals.user) { |
||||
|
||||
//has a session and user, not anon, so their permissions from the db/user instead.
|
||||
const { user } = res.locals; |
||||
calculatedPermissions = new Permission(user.permissions); |
||||
|
||||
//if they are on a board endpoint, also apply the board perms.
|
||||
if (res.locals.board != null) { |
||||
if (res.locals.board.owner === user.username) { |
||||
//they are board owner, give them board owner perms, in this board context
|
||||
calculatedPermissions.set(Permissions.MANAGE_BOARD_OWNER); |
||||
} else if (res.locals.board.staff[user.username] != null) { |
||||
//they are board staff, give them their board level staff perms, OR'd with account/global perms
|
||||
const boardPermissions = new Permission(res.locals.board.staff[user.username].permissions); |
||||
for (let bit of Permissions._MANAGE_BOARD_BITS) { |
||||
const inheritOrGlobal = calculatedPermissions.get(bit) || boardPermissions.get(bit); |
||||
calculatedPermissions.set(bit, inheritOrGlobal); |
||||
} |
||||
} |
||||
//and note, in future since we might need multiple-boards permission checks, we will have to change this.
|
||||
//could even build it with a map for each board, based on their stored permissions in that board, maybe like:
|
||||
//res.locals.boardPermissions[board] = new Permission(res.locals.board.settings.staff[user.username].permissions);
|
||||
//and then the MANAGE_BOARD_OWNER inheritance could be removed, since it should be set immutable
|
||||
//inside the board perms instead. and the existing code would make it for "global" BOs to have the permissions.
|
||||
//so we would remove the "...permissions.set(Permissions.MANAGE_BOARD_OWNER)..." above
|
||||
} |
||||
|
||||
//give ROOT all permission, BOARD_OWNER all MANAGE_BOARD*, etc
|
||||
calculatedPermissions.applyInheritance(); |
||||
|
||||
} else { |
||||
//not logged in, gets default anon permission
|
||||
calculatedPermissions = new Permission(PermissionTemplates.ANON.base64); |
||||
} |
||||
|
||||
return calculatedPermissions; |
||||
|
||||
} |
@ -1,8 +1,8 @@ |
||||
'use strict'; |
||||
|
||||
const hasPerms = require(__dirname+'/hasperms.js'); |
||||
const calcPerms = require(__dirname+'/calcperms.js'); |
||||
|
||||
module.exports = (req, res, next) => { |
||||
res.locals.permLevel = hasPerms(req, res); |
||||
res.locals.permissions = calcPerms(req, res); |
||||
next(); |
||||
} |
||||
|
@ -1,20 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = (req, res) => { |
||||
if (req.session) { |
||||
const { user } = res.locals; |
||||
if (user != null) { |
||||
if (user.authLevel < 4) { //assigned levels
|
||||
return user.authLevel; |
||||
} |
||||
if (res.locals.board != null) { |
||||
if (res.locals.board.owner === user.username) { |
||||
return 2; //board owner 2
|
||||
} else if (res.locals.board.settings.moderators.includes(user.username) === true) { |
||||
return 3; //board staff 3
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
return 4; //not logged in, not staff or moderator
|
||||
} |
@ -1,18 +1,53 @@ |
||||
'use strict'; |
||||
|
||||
const cache = {}; |
||||
//todo: refactor
|
||||
const Permissions = require(__dirname+'/../permissions.js') |
||||
, dynamicResponse = require(__dirname+'/../dynamic.js') |
||||
, cache = { |
||||
one: {}, all: {}, any: {}, |
||||
}; |
||||
|
||||
module.exports = (requiredLevel) => { |
||||
module.exports = { |
||||
|
||||
return cache[requiredLevel] || (cache[requiredLevel] = function(req, res, next) { |
||||
if (res.locals.permLevel > requiredLevel) { |
||||
return res.status(403).render('message', { |
||||
'title': 'Forbidden', |
||||
'message': 'No Permission', |
||||
'redirect': req.headers.referer || '/' |
||||
}); |
||||
} |
||||
next(); |
||||
}); |
||||
one: (requiredPermission) => { |
||||
return cache.one[requiredPermission] || (cache.one[requiredPermission] = function(req, res, next) { |
||||
if (!res.locals.permissions.get(requiredPermission)) { |
||||
return res.status(403).render('message', { |
||||
'title': 'Forbidden', |
||||
'message': 'No Permission', |
||||
'redirect': req.headers.referer || '/', |
||||
}); |
||||
} |
||||
next(); |
||||
}); |
||||
}, |
||||
|
||||
} |
||||
all: (...requiredPermissions) => { |
||||
//these caches working as intended with arrays?
|
||||
return cache.all[requiredPermissions] || (cache.all[requiredPermissions] = function(req, res, next) { |
||||
if (!res.locals.permissions.hasAll(...requiredPermissions)) { |
||||
return res.status(403).render('message', { |
||||
'title': 'Forbidden', |
||||
'message': 'No Permission', |
||||
'redirect': req.headers.referer || '/', |
||||
}); |
||||
} |
||||
next(); |
||||
}); |
||||
}, |
||||
|
||||
any: (...requiredPermissions) => { |
||||
//these caches working as intended with arrays?
|
||||
return cache.any[requiredPermissions] || (cache.any[requiredPermissions] = function(req, res, next) { |
||||
if (!res.locals.permissions.hasAny(...requiredPermissions)) { |
||||
return res.status(403).render('message', { |
||||
'title': 'Forbidden', |
||||
'message': 'No Permission', |
||||
'redirect': req.headers.referer || '/', |
||||
}); |
||||
} |
||||
next(); |
||||
}); |
||||
}, |
||||
|
||||
}; |
||||
|
@ -0,0 +1,48 @@ |
||||
'use strict'; |
||||
|
||||
const Permissions = require(__dirname+'/permissions.js') |
||||
, PermissionText = require(__dirname+'/permissiontext.js') //todo:combine^
|
||||
, BigBitfield = require('big-bitfield'); |
||||
|
||||
class Permission extends BigBitfield { |
||||
|
||||
constructor(data, name = 'Custom') { |
||||
super(data); |
||||
this.name = name; |
||||
} |
||||
|
||||
static permissionEntries = Object.entries(Permissions) |
||||
.filter(e => typeof e[1] === 'number'); |
||||
|
||||
static allPermissions = this.permissionEntries |
||||
.map(e => e[1]); |
||||
|
||||
toJSON() { |
||||
return this.constructor.permissionEntries |
||||
.reduce((acc, entry) => { |
||||
acc[entry[0]] = { |
||||
bit: entry[1], |
||||
state: this.get(entry[1]), |
||||
label: PermissionText[entry[0]].label, |
||||
desc: PermissionText[entry[0]].desc, |
||||
title: PermissionText[entry[0]].title, |
||||
}; |
||||
return acc; |
||||
}, {}); |
||||
} |
||||
|
||||
applyInheritance() { |
||||
if (this.get(Permissions.ROOT)){ //root gets all perms
|
||||
this.setAll(this.constructor.allPermissions); |
||||
} else if (this.get(Permissions.MANAGE_BOARD_OWNER)) { //BOs and "global staff"
|
||||
this.setAll([ |
||||
Permissions.MANAGE_BOARD_GENERAL, Permissions.MANAGE_BOARD_BANS,
|
||||
Permissions.MANAGE_BOARD_LOGS, Permissions.MANAGE_BOARD_SETTINGS,
|
||||
Permissions.MANAGE_BOARD_CUSTOMISATION, Permissions.MANAGE_BOARD_STAFF, |
||||
]); |
||||
} |
||||
} |
||||
|
||||
}; |
||||
|
||||
module.exports = Permission; |
@ -0,0 +1,43 @@ |
||||
'use strict'; |
||||
|
||||
const Permissions = { |
||||
ROOT: 0, |
||||
VIEW_RAW_IP: 1, |
||||
CREATE_BOARD: 2, |
||||
CREATE_ACCOUNT: 3, |
||||
BYPASS_BANS: 4, |
||||
BYPASS_SPAMCHECK: 5, |
||||
BYPASS_RATELIMITS: 6, |
||||
BYPASS_FILTERS: 7, |
||||
MANAGE_GLOBAL_GENERAL: 10, |
||||
MANAGE_GLOBAL_BANS: 11, |
||||
MANAGE_GLOBAL_LOGS: 12, |
||||
MANAGE_GLOBAL_NEWS: 13, |
||||
MANAGE_GLOBAL_BOARDS: 14, |
||||
MANAGE_GLOBAL_SETTINGS: 15, |
||||
MANAGE_GLOBAL_ACCOUNTS: 16, |
||||
MANAGE_BOARD_OWNER: 20, |
||||
MANAGE_BOARD_GENERAL: 21, |
||||
MANAGE_BOARD_BANS: 22, |
||||
MANAGE_BOARD_LOGS: 23, |
||||
MANAGE_BOARD_SETTINGS: 24, |
||||
MANAGE_BOARD_CUSTOMISATION: 25, |
||||
MANAGE_BOARD_STAFF: 26, |
||||
_MANAGE_BOARD_BITS: [20,21,22,23,24,25,26], |
||||
USE_MARKDOWN_PINKTEXT: 35, |
||||
USE_MARKDOWN_GREENTEXT: 36, |
||||
USE_MARKDOWN_BOLD: 37, |
||||
USE_MARKDOWN_UNDERLINE: 38, |
||||
USE_MARKDOWN_STRIKETHROUGH: 39, |
||||
USE_MARKDOWN_TITLE: 40, |
||||
USE_MARKDOWN_ITALIC: 41, |
||||
USE_MARKDOWN_SPOILER: 42, |
||||
USE_MARKDOWN_MONO: 43, |
||||
USE_MARKDOWN_CODE: 44, |
||||
USE_MARKDOWN_DETECTED: 45, |
||||
USE_MARKDOWN_LINK: 46, |
||||
USE_MARKDOWN_DICE: 47, |
||||
USE_MARKDOWN_FORTUNE: 48, |
||||
}; |
||||
|
||||
module.exports = Object.seal(Object.freeze(Object.preventExtensions(Permissions))); |
@ -0,0 +1,41 @@ |
||||
'use strict'; |
||||
|
||||
//todo: merge in permissions.js
|
||||
module.exports = { |
||||
ROOT: { title: 'Root', label: 'Root', desc: 'Full control. Use with caution!' }, |
||||
VIEW_RAW_IP: { title: 'Raw IPs', label: 'View Raw IPs', desc: 'Ability to see raw IPs in moderation interfaces.' }, |
||||
CREATE_BOARD: { title: 'Create', label: 'Create Board', desc: 'Ability to create new boards.' }, |
||||
CREATE_ACCOUNT: { label: 'Create Account', desc: 'Ability to register an account.' }, |
||||
BYPASS_BANS: { title: 'Bypasses', label: 'Bypass Bans', desc: 'Bypass all bans.' }, |
||||
BYPASS_SPAMCHECK: { label: 'Bypass Spamcheck', desc: 'Bypass the basic anti-flood spamcheck for too frequent similar posting.' }, |
||||
BYPASS_RATELIMITS: { label: 'Bypass Ratelimits', desc: 'Bypass ratelimits for getting new captchas, editing posts, editing board settings, etc.' }, |
||||
BYPASS_FILTERS: { label: 'Bypass Filters', desc: 'Bypass all post filters.' }, |
||||
MANAGE_GLOBAL_GENERAL: { title: 'Global Management',label: 'Global Staff', desc: 'General global staff permission. Access to recent posts and reports. Ability to submit global actions.' }, |
||||
MANAGE_GLOBAL_BANS: { label: 'Global Bans', desc: 'Access global bans. Ability to unban, edit, or deny appeals.' }, |
||||
MANAGE_GLOBAL_LOGS: { label: 'Global Logs', desc: 'Access global logs. Ability to search/filter' }, |
||||
MANAGE_GLOBAL_NEWS: { label: 'News', desc: 'Access news posting. Ability to add, edit, or delete newsposts.' }, |
||||
MANAGE_GLOBAL_BOARDS: { label: 'Boards', desc: 'Access the global board list. Ability to search/filter. Also grants the ability to transfer or delete any board.' }, |
||||
MANAGE_GLOBAL_SETTINGS: { label: 'Global Settings', desc: 'Access global settings. Ability to change any settings.' }, |
||||
MANAGE_GLOBAL_ACCOUNTS: { label: 'Accounts', desc: 'Access the accounts list. Ability to search/sort. Ability to edit permissions of any user. Can only be given by somebody else with "Root" permission.' }, //view, delete, change account permissions
|
||||
MANAGE_BOARD_OWNER: { title: 'Board Management', label: 'Board Owner', desc: 'Full control of the board, equivalent to the BO. Can delete and/or transfer the board. Can only be given by somebody else with "Board Owner" permission. Use with caution!' }, |
||||
MANAGE_BOARD_GENERAL: { label: 'Board Staff', desc: 'General board staff permission. Access mod index, catalog, recent posts and reports. Ability to submit mod actions. Bypass board-specific bans and post filters.' }, |
||||
MANAGE_BOARD_BANS: { label: 'Bans', desc: 'Access board bans. Ability to unban, edit, or deny appeals.' }, |
||||
MANAGE_BOARD_LOGS: { label: 'Logs', desc: 'Access board logs. Ability to search/filter.' }, |
||||
MANAGE_BOARD_SETTINGS: { label: 'Settings', desc: 'Access board settings. Ability to change any settings. Settings page will show transfer/delete forms for those with "Board Owner" permission.' }, |
||||
MANAGE_BOARD_CUSTOMISATION: { label: 'Customisation', desc: 'Access to board assets and custompages. Ability to upload, create, edit, delete.' }, |
||||
MANAGE_BOARD_STAFF: { label: 'Staff', desc: 'Access to staff management, and ability to add or remove permissions from others. Can only be given by somebody else with "Board Owner" permission. Use with caution!' }, |
||||
USE_MARKDOWN_PINKTEXT: { title: 'Post styling', label: 'Pinktext', desc: 'Use pinktext' }, |
||||
USE_MARKDOWN_GREENTEXT: { label: 'Greentext', desc: 'Use greentext' }, |
||||
USE_MARKDOWN_BOLD: { label: 'Bold', desc: 'Use bold' }, |
||||
USE_MARKDOWN_UNDERLINE: { label: 'Underline', desc: 'Use underline' }, |
||||
USE_MARKDOWN_STRIKETHROUGH: { label: 'Strikethrough', desc: 'Use strikethrough' }, |
||||
USE_MARKDOWN_TITLE: { label: 'Title', desc: 'Use titles' }, |
||||
USE_MARKDOWN_ITALIC: { label: 'Italic', desc: 'Use italics' }, |
||||
USE_MARKDOWN_SPOILER: { label: 'Spoiler', desc: 'Use spoilers' }, |
||||
USE_MARKDOWN_MONO: { label: 'Inline Monospace', desc: 'Use inline monospace' }, |
||||
USE_MARKDOWN_CODE: { label: 'Code Block', desc: 'Use code blocks' }, |
||||
USE_MARKDOWN_DETECTED: { label: 'Detected', desc: 'Use detected' }, |
||||
USE_MARKDOWN_LINK: { label: 'Links', desc: 'Make links clickable' }, |
||||
USE_MARKDOWN_DICE: { label: 'Dice Roll', desc: 'Use dice rolls' }, |
||||
USE_MARKDOWN_FORTUNE: { label: 'Fortune', desc: 'Use fortunes' }, |
||||
}; |
@ -0,0 +1,43 @@ |
||||
'use strict'; |
||||
|
||||
const Permissions = require(__dirname+'/permissions.js') |
||||
, Permission = require(__dirname+'/permission.js'); |
||||
|
||||
const ANON = new Permission() |
||||
ANON.setAll([ |
||||
Permissions.USE_MARKDOWN_PINKTEXT, Permissions.USE_MARKDOWN_GREENTEXT, Permissions.USE_MARKDOWN_BOLD,
|
||||
Permissions.USE_MARKDOWN_UNDERLINE, Permissions.USE_MARKDOWN_STRIKETHROUGH, Permissions.USE_MARKDOWN_TITLE,
|
||||
Permissions.USE_MARKDOWN_ITALIC, Permissions.USE_MARKDOWN_SPOILER, Permissions.USE_MARKDOWN_MONO,
|
||||
Permissions.USE_MARKDOWN_CODE, Permissions.USE_MARKDOWN_DETECTED, Permissions.USE_MARKDOWN_LINK,
|
||||
Permissions.USE_MARKDOWN_DICE, Permissions.USE_MARKDOWN_FORTUNE, Permissions.CREATE_BOARD,
|
||||
Permissions.CREATE_ACCOUNT |
||||
]); |
||||
|
||||
const BOARD_STAFF = new Permission(ANON.base64) |
||||
BOARD_STAFF.setAll([ |
||||
Permissions.MANAGE_BOARD_GENERAL, Permissions.MANAGE_BOARD_BANS, Permissions.MANAGE_BOARD_LOGS, Permissions.MANAGE_BOARD_SETTINGS, Permissions.MANAGE_BOARD_CUSTOMISATION, |
||||
]); |
||||
|
||||
const BOARD_OWNER = new Permission(BOARD_STAFF.base64) |
||||
BOARD_OWNER.setAll([ |
||||
Permissions.MANAGE_BOARD_OWNER, Permissions.MANAGE_BOARD_STAFF, |
||||
]); |
||||
|
||||
const GLOBAL_STAFF = new Permission(BOARD_OWNER.base64); |
||||
GLOBAL_STAFF.setAll([ |
||||
//no MANAGE_GLOBAL_ACCOUNTS, for now
|
||||
Permissions.MANAGE_GLOBAL_GENERAL, Permissions.MANAGE_GLOBAL_BANS, Permissions.MANAGE_GLOBAL_LOGS, Permissions.MANAGE_GLOBAL_NEWS,
|
||||
Permissions.MANAGE_GLOBAL_BOARDS, Permissions.MANAGE_GLOBAL_SETTINGS, Permissions.MANAGE_BOARD_OWNER, Permissions.BYPASS_FILTERS,
|
||||
Permissions.BYPASS_BANS, Permissions.BYPASS_SPAMCHECK, Permissions.BYPASS_RATELIMITS, |
||||
]); |
||||
|
||||
const ROOT = new Permission(); |
||||
ROOT.setAll(Permission.allPermissions); |
||||
|
||||
module.exports = { |
||||
ANON, |
||||
BOARD_STAFF, |
||||
BOARD_OWNER, |
||||
GLOBAL_STAFF, |
||||
ROOT, |
||||
}; |
@ -0,0 +1,86 @@ |
||||
'use strict'; |
||||
|
||||
const PermissionTemplates = require(__dirname+'/../helpers/permtemplates.js') |
||||
, Permission = require(__dirname+'/../helpers/permission.js') |
||||
, { Binary } = require('mongodb'); |
||||
|
||||
module.exports = async(db, redis) => { |
||||
console.log('making db changes for permissions update'); |
||||
console.log('setting new permission templates to replace old permission "levels"'); |
||||
await db.collection('accounts').updateMany({ permLevel: 0 }, { |
||||
'$set': { |
||||
'permissions': Binary(PermissionTemplates.ROOT.array), |
||||
}, |
||||
}); |
||||
await db.collection('accounts').updateMany({ permLevel: 1 }, { |
||||
'$set': { |
||||
'permissions': Binary(PermissionTemplates.GLOBAL_STAFF.array), |
||||
}, |
||||
}); |
||||
//not doing 2 and 3 anymore, since they were a weird, ugly part of the old "levels" system.
|
||||
//they can be added back manually by editing global perms if desired
|
||||
await db.collection('accounts').updateMany({ permLevel: { $gte: 2 } }, { //gte2, to get 2, 3, and 4.
|
||||
'$set': { |
||||
'permissions': Binary(PermissionTemplates.ANON.array), |
||||
}, |
||||
}); |
||||
console.log('renaming account modBoards->staffBoards'); |
||||
await db.collection('accounts').updateMany({}, { |
||||
'$unset': { |
||||
'authLevel': "", |
||||
}, |
||||
'$rename': { |
||||
'modBoards': 'staffBoards', |
||||
}, |
||||
}); |
||||
console.log('Adjusting global settings, and removing some redundant global settings that are now permission controlled'); |
||||
await db.collection('globalsettings').updateOne({ _id: 'globalsettings' }, { |
||||
'$unset': { |
||||
'userAccountCreation': '', |
||||
'userBoardCreation': '', |
||||
'ipHashPermLevel': '', |
||||
'deleteBoardPermLevel': '', |
||||
}, |
||||
'$set': { |
||||
'dontStoreRawIps': false, |
||||
} |
||||
}); |
||||
//board moderators -> staff, and give them all the BOARD_STAFF perms
|
||||
console.log('converting old "moderators" arrays to "staff" perms map and giving BOARD_STAFF template'); |
||||
const allBoards = await db.collection('boards').find({ webring: false }).toArray(); |
||||
const bulkWrites = allBoards.map(board => { |
||||
const staffObject = board.moderators.reduce((acc, mod) => { |
||||
acc[mod] = { |
||||
permissions: Binary(PermissionTemplates.BOARD_STAFF.array), |
||||
addedDate: new Date(), |
||||
}; |
||||
return acc; |
||||
}, {}); |
||||
//add add the BO to staff
|
||||
staffObject[board.owner] = { |
||||
permissions: Binary(PermissionTemplates.BOARD_OWNER.array), |
||||
addedDate: new Date(), |
||||
} |
||||
return { |
||||
'updateOne': { |
||||
'filter': { |
||||
'_id': board._id, |
||||
}, |
||||
'update': { |
||||
'$unset': { |
||||
'moderators': '', |
||||
}, |
||||
'$set': { |
||||
'staff': staffObject, |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
await db.collection('boards').bulkWrite(bulkWrites); |
||||
console.log('Clearing globalsettings cache'); |
||||
await redis.deletePattern('globalsettings'); |
||||
console.log('Clearing user and board cache'); |
||||
await redis.deletePattern('board:*'); |
||||
await redis.deletePattern('users:*'); |
||||
}; |
@ -0,0 +1,20 @@ |
||||
'use strict'; |
||||
|
||||
const { Boards, Accounts } = require(__dirname+'/../../db/') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, PermissionTemplates = require(__dirname+'/../../helpers/permtemplates.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
await Promise.all([ |
||||
Accounts.addStaffBoard([req.body.username], res.locals.board._id), |
||||
Boards.addStaff(res.locals.board._id, req.body.username, PermissionTemplates.BOARD_STAFF) |
||||
]); |
||||
|
||||
return dynamicResponse(req, res, 200, 'message', { |
||||
'title': 'Success', |
||||
'message': 'Added staff', |
||||
'redirect': `/${req.params.board}/manage/staff.html`, |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,63 @@ |
||||
'use strict'; |
||||
|
||||
const { Accounts, Boards } = require(__dirname+'/../../db/') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, cache = require(__dirname+'/../../redis.js') |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
const accountsWithBoards = await Accounts.getOwnedOrStaffBoards(req.body.checkedaccounts); |
||||
if (accountsWithBoards.length > 0) { |
||||
const bulkWrites = []; |
||||
for (let i = 0; i < accountsWithBoards.length; i++) { |
||||
const acc = accountsWithBoards[i]; |
||||
if (acc.staffBoards.length > 0) { |
||||
//remove from staff of any boards they are mod on
|
||||
bulkWrites.push({ |
||||
'updateMany': { |
||||
'filter': { |
||||
'_id': { |
||||
'$in': acc.staffBoards |
||||
} |
||||
}, |
||||
'update': { |
||||
'$unset': { |
||||
[`staff.${acc.username}`]: "", |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
cache.del(acc.staffBoards.map(b => `board:${b}`)); |
||||
} |
||||
if (acc.ownedBoards.length > 0) { |
||||
//remove as owner of any boards they own
|
||||
bulkWrites.push({ |
||||
'updateMany': { |
||||
'filter': { |
||||
'_id': { |
||||
'$in': acc.ownedBoards |
||||
} |
||||
}, |
||||
'update': { |
||||
'$set': { |
||||
'owner': null //board has no owner
|
||||
} |
||||
} |
||||
} |
||||
}); |
||||
cache.del(acc.ownedBoards.map(b => `board:${b}`)); |
||||
//todo: use list of board with no owners for claims
|
||||
} |
||||
} |
||||
await Boards.db.bulkWrite(bulkWrites); |
||||
} |
||||
|
||||
const amount = await Accounts.deleteMany(req.body.checkedaccounts).then(res => res.deletedCount); |
||||
|
||||
return dynamicResponse(req, res, 200, 'message', { |
||||
'title': 'Success', |
||||
'message': `${req.body.delete_account ? 'Deleted' : 'Edited'} ${amount} accounts`, |
||||
'redirect': '/globalmanage/accounts.html' |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,19 @@ |
||||
'use strict'; |
||||
|
||||
const { Boards, Accounts } = require(__dirname+'/../../db/') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
await Promise.all([ |
||||
Accounts.removeStaffBoard(req.body.checkedstaff, res.locals.board._id), |
||||
Boards.removeStaff(res.locals.board._id, req.body.checkedstaff) |
||||
]); |
||||
|
||||
return dynamicResponse(req, res, 200, 'message', { |
||||
'title': 'Success', |
||||
'message': 'Deleted staff', |
||||
'redirect': `/${req.params.board}/manage/staff.html`, |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,69 @@ |
||||
'use strict'; |
||||
|
||||
const { Accounts } = require(__dirname+'/../../db/') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, Permissions = require(__dirname+'/../../helpers/permissions.js') |
||||
, Permission = require(__dirname+'/../../helpers/permission.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
let updatingPermissions = new Permission(res.locals.editingAccount.permissions); |
||||
|
||||
//this can probably be made more general
|
||||
updatingPermissions.set(Permissions.VIEW_RAW_IP, (req.body.VIEW_RAW_IP != null)); |
||||
updatingPermissions.set(Permissions.CREATE_BOARD, (req.body.CREATE_BOARD != null)); |
||||
updatingPermissions.set(Permissions.CREATE_ACCOUNT, (req.body.CREATE_ACCOUNT != null)); |
||||
updatingPermissions.set(Permissions.BYPASS_BANS, (req.body.BYPASS_BANS != null)); |
||||
updatingPermissions.set(Permissions.BYPASS_SPAMCHECK, (req.body.BYPASS_SPAMCHECK != null)); |
||||
updatingPermissions.set(Permissions.BYPASS_RATELIMITS, (req.body.BYPASS_RATELIMITS != null)); |
||||
updatingPermissions.set(Permissions.BYPASS_FILTERS, (req.body.BYPASS_FILTERS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_GLOBAL_GENERAL, (req.body.MANAGE_GLOBAL_GENERAL != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_GLOBAL_BANS, (req.body.MANAGE_GLOBAL_BANS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_GLOBAL_LOGS, (req.body.MANAGE_GLOBAL_LOGS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_GLOBAL_NEWS, (req.body.MANAGE_GLOBAL_NEWS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_GLOBAL_BOARDS, (req.body.MANAGE_GLOBAL_BOARDS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_GLOBAL_SETTINGS, (req.body.MANAGE_GLOBAL_SETTINGS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_GENERAL, (req.body.MANAGE_BOARD_GENERAL != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_OWNER, (req.body.MANAGE_BOARD_OWNER != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_BANS, (req.body.MANAGE_BOARD_BANS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_LOGS, (req.body.MANAGE_BOARD_LOGS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_SETTINGS, (req.body.MANAGE_BOARD_SETTINGS != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_CUSTOMISATION, (req.body.MANAGE_BOARD_CUSTOMISATION != null)); |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_STAFF, (req.body.MANAGE_BOARD_STAFF != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_PINKTEXT, (req.body.USE_MARKDOWN_PINKTEXT != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_GREENTEXT, (req.body.USE_MARKDOWN_GREENTEXT != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_BOLD, (req.body.USE_MARKDOWN_BOLD != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_UNDERLINE, (req.body.USE_MARKDOWN_UNDERLINE != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_STRIKETHROUGH, (req.body.USE_MARKDOWN_STRIKETHROUGH != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_TITLE, (req.body.USE_MARKDOWN_TITLE != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_ITALIC, (req.body.USE_MARKDOWN_ITALIC != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_SPOILER, (req.body.USE_MARKDOWN_SPOILER != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_MONO, (req.body.USE_MARKDOWN_MONO != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_CODE, (req.body.USE_MARKDOWN_CODE != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_DETECTED, (req.body.USE_MARKDOWN_DETECTED != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_LINK, (req.body.USE_MARKDOWN_LINK != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_DICE, (req.body.USE_MARKDOWN_DICE != null)); |
||||
updatingPermissions.set(Permissions.USE_MARKDOWN_FORTUNE, (req.body.USE_MARKDOWN_FORTUNE != null)); |
||||
if (res.locals.permissions.get(Permissions.ROOT)) { |
||||
//be careful giving others manage_global_accounts!
|
||||
updatingPermissions.set(Permissions.MANAGE_GLOBAL_ACCOUNTS, (req.body.MANAGE_GLOBAL_ACCOUNTS != null)) |
||||
updatingPermissions.set(Permissions.ROOT, (req.body.ROOT != null)); |
||||
} |
||||
|
||||
const updated = await Accounts.setAccountPermissions(req.body.username, updatingPermissions).then(r => r.matchedCount); |
||||
|
||||
if (updated === 0) { |
||||
return dynamicResponse(req, res, 400, 'message', { |
||||
'title': 'Bad request', |
||||
'errors': 'Account does not exist', |
||||
'redirect': req.headers.referer || `/globalmanage/accounts.html`, |
||||
}); |
||||
} |
||||
|
||||
return dynamicResponse(req, res, 200, 'message', { |
||||
'title': 'Success', |
||||
'message': 'Edited account', |
||||
'redirect': `/globalmanage/editaccount/${req.body.username}.html`, |
||||
}); |
||||
|
||||
} |
@ -1,68 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
const { Accounts, Boards } = require(__dirname+'/../../db/') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, cache = require(__dirname+'/../../redis.js') |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
//edit the accounts
|
||||
let amount = 0; |
||||
if (req.body.delete_account) { |
||||
const accountsWithBoards = await Accounts.getOwnedOrModBoards(req.body.checkedaccounts); |
||||
if (accountsWithBoards.length > 0) { |
||||
const bulkWrites = []; |
||||
for (let i = 0; i < accountsWithBoards.length; i++) { |
||||
const acc = accountsWithBoards[i]; |
||||
if (acc.modBoards.length > 0) { |
||||
//remove from moderators of any boards they are mod on
|
||||
bulkWrites.push({ |
||||
'updateMany': { |
||||
'filter': { |
||||
'_id': { |
||||
'$in': acc.modBoards |
||||
} |
||||
}, |
||||
'update': { |
||||
'$pull': { |
||||
'settings.moderators': acc._id |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
cache.del(acc.modBoards.map(b => `board:${b}`)); |
||||
} |
||||
if (acc.ownedBoards.length > 0) { |
||||
//remove from moderators of any boards they are mod on
|
||||
bulkWrites.push({ |
||||
'updateMany': { |
||||
'filter': { |
||||
'_id': { |
||||
'$in': acc.ownedBoards |
||||
} |
||||
}, |
||||
'update': { |
||||
'$set': { |
||||
'owner': null //board has no owner
|
||||
} |
||||
} |
||||
} |
||||
}); |
||||
cache.del(acc.ownedBoards.map(b => `board:${b}`)); |
||||
//todo: use list of board with no owners for claims
|
||||
} |
||||
} |
||||
await Boards.db.bulkWrite(bulkWrites); |
||||
} |
||||
amount = await Accounts.deleteMany(req.body.checkedaccounts).then(res => res.deletedCount); |
||||
} else { |
||||
amount = await Accounts.setLevel(req.body.checkedaccounts, req.body.auth_level).then(res => res.modifiedCount); |
||||
} |
||||
|
||||
return dynamicResponse(req, res, 200, 'message', { |
||||
'title': 'Success', |
||||
'message': `${req.body.delete_account ? 'Deleted' : 'Edited'} ${amount} accounts`, |
||||
'redirect': '/globalmanage/accounts.html' |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,40 @@ |
||||
'use strict'; |
||||
|
||||
const { Boards } = require(__dirname+'/../../db/') |
||||
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') |
||||
, Permissions = require(__dirname+'/../../helpers/permissions.js') |
||||
, Permission = require(__dirname+'/../../helpers/permission.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
let updatingPermissions = new Permission(res.locals.board.staff[req.body.username].permissions); |
||||
|
||||
//maybe these can be changed
|
||||
//updatingPermissions.set(Permissions.MANAGE_BOARD_GENERSL, (req.body.MANAGE_BOARD_GENERAL != null))
|
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_BANS, (req.body.MANAGE_BOARD_BANS != null)) |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_LOGS, (req.body.MANAGE_BOARD_LOGS != null)) |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_SETTINGS, (req.body.MANAGE_BOARD_SETTINGS != null)) |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_CUSTOMISATION, (req.body.MANAGE_BOARD_CUSTOMISATION != null)) |
||||
if (res.locals.permissions.get(Permissions.MANAGE_BOARD_OWNER)) { |
||||
//be careful giving others manage_board_owner!
|
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_OWNER, (req.body.MANAGE_BOARD_OWNER != null)) |
||||
updatingPermissions.set(Permissions.MANAGE_BOARD_STAFF, (req.body.MANAGE_BOARD_STAFF != null)) |
||||
} |
||||
|
||||
const updated = await Boards.setStaffPermissions(req.params.board, req.body.username, updatingPermissions).then(r => r.matchedCount); |
||||
|
||||
if (updated === 0) { |
||||
return dynamicResponse(req, res, 400, 'message', { |
||||
'title': 'Bad request', |
||||
'errors': 'Staff does not exist', |
||||
'redirect': req.headers.referer || `/${req.params.board}/manage/staff.html`, |
||||
}); |
||||
} |
||||
|
||||
return dynamicResponse(req, res, 200, 'message', { |
||||
'title': 'Success', |
||||
'message': 'Edited staff', |
||||
'redirect': `/${req.params.board}/manage/editstaff/${req.body.username}.html`, |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
'use strict'; |
||||
|
||||
const { Accounts } = require(__dirname+'/../../../db/') |
||||
, Permission = require(__dirname+'/../../../helpers/permission.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
const editingAccount = await Accounts.findOne(req.params.accountusername); |
||||
|
||||
if (editingAccount == null) { |
||||
//account does not exist
|
||||
return next(); |
||||
} |
||||
|
||||
res |
||||
.set('Cache-Control', 'private, max-age=5') |
||||
.render('editaccount', { |
||||
csrf: req.csrfToken(), |
||||
board: res.locals.board, |
||||
accountUsername: req.params.accountusername, |
||||
accountPermissions: new Permission(editingAccount.permissions), |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
'use strict'; |
||||
|
||||
const Permission = require(__dirname+'/../../../helpers/permission.js'); |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
let staffData = res.locals.board.staff[req.params.staffusername]; |
||||
|
||||
if (staffData == null) { |
||||
//staff does not exist
|
||||
return next(); |
||||
} |
||||
|
||||
res |
||||
// .set('Cache-Control', 'private, max-age=5')
|
||||
.render('editstaff', { |
||||
csrf: req.csrfToken(), |
||||
board: res.locals.board, |
||||
permissions: res.locals.permissions, |
||||
staffUsername: req.params.staffusername, |
||||
staffPermissions: new Permission(staffData.permissions), |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,13 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
res |
||||
.set('Cache-Control', 'private, max-age=5') |
||||
.render('managemypermissions', { |
||||
user: res.locals.user, |
||||
board: res.locals.board, |
||||
permissions: res.locals.permissions, |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,11 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
res |
||||
.set('Cache-Control', 'private, max-age=5') |
||||
.render('managemypermissions', { |
||||
permissions: res.locals.permissions, |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,14 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
res |
||||
// .set('Cache-Control', 'private, max-age=5')
|
||||
.render('managestaff', { |
||||
csrf: req.csrfToken(), |
||||
permissions: res.locals.permissions, |
||||
board: res.locals.board, |
||||
user: res.locals.user, |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,12 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
res |
||||
.set('Cache-Control', 'private, max-age=5') |
||||
.render('mypermissions', { |
||||
user: res.locals.user, |
||||
permissions: res.locals.permissions, |
||||
}); |
||||
|
||||
} |
@ -0,0 +1,12 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = async (req, res, next) => { |
||||
|
||||
res |
||||
.set('Cache-Control', 'private, max-age=5') |
||||
.render('mypermissions', { |
||||
user: res.locals.user, |
||||
permissions: res.locals.permissions, |
||||
}); |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue