Finished basic channel ban DB mgmt and ajax calls.
This commit is contained in:
parent
2b52fe7f2f
commit
ef79e9941c
99
src/controllers/api/channel/banController.js
Normal file
99
src/controllers/api/channel/banController.js
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*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 <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
|
//NPM Imports
|
||||||
|
const {validationResult, matchedData} = require('express-validator');
|
||||||
|
|
||||||
|
//local imports
|
||||||
|
const {exceptionHandler} = require('../../../utils/loggerUtils.js');
|
||||||
|
const {userModel} = require('../../../schemas/userSchema.js');
|
||||||
|
const channelModel = require('../../../schemas/channel/channelSchema');
|
||||||
|
|
||||||
|
//api account functions
|
||||||
|
module.exports.get = async function(req, res){
|
||||||
|
try{
|
||||||
|
//Get validation result
|
||||||
|
const validResult = validationResult(req);
|
||||||
|
|
||||||
|
//If we data is valid
|
||||||
|
if(validResult.isEmpty()){
|
||||||
|
//Set channel object from sanatized/validated data, and get user document from session data
|
||||||
|
const {chanName} = matchedData(req);
|
||||||
|
const chanDB = await channelModel.findOne({name: chanName});
|
||||||
|
|
||||||
|
res.status(200);
|
||||||
|
return res.send(await chanDB.getChanBans());
|
||||||
|
}else{
|
||||||
|
res.status(400);
|
||||||
|
res.send({errors: validResult.array()})
|
||||||
|
}
|
||||||
|
}catch(err){
|
||||||
|
exceptionHandler(res, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.post = async function(req, res){
|
||||||
|
try{
|
||||||
|
//Get validation result
|
||||||
|
const validResult = validationResult(req);
|
||||||
|
|
||||||
|
//If we data is valid
|
||||||
|
if(validResult.isEmpty()){
|
||||||
|
//Set channel object from sanatized/validated data, and get user document from session data
|
||||||
|
const {chanName, user, expirationDays, banAlts} = matchedData(req);
|
||||||
|
const userDB = await userModel.findOne({user});
|
||||||
|
const chanDB = await channelModel.findOne({name: chanName});
|
||||||
|
|
||||||
|
await chanDB.banByUserDoc(userDB, expirationDays, banAlts);
|
||||||
|
|
||||||
|
res.status(200);
|
||||||
|
return res.send(await chanDB.getChanBans());
|
||||||
|
}else{
|
||||||
|
res.status(400);
|
||||||
|
res.send({errors: validResult.array()})
|
||||||
|
}
|
||||||
|
}catch(err){
|
||||||
|
exceptionHandler(res, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.delete = async function(req, res){
|
||||||
|
try{
|
||||||
|
//Get validation result
|
||||||
|
const validResult = validationResult(req);
|
||||||
|
|
||||||
|
//If we data is valid
|
||||||
|
if(validResult.isEmpty()){
|
||||||
|
//Set channel object from sanatized/validated data, and get user document from session data
|
||||||
|
const {chanName, user} = matchedData(req);
|
||||||
|
const userDB = await userModel.findOne({user});
|
||||||
|
const chanDB = await channelModel.findOne({name: chanName});
|
||||||
|
|
||||||
|
await chanDB.unbanByUserDoc(userDB);
|
||||||
|
|
||||||
|
res.status(200);
|
||||||
|
return res.send(await chanDB.getChanBans());
|
||||||
|
}else{
|
||||||
|
res.status(400);
|
||||||
|
res.send({errors: validResult.array()})
|
||||||
|
}
|
||||||
|
}catch(err){
|
||||||
|
exceptionHandler(res, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
//npm imports
|
//npm imports
|
||||||
|
const { body } = require('express-validator');
|
||||||
const { Router } = require('express');
|
const { Router } = require('express');
|
||||||
|
|
||||||
//local imports
|
//local imports
|
||||||
|
|
@ -29,6 +30,7 @@ const settingsController = require("../../controllers/api/channel/settingsContro
|
||||||
const permissionsController = require("../../controllers/api/channel/permissionsController")
|
const permissionsController = require("../../controllers/api/channel/permissionsController")
|
||||||
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");
|
||||||
|
|
||||||
//globals
|
//globals
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
@ -38,16 +40,28 @@ router.use("/register",permissionSchema.reqPermCheck("registerChannel"));
|
||||||
router.use("/settings", channelValidator.name('chanName'), channelModel.reqPermCheck("manageChannel"));
|
router.use("/settings", channelValidator.name('chanName'), channelModel.reqPermCheck("manageChannel"));
|
||||||
router.use("/permissions", channelValidator.name('chanName'), channelModel.reqPermCheck("manageChannel"));
|
router.use("/permissions", channelValidator.name('chanName'), channelModel.reqPermCheck("manageChannel"));
|
||||||
router.use("/rank", channelValidator.name('chanName'), channelModel.reqPermCheck("manageChannel"));
|
router.use("/rank", channelValidator.name('chanName'), channelModel.reqPermCheck("manageChannel"));
|
||||||
|
router.use("/delete", channelValidator.name('chanName'), channelModel.reqPermCheck("deleteChannel"));
|
||||||
|
router.use("/ban", channelValidator.name('chanName'), channelModel.reqPermCheck("manageChannel"));
|
||||||
|
|
||||||
//routing functions
|
//routing functions
|
||||||
|
//register
|
||||||
router.post('/register', channelValidator.name(), channelValidator.description(), channelValidator.thumbnail(), registerController.post);
|
router.post('/register', channelValidator.name(), channelValidator.description(), channelValidator.thumbnail(), registerController.post);
|
||||||
|
//list
|
||||||
router.get('/list', listController.get);
|
router.get('/list', listController.get);
|
||||||
|
//settings
|
||||||
router.get('/settings', settingsController.get);
|
router.get('/settings', settingsController.get);
|
||||||
router.post('/settings', channelValidator.settingsMap(), settingsController.post);
|
router.post('/settings', channelValidator.settingsMap(), settingsController.post);
|
||||||
|
//permissions
|
||||||
router.get('/permissions', permissionsController.get);
|
router.get('/permissions', permissionsController.get);
|
||||||
router.post('/permissions', channelPermissionValidator.channelPermissionsMap(), permissionsController.post);
|
router.post('/permissions', channelPermissionValidator.channelPermissionsMap(), permissionsController.post);
|
||||||
|
//rank
|
||||||
router.get('/rank', rankController.get);
|
router.get('/rank', rankController.get);
|
||||||
router.post('/rank', accountValidator.user(), channelValidator.rank(), rankController.post);
|
router.post('/rank', accountValidator.user(), channelValidator.rank(), rankController.post);
|
||||||
router.post('/delete', channelValidator.name('chanName'), channelValidator.name('confirm'), channelModel.reqPermCheck("deleteChannel"), deleteController.post);
|
//delete
|
||||||
|
router.post('/delete', channelValidator.name('confirm'), deleteController.post);
|
||||||
|
//ban
|
||||||
|
router.get('/ban', banController.get);
|
||||||
|
router.post('/ban', accountValidator.user(), body("banAlts").isBoolean(), body("expirationDays").isInt(), banController.post);
|
||||||
|
router.delete('/ban', accountValidator.user(), banController.delete);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
@ -67,6 +67,29 @@ const channelSchema = new mongoose.Schema({
|
||||||
required: true,
|
required: true,
|
||||||
enum: permissionModel.rankEnum
|
enum: permissionModel.rankEnum
|
||||||
}
|
}
|
||||||
|
}],
|
||||||
|
//Thankfully we don't have to keep track of alts, ips, or deleted users so this should be a little easier :P
|
||||||
|
banList: [{
|
||||||
|
user: {
|
||||||
|
type: mongoose.SchemaTypes.ObjectID,
|
||||||
|
required: true,
|
||||||
|
ref: "user"
|
||||||
|
},
|
||||||
|
banDate: {
|
||||||
|
type: mongoose.SchemaTypes.Date,
|
||||||
|
required: true,
|
||||||
|
default: new Date()
|
||||||
|
},
|
||||||
|
expirationDays: {
|
||||||
|
type: mongoose.SchemaTypes.Number,
|
||||||
|
required: true,
|
||||||
|
default: 14
|
||||||
|
},
|
||||||
|
banAlts: {
|
||||||
|
type: mongoose.SchemaTypes.Boolean,
|
||||||
|
required: true,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -323,6 +346,113 @@ channelSchema.methods.permCheck = async function (user, perm){
|
||||||
return await this.permCheckByUserDoc(userDB, perm)
|
return await this.permCheckByUserDoc(userDB, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channelSchema.methods.checkBanByUserDoc = async function(userDB){
|
||||||
|
var foundBan = null;
|
||||||
|
|
||||||
|
this.banList.forEach((ban) => {
|
||||||
|
if(ban.user != null){
|
||||||
|
if(ban.user.toString() == userDB._id.toString()){
|
||||||
|
foundBan = ban;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return foundBan;
|
||||||
|
}
|
||||||
|
|
||||||
|
channelSchema.methods.getChanBans = async function(){
|
||||||
|
//Create an empty list to hold our found bans
|
||||||
|
var banList = [];
|
||||||
|
//Populate the users in the banList
|
||||||
|
await this.populate('banList.user');
|
||||||
|
|
||||||
|
//Crawl through known bans
|
||||||
|
this.banList.forEach((ban) => {
|
||||||
|
|
||||||
|
var banObj = {
|
||||||
|
banDate: ban.banDate,
|
||||||
|
expirationDays: ban.expirationDays,
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the ban was permanent (expiration set before ban date)
|
||||||
|
if(ban.expirationDays > 0){
|
||||||
|
//if not calculate expiration date
|
||||||
|
var expirationDate = new Date(ban.banDate);
|
||||||
|
expirationDate.setDate(expirationDate.getDate() + ban.expirationDays);
|
||||||
|
|
||||||
|
//Set calculated expiration date
|
||||||
|
banObj.expirationDate = expirationDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Setup user object (Do this last to keep it at bottom for human-readibility of json :P)
|
||||||
|
banObj.user = {
|
||||||
|
id: ban.user.id,
|
||||||
|
user: ban.user.user,
|
||||||
|
img: ban.user.img,
|
||||||
|
date: ban.user.date
|
||||||
|
}
|
||||||
|
|
||||||
|
banList.push(banObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
return banList;
|
||||||
|
}
|
||||||
|
|
||||||
|
channelSchema.methods.banByUserDoc = async function(userDB, expirationDays, banAlts){
|
||||||
|
//Throw a shitfit if the user doesn't exist
|
||||||
|
if(userDB == null){
|
||||||
|
throw new Error("Cannot ban non-existant user!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundBan = await this.checkBanByUserDoc(userDB);
|
||||||
|
|
||||||
|
if(foundBan != null){
|
||||||
|
throw new Error("User already banned!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a new ban document based on input
|
||||||
|
const banDoc = {
|
||||||
|
user: userDB._id,
|
||||||
|
expirationDays,
|
||||||
|
banAlts
|
||||||
|
}
|
||||||
|
|
||||||
|
//Push the ban to the list
|
||||||
|
this.banList.push(banDoc);
|
||||||
|
|
||||||
|
await this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
channelSchema.methods.ban = async function(user, expirationDays, banAlts){
|
||||||
|
const userDB = await userModel.find({user});
|
||||||
|
return await this.banByUserDoc(userDB, expirationDays, banAlts);
|
||||||
|
}
|
||||||
|
|
||||||
|
channelSchema.methods.unbanByUserDoc = async function(userDB){
|
||||||
|
//Throw a shitfit if the user doesn't exist
|
||||||
|
if(userDB == null){
|
||||||
|
throw new Error("Cannot ban non-existant user!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundBan = await this.checkBanByUserDoc(userDB);
|
||||||
|
|
||||||
|
if(foundBan == null){
|
||||||
|
throw new Error("User already unbanned!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//You know I can't help but feel like an asshole for looking for the index of something I just pulled out of an array using forEach...
|
||||||
|
//Then again this is such an un-used function that the issue of code re-use overshadows performance
|
||||||
|
//I mean how often are we REALLY going to be un-banning users from channels?
|
||||||
|
const banIndex = this.banList.indexOf(foundBan);
|
||||||
|
this.banList.splice(banIndex,1);
|
||||||
|
return await this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
channelSchema.methods.unban = async function(user){
|
||||||
|
const userDB = await userModel.find({user});
|
||||||
|
return await this.unbanByUserDoc(userDB);
|
||||||
|
}
|
||||||
|
|
||||||
channelSchema.methods.nuke = async function(confirm){
|
channelSchema.methods.nuke = async function(confirm){
|
||||||
if(confirm == "" || confirm == null){
|
if(confirm == "" || confirm == null){
|
||||||
throw new Error("Empty Confirmation String!");
|
throw new Error("Empty Confirmation String!");
|
||||||
|
|
|
||||||
|
|
@ -324,8 +324,8 @@ class canopyAjaxUtils{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getChannelRank(channel){
|
async getChannelRank(chanName){
|
||||||
var response = await fetch(`/api/channel/rank?chanName=${channel}`,{
|
var response = await fetch(`/api/channel/rank?chanName=${chanName}`,{
|
||||||
method: "GET"
|
method: "GET"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -380,6 +380,53 @@ class canopyAjaxUtils{
|
||||||
utils.ux.displayResponseError(await response.json());
|
utils.ux.displayResponseError(await response.json());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getChanBans(chanName){
|
||||||
|
var response = await fetch(`/api/channel/ban?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 chanBan(chanName, user, expirationDays, banAlts){
|
||||||
|
var response = await fetch(`/api/channel/ban`,{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({chanName, user, expirationDays, banAlts})
|
||||||
|
});
|
||||||
|
|
||||||
|
if(response.status == 200){
|
||||||
|
return await response.json();
|
||||||
|
}else{
|
||||||
|
utils.ux.displayResponseError(await response.json());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async chanUnban(chanName, user){
|
||||||
|
var response = await fetch(`/api/channel/ban`,{
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({chanName, user})
|
||||||
|
});
|
||||||
|
|
||||||
|
if(response.status == 200){
|
||||||
|
return await response.json();
|
||||||
|
}else{
|
||||||
|
utils.ux.displayResponseError(await response.json());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const utils = new canopyUtils()
|
const utils = new canopyUtils()
|
||||||
Loading…
Reference in a new issue