Updated ban UI to handle IP-Bans.

This commit is contained in:
rainbow napkin 2025-01-01 23:00:03 -05:00
parent 977e8e1e2e
commit 7624e1928a
8 changed files with 165 additions and 71 deletions

View file

@ -306,24 +306,31 @@ userBanSchema.statics.unban = async function(user){
}
userBanSchema.statics.getBans = async function(){
const banDB = await this.find({}).populate('user');
//Get the ban, populating users and alts
const banDB = await this.find({}).populate('user').populate('alts');
//Create an empty array to hold ban records
var bans = [];
banDB.forEach((ban) => {
//Calcualte expiration date
//Create array to hold alts
var alts = [];
//Calculate expiration date
var expirationDate = new Date(ban.banDate);
expirationDate.setDate(expirationDate.getDate() + ban.expirationDays);
//Make sure we're not about to read the properties of a null object
if(ban.user != null){
var userObj = {
id: ban.user.id,
user: ban.user.user,
img: ban.user.img,
date: ban.user.date
}
var userObj = ban.user.getProfile();
}
//For each alt in the ban
for(alt of ban.alts){
//Get the profile and push it to the alt list
alts.push(alt.getProfile());
}
//Create ban object
const banObj = {
banDate: ban.banDate,
expirationDays: ban.expirationDays,
@ -331,14 +338,16 @@ userBanSchema.statics.getBans = async function(){
daysUntilExpiration: ban.getDaysUntilExpiration(),
user: userObj,
ips: ban.ips,
alts: ban.alts,
alts,
deletedNames: ban.deletedNames,
permanent: ban.permanent
}
//Add it to the array
bans.push(banObj);
});
//Return the array
return bans;
}

View file

@ -74,22 +74,23 @@ const userSchema = new mongoose.Schema({
required: true,
default: "/img/johnny.png"
},
//These should be larger than validator values to make room for escaped characters
bio: {
type: mongoose.SchemaTypes.String,
required: true,
maxLength: 1000,
maxLength: 2000,
default: "Bio not set!"
},
pronouns:{
type: mongoose.SchemaTypes.String,
optional: true,
maxLength: 20,
maxLength: 50,
default: ""
},
signature: {
type: mongoose.SchemaTypes.String,
required: true,
maxLength: 150,
maxLength: 300,
default: "Signature not set!"
},
highLevel: {

View file

@ -32,11 +32,12 @@ module.exports = {
img: (field = 'img') => body(field).optional().isURL({require_tld: false, require_host: false}).trim(),
pronouns: (field = 'pronouns') => body(field).optional().escape().trim().isLength({min: 0, max: 15}),
//Length check before escaping to keep symbols from throwing the count
pronouns: (field = 'pronouns') => body(field).optional().trim().isLength({min: 0, max: 15}).escape(),
signature: (field = 'signature') => body(field).optional().escape().trim().isLength({min: 1, max: 25}),
signature: (field = 'signature') => body(field).optional().trim().isLength({min: 1, max: 25}).escape(),
bio: (field = 'bio') => body(field).optional().escape().trim().isLength({min: 1, max: 1000}),
bio: (field = 'bio') => body(field).optional().trim().isLength({min: 1, max: 1000}).escape(),
rank: (field = 'rank') => body(field).escape().trim().custom(isRank),

View file

@ -18,17 +18,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
<div class="dynamic-container">
<table id="admin-ban-list-table" class="admin-list-table">
<tr id="admin-ban-list-entry-title" class="admin-list-entry-title-row">
<td id="admin-ban-list-entry-img-title" class="admin-list-entry-title admin-list-entry-item admin-list-entry-img-title">
<h3>Img</h3>
<td id="admin-ban-list-entry-user-title" class="admin-list-entry-title admin-list-entry-item">
<h3>Main<br>User</h3>
</td>
<td id="admin-ban-list-entry-alts-title" class="admin-list-entry-title admin-list-entry-item not-first-col">
<h3>Alt<br>Users</h3>
</td>
<td id="admin-ban-list-entry-ban-nuked-users-title" class="admin-list-entry-title admin-list-entry-item not-first-col">
<h3>Nuked<br>Users</h3>
</td>
<td id="admin-ban-list-entry-id-title" class="admin-list-entry-title admin-list-entry-item not-first-col">
<h3>ID</h3>
</td>
<td id="admin-ban-list-entry-name-title" class="admin-list-entry-title admin-list-entry-item not-first-col">
<h3>Name</h3>
</td>
<td id="admin-ban-list-entry-date-title" class="admin-list-entry-title admin-list-entry-item not-first-col">
<h3>Sign-Up<br>Date</h3>
<td id="admin-ban-list-entry-ban-ips-title" class="admin-list-entry-title admin-list-entry-item not-first-col">
<h3>Banned<br>IPs</h3>
</td>
<td id="admin-ban-list-entry-ban-date-title" class="admin-list-entry-title admin-list-entry-item not-first-col">
<h3>Ban<br>Date</h3>

View file

@ -16,6 +16,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
<link rel="stylesheet" type="text/css" href="/css/popup/ban.css">
<h3 class="popup-title">Ban NULL</h3>
<div class="ban-popup-content">
<span>
<label for="ban-popup-perm">IP-Ban:</label>
<input type="checkbox" name="ban-popup-ip" id="ban-popup-ip">
</span>
<span>
<label for="ban-popup-perm">Perma-Ban:</label>
<input type="checkbox" name="ban-popup-perm" id="ban-popup-perm">

View file

@ -98,10 +98,6 @@ img.admin-list-entry-item{
width: 8em;
}
#admin-ban-list-entry-expiration-date-title{
width: 11em;
}
div.toke-command-list{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(15em, 1fr));

View file

@ -32,6 +32,7 @@ class canopyAdminUtils{
//Setup title text real quick-like :P
this.title.innerHTML = `Ban ${this.target}`;
this.ipBan = document.querySelector("#ban-popup-ip");
this.permBan = document.querySelector("#ban-popup-perm");
this.expiration = document.querySelector("#ban-popup-expiration");
this.expirationPrefix = document.querySelector("#ban-popup-expiration-prefix");
@ -62,7 +63,8 @@ class canopyAdminUtils{
this.popup.closePopup();
//Submit the user ban based on input
const data = await adminUtil.banUser(this.target, this.permBan.checked, this.expiration.value);
console.log(this.ipBan.checked)
const data = await adminUtil.banUser(this.target, this.permBan.checked, this.ipBan.checked, this.expiration.value);
//For some reason comparing this against undefined or null wasnt working in and of itself...
if(data != null){
@ -457,66 +459,146 @@ class adminUserBanList{
}
renderBanList(banList){
//Clear out the ban list
this.clearBanList();
//For each ban received
banList.forEach((ban) => {
//Calculate expiration date and expiration days
var expirationDateString = `${new Date(ban.expirationDate).toDateString()}<br>(${ban.daysUntilExpiration} day(s) left)`;
var banActionString = ban.permanent ? "Nuke<br>Accounts" : "Un-Ban";
if(ban.user == null){
let expirationDateString = `${new Date(ban.expirationDate).toLocaleDateString()}<br>(${ban.daysUntilExpiration} day(s) left)`;
let banActionString = ban.permanent ? "Nuke<br>Accounts" : "Un-Ban";
let nuked = ban.user == null;
//If the user is null (the ban has been nuked)
if(nuked){
//Fudge the user object if it's already been deleted
ban.user = {
img: "/img/nuked.png",
id: "-",
user: ban.deletedNames[0] ? ban.deletedNames[0] : "UNKNOWN",
deleted: true
//Use dead name if we got one
user: ban.deletedNames[0] != null ? ban.deletedNames[0] : "Nuked"
};
ban.alts[0] = {
user: "Nuked"
}
//Fake the display string
var signUpDateString = "-"
expirationDateString = "Accounts<br>Nuked"
banActionString = "Accounts<br>Nuked"
}else{
var signUpDateString = new Date(ban.user.date).toDateString()
}
//Create entry row
const entryRow = document.createElement('tr');
entryRow.classList.add("admin-list-entry");
//Create IMG node inside of IMG cell
const imgNode = document.createElement('img');
imgNode.classList.add("admin-list-entry","admin-list-entry-item");
imgNode.src = ban.user.img;
//Create unban icon
const unbanIcon = document.createElement('i');
unbanIcon.classList.add("bi-emoji-smile-fill","admin-user-list-icon","admin-user-list-unban-icon");
unbanIcon.id = `admin-user-list-unban-icon-${ban.user.user}`;
unbanIcon.title = `Unban ${ban.user.user}`;
unbanIcon.addEventListener("click", this.unban.bind(this));
//Create nuke account icon
const nukeAccount = document.createElement('i');
nukeAccount.classList.add("bi-radioactive","admin-user-list-icon","admin-user-list-unban-icon");
nukeAccount.id = `admin-user-list-unban-icon-${ban.user.user}`;
nukeAccount.title = `Nuke accounts`;
nukeAccount.addEventListener("click",console.log);
//append img cell to row
entryRow.appendChild(utils.ux.newTableCell(imgNode, true));
//Generate and append row to table
this.table.appendChild(utils.ux.newTableRow([
ban.user.id,
ban.user.user,
signUpDateString,
new Date(ban.banDate).toDateString(),
this.renderUser(ban.user, nuked),
this.renderUsers(ban.alts, nuked),
this.renderDeadUsers(ban.deletedNames),
this.renderIPs(ban.ips),
new Date(ban.banDate).toLocaleDateString(),
expirationDateString,
banActionString,
(ban.user.deleted ? unbanIcon : [unbanIcon, nukeAccount])
this.renderIcons(ban.user)
]));
});
}
renderUser(user, nuked = false){
if(nuked){
var userNode = document.createElement('img');
userNode.classList.add("admin-list-entry","admin-list-entry-item");
userNode.src = '/img/nuked.png'
userNode.title = "Nuked"
}else{
var userNode = document.createElement('p');
userNode.innerHTML = user.user;
}
return userNode;
}
renderUsers(users, nuked){
//Create userlist span
let userList = document.createElement('span');
if(!nuked){
//For each user
for(let user of users){
//Render out the user
userList.appendChild(this.renderUser(user));
}
}else{
userList = document.createElement('img');
userList.classList.add("admin-list-entry","admin-list-entry-item");
userList.src = '/img/nuked.png'
userList.title = "Nuked"
}
//return our list
return userList;
}
renderDeadUsers(users){
//Create userlist span
const deadUsers = document.createElement('span');
//For each ip
for(let user of users){
//Create a node
const userNode = document.createElement('p');
//Fill it wit the ip
userNode.innerHTML = user;
//Append it
deadUsers.appendChild(userNode);
}
//return our list
return deadUsers;
}
renderIPs(ips){
//Create userlist span
const ipList = document.createElement('span');
//For each ip
for(let ip of ips.plaintext){
//Create a node
const ipNode = document.createElement('p');
//Fill it wit the ip
ipNode.innerHTML = ip;
//Append it
ipList.appendChild(ipNode);
}
//For each user
for(let hash of ips.hashed){
//Create a node
const ipNode = document.createElement('p');
//List it as a hashed ip with the hash as alt text
ipNode.innerHTML = '[Hashed IP]';
ipNode.title = hash;
//Append the node
ipList.appendChild(ipNode);
}
//return our list
return ipList;
}
renderIcons(user){
//Create unban icon
const unbanIcon = document.createElement('i');
unbanIcon.classList.add("bi-emoji-smile-fill","admin-user-list-icon","admin-user-list-unban-icon");
unbanIcon.id = `admin-user-list-unban-icon-${user.user}`;
unbanIcon.title = `Unban ${user.user}`;
unbanIcon.addEventListener("click", this.unban.bind(this));
//Create nuke account icon
const nukeAccount = document.createElement('i');
nukeAccount.classList.add("bi-radioactive","admin-user-list-icon","admin-user-list-unban-icon");
nukeAccount.id = `admin-user-list-unban-icon-${user.user}`;
nukeAccount.title = `Nuke accounts`;
nukeAccount.addEventListener("click",console.log);
//If our user has been deleted don't return the nuke icon
return (user.deleted ? unbanIcon : [unbanIcon, nukeAccount]);
}
}
class adminTokeCommandList{

View file

@ -57,6 +57,7 @@ class canopyUXUtils{
//add single items
addContent(content);
}else{
console.log(content);
//Crawl through content array
content.forEach((item)=>{
//add each item