accounts page, list owned and mod boards in accounts, show on global manage and accounts page

merge-requests/208/head
fatchan 5 years ago
parent ff22b3650c
commit 2b4e631756
  1. 2
      controllers/forms/editaccounts.js
  2. 2
      controllers/forms/transfer.js
  3. 3
      controllers/pages.js
  4. 83
      db/accounts.js
  5. 6
      db/boards.js
  6. 4
      helpers/checks/isloggedin.js
  7. 4
      helpers/sessionrefresh.js
  8. 30
      models/forms/changeboardsettings.js
  9. 10
      models/forms/create.js
  10. 4
      models/forms/deleteboard.js
  11. 56
      models/forms/editaccounts.js
  12. 8
      models/forms/login.js
  13. 4
      models/forms/transferboard.js
  14. 9
      models/pages/account.js
  15. 1
      models/pages/index.js
  16. 4
      queue.js
  17. 8
      redis.js
  18. 2
      views/includes/navbar.pug
  19. 49
      views/pages/account.pug
  20. 10
      views/pages/globalmanageaccounts.pug

@ -9,7 +9,7 @@ module.exports = async (req, res, next) => {
if (!req.body.checkedaccounts || req.body.checkedaccounts.length === 0 || req.body.checkedaccounts.length > 10) {
errors.push('Must select 1-10 accounts');
}
if (!req.body.auth_level && !req.body.delete_account) {
if (typeof req.body.auth_level !== 'number' && !req.body.delete_account) {
errors.push('Missing auth level or delete action');
}
if (typeof req.body.auth_level === 'number' && req.body.auth_level < 0 || req.body.auth_level > 4) {

@ -14,7 +14,7 @@ module.exports = async (req, res, next) => {
errors.push('Transfer username must be at less than 50 characters');
}
if (req.body.username === res.locals.board.owner) {
errors.push('You are already board owner...');
errors.push('New owner username must not be same as old owner');
}
if (alphaNumericRegex.test(req.body.username) !== true) {
errors.push('URI must contain a-z 0-9 only');

@ -16,7 +16,7 @@ const express = require('express')
, { globalManageReports, globalManageBans, globalManageRecent, globalManageAccounts, globalManageNews } = require(__dirname+'/../models/pages/globalmanage/')
, { changePassword, home, register, login, logout, create,
board, catalog, banners, randombanner, news, captchaPage,
captcha, thread, modlog, modloglist, boardlist } = require(__dirname+'/../models/pages/');
captcha, thread, modlog, modloglist, account, boardlist } = require(__dirname+'/../models/pages/');
//homepage
router.get('/index.html', home);
@ -60,6 +60,7 @@ router.get('/captcha', captcha); //get captcha image and cookie
router.get('/captcha.html', captchaPage); //iframed for noscript users
//accounts
router.get('/account.html', sessionRefresh, isLoggedIn, account); //page showing boards you are mod/owner of, links to password rese, logout, etc
router.get('/login.html', login);
router.get('/register.html', register);
router.get('/changepassword.html', changePassword);

@ -32,18 +32,20 @@ module.exports = {
'_id': username,
'passwordHash': passwordHash,
'authLevel': authLevel,
'ownedBoards': [],
'modBoards': []
});
},
changePassword: async (username, newPassword) => {
const passwordHash = await bcrypt.hash(newPassword, 12);
return db.updateOne({
'_id': username
}, {
'$set': {
'passwordHash': passwordHash
}
});
'_id': username
}, {
'$set': {
'passwordHash': passwordHash
}
});
},
find: (skip=0, limit=0) => {
@ -64,6 +66,75 @@ module.exports = {
});
},
addOwnedBoard: (username, board) => {
return db.updateOne({
'_id': username
}, {
'$addToSet': {
'ownedBoards': board
}
});
},
removeOwnedBoard: (username, board) => {
return db.updateOne({
'_id': username
}, {
'$pull': {
'ownedBoards': board
}
});
},
addModBoard: (usernames, board) => {
return db.updateMany({
'_id': {
'$in': usernames
}
}, {
'$addToSet': {
'modBoards': board
}
});
},
removeModBoard: (usernames, board) => {
return db.updateMany({
'_id': {
'$in': usernames
}
}, {
'$pull': {
'modBoards': board
}
});
},
getOwnedOrModBoards: (usernames) => {
return db.find({
'_id': {
'$in': usernames
},
'$or': [
{
'ownedBoards.0': {
'$exists': true
},
},
{
'modBoards.0': {
'$exists': true
}
}
]
}, {
'projection': {
'ownedBoards': 1,
'modBoards': 1,
}
}).toArray();
},
setLevel: (usernames, level) => {
//increase users auth level
return db.updateMany({

@ -131,7 +131,11 @@ module.exports = {
},
count: (showUnlisted=false) => {
return db.countDocuments(showUnlisted ? {} : { 'settings.unlisted': false });
if (showUnlisted) {
return db.countDocuments({ 'settings.unlisted': false });
} else {
return db.estimatedDocumentCount();
}
},
totalStats: () => {

@ -1,7 +1,7 @@
'use strict';
module.exports = async (req, res, next) => {
if (req.session.authenticated === true) {
if (req.session && req.session.authenticated === true) {
return next();
}
let goto;
@ -9,5 +9,5 @@ module.exports = async (req, res, next) => {
//coming from a GET page isLoggedIn middleware check
goto = req.path;
}
res.redirect(`/login.html${goto ? '?goto='+goto : ''}`);
return res.redirect(`/login.html${goto ? '?goto='+goto : ''}`);
}

@ -11,7 +11,9 @@ module.exports = async (req, res, next) => {
} else {
req.session.user = {
'username': account._id,
'authLevel': account.authLevel
'authLevel': account.authLevel,
'modBoards': account.modBoards,
'ownedBoards': account.ownedBoards,
};
}
}

@ -13,8 +13,12 @@ const { Boards, Posts, Accounts } = require(__dirname+'/../../db/')
module.exports = async (req, res, next) => {
//oldsettings before changes
const oldSettings = res.locals.board.settings;
//array of promises we might need
const promises = [];
let markdownAnnouncement;
if (req.body.announcement !== oldSettings.announcement.raw) {
//remarkup the announcement if it changes
@ -24,17 +28,34 @@ module.exports = async (req, res, next) => {
markdownAnnouncement = sanitized;
}
let moderators = req.body.moderators != null ? req.body.moderators.split('\r\n').filter(n => n).slice(0,10) : oldSettings.moderators
if (moderators !== oldSettings.moderators) {
//make sure moderators actually have existing accounts
let moderators = req.body.moderators != null ? req.body.moderators.split('\r\n').filter(n => n).slice(0,10) : [];
if (moderators.length === 0 && oldSettings.moderators.length > 0) {
//remove all mods if mod list being emptied
promises.push(Accounts.removeModBoard(oldSettings.moderators, req.params.board));
} else if (moderators !== oldSettings.moderators) {
if (moderators.length > 0) {
//make sure moderators actually have existing accounts
const validCount = await Accounts.countUsers(moderators);
if (validCount !== moderators.length) {
//some usernames were not valid, reset to old setting
moderators = oldSettings.moderators;
} else {
//all accounts exist, check added/removed
const modsRemoved = oldSettings.moderators.filter(m => !moderators.includes(m));
const modsAdded = moderators.filter(m => !oldSettings.moderators.includes(m));
if (modsRemoved.length > 0) {
//remove mod from accounts
promises.push(Accounts.removeModBoard(modsRemoved, req.params.board));
}
if (modsAdded.length > 0) {
//add mod to accounts
promises.push(Accounts.addModBoard(modsAdded, req.params.board));
}
}
}
}
//todo: make separate functions for handling array, boolean, number, text settings.
const newSettings = {
moderators,
'name': req.body.name && req.body.name.trim().length > 0 ? req.body.name : oldSettings.name,
@ -92,9 +113,6 @@ module.exports = async (req, res, next) => {
//update this in locals incase is used in later parts
res.locals.board.settings = newSettings;
//array of promises we might need
const promises = [];
//pages in new vs old settings
const oldMaxPage = Math.ceil(oldSettings.threadLimit/10);
const newMaxPage = Math.ceil(newSettings.threadLimit/10);

@ -1,6 +1,6 @@
'use strict';
const { Boards } = require(__dirname+'/../../db/')
const { Boards, Accounts } = require(__dirname+'/../../db/')
, { boardDefaults } = require(__dirname+'/../../configs/main.js');
module.exports = async (req, res, next) => {
@ -8,6 +8,7 @@ module.exports = async (req, res, next) => {
const { name, description } = req.body
, uri = req.body.uri.toLowerCase()
, tags = req.body.tags.split('\n').filter(n => n)
, owner = req.session.user.username
, board = await Boards.findOne(uri);
// if board exists reject
@ -22,7 +23,7 @@ module.exports = async (req, res, next) => {
//todo: add a settings for defaults
const newBoard = {
'_id': uri,
'owner': req.session.user.username,
owner,
'banners': [],
'sequence_value': 1,
'pph': 0,
@ -37,7 +38,10 @@ module.exports = async (req, res, next) => {
}
}
await Boards.insertOne(newBoard);
await Promise.all([
Boards.insertOne(newBoard),
Accounts.addOwnedBoard(owner, uri)
]);
return res.redirect(`/${uri}/index.html`);

@ -1,6 +1,6 @@
'use strict';
const { Boards, Stats, Posts, Bans, Modlogs } = require(__dirname+'/../../db/')
const { Accounts, Boards, Stats, Posts, Bans, Modlogs } = require(__dirname+'/../../db/')
, cache = require(__dirname+'/../../redis.js')
, deletePosts = require(__dirname+'/deletepost.js')
, uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js')
@ -17,6 +17,8 @@ module.exports = async (uri, board) => {
await deletePosts(allPosts, uri, true);
}
await Promise.all([
Accounts.removeOwnedBoard(board.owner, uri), //remove board from owner account
board.settings.moderators.length > 0 ? Accounts.removeModBoard(board.settings.moderators) : void 0, //remove board from mods accounts
Modlogs.deleteBoard(uri), //modlogs for the board
Bans.deleteBoard(uri), //bans for the board
Stats.deleteBoard(uri), //stats for the board

@ -1,21 +1,67 @@
'use strict';
const { Accounts } = require(__dirname+'/../../db/');
const { Accounts, Boards } = require(__dirname+'/../../db/')
, 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 res.render('message', {
'title': 'Success',
'message': `${req.body.delete_account ? 'Deleted' : 'Edited'} ${amount} accounts`,
'redirect': '/globalmanage/accounts.html'
});
'title': 'Success',
'message': `${req.body.delete_account ? 'Deleted' : 'Edited'} ${amount} accounts`,
'redirect': '/globalmanage/accounts.html'
});
}

@ -7,7 +7,7 @@ module.exports = async (req, res, next) => {
const username = req.body.username.toLowerCase();
const password = req.body.password;
const goto = req.body.goto;
const goto = req.body.goto || '/account.html';
const failRedirect = `/login.html${goto ? '?goto='+goto : ''}`
//fetch an account
@ -31,12 +31,14 @@ module.exports = async (req, res, next) => {
// add the account to the session and authenticate if password was correct
req.session.user = {
'username': account._id,
'authLevel': account.authLevel
'authLevel': account.authLevel,
'ownedBoards': account.ownedBoards,
'modBoards': account.modBoards,
};
req.session.authenticated = true;
//successful login
return res.redirect(goto || '/');
return res.redirect(goto);
}

@ -14,6 +14,10 @@ module.exports = async (req, res, next) => {
});
}
//modify accounts with new board ownership
await Accounts.removeOwnedBoard(res.locals.board.owner, req.params.board)
await Accounts.addOwnedBoard(newOwner._id, req.params.board);
//set owner in memory and in db
res.locals.board.owner = newOwner._id;
await Boards.setOwner(req.params.board, res.locals.board.owner);

@ -0,0 +1,9 @@
'use strict';
module.exports = async (req, res, next) => {
return res.render('account', {
user: req.session.user
});
}

@ -3,6 +3,7 @@
module.exports = {
changePassword: require(__dirname+'/changepassword.js'),
register: require(__dirname+'/register.js'),
account: require(__dirname+'/account.js'),
home: require(__dirname+'/home.js'),
login: require(__dirname+'/login.js'),
logout: require(__dirname+'/logout.js'),

@ -8,8 +8,8 @@ module.exports = {
queue: taskQueue,
push: (data, options) => {
taskQueue.add(data, options);
push: (data) => {
taskQueue.add(data, { removeOnComplete: true });
}
}

@ -33,8 +33,12 @@ module.exports = {
},
//delete value with key
del: (key) => {
return client.del(key);
del: (keyOrKeys) => {
if (Array.isArray(keyOrKeys)) {
return client.del(...keyOrKeys);
} else {
return client.del(keyOrKeys);
}
},
deletePattern: (pattern) => {

@ -2,6 +2,6 @@ nav.navbar#top
a.nav-item(href='/index.html') Home
a.nav-item(href='/news.html') News
a.nav-item(href='/boards.html') Boards
a.nav-item(href='/account.html') Account
a.nav-item(href=`/${board ? board._id+'/manage/reports' : 'globalmanage/recent'}.html`) Manage
a.nav-item(href='/create.html') Create
a.jsonly.nav-item.right#settings &#9881;

@ -0,0 +1,49 @@
extends ../layout.pug
block head
script(src='/js/all.js')
title Manage
block content
.board-header
h1.board-title Welcome, #{user.username}
h4.board-description Auth level: #{user.authLevel}
br
hr(size=1)
h4.no-m-p General:
ul
if user.authLevel <= 1
li: a(href='/globalmanage/recent.html') Global management
li: a(href='/create.html') Create a board
li: a(href='/changepassword.html') Change password
li: a(href='/logout') Log out
hr(size=1)
h4.no-m-p Boards you own:
if user.ownedBoards && user.ownedBoards.length > 0
ul
for b in user.ownedBoards
li
a(href=`/${b}/index.html`) /#{b}/
| -
a(href=`/${b}/manage/reports.html`) Reports
| ,
a(href=`/${b}/manage/bans.html`) Bans
| ,
a(href=`/${b}/manage/settings.html`) Settings
| ,
a(href=`/${b}/manage/banners.html`) Banners
else
p None
hr(size=1)
h4.no-m-p Boards you moderate:
if user.modBoards && user.modBoards.length > 0
ul
for b in user.modBoards
li
a(href=`/${b}/index.html`) /#{b}/
| -
a(href=`/${b}/manage/reports.html`) Reports
| ,
a(href=`/${b}/manage/bans.html`) Bans
else
p None

@ -20,11 +20,21 @@ block content
th
th Username
th Auth Level
th Own Boards
th Mod Boards
for account in accounts
tr
td: input(type='checkbox', name='checkedaccounts' value=account._id)
td #{account._id}
td #{account.authLevel}
td
for b in account.ownedBoards
a(href=`/${b}/index.html`) /#{b}/
|
td
for b in account.modBoards
a(href=`/${b}/index.html`) /#{b}/
|
.pages.mt-5
include ../includes/pages.pug
.row

Loading…
Cancel
Save