mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-12 03:02:54 +00:00
[MIRROR] ban panel as tgui (#11222)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
ecac2f2658
commit
2e85d4421a
193
code/modules/admin/DB ban/ban_panle_ui.dm
Normal file
193
code/modules/admin/DB ban/ban_panle_ui.dm
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/datum/tgui_ban_panel
|
||||||
|
var/client/holder //client of whoever is using this datum
|
||||||
|
var/datum/admins/admin_datum
|
||||||
|
var/playerckey
|
||||||
|
var/adminckey
|
||||||
|
var/playerip
|
||||||
|
var/playercid
|
||||||
|
var/dbbantype
|
||||||
|
var/min_search = FALSE
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/New(user, pckey, datum/admins/admind)//user can either be a client or a mob due to byondcode(tm)
|
||||||
|
if (istype(user, /client))
|
||||||
|
var/client/user_client = user
|
||||||
|
holder = user_client //if its a client, assign it to holder
|
||||||
|
else
|
||||||
|
var/mob/user_mob = user
|
||||||
|
holder = user_mob.client //if its a mob, assign the mob's client to holder
|
||||||
|
playerckey = pckey
|
||||||
|
admin_datum = admind
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/tgui_state(mob/user)
|
||||||
|
return ADMIN_STATE(R_BAN)
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/tgui_close()
|
||||||
|
holder = null
|
||||||
|
admin_datum = null
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/tgui_interact(mob/user, datum/tgui/ui)
|
||||||
|
ui = SStgui.try_update_ui(user, src, ui)
|
||||||
|
if(!ui)
|
||||||
|
ui = new(user, src, "BanPanel", "Ban Panel")
|
||||||
|
ui.open()
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/tgui_static_data(mob/user)
|
||||||
|
var/list/bantypes = list("traitor","changeling","operative","revolutionary","cultist","wizard") //For legacy bans.
|
||||||
|
for(var/antag_type in GLOB.all_antag_types) // Grab other bans.
|
||||||
|
var/datum/antagonist/antag = GLOB.all_antag_types[antag_type]
|
||||||
|
bantypes |= antag.bantype
|
||||||
|
|
||||||
|
var/list/data = list(
|
||||||
|
"player_ckey" = playerckey,
|
||||||
|
"admin_ckey" = adminckey,
|
||||||
|
"player_ip" = playerip,
|
||||||
|
"player_cid" = playercid,
|
||||||
|
"bantype" = dbbantype,
|
||||||
|
"possible_jobs" = get_all_jobs() + SSjob.get_job_titles_in_department(DEPARTMENT_SYNTHETIC) + bantypes,
|
||||||
|
"database_records" = database_lookup()
|
||||||
|
)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||||
|
var/list/data = list(
|
||||||
|
"min_search" = min_search,
|
||||||
|
)
|
||||||
|
return data
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||||
|
. = ..()
|
||||||
|
if(.)
|
||||||
|
return
|
||||||
|
|
||||||
|
switch(action)
|
||||||
|
if("confirmBan")
|
||||||
|
|
||||||
|
var/bantype = text2num(params["type"])
|
||||||
|
var/banip = params["ip"]
|
||||||
|
var/banduration = text2num(params["duration"])
|
||||||
|
var/banckey = ckey(params["ckey"])
|
||||||
|
var/bancid = params["cid"]
|
||||||
|
var/banjob = params["job"]
|
||||||
|
var/banreason = params["reason"]
|
||||||
|
to_world("we got [bantype]")
|
||||||
|
|
||||||
|
switch(bantype)
|
||||||
|
if(BANTYPE_PERMA)
|
||||||
|
if(!banckey || !banreason)
|
||||||
|
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey and reason)"))
|
||||||
|
return
|
||||||
|
banduration = null
|
||||||
|
banjob = null
|
||||||
|
if(BANTYPE_TEMP)
|
||||||
|
if(!banckey || !banreason || !banduration)
|
||||||
|
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey, reason and duration)"))
|
||||||
|
return
|
||||||
|
banjob = null
|
||||||
|
if(BANTYPE_JOB_PERMA)
|
||||||
|
if(!banckey || !banreason || !banjob)
|
||||||
|
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey, reason and job)"))
|
||||||
|
return
|
||||||
|
banduration = null
|
||||||
|
if(BANTYPE_JOB_TEMP)
|
||||||
|
if(!banckey || !banreason || !banjob || !banduration)
|
||||||
|
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey, reason and job)"))
|
||||||
|
return
|
||||||
|
|
||||||
|
var/mob/playermob
|
||||||
|
|
||||||
|
for(var/mob/M in GLOB.player_list)
|
||||||
|
if(M.ckey == banckey)
|
||||||
|
playermob = M
|
||||||
|
break
|
||||||
|
|
||||||
|
banreason = "(MANUAL BAN) " + banreason
|
||||||
|
|
||||||
|
if(!playermob)
|
||||||
|
if(banip)
|
||||||
|
banreason = "[banreason] (CUSTOM IP)"
|
||||||
|
if(bancid)
|
||||||
|
banreason = "[banreason] (CUSTOM CID)"
|
||||||
|
else
|
||||||
|
message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob")
|
||||||
|
notes_add(banckey, banreason, ui.user)
|
||||||
|
|
||||||
|
admin_datum.DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid )
|
||||||
|
if((bantype == BANTYPE_PERMA || bantype == BANTYPE_TEMP) && playermob.client)
|
||||||
|
qdel(playermob.client)
|
||||||
|
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
if("searchBans")
|
||||||
|
playerckey = ckey(params["ckey"])
|
||||||
|
adminckey = ckey(params["aCkey"])
|
||||||
|
playerip = params["ip"]
|
||||||
|
playercid = params["cid"]
|
||||||
|
dbbantype = text2num(params["banType"])
|
||||||
|
min_search = text2num(params["minMatch"])
|
||||||
|
update_tgui_static_data(ui.user, ui)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
if("banEdit")
|
||||||
|
var/banedit = params["action"]
|
||||||
|
var/banid = text2num(params["banid"])
|
||||||
|
if(!banedit || !banid)
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
admin_datum.DB_ban_edit(ui.user.client, banid, banedit)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/datum/tgui_ban_panel/proc/database_lookup()
|
||||||
|
|
||||||
|
if(!adminckey && !playerckey && !playerip && !playercid && !dbbantype)
|
||||||
|
return
|
||||||
|
|
||||||
|
var/adminsearch
|
||||||
|
var/playersearch
|
||||||
|
var/ipsearch
|
||||||
|
var/cidsearch
|
||||||
|
if(min_search)
|
||||||
|
if(adminckey && length(adminckey) >= 3)
|
||||||
|
adminsearch = "AND a_ckey LIKE '[adminckey]%' "
|
||||||
|
if(playerckey && length(playerckey) >= 3)
|
||||||
|
playersearch = "AND ckey LIKE '[playerckey]%' "
|
||||||
|
if(playerip && length(playerip) >= 3)
|
||||||
|
ipsearch = "AND ip LIKE '[playerip]%' "
|
||||||
|
if(playercid && length(playercid) >= 7)
|
||||||
|
cidsearch = "AND computerid LIKE '[playercid]%' "
|
||||||
|
else
|
||||||
|
if(adminckey)
|
||||||
|
adminsearch = "AND a_ckey = '[adminckey]' "
|
||||||
|
if(playerckey)
|
||||||
|
playersearch = "AND ckey = '[playerckey]' "
|
||||||
|
if(playerip)
|
||||||
|
ipsearch = "AND ip = '[playerip]' "
|
||||||
|
if(playercid)
|
||||||
|
cidsearch = "AND computerid = '[playercid]' "
|
||||||
|
|
||||||
|
var/bantypesearch
|
||||||
|
if(dbbantype)
|
||||||
|
bantypesearch = "AND bantype = "
|
||||||
|
|
||||||
|
switch(dbbantype)
|
||||||
|
if(BANTYPE_TEMP)
|
||||||
|
bantypesearch += "'TEMPBAN' "
|
||||||
|
if(BANTYPE_JOB_PERMA)
|
||||||
|
bantypesearch += "'JOB_PERMABAN' "
|
||||||
|
if(BANTYPE_JOB_TEMP)
|
||||||
|
bantypesearch += "'JOB_TEMPBAN' "
|
||||||
|
else
|
||||||
|
bantypesearch += "'PERMABAN' "
|
||||||
|
|
||||||
|
|
||||||
|
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100")
|
||||||
|
select_query.Execute()
|
||||||
|
|
||||||
|
var/list/all_bans = list()
|
||||||
|
var/now = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") // MUST BE the same format as SQL gives us the dates in, and MUST be least to most specific (i.e. year, month, day not day, month, year)
|
||||||
|
|
||||||
|
while(select_query.NextRow())
|
||||||
|
UNTYPED_LIST_ADD(all_bans, list("auto" = ((select_query.item[3] in list("TEMPBAN", "JOB_TEMPBAN")) && now > select_query.item[7]), "data_list" = select_query.item))
|
||||||
|
|
||||||
|
return all_bans
|
||||||
@@ -91,7 +91,8 @@
|
|||||||
|
|
||||||
/datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "")
|
/datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "")
|
||||||
|
|
||||||
if(!check_rights(R_BAN)) return
|
if(!check_rights(R_BAN))
|
||||||
|
return
|
||||||
|
|
||||||
var/bantype_str
|
var/bantype_str
|
||||||
if(bantype)
|
if(bantype)
|
||||||
@@ -112,7 +113,8 @@
|
|||||||
if(BANTYPE_ANY_FULLBAN)
|
if(BANTYPE_ANY_FULLBAN)
|
||||||
bantype_str = "ANY"
|
bantype_str = "ANY"
|
||||||
bantype_pass = 1
|
bantype_pass = 1
|
||||||
if( !bantype_pass ) return
|
if(!bantype_pass)
|
||||||
|
return
|
||||||
|
|
||||||
var/bantype_sql
|
var/bantype_sql
|
||||||
if(bantype_str == "ANY")
|
if(bantype_str == "ANY")
|
||||||
@@ -153,12 +155,13 @@
|
|||||||
|
|
||||||
DB_ban_unban_by_id(ban_id)
|
DB_ban_unban_by_id(ban_id)
|
||||||
|
|
||||||
/datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null)
|
/datum/admins/proc/DB_ban_edit(client/user, var/banid = null, var/param = null)
|
||||||
|
|
||||||
if(!check_rights(R_BAN)) return
|
if(!check_rights_for(user, R_BAN))
|
||||||
|
return
|
||||||
|
|
||||||
if(!isnum(banid) || !istext(param))
|
if(!isnum(banid) || !istext(param))
|
||||||
to_chat(usr, "Cancelled")
|
to_chat(user, "Cancelled")
|
||||||
return
|
return
|
||||||
|
|
||||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]")
|
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]")
|
||||||
@@ -174,7 +177,7 @@
|
|||||||
duration = query.item[2]
|
duration = query.item[2]
|
||||||
reason = query.item[3]
|
reason = query.item[3]
|
||||||
else
|
else
|
||||||
to_chat(usr, span_filter_adminlog("Invalid ban id. Contact the database admin"))
|
to_chat(user, span_filter_adminlog("Invalid ban id. Contact the database admin"))
|
||||||
qdel(query)
|
qdel(query)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -185,32 +188,34 @@
|
|||||||
switch(param)
|
switch(param)
|
||||||
if("reason")
|
if("reason")
|
||||||
if(!value)
|
if(!value)
|
||||||
value = sanitize(tgui_input_text(usr, "Insert the new reason for [pckey]'s ban", "New Reason", "[reason]", null))
|
value = sanitize(tgui_input_text(user, "Insert the new reason for [pckey]'s ban", "New Reason", "[reason]", null))
|
||||||
value = sql_sanitize_text(value)
|
value = sql_sanitize_text(value)
|
||||||
if(!value)
|
if(!value)
|
||||||
to_chat(usr, "Cancelled")
|
to_chat(user, "Cancelled")
|
||||||
return
|
return
|
||||||
|
|
||||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from <cite>" + span_bold("\\\"[reason]\\\"") + "</cite> to <cite>" + span_bold("\\\"[value]\\\"") + "</cite><BR>') WHERE id = [banid]")
|
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from <cite><b>\\\"[reason]\\\"</b></cite> to <cite><b>\\\"[value]\\\"</b></cite><BR>') WHERE id = [banid]")
|
||||||
update_query.Execute()
|
update_query.Execute()
|
||||||
message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s reason from [reason] to [value]",1)
|
message_admins("[key_name_admin(user)] has edited a ban for [pckey]'s reason from [reason] to [value]",1)
|
||||||
qdel(update_query)
|
qdel(update_query)
|
||||||
|
return
|
||||||
if("duration")
|
if("duration")
|
||||||
if(!value)
|
if(!value)
|
||||||
value = tgui_input_number(usr, "Insert the new duration (in minutes) for [pckey]'s ban", "New Duration", "[duration]", null)
|
value = tgui_input_number(user, "Insert the new duration (in minutes) for [pckey]'s ban", "New Duration", "[duration]", null)
|
||||||
if(!isnum(value) || !value)
|
if(!isnum(value) || !value)
|
||||||
to_chat(usr, "Cancelled")
|
to_chat(user, "Cancelled")
|
||||||
return
|
return
|
||||||
|
|
||||||
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]<br>'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]")
|
var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]<br>'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]")
|
||||||
message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s duration from [duration] to [value]",1)
|
message_admins("[key_name_admin(user)] has edited a ban for [pckey]'s duration from [duration] to [value]",1)
|
||||||
update_query.Execute()
|
update_query.Execute()
|
||||||
qdel(update_query)
|
qdel(update_query)
|
||||||
|
return
|
||||||
if("unban")
|
if("unban")
|
||||||
if(tgui_alert(usr, "Unban [pckey]?", "Unban?", list("Yes", "No")) == "Yes")
|
if(tgui_alert(user, "Unban [pckey]?", "Unban?", list("Yes", "No")) == "Yes")
|
||||||
DB_ban_unban_by_id(banid)
|
DB_ban_unban_by_id(banid)
|
||||||
return
|
return
|
||||||
to_chat(usr, span_filter_adminlog("Cancelled"))
|
to_chat(user, span_filter_adminlog("Cancelled"))
|
||||||
return
|
return
|
||||||
|
|
||||||
/datum/admins/proc/DB_ban_unban_by_id(var/id)
|
/datum/admins/proc/DB_ban_unban_by_id(var/id)
|
||||||
@@ -261,228 +266,20 @@
|
|||||||
if(!holder)
|
if(!holder)
|
||||||
return
|
return
|
||||||
|
|
||||||
holder.DB_ban_panel()
|
holder.DB_ban_panel(src)
|
||||||
|
|
||||||
|
|
||||||
/datum/admins/proc/DB_ban_panel(var/playerckey = null, var/adminckey = null, var/playerip = null, var/playercid = null, var/dbbantype = null, var/match = null)
|
/datum/admins/proc/DB_ban_panel(client/user, var/playerckey = null)
|
||||||
if(!usr.client)
|
if(!user)
|
||||||
return
|
return
|
||||||
|
|
||||||
if(!check_rights(R_BAN)) return
|
if(!check_rights_for(user, R_BAN))
|
||||||
|
return
|
||||||
|
|
||||||
establish_db_connection()
|
establish_db_connection()
|
||||||
if(!SSdbcore.IsConnected())
|
if(!SSdbcore.IsConnected())
|
||||||
to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection")]"))
|
to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection")]"))
|
||||||
return
|
return
|
||||||
|
|
||||||
var/output = "<div align='center'><table width='90%'><tr>"
|
var/datum/tgui_ban_panel/tgui = new(user, playerckey, src)
|
||||||
|
tgui.tgui_interact(user.mob)
|
||||||
output += "<td width='35%' align='center'>"
|
|
||||||
output += "<h1>Banning panel</h1>"
|
|
||||||
output += "</td>"
|
|
||||||
|
|
||||||
output += "<td width='65%' align='center' bgcolor='#f9f9f9'>"
|
|
||||||
|
|
||||||
output += "<form method='GET' action='?src=\ref[src]'>[HrefTokenFormField()]"
|
|
||||||
output += span_bold("Add custom ban:") + " (ONLY use this if you can't ban through any other method)"
|
|
||||||
output += "<input type='hidden' name='src' value='\ref[src]'>"
|
|
||||||
output += "<table width='100%'><tr>"
|
|
||||||
output += "<td width='50%' align='right'>" + span_bold("Ban type:") + "<select name='dbbanaddtype'>"
|
|
||||||
output += "<option value=''>--</option>"
|
|
||||||
output += "<option value='[BANTYPE_PERMA]'>PERMABAN</option>"
|
|
||||||
output += "<option value='[BANTYPE_TEMP]'>TEMPBAN</option>"
|
|
||||||
output += "<option value='[BANTYPE_JOB_PERMA]'>JOB PERMABAN</option>"
|
|
||||||
output += "<option value='[BANTYPE_JOB_TEMP]'>JOB TEMPBAN</option>"
|
|
||||||
output += "</select></td>"
|
|
||||||
output += "<td width='50%' align='right'>" + span_bold("Ckey:") + " <input type='text' name='dbbanaddckey'></td></tr>"
|
|
||||||
output += "<tr><td width='50%' align='right'>" + span_bold("IP:") + " <input type='text' name='dbbanaddip'></td>"
|
|
||||||
output += "<td width='50%' align='right'>" + span_bold("CID:") + " <input type='text' name='dbbanaddcid'></td></tr>"
|
|
||||||
output += "<tr><td width='50%' align='right'>" + span_bold("Duration:") + " <input type='text' name='dbbaddduration'></td>"
|
|
||||||
output += "<td width='50%' align='right'>" + span_bold("Job:") + "<select name='dbbanaddjob'>"
|
|
||||||
output += "<option value=''>--</option>"
|
|
||||||
for(var/j in get_all_jobs())
|
|
||||||
output += "<option value='[j]'>[j]</option>"
|
|
||||||
for(var/j in SSjob.get_job_titles_in_department(DEPARTMENT_SYNTHETIC))
|
|
||||||
output += "<option value='[j]'>[j]</option>"
|
|
||||||
var/list/bantypes = list("traitor","changeling","operative","revolutionary","cultist","wizard") //For legacy bans.
|
|
||||||
for(var/antag_type in GLOB.all_antag_types) // Grab other bans.
|
|
||||||
var/datum/antagonist/antag = GLOB.all_antag_types[antag_type]
|
|
||||||
bantypes |= antag.bantype
|
|
||||||
for(var/j in bantypes)
|
|
||||||
output += "<option value='[j]'>[j]</option>"
|
|
||||||
output += "</select></td></tr></table>"
|
|
||||||
output += span_bold("Reason:<br>") + "<textarea name='dbbanreason' cols='50'></textarea><br>"
|
|
||||||
output += "<input type='submit' value='Add ban'>"
|
|
||||||
output += "</form>"
|
|
||||||
|
|
||||||
output += "</td>"
|
|
||||||
output += "</tr>"
|
|
||||||
output += "</table>"
|
|
||||||
|
|
||||||
output += "<form method='GET' action='?src=\ref[src]'>[HrefTokenFormField()]"
|
|
||||||
output += "<table width='60%'><tr><td colspan='2' align='left'>" + span_bold("Search:") + ""
|
|
||||||
output += "<input type='hidden' name='src' value='\ref[src]'></td></tr>"
|
|
||||||
output += "<tr><td width='50%' align='right'>" + span_bold("Ckey:") + " <input type='text' name='dbsearchckey' value='[playerckey]'></td>"
|
|
||||||
output += "<td width='50%' align='right'>" + span_bold("Admin ckey:") + " <input type='text' name='dbsearchadmin' value='[adminckey]'></td></tr>"
|
|
||||||
output += "<tr><td width='50%' align='right'>" + span_bold("IP:") + " <input type='text' name='dbsearchip' value='[playerip]'></td>"
|
|
||||||
output += "<td width='50%' align='right'>" + span_bold("CID:") + " <input type='text' name='dbsearchcid' value='[playercid]'></td></tr>"
|
|
||||||
output += "<tr><td width='50%' align='right' colspan='2'>" + span_bold("Ban type:") + "<select name='dbsearchbantype'>"
|
|
||||||
output += "<option value=''>--</option>"
|
|
||||||
output += "<option value='[BANTYPE_PERMA]'>PERMABAN</option>"
|
|
||||||
output += "<option value='[BANTYPE_TEMP]'>TEMPBAN</option>"
|
|
||||||
output += "<option value='[BANTYPE_JOB_PERMA]'>JOB PERMABAN</option>"
|
|
||||||
output += "<option value='[BANTYPE_JOB_TEMP]'>JOB TEMPBAN</option>"
|
|
||||||
output += "</select></td></tr></table>"
|
|
||||||
output += "<br><input type='submit' value='search'><br>"
|
|
||||||
output += "<input type='checkbox' value='[match]' name='dbmatch' [match? "checked=\"1\"" : null]> Match(min. 3 characters to search by key or ip, and 7 to search by cid)<br>"
|
|
||||||
output += "</form>"
|
|
||||||
output += "Please note that all jobban bans or unbans are in-effect the following round.<br>"
|
|
||||||
output += "This search shows only last 100 bans."
|
|
||||||
|
|
||||||
if(adminckey || playerckey || playerip || playercid || dbbantype)
|
|
||||||
|
|
||||||
adminckey = ckey(adminckey)
|
|
||||||
playerckey = ckey(playerckey)
|
|
||||||
playerip = sql_sanitize_text(playerip)
|
|
||||||
playercid = sql_sanitize_text(playercid)
|
|
||||||
|
|
||||||
if(adminckey || playerckey || playerip || playercid || dbbantype)
|
|
||||||
|
|
||||||
var/blcolor = "#ffeeee" //banned light
|
|
||||||
var/bdcolor = "#ffdddd" //banned dark
|
|
||||||
var/ulcolor = "#eeffee" //unbanned light
|
|
||||||
var/udcolor = "#ddffdd" //unbanned dark
|
|
||||||
var/alcolor = "#eeeeff" // auto-unbanned light
|
|
||||||
var/adcolor = "#ddddff" // auto-unbanned dark
|
|
||||||
|
|
||||||
output += "<table width='90%' bgcolor='#e3e3e3' cellpadding='5' cellspacing='0' align='center'>"
|
|
||||||
output += "<tr>"
|
|
||||||
output += "<th width='25%'>" + span_bold("TYPE") + "</th>"
|
|
||||||
output += "<th width='20%'>" + span_bold("CKEY") + "</th>"
|
|
||||||
output += "<th width='20%'>" + span_bold("TIME APPLIED") + "</th>"
|
|
||||||
output += "<th width='20%'>" + span_bold("ADMIN") + "</th>"
|
|
||||||
output += "<th width='15%'>" + span_bold("OPTIONS") + "</th>"
|
|
||||||
output += "</tr>"
|
|
||||||
|
|
||||||
var/adminsearch = ""
|
|
||||||
var/playersearch = ""
|
|
||||||
var/ipsearch = ""
|
|
||||||
var/cidsearch = ""
|
|
||||||
var/bantypesearch = ""
|
|
||||||
|
|
||||||
if(!match)
|
|
||||||
if(adminckey)
|
|
||||||
adminsearch = "AND a_ckey = '[adminckey]' "
|
|
||||||
if(playerckey)
|
|
||||||
playersearch = "AND ckey = '[playerckey]' "
|
|
||||||
if(playerip)
|
|
||||||
ipsearch = "AND ip = '[playerip]' "
|
|
||||||
if(playercid)
|
|
||||||
cidsearch = "AND computerid = '[playercid]' "
|
|
||||||
else
|
|
||||||
if(adminckey && length(adminckey) >= 3)
|
|
||||||
adminsearch = "AND a_ckey LIKE '[adminckey]%' "
|
|
||||||
if(playerckey && length(playerckey) >= 3)
|
|
||||||
playersearch = "AND ckey LIKE '[playerckey]%' "
|
|
||||||
if(playerip && length(playerip) >= 3)
|
|
||||||
ipsearch = "AND ip LIKE '[playerip]%' "
|
|
||||||
if(playercid && length(playercid) >= 7)
|
|
||||||
cidsearch = "AND computerid LIKE '[playercid]%' "
|
|
||||||
|
|
||||||
if(dbbantype)
|
|
||||||
bantypesearch = "AND bantype = "
|
|
||||||
|
|
||||||
switch(dbbantype)
|
|
||||||
if(BANTYPE_TEMP)
|
|
||||||
bantypesearch += "'TEMPBAN' "
|
|
||||||
if(BANTYPE_JOB_PERMA)
|
|
||||||
bantypesearch += "'JOB_PERMABAN' "
|
|
||||||
if(BANTYPE_JOB_TEMP)
|
|
||||||
bantypesearch += "'JOB_TEMPBAN' "
|
|
||||||
else
|
|
||||||
bantypesearch += "'PERMABAN' "
|
|
||||||
|
|
||||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100")
|
|
||||||
select_query.Execute()
|
|
||||||
|
|
||||||
var/now = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") // MUST BE the same format as SQL gives us the dates in, and MUST be least to most specific (i.e. year, month, day not day, month, year)
|
|
||||||
|
|
||||||
while(select_query.NextRow())
|
|
||||||
var/banid = select_query.item[1]
|
|
||||||
var/bantime = select_query.item[2]
|
|
||||||
var/bantype = select_query.item[3]
|
|
||||||
var/reason = select_query.item[4]
|
|
||||||
var/job = select_query.item[5]
|
|
||||||
var/duration = select_query.item[6]
|
|
||||||
var/expiration = select_query.item[7]
|
|
||||||
var/ckey = select_query.item[8]
|
|
||||||
var/ackey = select_query.item[9]
|
|
||||||
var/unbanned = select_query.item[10]
|
|
||||||
var/unbanckey = select_query.item[11]
|
|
||||||
var/unbantime = select_query.item[12]
|
|
||||||
var/edits = select_query.item[13]
|
|
||||||
var/ip = select_query.item[14]
|
|
||||||
var/cid = select_query.item[15]
|
|
||||||
|
|
||||||
// true if this ban has expired
|
|
||||||
var/auto = (bantype in list("TEMPBAN", "JOB_TEMPBAN")) && now > expiration // oh how I love ISO 8601 (ish) date strings
|
|
||||||
|
|
||||||
var/lcolor = blcolor
|
|
||||||
var/dcolor = bdcolor
|
|
||||||
if(unbanned)
|
|
||||||
lcolor = ulcolor
|
|
||||||
dcolor = udcolor
|
|
||||||
else if(auto)
|
|
||||||
lcolor = alcolor
|
|
||||||
dcolor = adcolor
|
|
||||||
|
|
||||||
var/typedesc =""
|
|
||||||
switch(bantype)
|
|
||||||
if("PERMABAN")
|
|
||||||
typedesc = span_red(span_bold("PERMABAN"))
|
|
||||||
if("TEMPBAN")
|
|
||||||
typedesc = span_bold("TEMPBAN") + "<br>" + span_normal("([duration] minutes) [(unbanned || auto) ? "" : "(<a href=\"byond://?src=\ref[src];[HrefToken()];dbbanedit=duration;dbbanid=[banid]\">Edit</a>)"]<br>Expires [expiration]")
|
|
||||||
if("JOB_PERMABAN")
|
|
||||||
typedesc = span_bold("JOBBAN") + "<br>" + span_normal("([job])")
|
|
||||||
if("JOB_TEMPBAN")
|
|
||||||
typedesc = span_bold("TEMP JOBBAN") + "<br>" + span_normal("([job])<br>([duration] minutes<br>Expires [expiration]")
|
|
||||||
|
|
||||||
output += "<tr bgcolor='[dcolor]'>"
|
|
||||||
output += "<td align='center'>[typedesc]</td>"
|
|
||||||
output += "<td align='center'>" + span_bold("[ckey]") + "</td>"
|
|
||||||
output += "<td align='center'>[bantime]</td>"
|
|
||||||
output += "<td align='center'>" + span_bold("[ackey]") + "</td>"
|
|
||||||
output += "<td align='center'>[(unbanned || auto) ? "" : span_bold("<a href=\"byond://?src=\ref[src];[HrefToken()];dbbanedit=unban;dbbanid=[banid]\">Unban</a>")]</td>"
|
|
||||||
output += "</tr>"
|
|
||||||
output += "<tr bgcolor='[dcolor]'>"
|
|
||||||
output += "<td align='center' colspan='2' bgcolor=''>" + span_bold("IP:") + " [ip]</td>"
|
|
||||||
output += "<td align='center' colspan='3' bgcolor=''>" + span_bold("CIP:") + " [cid]</td>"
|
|
||||||
output += "</tr>"
|
|
||||||
output += "<tr bgcolor='[lcolor]'>"
|
|
||||||
output += "<td align='center' colspan='5'>" + span_bold("Reason: [(unbanned || auto) ? "" : "(<a href=\"byond://?src=\ref[src];[HrefToken()];dbbanedit=reason;dbbanid=[banid]\">Edit</a>)"]") + " <cite>\"[reason]\"</cite></td>"
|
|
||||||
output += "</tr>"
|
|
||||||
if(edits)
|
|
||||||
output += "<tr bgcolor='[dcolor]'>"
|
|
||||||
output += "<td align='center' colspan='5'>" + span_bold("EDITS") + "</td>"
|
|
||||||
output += "</tr>"
|
|
||||||
output += "<tr bgcolor='[lcolor]'>"
|
|
||||||
output += "<td align='center' colspan='5'>" + span_normal("[edits]") + "</td>"
|
|
||||||
output += "</tr>"
|
|
||||||
if(unbanned)
|
|
||||||
output += "<tr bgcolor='[dcolor]'>"
|
|
||||||
output += "<td align='center' colspan='5' bgcolor=''>" + span_bold("UNBANNED by admin [unbanckey] on [unbantime]") + "</td>"
|
|
||||||
output += "</tr>"
|
|
||||||
else if(auto)
|
|
||||||
output += "<tr bgcolor='[dcolor]'>"
|
|
||||||
output += "<td align='center' colspan='5' bgcolor=''>" + span_bold("EXPIRED at [expiration]") + "</td>"
|
|
||||||
output += "</tr>"
|
|
||||||
output += "<tr>"
|
|
||||||
output += "<td colspan='5' bgcolor='white'> </td>"
|
|
||||||
output += "</tr>"
|
|
||||||
|
|
||||||
output += "</table></div>"
|
|
||||||
qdel(select_query)
|
|
||||||
|
|
||||||
var/datum/browser/popup = new(owner, "lookupbans", "Lookup Bans", 900, 700)
|
|
||||||
popup.set_content(output)
|
|
||||||
popup.open()
|
|
||||||
|
|||||||
@@ -179,14 +179,14 @@ ADMIN_VERB(jobbans, R_BAN, "Display Job bans", "View job bans here.", "Admin.Inv
|
|||||||
if(CONFIG_GET(flag/ban_legacy_system))
|
if(CONFIG_GET(flag/ban_legacy_system))
|
||||||
user.holder.Jobbans()
|
user.holder.Jobbans()
|
||||||
else
|
else
|
||||||
user.holder.DB_ban_panel()
|
user.holder.DB_ban_panel(user)
|
||||||
feedback_add_details("admin_verb","VJB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
feedback_add_details("admin_verb","VJB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||||
|
|
||||||
ADMIN_VERB(unban_panel, R_BAN, "Unbanning Panel", "Unban players here.", ADMIN_CATEGORY_GAME)
|
ADMIN_VERB(unban_panel, R_BAN, "Unbanning Panel", "Unban players here.", ADMIN_CATEGORY_GAME)
|
||||||
if(CONFIG_GET(flag/ban_legacy_system))
|
if(CONFIG_GET(flag/ban_legacy_system))
|
||||||
user.holder.unbanpanel()
|
user.holder.unbanpanel()
|
||||||
else
|
else
|
||||||
user.holder.DB_ban_panel()
|
user.holder.DB_ban_panel(user)
|
||||||
feedback_add_details("admin_verb","UBP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
feedback_add_details("admin_verb","UBP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||||
|
|
||||||
ADMIN_VERB(game_panel, R_ADMIN|R_SERVER|R_FUN, "Game Panel", "Look at the state of the game.", ADMIN_CATEGORY_GAME)
|
ADMIN_VERB(game_panel, R_ADMIN|R_SERVER|R_FUN, "Game Panel", "Look at the state of the game.", ADMIN_CATEGORY_GAME)
|
||||||
|
|||||||
@@ -45,87 +45,6 @@
|
|||||||
|
|
||||||
// mentor_commands(href, href_list, src) - Skip because client is already admin & contents handled above
|
// mentor_commands(href, href_list, src) - Skip because client is already admin & contents handled above
|
||||||
|
|
||||||
if(href_list["dbsearchckey"] || href_list["dbsearchadmin"])
|
|
||||||
|
|
||||||
var/adminckey = href_list["dbsearchadmin"]
|
|
||||||
var/playerckey = href_list["dbsearchckey"]
|
|
||||||
var/playerip = href_list["dbsearchip"]
|
|
||||||
var/playercid = href_list["dbsearchcid"]
|
|
||||||
var/dbbantype = text2num(href_list["dbsearchbantype"])
|
|
||||||
var/match = 0
|
|
||||||
|
|
||||||
if("dbmatch" in href_list)
|
|
||||||
match = 1
|
|
||||||
|
|
||||||
DB_ban_panel(playerckey, adminckey, playerip, playercid, dbbantype, match)
|
|
||||||
return
|
|
||||||
|
|
||||||
else if(href_list["dbbanedit"])
|
|
||||||
var/banedit = href_list["dbbanedit"]
|
|
||||||
var/banid = text2num(href_list["dbbanid"])
|
|
||||||
if(!banedit || !banid)
|
|
||||||
return
|
|
||||||
|
|
||||||
DB_ban_edit(banid, banedit)
|
|
||||||
return
|
|
||||||
|
|
||||||
else if(href_list["dbbanaddtype"])
|
|
||||||
|
|
||||||
var/bantype = text2num(href_list["dbbanaddtype"])
|
|
||||||
var/banckey = href_list["dbbanaddckey"]
|
|
||||||
var/banip = href_list["dbbanaddip"]
|
|
||||||
var/bancid = href_list["dbbanaddcid"]
|
|
||||||
var/banduration = text2num(href_list["dbbaddduration"])
|
|
||||||
var/banjob = href_list["dbbanaddjob"]
|
|
||||||
var/banreason = href_list["dbbanreason"]
|
|
||||||
|
|
||||||
banckey = ckey(banckey)
|
|
||||||
|
|
||||||
switch(bantype)
|
|
||||||
if(BANTYPE_PERMA)
|
|
||||||
if(!banckey || !banreason)
|
|
||||||
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey and reason)"))
|
|
||||||
return
|
|
||||||
banduration = null
|
|
||||||
banjob = null
|
|
||||||
if(BANTYPE_TEMP)
|
|
||||||
if(!banckey || !banreason || !banduration)
|
|
||||||
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey, reason and duration)"))
|
|
||||||
return
|
|
||||||
banjob = null
|
|
||||||
if(BANTYPE_JOB_PERMA)
|
|
||||||
if(!banckey || !banreason || !banjob)
|
|
||||||
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey, reason and job)"))
|
|
||||||
return
|
|
||||||
banduration = null
|
|
||||||
if(BANTYPE_JOB_TEMP)
|
|
||||||
if(!banckey || !banreason || !banjob || !banduration)
|
|
||||||
to_chat(usr, span_filter_adminlog("Not enough parameters (Requires ckey, reason and job)"))
|
|
||||||
return
|
|
||||||
|
|
||||||
var/mob/playermob
|
|
||||||
|
|
||||||
for(var/mob/M in GLOB.player_list)
|
|
||||||
if(M.ckey == banckey)
|
|
||||||
playermob = M
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
banreason = "(MANUAL BAN) "+banreason
|
|
||||||
|
|
||||||
if(!playermob)
|
|
||||||
if(banip)
|
|
||||||
banreason = "[banreason] (CUSTOM IP)"
|
|
||||||
if(bancid)
|
|
||||||
banreason = "[banreason] (CUSTOM CID)"
|
|
||||||
else
|
|
||||||
message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob")
|
|
||||||
notes_add(banckey,banreason,usr)
|
|
||||||
|
|
||||||
DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid )
|
|
||||||
if((bantype == BANTYPE_PERMA || bantype == BANTYPE_TEMP) && playermob.client)
|
|
||||||
qdel(playermob.client)
|
|
||||||
|
|
||||||
else if(href_list["editrightsbrowser"])
|
else if(href_list["editrightsbrowser"])
|
||||||
edit_admin_permissions(0)
|
edit_admin_permissions(0)
|
||||||
|
|
||||||
@@ -763,7 +682,7 @@
|
|||||||
if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban.
|
if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban.
|
||||||
if(!CONFIG_GET(flag/ban_legacy_system))
|
if(!CONFIG_GET(flag/ban_legacy_system))
|
||||||
to_chat(usr, span_filter_adminlog("Unfortunately, database based unbanning cannot be done through this panel"))
|
to_chat(usr, span_filter_adminlog("Unfortunately, database based unbanning cannot be done through this panel"))
|
||||||
DB_ban_panel(M.ckey)
|
DB_ban_panel(usr.client, M.ckey)
|
||||||
return
|
return
|
||||||
var/msg
|
var/msg
|
||||||
for(var/job in joblist)
|
for(var/job in joblist)
|
||||||
|
|||||||
@@ -121,24 +121,31 @@
|
|||||||
return TRUE
|
return TRUE
|
||||||
|
|
||||||
switch(action)
|
switch(action)
|
||||||
|
if("cahngekey")
|
||||||
|
key = sanitize(params["ckey"])
|
||||||
|
return TRUE
|
||||||
|
|
||||||
if("add_player_info")
|
if("add_player_info")
|
||||||
var/key = params["ckey"]
|
var/key = params["ckey"]
|
||||||
var/add = tgui_input_text(ui.user, "Write your comment below.", "Add Player Info", multiline = TRUE, prevent_enter = TRUE)
|
var/add = tgui_input_text(ui.user, "Write your comment below.", "Add Player Info", multiline = TRUE, prevent_enter = TRUE)
|
||||||
if(!add) return
|
if(!add)
|
||||||
|
return FALSE
|
||||||
|
|
||||||
notes_add(key,add,ui.user)
|
notes_add(key,add,ui.user)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
if("remove_player_info")
|
if("remove_player_info")
|
||||||
var/key = params["ckey"]
|
var/key = params["ckey"]
|
||||||
var/index = params["index"]
|
var/index = params["index"]
|
||||||
|
|
||||||
notes_del(key, index)
|
notes_del(key, index)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
/datum/tgui_module/player_notes_info/tgui_data(mob/user)
|
/datum/tgui_module/player_notes_info/tgui_data(mob/user)
|
||||||
var/list/data = list()
|
var/list/data = list()
|
||||||
|
|
||||||
if(!key)
|
if(!key)
|
||||||
return
|
return data
|
||||||
|
|
||||||
var/p_age = "unknown"
|
var/p_age = "unknown"
|
||||||
for(var/client/C in GLOB.clients)
|
for(var/client/C in GLOB.clients)
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ h4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.blue {
|
.blue {
|
||||||
color: #0000ff;
|
color: #4ea0ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.black {
|
.black {
|
||||||
|
|||||||
6964
tgui/bun.lock
6964
tgui/bun.lock
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@happy-dom/global-registrator": "^17.6.3",
|
"@happy-dom/global-registrator": "^17.6.3",
|
||||||
"@rspack/cli": "^1.4.8",
|
"@rspack/cli": "^1.4.9",
|
||||||
"@rspack/core": "^1.4.8",
|
"@rspack/core": "^1.4.9",
|
||||||
"@types/bun": "^1.2.19",
|
"@types/bun": "^1.2.19",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^19.1.6",
|
"@types/react-dom": "^19.1.6",
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { Section, Stack, Table } from 'tgui-core/components';
|
||||||
|
|
||||||
|
import type { DatabaseRecord } from '../types';
|
||||||
|
import { DatabaseEntry } from './Helpers/DatabaseEntry';
|
||||||
|
|
||||||
|
export const BanSearchResults = (props: {
|
||||||
|
database_records: DatabaseRecord[] | null;
|
||||||
|
}) => {
|
||||||
|
const { database_records } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section fill scrollable>
|
||||||
|
<Stack vertical>
|
||||||
|
<Stack.Item grow>
|
||||||
|
<Table>
|
||||||
|
<Table.Row header backgroundColor="#383838">
|
||||||
|
<Table.Cell align="center">TYPE</Table.Cell>
|
||||||
|
<Table.Cell align="center">CKEY</Table.Cell>
|
||||||
|
<Table.Cell align="center">IP</Table.Cell>
|
||||||
|
<Table.Cell align="center">CID</Table.Cell>
|
||||||
|
<Table.Cell align="center">TIME APPLIED</Table.Cell>
|
||||||
|
<Table.Cell align="center">ADMIN</Table.Cell>
|
||||||
|
<Table.Cell align="center">OPTIONS</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
{database_records?.map((record) => (
|
||||||
|
<DatabaseEntry
|
||||||
|
key={record.data_list[0]}
|
||||||
|
databaseRecord={record}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Table>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useBackend } from 'tgui/backend';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Dropdown,
|
||||||
|
Input,
|
||||||
|
LabeledList,
|
||||||
|
NumberInput,
|
||||||
|
Section,
|
||||||
|
Stack,
|
||||||
|
TextArea,
|
||||||
|
} from 'tgui-core/components';
|
||||||
|
|
||||||
|
import { ban_types } from '../constants';
|
||||||
|
import type { Data } from '../types';
|
||||||
|
import { InputHelper } from './Helpers/InputHelper';
|
||||||
|
|
||||||
|
export const BanningSection = (props: { possibleJobs: string[] }) => {
|
||||||
|
const { act } = useBackend<Data>();
|
||||||
|
|
||||||
|
const { possibleJobs } = props;
|
||||||
|
|
||||||
|
const [banType, setBanType] = useState('');
|
||||||
|
const [banIP, setBanIP] = useState('');
|
||||||
|
const [banDuration, setBanDuration] = useState(0);
|
||||||
|
const [banCkey, setBanCkey] = useState('');
|
||||||
|
const [banCID, setBanCID] = useState('');
|
||||||
|
const [banJob, setBanJob] = useState('');
|
||||||
|
const [banReason, setBanReason] = useState('');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section fill>
|
||||||
|
<Stack vertical fill>
|
||||||
|
<Stack.Item>
|
||||||
|
<Stack>
|
||||||
|
<Stack.Item basis="30%">
|
||||||
|
<LabeledList>
|
||||||
|
<LabeledList.Item label="Ban Type">
|
||||||
|
<Dropdown
|
||||||
|
fluid
|
||||||
|
onSelected={(value) => {
|
||||||
|
setBanType(value);
|
||||||
|
}}
|
||||||
|
options={ban_types}
|
||||||
|
selected={banType}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="IP">
|
||||||
|
<Input
|
||||||
|
fluid
|
||||||
|
value={banIP}
|
||||||
|
onBlur={(value) => setBanIP(value)}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="Duration">
|
||||||
|
<NumberInput
|
||||||
|
fluid
|
||||||
|
value={banDuration}
|
||||||
|
minValue={0}
|
||||||
|
step={1}
|
||||||
|
maxValue={Infinity}
|
||||||
|
unit="min"
|
||||||
|
onChange={(value) => setBanDuration(value)}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
</LabeledList>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Divider />
|
||||||
|
<Stack.Item basis="30%">
|
||||||
|
<LabeledList>
|
||||||
|
<LabeledList.Item label="Ckey">
|
||||||
|
<Input
|
||||||
|
fluid
|
||||||
|
value={banCkey}
|
||||||
|
onBlur={(value) => setBanCkey(value)}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="CID">
|
||||||
|
<Input
|
||||||
|
fluid
|
||||||
|
value={banCID}
|
||||||
|
onBlur={(value) => setBanCID(value)}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="Job">
|
||||||
|
<Dropdown
|
||||||
|
fluid
|
||||||
|
onSelected={(value) => {
|
||||||
|
setBanJob(value);
|
||||||
|
}}
|
||||||
|
options={possibleJobs}
|
||||||
|
selected={banJob}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
</LabeledList>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Divider />
|
||||||
|
<Stack.Item basis="30%">
|
||||||
|
<InputHelper
|
||||||
|
banType={banType}
|
||||||
|
banCkey={banCkey}
|
||||||
|
banDuration={banDuration}
|
||||||
|
banJob={banJob}
|
||||||
|
banReason={banReason}
|
||||||
|
/>
|
||||||
|
<Button.Confirm
|
||||||
|
position="absolute"
|
||||||
|
top="60px"
|
||||||
|
onClick={() => {
|
||||||
|
act('confirmBan', {
|
||||||
|
type: ban_types.indexOf(banType) + 1,
|
||||||
|
ip: banIP,
|
||||||
|
duration: banDuration,
|
||||||
|
ckey: banCkey,
|
||||||
|
cid: banCID,
|
||||||
|
job: banJob,
|
||||||
|
reason: banReason,
|
||||||
|
});
|
||||||
|
setBanType('');
|
||||||
|
setBanIP('');
|
||||||
|
setBanDuration(0);
|
||||||
|
setBanCkey('');
|
||||||
|
setBanCID('');
|
||||||
|
setBanJob('');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add ban
|
||||||
|
</Button.Confirm>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Divider />
|
||||||
|
<Stack.Item>
|
||||||
|
<Box color="label">Reason:</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item grow>
|
||||||
|
<TextArea
|
||||||
|
fluid
|
||||||
|
height="100%"
|
||||||
|
value={banReason}
|
||||||
|
onBlur={(value) => setBanReason(value)}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import { useBackend } from 'tgui/backend';
|
||||||
|
import { Box, Button, Divider, Stack, Table } from 'tgui-core/components';
|
||||||
|
|
||||||
|
import { getBoxColor } from '../../functions';
|
||||||
|
import type { Data, DatabaseRecord } from '../../types';
|
||||||
|
|
||||||
|
// This list is of the format: banid, bantime, bantype, reason, job, duration, expiration,
|
||||||
|
// ckey, ackey, unbanned, unbanckey, unbantime, edits, ip, cid
|
||||||
|
export const DatabaseEntry = (props: { databaseRecord: DatabaseRecord }) => {
|
||||||
|
const { act } = useBackend<Data>();
|
||||||
|
|
||||||
|
const { databaseRecord } = props;
|
||||||
|
|
||||||
|
const { data_list, auto } = databaseRecord;
|
||||||
|
|
||||||
|
const [
|
||||||
|
banid,
|
||||||
|
bantime,
|
||||||
|
bantype,
|
||||||
|
reason,
|
||||||
|
job,
|
||||||
|
duration,
|
||||||
|
expiration,
|
||||||
|
ckey,
|
||||||
|
ackey,
|
||||||
|
unbanned,
|
||||||
|
unbanckey,
|
||||||
|
unbantime,
|
||||||
|
edits,
|
||||||
|
ip,
|
||||||
|
cid,
|
||||||
|
] = data_list;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Table.Row backgroundColor={getBoxColor(!!unbanned, !!auto)[0]}>
|
||||||
|
<Table.Cell
|
||||||
|
align="center"
|
||||||
|
collapsing
|
||||||
|
color={bantype === 'PERMABAN' ? 'red' : undefined}
|
||||||
|
>
|
||||||
|
<Stack vertical>
|
||||||
|
<Stack.Item>{bantype}</Stack.Item>
|
||||||
|
{(bantype === 'JOB_PERMABAN' || bantype === 'JOB_TEMPBAN') && (
|
||||||
|
<Stack.Item>{job}</Stack.Item>
|
||||||
|
)}
|
||||||
|
{(bantype === 'TEMPBAN' || bantype === 'JOB_TEMPBAN') && (
|
||||||
|
<Stack.Item>
|
||||||
|
<Stack>
|
||||||
|
<Stack.Item>{`(${duration} minutes)`}</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
{`Expire${!duration || auto ? 'd' : 's'} ${expiration}`}
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Stack.Item>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell align="center">{ckey}</Table.Cell>
|
||||||
|
<Table.Cell align="center">{ip}</Table.Cell>
|
||||||
|
<Table.Cell align="center">{cid}</Table.Cell>
|
||||||
|
<Table.Cell align="center">{bantime}</Table.Cell>
|
||||||
|
<Table.Cell align="center">{ackey}</Table.Cell>
|
||||||
|
<Table.Cell collapsing align="center">
|
||||||
|
<Stack>
|
||||||
|
{!!duration && !auto && bantype === 'TEMPBAN' && (
|
||||||
|
<Stack.Item>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
act('banEdit', { action: 'duration', banid: banid })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Duration
|
||||||
|
</Button>
|
||||||
|
</Stack.Item>
|
||||||
|
)}
|
||||||
|
{!unbanned && !auto && (
|
||||||
|
<Stack.Item>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
act('banEdit', { action: 'reason', banid: banid })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Reason
|
||||||
|
</Button>
|
||||||
|
</Stack.Item>
|
||||||
|
)}
|
||||||
|
{!unbanned && !auto && (
|
||||||
|
<Stack.Item>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
act('banEdit', { action: 'unban', banid: banid })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Unban
|
||||||
|
</Button>
|
||||||
|
</Stack.Item>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
<Table.Row backgroundColor={getBoxColor(!!unbanned, !!auto)[1]}>
|
||||||
|
<Table.Cell colSpan={7}>
|
||||||
|
<Stack vertical>
|
||||||
|
<Stack.Item>
|
||||||
|
<Stack>
|
||||||
|
<Stack.Item>Reason:</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<Box italic>{`"${reason}"`}</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
{!!edits && (
|
||||||
|
<>
|
||||||
|
<Table.Row backgroundColor={getBoxColor(!!unbanned, !!auto)[0]}>
|
||||||
|
<Table.Cell colSpan={7}>
|
||||||
|
<Box bold>EDITS</Box>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
<Table.Row backgroundColor={getBoxColor(!!unbanned, !!auto)[1]}>
|
||||||
|
<Table.Cell colSpan={7}>
|
||||||
|
{/* eslint-disable-next-line react/no-danger*/}
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: edits }} />
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{unbanned ? (
|
||||||
|
<Table.Row backgroundColor={getBoxColor(!!unbanned, !!auto)[0]}>
|
||||||
|
<Table.Cell colSpan={7}>
|
||||||
|
<Box bold>{`UNBANNED by admin ${unbanckey} on ${unbantime}`}</Box>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
) : (
|
||||||
|
!!auto && (
|
||||||
|
<Table.Row backgroundColor={getBoxColor(!!unbanned, !!auto)[0]}>
|
||||||
|
<Table.Cell colSpan={7}>
|
||||||
|
<Box bold>{`EXPIRED at ${expiration}`}</Box>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<Table.Row>
|
||||||
|
<Table.Cell colSpan={7}>
|
||||||
|
<Divider />
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { Box, Stack } from 'tgui-core/components';
|
||||||
|
|
||||||
|
export const InputHelper = (props: {
|
||||||
|
banType: string;
|
||||||
|
banCkey: string;
|
||||||
|
banDuration: number;
|
||||||
|
banJob: string;
|
||||||
|
banReason: string;
|
||||||
|
}) => {
|
||||||
|
const { banType, banCkey, banDuration, banJob, banReason } = props;
|
||||||
|
|
||||||
|
switch (banType) {
|
||||||
|
case 'PERMABAN':
|
||||||
|
if (!banCkey || !banReason) {
|
||||||
|
return <InputError banCkey={banCkey} banReason={banReason} />;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'TEMPBAN':
|
||||||
|
if (!banCkey || !banReason || !banDuration) {
|
||||||
|
return (
|
||||||
|
<InputError
|
||||||
|
banCkey={banCkey}
|
||||||
|
banReason={banReason}
|
||||||
|
banDuration={banDuration}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'JOB PERMABAN':
|
||||||
|
if (!banCkey || banReason || !banJob) {
|
||||||
|
return (
|
||||||
|
<InputError banCkey={banCkey} banReason={banReason} banJob={banJob} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'JOB TEMPBAN':
|
||||||
|
if (!banCkey || !banReason || !banDuration || !banJob) {
|
||||||
|
return (
|
||||||
|
<InputError
|
||||||
|
banCkey={banCkey}
|
||||||
|
banReason={banReason}
|
||||||
|
banDuration={banDuration}
|
||||||
|
banJob={banJob}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Box color="green">Valid Ban Input</Box>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InputError = (props: {
|
||||||
|
banCkey: string;
|
||||||
|
banReason: string;
|
||||||
|
banDuration?: number;
|
||||||
|
banJob?: string;
|
||||||
|
}) => {
|
||||||
|
const { banCkey, banReason, banDuration, banJob } = props;
|
||||||
|
|
||||||
|
const allMisisng: string[] = [];
|
||||||
|
if (!banCkey) {
|
||||||
|
allMisisng.push('Ckey');
|
||||||
|
}
|
||||||
|
if (!banReason) {
|
||||||
|
allMisisng.push('Reason');
|
||||||
|
}
|
||||||
|
if (banDuration !== undefined && !banDuration) {
|
||||||
|
allMisisng.push('Duration');
|
||||||
|
}
|
||||||
|
if (banJob !== undefined && !banJob) {
|
||||||
|
allMisisng.push('Job');
|
||||||
|
}
|
||||||
|
const formatter = new Intl.ListFormat('en', {
|
||||||
|
style: 'long',
|
||||||
|
type: 'conjunction',
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Stack vertical g={1.5}>
|
||||||
|
<Stack.Item>
|
||||||
|
<Box color="red">Invalid Ban Input</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<Stack>
|
||||||
|
<Stack.Item>
|
||||||
|
<Box color="label">Missing:</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<Box>{formatter.format(allMisisng)}</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useBackend } from 'tgui/backend';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Dropdown,
|
||||||
|
Input,
|
||||||
|
LabeledList,
|
||||||
|
Section,
|
||||||
|
Stack,
|
||||||
|
} from 'tgui-core/components';
|
||||||
|
|
||||||
|
import { ban_types } from '../constants';
|
||||||
|
import type { Data } from '../types';
|
||||||
|
|
||||||
|
export const SearchSection = (props: {
|
||||||
|
searchedCkey: string;
|
||||||
|
searchedAdminCkey: string;
|
||||||
|
searchedIp: string;
|
||||||
|
searchedCid: string;
|
||||||
|
searchedBanType: string;
|
||||||
|
minimumMatch: boolean;
|
||||||
|
}) => {
|
||||||
|
const { act } = useBackend<Data>();
|
||||||
|
|
||||||
|
const {
|
||||||
|
searchedCkey,
|
||||||
|
searchedAdminCkey,
|
||||||
|
searchedIp,
|
||||||
|
searchedCid,
|
||||||
|
searchedBanType,
|
||||||
|
minimumMatch,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const [ckey, setCkey] = useState(searchedCkey);
|
||||||
|
const [adminCkey, setAdminCkey] = useState(searchedAdminCkey);
|
||||||
|
const [ip, setIp] = useState(searchedIp);
|
||||||
|
const [cid, setCid] = useState(searchedCid);
|
||||||
|
const [banType, setBanType] = useState(searchedBanType);
|
||||||
|
const [minMatch, setMinMatch] = useState(minimumMatch);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section fill>
|
||||||
|
<Stack vertical fill>
|
||||||
|
<Stack.Item>
|
||||||
|
<Stack>
|
||||||
|
<Stack.Item basis="30%">
|
||||||
|
<LabeledList>
|
||||||
|
<LabeledList.Item label="Ckey">
|
||||||
|
<Input
|
||||||
|
fluid
|
||||||
|
value={ckey}
|
||||||
|
onBlur={(value) => setCkey(value)}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="IP">
|
||||||
|
<Input fluid value={ip} onBlur={(value) => setIp(value)} />
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="Ban Type">
|
||||||
|
<Dropdown
|
||||||
|
fluid
|
||||||
|
onSelected={(value) => {
|
||||||
|
setBanType(value);
|
||||||
|
}}
|
||||||
|
options={['Select...', ...ban_types]}
|
||||||
|
selected={banType}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
</LabeledList>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Divider />
|
||||||
|
<Stack.Item basis="30%">
|
||||||
|
<LabeledList>
|
||||||
|
<LabeledList.Item label="Admin Ckey">
|
||||||
|
<Input
|
||||||
|
fluid
|
||||||
|
value={adminCkey}
|
||||||
|
onBlur={(value) => setAdminCkey(value)}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="CID">
|
||||||
|
<Input fluid value={cid} onBlur={(value) => setCid(value)} />
|
||||||
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
act('searchBans', {
|
||||||
|
ckey: ckey,
|
||||||
|
aCkey: adminCkey,
|
||||||
|
ip: ip,
|
||||||
|
cid: cid,
|
||||||
|
minMatch: minMatch,
|
||||||
|
banType: ban_types.indexOf(banType) + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</Button>
|
||||||
|
</LabeledList.Item>
|
||||||
|
</LabeledList>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Divider />
|
||||||
|
<Stack.Item>
|
||||||
|
<Stack vertical g={1.5}>
|
||||||
|
<Stack.Item>
|
||||||
|
<Button.Checkbox
|
||||||
|
fluid
|
||||||
|
checked={minMatch}
|
||||||
|
onClick={() => setMinMatch(!minMatch)}
|
||||||
|
>
|
||||||
|
Match (min. 3 characters to search by key or ip, and 7 to
|
||||||
|
search by cid)
|
||||||
|
</Button.Checkbox>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<Box color="red">
|
||||||
|
Please note that all jobban bans are in-effect the following
|
||||||
|
round.
|
||||||
|
</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<Box>This search shows only the last 100 bans.</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
};
|
||||||
8
tgui/packages/tgui/interfaces/BanPanel/constants.ts
Normal file
8
tgui/packages/tgui/interfaces/BanPanel/constants.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export const ban_types = ['PERMABAN', 'TEMPBAN', 'JOB PERMABAN', 'JOB TEMPBAN'];
|
||||||
|
|
||||||
|
// ban color list [light, dark], banned, unbanned, auto_unbanned
|
||||||
|
export const ban_colors = [
|
||||||
|
['#300606', '#610d0d'],
|
||||||
|
['#041c04', '#093d09'],
|
||||||
|
['#070729', '#121261'],
|
||||||
|
];
|
||||||
10
tgui/packages/tgui/interfaces/BanPanel/functions.ts
Normal file
10
tgui/packages/tgui/interfaces/BanPanel/functions.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { ban_colors } from './constants';
|
||||||
|
|
||||||
|
export function getBoxColor(unbanned: boolean, auto: boolean): string[] {
|
||||||
|
if (unbanned) {
|
||||||
|
return ban_colors[1];
|
||||||
|
} else if (auto) {
|
||||||
|
return ban_colors[2];
|
||||||
|
}
|
||||||
|
return ban_colors[0];
|
||||||
|
}
|
||||||
47
tgui/packages/tgui/interfaces/BanPanel/index.tsx
Normal file
47
tgui/packages/tgui/interfaces/BanPanel/index.tsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { useBackend } from 'tgui/backend';
|
||||||
|
import { Window } from 'tgui/layouts';
|
||||||
|
import { Stack } from 'tgui-core/components';
|
||||||
|
|
||||||
|
import { BanningSection } from './Elements/BanningSection';
|
||||||
|
import { BanSearchResults } from './Elements/BanSearchResults';
|
||||||
|
import { SearchSection } from './Elements/SearchSection';
|
||||||
|
import type { Data } from './types';
|
||||||
|
|
||||||
|
export const BanPanel = (props) => {
|
||||||
|
const { act, data } = useBackend<Data>();
|
||||||
|
const {
|
||||||
|
player_ckey,
|
||||||
|
admin_ckey,
|
||||||
|
player_ip,
|
||||||
|
player_cid,
|
||||||
|
bantype,
|
||||||
|
min_search,
|
||||||
|
possible_jobs,
|
||||||
|
database_records,
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Window width={1200} height={800} theme="admin">
|
||||||
|
<Window.Content>
|
||||||
|
<Stack vertical fill>
|
||||||
|
<Stack.Item basis="30%">
|
||||||
|
<BanningSection possibleJobs={possible_jobs} />
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<SearchSection
|
||||||
|
searchedCkey={player_ckey || ''}
|
||||||
|
searchedAdminCkey={admin_ckey || ''}
|
||||||
|
searchedIp={player_ip || ''}
|
||||||
|
searchedCid={player_cid || ''}
|
||||||
|
searchedBanType={bantype || ''}
|
||||||
|
minimumMatch={!!min_search}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item grow>
|
||||||
|
<BanSearchResults database_records={database_records} />
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Window.Content>
|
||||||
|
</Window>
|
||||||
|
);
|
||||||
|
};
|
||||||
25
tgui/packages/tgui/interfaces/BanPanel/types.ts
Normal file
25
tgui/packages/tgui/interfaces/BanPanel/types.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import type { BooleanLike } from 'tgui-core/react';
|
||||||
|
|
||||||
|
export type Data = {
|
||||||
|
player_ckey: string | null;
|
||||||
|
admin_ckey: string | null;
|
||||||
|
player_ip: string | null;
|
||||||
|
player_cid: string | null;
|
||||||
|
bantype: string | null;
|
||||||
|
possible_jobs: string[];
|
||||||
|
database_records: DatabaseRecord[] | null;
|
||||||
|
|
||||||
|
min_search: BooleanLike;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DropdownEntry = {
|
||||||
|
displayText: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This list is of the format: banid, bantime, bantype, reason, job, duration, expiration,
|
||||||
|
// ckey, ackey, unbanned, unbanckey, unbantime, edits, ip, cid
|
||||||
|
export type DatabaseRecord = {
|
||||||
|
data_list: string[];
|
||||||
|
auto: BooleanLike;
|
||||||
|
};
|
||||||
@@ -1,12 +1,22 @@
|
|||||||
import { useBackend } from 'tgui/backend';
|
import { useBackend } from 'tgui/backend';
|
||||||
import { Window } from 'tgui/layouts';
|
import { Window } from 'tgui/layouts';
|
||||||
import { Box, Button, Divider, Section, Table } from 'tgui-core/components';
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Input,
|
||||||
|
LabeledList,
|
||||||
|
NoticeBox,
|
||||||
|
Section,
|
||||||
|
Stack,
|
||||||
|
Table,
|
||||||
|
} from 'tgui-core/components';
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
device_theme: string;
|
device_theme?: string;
|
||||||
age: string;
|
age?: string;
|
||||||
ckey: string;
|
ckey?: string;
|
||||||
entries: { author: string; date: string; comment: string }[];
|
entries?: { author: string; date: string; comment: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PlayerNotesInfo = (props) => {
|
export const PlayerNotesInfo = (props) => {
|
||||||
@@ -19,21 +29,49 @@ export const PlayerNotesInfo = (props) => {
|
|||||||
width={400}
|
width={400}
|
||||||
height={500}
|
height={500}
|
||||||
>
|
>
|
||||||
<Window.Content scrollable>
|
<Window.Content>
|
||||||
<Section title={`Player age: ${age}`}>
|
<Stack vertical fill>
|
||||||
|
{!entries && (
|
||||||
|
<Stack.Item>
|
||||||
|
<NoticeBox danger>Warning! Check your input!</NoticeBox>
|
||||||
|
</Stack.Item>
|
||||||
|
)}
|
||||||
|
<Stack.Item align="center">
|
||||||
|
<LabeledList>
|
||||||
|
<LabeledList.Item label="Ckey">
|
||||||
|
<Input
|
||||||
|
value={ckey}
|
||||||
|
fluid
|
||||||
|
onBlur={(value) => act('cahngekey', { ckey: value })}
|
||||||
|
/>
|
||||||
|
</LabeledList.Item>
|
||||||
|
</LabeledList>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item grow>
|
||||||
|
<Section fill title={`Player age: ${age}`}>
|
||||||
|
<Stack vertical fill>
|
||||||
|
<Stack.Item>
|
||||||
|
This ckey has {entries?.length} comments.
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item grow>
|
||||||
|
<Section fill scrollable>
|
||||||
<Table>
|
<Table>
|
||||||
This ckey has {entries.length} comments.
|
{entries?.map((entry, index) => (
|
||||||
{entries.map((entry, index) => (
|
|
||||||
<Table.Row key={entry.comment}>
|
<Table.Row key={entry.comment}>
|
||||||
<Table.Cell collapsing={false}>
|
<Table.Cell collapsing={false}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Box>
|
<Stack vertical>
|
||||||
Written by {entry.author} on{' '}
|
<Stack.Item>
|
||||||
<span color="blue">{entry.date}</span>
|
{`Written by ${entry.author} on `}
|
||||||
<br />
|
<Box inline color="blue">
|
||||||
<span color="green">"{entry.comment}"</span>
|
{entry.date}
|
||||||
</Box>
|
</Box>
|
||||||
<Button
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<Box color="red">{`"${entry.comment}"`}</Box>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Item>
|
||||||
|
<Button.Confirm
|
||||||
icon="trash"
|
icon="trash"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
act('remove_player_info', {
|
act('remove_player_info', {
|
||||||
@@ -43,13 +81,19 @@ export const PlayerNotesInfo = (props) => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
Remove
|
Remove
|
||||||
</Button>
|
</Button.Confirm>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
))}
|
))}
|
||||||
</Table>
|
</Table>
|
||||||
</Section>
|
</Section>
|
||||||
|
</Stack.Item>
|
||||||
|
<Stack.Divider />
|
||||||
|
<Stack.Item>
|
||||||
<Button
|
<Button
|
||||||
|
fluid
|
||||||
icon="comment"
|
icon="comment"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
act('add_player_info', {
|
act('add_player_info', {
|
||||||
@@ -59,6 +103,11 @@ export const PlayerNotesInfo = (props) => {
|
|||||||
>
|
>
|
||||||
Add Comment
|
Add Comment
|
||||||
</Button>
|
</Button>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
</Section>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
</Window.Content>
|
</Window.Content>
|
||||||
</Window>
|
</Window>
|
||||||
);
|
);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,11 +7,7 @@ export const GetAddons = (addons: string[]) => {
|
|||||||
|
|
||||||
addons?.forEach((addon) => {
|
addons?.forEach((addon) => {
|
||||||
result.push(
|
result.push(
|
||||||
'<span class="badge text-bg-secondary"><i class="' +
|
`<span class="badge text-bg-secondary"><i class="${AddonIcon[addon]}"></i>${addon}</span>`,
|
||||||
AddonIcon[addon] +
|
|
||||||
'"></i>' +
|
|
||||||
addon +
|
|
||||||
'</span>',
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,11 +23,7 @@ export const GetLiquidAddons = (addons: string[]) => {
|
|||||||
|
|
||||||
addons?.forEach((addon) => {
|
addons?.forEach((addon) => {
|
||||||
result.push(
|
result.push(
|
||||||
'<span class="badge text-bg-secondary"><i class="' +
|
`<span class="badge text-bg-secondary"><i class="${ReagentAddonIcon[addon]}"></i>${addon}</span>`,
|
||||||
ReagentAddonIcon[addon] +
|
|
||||||
'"></i>' +
|
|
||||||
addon +
|
|
||||||
'</span>',
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,11 +42,7 @@ export const GetAutotransferFlags = (
|
|||||||
|
|
||||||
addons?.forEach((addon) => {
|
addons?.forEach((addon) => {
|
||||||
result.push(
|
result.push(
|
||||||
'<span class="badge text-bg-secondary"><i class="' +
|
`<span class="badge text-bg-secondary"><i class="${AutotransferFlagIcon[addon]}"></i>${addon}</span>`,
|
||||||
AutotransferFlagIcon[addon] +
|
|
||||||
'"></i>' +
|
|
||||||
addon +
|
|
||||||
'</span>',
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,25 +18,12 @@ export const generateSoulcatcherString = (soulcatcher: Soulcatcher) => {
|
|||||||
const index = 'sc_1';
|
const index = 'sc_1';
|
||||||
|
|
||||||
let result = '';
|
let result = '';
|
||||||
result +=
|
result += `<div class="accordion-item"><h2 class="accordion-header" id="heading${index}">`;
|
||||||
'<div class="accordion-item"><h2 class="accordion-header" id="heading' +
|
result += `<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse${index}" aria-expanded="false" aria-controls="collapse${index}">`;
|
||||||
index +
|
|
||||||
'">';
|
|
||||||
result +=
|
|
||||||
'<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse' +
|
|
||||||
index +
|
|
||||||
'" aria-expanded="false" aria-controls="collapse' +
|
|
||||||
index +
|
|
||||||
'">';
|
|
||||||
result += `${name} (Soulcatcher)`;
|
result += `${name} (Soulcatcher)`;
|
||||||
result += '</button></h2>';
|
result += '</button></h2>';
|
||||||
|
|
||||||
result +=
|
result += `<div id="collapse${index}" class="accordion-collapse collapse" aria-labelledby="heading${index}" data-bs-parent="#accordionBellies">`;
|
||||||
'<div id="collapse' +
|
|
||||||
index +
|
|
||||||
'" class="accordion-collapse collapse" aria-labelledby="heading' +
|
|
||||||
index +
|
|
||||||
'" data-bs-parent="#accordionBellies">';
|
|
||||||
result += '<div class="accordion-body">';
|
result += '<div class="accordion-body">';
|
||||||
|
|
||||||
result += '<b>== Settings ==</b><br>';
|
result += '<b>== Settings ==</b><br>';
|
||||||
@@ -48,15 +35,9 @@ export const generateSoulcatcherString = (soulcatcher: Soulcatcher) => {
|
|||||||
}
|
}
|
||||||
for (const flag in SoulcatcherSettingsFlag) {
|
for (const flag in SoulcatcherSettingsFlag) {
|
||||||
if (arr.includes(flag)) {
|
if (arr.includes(flag)) {
|
||||||
result +=
|
result += `<span class="badge text-bg-success">${SoulcatcherSettingsFlag[flag]}</span>`;
|
||||||
'<span class="badge text-bg-success">' +
|
|
||||||
SoulcatcherSettingsFlag[flag] +
|
|
||||||
'</span>';
|
|
||||||
} else {
|
} else {
|
||||||
result +=
|
result += `<span class="badge text-bg-danger">${SoulcatcherSettingsFlag[flag]}</span>`;
|
||||||
'<span class="badge text-bg-danger">' +
|
|
||||||
SoulcatcherSettingsFlag[flag] +
|
|
||||||
'</span>';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2065,6 +2065,7 @@
|
|||||||
#include "code\modules\admin\topic.dm"
|
#include "code\modules\admin\topic.dm"
|
||||||
#include "code\modules\admin\ToRban.dm"
|
#include "code\modules\admin\ToRban.dm"
|
||||||
#include "code\modules\admin\callproc\callproc.dm"
|
#include "code\modules\admin\callproc\callproc.dm"
|
||||||
|
#include "code\modules\admin\DB ban\ban_panle_ui.dm"
|
||||||
#include "code\modules\admin\DB ban\functions.dm"
|
#include "code\modules\admin\DB ban\functions.dm"
|
||||||
#include "code\modules\admin\verb_datums\_admin_verb_datum.dm"
|
#include "code\modules\admin\verb_datums\_admin_verb_datum.dm"
|
||||||
#include "code\modules\admin\verbs\admin_ch.dm"
|
#include "code\modules\admin\verbs\admin_ch.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user