diff --git a/src/app/channel/activeChannel.js b/src/app/channel/activeChannel.js index ac8b590..42bf2e9 100644 --- a/src/app/channel/activeChannel.js +++ b/src/app/channel/activeChannel.js @@ -20,9 +20,10 @@ const flairModel = require('../../schemas/flairSchema'); const permissionModel = require('../../schemas/permissionSchema'); module.exports = class{ - constructor(server, name){ + constructor(server, chanDB){ this.server = server; - this.name = name; + this.name = chanDB.name; + this.tokeCommands = chanDB.tokeCommands; //Keeping these in a map was originally a vestige but it's more preformant than an array or object so :P this.userList = new Map(); } @@ -37,8 +38,11 @@ module.exports = class{ if(userObj){ //Add this socket on to the userobject userObj.sockets.push(socket.id); + //If the user is joining the channel }else{ + //Grab flair await userDB.populate('flair'); + //Set user object userObj = new connectedUser(userDB, chanRank, this, socket); } diff --git a/src/app/channel/channelManager.js b/src/app/channel/channelManager.js index 8fb8543..d786e50 100644 --- a/src/app/channel/channelManager.js +++ b/src/app/channel/channelManager.js @@ -109,7 +109,7 @@ module.exports = class{ if(!activeChan){ //If not, make it so - activeChan = new activeChannel(this, socket.chan); + activeChan = new activeChannel(this, chanDB); this.activeChannels.set(socket.chan, activeChan); } diff --git a/src/app/channel/tokebot.js b/src/app/channel/tokebot.js index c9a0f3b..a48b335 100644 --- a/src/app/channel/tokebot.js +++ b/src/app/channel/tokebot.js @@ -52,10 +52,22 @@ module.exports = class tokebot{ } tokeProcessor(commandObj){ - const foundToke = this.tokeCommands.indexOf(commandObj.argumentArray[0]); + //Check for site-wide toke commands + if(this.tokeCommands.indexOf(commandObj.argumentArray[0]) != -1){ + //Seems lame to set a bool in an if statement but this would've made a really ugly turinary + var foundToke = true; + }else{ + //Find the users active channel + const activeChan = this.server.activeChannels.get(commandObj.socket.chan); + + //Check if they're using a channel-only toke + //This should be safe to do without a null check but someone prove me wrong lmao + var foundToke = (activeChan.tokeCommands.indexOf(commandObj.argumentArray[0]) != -1); + } + //If we found a toke - if(foundToke != -1){ + if(foundToke){ //If there is no active toke or cooldown (new toke) if(this.tokeTimer == null && this.cooldownTimer == null){ //Call-out toke start diff --git a/src/controllers/api/channel/tokeCommandController.js b/src/controllers/api/channel/tokeCommandController.js index 4547a98..40b203a 100644 --- a/src/controllers/api/channel/tokeCommandController.js +++ b/src/controllers/api/channel/tokeCommandController.js @@ -23,10 +23,17 @@ const channelModel = require('../../../schemas/channel/channelSchema'); module.exports.get = async function(req, res){ try{ - const tokeList = await tokeCommandModel.getCommandStrings(); + //Pull validated and sanatized input and yoink the channel DB doc + const {chanName} = matchedData(req); + const chanDB = await channelModel.findOne({name: chanName}); - res.status(200); - return res.send(tokeList); + //if we found a channel in the DB + if(chanDB != null){ + res.status(200); + return res.send(chanDB.tokeCommands); + }else{ + return errorHandler(res, "Channel not found!", "Bad Query"); + } }catch(err){ return exceptionHandler(res, err); } @@ -39,20 +46,29 @@ module.exports.post = async function(req, res){ //if they're empty if(validResult.isEmpty()){ - /* - const {command} = matchedData(req); - const tokeDB = await tokeCommandModel.findOne({command}); + //Pull sanatized/validated input and yoink the chan doc + const {chanName, command} = matchedData(req); + const chanDB = await channelModel.findOne({name: chanName}); - if(tokeDB != null){ - return errorHandler(res, `Toke command '!${command}' already exists!`); + //Check that the channel exists + if(chanDB == null){ + return errorHandler(res, "Channel not found!", "Bad Query"); + } + + //Check for duplicate toke commands + if(chanDB.tokeCommands.indexOf(command) != -1){ + return errorHandler(res, "Cannot add duplicate toke command."); } //Add the toke - await tokeCommandModel.create({command}); + chanDB.tokeCommands.push(command); + + //Save the channel document + await chanDB.save(); //Return the updated command list res.status(200); - return res.send(await tokeCommandModel.getCommandStrings());*/ + return res.send(chanDB.tokeCommands); }else{ //otherwise scream res.status(400); @@ -70,19 +86,32 @@ module.exports.delete = async function(req, res){ //if they're empty if(validResult.isEmpty()){ - /* - const {command} = matchedData(req); - const tokeDB = await tokeCommandModel.findOne({command}); + //Pull sanatized/validated input and yoink the chan doc + const {chanName, command} = matchedData(req); + const chanDB = await channelModel.findOne({name: chanName}); - if(tokeDB == null){ - return errorHandler(res, `Cannot delete non-existant toke command '!${command}'!`); + //Check that the channel exists + if(chanDB == null){ + return errorHandler(res, "Channel not found!", "Bad Query"); } - await tokeDB.deleteOne(); + //get index of the requested toke to delete + const tokeIndex = chanDB.tokeCommands.indexOf(command); + + //Make sure the toke exists + if(tokeIndex == -1){ + return errorHandler(res, "Cannot delete non-existant toke command."); + } + + //splice out the requested toke command + chanDB.tokeCommands.splice(tokeIndex,1); + + //Save the channel document + await chanDB.save(); //Return the updated command list res.status(200); - return res.send(await tokeCommandModel.getCommandStrings());*/ + return res.send(chanDB.tokeCommands); }else{ //otherwise scream res.status(400); diff --git a/src/routers/api/channelRouter.js b/src/routers/api/channelRouter.js index 2722938..e426e04 100644 --- a/src/routers/api/channelRouter.js +++ b/src/routers/api/channelRouter.js @@ -24,6 +24,7 @@ const channelModel = require("../../schemas/channel/channelSchema"); const channelValidator = require("../../validators/channelValidator"); const accountValidator = require("../../validators/accountValidator"); const {channelPermissionValidator} = require("../../validators/permissionsValidator"); +const tokebotValidator = require("../../validators/tokebotValidator"); const registerController = require("../../controllers/api/channel/registerController"); const listController = require("../../controllers/api/channel/listController"); const settingsController = require("../../controllers/api/channel/settingsController"); @@ -31,6 +32,7 @@ const permissionsController = require("../../controllers/api/channel/permissions const rankController = require("../../controllers/api/channel/rankController"); const deleteController = require("../../controllers/api/channel/deleteController"); const banController = require("../../controllers/api/channel/banController"); +const tokeCommandController = require("../../controllers/api/channel/tokeCommandController"); //globals const router = Router(); @@ -42,6 +44,7 @@ router.use("/permissions", channelValidator.name('chanName')); router.use("/rank", channelValidator.name('chanName')); router.use("/delete", channelValidator.name('chanName')); router.use("/ban", channelValidator.name('chanName')); +router.use("/tokeCommand", channelValidator.name('chanName')); //routing functions //register @@ -63,5 +66,9 @@ router.post('/delete', channelModel.reqPermCheck("deleteChannel"), channelValid router.get('/ban', channelModel.reqPermCheck("manageChannel"), banController.get); router.post('/ban', channelModel.reqPermCheck("banUser"), accountValidator.user(), body("banAlts").isBoolean(), body("expirationDays").isInt(), banController.post); router.delete('/ban', channelModel.reqPermCheck("banUser"), accountValidator.user(), banController.delete); +//tokeCommand +router.get('/tokeCommand', channelModel.reqPermCheck("manageChannel"), tokeCommandController.get); +router.post('/tokeCommand', tokebotValidator.command(), channelModel.reqPermCheck("editTokeCommands"), tokeCommandController.post); +router.delete('/tokeCommand', tokebotValidator.command(), channelModel.reqPermCheck("editTokeCommands"), tokeCommandController.delete); module.exports = router; \ No newline at end of file diff --git a/src/schemas/channel/channelPermissionSchema.js b/src/schemas/channel/channelPermissionSchema.js index 16f9c4d..a15dcbb 100644 --- a/src/schemas/channel/channelPermissionSchema.js +++ b/src/schemas/channel/channelPermissionSchema.js @@ -70,6 +70,12 @@ const channelPermissionSchema = new mongoose.Schema({ default: "admin", required: true }, + editTokeCommands: { + type: mongoose.SchemaTypes.String, + enum: rankEnum, + default: "admin", + required: true + }, deleteChannel: { type: mongoose.SchemaTypes.String, enum: rankEnum, diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js index ca13a8a..4b21de6 100644 --- a/src/schemas/channel/channelSchema.js +++ b/src/schemas/channel/channelSchema.js @@ -147,6 +147,19 @@ channelSchema.pre('save', async function (next){ } } + + //if the toke commands where changed + if(this.isModified("tokeCommands")){ + //Get the active Channel object from the application side of the house + const activeChannel = server.channelManager.activeChannels.get(this.name); + + //If the channel is active + if(activeChannel != null){ + //Reload the toke command list + activeChannel.tokeCommands = this.tokeCommands; + } + } + next(); }); @@ -218,8 +231,7 @@ channelSchema.statics.reqPermCheck = function(perm, chanField = "chanName"){ //If we didnt find a channel if(chanDB == null){ //FUCK - res.status(401); - return res.send({error:`Cannot perm check non-existant channel!.`}); + return errorHandler(res, "You cannot check permissions against a non-existant channel!", 'Unauthorized', 401); } //Run a perm check against the current user and permission diff --git a/src/schemas/tokebot/tokeCommandSchema.js b/src/schemas/tokebot/tokeCommandSchema.js index 4920c24..4d8fa3d 100644 --- a/src/schemas/tokebot/tokeCommandSchema.js +++ b/src/schemas/tokebot/tokeCommandSchema.js @@ -45,7 +45,7 @@ tokeCommandSchema.pre('save', async function (next){ }); tokeCommandSchema.pre('deleteOne', {document: true}, async function (next){ - //Get server tokebot object + //Get server tokebot object (isn't this a fun dot crawler? Why hasn't anyone asked me to stop writing software yet?) const tokebot = server.channelManager.chatHandler.commandPreprocessor.tokebot; //Get the index of the command within tokeCommand and splice it out diff --git a/src/validators/permissionsValidator.js b/src/validators/permissionsValidator.js index 1ff4662..0036e53 100644 --- a/src/validators/permissionsValidator.js +++ b/src/validators/permissionsValidator.js @@ -135,6 +135,12 @@ module.exports.channelPermissionValidator = { options: module.exports.isRank }, }, + 'channelPermissionsMap.editTokeCommands': { + optional: true, + custom: { + options: module.exports.isRank + } + }, 'channelPermissionsMap.deleteChannel': { optional: true, custom: { diff --git a/www/js/utils.js b/www/js/utils.js index b409fc0..86ae85d 100644 --- a/www/js/utils.js +++ b/www/js/utils.js @@ -28,10 +28,17 @@ class canopyUXUtils{ //Update this and popup class to use nodes //and display multiple errors in one popup displayResponseError(body){ - const errors = body.errors; - errors.forEach((err)=>{ - new canopyUXUtils.popup(`

Server Error:


${err.msg}

`); - }); + try{ + const errors = body.errors; + errors.forEach((err)=>{ + new canopyUXUtils.popup(`

Server Error:


${err.msg}

`); + }); + }catch(err){ + console.error("Display Error Error:"); + console.error(body); + console.error("Display Error Error:"); + console.error(err); + } } @@ -507,6 +514,53 @@ class canopyAjaxUtils{ utils.ux.displayResponseError(await response.json()); } } + + async getChanTokes(chanName){ + var response = await fetch(`/api/channel/tokeCommand?chanName=${chanName}`,{ + method: "GET", + headers: { + "Content-Type": "application/json" + } + }); + + if(response.status == 200){ + return await response.json(); + }else{ + utils.ux.displayResponseError(await response.json()); + } + } + + async addChanToke(chanName, command){ + var response = await fetch('/api/channel/tokeCommand',{ + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({chanName, command}) + }); + + if(response.status == 200){ + return await response.json(); + }else{ + utils.ux.displayResponseError(await response.json()); + } + } + + async deleteChanToke(chanName, command){ + var response = await fetch('/api/channel/tokeCommand',{ + method: "DELETE", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({chanName, command}) + }); + + if(response.status == 200){ + return await response.json(); + }else{ + utils.ux.displayResponseError(await response.json()); + } + } } const utils = new canopyUtils() \ No newline at end of file