yup, this holds the JS for the shell shockers admin panel.
have fun!
Created
July 1, 2024 12:03
-
-
Save VillainsRule/cab7790973bf20d5e1887ad657a354ef to your computer and use it in GitHub Desktop.
the shell shockers admin code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(() => { | |
// src/shared/enums.mjs | |
var CloseCode = { | |
gameNotFound: 0, | |
gameFull: 0, | |
badName: 0, | |
mainMenu: 0, | |
gameIdleExceeded: 0, | |
corruptedLoginData0: 0, | |
corruptedLoginData1: 0, | |
corruptedLoginData2: 0, | |
corruptedLoginData3: 0, | |
corruptedLoginData4: 0, | |
corruptedLoginData5: 0, | |
gameMaxPlayersExceeded: 0, | |
gameDestroyUser: 0, | |
joinGameOutOfOrder: 0, | |
gameShuttingDown: 0, | |
readyBeforeReady: 0, | |
booted: 0, | |
gameErrorOnUserSocket: 0, | |
uuidNotFound: 0, | |
sessionNotFound: 0, | |
clusterFullCpu: 0, | |
clusterFullMem: 0, | |
noClustersAvailable: 0, | |
locked: 0 | |
}; | |
var i = 4e3; | |
Object.keys(CloseCode).forEach((k) => { | |
CloseCode[k] = i++; | |
}); | |
var CommCode = { | |
createPrivateGame: 0, | |
switchTeam: 0, | |
changeCharacter: 0, | |
pause: 0, | |
announcement: 0, | |
updateBalance: 0, | |
reload: 0, | |
refreshGameState: 0, | |
switchTeamFail: 0, | |
expireUpgrade: 0, | |
bootPlayer: 0, | |
banPlayer: 0, | |
loginRequired: 0, | |
gameLocked: 0, | |
reportPlayer: 0, | |
banned: 0, | |
metaGameState: 0, | |
syncMe: 0, | |
explode: 0, | |
keepAlive: 0, | |
musicInfo: 0, | |
hitMeHardBoiled: 0, | |
beginShellStreak: 0, | |
endShellStreak: 0, | |
startReload: 0, | |
fire: 0, | |
melee: 0, | |
throwGrenade: 0, | |
info: 0, | |
eventModifier: 0, | |
playerInfo: 0, | |
gameOptions: 0, | |
gameAction: 0, | |
requestGameOptions: 0, | |
gameJoined: 0, | |
socketReady: 0, | |
addPlayer: 0, | |
removePlayer: 0, | |
chat: 0, | |
syncThem: 0, | |
syncAmmo: 0, | |
die: 0, | |
hitThem: 0, | |
hitMe: 0, | |
collectItem: 0, | |
spawnItem: 0, | |
respawn: 0, | |
respawnDenied: 0, | |
swapWeapon: 0, | |
joinGame: 0, | |
observeGame: 0, | |
ping: 0, | |
pong: 0, | |
clientReady: 0, | |
requestRespawn: 0, | |
joinPublicGame: 0, | |
joinPrivateGame: 0 | |
}; | |
var i = 0; | |
Object.keys(CommCode).forEach((k) => { | |
CommCode[k] = i++; | |
}); | |
var GameTypes = [ | |
{ shortName: "FFA", longName: "Free For All", value: 0 }, | |
{ shortName: "Teams", longName: "Teams", value: 1 }, | |
{ shortName: "Spatula", longName: "Captula the Spatula", value: 2 }, | |
{ shortName: "King", longName: "King of the Coop", value: 3 } | |
]; | |
var SyncRate = 10; | |
var FramesBetweenSyncs = Math.ceil(30 / SyncRate); | |
var FeedbackType = { | |
comment: 0, | |
// For the heaping of praise upon us, probably. Definitely. Yeah. | |
feature: 1, | |
// Feature requests | |
bug: 2, | |
// Well, you know... bugs. | |
purchase: 3, | |
// Issues with item and golden egg purchases | |
account: 4, | |
// Account and privacy issues | |
abuse: 5, | |
// For people to bitch about other people "hacking" | |
other: 6, | |
// Who knows... Probably porn. | |
deleteAccount: 7 | |
// for account delete requests | |
}; | |
var CharClass = { | |
Soldier: 0, | |
Scrambler: 1, | |
Ranger: 2, | |
Eggsploder: 3, | |
Whipper: 4, | |
Crackshot: 5, | |
TriHard: 6 | |
}; | |
CharClass.length = Object.keys(CharClass).length; | |
var reportReasons = [ | |
"cheating", | |
"harrassment", | |
"offensive", | |
"other" | |
]; | |
var AdminRole = { | |
ManageAdmins: 1, | |
Boot: 2, | |
GameBan: 4, | |
Feedback: 8, | |
Announce: 16, | |
Ads: 32, | |
Players: 64, | |
Refunds: 128, | |
Settings: 256, | |
Media: 512, | |
Badguys: 1024, | |
Items: 2048, | |
Bots: 4096, | |
BanAdmin: 8192, | |
Twitch: 16384 | |
}; | |
// temp/admin.js | |
Date.prototype.toDatetimeLocal = function toDatetimeLocal() { | |
var date = this, ten = function(i2) { | |
return (i2 < 10 ? "0" : "") + i2; | |
}, YYYY = date.getFullYear(), MM = ten(date.getMonth() + 1), DD = ten(date.getDate()), HH = ten(date.getHours()), II = ten(date.getMinutes()), SS = ten(date.getSeconds()); | |
return YYYY + "-" + MM + "-" + DD + "T" + HH + ":" + II + ":" + SS; | |
}; | |
function twoDigits(d) { | |
if (0 <= d && d < 10) | |
return "0" + d.toString(); | |
if (-10 < d && d < 0) | |
return "-0" + (-1 * d).toString(); | |
return d.toString(); | |
} | |
Date.prototype.toMysqlFormat = function() { | |
return this.getUTCFullYear() + "-" + twoDigits(1 + this.getUTCMonth()) + "-" + twoDigits(this.getUTCDate()) + " " + twoDigits(this.getUTCHours()) + ":" + twoDigits(this.getUTCMinutes()) + ":" + twoDigits(this.getUTCSeconds()); | |
}; | |
var ws; | |
var docEl; | |
var headerEl; | |
var pendingActionCallbacks = {}; | |
var currentTab; | |
var profile = {}; | |
var admins = {}; | |
var items = {}; | |
var products = {}; | |
var actionId = 0; | |
var inboxListOpts = {}; | |
var mouse = { x: 0, y: 0 }; | |
var newsItems = []; | |
var shellYouTube = []; | |
var announcementMessage = ""; | |
var refundReasons = []; | |
var adminKey; | |
var skus = [ | |
["egg_pack_small", "Pile of eggs"], | |
["item_hat_galeggsy", "Galeggsy Wings"], | |
["egg_pack_medium", "Basket of eggs"], | |
["egg_pack_large", "Big Box of eggs"], | |
["egg_pack_giant", "Cluckton of eggs"], | |
//['item_gun_m24_techno', 'Untz Gun'], | |
["item_hat_yolk_arms", "Yolk Arms"], | |
["item_hat_cape", "Cape Hat"], | |
["item_hat_dragon", "Dragon Hat"], | |
["item_hat_space_gladi", "Space Gladiator"], | |
["item_hat_zombie_mask", "Zombie Hat"], | |
["item_gun_9mm_space", "Space Cluck9mm"], | |
["item_hat_oni", "Oni Hat"], | |
["item_gun_csg1_space", "Space CSG1"], | |
["item_gun_9mm_techno", "Cluck 9mm Techno"], | |
["item_gun_smg_techno", "SMG Techno (Tuh gun)"], | |
["item_hat_demon_wings", "Demon wings"], | |
["gun_gauge_techno", "Badoosh Gun"], | |
["item_hat_fallen_wing", "Fallen Wings"], | |
["item_gun_csg1_techno", "CSG1 Catz"], | |
["item_hat_chrome_wing", "Chrome Wings"], | |
["gun_eggk47_techno", "Eggk Poggers"], | |
["item_hat_steamWings", "Steampunk Wings"], | |
["item_gun_rpeggTechno", "RPEGG Techno"], | |
["item_gun_retro_9mm", "Retro Cluck9mm"], | |
["hat_premium_PixelAngel", "Pixel Angel Wings"], | |
["item_gun_aug_retro", "Retro TriHard"], | |
["item_hat_robot_wings", "Robot Pixel Wings"] | |
]; | |
var SOCIALMEDIA = [ | |
"Facebook", | |
"Instagram", | |
"TikTok", | |
"Discord", | |
"YouTube", | |
"Twitter", | |
"Twitch" | |
]; | |
var newsColums = [ | |
"", | |
"active", | |
"label", | |
"link", | |
"linksToTaggedItems", | |
"linksToItemId", | |
"linksToNugget", | |
"linksToPhotoBooth", | |
"linksToVipStore", | |
"linksToEggStoreItem", | |
"image" | |
]; | |
var adNewsColumns = [ | |
"", | |
"active", | |
"weighted", | |
"hideOnCG", | |
"label", | |
"link", | |
"linkToShop", | |
"linksToTaggedItems", | |
"linksToItemId", | |
"linksToNugget", | |
"linksToPhotoBooth", | |
"linksToVipStore", | |
"linkToChw", | |
"linkToBlackFriday", | |
"linkToEggOrg", | |
"linkToTwitch", | |
"linksToCreateGame", | |
"image" | |
]; | |
initSettings(); | |
var settings = localStorage.getItem("feedbackAdminSettings"); | |
if (settings) { | |
settings = JSON.parse(settings); | |
inboxListOpts = settings.inboxListOpts; | |
} | |
function initSettings() { | |
inboxListOpts = { | |
match: { | |
status: { | |
open: true, | |
active: true | |
}, | |
feedback_type: {}, | |
admin_id: null | |
}, | |
order: { status: "asc" }, | |
limit: { start: 0, count: 25 } | |
}; | |
} | |
window.onunload = function() { | |
inboxListOpts.limit.start = 0; | |
localStorage.setItem("feedbackAdminSettings", JSON.stringify({ inboxListOpts })); | |
}; | |
window.onload = function() { | |
showSpinner(); | |
if (firebase) | |
login((user) => { | |
user.getIdToken(true).then((idToken) => authorize(idToken)); | |
}, loginFail); | |
var keys = {}; | |
window.onkeydown = function(e) { | |
if (keys[e.code]) | |
return; | |
keys[e.code] = true; | |
if (currentTab && currentTab.onKeyPress) { | |
currentTab.onKeyPress(e.code); | |
} | |
}; | |
window.onkeyup = function(e) { | |
keys[e.code] = false; | |
}; | |
window.onmousemove = function(e) { | |
mouse.x = e.x; | |
mouse.y = e.y; | |
}; | |
}; | |
function login(success, fail) { | |
var config = { | |
apiKey: "AIzaSyDP4SIjKaw6A4c-zvfYxICpbEjn1rRnN50", | |
authDomain: "shellshockio-181719.firebaseapp.com", | |
databaseURL: "https://shellshockio-181719.firebaseio.com", | |
projectId: "shellshockio-181719", | |
storageBucket: "shellshockio-181719.appspot.com", | |
messagingSenderId: "68327206324" | |
}; | |
firebase.initializeApp(config); | |
firebase.auth().onAuthStateChanged(function(user) { | |
if (user) { | |
console.log("Login auth provider: " + user.providerData[0].providerId); | |
if (!user.emailVerified && user.providerData[0].providerId == "password") { | |
console.log("email not yet verified"); | |
return; | |
} | |
console.log("calling loggedIn from firebase.auth().onAuthStateChanged callback"); | |
success(user); | |
} else { | |
fail(); | |
} | |
}); | |
} | |
function loginFail() { | |
console.log(window.error); | |
alert("HI!"); | |
} | |
function authorize() { | |
firebase.auth().currentUser.getIdToken(true).then(function(idToken) { | |
console.log("Using services server: wss://" + window.location.hostname + "/services/"); | |
try { | |
ws = new WebSocket("wss://" + window.location.hostname + "/services/"); | |
} catch (e) { | |
console.log(e); | |
} | |
ws.onopen = function(e) { | |
console.log("authorizing"); | |
ws.send(JSON.stringify({ | |
cmd: "authAdmin", | |
token: idToken | |
})); | |
setInterval(() => { | |
ws.send(JSON.stringify({ cmd: "ping" })); | |
}, 15e3); | |
}; | |
ws.onmessage = function(e) { | |
var data = JSON.parse(e.data); | |
if (!data.pong) | |
console.log(data); | |
if (data.authorized !== void 0) { | |
if (data.authorized == true) { | |
console.log("authorized"); | |
adminKey = data.key; | |
loggedIn(data); | |
} else { | |
console.log("not authorized!"); | |
} | |
} else if (data.error) { | |
alert(JSON.stringify(data)); | |
} else if (data.rows) { | |
hideSpinner(); | |
if (pendingActionCallbacks[data.actionId]) { | |
pendingActionCallbacks[data.actionId](data); | |
delete pendingActionCallbacks[data.actionId]; | |
} | |
} else { | |
if (!data.pong) | |
hideSpinner(); | |
if (pendingActionCallbacks[data.actionId]) { | |
pendingActionCallbacks[data.actionId](data); | |
delete pendingActionCallbacks[data.actionId]; | |
} | |
} | |
}; | |
ws.onclose = function(e) { | |
switch (e.code) { | |
case 4100: | |
document.body.innerHTML = "Hey! You're not an admin!"; | |
break; | |
default: | |
document.body.innerHTML = "Connection lost for SOME REASON"; | |
break; | |
} | |
}; | |
ws.onerror = function(e) { | |
console.log("error: " + JSON.stringify(e, ["message", "arguments", "type", "name"])); | |
}; | |
}); | |
} | |
function loggedIn(data) { | |
var user = firebase.auth().currentUser; | |
profile.id = data.id; | |
profile.playerId = data.player_id; | |
profile.name = data.name || user.displayName || "An admin has no name"; | |
profile.email = data.email || user.email || "An admin has no email"; | |
profile.roles = data.roles || 0; | |
docEl = document.getElementById("doc"); | |
headerEl = document.getElementById("header"); | |
headerEl.style.display = "block"; | |
var responses = 0; | |
requestAction("getAdmins", {}, (data2) => { | |
for (var i2 in data2.rows) { | |
var row = data2.rows[i2]; | |
admins[row.player_id] = data2.rows[i2]; | |
} | |
response(); | |
if (profile.roles & AdminRole.Announce) | |
openAnnouncementTab(); | |
if (profile.roles & AdminRole.Ads) | |
openAdsTab(); | |
if (profile.roles & AdminRole.Media) | |
openMediaTab(); | |
if (profile.roles & AdminRole.Settings) | |
openSettingsTab(); | |
if (profile.roles & AdminRole.Players) | |
openPlayersTab(); | |
if (profile.roles & AdminRole.Refunds) | |
openRefunds(); | |
if (profile.roles & AdminRole.Badguys) | |
openBadguysTab(); | |
if (profile.roles & AdminRole.BanAdmin) | |
openBansTab(); | |
if (profile.roles & AdminRole.ManageAdmins) | |
openAdminsTab(); | |
if (profile.roles & AdminRole.Twitch) | |
openTwitchTab(); | |
}); | |
requestAction("getItems", {}, (data2) => { | |
for (var i2 in data2.rows) { | |
var row = data2.rows[i2]; | |
items[row.id] = data2.rows[i2]; | |
} | |
response(); | |
}); | |
requestAction("getProducts", {}, (data2) => { | |
for (var i2 in data2.rows) { | |
var row = data2.rows[i2]; | |
products[row.id] = data2.rows[i2]; | |
} | |
response(); | |
}); | |
requestAction("getRefundResponses", {}, (data2) => { | |
data2.rows.forEach((el) => refundReasons.push(el)); | |
response(); | |
}); | |
function response() { | |
responses++; | |
console.log("responses: " + responses); | |
if (responses >= 4) { | |
if (profile.roles & AdminRole.Feedback) | |
openInbox(); | |
handleQueryString(); | |
} | |
} | |
if (user.photoURL) { | |
var url = user.photoURL; | |
var pd = user.providerData[0]; | |
if (pd.providerId == "facebook.com") { | |
url = "https://graph.facebook.com/" + pd.uid + "/picture"; | |
} | |
document.getElementById("profilePic").src = url; | |
document.getElementById("profilePic").style.display = "block"; | |
} | |
document.getElementById("profileName").innerText = profile.name; | |
} | |
function handleQueryString() { | |
if (window.location.search.length > 0) { | |
var opts = window.location.search.slice(1).split("&"); | |
for (var o in opts) { | |
var opt = opts[o].split("="); | |
var key = opt[0]; | |
var val = opt[1]; | |
if (key !== void 0 && val !== void 0) { | |
switch (key) { | |
case "ticket": | |
if (profile.roles & AdminRole.Players) { | |
openTicket(parseInt(val, 10)); | |
} | |
break; | |
case "playerId": | |
if (profile.roles & AdminRole.Players) { | |
openPlayerDataFromPlayerId(val); | |
} | |
break; | |
} | |
} | |
} | |
} | |
} | |
function requestAction(action, data, callback) { | |
showSpinner(); | |
data.cmd = "admin"; | |
actionId = ++actionId % 1e4; | |
data.action = action; | |
data.actionId = actionId; | |
console.log("Sending to Services:", data); | |
ws.send(JSON.stringify(data)); | |
if (callback) { | |
pendingActionCallbacks[actionId] = callback; | |
} | |
} | |
function openDialog(header2) { | |
var el = document.getElementById("dialog"); | |
el.style.display = "block"; | |
var d = document.getElementById("dialogContent"); | |
addHeader(d, header2); | |
return d; | |
} | |
function closeDialog() { | |
var el = document.getElementById("dialog"); | |
el.style.display = "none"; | |
var d = document.getElementById("dialogContent"); | |
while (d.firstChild) { | |
d.removeChild(d.firstChild); | |
} | |
} | |
function createTable(rows, columnFilter, rowFunc, cellFunc, colFunc, id) { | |
var table = document.createElement("table"); | |
if (id) | |
table.id = id; | |
var keys; | |
if (columnFilter) { | |
keys = []; | |
for (var i2 in columnFilter) { | |
keys.push(columnFilter[i2]); | |
} | |
} else { | |
var keysObj = {}; | |
for (var i2 in rows) { | |
Object.keys(rows[i2]).forEach((k) => { | |
keysObj[k] = true; | |
}); | |
} | |
keys = Object.keys(keysObj); | |
} | |
var thead = document.createElement("thead"); | |
table.appendChild(thead); | |
var tr = document.createElement("tr"); | |
thead.appendChild(tr); | |
keys.forEach((k) => { | |
var th = document.createElement("th"); | |
tr.appendChild(th); | |
th.innerText = k; | |
th.label = k; | |
if (colFunc) | |
colFunc(th); | |
}); | |
for (var row in rows) { | |
parseRow(rows[row]); | |
var tr = document.createElement("tr"); | |
tr.rowIdx = row; | |
table.appendChild(tr); | |
if (rowFunc) | |
rowFunc(rows[row], tr, row); | |
keys.forEach((k) => { | |
var td = document.createElement("td"); | |
td.key = k; | |
td.rowIdx = row; | |
tr.appendChild(td); | |
td.innerText = rows[row][k]; | |
if (cellFunc) | |
cellFunc(k, td, rows[row]); | |
}); | |
} | |
return table; | |
} | |
function popupList(items2, callback) { | |
var container = document.createElement("div"); | |
container.className = "popupListContainer"; | |
var x = event.x; | |
var y = event.y; | |
container.onmouseleave = () => { | |
document.body.removeChild(container); | |
}; | |
for (var i2 in items2) { | |
var row = addRow(container, "selectRow"); | |
row.innerText = items2[i2]; | |
row.onclick = function(idx) { | |
return () => { | |
document.body.removeChild(container); | |
callback(idx); | |
}; | |
}(i2); | |
} | |
document.body.appendChild(container); | |
var rect = container.getBoundingClientRect(); | |
if (x < 32) | |
x = 32; | |
if (x + rect.width - 32 > window.innerWidth) | |
x = window.innerWidth - rect.width + 32; | |
if (y < 24) | |
y = 24; | |
if (y + rect.height - 24 > window.innerHeight) | |
y = window.innerHeight - rect.height + 24; | |
container.style.left = x - 32 + "px"; | |
container.style.top = y - 24 + "px"; | |
return container; | |
} | |
function localTime(date) { | |
var tz = new Date(date); | |
var ms = Date.parse(date); | |
ms -= tz.getTimezoneOffset() * 60 * 1e3; | |
var adjDate = new Date(ms); | |
return adjDate.toLocaleString("en-US"); | |
} | |
function fitToContent(input) { | |
var context = document.getElementById("textWidthTester").getContext("2d"); | |
context.font = '1em "Open Sans", sans-serif'; | |
var width = Math.max(context.measureText(input.value).width, 20); | |
input.style.width = width + "px"; | |
} | |
function getRequest(url, callback) { | |
var req = new XMLHttpRequest(); | |
if (!req) { | |
return false; | |
} | |
if (typeof callback != "function") | |
callback = function() { | |
}; | |
req.onreadystatechange = function() { | |
if (req.readyState == 4) { | |
return req.status === 200 ? callback(null, req.responseText) : callback(req.status, null); | |
} | |
}; | |
req.open("GET", url, true); | |
req.send(null); | |
return req; | |
} | |
function openFileHelper(callback, extensions) { | |
var e = document.getElementById("openHelper"); | |
e.value = ""; | |
e.accept = extensions || ""; | |
e.onchange = (event2) => { | |
var file = event2.target.files[0]; | |
callback(file); | |
}; | |
e.click(); | |
} | |
function openBinaryUploader(callback, extensions) { | |
closeDialog(); | |
openFileHelper((file) => { | |
var reader = new FileReader(); | |
reader.onload = function() { | |
callback({ | |
ext: file.name.match(/\.[0-9a-z]+$/i)[0], | |
data: reader.result | |
}); | |
}; | |
reader.readAsDataURL(file); | |
}, extensions); | |
} | |
var bc = new BroadcastChannel("ShellShockersAdmin"); | |
bc.onmessage = (e) => { | |
let msg = e.data; | |
switch (msg.cmd) { | |
case "getPlayer": | |
openPlayerDataFromPlayerId(msg.id, msg.ip); | |
break; | |
} | |
}; | |
var adminData; | |
var RoleDescription = { | |
ManageAdmins: "<b><i>Add/Remove admins and change their permissions</i></b>", | |
Boot: "Boot players from within private games", | |
GameBan: "Ban players from within public and private games", | |
Feedback: "Access Feedback on the Admin page", | |
Announce: "Manage Announcements on the Admin page", | |
Ads: "Manage Ads on the Admin page", | |
Players: "Access the Players tab and manage player data on the Admin page", | |
Refunds: "Manage Refunds on the Admin page", | |
Settings: "Manage Settings on the Admin page", | |
Media: "Manage Media on the Admin page", | |
Badguys: "Access the Badguys tab on the Admin page", | |
Items: "Access Item and Product data", | |
Bots: "Launch Bots from within games", | |
BanAdmin: "Add/lift IP and Player bans" | |
}; | |
function openAdminsTab() { | |
addTab("Admins", false, renderAdmins); | |
} | |
function renderAdmins(page) { | |
fetchAdmins((data) => { | |
finishRenderAdmins(page, data); | |
}); | |
} | |
function fetchAdmins(callback) { | |
requestAction("getAdmins", {}, (data) => { | |
hideSpinner(); | |
adminData = {}; | |
data.rows.forEach((row) => { | |
adminData[row.player_id] = row; | |
adminData[row.player_id].updated = false; | |
}); | |
callback(data.rows); | |
}); | |
} | |
function finishRenderAdmins(page, data) { | |
addButton(page, "New Admin", "green", () => { | |
let submission = { | |
player_id: 0, | |
name: "", | |
email: "", | |
roles: 0 | |
}; | |
let checkboxes = {}; | |
let d = openDialog("New Admin"); | |
let row = addRow(d); | |
var col = addCol(row); | |
var idIn = addInput(addRow(col), "player id"); | |
var nameIn = addInput(addRow(col), "name"); | |
var emailIn = addInput(addRow(col), "email"); | |
idIn.size = 80; | |
nameIn.size = 80; | |
emailIn.size = 80; | |
idIn.oninput = () => { | |
submission.player_id = parseInt(idIn.value, 10); | |
fitToContent(idIn); | |
}; | |
nameIn.oninput = () => { | |
submission.name = nameIn.value; | |
fitToContent(nameIn); | |
}; | |
emailIn.oninput = () => { | |
submission.email = emailIn.value; | |
fitToContent(emailIn); | |
}; | |
addCol(row, "colBreakLg"); | |
col = addCol(row); | |
Object.keys(AdminRole).forEach((key) => { | |
let line = addRow(col); | |
var c = addCol(line); | |
c.style.width = "200px"; | |
let checkbox = addCheckbox(c, key); | |
checkboxes[key] = checkbox; | |
c = addCol(line); | |
c.innerHTML = RoleDescription[key]; | |
}); | |
lineBreak(d); | |
let buttons = addRow(d); | |
addButton(buttons, "Save", "green", () => { | |
Object.keys(checkboxes).forEach((key) => { | |
if (checkboxes[key].checked) { | |
submission.roles |= AdminRole[key]; | |
} | |
}); | |
requestAction("addAdmin", submission, () => { | |
hideSpinner(); | |
markDirty("Admins", true); | |
}); | |
closeDialog(); | |
}); | |
addButton(buttons, "Cancel", "red", () => { | |
closeDialog(); | |
}); | |
}); | |
var list = addRow(page); | |
var table = createTable(data, ["", "player_id", "name", "email", "roles"], null, cellFunc, null); | |
list.appendChild(table); | |
function cellFunc(key, td, row) { | |
switch (key) { | |
case "": | |
if (!row.player_id) | |
break; | |
var btn = document.createElement("div"); | |
btn.className = "roundButton removeButton"; | |
btn.onclick = () => { | |
let d = openDialog("Delete Admin"); | |
addSmallHeader(d).innerText = row.name; | |
lineBreak(d); | |
addRow(d).innerText = "Are you sure you want to delete this admin?"; | |
lineBreak(d); | |
var buttons = addRow(d); | |
addButton(buttons, "Yes", "red", () => { | |
requestAction("deleteAdmin", { player_id: row.player_id }, () => { | |
hideSpinner(); | |
markDirty("Admins", true); | |
}); | |
closeDialog(); | |
}); | |
addButton(buttons, "No", "green", closeDialog); | |
}; | |
td.innerText = ""; | |
td.appendChild(btn); | |
break; | |
case "roles": | |
let num2 = td.innerText; | |
if (num2 === "") { | |
num2 = "0x0000"; | |
} else { | |
num2 = "0x" + parseInt(num2).toString(16).toUpperCase(); | |
td.innerText = num2; | |
td.style.cursor = "pointer"; | |
} | |
td.onclick = () => { | |
let d = openDialog("Roles for " + row.name); | |
Object.keys(AdminRole).forEach((key2) => { | |
let line = addRow(d); | |
var col = addCol(line); | |
col.style.width = "200px"; | |
let checkbox = addCheckbox(col, key2, () => { | |
if (checkbox.checked) { | |
row.roles |= AdminRole[key2]; | |
} else { | |
row.roles &= ~AdminRole[key2]; | |
} | |
adminData[row.player_id].roles = row.roles; | |
adminData[row.player_id].updated = true; | |
}); | |
col = addCol(line); | |
col.innerHTML = RoleDescription[key2]; | |
checkbox.checked = (row.roles & AdminRole[key2]) !== 0; | |
}); | |
lineBreak(d); | |
var buttons = addRow(d); | |
addButton(buttons, "Apply", "red", () => { | |
Object.keys(adminData).forEach((key2) => { | |
let d2 = adminData[key2]; | |
if (d2.updated) { | |
let submission = { | |
player_id: d2.player_id, | |
name: d2.name, | |
email: d2.email, | |
roles: d2.roles | |
}; | |
requestAction("updateAdminProfile", submission, () => { | |
hideSpinner(); | |
markDirty("Admins", true); | |
}); | |
} | |
}); | |
closeDialog(); | |
}); | |
addButton(buttons, "Cancel", "green", closeDialog); | |
}; | |
break; | |
case "player_id": | |
case "name": | |
case "email": | |
td.innerHTML = ""; | |
var input = document.createElement("input"); | |
input.value = row[key]; | |
fitToContent(input); | |
input.oninput = () => { | |
adminData[row.player_id][key] = input.value; | |
fitToContent(input); | |
}; | |
input.onchange = () => { | |
adminData[row.player_id].updated = true; | |
}; | |
td.appendChild(input); | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
var houseAds; | |
function openAdsTab() { | |
addTab("Ads", false, renderAds); | |
} | |
function renderAds(page) { | |
fetchAds(() => { | |
finishRenderAds(page); | |
}); | |
} | |
function fetchAds(callback) { | |
getRequest("data/housePromo.json?" + Date.now(), (err, res) => { | |
if (err) { | |
houseAds = { big: [], small: [], bigBanner: [], shellLogo: [], houseAdPercentChance: 100, specialItemsTag: "", featuredSocialMedia: "", premFeatured: "", smHouseAds: [] }; | |
} else { | |
houseAds = JSON.parse(res); | |
if (houseAds.specialItemsTag === void 0) { | |
houseAds.specialItemsTag = ""; | |
} | |
if (houseAds.featuredSocialMedia === void 0) { | |
houseAds.featuredSocialMedia = ""; | |
} | |
if (houseAds.premFeatured === void 0) { | |
houseAds.premFeatured = ""; | |
} | |
if (houseAds.shellLogo === void 0) { | |
houseAds.shellLogo = []; | |
} | |
} | |
houseAds.big.push({}); | |
houseAds.small.push({}); | |
houseAds.bigBanner.push({}); | |
houseAds.smHouseAds = houseAds.smHouseAds || []; | |
houseAds.shellLogo.push({}); | |
callback(); | |
}); | |
} | |
function finishRenderAds(page) { | |
const specialTagStuff = addRow(page, "admin-special-tag-stuff display-flex gap"); | |
var buttons = addRow(page, "admin-ads--save-buttons"); | |
var saveButton = addButton(buttons, "Save Changes", "green", save); | |
var discardButton = addButton(buttons, "Discard", "red", () => { | |
markDirty("Ads", true); | |
}); | |
saveButton.disabled = true; | |
discardButton.disabled = true; | |
var specialItemsTag = addRow(page, "admin-ads--special-tags"); | |
var itemTag = addInput(specialItemsTag, "Special Items Tag", houseAds.specialItemsTag, null, (newVal) => { | |
houseAds.specialItemsTag = newVal; | |
change(); | |
markDirty("Ads", false); | |
}); | |
var socialMediaIcon = addRow(page, "admin-social-media"); | |
const socialOptions = [ | |
["Facebook", "Facebook"], | |
["Twitter", "Twitter"], | |
["Instagram", "Instagram"], | |
["tiktok", "TikTok"], | |
["discord", "Discord"], | |
["Steam", "Steam"], | |
["Twitch", "Twitch"] | |
]; | |
addSmallHeader(socialMediaIcon, "Select featured social media", "left"); | |
var socialIconSelect = addSelect("idisid", socialOptions, houseAds.featuredSocialMedia, (newVal) => { | |
houseAds.featuredSocialMedia = newVal; | |
change(); | |
markDirty("Ads", false); | |
}, "Social media select"); | |
socialMediaIcon.appendChild(socialIconSelect); | |
const PremFeatured = addRow(page, "admin-social-media"); | |
const premFeatOption = [ | |
["premFeatOne", "premFeatOne"], | |
["premFeatTwo", "premFeatTwo"] | |
]; | |
addSmallHeader(PremFeatured, "Select Premium featured tags", "left"); | |
const premFeatSelect = addSelect("idisidisid", premFeatOption, houseAds.premFeatured, (newVal) => { | |
houseAds.premFeatured = newVal; | |
change(); | |
markDirty("Ads", false); | |
}, "Premium featured tags"); | |
PremFeatured.appendChild(premFeatSelect); | |
specialTagStuff.appendChild(specialItemsTag); | |
specialTagStuff.appendChild(socialMediaIcon); | |
specialTagStuff.appendChild(PremFeatured); | |
if (!adNewsColumns.includes("linksToKotc")) { | |
adNewsColumns.splice(9, 0, "linksToKotc"); | |
} | |
function sortActiveAds(a, b2) { | |
if (!a.active && b2.active) | |
return 1; | |
if (a.active && !b2.active) | |
return -1; | |
} | |
houseAds.small.sort((a, b2) => sortActiveAds(a, b2)); | |
houseAds.big.sort((a, b2) => sortActiveAds(a, b2)); | |
houseAds.bigBanner.sort((a, b2) => sortActiveAds(a, b2)); | |
const adDiv = addDiv(page, "admin-ads-accordion", "accordion"); | |
const shellLogo = addRow(page, "admin-shell-logo"); | |
const shellLogoHeader = addSmallHeader(shellLogo, "Shell Logo(s)", "accordion-header"); | |
const shellLogoWrap = addDiv(shellLogo, "shell-logo-table", "hideme accordion-wrap"); | |
var shellLogoTable = createTable(houseAds.shellLogo, ["", "active", "label", "image"], null, cellFuncLogo, null); | |
shellLogoWrap.appendChild(shellLogoTable); | |
shellLogo.appendChild(shellLogoWrap); | |
adDiv.appendChild(shellLogo); | |
var list = addRow(page); | |
var bigHeader = addSmallHeader(list, "800x600 popup on front page +", "accordion-header"); | |
var bigTableWrap = addDiv(list, "big-table", "hideme accordion-wrap"); | |
var bigTable = createTable(houseAds.big, adNewsColumns, null, cellFuncLarge, null); | |
bigTableWrap.appendChild(bigTable); | |
list.appendChild(bigTableWrap); | |
adDiv.appendChild(list); | |
var list = addRow(page); | |
var bigTableWrap = addDiv(list, "sm-table", "hideme accordion-wrap"); | |
var smHeader = addSmallHeader(list, "House ads 300x250 +", "accordion-header"); | |
var smallTable = createTable(houseAds.small, adNewsColumns, null, cellFuncSmall, null); | |
bigTableWrap.appendChild(smallTable); | |
list.appendChild(bigTableWrap); | |
adDiv.appendChild(list); | |
var list = addRow(page); | |
var bigTableWrap = addDiv(list, "banner-table", "hideme accordion-wrap"); | |
var bannerHeader = addSmallHeader(list, "728x90 or 970x250 banner for ad blockers +", "accordion-header"); | |
var largeBannerTable = createTable(houseAds.bigBanner, adNewsColumns, null, cellFuncBigBanner, null); | |
bigTableWrap.appendChild(largeBannerTable); | |
list.appendChild(bigTableWrap); | |
adDiv.appendChild(list); | |
function toggleTable(el, table) { | |
const element = el.target ? el.target : el; | |
let text; | |
if (el.type === "click") { | |
text = el.target.innerText; | |
} else { | |
text = el.innerText; | |
} | |
text.indexOf("+") > -1 ? element.innerText = text.replace("+", "-") : element.innerText = text.replace("-", "+"); | |
document.getElementById(table).classList.toggle("hideme"); | |
} | |
bigHeader.onclick = (e) => toggleTable(e, "big-table"); | |
smHeader.onclick = (e) => toggleTable(e, "sm-table"); | |
bannerHeader.onclick = (e) => toggleTable(e, "banner-table"); | |
shellLogoHeader.onclick = (e) => toggleTable(e, "shell-logo-table"); | |
function cellFuncLogo(key, td) { | |
cellFunc(key, td, houseAds.shellLogo); | |
} | |
function cellFuncLarge(key, td) { | |
cellFunc(key, td, houseAds.big); | |
} | |
function cellFuncBigBanner(key, td) { | |
cellFunc(key, td, houseAds.bigBanner); | |
} | |
function cellFuncSmall(key, td) { | |
cellFunc(key, td, houseAds.small); | |
} | |
function cellFunc(key, td, category) { | |
td.category = category; | |
if (td.innerText === "undefined") | |
td.innerText = ""; | |
if (key == "") { | |
if (td.rowIdx < category.length - 1) { | |
var btn = document.createElement("div"); | |
btn.className = "roundButton removeButton"; | |
btn.onclick = () => { | |
delete category[td.rowIdx]; | |
td.parentElement.remove(); | |
change(); | |
}; | |
td.innerText = ""; | |
td.appendChild(btn); | |
} | |
} else if (key == "active" || key == "weighted") { | |
td.innerText = ""; | |
td.style = "text-align: center"; | |
var check = addCheckbox(td); | |
check.checked = category[td.rowIdx][key]; | |
check.onchange = () => { | |
category[td.rowIdx][key] = check.checked; | |
change(); | |
}; | |
} else if (key == "hideOnCG") { | |
td.innerText = ""; | |
td.style = "text-align: center"; | |
var check = addCheckbox(td); | |
check.checked = category[td.rowIdx].hideOnCG; | |
check.onchange = () => { | |
category[td.rowIdx].hideOnCG = check.checked; | |
change(); | |
}; | |
} else if (key == "linksToEggStoreItem") { | |
let sel = addSelect("products", skus, category[td.rowIdx][td.key]); | |
sel.onchange = () => { | |
category[td.rowIdx][td.key] = sel.options[sel.selectedIndex].value; | |
change(); | |
changedLink(td); | |
}; | |
td.innerText = ""; | |
td.appendChild(sel); | |
} else if (key == "image") { | |
var id = td.category[td.rowIdx].id; | |
if (!id) { | |
var img = document.createElement("img"); | |
img.src = "WHEE"; | |
img.className = "adThumbnail"; | |
img.onclick = () => { | |
openImageUploader(img); | |
}; | |
td.appendChild(img); | |
} else { | |
var img = document.createElement("img"); | |
img.src = "data/img/art/" + id + td.category[td.rowIdx].imageExt; | |
img.className = "adThumbnail"; | |
img.onclick = () => { | |
expandThumbnail(td.parentElement.children[2].firstChild.value, img); | |
}; | |
td.appendChild(img); | |
} | |
} else { | |
var crazyGame; | |
const links = []; | |
var input = document.createElement("input"); | |
var inputLabel; | |
var cgLabel; | |
if (key === "linkToShop") { | |
input.type = "number"; | |
input.min = 2; | |
input.max = 4; | |
} | |
if (key === "link") { | |
td.className = "link"; | |
inputLabel = document.createElement("label"); | |
inputLabel.innerText = "Link: "; | |
cgLabel = document.createElement("label"); | |
cgLabel.innerText = "CG: "; | |
crazyGame = document.createElement("input"); | |
if (!Array.isArray(category[td.rowIdx][td.key])) { | |
links.push(td.innerText); | |
category[td.rowIdx][td.key] = links; | |
input.value = td.innerText; | |
} else { | |
input.value = category[td.rowIdx][td.key][0]; | |
if (category[td.rowIdx][td.key].length > 0) { | |
crazyGame.value = category[td.rowIdx][td.key][1] ? category[td.rowIdx][td.key][1] : ""; | |
} | |
} | |
} else { | |
input.value = td.innerText; | |
} | |
if (key != "label") { | |
if (key === "link") { | |
input.oninput = () => { | |
category[td.rowIdx][td.key][0] = input.value; | |
changedLink(td); | |
fitToContent(input); | |
}; | |
input.className = key; | |
crazyGame.oninput = () => { | |
category[td.rowIdx][td.key][1] = crazyGame.value ? crazyGame.value : ""; | |
changedLink(td); | |
fitToContent(input); | |
}; | |
crazyGame.className = key; | |
} else { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
changedLink(td); | |
fitToContent(input); | |
}; | |
input.className = key; | |
} | |
} else { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
change(); | |
fitToContent(input); | |
}; | |
input.className = key; | |
} | |
if (key === "linkToShop") { | |
inputLabel = document.createElement("label"); | |
inputLabel.innerText = "2 = shop, 3 = featured, 4 = skins "; | |
} | |
td.innerText = ""; | |
if (crazyGame) { | |
td.appendChild(inputLabel); | |
} | |
fitToContent(input); | |
td.appendChild(input); | |
if (key === "linkToShop") { | |
td.appendChild(inputLabel); | |
} | |
if (crazyGame) { | |
td.appendChild(cgLabel); | |
fitToContent(input); | |
td.appendChild(crazyGame); | |
} | |
} | |
} | |
function expandThumbnail(name, imgEl) { | |
var d = openDialog(name); | |
var row = addRow(d); | |
addImage(row, imgEl.src); | |
var buttons2 = addRow(d); | |
addButton(buttons2, "Update", "green", () => { | |
openImageUploader(imgEl); | |
}); | |
addButton(buttons2, "Close", "red", () => { | |
closeDialog(); | |
}); | |
} | |
function openImageUploader(imgEl) { | |
closeDialog(); | |
openBinaryUploader((res) => { | |
var td = imgEl.parentElement; | |
td.category[td.rowIdx].image = res.data; | |
td.category[td.rowIdx].imageExt = res.ext; | |
imgEl.src = res.data; | |
change(); | |
}, ".png,.gif,.jpg,.jpeg,.svg"); | |
} | |
function change() { | |
saveButton.disabled = false; | |
discardButton.disabled = false; | |
} | |
function changedLink(td) { | |
var tr = td.parentElement; | |
for (var i2 = 5; i2 < 18; i2++) { | |
var cell = tr.children[i2]; | |
if (cell != td) { | |
var el = cell.firstChild; | |
if (cell.key === "link") { | |
for (const child of cell.children) { | |
if (child.tagName === "INPUT") { | |
child.value = ""; | |
} | |
} | |
cell.category[cell.rowIdx][cell.key] = []; | |
} else { | |
if (el) { | |
el.value = ""; | |
delete cell.category[cell.rowIdx][cell.key]; | |
} | |
} | |
} | |
} | |
saveButton.disabled = false; | |
discardButton.disabled = false; | |
} | |
function save() { | |
showSpinner(); | |
const openAcc = Array.from(document.querySelectorAll(".accordion-wrap")); | |
requestAction("uploadAds", { ads: houseAds }, () => { | |
hideSpinner(); | |
markDirty("Ads", true); | |
setTimeout(() => { | |
openAcc.forEach((el) => { | |
if (!el.classList.contains("hideme")) { | |
toggleTable(el.parentElement.firstChild, el.id); | |
} | |
}); | |
}, 200); | |
}); | |
} | |
} | |
function openAnnouncementTab() { | |
addTab("Announcement", false, renderAnnouncement); | |
} | |
function renderAnnouncement(page) { | |
let ws2 = new WebSocket(`wss://${location.host}/matchmaker/`); | |
ws2.onopen = () => { | |
ws2.send('{ "command": "regionList" }'); | |
}; | |
ws2.onmessage = (e) => { | |
let data = JSON.parse(e.data); | |
switch (data.command) { | |
case "regionList": | |
hideSpinner(); | |
finishRenderAnnouncement(page, data.regionList); | |
break; | |
case "notice": | |
announcementMessage = data.notices.announcement; | |
break; | |
} | |
}; | |
} | |
function finishRenderAnnouncement(page, regionList) { | |
var el = addCol(page, "center"); | |
addHeader(el, "Announcement"); | |
lineBreak(el).innerText = "current message"; | |
var oldMessage = addCol(el, "textBox"); | |
oldMessage.style.maxWidth = "20em"; | |
oldMessage.innerText = announcementMessage !== "" ? announcementMessage : "(none)"; | |
lineBreak(el); | |
lineBreak(el).innerText = "new message"; | |
var newMessage = addInputBox(el, "", null, null); | |
newMessage.placeholder = "Leave blank to remove current message"; | |
lineBreak(el); | |
var sendButton = addButton(el, "Send", "green"); | |
sendButton.onclick = () => { | |
showSpinner(); | |
requestAction("setAnnouncement", { message: newMessage.value }, () => { | |
hideSpinner(); | |
oldMessage.innerText = newMessage.value !== "" ? newMessage.value : "(none)"; | |
}); | |
}; | |
} | |
var badguys = []; | |
var histogram = []; | |
function openBadguysTab() { | |
addTab("Badguys", false, renderBadguys); | |
} | |
function renderBadguys(page) { | |
let responses = 0; | |
function response() { | |
if (++responses === 2) { | |
finishRenderBadguys(page); | |
} | |
} | |
requestAction("badguys", {}, (data) => { | |
hideSpinner(); | |
badguys = data.requestTracker; | |
response(); | |
}); | |
requestAction("getIpHistogram", {}, (data) => { | |
hideSpinner(); | |
histogram = Object.keys(data.histogram).map((ip) => { | |
return { ip, num: data.histogram[ip] }; | |
}).sort((a, b2) => { | |
return b2.num - a.num; | |
}); | |
response(); | |
}); | |
} | |
function finishRenderBadguys(page) { | |
var el = addCol(page, "center"); | |
addHeader(el, "Badguy Tracker"); | |
var requestRow = addRow(page); | |
var button = addButton(requestRow, "Refresh", "green"); | |
button.onclick = () => { | |
page.innerHTML = ""; | |
renderBadguys(page); | |
}; | |
var requestHeader = document.createElement("h3"); | |
requestHeader.innerText = "Services Requests by Request Type"; | |
requestRow.appendChild(requestHeader); | |
var requestCaption = document.createElement("div"); | |
requestCaption.innerText = "From IPs active in past 30 seconds with 10 or more requests per minute"; | |
requestRow.appendChild(requestCaption); | |
var list = addRow(page); | |
var columns = Object.keys(badguys); | |
var table = document.createElement("table"); | |
list.appendChild(table); | |
var header2 = document.createElement("tr"); | |
table.appendChild(header2); | |
for (var column of columns) { | |
var th = document.createElement("th"); | |
th.innerText = column; | |
header2.appendChild(th); | |
} | |
var contentRow = document.createElement("tr"); | |
table.appendChild(contentRow); | |
for (var column of columns) { | |
let cellFunc2 = function(key, td2) { | |
if (key === "ip") { | |
td2.style.cursor = "pointer"; | |
td2.onclick = () => { | |
openLogWindow(td2.innerText); | |
}; | |
} | |
}; | |
let data = badguys[column]; | |
let td = document.createElement("td"); | |
td.style.verticalAlign = "top"; | |
let innerTable = createTable(data, ["ip", "count", "perMinute"], null, cellFunc2, null); | |
td.appendChild(innerTable); | |
contentRow.appendChild(td); | |
} | |
lineBreak(page); | |
var row = addRow(page); | |
var header2 = document.createElement("h3"); | |
header2.innerText = "IP Histogram"; | |
row.appendChild(header2); | |
var caption = document.createElement("div"); | |
caption.innerText = "IPs currently connected to game clusters"; | |
row.appendChild(caption); | |
var table = createTable(histogram, ["ip", "num"], null, cellFunc, null); | |
row.appendChild(table); | |
function cellFunc(key, td) { | |
} | |
} | |
function openLogWindow(ip) { | |
var logWindow = window.open(); | |
logWindow.document.write("<style>body { background: #333; font-family: monospace; color: #ddd; }</style>"); | |
let ws2 = new WebSocket("wss://" + window.location.hostname + "/services-log/"); | |
ws2.onopen = () => { | |
ws2.send(JSON.stringify({ id: profile.id, adminKey, ip })); | |
}; | |
ws2.onmessage = (e) => { | |
logWindow.document.write(`<p>${e.data}</p>`); | |
}; | |
} | |
var ipBans = []; | |
var playerBans = []; | |
var playerReports = []; | |
function openBansTab() { | |
addTab("Bans", false, renderBans); | |
} | |
function renderBans(page) { | |
let responses = 0; | |
function response() { | |
if (++responses === 3) { | |
finishRenderBans(page); | |
} | |
} | |
requestAction("getIpBans", {}, (data) => { | |
hideSpinner(); | |
ipBans = data.rows; | |
response(); | |
}); | |
requestAction("getAllPlayerBans", {}, (data) => { | |
hideSpinner(); | |
playerBans = data.rows; | |
response(); | |
}); | |
requestAction("getPlayerReports", {}, (data) => { | |
hideSpinner(); | |
playerReports = data.rows; | |
response(); | |
}); | |
} | |
function finishRenderBans(page) { | |
var el = addCol(page, "center"); | |
addHeader(el, "Ban Management"); | |
var buttonRow = addRow(page); | |
var button = addButton(buttonRow, "Refresh", "green"); | |
button.onclick = () => { | |
page.innerHTML = ""; | |
renderBans(page); | |
}; | |
lineBreak(page); | |
var ipHeader = document.createElement("h3"); | |
ipHeader.innerText = "IP Bans"; | |
page.appendChild(ipHeader); | |
let banButton = addButton(page, "Add IP Ban", "red", () => { | |
openBanIpDialog(); | |
}); | |
var list = addRow(page); | |
function formatIpBans(column, td, row) { | |
if (column === "date" || column === "expire" || column === "lifted") { | |
if (td.innerHTML !== "") { | |
td.innerHTML = localTime(td.innerHTML); | |
} else { | |
if (row.expired) { | |
td.innerHTML = "Expired"; | |
} else { | |
td.innerHTML = ""; | |
var btn = document.createElement("div"); | |
btn.className = "smallButton green"; | |
btn.innerText = "Lift Ban"; | |
btn.onclick = () => { | |
liftIpBan(row.ip); | |
}; | |
td.appendChild(btn); | |
} | |
} | |
} else if (column === "admin_id") { | |
td.innerHTML = admins[parseInt(td.innerHTML, 10)].name; | |
} | |
} | |
var table = createTable(ipBans, ["admin_id", "ip", "date", "expire", "lifted", "reason"], null, formatIpBans, null); | |
list.appendChild(table); | |
function openBanIpDialog() { | |
var d = openDialog("Ban IP"); | |
var row = addRow(d); | |
var rowTwo = addRow(d); | |
var rowThree = addRow(d); | |
var banInputCount = 0; | |
function gotBanInput() { | |
if (++banInputCount === 3) { | |
banButton2.disabled = false; | |
} | |
} | |
var ipEl = addInput(row, "IP", "", null, () => gotBanInput()); | |
ipEl.style.width = "500px"; | |
var reasonEl = addInput(rowTwo, "Reason", "", null, () => gotBanInput()); | |
reasonEl.style.width = "500px"; | |
let list2 = [ | |
["15 MINUTE", "15 minutes"], | |
["30 MINUTE", "30 minutes"], | |
["1 HOUR", "1 hour"], | |
["1 DAY", "1 day"], | |
["1 WEEK", "1 week"], | |
["1 MONTH", "1 month"], | |
["1 YEAR", "1 year"] | |
]; | |
var durationEl = addSelect("", list2, "", () => gotBanInput(), "Duration"); | |
rowThree.appendChild(durationEl); | |
lineBreak(d); | |
var buttons = addRow(d); | |
let banButton2 = addButton(buttons, "Drop Ban Hammer", "red", () => { | |
let ip = ipEl.value; | |
let reason = reasonEl.value; | |
let duration = durationEl.value; | |
banIp(ip, duration, reason); | |
closeDialog(); | |
}); | |
addButton(buttons, "Show Mercy", "green", closeDialog); | |
} | |
function banIp(ip, duration, reason) { | |
requestAction("banIp", { ip, duration, reason }, (data) => { | |
hideSpinner(); | |
markDirty(page.id, true); | |
}); | |
} | |
function liftIpBan(ip) { | |
showSpinner(); | |
requestAction("liftIpBan", { ip }, (data) => { | |
hideSpinner(); | |
markDirty(page.id, true); | |
}); | |
} | |
lineBreak(page); | |
var playerHeader = document.createElement("h3"); | |
playerHeader.innerText = "Player Bans"; | |
page.appendChild(playerHeader); | |
var list = addRow(page); | |
function formatPlayerBans(column, td, row) { | |
if (column === "date" || column === "expire" || column === "lifted") { | |
if (td.innerHTML !== "") { | |
td.innerHTML = localTime(td.innerHTML); | |
} else if (row.expired) { | |
td.innerHTML = "Expired"; | |
} | |
} else if (column === "admin_id") { | |
td.innerHTML = admins[parseInt(td.innerHTML, 10)].name; | |
} else if (column === "player_id") { | |
makePlayerIdLink(td); | |
} | |
} | |
var table = createTable(playerBans, ["admin_id", "player_id", "date", "expire", "lifted", "reason"], null, formatPlayerBans, null); | |
list.appendChild(table); | |
lineBreak(page); | |
var reportHeader = document.createElement("h3"); | |
reportHeader.innerText = "Player Reports"; | |
page.appendChild(reportHeader); | |
var list = addRow(page); | |
function formatPlayerReports(column, td, row) { | |
if (column === "date_reported") { | |
td.innerHTML = localTime(td.innerHTML); | |
} else if (column === "reasons") { | |
let reasons = []; | |
let reasonMask = parseInt(td.innerText, 10); | |
for (let i2 = 0; i2 < reportReasons.length; i2++) { | |
if (reasonMask & 1 << i2) { | |
reasons.push(reportReasons[i2]); | |
} | |
} | |
td.innerHTML = reasons.join(", "); | |
} else if (column === "player_id" || column === "reporter_id") { | |
makePlayerIdLink(td); | |
} | |
} | |
var table = createTable(playerReports, ["player_id", "reporter_id", "date_reported", "reasons"], null, formatPlayerReports, null); | |
list.appendChild(table); | |
function makePlayerIdLink(td) { | |
td.className = "fieldValue link"; | |
td.onclick = function(playerId) { | |
return () => openPlayerDataFromPlayerId(playerId); | |
}(parseInt(td.innerText, 10)); | |
} | |
} | |
var statusEnum = { | |
open: 0, | |
active: 1, | |
closed: 2 | |
}; | |
var statusNames = ["open", "active", "closed"]; | |
function openInbox() { | |
var tab = addTab("Feedback", false, renderInbox); | |
tab.onKeyPress = (key) => { | |
switch (key) { | |
case "Backspace": | |
var row = tab.attachedPage.highlightedRow; | |
var rect = row.getBoundingClientRect(); | |
if (mouse.x >= rect.left && mouse.x < rect.right && mouse.y >= rect.top && mouse.y < rect.bottom) { | |
requestAction( | |
"setStatus", | |
{ status: statusEnum.closed, ticket_id: row.ticketId }, | |
() => { | |
markDirty("Feedback", true); | |
} | |
); | |
} | |
break; | |
} | |
}; | |
} | |
function renderInbox(page) { | |
var opts = { match: {}, order: [] }; | |
opts.match.status = []; | |
Object.keys(inboxListOpts.match.status).forEach((k) => { | |
opts.match.status.push(statusEnum[k]); | |
}); | |
opts.match.feedback_type = []; | |
Object.keys(inboxListOpts.match.feedback_type).forEach((k) => { | |
opts.match.feedback_type.push(FeedbackType[k]); | |
}); | |
if (inboxListOpts.match.admin_id) { | |
opts.match.admin_id = [inboxListOpts.match.admin_id]; | |
} | |
Object.keys(inboxListOpts.order).forEach((k) => { | |
opts.order.push(k + " " + inboxListOpts.order[k]); | |
}); | |
opts.limit = inboxListOpts.limit; | |
if (!inboxListOpts.order["date_created"]) { | |
opts.order.push("date_created desc"); | |
} | |
var filter = addRow(page, "fillWidth"); | |
var buttons = addCol(filter); | |
addButton(buttons, "\u21BB Refresh", "green", function() { | |
return () => { | |
markDirty("Feedback", true); | |
}; | |
}()); | |
addButton(buttons, "Filters", "orange", openFilterDialog); | |
addButton(buttons, '<div class="magGlass">\u26B2</div> Find Ticket', "blue", openFindDialog); | |
addRule(page); | |
var list = addRow(page); | |
addRule(page); | |
var pageCount = 0; | |
var pageSel = addRow(page); | |
addButton(pageSel, "\u25C0\u25C0", "blue", () => flipPage(-1e6)); | |
addButton(pageSel, "\u25C0", "blue", () => flipPage(-1)); | |
var pageNum = addButton(pageSel, " "); | |
pageNum.disabled = true; | |
addButton(pageSel, "\u25B6", "blue", () => flipPage(1)); | |
addButton(pageSel, "\u25B6\u25B6", "blue", () => flipPage(1e6)); | |
function flipPage(ofs) { | |
inboxListOpts.limit.start = Math.max(0, Math.min(inboxListOpts.limit.start + ofs * inboxListOpts.limit.count, (pageCount - 1) * inboxListOpts.limit.count)); | |
markDirty("Feedback", true); | |
} | |
var counts = [25, 50, 100]; | |
var count = addButton(pageSel, "show " + inboxListOpts.limit.count + " per page", "orange", () => { | |
popupList(counts, (idx) => { | |
inboxListOpts.limit.count = counts[idx]; | |
markDirty("Feedback", true); | |
}); | |
}); | |
var rowsFoundEl = addCol(pageSel, "fieldName"); | |
rowsFoundEl.style += "padding: 0px; margin-top: 10px; margin-left: 16px"; | |
requestAction("readInbox", opts, (data) => { | |
if (!data || data.rows.length == 0) { | |
list.innerText = "No data"; | |
return; | |
} | |
pageCount = Math.ceil(data.count / inboxListOpts.limit.count); | |
pageNum.innerText = Math.floor(inboxListOpts.limit.start / inboxListOpts.limit.count + 1) + " of " + pageCount; | |
rowsFoundEl.innerText = data.count + " records found"; | |
list.appendChild(createTable(data.rows, [ | |
"ticket_id", | |
"status", | |
"email", | |
"comments", | |
"date_created", | |
"feedback_type" | |
], rowFunc, cellFunc, colFunc)); | |
function rowFunc(row, tr) { | |
tr.className = "selectRow"; | |
tr.ticketId = row.ticket_id; | |
tr.onclick = function(id) { | |
return () => openTicket(id); | |
}(row.ticket_id); | |
tr.onmouseenter = function() { | |
return () => { | |
page.highlightedRow = tr; | |
}; | |
}(); | |
} | |
function cellFunc(key, td) { | |
if (key == "comments" && td.innerText.length > 64) { | |
td.innerText = td.innerText.substr(0, 64) + "..."; | |
} | |
if (key == "status") { | |
td.className += " " + td.innerText; | |
} | |
} | |
function colFunc(th) { | |
Object.keys(inboxListOpts.order).forEach((k) => { | |
if (k == th.label) { | |
var arrow = document.createElement("span"); | |
arrow.style.color = "slategray"; | |
if (inboxListOpts.order[k] == "asc") { | |
arrow.innerHTML = " \u25B4"; | |
} else { | |
arrow.innerHTML = " \u25BE"; | |
} | |
th.appendChild(arrow); | |
} | |
}); | |
th.onclick = function() { | |
return () => sortInbox(th.label); | |
}(); | |
} | |
}); | |
} | |
function sortInbox(colName) { | |
if (inboxListOpts.order[colName]) { | |
if (inboxListOpts.order[colName] == "desc") { | |
inboxListOpts.order = {}; | |
inboxListOpts.order[colName] = "asc"; | |
} else { | |
delete inboxListOpts.order[colName]; | |
} | |
} else { | |
inboxListOpts.order = {}; | |
inboxListOpts.order[colName] = "desc"; | |
} | |
markDirty("Feedback", true); | |
} | |
function openPlayersTab() { | |
addTab("Players", false, renderPlayers); | |
} | |
function renderPlayers(page) { | |
var el = addCol(page, "center"); | |
addHeader(el, "Player Management"); | |
var row = addRow(el); | |
var emailIn = addInput(row, "email", null, () => { | |
openPlayerDataFromEmail(emailIn.value); | |
emailIn.value = ""; | |
}); | |
emailIn.size = 40; | |
var row = addRow(el); | |
var firebaseIn = addInput(row, "firebase id", null, () => { | |
openPlayerDataFromFirebaseId(firebaseIn.value); | |
firebaseIn.value = ""; | |
}); | |
firebaseIn.size = 40; | |
var row = addRow(el); | |
var idIn = addInput(row, "player id", null, () => { | |
openPlayerDataFromPlayerId(idIn.value); | |
idIn.value = ""; | |
}); | |
idIn.size = 40; | |
var row = addRow(el); | |
var ipIn = addInput(row, "IP address", null, () => { | |
openPlayerDataFromIP(ipIn.value); | |
ipIn.value = ""; | |
}); | |
ipIn.size = 40; | |
var button = addButton(el, "Search", "green"); | |
button.onclick = () => { | |
if (emailIn.value) { | |
openPlayerDataFromEmail(emailIn.value); | |
emailIn.value = ""; | |
} else if (firebaseIn.value) { | |
openPlayerDataFromFirebaseId(firebaseIn.value); | |
firebaseIn.value = ""; | |
} else if (idIn.value) { | |
openPlayerDataFromPlayerId(idIn.value); | |
idIn.value = ""; | |
} else if (ipIn.value) { | |
openPlayerDataFromIP(ipIn.value); | |
ipIn.value = ""; | |
} | |
}; | |
} | |
function openFindDialog() { | |
var d = openDialog("Find Ticket"); | |
var row = addRow(d); | |
var ticketIn = addInput(row, "Ticket ID", null, (value) => { | |
closeDialog(); | |
openTicket(Number.parseInt(value, 10)); | |
}); | |
ticketIn.size = 30; | |
ticketIn.focus(); | |
var buttons = addRow(d); | |
addButton(buttons, "Find", "green", () => { | |
closeDialog(); | |
openTicket(Number.parseInt(ticketIn.value, 10)); | |
}); | |
addButton(buttons, "Cancel", "red", closeDialog); | |
} | |
function openFilterDialog() { | |
var d = openDialog("Filters"); | |
var row = addRow(d); | |
var assignCheck = addCheckbox(row, "Assigned to me"); | |
assignCheck.checked = inboxListOpts.match.admin_id ? true : false; | |
lineBreak(d); | |
var row = addRow(d); | |
var col = addCol(row, "section"); | |
addSmallHeader(col, "status"); | |
statusChecks = {}; | |
for (var i2 in statusNames) { | |
var name = statusNames[i2]; | |
statusChecks[name] = addCheckbox(addRow(col), name); | |
statusChecks[name].checked = inboxListOpts.match.status[name]; | |
} | |
; | |
colBreak(row); | |
var col = addCol(row, "section"); | |
addSmallHeader(col, "feedback_type"); | |
typeChecks = {}; | |
Object.keys(FeedbackType).forEach((k) => { | |
typeChecks[k] = addCheckbox(addRow(col), k); | |
typeChecks[k].checked = inboxListOpts.match.feedback_type[k]; | |
}); | |
lineBreak(row); | |
var row = addRow(d); | |
addButton(row, "Apply", "green", apply); | |
addButton(row, "Cancel", "red", closeDialog); | |
function apply() { | |
inboxListOpts.match.status = {}; | |
inboxListOpts.match.feedback_type = {}; | |
Object.keys(statusChecks).forEach((k) => { | |
if (statusChecks[k].checked) { | |
inboxListOpts.match.status[k] = true; | |
} | |
}); | |
Object.keys(typeChecks).forEach((k) => { | |
if (typeChecks[k].checked) { | |
inboxListOpts.match.feedback_type[k] = true; | |
} | |
}); | |
inboxListOpts.match.admin_id = assignCheck.checked ? profile.id : null; | |
closeDialog(); | |
markDirty("Feedback", true); | |
} | |
} | |
function addRule(dom) { | |
var el = document.createElement("hr"); | |
dom.appendChild(el); | |
return el; | |
} | |
function lineBreak(dom) { | |
var el = document.createElement("div"); | |
el.innerHTML = " "; | |
dom.appendChild(el); | |
return el; | |
} | |
function colBreak(dom) { | |
var el = document.createElement("div"); | |
el.className = "colBreak"; | |
dom.appendChild(el); | |
return el; | |
} | |
function addInput(dom, title, value, onEnter, onKeyUp, isType) { | |
var div = document.createElement("div"); | |
div.className = "inputContainer"; | |
var input = document.createElement("input"); | |
if (isType) | |
input.type = isType; | |
input.onkeydown = (e) => { | |
if (e.code == "ENTER") { | |
input.blur(); | |
if (onEnter) | |
onEnter(input.value); | |
} | |
}; | |
input.onkeyup = (e) => { | |
if (onKeyUp) | |
onKeyUp(input.value); | |
}; | |
input.value = value || ""; | |
div.appendChild(input); | |
if (title) { | |
var titleEl = document.createElement("div"); | |
titleEl.innerText = title; | |
titleEl.className = "inputTitle"; | |
div.appendChild(titleEl); | |
} | |
dom.appendChild(div); | |
return input; | |
} | |
function addCol(dom, className) { | |
var el = document.createElement("div"); | |
el.className = "col " + className; | |
dom.appendChild(el); | |
return el; | |
} | |
function addRow(dom, className) { | |
className = className || ""; | |
var el = document.createElement("div"); | |
el.className = "row " + className; | |
dom.appendChild(el); | |
return el; | |
} | |
function addHeader(dom, text, className) { | |
var el = document.createElement("h2"); | |
el.innerText = text; | |
el.className = className ? className : "center"; | |
dom.appendChild(el); | |
return el; | |
} | |
function addSmallHeader(dom, text, styled) { | |
let isClass = !styled ? "center" : styled; | |
var el = document.createElement("h3"); | |
el.innerText = text; | |
el.className = isClass; | |
dom.appendChild(el); | |
return el; | |
} | |
function addButton(dom, label, color, onclick) { | |
var el = document.createElement("button"); | |
if (color) | |
el.className = color; | |
el.innerHTML = label; | |
if (onclick) | |
el.onclick = onclick; | |
if (dom) | |
dom.appendChild(el); | |
return el; | |
} | |
function addCheckbox(dom, name, onChanged) { | |
name = name || ""; | |
var container = document.createElement("div"); | |
container.style.display = "inline-block"; | |
var check = document.createElement("input"); | |
check.type = "checkbox"; | |
container.appendChild(check); | |
if (name) { | |
var label = document.createElement("label"); | |
label.style.display = "inline-block"; | |
label.innerText = name; | |
container.appendChild(label); | |
} | |
if (dom) | |
dom.appendChild(container); | |
if (onChanged) { | |
check.onclick = function(name2, el) { | |
return () => onChanged(name2, el.checked); | |
}(name, check); | |
} | |
return check; | |
} | |
function addImage(dom, src) { | |
var img = document.createElement("img"); | |
img.src = src; | |
if (dom) | |
dom.appendChild(img); | |
return img; | |
} | |
function addFields(dom, data, keys, func) { | |
var nameCol = addCol(dom); | |
var valCol = addCol(dom); | |
dom.className += " fieldBlock"; | |
for (var i2 in keys) { | |
var el = addRow(nameCol); | |
var keyEl = addCol(el, "fieldName"); | |
var el = addRow(valCol); | |
var valEl = addCol(el, "fieldValue"); | |
var key = keys[i2]; | |
var val = data[keys[i2]]; | |
if (val == null) { | |
valEl.className = "fieldValue small"; | |
val = "N/A"; | |
} | |
if (key == "date_modified" || key == "date_created" || key == "login") { | |
val = localTime(val); | |
} | |
keyEl.innerText = key; | |
valEl.innerText = val; | |
if (func) | |
func(keyEl, valEl); | |
} | |
} | |
function addField(dom, label, value) { | |
var el = addRow(dom); | |
addCol(el, "fieldName").innerText = label + ": "; | |
addCol(el, "fieldValue").innerText = value; | |
return el; | |
} | |
function getFieldName(el) { | |
return el.children[0]; | |
} | |
function getFieldValue(el) { | |
return el.children[1]; | |
} | |
function addSelect(id, options, selected, onchangeFc, label, multiple) { | |
const wrap = document.createElement("div"), select = document.createElement("select"), opDefault = document.createElement("option"), elLabel = document.createElement("label"); | |
select.id = id; | |
select.name = id; | |
if (multiple) | |
select.multiple = true; | |
opDefault.textContent = "Select option"; | |
opDefault.disabled = true; | |
opDefault.selected = selected ? false : true; | |
opDefault.value = null; | |
select.appendChild(opDefault); | |
if (label) { | |
elLabel.innerText = label; | |
elLabel.htmlFor = id; | |
elLabel.className = "inputTitle"; | |
} | |
options.forEach((option) => { | |
let child = document.createElement("option"); | |
child.value = option[0]; | |
if (selected === option[0]) | |
child.selected = true; | |
child.innerText = option[1] ? option[1] : option[0]; | |
select.appendChild(child); | |
}); | |
select.onchange = (e) => { | |
wrap.value = select.value; | |
if (onchangeFc) | |
onchangeFc(select.value); | |
}; | |
wrap.appendChild(select); | |
if (label) { | |
wrap.appendChild(elLabel); | |
} | |
return wrap; | |
} | |
function addInputBox(dom, title, value, onKeyUp) { | |
var div = document.createElement("div"); | |
div.className = "inputContainer"; | |
var input = document.createElement("textarea"); | |
input.cols = 40; | |
input.rows = 3; | |
input.onkeyup = (e) => { | |
if (onKeyUp) | |
onKeyUp(input.value); | |
}; | |
input.value = value || ""; | |
div.appendChild(input); | |
var titleEl = document.createElement("div"); | |
titleEl.innerText = title; | |
titleEl.className = "inputTitle"; | |
div.appendChild(titleEl); | |
dom.appendChild(div); | |
return input; | |
} | |
function addDiv(dom, id, divClass) { | |
var div = document.createElement("div"); | |
div.id = id; | |
div.className = divClass || "add-div"; | |
dom.appendChild(div); | |
return div; | |
} | |
function copyToClipboard(str) { | |
var e = document.getElementById("clipboard"); | |
e.value = str; | |
e.select(); | |
try { | |
document.execCommand("copy"); | |
} catch (err) { | |
console.log("Unable to copy to clipboard"); | |
} | |
} | |
var fetchJson = (jsonData, jsonDoc, callback) => { | |
var newData = []; | |
jsonData.splice(0, jsonData.length); | |
getRequest(jsonDoc + Date.now(), (err, res) => { | |
if (err === 404) { | |
console.log("Accept it and move on."); | |
} else { | |
try { | |
const parsedJson = JSON.parse(res); | |
if (parsedJson.length > 0) { | |
parsedJson.forEach((item) => newData.push(item)); | |
} | |
} catch (e) { | |
console.log("Fetch json request error: ", e); | |
} | |
} | |
newData.push({}); | |
if (callback !== null) | |
callback(); | |
}); | |
return newData; | |
}; | |
function openMediaTab() { | |
addTab("Media", false, renderMedia); | |
} | |
function renderMedia(page) { | |
newsItems = fetchJson(newsItems, "data/shellNews.json?", () => finishRenderMedia(page)); | |
setTimeout(() => { | |
shellYouTube = fetchJson(shellYouTube, "data/shellYouTube.json?", () => finishRenderYTube(page)); | |
}, 50); | |
} | |
var newsIsDraggable = true; | |
function finishRenderMedia(page) { | |
const list = addRow(page, "media-dashboard-container"); | |
const newsColumns = [...newsColums]; | |
newsColumns[newsColumns.indexOf("label")] = "content"; | |
newsColumns.splice(8, 0, "linksToChangeLog"); | |
newsColumns.splice(0, 0, ""); | |
newsColumns.push("hideOnCrazyGames"); | |
if (!newsColumns.includes("linksToKotc")) { | |
newsColumns.splice(11, 0, "linksToKotc"); | |
} | |
const buttons = addRow(page, "btn-group-news"); | |
const saveButton = addButton(buttons, "Save Changes", "green", save), discardButton = addButton(buttons, "Discard", "red", () => { | |
markDirty("Media", true); | |
newsIsDraggable = true; | |
}); | |
saveButton.disabled = true; | |
discardButton.disabled = true; | |
const newsTable = createTable(newsItems, newsColumns, rowFunc, cellFuncLarge, null); | |
addHeader(list, "Shell News"); | |
list.appendChild(newsTable); | |
let draggedRow = null, draggedData = null, dragOver = null; | |
const newsBackup = newsItems.length - 1; | |
function rowFunc(row, tr) { | |
function idGenerate(length) { | |
let result = ""; | |
let characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |
let charactersLength = characters.length; | |
for (let i2 = 0; i2 < length; i2++) { | |
result += characters.charAt(Math.floor(Math.random() * charactersLength)); | |
} | |
return result; | |
} | |
if ("content" in row) { | |
tr.draggable = true; | |
const rando = idGenerate(6); | |
row.elId = rando; | |
tr.id = rando; | |
} else { | |
tr.draggable = false; | |
} | |
if (!newsIsDraggable) { | |
tr.draggable = false; | |
return; | |
} | |
tr.ondragstart = function(e) { | |
e.currentTarget.style.backgroundColor = "gray"; | |
e.currentTarget.style.visiblity = "hidden"; | |
draggedData = row; | |
draggedRow = this; | |
}; | |
tr.ondragenter = function(e) { | |
e.preventDefault(); | |
e.currentTarget.style.visiblity = "hidden"; | |
dragOver = this; | |
if (draggedRow == this) { | |
return false; | |
} | |
}; | |
tr.ondragover = function(e) { | |
e.preventDefault(); | |
e.currentTarget.style.backgroundColor = "lightgray"; | |
}; | |
tr.ondragleave = function(e) { | |
e.currentTarget.style.backgroundColor = "initial"; | |
}; | |
tr.ondragend = function(e) { | |
const moveElement = (array, initialIndex, finalIndex) => { | |
if (initialIndex === -1 || finalIndex === -1) { | |
return false; | |
} | |
array.pop(); | |
array.splice(finalIndex, 0, array.splice(initialIndex, 1)[0]); | |
array.push({}); | |
return array; | |
}; | |
this.classList.remove("is-dragging"); | |
e.currentTarget.style.backgroundColor = "none"; | |
const getDragOverId = dragOver.id, getDraggedId = draggedRow.id, dragItemIdx = newsItems.findIndex((i2) => i2.elId === getDraggedId), dragOverItemIdx = newsItems.findIndex((i2) => i2.elId === getDragOverId); | |
const newArray = moveElement(newsItems, dragItemIdx, dragOverItemIdx); | |
if (!newArray) { | |
console.log("Drag failed"); | |
save(); | |
return; | |
} | |
if (draggedRow !== dragOver) { | |
newsTable.insertBefore(draggedRow, dragOver); | |
} | |
newsItems = newArray; | |
save(); | |
}; | |
tr.ondrop = function(e) { | |
}; | |
} | |
function cellFuncLarge(key, td) { | |
cellFunc(key, td, newsItems); | |
} | |
function cellFunc(key, td, category) { | |
td.category = category; | |
if (td.innerText === "undefined") | |
td.innerText = ""; | |
if (key == "") { | |
if (td.rowIdx < category.length - 1) { | |
if (td.previousSibling) { | |
td.innerHTML = "☰"; | |
td.className = "draggable"; | |
td.draggable = false; | |
} else { | |
var btn = document.createElement("div"); | |
btn.className = "roundButton removeButton"; | |
btn.onclick = () => { | |
delete category[td.rowIdx]; | |
td.parentElement.remove(); | |
change(); | |
}; | |
td.innerText = ""; | |
td.appendChild(btn); | |
} | |
} | |
} else if (key == "active") { | |
td.innerText = ""; | |
td.style = "text-align: center"; | |
var check = addCheckbox(td); | |
check.checked = category[td.rowIdx].active; | |
check.onchange = () => { | |
category[td.rowIdx].active = check.checked; | |
change(); | |
}; | |
} else if (key == "linksToEggStoreItem") { | |
let sel = addSelect("products", skus, category[td.rowIdx][td.key]); | |
sel.onchange = () => { | |
category[td.rowIdx][td.key] = sel.options[sel.selectedIndex].value; | |
change(); | |
changedLink(td, key); | |
}; | |
td.innerText = ""; | |
td.appendChild(sel); | |
} else if (key == "image") { | |
var id = td.category[td.rowIdx].id; | |
if (!id) { | |
var img = document.createElement("img"); | |
img.src = "WHEE"; | |
img.className = "adThumbnail"; | |
img.onclick = () => { | |
openImageUploader(img); | |
}; | |
td.appendChild(img); | |
} else { | |
var img = document.createElement("img"); | |
img.src = "data/img/newsItems/" + id + td.category[td.rowIdx].imageExt; | |
img.className = "adThumbnail"; | |
img.onclick = () => { | |
expandThumbnail(td.parentElement.children[2].firstChild.value, img); | |
}; | |
td.appendChild(img); | |
} | |
} else { | |
var input = document.createElement("input"); | |
input.value = td.innerText; | |
if (key != "content") { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
changedLink(td, key); | |
fitToContent(input); | |
}; | |
input.className = key; | |
} else { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
change(); | |
fitToContent(input); | |
}; | |
input.className = key; | |
} | |
fitToContent(input); | |
td.innerText = ""; | |
td.appendChild(input); | |
} | |
} | |
function expandThumbnail(name, imgEl) { | |
var d = openDialog(name); | |
var row = addRow(d); | |
addImage(row, imgEl.src); | |
var buttons2 = addRow(d); | |
addButton(buttons2, "Update", "green", () => { | |
openImageUploader(imgEl); | |
}); | |
addButton(buttons2, "Close", "red", () => { | |
closeDialog(); | |
}); | |
} | |
function openImageUploader(imgEl) { | |
closeDialog(); | |
openBinaryUploader((res) => { | |
var td = imgEl.parentElement; | |
td.category[td.rowIdx].image = res.data; | |
td.category[td.rowIdx].imageExt = res.ext; | |
imgEl.src = res.data; | |
change(); | |
}, ".png,.gif,.jpg,.jpeg"); | |
} | |
function change() { | |
newsIsDraggable = false; | |
saveButton.disabled = false; | |
discardButton.disabled = false; | |
} | |
function changedLink(td, key) { | |
if (key !== "hideOnCrazyGames") { | |
var tr = td.parentElement; | |
for (var i2 = 4; i2 < 13; i2++) { | |
var cell = tr.children[i2]; | |
if (cell != td) { | |
var el = cell.firstChild; | |
if (el) { | |
el.value = ""; | |
delete cell.category[cell.rowIdx][cell.key]; | |
} | |
} | |
} | |
} | |
saveButton.disabled = false; | |
discardButton.disabled = false; | |
} | |
function save() { | |
showSpinner(); | |
newsIsDraggable = true; | |
requestAction("shellNews", { news: newsItems }, () => { | |
hideSpinner(); | |
markDirty("Media", true); | |
}); | |
} | |
} | |
var yTubeIsDraggable = true; | |
function finishRenderYTube(page) { | |
const yContent = addRow(page, "youtube-dashboard-container"), buttons = addRow(page, "btn-group-news"), youTubeColumns = ["", "active", "title", "author", "desc", "link", "image"], saveButton = addButton(buttons, "Save Changes", "green", save), discardButton = addButton(buttons, "Discard", "red", () => { | |
markDirty("Media", true); | |
yTubeIsDraggable = true; | |
}); | |
let yTubeTable = createTable(shellYouTube, youTubeColumns, rowFunc, cellFuncLarge, null); | |
function addVideoError() { | |
var d = openDialog("No video content. Wrong id?"); | |
var buttons2 = addRow(d); | |
addButton(buttons2, "Close", "red", () => { | |
closeDialog(); | |
}); | |
} | |
function addVideo() { | |
var d = openDialog("Add Video Id"); | |
var row = addRow(d); | |
var input = document.createElement("input"); | |
input.placeholder = "video id eg. SvPlRd7xjAs"; | |
d.appendChild(input); | |
var buttons2 = addRow(d); | |
addButton(buttons2, "Add", "green", () => { | |
getVideoContent(input.value); | |
closeDialog(); | |
}); | |
addButton(buttons2, "Close", "red", () => { | |
closeDialog(); | |
}); | |
} | |
function getVideoContent(id) { | |
const youTube = "youtube.com/watch?v=", youTubeOembed = "https://www.youtube.com/oembed?url=http://", prep = { active: true, link: "https://www." + youTube + id, desc: "", imageExt: "" }; | |
fetch(youTubeOembed + youTube + id + "&format=json", { | |
// mode: 'no-cors', | |
headers: { | |
method: "GET", | |
"Content-Type": "application/json", | |
Accept: "application/json" | |
} | |
}).then((res) => { | |
showSpinner(); | |
if (!res.ok) | |
return addVideoError(); | |
return res.json(); | |
}).then((data) => { | |
if (data === void 0) { | |
hideSpinner(); | |
return; | |
} | |
setTimeout(() => { | |
change(); | |
prep.id = id; | |
prep.author = data.author_name; | |
prep.title = data.title; | |
prep.externalImg = data.thumbnail_url; | |
shellYouTube.unshift(prep); | |
yTubeTable.parentElement.removeChild(yTubeTable); | |
yTubeTable = createTable(shellYouTube, youTubeColumns, rowFunc, cellFuncLarge, null); | |
hideSpinner(); | |
yContent.appendChild(yTubeTable); | |
}, 250); | |
}); | |
} | |
let addVideoBtn = addButton(buttons, "+ Add video", "green", addVideo); | |
saveButton.disabled = true; | |
discardButton.disabled = true; | |
addHeader(yContent, "YouTube"); | |
yContent.appendChild(addVideoBtn); | |
yContent.appendChild(yTubeTable); | |
const yTubeBackup = shellYouTube.length - 1; | |
let draggedRow = null, dragOver = null; | |
function rowFunc(row, tr) { | |
if ("title" in row) { | |
tr.draggable = true; | |
} else { | |
tr.draggable = false; | |
} | |
if (!yTubeIsDraggable) { | |
tr.draggable = false; | |
return; | |
} | |
tr.ondragenter = function(e) { | |
dragOver = this; | |
if (draggedRow == this) | |
return false; | |
this.classList.add("dragOver"); | |
}; | |
tr.ondragleave = function(e) { | |
this.classList.remove("dragOver"); | |
}; | |
tr.ondragstart = function(e) { | |
if (!yTubeIsDraggable) { | |
alert("Save changes or discard before dragging, please."); | |
return; | |
} | |
; | |
this.classList.add("dragging"); | |
draggedRow = this; | |
}; | |
tr.ondragend = function(e) { | |
this.classList.remove("dragging"); | |
if (!yTubeIsDraggable) { | |
return; | |
} | |
; | |
if (draggedRow != dragOver) { | |
yTubeTable.insertBefore(draggedRow, dragOver); | |
} | |
let tempItems = []; | |
for (let r = 1; r < yTubeTable.rows.length - 1; r++) { | |
let row2 = yTubeTable.rows[r]; | |
tempItems.push(shellYouTube[row2.rowIdx]); | |
row2.rowIdx = r; | |
} | |
const removeNull = tempItems.filter((el) => el != null); | |
if (removeNull.length === yTubeBackup) { | |
shellYouTube.splice(0, shellYouTube.length); | |
if (tempItems.length > 0) { | |
tempItems.forEach((item) => shellYouTube.push(item)); | |
} | |
save(); | |
} else { | |
saveButton.disabled = true; | |
discardButton.disabled = true; | |
markDirty("Media", true); | |
alert("Doh, drag & drop goofed. Resetting. SORRY!"); | |
return; | |
} | |
}; | |
} | |
function cellFuncLarge(key, td) { | |
cellFunc(key, td, shellYouTube); | |
} | |
function cellFunc(key, td, category) { | |
td.category = category; | |
if (td.innerText === "undefined") | |
td.innerText = ""; | |
if (key == "") { | |
if (td.rowIdx < category.length - 1) { | |
if (td.previousSibling) { | |
td.innerHTML = "☰"; | |
td.className = "draggable"; | |
td.draggable = false; | |
} else { | |
var actions = document.createElement("div"); | |
var btn = document.createElement("div"); | |
var move = document.createElement("div"); | |
actions.className = "display-flex flex-align-center"; | |
move.innerHTML = "☰"; | |
move.className = "draggable margin-right-1"; | |
move.draggable = false; | |
btn.className = "roundButton removeButton"; | |
btn.onclick = () => { | |
delete category[td.rowIdx]; | |
td.parentElement.remove(); | |
change(); | |
}; | |
td.innerText = ""; | |
actions.appendChild(move); | |
actions.appendChild(btn); | |
td.appendChild(actions); | |
} | |
} | |
} else if (key == "active") { | |
td.innerText = ""; | |
td.style = "text-align: center"; | |
var check = addCheckbox(td); | |
check.checked = category[td.rowIdx].active; | |
check.onchange = () => { | |
category[td.rowIdx].active = check.checked; | |
change(); | |
}; | |
} else if (key == "image") { | |
const id = td.category[td.rowIdx].imageId; | |
if (!id && !td.category[td.rowIdx].externalImg) { | |
var img = document.createElement("img"); | |
img.src = "WHEE"; | |
img.className = "adThumbnail"; | |
img.onclick = () => { | |
openImageUploader(img); | |
}; | |
td.appendChild(img); | |
} else { | |
var img = document.createElement("img"); | |
if (td.category[td.rowIdx].imageExt) { | |
img.src = "data/img/youtube/" + id + td.category[td.rowIdx].imageExt; | |
} else { | |
img.src = td.category[td.rowIdx].externalImg; | |
} | |
img.className = "adThumbnail"; | |
img.onclick = () => { | |
expandThumbnail(td.parentElement.children[2].firstChild.value, img); | |
}; | |
td.appendChild(img); | |
} | |
} else { | |
var input = document.createElement("input"); | |
input.value = td.innerText; | |
if (key != "content") { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
fitToContent(input); | |
change(); | |
}; | |
input.className = key; | |
} else { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
change(); | |
fitToContent(input); | |
}; | |
input.className = key; | |
} | |
fitToContent(input); | |
td.innerText = ""; | |
td.appendChild(input); | |
} | |
} | |
function expandThumbnail(name, imgEl) { | |
var d = openDialog(name); | |
var row = addRow(d); | |
addImage(row, imgEl.src); | |
var buttons2 = addRow(d); | |
addButton(buttons2, "Update", "green", () => { | |
openImageUploader(imgEl); | |
}); | |
addButton(buttons2, "Close", "red", () => { | |
closeDialog(); | |
}); | |
} | |
function openImageUploader(imgEl) { | |
closeDialog(); | |
openBinaryUploader((res) => { | |
var td = imgEl.parentElement; | |
td.category[td.rowIdx].image = res.data; | |
td.category[td.rowIdx].imageExt = res.ext; | |
imgEl.src = res.data; | |
change(); | |
}, ".png,.gif,.jpg,.jpeg"); | |
} | |
function change() { | |
newsIsDraggable = false; | |
saveButton.disabled = false; | |
discardButton.disabled = false; | |
} | |
function save() { | |
showSpinner(); | |
newsIsDraggable = true; | |
requestAction("shellYoutube", { videos: shellYouTube }, (data) => { | |
hideSpinner(); | |
markDirty("Media", true); | |
}); | |
} | |
} | |
var vipAvailable = []; | |
var activeSub = { | |
accounts: [] | |
}; | |
function openPlayerDataFromTicket(ticketId, firebaseId) { | |
if (openTabByName("PLR-" + ticketId, true)) | |
return; | |
addTab("PLR-" + ticketId, true, (page) => { | |
page.ticketId = ticketId; | |
page.firebaseId = firebaseId; | |
renderPlayerData(page); | |
}); | |
} | |
function openPlayerDataFromFirebaseId(firebaseId, ip) { | |
if (openTabByName("PLR-" + firebaseId, true)) | |
return; | |
addTab("PLR-" + firebaseId, true, (page) => { | |
page.firebaseId = firebaseId; | |
page.ip = ip; | |
renderPlayerData(page); | |
}); | |
} | |
function openPlayerDataFromEmail(email) { | |
if (openTabByName("PLR-" + email, true)) | |
return; | |
addTab("PLR-" + email, true, (page) => { | |
page.email = email; | |
renderPlayerData(page); | |
}); | |
} | |
function openPlayerDataFromPlayerId(id) { | |
if (openTabByName("PLR-" + id, true)) | |
return; | |
addTab("PLR-" + id, true, (page) => { | |
page.playerId = id; | |
renderPlayerData(page); | |
}); | |
} | |
function openPlayerDataFromIP(ip) { | |
if (openTabByName("PLR-" + ip, true)) | |
return; | |
addTab("PLR-" + ip, true, (page) => { | |
page.ip = ip; | |
renderPlayerData(page); | |
}); | |
} | |
function renderPlayerData(page) { | |
var ticketId = page.ticketId; | |
const firebaseId = page.firebaseId; | |
const ip = page.ip; | |
let currentFirebaseId = page.firebaseId ? page.firebaseId : null; | |
var email = page.email; | |
var playerId = page.playerId; | |
var impersonateFunc = function(impersonateId) { | |
var baseUrl = location.protocol + "//" + location.hostname + (location.port ? ":" + location.port : ""); | |
window.open(baseUrl + "?adminImpersonate=" + impersonateId); | |
}; | |
var criteria; | |
if (firebaseId) { | |
criteria = { firebase_id: firebaseId }; | |
} else if (email) { | |
criteria = { email }; | |
} else if (playerId) { | |
criteria = { id: playerId }; | |
} else if (ip) { | |
criteria = { ip }; | |
} | |
requestAction("getPlayer", criteria, (data) => { | |
if (!data.result) { | |
page.innerText = "Player not found"; | |
return; | |
} | |
data = data.result; | |
currentFirebaseId = data.firebase_id; | |
playerId = data.id; | |
parseRow("data"); | |
var col = addCol(page); | |
addButton(col, "Impersonate", "green", () => { | |
return impersonateFunc(data.firebase_id); | |
}); | |
addButton(col, "Transfer Account", "orange", () => { | |
openTransferPlayerDialog(data.id, data.firebase_id); | |
}); | |
addButton(col, "Delete Account", "red", () => { | |
openDeletePlayerDialog(data); | |
}); | |
if (page.ip) { | |
addCol(page, "colBreak").innerText = "IP: " + page.ip; | |
} | |
lineBreak(page); | |
var profileRow = addRow(page); | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "Bans"; | |
var banButtonRow = addRow(page); | |
let banButton = addButton(banButtonRow, "Ban Player", "red", () => { | |
openBanPlayerDialog(playerId); | |
}); | |
let liftBanButton = addButton(banButtonRow, "Lift Ban", "green", () => { | |
liftPlayerBan(playerId); | |
}); | |
banButton.style.display = "none"; | |
liftBanButton.style.display = "none"; | |
var banRow = addRow(page); | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "Content Creator"; | |
const CREATOR = addRow(page); | |
let newData = [], origData; | |
addButton(CREATOR, "Add", "orange", () => { | |
openAddCreatorDialog(); | |
}); | |
const saveButton = addButton(CREATOR, "Save Changes", "green", saveCreator), discardButton = addButton(CREATOR, "Discard", "red", () => { | |
}); | |
saveButton.disabled = true; | |
discardButton.disabled = true; | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "Upgrades"; | |
var upgrade = addRow(page); | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "Refunds"; | |
var refundArea = addRow(page); | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "transactions"; | |
var transRow = addRow(page); | |
lineBreak(page); | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "items"; | |
var itemRow = addRow(page); | |
var links = { | |
current_balance: true, | |
kills: true, | |
deaths: true, | |
streak: true | |
}; | |
var col = addCol(profileRow); | |
addFields(col, data, [ | |
"id", | |
"firebase_id", | |
"providers", | |
"email", | |
"login", | |
"date_created", | |
"date_modified" | |
]); | |
var col = addCol(profileRow); | |
addFields(col, data, [ | |
"ip", | |
"current_balance", | |
"primary_item_id", | |
"secondary_item_id", | |
"hat_item_id", | |
"stamp_item_id" | |
], (keyEl, valEl) => { | |
if (links[keyEl.innerText]) { | |
valEl.className = "fieldValue link"; | |
valEl.onclick = function(firebaseId2, key, valEl2) { | |
return () => openModifyPlayerDialog(firebaseId2, key, valEl2); | |
}(data.firebase_id, keyEl.innerText, valEl); | |
} | |
}); | |
var col = addCol(profileRow); | |
addFields(col, data, [ | |
"class", | |
"color", | |
"kills", | |
"deaths", | |
"streak" | |
], (keyEl, valEl) => { | |
if (links[keyEl.innerText]) { | |
valEl.className = "fieldValue link"; | |
valEl.onclick = function(firebaseId2, key, valEl2) { | |
return () => openModifyPlayerDialog(firebaseId2, key, valEl2); | |
}(data.firebase_id, keyEl.innerText, valEl); | |
} | |
}); | |
function formatBans(column, td) { | |
if (column === "date" || column === "expire" || column === "lifted") { | |
if (td.innerHTML !== "") { | |
td.innerHTML = localTime(td.innerHTML); | |
} else { | |
td.innerHTML = "N/A"; | |
} | |
} else if (column === "admin_id") { | |
td.innerHTML = admins[parseInt(td.innerHTML, 10)].name; | |
} | |
} | |
requestAction("getPlayerBans", { player_id: data.id }, (data2) => { | |
if (data2.rows && data2.rows[0] && data2.rows[0].lifted === null) { | |
let expired = data2.rows[0].expired; | |
if (expired) { | |
banButton.style.display = "block"; | |
liftBanButton.style.display = "none"; | |
} else { | |
banButton.style.display = "none"; | |
liftBanButton.style.display = "block"; | |
} | |
} else { | |
banButton.style.display = "block"; | |
liftBanButton.style.display = "none"; | |
} | |
banRow.appendChild(createTable(data2.rows, [ | |
"admin_id", | |
"date", | |
"expire", | |
"lifted", | |
"reason" | |
], "", formatBans)); | |
}); | |
function transactionUrl(column, td) { | |
if (column === "xsolla_id") { | |
const content = td.innerHTML; | |
const a = document.createElement("a"); | |
a.href = "https://publisher.xsolla.com/56738/support/transactions/details/" + content; | |
a.target = "_blank"; | |
a.innerHTML = content; | |
td.innerHTML = ""; | |
td.appendChild(a); | |
} | |
} | |
requestAction("getPlayerTransactions", { player_id: data.id }, (data2) => { | |
transRow.appendChild(createTable(data2.rows, [ | |
"id", | |
"item_id", | |
"product_id", | |
"amount", | |
"refund", | |
"xsolla_id", | |
"date_created", | |
"date_modified" | |
], "", transactionUrl)); | |
}); | |
requestAction("getPlayerUpgrades", { player_id: data.id }, (rData) => { | |
const expiresTxt = "Expires on:"; | |
let editClicked = false; | |
let trySameVip = false; | |
let activeExpiry = null; | |
activeSub.accounts.push({ id: data.firebase_id }); | |
const idx = activeSub.accounts.findIndex((el) => el.id === data.firebase_id); | |
if (rData.rows && rData.rows.length && rData.rows.length > 0) { | |
if (rData.rows[0].expiry) { | |
activeExpiry = rData.rows[0].expiry.replace("T", " ").replace(".000Z", ""); | |
activeSub.accounts[idx].skuId = null; | |
} | |
if (rData.rows[0].isActive) { | |
activeSub.accounts[idx].skuId = rData.rows[0].id; | |
} | |
} | |
const upgradeEl = document.createElement("div"); | |
const vipSelect = document.createElement("select"); | |
requestAction("getAvaiableVip", {}, (rData2) => { | |
vipAvailable = [...rData2.rows]; | |
if (vipAvailable.length > 0) { | |
vipAvailable.forEach((el, key) => { | |
vipSelect[key] = new Option(el.name, el.id, false, el.id === activeSub.accounts[idx].skuId); | |
}); | |
upgradeEl.appendChild(vipSelect); | |
} | |
}); | |
const isExpired = activeSub.accounts[idx].skuId ? expiresTxt : "NOT ACTIVE since: "; | |
upgrade.textContent = `${isExpired} ${activeExpiry ? activeExpiry : "Never!"}`; | |
const msg = document.createElement("span"); | |
upgradeEl.appendChild(msg); | |
const editBtn = document.createElement("button"); | |
editBtn.textContent = activeSub.accounts[idx].skuId ? "Change" : "Add"; | |
editBtn.className = activeSub.accounts[idx].skuId ? "orange" : "green"; | |
const revokeBtn = document.createElement("button"); | |
revokeBtn.textContent = "Revoke"; | |
revokeBtn.className = "red"; | |
if (activeSub.accounts[idx].skuId) { | |
upgradeEl.appendChild(revokeBtn); | |
} | |
upgradeEl.appendChild(editBtn); | |
upgrade.appendChild(upgradeEl); | |
editBtn.onclick = (e) => { | |
if (editClicked) { | |
e.preventDefault(); | |
return; | |
} | |
editClicked = true; | |
const date = /* @__PURE__ */ new Date(); | |
const trySubId = Number(vipSelect.value); | |
if (trySubId == activeSub.accounts[idx].skuId && !trySameVip) { | |
msg.textContent = "Did you mean to select the same vip plan? If so, try again."; | |
trySameVip = true; | |
editClicked = false; | |
return; | |
} | |
showSpinner(); | |
switch (trySubId) { | |
case 25: | |
case 10: | |
date.setMonth(date.getMonth() + 1); | |
break; | |
case 26: | |
case 11: | |
date.setMonth(date.getMonth() + 3); | |
break; | |
case 27: | |
case 12: | |
date.setFullYear(date.getFullYear() + 1); | |
break; | |
default: | |
hideSpinner(); | |
editClicked = false; | |
upgrade.textContent = "Something went wrong. Try again...?"; | |
break; | |
} | |
const getExpiry = date.toISOString(); | |
const expiry = getExpiry.slice(0, getExpiry.indexOf(".")); | |
requestAction("updatePlayerVip", { firebase_id: data.firebase_id, expiry, sku: vipAvailable.filter((el) => el.id == trySubId)[0].sku }, (nData) => { | |
activeSub.accounts[idx].skuId = null; | |
setTimeout(() => { | |
closeTab(currentTab); | |
openPlayerDataFromFirebaseId(data.firebase_id); | |
hideSpinner(); | |
}, 1e3); | |
}); | |
}; | |
revokeBtn.onclick = () => { | |
showSpinner(); | |
revokeBtn.textContent = "REVOKING..."; | |
const date = /* @__PURE__ */ new Date(); | |
const getExpiry = date.toISOString(); | |
const expiry = getExpiry.slice(0, getExpiry.indexOf(".")); | |
requestAction("updatePlayerVipRevoke", { firebase_id: data.firebase_id, current_vip_id: activeSub.accounts[idx].skuId, expiry }, (cData) => { | |
activeSub.accounts[idx].skuId = null; | |
showSpinner(); | |
setTimeout(() => { | |
closeTab(currentTab); | |
openPlayerDataFromFirebaseId(data.firebase_id); | |
hideSpinner(); | |
}, 2e3); | |
}); | |
}; | |
}); | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "Refunds"; | |
const refundsEl = addCol(profileRow); | |
const refundReviewed = (column, td) => { | |
if (column === "reviewed") { | |
const val = td.innerHTML == 1 ? true : false; | |
const x = document.createElement("input"); | |
td.textContent = ""; | |
x.setAttribute("type", "checkbox"); | |
x.checked = val; | |
td.appendChild(x); | |
td.onclick = (e) => { | |
requestAction("updateRefund", { firebaseId: currentFirebaseId, id: td.parentElement.id, val: x.checked ? 1 : 0 }); | |
markDirty("Refunds", true, true); | |
}; | |
} | |
}; | |
requestAction("getRefunds", { firebaseId: currentFirebaseId, reviewed: false }, (rData) => { | |
refundsEl.appendChild(createTable(rData.rows, [ | |
"id", | |
"sku", | |
"transaction_id", | |
"reason", | |
"date_created", | |
"reviewed" | |
], (keyEl, valEl) => { | |
keyEl.reason = refundReasons.find((el) => el.code == keyEl.reason).type; | |
valEl.id = keyEl.id; | |
}, refundReviewed)); | |
}); | |
refundArea.appendChild(refundsEl); | |
requestAction("getPlayerItems", { player_id: data.id }, (data2) => { | |
const itemsToDelete = []; | |
const confirmItemToDelete = (item) => { | |
let d = openDialog("Delete Player Item?"), row = addRow(d), itemText = `<p>PlayerId: ${playerId}: </p>`; | |
itemsToDelete.forEach((el) => { | |
itemText += `<p>Item ID: ${el.id}, Name: ${el.name}</p>`; | |
}); | |
addCol(row).innerHTML = itemText; | |
var buttons = addRow(d); | |
addButton(buttons, "Delete", "green", () => { | |
requestAction("deletePlayerItem", { itemIds: itemsToDelete, playerId }, (data3) => { | |
closeDialog(); | |
closeTab(currentTab); | |
openPlayerDataFromPlayerId(playerId); | |
setTimeout(() => { | |
var d2 = openDialog("Player item deleted"); | |
addRow(d2); | |
var buttons2 = addRow(d2); | |
addButton(buttons2, "Close", "green", () => { | |
closeDialog(); | |
}); | |
}, 500); | |
}); | |
}); | |
addButton(buttons, "Close", "red", () => { | |
closeDialog(); | |
}); | |
}; | |
const prepRmBtnAndItemData = (key, td) => { | |
if (key === "action") { | |
const btn = document.createElement("button"); | |
const itemId = td.parentElement.children[1].innerHTML; | |
var matches = itemId.match(/\[(.*?)\]/); | |
let key2 = null; | |
let item = null; | |
if (matches) { | |
key2 = matches[1]; | |
} | |
if (key2) { | |
item = items[key2]; | |
} | |
const deleteItemCheckbox = document.createElement("input"); | |
btn.disabled = true; | |
deleteItemCheckbox.setAttribute("type", "checkbox"); | |
deleteItemCheckbox.className = "deleteItemCheckbox"; | |
deleteItemCheckbox.onclick = (e) => { | |
if (e.target.checked) { | |
if (item) { | |
itemsToDelete.push(item); | |
btn.disabled = false; | |
} | |
} else { | |
itemsToDelete.splice(itemsToDelete.indexOf(item), 1); | |
btn.disabled = true; | |
} | |
}; | |
td.textContent = ""; | |
btn.innerHTML = "Delete selected"; | |
btn.className = "red"; | |
btn.onclick = (e) => { | |
if (itemsToDelete.length > 0) { | |
confirmItemToDelete(item); | |
} else { | |
e.preventDefault(); | |
} | |
}; | |
td.appendChild(btn); | |
td.appendChild(deleteItemCheckbox); | |
} | |
}; | |
itemRow.appendChild(createTable(data2.rows, ["id", "item_id", "date_created", "date_modified", "action"], null, prepRmBtnAndItemData)); | |
}); | |
requestAction("getPlayerSocial", { player_id: data.id }, (data2) => { | |
let parsedData = []; | |
let filtered = []; | |
if ("rows" in data2) { | |
parsedData = data2.rows[0].social; | |
filtered = parsedData.filter((e) => e !== null); | |
} | |
newData = filtered; | |
setTable(newData); | |
}); | |
function setTable(data2) { | |
CREATOR.appendChild(createTable(data2, ["Remove", "id", "url", "active"], null, cellFuncLarge, null, "creator-table")); | |
} | |
function cellFuncLarge(key, td) { | |
cellFunc(key, td, newData); | |
} | |
function cellFunc(key, td, category) { | |
td.category = category; | |
if (td.innerText === "undefined") | |
td.innerText = ""; | |
if (key == "Remove") { | |
var btn = document.createElement("div"); | |
btn.className = "roundButton removeButton"; | |
btn.onclick = () => { | |
delete category[td.rowIdx]; | |
td.parentElement.remove(); | |
change(); | |
}; | |
td.innerText = ""; | |
td.appendChild(btn); | |
} else if (key === "id") { | |
td.innerText = SOCIALMEDIA[category[td.rowIdx].id]; | |
} else if (key == "active") { | |
td.innerText = ""; | |
td.style = "text-align: center"; | |
var check = addCheckbox(td); | |
check.checked = category[td.rowIdx].active; | |
check.onchange = () => { | |
category[td.rowIdx].active = check.checked; | |
checkChange(category[td.rowIdx], category); | |
}; | |
} else { | |
var input = document.createElement("input"); | |
input.value = td.innerText; | |
if (key != "content") { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
}; | |
input.className = key; | |
} else { | |
input.oninput = () => { | |
category[td.rowIdx][td.key] = input.value; | |
change(); | |
}; | |
input.className = key; | |
} | |
td.innerText = ""; | |
td.appendChild(input); | |
} | |
} | |
function change() { | |
saveButton.disabled = false; | |
discardButton.disabled = false; | |
} | |
function checkChange(changed, cat) { | |
const items2 = cat.length - 1; | |
cat.forEach((item, idx) => { | |
if (item.id !== changed.id) { | |
item.active = false; | |
} | |
if (idx === items2) { | |
let table = document.getElementById("creator-table"); | |
table.remove(); | |
newData = cat; | |
change(); | |
setTable(newData); | |
} | |
}); | |
} | |
function saveCreator() { | |
showSpinner(); | |
const date = /* @__PURE__ */ new Date(); | |
requestAction("updateContentCreator", { id: data.id, data: newData }, () => { | |
const idx = activeSub.accounts.findIndex((el) => el.id = data.firebase_id); | |
showSpinner(); | |
if (newData.length > 0 && newData.filter((e) => e.active).length > 0) { | |
date.setFullYear(date.getFullYear() + 1); | |
let getExpiry = date.toISOString(); | |
let expiry = getExpiry.slice(0, getExpiry.indexOf(".")); | |
requestAction("updatePlayerVip", { firebase_id: data.firebase_id, expiry, sku: vipAvailable.filter((el) => el.name == "12 month membership")[0].sku }, (nData) => { | |
setTimeout(() => { | |
closeTab(currentTab); | |
openPlayerDataFromFirebaseId(data.firebase_id); | |
hideSpinner(); | |
}, 1e3); | |
}); | |
} else { | |
if (activeSub.accounts[idx].skuId) { | |
showSpinner(); | |
let getExpiry = date.toISOString(); | |
let expiry = getExpiry.slice(0, getExpiry.indexOf(".")); | |
requestAction("updatePlayerVipRevoke", { firebase_id: data.firebase_id, current_vip_id: activeSub.accounts[idx].skuId, expiry }, (cData) => { | |
activeSub.accounts[idx].skuId = null; | |
showSpinner(); | |
setTimeout(() => { | |
closeTab(currentTab); | |
openPlayerDataFromFirebaseId(data.firebase_id); | |
hideSpinner(); | |
}, 2e3); | |
}); | |
} else { | |
hideSpinner(); | |
} | |
} | |
}); | |
} | |
function openAddCreatorDialog() { | |
var d = openDialog("Add new creator content"); | |
var row = addRow(d); | |
row.style.color = "slategray"; | |
lineBreak(d); | |
var row = addRow(d, "social-add-wrap"); | |
const SOCIALS = document.createElement("select"), SELECTWRAP = document.createElement("div"), SELECTLABEL = document.createElement("label"), LABELFOR = "social-media", SOCIALLENGTH = SOCIALMEDIA.length - 1; | |
SOCIALS.name = LABELFOR; | |
SELECTWRAP.className = "social-media-wrap"; | |
SELECTLABEL.textContent = "Social Media"; | |
SELECTLABEL.htmlFor = LABELFOR; | |
const socialSet = (id) => { | |
return newData.find((item) => { | |
if (item.id === id) { | |
return true; | |
} | |
return false; | |
}); | |
}; | |
SOCIALMEDIA.forEach((item, idx) => { | |
const OPTION = document.createElement("option"); | |
OPTION.value = idx; | |
OPTION.text = item; | |
if (socialSet(idx)) { | |
OPTION.disabled = true; | |
} | |
SOCIALS.appendChild(OPTION); | |
if (idx === SOCIALLENGTH) { | |
SELECTWRAP.appendChild(SOCIALS); | |
SELECTWRAP.appendChild(SELECTLABEL); | |
row.appendChild(SELECTWRAP); | |
} | |
}); | |
const URLINPUT = addInput(row, "Url", "", "", "", "url"), ACTIVECHECK = addCheckbox(row, "Active", () => { | |
}); | |
lineBreak(d); | |
const buttons = addRow(d); | |
addButton(buttons, "ADD", "green", () => { | |
if (ACTIVECHECK.checked) { | |
newData.forEach((i2) => i2.active = false); | |
} | |
newData.push({ id: Number(SOCIALS.value), url: URLINPUT.value, active: ACTIVECHECK.checked }); | |
let table = document.getElementById("creator-table"); | |
table.remove(); | |
change(); | |
setTable(newData); | |
closeDialog(); | |
}); | |
addButton(buttons, "Cancel", "orange", closeDialog); | |
} | |
function openBanPlayerDialog(playerId2) { | |
var d = openDialog("Ban Player"); | |
var row = addRow(d); | |
var rowTwo = addRow(d); | |
var banInputCount = 0; | |
function gotBanInput() { | |
if (++banInputCount === 2) { | |
banButton2.disabled = false; | |
} | |
} | |
var reasonEl = addInput(row, "Reason", "", null, () => gotBanInput()); | |
reasonEl.style.width = "500px"; | |
let list = [ | |
["15 MINUTE", "15 minutes"], | |
["30 MINUTE", "30 minutes"], | |
["1 HOUR", "1 hour"], | |
["1 DAY", "1 day"], | |
["1 WEEK", "1 week"], | |
["1 MONTH", "1 month"], | |
["1 YEAR", "1 year"] | |
]; | |
var durationEl = addSelect("", list, "", () => gotBanInput(), "Duration"); | |
rowTwo.appendChild(durationEl); | |
lineBreak(d); | |
var buttons = addRow(d); | |
let banButton2 = addButton(buttons, "Drop Ban Hammer", "red", () => { | |
let reason = reasonEl.value; | |
let duration = durationEl.value; | |
banPlayer(playerId2, duration, reason); | |
closeDialog(); | |
}); | |
banButton2.disabled = true; | |
addButton(buttons, "Show Mercy", "green", closeDialog); | |
} | |
function banPlayer(bannedId, duration, reason) { | |
showSpinner(); | |
requestAction("banPlayer", { bannedId, duration, reason }, (data2) => { | |
hideSpinner(); | |
markDirty(page.id, true); | |
}); | |
} | |
function liftPlayerBan(bannedId) { | |
showSpinner(); | |
requestAction("liftPlayerBan", { bannedId }, (data2) => { | |
hideSpinner(); | |
markDirty(page.id, true); | |
}); | |
} | |
}); | |
} | |
function openModifyPlayerDialog(firebaseId, key, valEl) { | |
var d = openDialog("Modify Player"); | |
var row = addRow(d); | |
row.style.color = "slategray"; | |
row.innerText = 'Enter a new value for "' + key + '"'; | |
lineBreak(d); | |
var row = addRow(d); | |
var input = addInput(row, key, valEl.innerText, () => { | |
modifyPlayerData(firebaseId, key, valEl, input.value); | |
closeDialog(); | |
}); | |
input.size = 40; | |
lineBreak(d); | |
var buttons = addRow(d); | |
addButton(buttons, "Update", "red", () => { | |
modifyPlayerData(firebaseId, key, valEl, input.value); | |
closeDialog(); | |
}); | |
addButton(buttons, "Cancel", "orange", closeDialog); | |
} | |
function modifyPlayerData(firebaseId, key, valEl, val) { | |
requestAction("modifyPlayer", { firebaseId, key, val }, (data) => { | |
if (data.error) { | |
var d = openDialog("Error"); | |
var row = addRow(d); | |
row.style.color = "slategray"; | |
row.innerText = data.error; | |
lineBreak(d); | |
row = addRow(d); | |
addButton(row, "OK", "green", () => closeDialog()); | |
return; | |
} | |
valEl.innerText = val; | |
}); | |
} | |
function openDeletePlayerDialog(data) { | |
var d = openDialog("Delete Player"); | |
var row = addRow(d); | |
var rowTwo = addRow(d); | |
var rowThree = addRow(d); | |
row.style.color = "slategray"; | |
rowTwo.style.color = "red"; | |
row.innerText = "Are you ABSOLUTELY sure you want to delete this user from the database? This operation cannot be un-done. If this was prompted by user request, make sure you've made a reasonable effort to verify that the request originated from the owner of this account.\n\n"; | |
rowTwo.innerHTML = `<strong>CONFIRM INFO!</strong> Firebase: ${data.firebase_id}. Email: ${data.email}. Id: ${data.id}. <br /><br />`; | |
rowThree.innerText = "Do you still wish to proceed?"; | |
lineBreak(d); | |
var buttons = addRow(d); | |
addButton(buttons, "Delete", "red", () => { | |
deletePlayer(data.id, data.firebase_id); | |
closeDialog(); | |
}); | |
addButton(buttons, "Cancel", "green", closeDialog); | |
} | |
function openTransferPlayerDialog(id, firebaseId) { | |
var d = openDialog("Transfer Player Data"); | |
var row = addRow(d); | |
row.style.color = "slategray"; | |
row.innerText = "Transfer this player's data to another account by entering\none of the new account's identifying fields below:"; | |
lineBreak(d); | |
var row = addRow(d); | |
var emailIn = addInput(row, "email", null, () => { | |
transferPlayerData(id, firebaseId, { email: emailIn.value }); | |
emailIn.value = ""; | |
closeDialog(); | |
}); | |
emailIn.size = 60; | |
var row = addRow(d); | |
var firebaseIn = addInput(row, "firebase id", null, () => { | |
transferPlayerData(id, firebaseId, { firebase_id: firebaseIn.value }); | |
firebaseIn.value = ""; | |
closeDialog(); | |
}); | |
firebaseIn.size = 60; | |
var buttons = addRow(d); | |
addButton(buttons, "Transfer", "red", () => { | |
if (emailIn.value) { | |
transferPlayerData(id, firebaseId, { email: emailIn.value }); | |
emailIn.value = ""; | |
} else if (firebaseIn.value) { | |
transferPlayerData(id, firebaseId, { firebase_id: firebaseIn.value }); | |
firebaseIn.value = ""; | |
} | |
closeDialog(); | |
}); | |
addButton(buttons, "Cancel", "green", closeDialog); | |
} | |
function transferPlayerData(id, firebaseId, searchCriteria) { | |
requestAction("transferPlayerData", { id, firebaseId, searchCriteria }, (data) => { | |
if (data.error) { | |
var d = openDialog("Error"); | |
var row = addRow(d); | |
row.style.color = "slategray"; | |
row.innerText = data.error; | |
lineBreak(d); | |
row = addRow(d); | |
addButton(row, "OK", "green", () => closeDialog()); | |
return; | |
} | |
closeTab(currentTab); | |
if (searchCriteria.email) { | |
openPlayerDataFromEmail(searchCriteria.email); | |
} else if (searchCriteria.firebaseId) { | |
openPlayerDataFromFirebaseId(searchCriteria.firebaseId); | |
} | |
}); | |
} | |
function deletePlayer(id, firebaseId) { | |
requestAction("deletePlayer", { id, firebaseId }, (data) => { | |
hideSpinner(); | |
if (data.error) { | |
var d = openDialog("Error"); | |
var row = addRow(d); | |
row.style.color = "slategray"; | |
row.innerText = data.error; | |
} else { | |
var d = openDialog("Player Deleted"); | |
var row = addRow(d); | |
row.style.color = "slategray"; | |
row.innerText = "Player successfully deleted."; | |
} | |
lineBreak(d); | |
row = addRow(d); | |
addButton(row, "OK", "green", () => { | |
closeTab(currentTab); | |
closeDialog(); | |
}); | |
}); | |
} | |
var refundTab; | |
var refundList; | |
var smackers; | |
var refundPage = 1; | |
var refundsPerPage = 10; | |
var maxPageCount = 1; | |
var pageDisplay; | |
var tabNotify = document.createElement("span"); | |
tabNotify.className = "notify"; | |
function openRefunds() { | |
refundTab = addTab("Refunds", false, renderRefunds); | |
} | |
function prepRefundTab() { | |
showSpinner(); | |
setTimeout(() => { | |
loadRefunds(smackers, true); | |
setTimeout(() => { | |
loadRefunds(refundList, false); | |
}, 1e3); | |
}, 1e3); | |
} | |
function paginate(array, page_size, page_number) { | |
return array.slice((page_number - 1) * page_size, page_number * page_size); | |
} | |
function loadRefunds(el, loadAll) { | |
requestAction("getRefunds", { firebaseId: false, reviewed: loadAll }, (data) => { | |
hideSpinner(); | |
function createRefundTable() { | |
el.appendChild(createTable(refunds, [ | |
"id", | |
"firebase_id", | |
"sku", | |
"transaction_id", | |
"reason", | |
"reviewed", | |
"date_created" | |
], rowFunc, colFunc)); | |
} | |
el.innerHTML = ""; | |
let refunds = [], refundRows = []; | |
if (!data || data.rows === void 0 || data.rows.length == 0) { | |
el.innerText = "HOORAY! No refunds!"; | |
tabNotify.innerHTML = ""; | |
tabNotify.style.display = "none"; | |
return; | |
} | |
function compare(a, b2) { | |
if (a.firebase_id < b2.firebase_id) { | |
return -1; | |
} | |
if (a.firebase_id > b2.firebase_id) { | |
return 1; | |
} | |
return 0; | |
} | |
data.rows.sort(compare); | |
refundRows = [...data.rows]; | |
let prevBtn, nextBtn; | |
if (!loadAll) { | |
tabNotify.style.display = "inline-block"; | |
tabNotify.innerHTML = data.rows.length; | |
refundTab.appendChild(tabNotify); | |
refunds.push(...data.rows); | |
} else { | |
const btns = addRow(el); | |
prevBtn = addButton(btns, "\u25C0 previous", "green", pagPrev); | |
nextBtn = addButton(btns, "next \u25B6", "green", pagNext); | |
pageDisplay = addCol(btns); | |
maxPageCount = Math.ceil(data.rows.length / refundsPerPage); | |
prevBtn.disabled = true; | |
if (!maxPageCount || maxPageCount === 1) { | |
nextBtn.disabled = true; | |
} | |
pageDisplay.textContent = `Page: 1 of ${maxPageCount}`; | |
refunds.push(...paginate(data.rows, refundsPerPage, refundPage)); | |
} | |
function pagNext() { | |
prevBtn.disabled = false; | |
if (refundPage === maxPageCount) { | |
prevBtn.disabled = false; | |
nextBtn.disabled = true; | |
return; | |
} else { | |
const table = el.getElementsByTagName("table")[0].remove(); | |
refundPage += 1; | |
if (refundPage === maxPageCount) { | |
nextBtn.disabled = true; | |
} | |
pageDisplay.textContent = `Page: ${refundPage} of ${maxPageCount}`; | |
refunds = []; | |
refunds.push(...paginate(refundRows, refundsPerPage, refundPage)); | |
createRefundTable(); | |
} | |
} | |
function pagPrev() { | |
nextBtn.disabled = false; | |
if (refundPage === 1) { | |
prevBtn.disabled = false; | |
nextBtn.disabled = true; | |
return; | |
} else { | |
const table = el.getElementsByTagName("table")[0].remove(); | |
refundPage -= 1; | |
if (refundPage === 1) { | |
prevBtn.disabled = true; | |
} | |
pageDisplay.textContent = `Page: ${refundPage} of ${maxPageCount}`; | |
refunds = []; | |
refunds.push(...paginate(refundRows, refundsPerPage, refundPage)); | |
createRefundTable(); | |
} | |
} | |
createRefundTable(); | |
function rowFunc(row, tr) { | |
tr.id = row.id; | |
if (!isNaN(row.reason)) { | |
row.reason = refundReasons.find((el2) => el2.code == row.reason).type; | |
} | |
tr.onclick = (e) => { | |
openPlayerDataFromFirebaseId(row.firebase_id); | |
}; | |
} | |
function colFunc(column, td) { | |
if (column === "reviewed") { | |
const val = td.innerHTML == 1 ? true : false; | |
const x = document.createElement("input"); | |
td.textContent = ""; | |
x.setAttribute("type", "checkbox"); | |
x.checked = val; | |
x.disabled = true; | |
td.appendChild(x); | |
} | |
} | |
}); | |
} | |
function renderRefunds(page) { | |
addRule(page); | |
refundList = addRow(page); | |
addRule(page); | |
smackers = addRow(page); | |
prepRefundTab(); | |
} | |
var showSsSettings = (page) => { | |
const showItemsGiven = () => { | |
itemList.classList.toggle("hideme"); | |
}; | |
var el = addCol(page, "center"); | |
addHeader(el, "Game Settings"); | |
addRule(page); | |
addSmallHeader(page, "Chickn Winner", "h3"); | |
function getChwWinnerStats() { | |
requestAction("getChwStats", {}, updateTxt); | |
} | |
setTimeout(() => { | |
getChwWinnerStats(); | |
}, 1e3); | |
addButton(page, "Update", "orange", getChwWinnerStats); | |
addButton(page, "Hide/show items", "orange", showItemsGiven); | |
const wrap = addDiv(page); | |
const eggs = addDiv(wrap); | |
const statItems = addDiv(wrap); | |
const itemsToEggs = addDiv(wrap); | |
const ratio = addDiv(wrap); | |
const total = addDiv(wrap); | |
const itemsGiven = addDiv(wrap); | |
const itemList = document.createElement("ul"); | |
const itemHeader = document.createElement("h3"); | |
const tiers = addDiv(wrap); | |
const tierList = document.createElement("ul"); | |
const tierHeader = document.createElement("h3"); | |
itemList.classList.add("hideme"); | |
itemHeader.innerText = "Items given"; | |
tierHeader.innerHTML = "Tiers given"; | |
function calculateRatio(num1, num2) { | |
for (num = num2; num > 1; num--) { | |
if (num1 % num == 0 && num2 % num == 0) { | |
num1 = num1 / num; | |
num2 = num2 / num; | |
} | |
} | |
return num1 + ":" + num2; | |
} | |
function updateTxt(stats) { | |
itemsGiven.appendChild(itemHeader); | |
itemsGiven.appendChild(itemList); | |
tiers.appendChild(tierHeader); | |
tiers.appendChild(tierList); | |
eggs.innerHTML = `Egg draw(s): ${stats.data.eggs}`; | |
statItems.innerHTML = `Item draw(s): ${stats.data.item}`; | |
itemsToEggs.innerHTML = `Items owned draw(s): ${stats.data.itemToEggs} (actual items draw(s): ${stats.data.item + stats.data.itemToEggs})`; | |
ratio.innerHTML = `Ratio (items to eggs): ${calculateRatio(stats.data.itemToEggs + stats.data.item, stats.data.eggs - stats.data.itemToEggs)}`; | |
total.innerHTML = `Total: ${stats.data.eggs + stats.data.item}`; | |
itemList.innerHTML = ""; | |
Object.entries(stats.data.items).forEach((key) => { | |
let item = document.createElement("li"); | |
let subList = document.createElement("ul"); | |
let subData = document.createElement("li"); | |
let subSubData = document.createElement("li"); | |
let itemId = parseInt(key); | |
item.innerHTML = `<i>${items[itemId] ? items[itemId].name : itemId}</i>`; | |
subData.innerHTML = `Count: ${stats.data.items[itemId].count}`; | |
subSubData.innerHTML = `Tier: ${stats.data.items[itemId].tier}`; | |
itemList.appendChild(item); | |
item.appendChild(subList); | |
subList.appendChild(subData); | |
subList.appendChild(subSubData); | |
}); | |
tierList.innerHTML = ""; | |
Object.entries(stats.data.tier).forEach((key) => { | |
let item = document.createElement("li"); | |
item.innerHTML = `<i>Tier ${parseInt(key)}</i>: count: ${stats.data.tier[parseInt(key)]}`; | |
tierList.appendChild(item); | |
}); | |
} | |
}; | |
function openSettingsTab() { | |
addTab("Settings", false, showSsSettings); | |
} | |
function openTicket(id) { | |
if (openTabByName("TCK-" + id)) | |
return; | |
addTab("TCK-" + id, true, (page) => { | |
page.ticketId = id; | |
renderTicket(page); | |
}); | |
} | |
function renderTicket(page) { | |
requestAction("getTicket", { ticket_id: page.ticketId }, (data) => { | |
if (!data.rows) { | |
page.innerText = "No ticket found for this ID"; | |
return; | |
} | |
data = data.rows[0]; | |
parseRow(data); | |
var col = addCol(page); | |
var admin = admins[data.admin_id]; | |
var assign = addField(col, "", ""); | |
var assignName = getFieldName(assign); | |
var assignVal = getFieldValue(assign); | |
if (admin) { | |
assignName.innerText = "assigned to: "; | |
assignVal.innerText = admin.name; | |
} else { | |
assignName.innerText = "unassigned"; | |
assignVal.innerText = "GIMME!"; | |
assignVal.className = "col fieldValue link"; | |
assignVal.onclick = function() { | |
requestAction("assign", { | |
ticket_id: page.ticketId, | |
admin_id: profile.id | |
}, () => { | |
assignName.innerText = "assigned to:"; | |
assignVal.innerText = profile.name; | |
assignVal.onclick = null; | |
assignVal.className = "col fieldValue"; | |
}); | |
}; | |
} | |
var col = addCol(page); | |
addButton(col, "Copy URL", "green", () => { | |
copyToClipboard(window.location.href + "?ticket=" + page.ticketId); | |
}); | |
var impersonateFunc = function(impersonateId) { | |
var baseUrl = location.protocol + "//" + location.hostname + (location.port ? ":" + location.port : ""); | |
window.open(baseUrl + "?adminImpersonate=" + impersonateId); | |
}; | |
addButton(col, "Impersonate", "green", () => { | |
return impersonateFunc(data.firebase_id); | |
}); | |
lineBreak(page); | |
var row = addRow(page); | |
var col = addCol(row); | |
addFields(col, data, [ | |
"ticket_id", | |
"feedback_type", | |
"status", | |
"date_created" | |
], (keyEl, valEl) => { | |
if (keyEl.innerText == "status") { | |
valEl.className = "fieldValue link"; | |
valEl.onclick = () => popupList(statusNames, (idx) => { | |
requestAction( | |
"setStatus", | |
{ status: idx, ticket_id: data.ticket_id }, | |
() => { | |
valEl.innerText = statusNames[idx]; | |
markDirty("Feedback"); | |
} | |
); | |
}); | |
} | |
}); | |
col = addCol(row); | |
addFields(col, data, [ | |
"username", | |
"times_played", | |
"xsolla_token", | |
"firebase_id", | |
"email" | |
], (keyEl, valEl) => { | |
if (keyEl.innerText == "firebase_id") { | |
valEl.className = "fieldValue link"; | |
valEl.onclick = function(ticketId, firebaseId) { | |
return () => openPlayerDataFromTicket(ticketId, firebaseId); | |
}(data.ticket_id, data.firebase_id); | |
} | |
}); | |
col = addCol(row); | |
addFields(col, data, [ | |
"from_eu", | |
"of_age", | |
"targeted_ads" | |
]); | |
lineBreak(page); | |
row = addRow(page, "fieldName").innerText = "comments"; | |
row = addRow(page, "textBox").innerText = data.comments; | |
row = addRow(page); | |
var reply = addButton(row, "Reply", "blue"); | |
var note = addCol(row); | |
note.style.color = "slategray"; | |
note.style.margin = "10px"; | |
note.innerText = 'Replying will set status to "active"'; | |
reply.onclick = () => { | |
var str = "mailto:" + data.email + "?from=" + profile.email + "&subject=" + encodeURIComponent("Re: Shell Shockers [#" + data.ticket_id + "]") + "&body=" + encodeURIComponent("\n\n\n------------------------\nOriginal message\n------------------------\n" + data.comments); | |
window.location.href = str; | |
requestAction("setStatus", { | |
status: statusEnum.active, | |
ticket_id: data.ticket_id | |
}, () => { | |
}); | |
}; | |
lineBreak(page); | |
row = addRow(page); | |
col = addCol(row); | |
addFields(col, data, [ | |
"game_version", | |
"browser_name", | |
"browser_version", | |
"os_name", | |
"os_version", | |
"engine_name", | |
"engine_version", | |
"server", | |
"url", | |
"referrer" | |
]); | |
col = addCol(row); | |
addFields(col, data, [ | |
"ping", | |
"highest_ping", | |
"fps", | |
"screen_size", | |
"inner_size", | |
"color_depth", | |
"pixel_depth", | |
"gl_vendor", | |
"gl_version", | |
"renderer", | |
"max_texture_size" | |
]); | |
lineBreak(page); | |
col = addCol(row); | |
addFields(col, data, [ | |
"game_type", | |
"game_code", | |
"current_balance", | |
"local_kills", | |
"local_deaths", | |
"local_streak", | |
"selected_class", | |
"selected_color", | |
"hat", | |
"stamp", | |
"weapons" | |
], (keyEl, valEl) => { | |
if (keyEl.innerText == "game_code" && data.game_code) { | |
valEl.innerHTML = '<a href="https://shellshock.io/#' + data.game_code + '" target="_window">' + data.game_code + "</a>"; | |
} | |
}); | |
addRow(page, "fieldName").innerText = "log"; | |
addRow(page, "textBox").innerText = decodeURIComponent(data.log); | |
lineBreak(page); | |
addRow(page, "fieldName").innerText = "debug"; | |
addRow(page, "textBox").innerHTML = "<pre>" + JSON.stringify(data.debug, null, " ") + "</pre>"; | |
}); | |
} | |
var twitchBlacklist = null; | |
function openTwitchTab() { | |
addTab("Twitch", false, renderTwitch); | |
} | |
function renderTwitch(page) { | |
let responses = 0; | |
function response() { | |
if (++responses === 1) { | |
finishRenderTwitch(page); | |
} | |
} | |
requestAction("getTwitchBlacklist", {}, (data) => { | |
hideSpinner(); | |
twitchBlacklist = JSON.parse(data.twitchBlacklist); | |
response(); | |
}); | |
} | |
function finishRenderTwitch(page) { | |
var el = addCol(page, "center"); | |
addHeader(el, "Twitch"); | |
var buttonRow = addRow(page); | |
var button = addButton(buttonRow, "Submit Changes", "green"); | |
button.disabled = true; | |
button.onclick = () => { | |
twitchBlacklist = {}; | |
list.value.split("\n").forEach((l) => { | |
if (l.trim().length > 0) | |
twitchBlacklist[l] = true; | |
}); | |
requestAction("updateTwitchBlacklist", { twitchBlacklist }, (data) => { | |
page.innerHTML = ""; | |
requestAction("getTwitchBlacklist", {}, (data2) => { | |
hideSpinner(); | |
twitchBlacklist = JSON.parse(data2.twitchBlacklist); | |
finishRenderTwitch(page); | |
}); | |
}); | |
}; | |
lineBreak(page); | |
var r = addRow(page); | |
var list = addInputBox(r, "", null, null); | |
list.rows = 20; | |
list.spellcheck = false; | |
list.value = Object.keys(twitchBlacklist).sort((a, b2) => a.toLowerCase().localeCompare(b2.toLowerCase())).join("\n"); | |
list.oninput = () => { | |
button.disabled = false; | |
}; | |
} | |
function parseRow(row) { | |
if (row.status !== void 0) { | |
row.status = statusNames[row.status]; | |
} | |
if (row.feedback_type !== void 0) { | |
row.feedback_type = ["comment", "feature", "bug", "purchase", "account", "abuse", "other", "deleteAccount"][row.feedback_type]; | |
} | |
var bools = ["from_eu", "of_age", "targeted_ads", "hold_to_aim", "enable_chat", "auto_detail", "shadows_enabled", "high_res"]; | |
for (var b2 in bools) { | |
if (row[bools[b2]] !== void 0) { | |
row[bools[b2]] = ["no", "yes"][row[bools[b2]]]; | |
} | |
} | |
if (row.selected_class !== void 0) { | |
row.selected_class = ["soldier", "scrambler", "free ranger"][row.selected_class]; | |
} | |
if (row.class !== void 0) { | |
row.class = ["soldier", "scrambler", "free ranger"][row.class]; | |
} | |
if (row.date_created !== void 0) { | |
row.date_created = localTime(row.date_created); | |
} | |
if (row.date_modified !== void 0) { | |
row.date_modified = localTime(row.date_modified); | |
} | |
if (row.login !== void 0) { | |
row.login = localTime(row.login); | |
} | |
if (row.hasOwnProperty("game_type") && row.game_type != null) { | |
row.game_type = GameTypes[row.game_type].shortName; | |
} | |
if (row.hasOwnProperty("item_id") && row.item_id != null) { | |
row.item_id = `[${row.item_id}] - ` + (items[row.item_id] ? `${items[row.item_id].name}` : "Item ID CHANGED"); | |
} | |
if (row.hasOwnProperty("primary_item_id") && row.primary_item_id != null) { | |
row.primary_item_id = items[row.primary_item_id].name; | |
} | |
if (row.hasOwnProperty("secondary_item_id") && row.secondary_item_id != null) { | |
row.secondary_item_id = items[row.secondary_item_id].name; | |
} | |
if (row.hasOwnProperty("hat_item_id") && row.hat_item_id != null) { | |
row.hat_item_id = items[row.hat_item_id].name; | |
} | |
if (row.hasOwnProperty("stamp_item_id") && row.stamp_item_id != null) { | |
row.stamp_item_id = items[row.stamp_item_id].name; | |
} | |
if (row.hasOwnProperty("grenade_item_id") && row.grenade_item_id != null) { | |
row.grenade_item_id = items[row.grenade_item_id].name; | |
} | |
if (row.hasOwnProperty("product_id") && row.product_id != null) { | |
row.product_id = products[row.product_id].name; | |
} | |
} | |
function showSpinner() { | |
document.getElementById("spinner").style.display = "block"; | |
} | |
function hideSpinner() { | |
document.getElementById("spinner").style.display = "none"; | |
} | |
function findTab(name) { | |
var arr = Array.from(headerEl.children); | |
for (var i2 = 0; i2 < arr.length; i2++) { | |
var e = arr[i2]; | |
if (e.innerText && e.innerText == name || e.innerText && e.innerText.includes(name)) { | |
return e; | |
} | |
} | |
return null; | |
} | |
function addTab(name, canClose, callback) { | |
tabAway(); | |
var page = addRow(doc, "page"); | |
page.id = name; | |
var tab = document.createElement("div"); | |
tab.className = "tab tabActive"; | |
tab.innerText = name; | |
tab.attachedPage = page; | |
tab.onclick = () => tabClicked(tab); | |
tab.onmouseenter = function() { | |
if (currentTab != this) { | |
this.className = "tab tabHover"; | |
} | |
}; | |
tab.onmouseleave = function() { | |
if (currentTab == this) { | |
this.className = "tab tabActive"; | |
} else { | |
this.className = "tab"; | |
} | |
}; | |
header.appendChild(tab); | |
currentTab = tab; | |
if (canClose) { | |
var x = document.createElement("div"); | |
x.className = "closer"; | |
x.onclick = () => { | |
closeTab(tab); | |
event.stopPropagation(); | |
}; | |
tab.appendChild(x); | |
} else { | |
tab.style.paddingRight = "1em"; | |
} | |
page.focus(); | |
tab.renderFunc = callback; | |
callback(page); | |
return tab; | |
} | |
function closeTab(e) { | |
if (e == currentTab) { | |
tabClicked(e.previousSibling); | |
} | |
e.attachedPage.parentNode.removeChild(e.attachedPage); | |
header.removeChild(e); | |
} | |
function tabAway(e) { | |
if (currentTab) { | |
lastTab = currentTab; | |
currentTab.scrollRestore = document.scrollingElement.scrollTop; | |
currentTab.attachedPage.style.display = "none"; | |
currentTab.className = "tab"; | |
} | |
} | |
function openTabByName(name, canClose) { | |
var tab = findTab(name); | |
if (tab) { | |
openTab(tab); | |
return true; | |
} | |
return false; | |
} | |
function openTab(tab) { | |
if (currentTab == tab) | |
return; | |
tabAway(); | |
tab.className = "tab tabActive"; | |
tab.attachedPage.style.display = "block"; | |
currentTab = tab; | |
if (tab.scrollRestore) { | |
document.scrollingElement.scrollTop = tab.scrollRestore; | |
} | |
} | |
function tabClicked(tab, keepClosed) { | |
if (tab.attachedPage.isDirty) { | |
while (tab.attachedPage.firstChild) { | |
tab.attachedPage.removeChild(tab.attachedPage.firstChild); | |
} | |
tab.renderFunc(tab.attachedPage); | |
tab.attachedPage.focus(); | |
tab.attachedPage.isDirty = false; | |
} | |
if (!keepClosed) { | |
openTab(tab); | |
} | |
} | |
function markDirty(name, refreshNow, keepClosed) { | |
var tab = findTab(name); | |
if (tab) { | |
tab.attachedPage.isDirty = true; | |
if (refreshNow) | |
tabClicked(tab, keepClosed); | |
} | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment