Implemented custom per-channel !toke commands in back-end.

This commit is contained in:
rainbow napkin 2024-12-15 09:51:32 -05:00
parent 575244ac53
commit a1fbbea7b7
10 changed files with 159 additions and 29 deletions

View file

@ -20,9 +20,10 @@ const flairModel = require('../../schemas/flairSchema');
const permissionModel = require('../../schemas/permissionSchema'); const permissionModel = require('../../schemas/permissionSchema');
module.exports = class{ module.exports = class{
constructor(server, name){ constructor(server, chanDB){
this.server = server; 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 //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(); this.userList = new Map();
} }
@ -37,8 +38,11 @@ module.exports = class{
if(userObj){ if(userObj){
//Add this socket on to the userobject //Add this socket on to the userobject
userObj.sockets.push(socket.id); userObj.sockets.push(socket.id);
//If the user is joining the channel
}else{ }else{
//Grab flair
await userDB.populate('flair'); await userDB.populate('flair');
//Set user object
userObj = new connectedUser(userDB, chanRank, this, socket); userObj = new connectedUser(userDB, chanRank, this, socket);
} }

View file

@ -109,7 +109,7 @@ module.exports = class{
if(!activeChan){ if(!activeChan){
//If not, make it so //If not, make it so
activeChan = new activeChannel(this, socket.chan); activeChan = new activeChannel(this, chanDB);
this.activeChannels.set(socket.chan, activeChan); this.activeChannels.set(socket.chan, activeChan);
} }

View file

@ -52,10 +52,22 @@ module.exports = class tokebot{
} }
tokeProcessor(commandObj){ 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 we found a toke
if(foundToke != -1){ if(foundToke){
//If there is no active toke or cooldown (new toke) //If there is no active toke or cooldown (new toke)
if(this.tokeTimer == null && this.cooldownTimer == null){ if(this.tokeTimer == null && this.cooldownTimer == null){
//Call-out toke start //Call-out toke start

View file

@ -23,10 +23,17 @@ const channelModel = require('../../../schemas/channel/channelSchema');
module.exports.get = async function(req, res){ module.exports.get = async function(req, res){
try{ 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});
//if we found a channel in the DB
if(chanDB != null){
res.status(200); res.status(200);
return res.send(tokeList); return res.send(chanDB.tokeCommands);
}else{
return errorHandler(res, "Channel not found!", "Bad Query");
}
}catch(err){ }catch(err){
return exceptionHandler(res, err); return exceptionHandler(res, err);
} }
@ -39,20 +46,29 @@ module.exports.post = async function(req, res){
//if they're empty //if they're empty
if(validResult.isEmpty()){ if(validResult.isEmpty()){
/* //Pull sanatized/validated input and yoink the chan doc
const {command} = matchedData(req); const {chanName, command} = matchedData(req);
const tokeDB = await tokeCommandModel.findOne({command}); const chanDB = await channelModel.findOne({name: chanName});
if(tokeDB != null){ //Check that the channel exists
return errorHandler(res, `Toke command '!${command}' already 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 //Add the toke
await tokeCommandModel.create({command}); chanDB.tokeCommands.push(command);
//Save the channel document
await chanDB.save();
//Return the updated command list //Return the updated command list
res.status(200); res.status(200);
return res.send(await tokeCommandModel.getCommandStrings());*/ return res.send(chanDB.tokeCommands);
}else{ }else{
//otherwise scream //otherwise scream
res.status(400); res.status(400);
@ -70,19 +86,32 @@ module.exports.delete = async function(req, res){
//if they're empty //if they're empty
if(validResult.isEmpty()){ if(validResult.isEmpty()){
/* //Pull sanatized/validated input and yoink the chan doc
const {command} = matchedData(req); const {chanName, command} = matchedData(req);
const tokeDB = await tokeCommandModel.findOne({command}); const chanDB = await channelModel.findOne({name: chanName});
if(tokeDB == null){ //Check that the channel exists
return errorHandler(res, `Cannot delete non-existant toke command '!${command}'!`); 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 //Return the updated command list
res.status(200); res.status(200);
return res.send(await tokeCommandModel.getCommandStrings());*/ return res.send(chanDB.tokeCommands);
}else{ }else{
//otherwise scream //otherwise scream
res.status(400); res.status(400);

View file

@ -24,6 +24,7 @@ const channelModel = require("../../schemas/channel/channelSchema");
const channelValidator = require("../../validators/channelValidator"); const channelValidator = require("../../validators/channelValidator");
const accountValidator = require("../../validators/accountValidator"); const accountValidator = require("../../validators/accountValidator");
const {channelPermissionValidator} = require("../../validators/permissionsValidator"); const {channelPermissionValidator} = require("../../validators/permissionsValidator");
const tokebotValidator = require("../../validators/tokebotValidator");
const registerController = require("../../controllers/api/channel/registerController"); const registerController = require("../../controllers/api/channel/registerController");
const listController = require("../../controllers/api/channel/listController"); const listController = require("../../controllers/api/channel/listController");
const settingsController = require("../../controllers/api/channel/settingsController"); 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 rankController = require("../../controllers/api/channel/rankController");
const deleteController = require("../../controllers/api/channel/deleteController"); const deleteController = require("../../controllers/api/channel/deleteController");
const banController = require("../../controllers/api/channel/banController"); const banController = require("../../controllers/api/channel/banController");
const tokeCommandController = require("../../controllers/api/channel/tokeCommandController");
//globals //globals
const router = Router(); const router = Router();
@ -42,6 +44,7 @@ router.use("/permissions", channelValidator.name('chanName'));
router.use("/rank", channelValidator.name('chanName')); router.use("/rank", channelValidator.name('chanName'));
router.use("/delete", channelValidator.name('chanName')); router.use("/delete", channelValidator.name('chanName'));
router.use("/ban", channelValidator.name('chanName')); router.use("/ban", channelValidator.name('chanName'));
router.use("/tokeCommand", channelValidator.name('chanName'));
//routing functions //routing functions
//register //register
@ -63,5 +66,9 @@ router.post('/delete', channelModel.reqPermCheck("deleteChannel"), channelValid
router.get('/ban', channelModel.reqPermCheck("manageChannel"), banController.get); 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.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); 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; module.exports = router;

View file

@ -70,6 +70,12 @@ const channelPermissionSchema = new mongoose.Schema({
default: "admin", default: "admin",
required: true required: true
}, },
editTokeCommands: {
type: mongoose.SchemaTypes.String,
enum: rankEnum,
default: "admin",
required: true
},
deleteChannel: { deleteChannel: {
type: mongoose.SchemaTypes.String, type: mongoose.SchemaTypes.String,
enum: rankEnum, enum: rankEnum,

View file

@ -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(); next();
}); });
@ -218,8 +231,7 @@ channelSchema.statics.reqPermCheck = function(perm, chanField = "chanName"){
//If we didnt find a channel //If we didnt find a channel
if(chanDB == null){ if(chanDB == null){
//FUCK //FUCK
res.status(401); return errorHandler(res, "You cannot check permissions against a non-existant channel!", 'Unauthorized', 401);
return res.send({error:`Cannot perm check non-existant channel!.`});
} }
//Run a perm check against the current user and permission //Run a perm check against the current user and permission

View file

@ -45,7 +45,7 @@ tokeCommandSchema.pre('save', async function (next){
}); });
tokeCommandSchema.pre('deleteOne', {document: true}, 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; const tokebot = server.channelManager.chatHandler.commandPreprocessor.tokebot;
//Get the index of the command within tokeCommand and splice it out //Get the index of the command within tokeCommand and splice it out

View file

@ -135,6 +135,12 @@ module.exports.channelPermissionValidator = {
options: module.exports.isRank options: module.exports.isRank
}, },
}, },
'channelPermissionsMap.editTokeCommands': {
optional: true,
custom: {
options: module.exports.isRank
}
},
'channelPermissionsMap.deleteChannel': { 'channelPermissionsMap.deleteChannel': {
optional: true, optional: true,
custom: { custom: {

View file

@ -28,10 +28,17 @@ class canopyUXUtils{
//Update this and popup class to use nodes //Update this and popup class to use nodes
//and display multiple errors in one popup //and display multiple errors in one popup
displayResponseError(body){ displayResponseError(body){
try{
const errors = body.errors; const errors = body.errors;
errors.forEach((err)=>{ errors.forEach((err)=>{
new canopyUXUtils.popup(`<h3>Server Error:</h3><p><br>${err.msg}</p>`); new canopyUXUtils.popup(`<h3>Server Error:</h3><p><br>${err.msg}</p>`);
}); });
}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()); 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() const utils = new canopyUtils()