mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-27 05:57:24 +01:00
Merge pull request #14422 from dearmochi/tgui-security-records
[TGUI] Security Records
This commit is contained in:
@@ -97,3 +97,4 @@
|
||||
#define LOGIN_TYPE_NORMAL 1
|
||||
#define LOGIN_TYPE_AI 2
|
||||
#define LOGIN_TYPE_ROBOT 3
|
||||
#define LOGIN_TYPE_ADMIN 4
|
||||
|
||||
+12
-11
@@ -238,36 +238,37 @@
|
||||
if(70 to INFINITY) return "elderly"
|
||||
else return "unknown"
|
||||
|
||||
/proc/set_criminal_status(mob/living/user, datum/data/record/target_records , criminal_status, comment, user_rank, list/authcard_access = list())
|
||||
/proc/set_criminal_status(mob/living/user, datum/data/record/target_records , criminal_status, comment, user_rank, list/authcard_access = list(), user_name)
|
||||
var/status = criminal_status
|
||||
var/their_name = target_records.fields["name"]
|
||||
var/their_rank = target_records.fields["rank"]
|
||||
switch(criminal_status)
|
||||
if("arrest")
|
||||
if("arrest", SEC_RECORD_STATUS_ARREST)
|
||||
status = SEC_RECORD_STATUS_ARREST
|
||||
if("none")
|
||||
if("none", SEC_RECORD_STATUS_NONE)
|
||||
status = SEC_RECORD_STATUS_NONE
|
||||
if("execute")
|
||||
if("execute", SEC_RECORD_STATUS_EXECUTE)
|
||||
if((ACCESS_MAGISTRATE in authcard_access) || (ACCESS_ARMORY in authcard_access))
|
||||
status = SEC_RECORD_STATUS_EXECUTE
|
||||
message_admins("[ADMIN_FULLMONTY(usr)] authorized <span class='warning'>EXECUTION</span> for [their_rank] [their_name], with comment: [comment]")
|
||||
else
|
||||
return 0
|
||||
if("search")
|
||||
if("search", SEC_RECORD_STATUS_SEARCH)
|
||||
status = SEC_RECORD_STATUS_SEARCH
|
||||
if("monitor")
|
||||
if("monitor", SEC_RECORD_STATUS_MONITOR)
|
||||
status = SEC_RECORD_STATUS_MONITOR
|
||||
if ("demote")
|
||||
if("demote", SEC_RECORD_STATUS_DEMOTE)
|
||||
message_admins("[ADMIN_FULLMONTY(usr)] set criminal status to <span class='warning'>DEMOTE</span> for [their_rank] [their_name], with comment: [comment]")
|
||||
status = SEC_RECORD_STATUS_DEMOTE
|
||||
if("incarcerated")
|
||||
if("incarcerated", SEC_RECORD_STATUS_INCARCERATED)
|
||||
status = SEC_RECORD_STATUS_INCARCERATED
|
||||
if("parolled")
|
||||
if("parolled", SEC_RECORD_STATUS_PAROLLED)
|
||||
status = SEC_RECORD_STATUS_PAROLLED
|
||||
if("released")
|
||||
if("released", SEC_RECORD_STATUS_RELEASED)
|
||||
status = SEC_RECORD_STATUS_RELEASED
|
||||
target_records.fields["criminal"] = status
|
||||
log_admin("[key_name_admin(user)] set secstatus of [their_rank] [their_name] to [status], comment: [comment]")
|
||||
target_records.fields["comments"] += "Set to [status] by [user.name] ([user_rank]) on [GLOB.current_date_string] [station_time_timestamp()], comment: [comment]"
|
||||
target_records.fields["comments"] += "Set to [status] by [user_name || user.name] ([user_rank]) on [GLOB.current_date_string] [station_time_timestamp()], comment: [comment]"
|
||||
update_all_mob_security_hud()
|
||||
return 1
|
||||
|
||||
|
||||
@@ -278,8 +278,8 @@ GLOBAL_VAR_INIT(record_id_num, 1001)
|
||||
G.fields["sex"] = capitalize(H.gender)
|
||||
G.fields["species"] = H.dna.species.name
|
||||
G.fields["photo"] = get_id_photo(H)
|
||||
G.fields["photo-south"] = "'data:image/png;base64,[icon2base64(icon(G.fields["photo"], dir = SOUTH))]'"
|
||||
G.fields["photo-west"] = "'data:image/png;base64,[icon2base64(icon(G.fields["photo"], dir = WEST))]'"
|
||||
G.fields["photo-south"] = "data:image/png;base64,[icon2base64(icon(G.fields["photo"], dir = SOUTH))]"
|
||||
G.fields["photo-west"] = "data:image/png;base64,[icon2base64(icon(G.fields["photo"], dir = WEST))]"
|
||||
if(H.gen_record && !jobban_isbanned(H, "Records"))
|
||||
G.fields["notes"] = H.gen_record
|
||||
else
|
||||
@@ -319,7 +319,7 @@ GLOBAL_VAR_INIT(record_id_num, 1001)
|
||||
if(H.sec_record && !jobban_isbanned(H, "Records"))
|
||||
S.fields["notes"] = H.sec_record
|
||||
else
|
||||
S.fields["notes"] = "No notes."
|
||||
S.fields["notes"] = "No notes found."
|
||||
LAZYINITLIST(S.fields["comments"])
|
||||
security += S
|
||||
|
||||
|
||||
@@ -2,43 +2,67 @@
|
||||
#define SEC_DATA_MAINT 2 // Records maintenance
|
||||
#define SEC_DATA_RECORD 3 // Record
|
||||
|
||||
/obj/machinery/computer/secure_data//TODO:SANITY
|
||||
#define SEC_FIELD(N, V, E, LB) list(field = N, value = V, edit = E, line_break = LB)
|
||||
|
||||
/obj/machinery/computer/secure_data
|
||||
name = "security records"
|
||||
desc = "Used to view and edit personnel's security records."
|
||||
icon_keyboard = "security_key"
|
||||
icon_screen = "security"
|
||||
req_one_access = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS)
|
||||
circuit = /obj/item/circuitboard/secure_data
|
||||
var/obj/item/card/id/scan = null
|
||||
var/authenticated = null
|
||||
var/rank = null
|
||||
var/list/authcard_access = list()
|
||||
var/screen = null
|
||||
var/datum/data/record/active1 = null
|
||||
var/datum/data/record/active2 = null
|
||||
var/temp = null
|
||||
var/printing = null
|
||||
//Sorting Variables
|
||||
var/sortBy = "name"
|
||||
var/order = 1 // -1 = Descending - 1 = Ascending
|
||||
/// The current page being viewed.
|
||||
var/current_page = SEC_DATA_R_LIST
|
||||
/// The current general record being viewed.
|
||||
var/datum/data/record/record_general = null
|
||||
/// The current security record being viewed.
|
||||
var/datum/data/record/record_security = null
|
||||
/// Whether the computer is currently printing a paper or not.
|
||||
var/is_printing = FALSE
|
||||
/// The editable fields and their associated question to display to the user.
|
||||
var/static/list/field_edit_questions
|
||||
/// The editable fields and their associated choices to display to the user.
|
||||
var/static/list/field_edit_choices
|
||||
/// The current temporary notice.
|
||||
var/temp_notice
|
||||
|
||||
light_color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/machinery/computer/secure_data/Initialize(mapload)
|
||||
. = ..()
|
||||
req_one_access = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS)
|
||||
if(!field_edit_questions)
|
||||
field_edit_questions = list(
|
||||
// General
|
||||
"name" = "Please input new name:",
|
||||
"id" = "Please input new ID:",
|
||||
"sex" = "Please select new sex:",
|
||||
"age" = "Please input new age:",
|
||||
"fingerprint" = "Please input new fingerprint hash:",
|
||||
// Security
|
||||
"criminal" = "Please select new criminal status:",
|
||||
"mi_crim" = "Please input new minor crimes:",
|
||||
"mi_crim_d" = "Please summarize minor crimes:",
|
||||
"ma_crim" = "Please input new major crimes:",
|
||||
"ma_crim_d" = "Please summarize major crimes:",
|
||||
"notes" = "Please input new important notes:",
|
||||
)
|
||||
field_edit_choices = list(
|
||||
// General
|
||||
"sex" = list("Male", "Female"),
|
||||
// Security
|
||||
"criminal" = list(SEC_RECORD_STATUS_NONE, SEC_RECORD_STATUS_ARREST, SEC_RECORD_STATUS_EXECUTE, SEC_RECORD_STATUS_INCARCERATED, SEC_RECORD_STATUS_RELEASED, SEC_RECORD_STATUS_PAROLLED, SEC_RECORD_STATUS_DEMOTE, SEC_RECORD_STATUS_SEARCH, SEC_RECORD_STATUS_MONITOR),
|
||||
)
|
||||
|
||||
/obj/machinery/computer/secure_data/Destroy()
|
||||
active1 = null
|
||||
active2 = null
|
||||
record_general = null
|
||||
record_security = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/secure_data/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/card/id) && !scan)
|
||||
user.drop_item()
|
||||
O.forceMove(src)
|
||||
scan = O
|
||||
ui_interact(user)
|
||||
if(tgui_login_attackby(O, user))
|
||||
return
|
||||
return ..()
|
||||
|
||||
//Someone needs to break down the dat += into chunks instead of long ass lines.
|
||||
/obj/machinery/computer/secure_data/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
@@ -46,267 +70,124 @@
|
||||
to_chat(user, "<span class='danger'>Unable to establish a connection</span>: You're too far away from the station!")
|
||||
return
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/secure_data/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/computer/secure_data/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "secure_data.tmpl", name, 800, 800)
|
||||
ui = new(user, src, ui_key, "SecurityRecords", name, 800, 800)
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE)
|
||||
|
||||
/obj/machinery/computer/secure_data/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
data["temp"] = temp
|
||||
data["scan"] = scan ? scan.name : null
|
||||
data["authenticated"] = authenticated
|
||||
data["screen"] = screen
|
||||
if(authenticated)
|
||||
switch(screen)
|
||||
/obj/machinery/computer/secure_data/tgui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/list/data = list()
|
||||
data["currentPage"] = current_page
|
||||
data["isPrinting"] = is_printing
|
||||
tgui_login_data(data, user)
|
||||
data["modal"] = tgui_modal_data()
|
||||
data["temp"] = temp_notice
|
||||
if(data["loginState"]["logged_in"])
|
||||
switch(current_page)
|
||||
if(SEC_DATA_R_LIST)
|
||||
if(!isnull(GLOB.data_core.general))
|
||||
for(var/datum/data/record/R in sortRecord(GLOB.data_core.general, sortBy, order))
|
||||
var/crimstat = "null"
|
||||
for(var/datum/data/record/E in GLOB.data_core.security)
|
||||
if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])
|
||||
crimstat = E.fields["criminal"]
|
||||
break
|
||||
var/background = "''"
|
||||
switch(crimstat)
|
||||
if(SEC_RECORD_STATUS_EXECUTE)
|
||||
background = "'background-color:#5E0A1A'"
|
||||
if(SEC_RECORD_STATUS_ARREST)
|
||||
background = "'background-color:#890E26'"
|
||||
if(SEC_RECORD_STATUS_SEARCH)
|
||||
background = "'background-color:#999900'"
|
||||
if(SEC_RECORD_STATUS_MONITOR)
|
||||
background = "'background-color:#004C99'"
|
||||
if(SEC_RECORD_STATUS_DEMOTE)
|
||||
background = "'background-color:#C2A111'"
|
||||
if(SEC_RECORD_STATUS_INCARCERATED)
|
||||
background = "'background-color:#743B03'"
|
||||
if(SEC_RECORD_STATUS_PAROLLED)
|
||||
background = "'background-color:#743B03'"
|
||||
if(SEC_RECORD_STATUS_RELEASED)
|
||||
background = "'background-color:#216489'"
|
||||
if(SEC_RECORD_STATUS_NONE)
|
||||
background = "'background-color:#007f47'"
|
||||
if("null")
|
||||
crimstat = "No record."
|
||||
data["records"] += list(list("ref" = "\ref[R]", "id" = R.fields["id"], "name" = R.fields["name"], "rank" = R.fields["rank"], "fingerprint" = R.fields["fingerprint"], "background" = background, "crimstat" = crimstat))
|
||||
// Prepare the list of security records to associate with the general ones.
|
||||
// This is not ideal but datacore code sucks and needs to be rewritten.
|
||||
var/list/sec_records_assoc = list()
|
||||
for(var/datum/data/record/S in GLOB.data_core.security)
|
||||
sec_records_assoc["[S.fields["name"]]|[S.fields["id"]]"] = S
|
||||
// List the general records
|
||||
var/list/records = list()
|
||||
data["records"] = records
|
||||
for(var/datum/data/record/G in GLOB.data_core.general)
|
||||
var/datum/data/record/S = sec_records_assoc["[G.fields["name"]]|[G.fields["id"]]"]
|
||||
var/list/record_line = list("uid_gen" = G.UID(), "id" = G.fields["id"], "name" = G.fields["name"], "rank" = G.fields["rank"], "fingerprint" = G.fields["fingerprint"])
|
||||
record_line["status"] = S?.fields["criminal"] || "No record"
|
||||
record_line["uid_sec"] = S?.UID() // So we don't have to perform the search through a for loop again later
|
||||
records[++records.len] = record_line
|
||||
if(SEC_DATA_RECORD)
|
||||
var/list/general = list()
|
||||
data["general"] = general
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
var/list/fields = list()
|
||||
general["fields"] = fields
|
||||
fields[++fields.len] = list("field" = "Name:", "value" = active1.fields["name"], "edit" = "name")
|
||||
fields[++fields.len] = list("field" = "ID:", "value" = active1.fields["id"], "edit" = "id")
|
||||
fields[++fields.len] = list("field" = "Sex:", "value" = active1.fields["sex"], "edit" = "sex")
|
||||
fields[++fields.len] = list("field" = "Age:", "value" = active1.fields["age"], "edit" = "age")
|
||||
fields[++fields.len] = list("field" = "Rank:", "value" = active1.fields["rank"], "edit" = "rank")
|
||||
fields[++fields.len] = list("field" = "Fingerprint:", "value" = active1.fields["fingerprint"], "edit" = "fingerprint")
|
||||
fields[++fields.len] = list("field" = "Physical Status:", "value" = active1.fields["p_stat"], "edit" = null)
|
||||
fields[++fields.len] = list("field" = "Mental Status:", "value" = active1.fields["m_stat"], "edit" = null)
|
||||
var/list/photos = list()
|
||||
general["photos"] = photos
|
||||
photos[++photos.len] = list("photo" = active1.fields["photo-south"])
|
||||
photos[++photos.len] = list("photo" = active1.fields["photo-west"])
|
||||
general["has_photos"] += (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0)
|
||||
general["empty"] = 0
|
||||
if(record_general && GLOB.data_core.general.Find(record_general))
|
||||
var/list/gen_fields = record_general.fields
|
||||
general["fields"] = list(
|
||||
SEC_FIELD("Name", gen_fields["name"], "name", FALSE),
|
||||
SEC_FIELD("ID", gen_fields["id"], "id", TRUE),
|
||||
SEC_FIELD("Sex", gen_fields["sex"], "sex", FALSE),
|
||||
SEC_FIELD("Age", gen_fields["age"], "age", TRUE),
|
||||
SEC_FIELD("Assignment", gen_fields["rank"], null, FALSE),
|
||||
SEC_FIELD("Fingerprint", gen_fields["fingerprint"], "fingerprint", TRUE),
|
||||
SEC_FIELD("Physical Status", gen_fields["p_stat"], null, FALSE),
|
||||
SEC_FIELD("Mental Status", gen_fields["m_stat"], null, TRUE),
|
||||
SEC_FIELD("Important Notes", gen_fields["notes"], null, FALSE),
|
||||
)
|
||||
general["photos"] = list(
|
||||
gen_fields["photo-south"],
|
||||
gen_fields["photo-west"],
|
||||
)
|
||||
general["has_photos"] = (gen_fields["photo-south"] || gen_fields["photo-west"]) ? TRUE : FALSE
|
||||
general["empty"] = FALSE
|
||||
else
|
||||
general["empty"] = 1
|
||||
general["empty"] = TRUE
|
||||
|
||||
var/list/security = list()
|
||||
data["security"] = security
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.security.Find(active2))
|
||||
var/list/fields = list()
|
||||
security["fields"] = fields
|
||||
fields[++fields.len] = list("field" = "Criminal Status:", "value" = active2.fields["criminal"], "edit" = "criminal", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Minor Crimes:", "value" = active2.fields["mi_crim"], "edit" = "mi_crim", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["mi_crim_d"], "edit" = "mi_crim_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Major Crimes:", "value" = active2.fields["ma_crim"], "edit" = "ma_crim", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["ma_crim_d"], "edit" = "ma_crim_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Important Notes:", "value" = active2.fields["notes"], "edit" = "notes", "line_break" = 0)
|
||||
if(!active2.fields["comments"] || !islist(active2.fields["comments"]))
|
||||
active2.fields["comments"] = list()
|
||||
security["comments"] = active2.fields["comments"]
|
||||
security["empty"] = 0
|
||||
if(record_security && GLOB.data_core.security.Find(record_security))
|
||||
var/list/sec_fields = record_security.fields
|
||||
security["fields"] = list(
|
||||
SEC_FIELD("Criminal Status", sec_fields["criminal"], "criminal", TRUE),
|
||||
SEC_FIELD("Minor Crimes", sec_fields["mi_crim"], "mi_crim", FALSE),
|
||||
SEC_FIELD("Details", sec_fields["mi_crim_d"], "mi_crim_d", TRUE),
|
||||
SEC_FIELD("Major Crimes", sec_fields["ma_crim"], "ma_crim", FALSE),
|
||||
SEC_FIELD("Details", sec_fields["ma_crim_d"], "ma_crim_d", TRUE),
|
||||
SEC_FIELD("Important Notes", sec_fields["notes"], null, FALSE),
|
||||
)
|
||||
if(!islist(sec_fields["comments"]))
|
||||
sec_fields["comments"] = list()
|
||||
security["comments"] = sec_fields["comments"]
|
||||
security["empty"] = FALSE
|
||||
else
|
||||
security["empty"] = 1
|
||||
security["empty"] = TRUE
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/secure_data/Topic(href, href_list)
|
||||
/obj/machinery/computer/secure_data/tgui_act(action, list/params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(!GLOB.data_core.general.Find(active1))
|
||||
active1 = null
|
||||
if(!GLOB.data_core.security.Find(active2))
|
||||
active2 = null
|
||||
. = TRUE
|
||||
if(tgui_act_modal(action, params))
|
||||
return
|
||||
if(tgui_login_act(action, params))
|
||||
return
|
||||
|
||||
if(href_list["temp"])
|
||||
temp = null
|
||||
|
||||
if(href_list["temp_action"])
|
||||
var/temp_href = splittext(href_list["temp_action"], "=")
|
||||
switch(temp_href[1])
|
||||
if("del_all2")
|
||||
for(var/datum/data/record/R in GLOB.data_core.security)
|
||||
qdel(R)
|
||||
update_all_mob_security_hud()
|
||||
setTemp("<h3>All records deleted.</h3>")
|
||||
if("del_alllogs2")
|
||||
if(GLOB.cell_logs.len)
|
||||
setTemp("<h3>All cell logs deleted.</h3>")
|
||||
GLOB.cell_logs.Cut()
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Error; No cell logs to delete.</span>")
|
||||
if("del_r2")
|
||||
if(active2)
|
||||
qdel(active2)
|
||||
update_all_mob_security_hud()
|
||||
if("del_rg2")
|
||||
if(active1)
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
if(R.fields["name"] == active1.fields["name"] && R.fields["id"] == active1.fields["id"])
|
||||
qdel(R)
|
||||
QDEL_NULL(active1)
|
||||
QDEL_NULL(active2)
|
||||
update_all_mob_security_hud()
|
||||
screen = SEC_DATA_R_LIST
|
||||
if("criminal")
|
||||
if(active2)
|
||||
var/t1
|
||||
if(temp_href[2] == "execute")
|
||||
t1 = copytext(trim(sanitize(input("Explain why they are being executed. Include a list of their crimes, and victims.", "EXECUTION ORDER", null, null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
else
|
||||
t1 = copytext(trim(sanitize(input("Enter Reason:", "Secure. records", null, null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1)
|
||||
t1 = "(none)"
|
||||
if(!set_criminal_status(usr, active2, temp_href[2], t1, rank, authcard_access))
|
||||
setTemp("<h3 class='bad'>Error: permission denied.</h3>")
|
||||
return 1
|
||||
if("rank")
|
||||
if(active1)
|
||||
active1.fields["rank"] = temp_href[2]
|
||||
if(temp_href[2] in GLOB.joblist)
|
||||
active1.fields["real_rank"] = temp_href[2]
|
||||
|
||||
if(href_list["scan"])
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
scan = I
|
||||
|
||||
if(href_list["login"])
|
||||
if(isAI(usr))
|
||||
authenticated = usr.name
|
||||
rank = "AI"
|
||||
else if(isrobot(usr))
|
||||
authenticated = usr.name
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
rank = "[R.modtype] [R.braintype]"
|
||||
else if(istype(scan, /obj/item/card/id))
|
||||
if(check_access(scan))
|
||||
authenticated = scan.registered_name
|
||||
rank = scan.assignment
|
||||
authcard_access = scan.access
|
||||
|
||||
if(authenticated)
|
||||
active1 = null
|
||||
active2 = null
|
||||
screen = SEC_DATA_R_LIST
|
||||
|
||||
if(authenticated)
|
||||
if(href_list["logout"])
|
||||
authenticated = null
|
||||
screen = null
|
||||
active1 = null
|
||||
active2 = null
|
||||
authcard_access = list()
|
||||
|
||||
else if(href_list["sort"])
|
||||
// Reverse the order if clicked twice
|
||||
if(sortBy == href_list["sort"])
|
||||
if(order == 1)
|
||||
order = -1
|
||||
else
|
||||
order = 1
|
||||
else
|
||||
sortBy = href_list["sort"]
|
||||
order = initial(order)
|
||||
|
||||
else if(href_list["screen"])
|
||||
screen = text2num(href_list["screen"])
|
||||
if(screen < 1)
|
||||
screen = SEC_DATA_R_LIST
|
||||
|
||||
active1 = null
|
||||
active2 = null
|
||||
|
||||
else if(href_list["d_rec"])
|
||||
var/datum/data/record/R = locate(href_list["d_rec"])
|
||||
var/datum/data/record/M = locate(href_list["d_rec"])
|
||||
if(!GLOB.data_core.general.Find(R))
|
||||
setTemp("<h3 class='bad'>Record not found!</h3>")
|
||||
return 1
|
||||
for(var/datum/data/record/E in GLOB.data_core.security)
|
||||
if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])
|
||||
M = E
|
||||
active1 = R
|
||||
active2 = M
|
||||
screen = SEC_DATA_RECORD
|
||||
|
||||
else if(href_list["del_all"])
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_all2=1", "status" = null)
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete all records?</h3>", buttons)
|
||||
|
||||
else if(href_list["del_alllogs"])
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_alllogs2=1", "status" = null)
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete all cell logs?</h3>", buttons)
|
||||
|
||||
else if(href_list["del_rg"])
|
||||
if(active1)
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_rg2=1", "status" = null)
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete the record (ALL)?</h3>", buttons)
|
||||
|
||||
else if(href_list["del_r"])
|
||||
if(active1)
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_r2=1", "status" = null)
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete the record (Security Portion Only)?</h3>", buttons)
|
||||
|
||||
else if(href_list["new_s"])
|
||||
if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record))
|
||||
var/datum/data/record/R = new /datum/data/record()
|
||||
R.fields["name"] = active1.fields["name"]
|
||||
R.fields["id"] = active1.fields["id"]
|
||||
R.name = "Security Record #[R.fields["id"]]"
|
||||
R.fields["criminal"] = "None"
|
||||
R.fields["mi_crim"] = "None"
|
||||
R.fields["mi_crim_d"] = "No minor crime convictions."
|
||||
R.fields["ma_crim"] = "None"
|
||||
R.fields["ma_crim_d"] = "No major crime convictions."
|
||||
R.fields["notes"] = "No notes."
|
||||
GLOB.data_core.security += R
|
||||
active2 = R
|
||||
screen = SEC_DATA_RECORD
|
||||
|
||||
else if(href_list["new_g"])
|
||||
var/logged_in = tgui_login_get().logged_in
|
||||
switch(action)
|
||||
if("cleartemp")
|
||||
temp_notice = null
|
||||
if("page") // Select Page
|
||||
if(!logged_in)
|
||||
return
|
||||
var/page_num = clamp(text2num(params["page"]), SEC_DATA_R_LIST, SEC_DATA_MAINT) // SEC_DATA_RECORD cannot be accessed through this act
|
||||
current_page = page_num
|
||||
record_general = null
|
||||
record_security = null
|
||||
if("view") // View Record
|
||||
if(!logged_in)
|
||||
return
|
||||
var/datum/data/record/G = locateUID(params["uid_gen"])
|
||||
var/datum/data/record/S = locateUID(params["uid_sec"])
|
||||
if(!istype(G)) // No general record!
|
||||
set_temp("General record not found!", "danger")
|
||||
return
|
||||
if(istype(S) && !(G.fields["name"] == S.fields["name"] && G.fields["id"] == S.fields["id"])) // General and security records don't match!
|
||||
S = null
|
||||
record_general = G
|
||||
record_security = S
|
||||
current_page = SEC_DATA_RECORD
|
||||
if("new_general") // New General Record
|
||||
if(!logged_in)
|
||||
return
|
||||
if(record_general)
|
||||
return
|
||||
var/datum/data/record/G = new /datum/data/record()
|
||||
G.fields["name"] = "New Record"
|
||||
G.fields["id"] = "[add_zero(num2hex(rand(1, 1.6777215E7)), 6)]"
|
||||
@@ -318,229 +199,251 @@
|
||||
G.fields["p_stat"] = "Active"
|
||||
G.fields["m_stat"] = "Stable"
|
||||
G.fields["species"] = "Human"
|
||||
G.fields["notes"] = "No notes."
|
||||
GLOB.data_core.general += G
|
||||
active1 = G
|
||||
active2 = null
|
||||
record_general = G
|
||||
record_security = null
|
||||
current_page = SEC_DATA_RECORD
|
||||
if("new_security") // New Security Record
|
||||
if(!logged_in)
|
||||
return
|
||||
if(!record_general || record_security)
|
||||
return
|
||||
var/datum/data/record/S = new /datum/data/record()
|
||||
S.fields["name"] = record_general.fields["name"]
|
||||
S.fields["id"] = record_general.fields["id"]
|
||||
S.name = "Security Record #[S.fields["id"]]"
|
||||
S.fields["criminal"] = SEC_RECORD_STATUS_NONE
|
||||
S.fields["mi_crim"] = "None"
|
||||
S.fields["mi_crim_d"] = "No minor crime convictions."
|
||||
S.fields["ma_crim"] = "None"
|
||||
S.fields["ma_crim_d"] = "No major crime convictions."
|
||||
S.fields["notes"] = "No notes."
|
||||
GLOB.data_core.security += S
|
||||
record_security = S
|
||||
update_all_mob_security_hud()
|
||||
if("delete_general") // Delete General, Security and Medical Records
|
||||
if(!logged_in)
|
||||
return
|
||||
if(!record_general)
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] has deleted [record_general.fields["name"]]'s general, security and medical records at [ADMIN_COORDJMP(usr)]")
|
||||
usr.create_log(MISC_LOG, "deleted [record_general.fields["name"]]'s general, security and medical records")
|
||||
for(var/datum/data/record/M in GLOB.data_core.medical)
|
||||
if(M.fields["name"] == record_general.fields["name"] && M.fields["id"] == record_general.fields["id"])
|
||||
qdel(M)
|
||||
QDEL_NULL(record_general)
|
||||
QDEL_NULL(record_security)
|
||||
update_all_mob_security_hud()
|
||||
current_page = SEC_DATA_R_LIST
|
||||
set_temp("General, Security and Medical records deleted.")
|
||||
if("delete_security") // Delete Security Record
|
||||
if(!logged_in)
|
||||
return
|
||||
if(!record_security)
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] has deleted [record_security.fields["name"]]'s security record at [ADMIN_COORDJMP(usr)]")
|
||||
usr.create_log(MISC_LOG, "deleted [record_security.fields["name"]]'s security record")
|
||||
QDEL_NULL(record_security)
|
||||
update_all_mob_security_hud()
|
||||
set_temp("Security record deleted.")
|
||||
if("delete_security_all") // Delete All Security Records
|
||||
if(!logged_in)
|
||||
return
|
||||
for(var/datum/data/record/S in GLOB.data_core.security)
|
||||
qdel(S)
|
||||
message_admins("[key_name_admin(usr)] has deleted all security records at [ADMIN_COORDJMP(usr)]")
|
||||
usr.create_log(MISC_LOG, "deleted all security records")
|
||||
update_all_mob_security_hud()
|
||||
set_temp("All security records deleted.")
|
||||
if("delete_cell_logs") // Delete All Cell Logs
|
||||
if(!logged_in)
|
||||
return
|
||||
if(!length(GLOB.cell_logs))
|
||||
set_temp("There are no cell logs to delete.")
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] has deleted all cell logs at [ADMIN_COORDJMP(usr)]")
|
||||
usr.create_log(MISC_LOG, "deleted all cell logs")
|
||||
GLOB.cell_logs.Cut()
|
||||
set_temp("All cell logs deleted.")
|
||||
if("comment_delete") // Delete Comment
|
||||
if(!logged_in)
|
||||
return
|
||||
var/index = text2num(params["id"])
|
||||
if(!index || !record_security)
|
||||
return
|
||||
|
||||
else if(href_list["print_r"])
|
||||
if(!printing)
|
||||
printing = 1
|
||||
playsound(loc, "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1)
|
||||
sleep(50)
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
P.info = "<CENTER><B>Security Record</B></CENTER><BR>"
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]]
|
||||
<BR>\nSex: [active1.fields["sex"]]
|
||||
<BR>\nAge: [active1.fields["age"]]
|
||||
<BR>\nFingerprint: [active1.fields["fingerprint"]]
|
||||
<BR>\nPhysical Status: [active1.fields["p_stat"]]
|
||||
<BR>\nMental Status: [active1.fields["m_stat"]]<BR>"}
|
||||
else
|
||||
P.info += "<B>General Record Lost!</B><BR>"
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.security.Find(active2))
|
||||
P.info += {"<BR>\n<CENTER><B>Security Data</B></CENTER>
|
||||
<BR>\nCriminal Status: [active2.fields["criminal"]]<BR>\n
|
||||
<BR>\nMinor Crimes: [active2.fields["mi_crim"]]
|
||||
<BR>\nDetails: [active2.fields["mi_crim_d"]]<BR>\n
|
||||
<BR>\nMajor Crimes: [active2.fields["ma_crim"]]
|
||||
<BR>\nDetails: [active2.fields["ma_crim_d"]]<BR>\n
|
||||
<BR>\nImportant Notes:
|
||||
<BR>\n\t[active2.fields["notes"]]<BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>"}
|
||||
for(var/c in active2.fields["comments"])
|
||||
P.info += "[c]<BR>"
|
||||
else
|
||||
P.info += "<B>Security Record Lost!</B><BR>"
|
||||
P.info += "</TT>"
|
||||
P.name = "paper - 'Security Record: [active1.fields["name"]]'"
|
||||
printing = 0
|
||||
var/list/comments = record_security.fields["comments"]
|
||||
if(!length(comments))
|
||||
return
|
||||
index = clamp(index, 1, length(comments))
|
||||
comments.Cut(index, index + 1)
|
||||
if("print_record")
|
||||
if(!logged_in)
|
||||
return
|
||||
if(is_printing)
|
||||
return
|
||||
is_printing = TRUE
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
|
||||
addtimer(CALLBACK(src, .proc/print_record_finish), 5 SECONDS)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/* Removed due to BYOND issue
|
||||
else if(href_list["print_p"])
|
||||
if(!printing)
|
||||
printing = 1
|
||||
playsound(loc, "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1)
|
||||
sleep(50)
|
||||
if(istype(active1, /datum/data/record) && data_core.general.Find(active1))
|
||||
create_record_photo(active1)
|
||||
printing = 0
|
||||
*/
|
||||
add_fingerprint(usr)
|
||||
|
||||
else if(href_list["printlogs"])
|
||||
if(GLOB.cell_logs.len && !printing)
|
||||
var/obj/item/paper/P = input(usr, "Select log to print", "Available Cell Logs") as null|anything in GLOB.cell_logs
|
||||
if(!P)
|
||||
return 0
|
||||
printing = 1
|
||||
playsound(loc, "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1)
|
||||
to_chat(usr, "<span class='notice'>Printing file [P.name].</span>")
|
||||
sleep(50)
|
||||
var/obj/item/paper/log = new /obj/item/paper(loc)
|
||||
log.name = P.name
|
||||
log.info = P.info
|
||||
printing = 0
|
||||
return 1
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>[src] has no logs stored or is already printing.</span>")
|
||||
|
||||
|
||||
else if(href_list["add_c"])
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/a2 = active2
|
||||
var/t1 = copytext(trim(sanitize(input("Add Comment:", "Secure. records", null, null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["comments"] += "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]<BR>[t1]"
|
||||
|
||||
else if(href_list["del_c"])
|
||||
var/index = min(max(text2num(href_list["del_c"]) + 1, 1), length(active2.fields["comments"]))
|
||||
if(istype(active2, /datum/data/record) && active2.fields["comments"][index])
|
||||
active2.fields["comments"] -= active2.fields["comments"][index]
|
||||
|
||||
if(href_list["field"])
|
||||
if(..())
|
||||
return 1
|
||||
var/a1 = active1
|
||||
var/a2 = active2
|
||||
switch(href_list["field"])
|
||||
if("name")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = reject_bad_name(clean_input("Please input name:", "Secure. records", active1.fields["name"], null))
|
||||
if(!t1 || !length(trim(t1)) || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["name"] = t1
|
||||
if(istype(active2, /datum/data/record))
|
||||
active2.fields["name"] = t1
|
||||
if("id")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input id:", "Secure. records", active1.fields["id"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["id"] = t1
|
||||
if(istype(active2, /datum/data/record))
|
||||
active2.fields["id"] = t1
|
||||
if("fingerprint")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Secure. records", active1.fields["fingerprint"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["fingerprint"] = t1
|
||||
if("sex")
|
||||
if(istype(active1, /datum/data/record))
|
||||
if(active1.fields["sex"] == "Male")
|
||||
active1.fields["sex"] = "Female"
|
||||
else
|
||||
active1.fields["sex"] = "Male"
|
||||
if("age")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["age"] = t1
|
||||
if("mi_crim")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input minor crimes list:", "Secure. records", active2.fields["mi_crim"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["mi_crim"] = t1
|
||||
if("mi_crim_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize minor crimes:", "Secure. records", active2.fields["mi_crim_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["mi_crim_d"] = t1
|
||||
if("ma_crim")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input major crimes list:", "Secure. records", active2.fields["ma_crim"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["ma_crim"] = t1
|
||||
if("ma_crim_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize major crimes:", "Secure. records", active2.fields["ma_crim_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["ma_crim_d"] = t1
|
||||
if("notes")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(html_encode(trim(input("Please summarize notes:", "Secure. records", html_decode(active2.fields["notes"]), null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["notes"] = t1
|
||||
if("criminal")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "None", "icon" = "unlock", "href" = "criminal=none", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_NONE ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*Arrest*", "icon" = "lock", "href" = "criminal=arrest", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_ARREST ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Search", "icon" = "lock", "href" = "criminal=search", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_SEARCH ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Monitor", "icon" = "unlock", "href" = "criminal=monitor", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_MONITOR ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Demote", "icon" = "lock", "href" = "criminal=demote", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_DEMOTE ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Incarcerated", "icon" = "lock", "href" = "criminal=incarcerated", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_INCARCERATED ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*Execute*", "icon" = "lock", "href" = "criminal=execute", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_EXECUTE ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Parolled", "icon" = "unlock-alt", "href" = "criminal=parolled", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_PAROLLED ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Released", "icon" = "unlock", "href" = "criminal=released", "status" = (active2.fields["criminal"] == SEC_RECORD_STATUS_RELEASED ? "selected" : null))
|
||||
setTemp("<h3>Criminal Status</h3>", buttons)
|
||||
if("rank")
|
||||
var/list/L = list("Head of Personnel", "Captain", "AI")
|
||||
//This was so silly before the change. Now it actually works without beating your head against the keyboard. /N
|
||||
if(istype(active1, /datum/data/record) && L.Find(rank))
|
||||
var/list/buttons = list()
|
||||
for(var/rank in GLOB.joblist)
|
||||
buttons[++buttons.len] = list("name" = rank, "icon" = null, "href" = "rank=[rank]", "status" = (active1.fields["rank"] == rank ? "selected" : null))
|
||||
setTemp("<h3>Rank</h3>", buttons)
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/machinery/computer/secure_data/proc/tgui_act_modal(action, list/params)
|
||||
if(!tgui_login_get().logged_in)
|
||||
return
|
||||
. = TRUE
|
||||
var/id = params["id"]
|
||||
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_OPEN)
|
||||
switch(id)
|
||||
if("edit")
|
||||
var/field = arguments["field"]
|
||||
if(!length(field) || !field_edit_questions[field])
|
||||
return
|
||||
var/question = field_edit_questions[field]
|
||||
var/choices = field_edit_choices[field]
|
||||
if(length(choices))
|
||||
tgui_modal_choice(src, id, question, arguments = arguments, value = arguments["value"], choices = choices)
|
||||
else
|
||||
setTemp("<h3 class='bad'>You do not have the required rank to do this!</h3>")
|
||||
if("species")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please enter race:", "General records", active1.fields["species"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["species"] = t1
|
||||
return 1
|
||||
tgui_modal_input(src, id, question, arguments = arguments, value = arguments["value"])
|
||||
if("comment_add")
|
||||
tgui_modal_input(src, id, "Please enter your message:")
|
||||
if("print_cell_log")
|
||||
if(is_printing)
|
||||
return
|
||||
if(!length(GLOB.cell_logs))
|
||||
set_temp("There are no cell logs available to print.")
|
||||
return
|
||||
var/list/choices = list()
|
||||
var/list/already_in = list()
|
||||
for(var/p in GLOB.cell_logs)
|
||||
var/obj/item/paper/P = p
|
||||
if(already_in[P.name])
|
||||
continue
|
||||
choices += P.name
|
||||
already_in[P.name] = TRUE
|
||||
tgui_modal_choice(src, id, "Please select the cell log you would like printed:", choices = choices)
|
||||
else
|
||||
return FALSE
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
if("edit")
|
||||
var/field = arguments["field"]
|
||||
if(!length(field) || !field_edit_questions[field])
|
||||
return
|
||||
var/list/choices = field_edit_choices[field]
|
||||
if(length(choices) && !(answer in choices))
|
||||
return
|
||||
|
||||
/obj/machinery/computer/secure_data/proc/setTemp(text, list/buttons = list())
|
||||
temp = list("text" = text, "buttons" = buttons, "has_buttons" = buttons.len > 0)
|
||||
if(field == "age")
|
||||
var/new_age = text2num(answer)
|
||||
if(new_age < AGE_MIN || new_age > AGE_MAX)
|
||||
set_temp("Invalid age. It must be between [AGE_MIN] and [AGE_MAX].", "danger")
|
||||
return
|
||||
answer = new_age
|
||||
else if(field == "criminal")
|
||||
var/text = "Please enter a reason for the status change to [answer]:"
|
||||
if(answer == SEC_RECORD_STATUS_EXECUTE)
|
||||
text = "Please explain why they are being executed. Include a list of their crimes, and victims."
|
||||
else if(answer == SEC_RECORD_STATUS_DEMOTE)
|
||||
text = "Please explain why they are being demoted. Include a list of their offenses."
|
||||
tgui_modal_input(src, "criminal_reason", text, arguments = list("status" = answer))
|
||||
return
|
||||
|
||||
/* Proc disabled due to BYOND Issue
|
||||
if(record_security && (field in record_security.fields))
|
||||
record_security.fields[field] = answer
|
||||
else if(record_general && (field in record_general.fields))
|
||||
record_general.fields[field] = answer
|
||||
if("criminal_reason")
|
||||
var/status = arguments["status"]
|
||||
if(!record_security || !(status in field_edit_choices["criminal"]))
|
||||
return
|
||||
if((status in list(SEC_RECORD_STATUS_EXECUTE, SEC_RECORD_STATUS_DEMOTE)) && !length(answer))
|
||||
set_temp("A valid reason must be provided for this status.", "danger")
|
||||
return
|
||||
var/datum/tgui_login/state = tgui_login_get()
|
||||
if(!set_criminal_status(usr, record_security, status, answer, state.rank, state.access, state.name))
|
||||
set_temp("Required permissions to set this criminal status not found!", "danger")
|
||||
if("comment_add")
|
||||
var/datum/tgui_login/state = tgui_login_get()
|
||||
if(!length(answer) || !record_security || !length(state.name))
|
||||
return
|
||||
record_security.fields["comments"] += list(list(
|
||||
header = "Made by [state.name] ([state.rank]) on [GLOB.current_date_string] [station_time_timestamp()]",
|
||||
text = answer
|
||||
))
|
||||
if("print_cell_log")
|
||||
if(is_printing)
|
||||
return
|
||||
var/obj/item/paper/T
|
||||
for(var/obj/item/paper/P in GLOB.cell_logs)
|
||||
if(P.name == answer)
|
||||
T = P
|
||||
break
|
||||
if(!T)
|
||||
set_temp("Cell log not found!", "danger")
|
||||
return
|
||||
is_printing = TRUE
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
|
||||
addtimer(CALLBACK(src, .proc/print_cell_log_finish, T.name, T.info), 5 SECONDS)
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/secure_data/proc/create_record_photo(datum/data/record/R)
|
||||
// basically copy-pasted from the camera code but different enough that it has to be redone
|
||||
var/icon/photoimage = get_record_photo(R)
|
||||
var/icon/small_img = icon(photoimage)
|
||||
var/icon/tiny_img = icon(photoimage)
|
||||
var/icon/ic = icon('icons/obj/items.dmi',"photo")
|
||||
var/icon/pc = icon('icons/obj/bureaucracy.dmi', "photo")
|
||||
small_img.Scale(8, 8)
|
||||
tiny_img.Scale(4, 4)
|
||||
ic.Blend(small_img, ICON_OVERLAY, 10, 13)
|
||||
pc.Blend(tiny_img, ICON_OVERLAY, 12, 19)
|
||||
/**
|
||||
* Called when the print record timer finishes
|
||||
*/
|
||||
/obj/machinery/computer/secure_data/proc/print_record_finish()
|
||||
var/obj/item/paper/P = new(loc)
|
||||
P.info = "<center><b>Security Record</b></center><br>"
|
||||
if(record_general && GLOB.data_core.general.Find(record_general))
|
||||
P.info += {"Name: [record_general.fields["name"]] ID: [record_general.fields["id"]]
|
||||
<br>\nSex: [record_general.fields["sex"]]
|
||||
<br>\nAge: [record_general.fields["age"]]
|
||||
<br>\nFingerprint: [record_general.fields["fingerprint"]]
|
||||
<br>\nPhysical Status: [record_general.fields["p_stat"]]
|
||||
<br>\nMental Status: [record_general.fields["m_stat"]]<br>"}
|
||||
P.name = "paper - 'Security Record: [record_general.fields["name"]]'"
|
||||
else
|
||||
P.info += "<b>General Record Lost!</b><br>"
|
||||
if(record_security && GLOB.data_core.security.Find(record_security))
|
||||
P.info += {"<br>\n<center><b>Security Data</b></center>
|
||||
<br>\nCriminal Status: [record_security.fields["criminal"]]<br>\n
|
||||
<br>\nMinor Crimes: [record_security.fields["mi_crim"]]
|
||||
<br>\nDetails: [record_security.fields["mi_crim_d"]]<br>\n
|
||||
<br>\nMajor Crimes: [record_security.fields["ma_crim"]]
|
||||
<br>\nDetails: [record_security.fields["ma_crim_d"]]<br>\n
|
||||
<br>\nImportant Notes:
|
||||
<br>\n\t[record_security.fields["notes"]]<br>\n<br>\n<center><B>Comments/Log</B></center><br>"}
|
||||
for(var/c in record_security.fields["comments"])
|
||||
P.info += "[c]<br>"
|
||||
else
|
||||
P.info += "<b>Security Record Lost!</b><br>"
|
||||
is_printing = FALSE
|
||||
SStgui.update_uis(src)
|
||||
|
||||
var/datum/picture/P = new()
|
||||
P.fields["name"] = "File Photo - [R.fields["name"]]"
|
||||
P.fields["author"] = "Central Command"
|
||||
P.fields["icon"] = ic
|
||||
P.fields["tiny"] = pc
|
||||
P.fields["img"] = photoimage
|
||||
P.fields["desc"] = "You can see [R.fields["name"]] on the photo."
|
||||
P.fields["pixel_x"] = rand(-10, 10)
|
||||
P.fields["pixel_y"] = rand(-10, 10)
|
||||
P.fields["size"] = 2
|
||||
|
||||
var/obj/item/photo/PH = new/obj/item/photo(loc)
|
||||
PH.construct(P)
|
||||
|
||||
*/
|
||||
|
||||
/obj/machinery/computer/secure_data/proc/get_record_photo(datum/data/record/R)
|
||||
// similar to the code to make a photo, but of course the actual rendering is completely different
|
||||
var/icon/res = icon('icons/effects/96x96.dmi', "")
|
||||
// will be 2x2 to fit the 2 directions
|
||||
res.Scale(2 * 32, 2 * 32)
|
||||
// transparent background (it's a plastic transparency, you see) with the front and side icons
|
||||
res.Blend(icon(R.fields["photo"], dir = SOUTH), ICON_OVERLAY, 1, 17)
|
||||
res.Blend(icon(R.fields["photo"], dir = WEST), ICON_OVERLAY, 33, 17)
|
||||
|
||||
return res
|
||||
/**
|
||||
* Called when the print cell log timer finishes
|
||||
*/
|
||||
/obj/machinery/computer/secure_data/proc/print_cell_log_finish(name, info)
|
||||
var/obj/item/paper/P = new(loc)
|
||||
P.name = name
|
||||
P.info = info
|
||||
is_printing = FALSE
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/computer/secure_data/emp_act(severity)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
@@ -548,8 +451,8 @@
|
||||
return
|
||||
|
||||
for(var/datum/data/record/R in GLOB.data_core.security)
|
||||
if(prob(10/severity))
|
||||
switch(rand(1,6))
|
||||
if(prob(10 / severity))
|
||||
switch(rand(1, 6))
|
||||
if(1)
|
||||
R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
|
||||
if(2)
|
||||
@@ -570,9 +473,17 @@
|
||||
|
||||
..(severity)
|
||||
|
||||
/obj/machinery/computer/secure_data/detective_computer
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "messyfiles"
|
||||
/**
|
||||
* Sets a temporary message to display to the user
|
||||
*
|
||||
* Arguments:
|
||||
* * text - Text to display, null/empty to clear the message from the UI
|
||||
* * style - The style of the message: (color name), info, success, warning, danger
|
||||
*/
|
||||
/obj/machinery/computer/secure_data/proc/set_temp(text = "", style = "info", update_now = FALSE)
|
||||
temp_notice = list(text = text, style = style)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/computer/secure_data/laptop
|
||||
name = "security laptop"
|
||||
@@ -580,8 +491,9 @@
|
||||
icon_state = "laptop"
|
||||
icon_keyboard = "seclaptop_key"
|
||||
icon_screen = "seclaptop"
|
||||
density = 0
|
||||
density = FALSE
|
||||
|
||||
#undef SEC_DATA_R_LIST
|
||||
#undef SEC_DATA_MAINT
|
||||
#undef SEC_DATA_RECORD
|
||||
#undef SEC_FIELD
|
||||
|
||||
@@ -58,6 +58,7 @@ GLOBAL_LIST(tgui_logins)
|
||||
)
|
||||
data["isAI"] = isAI(user)
|
||||
data["isRobot"] = isrobot(user)
|
||||
data["isAdmin"] = user.can_admin_interact()
|
||||
|
||||
/**
|
||||
* Convenience function to perform login actions when
|
||||
@@ -117,17 +118,18 @@ GLOBAL_LIST(tgui_logins)
|
||||
* Attempts to log in with the given login type.
|
||||
*
|
||||
* Arguments:
|
||||
* * login_type - The login type: LOGIN_TYPE_NORMAL (checks for inserted ID), LOGIN_TYPE_AI and LOGIN_TYPE_ROBOT
|
||||
* * login_type - The login type: LOGIN_TYPE_NORMAL (checks for inserted ID), LOGIN_TYPE_AI, LOGIN_TYPE_ROBOT and LOGIN_TYPE_ADMIN
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_login(login_type = LOGIN_TYPE_NORMAL, datum/tgui_login/state = tgui_login_get())
|
||||
if(!state.id || state.logged_in)
|
||||
if(state.logged_in)
|
||||
return
|
||||
|
||||
if(login_type == LOGIN_TYPE_NORMAL)
|
||||
if(state.id && login_type == LOGIN_TYPE_NORMAL)
|
||||
if(check_access(state.id))
|
||||
state.name = state.id.registered_name
|
||||
state.rank = state.id.assignment
|
||||
state.access = state.id.access
|
||||
else if(login_type == LOGIN_TYPE_AI && isAI(usr))
|
||||
state.name = usr.name
|
||||
state.rank = "AI"
|
||||
@@ -135,6 +137,10 @@ GLOBAL_LIST(tgui_logins)
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
state.name = usr.name
|
||||
state.rank = "[R.modtype] [R.braintype]"
|
||||
else if(login_type == LOGIN_TYPE_ADMIN && usr.can_admin_interact())
|
||||
state.name = "*CONFIDENTIAL*"
|
||||
state.rank = "CentComm Secure Connection"
|
||||
state.access = get_all_accesses() + get_all_centcom_access()
|
||||
|
||||
state.logged_in = TRUE
|
||||
tgui_login_on_login(state = state)
|
||||
@@ -153,6 +159,7 @@ GLOBAL_LIST(tgui_logins)
|
||||
|
||||
state.name = ""
|
||||
state.rank = ""
|
||||
state.access = null
|
||||
state.logged_in = FALSE
|
||||
tgui_login_on_logout(state = state)
|
||||
|
||||
@@ -196,9 +203,11 @@ GLOBAL_LIST(tgui_logins)
|
||||
var/obj/item/card/id/id = null
|
||||
var/name = ""
|
||||
var/rank = ""
|
||||
var/list/access = null
|
||||
var/logged_in = FALSE
|
||||
|
||||
/datum/tgui_login/New(id, name, rank)
|
||||
/datum/tgui_login/New(id, name, rank, access)
|
||||
src.id = id
|
||||
src.name = name
|
||||
src.rank = rank
|
||||
src.access = access
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
<!--
|
||||
Title: Security Records UI
|
||||
Used In File(s): \code\game\machinery\computer\security.dm
|
||||
-->
|
||||
|
||||
<!--
|
||||
#define SEC_DATA_R_LIST 1 // Main menu
|
||||
#define SEC_DATA_MAINT 2 // Record list
|
||||
#define SEC_DATA_RECORD 3 // Records maintenance
|
||||
-->
|
||||
|
||||
{{if !data.temp && data.screen == 1}}
|
||||
<script type='text/javascript'>
|
||||
var hidden;
|
||||
function updateSearch(){
|
||||
var filter_text = document.getElementById('filter');
|
||||
var filter = filter_text.value.toLowerCase();
|
||||
|
||||
if(hidden != null){
|
||||
hidden.parent("td").parent("tr").show()
|
||||
}
|
||||
|
||||
if(filter == ""){
|
||||
return;
|
||||
} else {
|
||||
hidden = $("#maintable_data").children("tbody").children("tr").children("td").children("input").filter(function(index) {
|
||||
return $(this)[0].value.toLowerCase().indexOf(filter) == -1
|
||||
});
|
||||
hidden.parent("td").parent("tr").hide()
|
||||
}
|
||||
}
|
||||
|
||||
function selectTextField(){
|
||||
var filter_text = document.getElementById('filter');
|
||||
filter_text.focus();
|
||||
filter_text.select();
|
||||
}
|
||||
|
||||
$(window).load(function() {
|
||||
selectTextField();
|
||||
updateSearch();
|
||||
});
|
||||
|
||||
$("#filter").keyup(function() {
|
||||
updateSearch();
|
||||
});
|
||||
</script>
|
||||
{{/if}}
|
||||
<style type="text/css">
|
||||
.infoButton {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
input[type=text], input[type=submit] {
|
||||
border: 1px solid #161616;
|
||||
background-color: #40628a;
|
||||
color: #FFFFFF;
|
||||
padding: 4px;
|
||||
}
|
||||
input[type=submit]:hover {
|
||||
background-color: #507aac;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
<b>Confirm Identity:</b>
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.scan ? data.scan : "----------", 'eject', {'scan' : 1}, null, data.scan ? 'itemContentWide' : 'fixedLeft')}}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{if data.authenticated}}
|
||||
{{if data.screen == 1}} <!-- SEC_DATA_R_LIST -->
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block;">{{:helper.link('New Record', 'plus', {'new_g' : 1})}}</div>
|
||||
</div>
|
||||
<h3><center>Record List</center></h3>
|
||||
<table width='560' align='center' cellspacing='0' cellpadding='5' id='maintable'>
|
||||
<tr id='search_tr'>
|
||||
<td align='center'>
|
||||
<b>Search:</b> <input type='text' id='filter' value='' style='width:300px;'></input>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="statusDisplay" style="overflow: auto;">
|
||||
<span id='maintable_data_archive'>
|
||||
<table style='width: 100%' id='maintable_data'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{:helper.link('Name', null, {'sort' : 'name'}, null, 'infoButton')}}</th>
|
||||
<th>{{:helper.link('ID', null, {'sort' : 'id'}, null, 'infoButton')}}</th>
|
||||
<th>{{:helper.link('Rank', null, {'sort' : 'rank'}, null, 'infoButton')}}</th>
|
||||
<th>{{:helper.link('Fingerprints', null, {'sort' : 'fingerprint'}, null, 'infoButton')}}</th>
|
||||
<th>{{:helper.link('Criminal Status', null, {'sort' : 'crimstat'}, null, 'infoButton')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{for data.records}}
|
||||
<tr style={{:value.background}}>
|
||||
<td><input type='hidden' value='{{:value.name}} {{:value.id}} {{:value.rank}} {{:value.fingerprint}} {{:value.crimstat}}'></input> {{:helper.link(value.name, 'user', {'d_rec' : value.ref}, null, 'infoButton')}}</td>
|
||||
<td>{{:value.id}}</td>
|
||||
<td>{{:value.rank}}</td>
|
||||
<td>{{:value.fingerprint}}</td>
|
||||
<td>{{:value.crimstat}}</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
</span>
|
||||
</div>
|
||||
<h3><center>Menu</center></h3>
|
||||
<div class="line">{{:helper.link('Record Maintenance', 'wrench', {'screen' : 2})}}</div>
|
||||
<div class="line">{{:helper.link('Print Cell Log', 'print', {'printlogs' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Logout', 'lock', {'logout' : 1})}}</div>
|
||||
{{else data.screen == 2}} <!-- SEC_DATA_MAINT -->
|
||||
<h3>Records Maintenance</h3>
|
||||
<div class="line">{{:helper.link('Backup To Disk', 'download', {'back' : 1}, 'disabled')}}</div>
|
||||
<div class="line">{{:helper.link('Upload From Disk', 'upload', {'u_load' : 1}, 'disabled')}}</div>
|
||||
<div class="line">{{:helper.link('Delete All Records', 'trash', {'del_all' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Delete All Cell Logs', 'trash', {'del_alllogs' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{else data.screen == 3}} <!-- SEC_DATA_RECORD -->
|
||||
<h3><center>Security Record</center></h3>
|
||||
<h4><center>General Data</center></h4>
|
||||
{{if data.general.empty}}
|
||||
<span class="bad"><center>General Record Lost!</center></span>
|
||||
{{else}}
|
||||
<div class="statusDisplayRecords">
|
||||
<table style='width:100%'><tr>
|
||||
<td valign='top' style='margin-right: 300px;'>
|
||||
{{for data.general.fields}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
{{:value.field}}
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(value.value, value.edit ? 'pencil' : 'user-times', {'field' : value.edit}, value.edit ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
</td>
|
||||
<td valign='middle' align='center' style='width: 300px;'>
|
||||
{{if data.general.has_photos}}
|
||||
<!-- Removed due to BYOND issue.
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block;">{{:helper.link('Print photo', 'camera', {'print_p' : 1})}}</div>
|
||||
</div>
|
||||
-->
|
||||
{{for data.general.photos}}
|
||||
{{if value.photo}}
|
||||
<img src={{:value.photo}} height=96 width=96 border=5>
|
||||
{{/if}}
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<h4><center>Security Data</center></h4>
|
||||
{{if data.security.empty}}
|
||||
<span class="bad"><center>Security Record Lost!</center></span>
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block; height: 100%; vertical-align: middle;">{{:helper.link('New Record', 'plus', {'new_s' : 1})}}</div>
|
||||
</div>
|
||||
<h3><center>Menu</center></h3>
|
||||
{{else}}
|
||||
{{for data.security.fields}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
{{:value.field}}
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(value.value, 'pencil', {'field' : value.edit})}}
|
||||
</div>
|
||||
</div>
|
||||
{{if value.line_break}}
|
||||
<br>
|
||||
{{/if}}
|
||||
{{/for}}
|
||||
|
||||
<h4><center>Comments/Log</center></h4>
|
||||
{{for data.security.comments}}
|
||||
<div class="line">{{:value}}</div>
|
||||
<div class="line">{{:helper.link('Remove entry', 'trash', {'del_c' : index})}}</div>
|
||||
<br><hr>
|
||||
{{/for}}
|
||||
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block; height: 100%; vertical-align: middle;">{{:helper.link('Add Entry', 'plus', {'add_c' : 1})}}</div>
|
||||
</div>
|
||||
|
||||
<h3><center>Menu</center></h3>
|
||||
<div class="line">{{:helper.link('Delete Record (Security Only)', 'trash', {'del_r' : 1})}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="line">{{:helper.link('Delete Record (All)', 'trash', {'del_rg' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Print Record', 'print', {'print_r' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<h3>Menu</h3>
|
||||
{{:helper.link('Login', 'unlock', {'login' : 1})}}
|
||||
{{/if}}
|
||||
|
||||
{{if data.temp}}
|
||||
<div class="mask" style="display: table;">
|
||||
<div class="maskContent" style="margin: 0px; vertical-align: middle; display: table-cell;">
|
||||
{{if data.temp.notice}}
|
||||
<div class="notice"><center>{{:data.temp.text}}</center></div>
|
||||
{{else}}
|
||||
<center>{{:data.temp.text}}</center>
|
||||
{{/if}}
|
||||
|
||||
{{if data.temp.has_buttons}}
|
||||
<div class="line">
|
||||
<div style="display: inline-block;">
|
||||
<div style="width: 500px; display: flex; display: -webkit-flex; flex-wrap: wrap; -webkit-flex-wrap: wrap; justify-content: center; -webkit-justify-content: center;">
|
||||
{{for data.temp.buttons}}
|
||||
{{:helper.link(value.name, value.icon, {'temp' : 1, 'temp_action' : value.href}, value.status)}}
|
||||
{{/for}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div style="display: inline-block;">
|
||||
<div class="item">{{:helper.link('Clear screen', 'home', {'temp' : 1})}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -24,6 +24,7 @@ import './styles/themes/hackerman.scss';
|
||||
import './styles/themes/malfunction.scss';
|
||||
import './styles/themes/ntos.scss';
|
||||
import './styles/themes/retro.scss';
|
||||
import './styles/themes/security.scss';
|
||||
import './styles/themes/syndicate.scss';
|
||||
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ const MedicalRecordsViewGeneral = (_properties, context) => {
|
||||
textAlign="center"
|
||||
color="label">
|
||||
<img
|
||||
src={p.substr(1, p.length - 1)}
|
||||
src={p}
|
||||
style={{
|
||||
width: '96px',
|
||||
'margin-bottom': '0.5rem',
|
||||
|
||||
@@ -0,0 +1,436 @@
|
||||
import { createSearch, decodeHtmlEntities } from 'common/string';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend, useLocalState } from "../backend";
|
||||
import { Box, Button, Flex, Icon, Input, LabeledList, Section, Table, Tabs } from '../components';
|
||||
import { FlexItem } from '../components/Flex';
|
||||
import { Window } from "../layouts";
|
||||
import { ComplexModal, modalOpen } from './common/ComplexModal';
|
||||
import { LoginInfo } from './common/LoginInfo';
|
||||
import { LoginScreen } from './common/LoginScreen';
|
||||
import { TemporaryNotice } from './common/TemporaryNotice';
|
||||
|
||||
const statusStyles = {
|
||||
"*Execute*": "execute",
|
||||
"*Arrest*": "arrest",
|
||||
"Incarcerated": "incarcerated",
|
||||
"Parolled": "parolled",
|
||||
"Released": "released",
|
||||
};
|
||||
|
||||
const doEdit = (context, field) => {
|
||||
modalOpen(context, 'edit', {
|
||||
field: field.edit,
|
||||
value: field.value,
|
||||
});
|
||||
};
|
||||
|
||||
export const SecurityRecords = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
loginState,
|
||||
currentPage,
|
||||
} = data;
|
||||
|
||||
let body;
|
||||
if (!loginState.logged_in) {
|
||||
return (
|
||||
<Window theme="security" resizable>
|
||||
<Window.Content>
|
||||
<LoginScreen />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
} else {
|
||||
if (currentPage === 1) {
|
||||
body = <SecurityRecordsPageList />;
|
||||
} else if (currentPage === 2) {
|
||||
body = <SecurityRecordsPageMaintenance />;
|
||||
} else if (currentPage === 3) {
|
||||
body = <SecurityRecordsPageView />;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Window theme="security" resizable>
|
||||
<ComplexModal />
|
||||
<Window.Content scrollable className="Layout__content--flexColumn">
|
||||
<LoginInfo />
|
||||
<TemporaryNotice />
|
||||
<SecurityRecordsNavigation />
|
||||
<Section height="100%" flexGrow="1">
|
||||
{body}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const SecurityRecordsNavigation = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
currentPage,
|
||||
general,
|
||||
} = data;
|
||||
return (
|
||||
<Tabs>
|
||||
<Tabs.Tab
|
||||
selected={currentPage === 1}
|
||||
onClick={() => act('page', { page: 1 })}>
|
||||
<Icon name="list" />
|
||||
List Records
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
selected={currentPage === 2}
|
||||
onClick={() => act('page', { page: 2 })}>
|
||||
<Icon name="wrench" />
|
||||
Record Maintenance
|
||||
</Tabs.Tab>
|
||||
{(currentPage === 3 && general && !general.empty) && (
|
||||
<Tabs.Tab
|
||||
selected={currentPage === 3}>
|
||||
<Icon name="file" />
|
||||
Record: {general.fields[0].value}
|
||||
</Tabs.Tab>
|
||||
)}
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
const SecurityRecordsPageList = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
records,
|
||||
} = data;
|
||||
const [searchText, setSearchText] = useLocalState(context, "searchText", "");
|
||||
const [sortId, _setSortId] = useLocalState(context, "sortId", "name");
|
||||
const [sortOrder, _setSortOrder] = useLocalState(context, "sortOrder", true);
|
||||
return (
|
||||
<Flex direction="column" height="100%">
|
||||
<SecurityRecordsActions />
|
||||
<Section flexGrow="1" mt="0.5rem">
|
||||
<Table className="SecurityRecords__list">
|
||||
<Table.Row bold>
|
||||
<SortButton id="name">Name</SortButton>
|
||||
<SortButton id="id">ID</SortButton>
|
||||
<SortButton id="rank">Assignment</SortButton>
|
||||
<SortButton id="fingerprint">Fingerprint</SortButton>
|
||||
<SortButton id="status">Criminal Status</SortButton>
|
||||
</Table.Row>
|
||||
{records
|
||||
.filter(createSearch(searchText, record => {
|
||||
return record.name + "|"
|
||||
+ record.id + "|"
|
||||
+ record.rank + "|"
|
||||
+ record.fingerprint + "|"
|
||||
+ record.status;
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
const i = sortOrder ? 1 : -1;
|
||||
return a[sortId].localeCompare(b[sortId]) * i;
|
||||
})
|
||||
.map(record => (
|
||||
<Table.Row
|
||||
key={record.id}
|
||||
className={"SecurityRecords__listRow--"
|
||||
+ statusStyles[record.status]}
|
||||
onClick={() => act('view', {
|
||||
uid_gen: record.uid_gen,
|
||||
uid_sec: record.uid_sec,
|
||||
})}>
|
||||
<Table.Cell><Icon name="user" /> {record.name}</Table.Cell>
|
||||
<Table.Cell>{record.id}</Table.Cell>
|
||||
<Table.Cell>{record.rank}</Table.Cell>
|
||||
<Table.Cell>{record.fingerprint}</Table.Cell>
|
||||
<Table.Cell>{record.status}</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const SortButton = (properties, context) => {
|
||||
const [sortId, setSortId] = useLocalState(context, "sortId", "name");
|
||||
const [sortOrder, setSortOrder] = useLocalState(context, "sortOrder", true);
|
||||
const {
|
||||
id,
|
||||
children,
|
||||
} = properties;
|
||||
return (
|
||||
<Table.Cell>
|
||||
<Button
|
||||
color={sortId !== id && "transparent"}
|
||||
width="100%"
|
||||
onClick={() => {
|
||||
if (sortId === id) {
|
||||
setSortOrder(!sortOrder);
|
||||
} else {
|
||||
setSortId(id);
|
||||
setSortOrder(true);
|
||||
}
|
||||
}}>
|
||||
{children}
|
||||
{sortId === id && (
|
||||
<Icon
|
||||
name={sortOrder ? "sort-up" : "sort-down"}
|
||||
ml="0.25rem;"
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
);
|
||||
};
|
||||
|
||||
const SecurityRecordsActions = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isPrinting,
|
||||
} = data;
|
||||
const [searchText, setSearchText] = useLocalState(context, "searchText", "");
|
||||
return (
|
||||
<Flex>
|
||||
<FlexItem>
|
||||
<Button
|
||||
content="New Record"
|
||||
icon="plus"
|
||||
onClick={() => act('new_general')}
|
||||
/>
|
||||
<Button
|
||||
disabled={isPrinting}
|
||||
icon={isPrinting ? 'spinner' : 'print'}
|
||||
iconSpin={!!isPrinting}
|
||||
content="Print Cell Log"
|
||||
ml="0.25rem"
|
||||
onClick={() => modalOpen(context, "print_cell_log")}
|
||||
/>
|
||||
</FlexItem>
|
||||
<FlexItem grow="1" ml="0.5rem">
|
||||
<Input
|
||||
placeholder="Search by Name, ID, Assignment, Fingerprint, Status"
|
||||
width="100%"
|
||||
onInput={(e, value) => setSearchText(value)}
|
||||
/>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const SecurityRecordsPageMaintenance = (properties, context) => {
|
||||
const { act } = useBackend(context);
|
||||
return (
|
||||
<Box>
|
||||
<Button
|
||||
disabled
|
||||
icon="download"
|
||||
content="Backup to Disk"
|
||||
tooltip="This feature is not available."
|
||||
tooltipPosition="right"
|
||||
/><br />
|
||||
<Button
|
||||
disabled
|
||||
icon="upload"
|
||||
content="Upload from Disk"
|
||||
tooltip="This feature is not available."
|
||||
tooltipPosition="right"
|
||||
my="0.5rem"
|
||||
/><br />
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
content="Delete All Security Records"
|
||||
onClick={() => act('delete_security_all')}
|
||||
mb="0.5rem"
|
||||
/><br />
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
content="Delete All Cell Logs"
|
||||
onClick={() => act('delete_cell_logs')}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const SecurityRecordsPageView = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isPrinting,
|
||||
general,
|
||||
security,
|
||||
} = data;
|
||||
if (!general || !general.fields) {
|
||||
return (
|
||||
<Box color="bad">
|
||||
General records lost!
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<Section
|
||||
title="General Data"
|
||||
level={2}
|
||||
mt="-6px"
|
||||
buttons={
|
||||
<Fragment>
|
||||
<Button
|
||||
disabled={isPrinting}
|
||||
icon={isPrinting ? 'spinner' : 'print'}
|
||||
iconSpin={!!isPrinting}
|
||||
content="Print Record"
|
||||
onClick={() => act('print_record')}
|
||||
/>
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
tooltip={"WARNING: This will also delete the Security "
|
||||
+ "and Medical records associated to this crew member!"}
|
||||
tooltipPosition="bottom-left"
|
||||
content="Delete Record"
|
||||
onClick={() => act('delete_general')}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
<SecurityRecordsViewGeneral />
|
||||
</Section>
|
||||
<Section
|
||||
title="Security Data"
|
||||
level={2}
|
||||
mt="-12px"
|
||||
buttons={
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
disabled={security.empty}
|
||||
content="Delete Record"
|
||||
onClick={() => act('delete_security')}
|
||||
/>
|
||||
}>
|
||||
<SecurityRecordsViewSecurity />
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const SecurityRecordsViewGeneral = (_properties, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
general,
|
||||
} = data;
|
||||
if (!general || !general.fields) {
|
||||
return (
|
||||
<Box color="bad">
|
||||
General records lost!
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<Box float="left">
|
||||
<LabeledList>
|
||||
{general.fields.map((field, i) => (
|
||||
<LabeledList.Item key={i} label={field.field}>
|
||||
{decodeHtmlEntities('' + field.value)}
|
||||
{!!field.edit && (
|
||||
<Button
|
||||
icon="pen"
|
||||
ml="0.5rem"
|
||||
mb={field.line_break ? '1rem' : 'initial'}
|
||||
onClick={() => doEdit(context, field)}
|
||||
/>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Box>
|
||||
<Box position="absolute" right="0" textAlign="right">
|
||||
{!!general.has_photos && (
|
||||
general.photos.map((p, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
display="inline-block"
|
||||
textAlign="center"
|
||||
color="label">
|
||||
<img
|
||||
src={p}
|
||||
style={{
|
||||
width: '96px',
|
||||
'margin-bottom': '0.5rem',
|
||||
'-ms-interpolation-mode': 'nearest-neighbor',
|
||||
}}
|
||||
/><br />
|
||||
Photo #{i + 1}
|
||||
</Box>
|
||||
))
|
||||
)}
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const SecurityRecordsViewSecurity = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
security,
|
||||
} = data;
|
||||
if (!security || !security.fields) {
|
||||
return (
|
||||
<Box color="bad">
|
||||
Security records lost!<br />
|
||||
<Button
|
||||
icon="pen"
|
||||
content="Create New Record"
|
||||
mt="0.5rem"
|
||||
onClick={() => act('new_security')}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<LabeledList>
|
||||
{security.fields.map((field, i) => (
|
||||
<LabeledList.Item
|
||||
key={i}
|
||||
label={field.field}>
|
||||
{decodeHtmlEntities(field.value)}
|
||||
{!!field.edit && (
|
||||
<Button
|
||||
icon="pen"
|
||||
ml="0.5rem"
|
||||
mb={field.line_break ? '1rem' : 'initial'}
|
||||
onClick={() => doEdit(context, field)}
|
||||
/>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
<Section
|
||||
title="Comments/Log"
|
||||
level={2}
|
||||
buttons={
|
||||
<Button
|
||||
icon="comment"
|
||||
content="Add Entry"
|
||||
onClick={() => modalOpen(context, 'comment_add')}
|
||||
/>
|
||||
}>
|
||||
{security.comments.length === 0 ? (
|
||||
<Box color="label">
|
||||
No comments found.
|
||||
</Box>
|
||||
) : security.comments.map((comment, i) => (
|
||||
<Box key={i}>
|
||||
<Box color="label" display="inline">
|
||||
{comment.header || "Auto-generated"}
|
||||
</Box><br />
|
||||
{comment.text || comment}
|
||||
<Button
|
||||
icon="comment-slash"
|
||||
color="bad"
|
||||
ml="0.5rem"
|
||||
onClick={() => act('comment_delete', { id: i + 1 })}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
@@ -89,6 +89,7 @@ export const ComplexModal = (props, context) => {
|
||||
onClick={() => modalClose(context)}
|
||||
/>
|
||||
);
|
||||
let overflowY = "auto";
|
||||
|
||||
// Different contents depending on the type
|
||||
if (bodyOverrides[id]) {
|
||||
@@ -140,6 +141,7 @@ export const ComplexModal = (props, context) => {
|
||||
onSelected={val => modalAnswer(context, id, val)}
|
||||
/>
|
||||
);
|
||||
overflowY = "initial";
|
||||
} else if (type === "bento") {
|
||||
modalBody = (
|
||||
<Flex
|
||||
@@ -188,7 +190,7 @@ export const ComplexModal = (props, context) => {
|
||||
maxHeight={props.maxHeight || (window.innerHeight / 2 + "px")}
|
||||
onEnter={modalOnEnter}
|
||||
mx="auto"
|
||||
overflowY="auto">
|
||||
overflowY={overflowY}>
|
||||
<Box display="inline">
|
||||
{text}
|
||||
</Box>
|
||||
|
||||
@@ -8,6 +8,8 @@ import { Box, Button, Flex, Icon, Section } from '../../components';
|
||||
* * `loginState` — The current login state
|
||||
* * `isAI` — Whether the user is an AI. If true, shows "Login as AI"
|
||||
* * `isRobot` — Whether the user is a robot. If true, shows "Login as Cyborg"
|
||||
* * `isAdmin` — Whether the user is an admin. If true, shows
|
||||
* "Secure CentComm Login"
|
||||
*
|
||||
* Clicking the main button calls the `login_insert` TGUI act.
|
||||
* Clicking either the AI or normal login button calls
|
||||
@@ -15,10 +17,11 @@ import { Box, Button, Flex, Icon, Section } from '../../components';
|
||||
* * 1 (LOGIN_TYPE_NORMAL) if it's an ID login
|
||||
* * 2 (LOGIN_TYPE_AI) if it's an AI login
|
||||
* * 3 (LOGIN_TYPE_ROBOT) if it's a robot login
|
||||
* * 4 (LOGIN_TYPE_ADMIN) if it's an admin login
|
||||
*
|
||||
* You will have to handle the AI login case in the same action.
|
||||
* The normal login button is only available when `loginState.id` is not null.
|
||||
* The AI and robot login buttons are only visible if the user is one
|
||||
* The AI, robot and admin login buttons are only visible if the user is one
|
||||
* @param {object} _properties
|
||||
* @param {object} context
|
||||
*/
|
||||
@@ -28,6 +31,7 @@ export const LoginScreen = (_properties, context) => {
|
||||
loginState,
|
||||
isAI,
|
||||
isRobot,
|
||||
isAdmin,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Welcome" height="100%" stretchContents>
|
||||
@@ -77,6 +81,15 @@ export const LoginScreen = (_properties, context) => {
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{!!isAdmin && (
|
||||
<Button
|
||||
icon="sign-in-alt"
|
||||
content="CentComm Secure Login"
|
||||
onClick={() => act('login_login', {
|
||||
login_type: 4,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
|
||||
@use '../base.scss';
|
||||
@use '../colors.scss';
|
||||
@use '../functions.scss' as *;
|
||||
|
||||
.SecurityRecords__list {
|
||||
tr > td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr:not(:first-child) {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
transition: background-color 50ms;
|
||||
&:hover, &:focus {
|
||||
background-color: rgba(base.$color-bg, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.SecurityRecords__listRow--execute {
|
||||
background-color: colors.bg(#7a49a5);
|
||||
}
|
||||
|
||||
.SecurityRecords__listRow--arrest {
|
||||
background-color: colors.bg(#890E26);
|
||||
}
|
||||
|
||||
.SecurityRecords__listRow--incarcerated, .SecurityRecords__listRow--parolled {
|
||||
background-color: colors.bg(#743B03);
|
||||
}
|
||||
|
||||
.SecurityRecords__listRow--released {
|
||||
background-color: colors.bg(#216489);
|
||||
}
|
||||
@@ -42,6 +42,7 @@
|
||||
@include meta.load-css('./interfaces/CameraConsole.scss');
|
||||
@include meta.load-css('./interfaces/NuclearBomb.scss');
|
||||
@include meta.load-css('./interfaces/Roulette.scss');
|
||||
@include meta.load-css('./interfaces/SecurityRecords.scss');
|
||||
|
||||
// Layouts
|
||||
@include meta.load-css('./layouts/Layout.scss');
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
@use 'sass:color';
|
||||
@use 'sass:meta';
|
||||
|
||||
@use '../colors.scss' with (
|
||||
$primary: #a14c49,
|
||||
$blue: #d0212d,
|
||||
$label: #a7817e,
|
||||
$fg-map-keys: ('label'),
|
||||
$bg-map-keys: ('good')
|
||||
);
|
||||
@use '../base.scss';
|
||||
|
||||
.theme-security {
|
||||
// Atomic classes
|
||||
@include meta.load-css('../atomic/color.scss');
|
||||
|
||||
// Components
|
||||
@include meta.load-css('../components/Button.scss', $with: (
|
||||
'color-default': colors.$primary,
|
||||
));
|
||||
@include meta.load-css('../components/Input.scss', $with: (
|
||||
'border-color': #ff8d88,
|
||||
));
|
||||
@include meta.load-css('../components/NoticeBox.scss');
|
||||
@include meta.load-css('../components/Section.scss');
|
||||
}
|
||||
Reference in New Issue
Block a user