Finished up implementing channel-based user bans.
This commit is contained in:
parent
ef79e9941c
commit
96953979a2
19 changed files with 518 additions and 202 deletions
|
|
@ -46,6 +46,19 @@ module.exports = class{
|
|||
//Get the active channel based on the socket
|
||||
var {activeChan, chanDB} = await this.getActiveChan(socket);
|
||||
|
||||
//Check for ban
|
||||
const ban = await chanDB.checkBanByUserDoc(userDB);
|
||||
if(ban != null){
|
||||
//Toss out banned user's
|
||||
if(ban.expirationDays < 0){
|
||||
socket.emit("kick", {type: "Unauthorized", reason: "You have been permanently banned from this channel!"});
|
||||
}else{
|
||||
socket.emit("kick", {type: "Unauthorized", reason: `You have been temporarily banned from this channel, and will be unbanned in ${ban.getDaysUntilExpiration()} day(s)!`});
|
||||
}
|
||||
socket.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
//Define listeners
|
||||
this.defineListeners(socket);
|
||||
this.chatHandler.defineListeners(socket);
|
||||
|
|
|
|||
20
src/controllers/popup/channelUserBanController.js
Normal file
20
src/controllers/popup/channelUserBanController.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/channelUserBan');
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ const { Router } = require('express');
|
|||
//local imports
|
||||
const placeholderController = require("../controllers/popup/placeholderController");
|
||||
const userBanController = require("../controllers/popup/userBanController");
|
||||
const channelUserBanController = require("../controllers/popup/channelUserBanController");
|
||||
|
||||
//globals
|
||||
const router = Router();
|
||||
|
|
@ -28,5 +29,6 @@ const router = Router();
|
|||
//routing functions
|
||||
router.get('/placeholder', placeholderController.get);
|
||||
router.get('/userBan', userBanController.get);
|
||||
router.get('/channelUserBan', channelUserBanController.get);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
53
src/schemas/channel/channelBanSchema.js
Normal file
53
src/schemas/channel/channelBanSchema.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*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 {mongoose} = require('mongoose');
|
||||
|
||||
const channelBanSchema = new mongoose.Schema({
|
||||
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
|
||||
}
|
||||
});
|
||||
|
||||
//methods
|
||||
channelBanSchema.methods.getDaysUntilExpiration = function(){
|
||||
//Get ban date
|
||||
const expirationDate = new Date(this.banDate);
|
||||
//Get expiration days and calculate expiration date
|
||||
expirationDate.setDate(expirationDate.getDate() + this.expirationDays);
|
||||
//Calculate and return days until ban expiration
|
||||
return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1);
|
||||
}
|
||||
|
||||
module.exports = channelBanSchema;
|
||||
|
|
@ -19,11 +19,12 @@ const {mongoose} = require('mongoose');
|
|||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//Local Imports
|
||||
const statModel = require('../statSchema.js');
|
||||
const {userModel} = require('../userSchema.js');
|
||||
const permissionModel = require('../permissionSchema.js');
|
||||
const channelPermissionSchema = require('./channelPermissionSchema.js');
|
||||
const { exceptionHandler } = require('../../utils/loggerUtils.js');
|
||||
const statModel = require('../statSchema');
|
||||
const {userModel} = require('../userSchema');
|
||||
const permissionModel = require('../permissionSchema');
|
||||
const channelPermissionSchema = require('./channelPermissionSchema');
|
||||
const channelBanSchema = require('./channelBanSchema');
|
||||
const { exceptionHandler } = require('../../utils/loggerUtils');
|
||||
|
||||
const channelSchema = new mongoose.Schema({
|
||||
id: {
|
||||
|
|
@ -69,28 +70,7 @@ const channelSchema = new mongoose.Schema({
|
|||
}
|
||||
}],
|
||||
//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
|
||||
}
|
||||
}]
|
||||
banList: [channelBanSchema]
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -194,6 +174,21 @@ channelSchema.statics.reqPermCheck = function(perm, chanField = "chanName"){
|
|||
}
|
||||
}
|
||||
|
||||
channelSchema.statics.processExpiredBans = async function(){
|
||||
const chanDB = await this.find({});
|
||||
|
||||
chanDB.forEach((channel) => {
|
||||
channel.banList.forEach(async (ban, i) => {
|
||||
//ignore permanent and non-expired bans
|
||||
if(ban.expirationDays >= 0 && ban.getDaysUntilExpiration() <= 0){
|
||||
//Get the index of the ban
|
||||
channel.banList.splice(i,1);
|
||||
return await channel.save();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
//methods
|
||||
channelSchema.methods.updateSettings = async function(settingsMap){
|
||||
settingsMap.forEach((value, key) => {
|
||||
|
|
@ -372,6 +367,7 @@ channelSchema.methods.getChanBans = async function(){
|
|||
var banObj = {
|
||||
banDate: ban.banDate,
|
||||
expirationDays: ban.expirationDays,
|
||||
banAlts: ban.banAlts,
|
||||
}
|
||||
|
||||
//Check if the ban was permanent (expiration set before ban date)
|
||||
|
|
@ -382,6 +378,7 @@ channelSchema.methods.getChanBans = async function(){
|
|||
|
||||
//Set calculated expiration date
|
||||
banObj.expirationDate = expirationDate;
|
||||
banObj.daysUntilExpiration = ban.getDaysUntilExpiration();
|
||||
}
|
||||
|
||||
//Setup user object (Do this last to keep it at bottom for human-readibility of json :P)
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ userBanSchema.statics.getBans = async function(){
|
|||
banDate: ban.banDate,
|
||||
expirationDays: ban.expirationDays,
|
||||
expirationDate: expirationDate,
|
||||
daysUntilExpiration: ban.getDaysUntilExpiration(),
|
||||
user: userObj,
|
||||
ips: ban.ips,
|
||||
alts: ban.alts,
|
||||
|
|
@ -247,7 +248,7 @@ userBanSchema.methods.getDaysUntilExpiration = function(){
|
|||
//Get expiration days and calculate expiration date
|
||||
expirationDate.setDate(expirationDate.getDate() + this.expirationDays);
|
||||
//Calculate and return days until ban expiration
|
||||
return daysUntilExpiraiton = ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1);
|
||||
return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1);
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("userBan", userBanSchema);
|
||||
|
|
@ -18,9 +18,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
|||
const cron = require('node-cron');
|
||||
|
||||
//Local Imports
|
||||
const userBanSchema = require('../schemas/userBanSchema');
|
||||
const userBanModel = require('../schemas/userBanSchema');
|
||||
const channelModel = require('../schemas/channel/channelSchema');
|
||||
|
||||
module.exports.schedule = function(){
|
||||
//Process expired global bans every night at midnight
|
||||
cron.schedule('0 0 * * *', ()=>{userBanModel.processExpiredBans()},{scheduled: true, timezone: "UTC"});
|
||||
}
|
||||
|
||||
module.exports.kickoff = function(){
|
||||
//Process expired bans every night at midnight
|
||||
cron.schedule('0 0 * * *', ()=>{userBanSchema.processExpiredBans()},{scheduled: true, timezone: "UTC"});
|
||||
//Process expired global bans that may have expired since last restart
|
||||
userBanModel.processExpiredBans()
|
||||
//Process expired channel bans that may haven ot expired since last restart
|
||||
channelModel.processExpiredBans();
|
||||
|
||||
//Schedule jobs
|
||||
module.exports.schedule();
|
||||
}
|
||||
|
|
@ -23,10 +23,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<h1 class="panel-title"><%= instance %> Admin Panel</h1>
|
||||
<%- include('partial/adminPanel/channelList', {chanGuide}) %>
|
||||
<%- include('partial/adminPanel/userList', {user, userList, rankEnum}) %>
|
||||
<%- include('partial/adminPanel/permList', {permList, rankEnum}) %>
|
||||
<%- include('partial/adminPanel/userBanList') %>
|
||||
<div class="admin-panel-container-div">
|
||||
<%- include('partial/adminPanel/channelList', {chanGuide}) %>
|
||||
<%- include('partial/adminPanel/userList', {user, userList, rankEnum}) %>
|
||||
<%- include('partial/adminPanel/permList', {permList, rankEnum}) %>
|
||||
<%- include('partial/adminPanel/userBanList') %>
|
||||
</div>
|
||||
</body>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
|
|
|
|||
|
|
@ -24,10 +24,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<body>
|
||||
<%- include('partial/navbar', {user}); %>
|
||||
<h1 class="panel-title"><%- channel.name %> - Channel Settings</h1>
|
||||
<%- include('partial/channelSettings/userList.ejs'); %>
|
||||
<%- include('partial/channelSettings/settings.ejs'); %>
|
||||
<%- include('partial/channelSettings/permList.ejs'); %>
|
||||
<a href="javascript:" id="channel-delete">Delete Channel</a>
|
||||
<div class="admin-panel-container-div">
|
||||
<%- include('partial/channelSettings/userList.ejs'); %>
|
||||
<%- include('partial/channelSettings/banList.ejs'); %>
|
||||
<%- include('partial/channelSettings/settings.ejs'); %>
|
||||
<%- include('partial/channelSettings/permList.ejs'); %>
|
||||
</div>
|
||||
<button href="javascript:" id="channel-delete">Delete Channel</button>
|
||||
<footer>
|
||||
<%- include('partial/scripts', {user}); %>
|
||||
<script src="/js/channelSettings.js"></script>
|
||||
|
|
|
|||
|
|
@ -27,19 +27,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<h3>Name</h3>
|
||||
</td>
|
||||
<td id="admin-ban-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>
|
||||
<h3>Sign-Up<br>Date</h3>
|
||||
</td>
|
||||
<td id="admin-ban-list-entry-ban-date-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>Ban Date</h3>
|
||||
<h3>Ban<br>Date</h3>
|
||||
</td>
|
||||
<td id="admin-ban-list-entry-expiration-date-title" class="admin-list-entry admin-list-entry-title admin-list-entry-item admin-list-entry-not-first-col">
|
||||
<h3>Expiration Date</h3>
|
||||
<h3>Expires</h3>
|
||||
</td>
|
||||
<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>
|
||||
<h3>Expiration<br>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>
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<h3>E-Mail</h3>
|
||||
</td>
|
||||
<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>
|
||||
<h3>Sign-Up<br>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) => { %>
|
||||
|
|
|
|||
34
src/views/partial/channelSettings/banList.ejs
Normal file
34
src/views/partial/channelSettings/banList.ejs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<!--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/>.-->
|
||||
<div class="admin-list-div">
|
||||
<h3 id="channel-ban-title">Channel Bans:</h3>
|
||||
<span id="new-ban-span" class="admin-list-new-span">
|
||||
<input placeholder="Add Username..." id="new-ban-input" class="admin-list-new-input">
|
||||
<button id="new-ban-button">Ban</button>
|
||||
</span>
|
||||
<table id="admin-ban-list-table" class="admin-list-table">
|
||||
<tr class="admin-list-entry-title-row">
|
||||
<td class="admin-list-entry-item admin-list-entry admin-list-entry-img-title"><h3>Img</h3></td>
|
||||
<td id="admin-user-list-entry-id-title" class="admin-list-entry-item admin-list-entry admin-list-entry-not-first-col"><h3>ID</h3></td>
|
||||
<td class="admin-list-entry-item admin-list-entry admin-list-entry-not-first-col"><h3>Name</h3></td>
|
||||
<td class="admin-list-entry-item admin-list-entry admin-list-entry-not-first-col"><h3>Ban<br>Alts</h3></td>
|
||||
<td id="channel-user-list-entry-ban-date-title" class="admin-list-entry-item admin-list-entry admin-list-entry-not-first-col"><h3>Ban Date</h3></td>
|
||||
<td id="channel-user-list-entry-expiration-date-title" class="admin-list-entry-item admin-list-entry admin-list-entry-not-first-col"><h3>Expires</h3></td>
|
||||
<td id="channel-user-list-entry-actions-title" class="admin-list-entry-item admin-list-entry admin-list-entry-not-first-col"> </td>
|
||||
</tr>
|
||||
<!-- This is getting filled via AJAX since we need to refresh it when new users are added anywho. -->
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -16,8 +16,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
|||
<div class="admin-list-div">
|
||||
<h3 id="channel-rank-title">Channel Ranks:</h3>
|
||||
<sup id="channel-rank-sup">Users set to default channel rank 'user' will NOT be listed below.</sup>
|
||||
<span id="new-rank-span">
|
||||
<input placeholder="Add Username..." id="new-rank-input">
|
||||
<span id="new-rank-span" class="admin-list-new-span">
|
||||
<input placeholder="Add Username..." id="new-rank-input" class="admin-list-new-input">
|
||||
<select id="new-rank-select">
|
||||
<%rankEnum.slice().reverse().forEach((rank)=>{ %>
|
||||
<option value="<%= rank %>"><%= rank %></option>
|
||||
|
|
|
|||
39
src/views/partial/popup/channelUserBan.ejs
Normal file
39
src/views/partial/popup/channelUserBan.ejs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<!--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/>.-->
|
||||
<!-- I could turn this into partials which get called by both this and userBan but that seems like a lot of work to avoid a quick copy/pase
|
||||
even if I'm usually against that, sometimes you gotta break da rulez :P -->
|
||||
<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>
|
||||
<label id="ban-popup-alts-prefix" for="ban-popup-alts">Ban Alts: </label>
|
||||
<input type="checkbox" name="ban-popup-alts" id="ban-popup-alts" checked>
|
||||
</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