diff --git a/src/controllers/api/admin/changeRankController.js b/src/controllers/api/admin/changeRankController.js
index ce2130c..ca34ff8 100644
--- a/src/controllers/api/admin/changeRankController.js
+++ b/src/controllers/api/admin/changeRankController.js
@@ -22,7 +22,7 @@ const {exceptionHandler} = require('../../../utils/loggerUtils');
const permissionModel = require('../../../schemas/permissionSchema');
const userModel = require('../../../schemas/userSchema');
-//api account functions
+//api change rank functions
module.exports.post = async function(req, res){
try{
const validResult = validationResult(req);
diff --git a/src/controllers/api/admin/listChannelsController.js b/src/controllers/api/admin/listChannelsController.js
index 138a42d..ed3f943 100644
--- a/src/controllers/api/admin/listChannelsController.js
+++ b/src/controllers/api/admin/listChannelsController.js
@@ -18,7 +18,7 @@ along with this program. If not, see .*/
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
const channelModel = require('../../../schemas/channelSchema.js');
-//api account functions
+//api list channel functions
module.exports.get = async function(req, res){
try{
const chanGuide = await channelModel.getChannelList(true);
diff --git a/src/controllers/api/admin/listPermissionsController.js b/src/controllers/api/admin/listPermissionsController.js
deleted file mode 100644
index c3ddd0e..0000000
--- a/src/controllers/api/admin/listPermissionsController.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*Canopy - The next generation of stoner streaming software
-Copyright (C) 2024 Rainbownapkin and the TTN Community
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .*/
-
-//local imports
-const {exceptionHandler} = require('../../../utils/loggerUtils.js');
-const permissionModel = require('../../../schemas/permissionSchema.js');
-
-//api account functions
-module.exports.get = async function(req, res){
- try{
- const perms = await permissionModel.getPerms();
-
- res.status(200);
- return res.send(perms);
- }catch(err){
- return exceptionHandler(res, err);
- }
-}
\ No newline at end of file
diff --git a/src/controllers/api/admin/listUsersController.js b/src/controllers/api/admin/listUsersController.js
index 624a957..4f057e8 100644
--- a/src/controllers/api/admin/listUsersController.js
+++ b/src/controllers/api/admin/listUsersController.js
@@ -18,7 +18,7 @@ along with this program. If not, see .*/
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
const userModel = require('../../../schemas/userSchema');
-//api account functions
+//api list account functions
module.exports.get = async function(req, res){
try{
const userList = await userModel.getUserList(true);
diff --git a/src/controllers/api/admin/permissionsController.js b/src/controllers/api/admin/permissionsController.js
new file mode 100644
index 0000000..d1c8399
--- /dev/null
+++ b/src/controllers/api/admin/permissionsController.js
@@ -0,0 +1,85 @@
+/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .*/
+
+//npm imports
+const {validationResult, matchedData} = require('express-validator');
+
+//local imports
+const {exceptionHandler} = require('../../../utils/loggerUtils.js');
+const permissionModel = require('../../../schemas/permissionSchema.js');
+
+//api permissions functions
+module.exports.get = async function(req, res){
+ try{
+ const perms = await permissionModel.getPerms();
+
+ res.status(200);
+ return res.send(perms);
+ }catch(err){
+ return exceptionHandler(res, err);
+ }
+}
+
+module.exports.post = async function(req, res){
+ try{
+ //check for validation errors
+ const validResult = validationResult(req);
+
+ //if none
+ if(validResult.isEmpty()){
+ //grab validated/sanatized data
+ const {permissionsMap} = matchedData(req);
+ const perms = await permissionModel.getPerms();
+ var permError = false;
+
+ //For each permission submitted
+ Object.keys(permissionsMap).forEach((perm) => {
+ //Check to make sure no one is jumping perms (this should be admins only, but just in-case)
+ //Setting a boolean inside of an if statement seems fucked, until you realize it won't set it back false on the next loop :P
+ if(permissionModel.rankToNum(perms[perm]) > permissionModel.rankToNum(req.session.user.rank) || permissionModel.rankToNum(permissionsMap[perm]) > permissionModel.rankToNum(req.session.user.rank)){
+ permError = true;
+ }
+
+ //Set permissions in the permissions model
+ perms[perm] = permissionsMap[perm];
+ });
+
+ //Flip our shit if something's wrong.
+ if(permError){
+ res.status(401);
+ return res.send({errors:[{type: "Unauthorized", msg: "New rank must be equal to or below that of the user changing it.", date: new Date()}]});
+ }
+
+ await perms.save();
+
+ //Cleanup return object
+ var returnObj = perms.toObject();
+
+ delete returnObj._id
+ delete returnObj.__v
+
+ //send successful response
+ res.status(200);
+ return res.send(returnObj);
+ //otherwise scream
+ }else{
+ res.status(400);
+ res.send({errors: validResult.array()})
+ }
+ }catch(err){
+ return exceptionHandler(res, err);
+ }
+}
\ No newline at end of file
diff --git a/src/routers/api/adminRouter.js b/src/routers/api/adminRouter.js
index 3af1d11..564e131 100644
--- a/src/routers/api/adminRouter.js
+++ b/src/routers/api/adminRouter.js
@@ -20,11 +20,12 @@ const { Router } = require('express');
//local imports
const accountValidator = require("../../validators/accountValidator");
+const {permissionsValidator} = require("../../validators/permissionsValidator");
const permissionSchema = require("../../schemas/permissionSchema");
const listUsersController = require("../../controllers/api/admin/listUsersController");
const listChannelsController = require("../../controllers/api/admin/listChannelsController");
const changeRankController = require("../../controllers/api/admin/changeRankController");
-const listPermissionsController = require("../../controllers/api/admin/listPermissionsController");
+const permissionsController = require("../../controllers/api/admin/permissionsController");
//globals
const router = Router();
@@ -35,7 +36,8 @@ router.use(permissionSchema.reqPermCheck("adminAPI"));
//routing functions
router.get('/listUsers', listUsersController.get);
router.get('/listChannels', listChannelsController.get);
-router.get('/listPermissions', listPermissionsController.get);
+router.get('/permissions', permissionsController.get);
+router.post('/permissions', permissionsValidator.permissionsMap(), permissionsController.post);
router.post('/changeRank', accountValidator.user(), accountValidator.rank(), changeRankController.post);
module.exports = router;
diff --git a/src/validators/accountValidator.js b/src/validators/accountValidator.js
index 063d895..d875abd 100644
--- a/src/validators/accountValidator.js
+++ b/src/validators/accountValidator.js
@@ -18,13 +18,7 @@ along with this program. If not, see .*/
const { check, body, checkSchema, checkExact} = require('express-validator');
//local imports
-const permissionSchema = require("../schemas/permissionSchema");
-
-function isRank(value){
- rankVal = permissionSchema.rankToNum(value);
-
- return rankVal != -1;
-}
+const {isRank} = require('./permissionsValidator');
module.exports = {
user: (field = 'user') => body(field).escape().trim().isLength({min: 1, max: 22}),
diff --git a/src/validators/permissionsValidator.js b/src/validators/permissionsValidator.js
new file mode 100644
index 0000000..738fa3b
--- /dev/null
+++ b/src/validators/permissionsValidator.js
@@ -0,0 +1,62 @@
+/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .*/
+
+//NPM Imports
+const { check, body, checkSchema, checkExact} = require('express-validator');
+
+//local imports
+const permissionSchema = require("../schemas/permissionSchema");
+
+module.exports.isRank = function(value){
+ rankVal = permissionSchema.rankToNum(value);
+
+ return rankVal != -1;
+}
+
+module.exports.permissionsValidator = {
+ permissionsMap: () => checkExact(checkSchema({
+ 'permissionsMap.adminPanel': {
+ optional: true,
+ custom: {
+ options: module.exports.isRank
+ },
+ },
+ 'permissionsMap.adminAPI': {
+ optional: true,
+ custom: {
+ options: module.exports.isRank
+ },
+ },
+ 'permissionsMap.registerChannel': {
+ optional: true,
+ custom: {
+ options: module.exports.isRank
+ },
+ },
+ 'permissionsMap.manageChannel': {
+ optional: true,
+ custom: {
+ options: module.exports.isRank
+ },
+ },
+ 'permissionsMap.deleteChannel': {
+ optional: true,
+ custom: {
+ options: module.exports.isRank
+ },
+ }
+ }))
+}
\ No newline at end of file
diff --git a/www/js/adminPanel.js b/www/js/adminPanel.js
index f7fe6e4..2813ccf 100644
--- a/www/js/adminPanel.js
+++ b/www/js/adminPanel.js
@@ -35,6 +35,23 @@ class canopyAdminUtils{
utils.ux.displayResponseError(await response.json());
}
}
+
+ async setPermission(permObj){
+ var response = await fetch(`/api/admin/permissions`,{
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ //Unfortunately JSON doesn't natively handle ES6 maps, and god forbid someone update the standard in a way that's backwards compatible...
+ body: JSON.stringify({permissionsMap: Object.fromEntries(permObj)})
+ });
+
+ if(response.status == 200){
+ return await response.json();
+ }else{
+ utils.ux.displayResponseError(await response.json());
+ }
+ }
}
class adminUserList{