Worked ban frontend and api.
This commit is contained in:
parent
5c936462a6
commit
c848994c1d
18 changed files with 513 additions and 41 deletions
|
|
@ -36,6 +36,31 @@ module.exports.get = async function(req, res){
|
|||
}
|
||||
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
if(validResult.isEmpty()){
|
||||
const {user, permanent, expirationDays} = matchedData(req);
|
||||
const userDB = await userModel.findOne({user});
|
||||
|
||||
if(userDB == null){
|
||||
res.status(400);
|
||||
return res.send({errors:[{type: "Bad Query", msg: "User not found.", date: new Date()}]});
|
||||
}
|
||||
|
||||
await banModel.banByUserDoc(userDB, permanent, expirationDays);
|
||||
|
||||
res.status(200);
|
||||
return res.send(await banModel.getBans());
|
||||
}else{
|
||||
res.status(400);
|
||||
return res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
return exceptionHandler(res, err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.delete = async function(req, res){
|
||||
try{
|
||||
const validResult = validationResult(req);
|
||||
if(validResult.isEmpty()){
|
||||
|
|
@ -44,11 +69,13 @@ module.exports.post = async function(req, res){
|
|||
|
||||
if(userDB == null){
|
||||
res.status(400);
|
||||
res.send({errors:[{type: "Bad Query", msg: "User not found.", date: new Date()}]});
|
||||
return res.send({errors:[{type: "Bad Query", msg: "User not found.", date: new Date()}]});
|
||||
}
|
||||
|
||||
await banModel.banByUserDoc(userDB);
|
||||
await banModel.unbanByUserDoc(userDB);
|
||||
|
||||
res.status(200);
|
||||
return res.send(await banModel.getBans());
|
||||
}else{
|
||||
res.status(400);
|
||||
return res.send({errors: validResult.array()})
|
||||
|
|
|
|||
20
src/controllers/popup/placeholderController.js
Normal file
20
src/controllers/popup/placeholderController.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*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/>.*/
|
||||
|
||||
//root index functions
|
||||
module.exports.get = async function(req, res){
|
||||
res.render('partial/popup/placeholder', {});
|
||||
}
|
||||
20
src/controllers/popup/userBanController.js
Normal file
20
src/controllers/popup/userBanController.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*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/>.*/
|
||||
|
||||
//root index functions
|
||||
module.exports.get = async function(req, res){
|
||||
res.render('partial/popup/userBan');
|
||||
}
|
||||
|
|
@ -15,7 +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/>.*/
|
||||
|
||||
//npm imports
|
||||
const { checkExact } = require('express-validator');
|
||||
const { body, checkExact} = require('express-validator');
|
||||
const { Router } = require('express');
|
||||
|
||||
|
||||
|
|
@ -42,6 +42,8 @@ router.get('/permissions', permissionsController.get);
|
|||
router.post('/permissions', checkExact([permissionsValidator.permissionsMap(), channelPermissionValidator.channelPermissionsMap()]), permissionsController.post);
|
||||
router.post('/changeRank', accountValidator.user(), accountValidator.rank(), changeRankController.post);
|
||||
router.get('/ban', banController.get);
|
||||
router.post('/ban', accountValidator.user(), banController.post);
|
||||
//Sometimes they're so simple you don't need to put your validators in their own special place :P
|
||||
router.post('/ban', accountValidator.user(), body("permanent").isBoolean(), body("expirationDays").isInt(), banController.post);
|
||||
router.delete('/ban', accountValidator.user(), banController.delete);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
32
src/routers/popupRouter.js
Normal file
32
src/routers/popupRouter.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*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 { Router } = require('express');
|
||||
|
||||
|
||||
//local imports
|
||||
const placeholderController = require("../controllers/popup/placeholderController");
|
||||
const userBanController = require("../controllers/popup/userBanController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
||||
//routing functions
|
||||
router.get('/placeholder', placeholderController.get);
|
||||
router.get('/userBan', userBanController.get);
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -48,7 +48,7 @@ const userBanSchema = new mongoose.Schema({
|
|||
default: 30
|
||||
},
|
||||
//If true, then expiration date deletes associated accounts instead of deleting the ban record
|
||||
deleteAccountOnExpire: {
|
||||
permanent: {
|
||||
type: mongoose.SchemaTypes.Boolean,
|
||||
required: true,
|
||||
default: false
|
||||
|
|
@ -73,17 +73,58 @@ userBanSchema.statics.checkBan = async function(user){
|
|||
return this.checkBanByUserDoc(userDB);
|
||||
}
|
||||
|
||||
userBanSchema.statics.banByUserDoc = async function(userDB){
|
||||
userBanSchema.statics.banByUserDoc = async function(userDB, permanent, expirationDays){
|
||||
//Prevent missing users
|
||||
if(userDB == null){
|
||||
throw new Error("User not found")
|
||||
}
|
||||
|
||||
//Ensure the user isn't already banned
|
||||
if(await this.checkBanByUserDoc(userDB) != null){
|
||||
throw new Error("User already banned");
|
||||
}
|
||||
|
||||
return await this.create({user: userDB._id});
|
||||
if(expirationDays < 0){
|
||||
throw new Error("Expiration Days must be a positive integer!");
|
||||
}else if(expirationDays < 30 && permanent){
|
||||
throw new Error("Permanent bans must be given at least 30 days before automatic account deletion!");
|
||||
}else if(expirationDays > 185){
|
||||
throw new Error("Expiration/Deletion date cannot be longer than half a year out from the original ban date.");
|
||||
}
|
||||
|
||||
//Log the user out
|
||||
await userDB.killAllSessions();
|
||||
|
||||
//Add the ban to the database
|
||||
return await this.create({user: userDB._id, permanent, expirationDays});
|
||||
}
|
||||
|
||||
userBanSchema.statics.ban = async function(user){
|
||||
userBanSchema.statics.ban = async function(user, permanent, expirationDays){
|
||||
const userDB = await userModel.findOne({user: user.user});
|
||||
return this.banByUserDoc(userDB);
|
||||
return this.banByUserDoc(userDB, permanent, expirationDays);
|
||||
}
|
||||
|
||||
userBanSchema.statics.unbanByUserDoc = async function(userDB){
|
||||
|
||||
//Prevent missing users
|
||||
if(userDB == null){
|
||||
throw new Error("User not found")
|
||||
}
|
||||
|
||||
const ban = await this.checkBanByUserDoc(userDB);
|
||||
|
||||
if(!ban){
|
||||
throw new Error("User already un-banned");
|
||||
}
|
||||
|
||||
//Use _id in-case mongoose wants to be a cunt
|
||||
var oldBan = await this.deleteOne({_id: ban._id});
|
||||
return oldBan;
|
||||
}
|
||||
|
||||
userBanSchema.statics.unban = async function(user){
|
||||
const userDB = await userModel.findOne({user: user.user});
|
||||
return this.unbanByUserDoc(userDB);
|
||||
}
|
||||
|
||||
userBanSchema.statics.getBans = async function(){
|
||||
|
|
@ -109,7 +150,7 @@ userBanSchema.statics.getBans = async function(){
|
|||
user: userObj,
|
||||
ips: ban.ips,
|
||||
alts: ban.alts,
|
||||
deleteAccountOnExpire: ban.deleteAccountOnExpire
|
||||
permanent: ban.permanent
|
||||
}
|
||||
|
||||
bans.push(banObj);
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ userSchema.statics.getUserList = async function(fullList = false){
|
|||
//create a user object with limited properties (safe for public consumption)
|
||||
var userObj = {
|
||||
id: user.id,
|
||||
name: user.user,
|
||||
user: user.user,
|
||||
img: user.img,
|
||||
date: user.date
|
||||
}
|
||||
|
|
@ -270,7 +270,7 @@ userSchema.methods.nuke = async function(pass){
|
|||
|
||||
if(this.checkPass(pass)){
|
||||
//Annoyingly there isnt a good way to do this from 'this'
|
||||
var oldUser = await module.exports.deleteOne(this);
|
||||
var oldUser = await module.exports.userModel.deleteOne(this);
|
||||
|
||||
if(oldUser){
|
||||
await this.killAllSessions();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const adminPanelRouter = require('./routers/adminPanelRouter');
|
|||
const channelRouter = require('./routers/channelRouter');
|
||||
const newChannelRouter = require('./routers/newChannelRouter');
|
||||
const panelRouter = require('./routers/panelRouter');
|
||||
const popupRouter = require('./routers/popupRouter');
|
||||
const apiRouter = require('./routers/apiRouter');
|
||||
|
||||
//Define Config
|
||||
|
|
@ -92,6 +93,8 @@ app.use('/c', channelRouter);
|
|||
app.use('/newChannel', newChannelRouter);
|
||||
//Panel
|
||||
app.use('/panel', panelRouter);
|
||||
//Popup
|
||||
app.use('/popup', popupRouter);
|
||||
//Bot-Ready
|
||||
app.use('/api', apiRouter);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<td id="admin-ban-list-entry-expiration-type-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>Expiration Action</h3>
|
||||
</td>
|
||||
<td id="admin-ban-list-entry-actions-type-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>Actions</h3>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -29,33 +29,36 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<td id="admin-user-list-entry-rank-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>Rank</h3>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-rank-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<td id="admin-user-list-entry-mail-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>E-Mail</h3>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-rank-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<td id="admin-user-list-entry-date-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>Sign-Up Date</h3>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-control-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>Actions</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<% userList.forEach((curUser) => { %>
|
||||
<tr id="admin-user-list-entry-<%- curUser.name %>" class="admin-list-entry">
|
||||
<td id="admin-user-list-entry-img-<%- curUser.name %>" class="admin-list-entry admin-list-entry-item">
|
||||
<a href="/profile/<%- curUser.name %>" class="admin-list-entry admin-list-entry-item">
|
||||
<img id="admin-user-list-entry-img-<%- curUser.name %>" class="admin-list-entry admin-list-entry-item" src="<%- curUser.img %>">
|
||||
<tr id="admin-user-list-entry-<%- curUser.user %>" class="admin-list-entry">
|
||||
<td id="admin-user-list-entry-img-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item">
|
||||
<a href="/profile/<%- curUser.user %>" class="admin-list-entry admin-list-entry-item">
|
||||
<img id="admin-user-list-entry-img-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item" src="<%- curUser.img %>">
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-id-<%- curUser.name %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<a href="/profile/<%- curUser.name %>" class="admin-list-entry admin-list-entry-item">
|
||||
<td id="admin-user-list-entry-id-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<a href="/profile/<%- curUser.user %>" class="admin-list-entry admin-list-entry-item">
|
||||
<%- curUser.id %>
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-name-<%- curUser.name %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<a href="/profile/<%- curUser.name %>" class="admin-list-entry admin-list-entry-item">
|
||||
<%- curUser.name %>
|
||||
<td id="admin-user-list-entry-name-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<a href="/profile/<%- curUser.user %>" class="admin-list-entry admin-list-entry-item">
|
||||
<%- curUser.user %>
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-rank-<%- curUser.name %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<td id="admin-user-list-entry-rank-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<% if(rankEnum.indexOf(curUser.rank) < rankEnum.indexOf(user.rank)){%>
|
||||
<select id="admin-user-list-rank-select-<%- curUser.name %>" class="admin-user-list-rank-select">
|
||||
<select id="admin-user-list-rank-select-<%- curUser.user %>" class="admin-user-list-rank-select">
|
||||
<%rankEnum.slice().reverse().forEach((rank)=>{ %>
|
||||
<option <%if(curUser.rank == rank){%> selected <%}%> value="<%- rank %>"><%- rank %></option>
|
||||
<% }); %>
|
||||
|
|
@ -64,12 +67,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<%- curUser.rank %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-email-<%- curUser.name %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<td id="admin-user-list-entry-email-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<%- curUser.email ? curUser.email : "N/A" %>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-date-<%- curUser.name %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<td id="admin-user-list-entry-date-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<%- curUser.date.toUTCString() %>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-action-<%- curUser.user %>" class="admin-list-entry admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<!-- It's either this or add whitespce >:( -->
|
||||
<i class="bi-radioactive admin-user-list-icon admin-user-list-nuke-icon" id="admin-user-list-nuke-icon-<%- curUser.user %>" title="Nuke Account: <%- curUser.user %>"></i><i class="bi-fire admin-user-list-icon admin-user-list-ban-icon" id="admin-user-list-ban-icon-<%- curUser.user %>" title="Ban User: <%- curUser.user %>"></i><i class="bi-arrow-clockwise admin-user-list-icon admin-user-list-pw-reset-icon" id="admin-user-list-pw-reset-icon-<%- curUser.user %>" title="Generate Password Reset Link for <%- curUser.user %>"></i>
|
||||
</td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
</table>
|
||||
|
|
|
|||
16
src/views/partial/popup/placeholder.ejs
Normal file
16
src/views/partial/popup/placeholder.ejs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!--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/>.-->
|
||||
<h1>This is a test popup!</h1>
|
||||
33
src/views/partial/popup/userBan.ejs
Normal file
33
src/views/partial/popup/userBan.ejs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<!--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/>.-->
|
||||
<link rel="stylesheet" type="text/css" href="/css/popup/userBan.css">
|
||||
<h3 class="popup-title">Ban NULL</h3>
|
||||
<form class="ban-popup-content" action="javascript:">
|
||||
<span>
|
||||
<label for="ban-popup-perm">Perma-Ban:</label>
|
||||
<input type="checkbox" name="ban-popup-perm" id="ban-popup-perm">
|
||||
</span>
|
||||
<span>
|
||||
<label id="ban-popup-expiration-prefix" for="ban-popup-expiration">Ban Expires In: </label>
|
||||
<input type="number" name="ban-popup-expiration" id="ban-popup-expiration" value="14">
|
||||
<label fid="ban-popup-expiration-postfix" or="ban-popup-expiration"> Days</label>
|
||||
</span>
|
||||
<span id="ban-popup-button-span">
|
||||
<button id="ban-popup-cancel-button">Cancel</button>
|
||||
<span id="ban-popup-button-span-spacer"></span>
|
||||
<button id="ban-popup-ban-button">Ban</button>
|
||||
</span>
|
||||
</form>
|
||||
Loading…
Add table
Add a link
Reference in a new issue