Finished up implementing channel-based user bans.

This commit is contained in:
rainbow napkin 2024-12-01 17:18:43 -05:00
parent ef79e9941c
commit 96953979a2
19 changed files with 518 additions and 202 deletions

View file

@ -19,10 +19,11 @@ class channelSettingsPage{
//Get channel name off of the URL
this.channel = window.location.pathname.slice(3).replace('/settings','');
//Instantiate UX handling objects, making sure to pass the channel name.
this.deleteBtn = new deleteBtn(this.channel);
this.rankList = new rankList(this.channel);
this.prefrenceList = new prefrenceList(this.channel);
this.banList = new banList(this.channel);
this.permList = new permList(this.channel);
this.prefrenceList = new prefrenceList(this.channel);
this.deleteBtn = new deleteBtn(this.channel);
}
}
@ -42,15 +43,6 @@ class rankList{
this.userPrompt.addEventListener("keydown", this.submitNewRank.bind(this));
}
resetInput(){
//These change every time the table is refreshed, so we should reset the property as well.
this.inputs = document.querySelectorAll(".channel-rank-select");
this.inputs.forEach((input) => {
input.addEventListener("change", this.submitUpdate.bind(this));
});
}
async loadList(){
const list = await utils.ajax.getChannelRank(this.channel);
@ -87,7 +79,7 @@ class rankList{
//Do not pass go, do not collect $200
return;
}
//Get rank of logged in user
//Get name/rank of logged in user
const curName = document.querySelector("#username").textContent
const curUser = data[curName];
const rankEnum = await utils.ajax.getRankEnum();
@ -95,47 +87,25 @@ class rankList{
//clear the table
this.clearTable();
//For each user in the list
Object.entries(data).forEach((userAr) => {
//pull user object from entry array
const user = userAr[1];
//Create entry row
const entryRow = document.createElement('tr');
entryRow.classList.add("admin-list-entry");
//Create IMG cell
const imgCell = document.createElement('td')
imgCell.classList.add("admin-list-entry","admin-list-entry-item");
//Create IMG node inside of IMG cell
const imgNode = document.createElement('img');
imgNode.classList.add("admin-list-entry","admin-list-entry-item");
imgNode.src = user.img;
//append Img Node to Img Cell
imgCell.appendChild(imgNode);
//Create ID cell
const idCell = document.createElement('td');
idCell.classList.add("admin-list-entry","admin-list-entry-item","admin-list-entry-not-first-col");
idCell.innerHTML = user.id;
//Create Name cell
const nameCell = document.createElement('td');
nameCell.classList.add("admin-list-entry","admin-list-entry-item","admin-list-entry-not-first-col");
nameCell.innerHTML = user.user;
//Create Rank cell
const rankCell = document.createElement('td');
rankCell.classList.add("admin-list-entry","admin-list-entry-item","admin-list-entry-not-first-col");
//If the listed user rank is equal or higher than the signed-in user
if(rankEnum.indexOf(user.rank) >= rankEnum.indexOf(curUser.rank)){
rankCell.innerHTML = user.rank;
var rankContent = user.rank;
}else{
//Create rank select
const rankSelect = document.createElement('select');
rankSelect.id = `channel-rank-select-${user.user}`
rankSelect.classList.add("channel-rank-select")
var rankContent = document.createElement('select');
rankContent.id = `channel-rank-select-${user.user}`
rankContent.classList.add("channel-rank-select")
rankContent.addEventListener("change", this.submitUpdate.bind(this));
//for each rank in the enum
rankEnum.slice().reverse().forEach((rank) => {
@ -144,24 +114,17 @@ class rankList{
rankOption.value = rank;
rankOption.innerHTML = rank;
rankOption.selected = user.rank == rank;
rankSelect.appendChild(rankOption);
rankContent.appendChild(rankOption);
});
//Set value to current user rank and append it to Rank Cell
rankCell.appendChild(rankSelect);
}
//Append cells to row
entryRow.appendChild(imgCell);
entryRow.appendChild(idCell);
entryRow.appendChild(nameCell);
entryRow.appendChild(rankCell);
//Append row to table
this.table.appendChild(entryRow);
//reset input events
this.resetInput();
//Generate row and append to table
this.table.appendChild(utils.ux.newTableRow([
imgNode,
user.id,
user.user,
rankContent
]));
});
}
@ -177,6 +140,137 @@ class rankList{
}
}
class banList{
constructor(channel){
this.channel = channel;
this.table = document.querySelector("#admin-ban-list-table");
this.banPrompt = document.querySelector("#new-ban-input");
this.banButton = document.querySelector("#new-ban-button");
this.loadList();
this.setupInput();
}
setupInput(){
this.banButton.addEventListener('click', this.ban.bind(this));
}
async loadList(){
const data = await utils.ajax.getChanBans(this.channel);
this.updateList(data);
}
clearList(){
const oldRows = this.table.querySelectorAll('tr.admin-list-entry');
oldRows.forEach((row) => {
row.remove();
});
}
async ban(event){
new banUserPopup(this.channel, this.banPrompt.value, this.updateList.bind(this));
}
async unban(event){
//Rip user outta the target id
const user = event.target.id.replace("admin-user-list-unban-icon-","");
//Tell the server to unban them and get the list returned
const list = await utils.ajax.chanUnban(this.channel, user);
//Use the list to update the UI
this.updateList(list);
}
updateList(bans){
//for each ban listed
this.clearList();
bans.forEach((ban)=>{
//Create IMG node
const imgNode = document.createElement('img');
imgNode.classList.add("admin-list-entry","admin-list-entry-item");
imgNode.src = ban.user.img;
//Create banAlts check
const banAlts = document.createElement('i');
banAlts.classList.add("admin-user-list-ban-alts",ban.banAlts ? "bi-check" : "bi-x");
//Create unban icon node
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));
//THIS IS NOT YET PROPERLY IMPLEMENTED AS getDaysUntilExpiration has not been made for chan bans
const expirationString = ban.expirationDays < 0 ? "Never" : `${new Date(ban.expirationDate).toDateString()}<br>(${ban.daysUntilExpiration} day(s) left)`;
//Generate row and append to table
this.table.appendChild(utils.ux.newTableRow([
imgNode,
ban.user.id,
ban.user.user,
banAlts,
new Date(ban.banDate).toDateString(),
expirationString,
unbanIcon
]));
});
}
}
class banUserPopup{
constructor(channel, target, cb){
this.channel = channel;
this.target = target;
this.cb = cb;
this.popup = new canopyUXUtils.popup("channelUserBan", true, this.asyncConstruction.bind(this));
}
asyncConstruction(){
this.title = document.querySelector(".popup-title");
//Setup title text real quick-like :P
this.title.innerHTML = `Ban ${this.target}`;
this.permBan = document.querySelector("#ban-popup-perm");
this.expiration = document.querySelector("#ban-popup-expiration");
this.expirationPrefix = document.querySelector("#ban-popup-expiration-prefix");
this.banAlts = document.querySelector("#ban-popup-alts");
this.banButton = document.querySelector("#ban-popup-ban-button");
this.cancelButton = document.querySelector("#ban-popup-cancel-button");
this.setupInput();
}
setupInput(){
this.permBan.addEventListener("change", this.permaBanLabel.bind(this));
this.cancelButton.addEventListener("click", this.popup.closePopup.bind(this.popup));
this.banButton.addEventListener("click",this.ban.bind(this));
}
permaBanLabel(event){
if(event.target.checked){
this.expiration.disabled = true;
}else{
this.expiration.disabled = false;
}
}
async ban(event){
//Get expiration days
const expirationDays = this.permBan.checked ? -1 : this.expiration.value;
//Send ban request off to server and retrieve new ban list
const data = await utils.ajax.chanBan(this.channel, this.target, expirationDays, this.banAlts.checked);
//Close the popup
this.popup.closePopup();
//If we have data and a callback, run the callback with our data
if(data != null && this.cb != null){
await this.cb(data);
}
}
}
class prefrenceList{
constructor(channel){
this.channel = channel;
@ -206,26 +300,6 @@ class prefrenceList{
}
}
class deleteBtn{
constructor(channel){
this.channel = channel;
this.delete = document.querySelector("#channel-delete");
this.delete.addEventListener('click', this.promptDelete.bind(this));
}
promptDelete(){
var confirm = window.prompt(`Warning: You are about to nuke ${this.channel} off of the face of the fucking planet, no taksie-backsies. \n \n Type in ${this.channel} to confirm.`);
this.deleteChannel(confirm);
}
async deleteChannel(confirm){
if(this.channel === confirm){
utils.ajax.deleteChannel(this.channel, confirm);
}
}
}
class permList{
constructor(channel){
this.channel = channel
@ -254,4 +328,24 @@ class permList{
}
}
new channelSettingsPage();
class deleteBtn{
constructor(channel){
this.channel = channel;
this.delete = document.querySelector("#channel-delete");
this.delete.addEventListener('click', this.promptDelete.bind(this));
}
promptDelete(){
var confirm = window.prompt(`Warning: You are about to nuke ${this.channel} off of the face of the fucking planet, no taksie-backsies. \n \n Type in ${this.channel} to confirm.`);
this.deleteChannel(confirm);
}
async deleteChannel(confirm){
if(this.channel === confirm){
utils.ajax.deleteChannel(this.channel, confirm);
}
}
}
const channelSettings = new channelSettingsPage();