mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-08-30 00:35:45 +01:00
[MIRROR] Check Access List Mapper Verb (#12647)
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
co-authored by
Will
Kashargul
parent
646a9a1030
commit
74f6f2f08d
@@ -0,0 +1,81 @@
|
||||
|
||||
/*
|
||||
Tgui panel for admins editing the access list of various machines.
|
||||
*/
|
||||
/datum/access_viewer
|
||||
var/datum/weakref/focused_obj
|
||||
|
||||
/datum/access_viewer/Destroy(force)
|
||||
focused_obj = null
|
||||
. = ..()
|
||||
|
||||
/datum/access_viewer/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "AccessViewer", "Access Viewer")
|
||||
ui.open()
|
||||
|
||||
/datum/access_viewer/tgui_state(mob/user)
|
||||
return ADMIN_STATE(R_DEBUG)
|
||||
|
||||
/datum/access_viewer/tgui_act(action, params, datum/tgui/ui)
|
||||
if(..() || !check_rights_for(ui.user.client, R_DEBUG))
|
||||
return FALSE
|
||||
|
||||
var/obj/machinery/req_thing = focused_obj?.resolve()
|
||||
if(!req_thing)
|
||||
return FALSE
|
||||
|
||||
switch(action)
|
||||
if("req_all")
|
||||
var/set_id = text2num(params["set_id"])
|
||||
if(!set_id)
|
||||
return FALSE
|
||||
if(!req_thing.req_access)
|
||||
req_thing.req_access = list()
|
||||
if(set_id in req_thing.req_access)
|
||||
req_thing.req_access -= set_id
|
||||
else
|
||||
req_thing.req_access += set_id
|
||||
return TRUE
|
||||
|
||||
if("req_one")
|
||||
var/set_id = text2num(params["set_id"])
|
||||
if(!set_id)
|
||||
return FALSE
|
||||
if(!req_thing.req_one_access)
|
||||
req_thing.req_one_access = list()
|
||||
if(set_id in req_thing.req_one_access)
|
||||
req_thing.req_one_access -= set_id
|
||||
else
|
||||
req_thing.req_one_access += set_id
|
||||
return TRUE
|
||||
|
||||
/datum/access_viewer/tgui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/list/access_list = list()
|
||||
for(var/datum/access/dat as anything in subtypesof(/datum/access))
|
||||
access_list += list(
|
||||
list(
|
||||
"id" = dat.id,
|
||||
"name" = dat.desc,
|
||||
"region" = dat.region,
|
||||
"access_type" = dat.access_type,
|
||||
)
|
||||
)
|
||||
data["access_list"] = access_list
|
||||
return data
|
||||
|
||||
/datum/access_viewer/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
// Check if the object still exists
|
||||
var/obj/machinery/req_thing = focused_obj?.resolve()
|
||||
if(req_thing)
|
||||
data["name"] = req_thing.name
|
||||
data["coords"] = "[req_thing.x].[req_thing.y].[req_thing.z]"
|
||||
data["req_access"] = req_thing.req_access ? req_thing.req_access : list()
|
||||
data["req_one_access"] = req_thing.req_one_access ? req_thing.req_one_access : list()
|
||||
return data
|
||||
|
||||
/datum/access_viewer/proc/set_access_focus(obj/machinery/req_thing)
|
||||
focused_obj = WEAKREF(req_thing)
|
||||
@@ -35,6 +35,8 @@ GLOBAL_PROTECT(href_token)
|
||||
var/datum/spawn_menu/spawn_menu
|
||||
var/datum/spawnpanel/spawn_panel
|
||||
|
||||
var/datum/access_viewer/access_view_menu
|
||||
|
||||
/// A lazylist of tagged datums, for quick reference with the View Tags verb
|
||||
var/list/tagged_datums
|
||||
|
||||
|
||||
@@ -5,3 +5,12 @@ ADMIN_VERB(spawn_panel, R_SPAWN, "Spawn Panel", "Spawn Panel (TGUI).", ADMIN_CAT
|
||||
user.holder.spawn_panel = panel
|
||||
panel.tgui_interact(user.mob)
|
||||
feedback_add_details("admin_verb","SP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
ADMIN_VERB_AND_CONTEXT_MENU(machine_access_check, R_DEBUG, "Check Access List", "Read and edit the access list of a machine.", ADMIN_CATEGORY_GAME, obj/machinery/req_thing in world)
|
||||
var/datum/access_viewer/panel = user.holder.access_view_menu
|
||||
if(!panel)
|
||||
panel = new()
|
||||
user.holder.access_view_menu = panel
|
||||
panel.set_access_focus(req_thing)
|
||||
panel.tgui_interact(user.mob)
|
||||
feedback_add_details("admin_verb","SR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -17,3 +17,34 @@
|
||||
// continue
|
||||
|
||||
TEST_FAIL(log_entry)
|
||||
|
||||
/* Should probably be done as a linter thing instead
|
||||
/// Checks all machines for legal access numbers
|
||||
/datum/unit_test/all_access_id_must_have_existing_datums
|
||||
|
||||
/datum/unit_test/all_access_id_must_have_existing_datums/Run()
|
||||
var/failed = FALSE
|
||||
var/list/access_datums = SSaccess.get_all_access_datums_by_id()
|
||||
|
||||
for(var/obj/machinery/thing in world)
|
||||
failed += validate_list(thing.req_access, thing, "req_access")
|
||||
failed += validate_list(thing.req_one_access, thing, "req_one_access")
|
||||
if(failed)
|
||||
TEST_FAIL("Machinery had an illegal access id.")
|
||||
|
||||
/datum/unit_test/proc/validate_list(var/list/access_list, var/obj/machinery/thing, name_list)
|
||||
if(!access_list)
|
||||
return FALSE // null is legal
|
||||
|
||||
if(!islist(access_list))
|
||||
TEST_NOTICE(src, "Access - [thing] ([thing.x].[thing.y].[thing.z]) had a [name_list] that was not a list or null.")
|
||||
return TRUE // Was something other than null or a list... illegal
|
||||
|
||||
var/failed = FALSE
|
||||
for(var/access in access_list)
|
||||
if(!SSaccess.get_access_by_id(access))
|
||||
TEST_NOTICE(src, "Access - [thing] ([thing.x].[thing.y].[thing.z]) had a [name_list] with a non-existant id [access].")
|
||||
failed = TRUE // has a non-existant id, illegal
|
||||
|
||||
return failed
|
||||
*/
|
||||
|
||||
@@ -37,8 +37,8 @@ export function setClientTheme(name) {
|
||||
'rpanewindow.background-color': 'none',
|
||||
'rpanewindow.text-color': '#000000',
|
||||
'mainvsplit.background-color': 'none',
|
||||
'info.tab-background-color': 'none',
|
||||
'info.tab-text-color': '#000000',
|
||||
//'info.tab-background-color': 'none',
|
||||
//'info.tab-text-color': '#000000',
|
||||
'discord.background-color': 'none',
|
||||
'discord.text-color': '#000000',
|
||||
'mapb.background-color': 'none',
|
||||
@@ -57,47 +57,47 @@ export function setClientTheme(name) {
|
||||
|
||||
return Byond.winset({
|
||||
// Main windows
|
||||
'infowindow.background-color': 'none',
|
||||
'infowindow.text-color': '#000000',
|
||||
'info.background-color': 'none',
|
||||
'info.text-color': '#000000',
|
||||
//'infowindow.background-color': 'none',
|
||||
//'infowindow.text-color': '#000000',
|
||||
//'info.background-color': 'none',
|
||||
//'info.text-color': '#000000',
|
||||
'browseroutput.background-color': 'none',
|
||||
'browseroutput.text-color': '#000000',
|
||||
'outputwindow.background-color': 'none',
|
||||
'outputwindow.text-color': '#000000',
|
||||
'mainwindow.background-color': 'none',
|
||||
'split.background-color': 'none',
|
||||
//'split.background-color': 'none',
|
||||
// Buttons
|
||||
'changelog.background-color': 'none',
|
||||
'changelog.text-color': '#000000',
|
||||
'rules.background-color': 'none',
|
||||
'rules.text-color': '#000000',
|
||||
'wiki.background-color': 'none',
|
||||
'wiki.text-color': '#000000',
|
||||
'forum.background-color': 'none',
|
||||
'forum.text-color': '#000000',
|
||||
//'rules.background-color': 'none',
|
||||
//'rules.text-color': '#000000',
|
||||
//'wiki.background-color': 'none',
|
||||
//'wiki.text-color': '#000000',
|
||||
//'forum.background-color': 'none',
|
||||
//'forum.text-color': '#000000',
|
||||
'github.background-color': 'none',
|
||||
'github.text-color': '#000000',
|
||||
'report-issue.background-color': 'none',
|
||||
'report-issue.text-color': '#000000',
|
||||
//'report-issue.background-color': 'none',
|
||||
//'report-issue.text-color': '#000000',
|
||||
// Status and verb tabs
|
||||
'output.background-color': 'none',
|
||||
'output.text-color': '#000000',
|
||||
'statwindow.background-color': 'none',
|
||||
'statwindow.text-color': '#000000',
|
||||
'stat.background-color': '#FFFFFF',
|
||||
'stat.tab-background-color': 'none',
|
||||
'stat.text-color': '#000000',
|
||||
'stat.tab-text-color': '#000000',
|
||||
'stat.prefix-color': '#000000',
|
||||
'stat.suffix-color': '#000000',
|
||||
//'stat.background-color': '#FFFFFF',
|
||||
//'stat.tab-background-color': 'none',
|
||||
//'stat.text-color': '#000000',
|
||||
//'stat.tab-text-color': '#000000',
|
||||
//'stat.prefix-color': '#000000',
|
||||
//'stat.suffix-color': '#000000',
|
||||
// Say, OOC, me Buttons etc.
|
||||
'saybutton.background-color': 'none',
|
||||
'saybutton.text-color': '#000000',
|
||||
'oocbutton.background-color': 'none',
|
||||
'oocbutton.text-color': '#000000',
|
||||
'mebutton.background-color': 'none',
|
||||
'mebutton.text-color': '#000000',
|
||||
//'oocbutton.background-color': 'none',
|
||||
//'oocbutton.text-color': '#000000',
|
||||
//'mebutton.background-color': 'none',
|
||||
//'mebutton.text-color': '#000000',
|
||||
'asset_cache_browser.background-color': 'none',
|
||||
'asset_cache_browser.text-color': '#000000',
|
||||
'tooltip.background-color': 'none',
|
||||
@@ -114,8 +114,8 @@ export function setClientTheme(name) {
|
||||
'rpanewindow.background-color': COLOR_DARK_BG_DARKER,
|
||||
'rpanewindow.text-color': COLOR_DARK_TEXT,
|
||||
'mainvsplit.background-color': COLOR_DARK_BG,
|
||||
'info.tab-background-color': COLOR_DARK_BG,
|
||||
'info.tab-text-color': COLOR_DARK_TEXT,
|
||||
//'info.tab-background-color': COLOR_DARK_BG,
|
||||
//'info.tab-text-color': COLOR_DARK_TEXT,
|
||||
'mapb.background-color': '#494949',
|
||||
'mapb.text-color': COLOR_DARK_TEXT,
|
||||
'discord.background-color': '#494949',
|
||||
@@ -136,8 +136,8 @@ export function setClientTheme(name) {
|
||||
// Main windows
|
||||
'infowindow.background-color': COLOR_DARK_BG,
|
||||
'infowindow.text-color': COLOR_DARK_TEXT,
|
||||
'info.background-color': COLOR_DARK_BG,
|
||||
'info.text-color': COLOR_DARK_TEXT,
|
||||
//'info.background-color': COLOR_DARK_BG,
|
||||
//'info.text-color': COLOR_DARK_TEXT,
|
||||
'browseroutput.background-color': COLOR_DARK_BG,
|
||||
'browseroutput.text-color': COLOR_DARK_TEXT,
|
||||
'outputwindow.background-color': COLOR_DARK_BG,
|
||||
@@ -147,16 +147,16 @@ export function setClientTheme(name) {
|
||||
// Buttons
|
||||
'changelog.background-color': '#494949',
|
||||
'changelog.text-color': COLOR_DARK_TEXT,
|
||||
'rules.background-color': '#494949',
|
||||
'rules.text-color': COLOR_DARK_TEXT,
|
||||
//'rules.background-color': '#494949',
|
||||
//'rules.text-color': COLOR_DARK_TEXT,
|
||||
'wiki.background-color': '#494949',
|
||||
'wiki.text-color': COLOR_DARK_TEXT,
|
||||
'forum.background-color': '#494949',
|
||||
'forum.text-color': COLOR_DARK_TEXT,
|
||||
'github.background-color': '#3a3a3a',
|
||||
'github.text-color': COLOR_DARK_TEXT,
|
||||
'report-issue.background-color': '#492020',
|
||||
'report-issue.text-color': COLOR_DARK_TEXT,
|
||||
//'report-issue.background-color': '#492020',
|
||||
//'report-issue.text-color': COLOR_DARK_TEXT,
|
||||
// Status and verb tabs
|
||||
'output.background-color': COLOR_DARK_BG_DARKER,
|
||||
'output.text-color': COLOR_DARK_TEXT,
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Box, Tooltip } from 'tgui-core/components';
|
||||
import { ACCESS_FLAGS } from './constants';
|
||||
|
||||
export const AccessTypeDisplay = (props: { type: number }) => {
|
||||
const { type } = props;
|
||||
|
||||
const names = ACCESS_FLAGS.filter((flag) => type & flag.bit).map(
|
||||
(f) => f.label,
|
||||
);
|
||||
const allFlags = ACCESS_FLAGS.reduce((acc, f) => acc | f.bit, 0);
|
||||
|
||||
const label =
|
||||
names.length === 0
|
||||
? 'None'
|
||||
: type === allFlags
|
||||
? 'All'
|
||||
: names.length > 1
|
||||
? 'Multiple'
|
||||
: names[0];
|
||||
|
||||
const tooltip =
|
||||
names.length > 1 || type === allFlags ? names.join(', ') : undefined;
|
||||
|
||||
return (
|
||||
<Tooltip content={tooltip}>
|
||||
<Box>{label}</Box>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
export enum region_ids {
|
||||
None = -1,
|
||||
All = 0,
|
||||
Security,
|
||||
Medbay,
|
||||
Research,
|
||||
Engineering,
|
||||
Command,
|
||||
General,
|
||||
Supply,
|
||||
}
|
||||
|
||||
enum access_types {
|
||||
None = 0,
|
||||
Centcom = 1,
|
||||
Station = 2,
|
||||
Syndicate = 4,
|
||||
Private = 8,
|
||||
}
|
||||
|
||||
export const ACCESS_FLAGS = [
|
||||
{ bit: access_types.Centcom, label: 'Centcom' },
|
||||
{ bit: access_types.Station, label: 'Station' },
|
||||
{ bit: access_types.Syndicate, label: 'Syndicate' },
|
||||
{ bit: access_types.Private, label: 'Private' },
|
||||
];
|
||||
@@ -0,0 +1,106 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { useBackend } from 'tgui/backend';
|
||||
import { Window } from 'tgui/layouts';
|
||||
import { Button, Divider, Input, Section, Table } from 'tgui-core/components';
|
||||
import { createSearch } from 'tgui-core/string';
|
||||
import { AccessTypeDisplay } from './AccessTypeDisplay';
|
||||
import { region_ids } from './constants';
|
||||
import type { Access, Data } from './types';
|
||||
|
||||
export const AccessViewer = (props) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
const { access_list, name, coords, req_access, req_one_access } = data;
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const access_regions: Record<number, Access[]> = {
|
||||
[region_ids.None]: [],
|
||||
[region_ids.Security]: [],
|
||||
[region_ids.Medbay]: [],
|
||||
[region_ids.Research]: [],
|
||||
[region_ids.Engineering]: [],
|
||||
[region_ids.Command]: [],
|
||||
[region_ids.General]: [],
|
||||
[region_ids.Supply]: [],
|
||||
};
|
||||
|
||||
const search = createSearch<Access>(searchText.toLowerCase(), (entry) =>
|
||||
`${entry.id}: ${entry.name}`.toLowerCase(),
|
||||
);
|
||||
|
||||
access_list.forEach((entry) => {
|
||||
entry.has_req = req_access?.includes(entry.id);
|
||||
entry.has_req_one = req_one_access?.includes(entry.id);
|
||||
|
||||
if (search(entry)) {
|
||||
access_regions[entry.region].push(entry);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Window width={620} height={540}>
|
||||
<Window.Content>
|
||||
<Section
|
||||
fill
|
||||
title={`${name}'s access at ${coords}`}
|
||||
scrollable
|
||||
buttons={
|
||||
<Input
|
||||
width="200px"
|
||||
value={searchText}
|
||||
onChange={setSearchText}
|
||||
placeholder="Search for access..."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Table>
|
||||
{Object.keys(access_regions).map((key, index) => (
|
||||
<Fragment key={key}>
|
||||
{index > 0 && (
|
||||
<Table.Row>
|
||||
<Table.Cell colSpan={4}>
|
||||
<Divider />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
<Table.Row header>
|
||||
<Table.Cell colSpan={4}>{region_ids[key]}</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell colSpan={4}>
|
||||
<Divider />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{access_regions[key].map((entry: Access) => (
|
||||
<Table.Row key={entry.id}>
|
||||
<Table.Cell
|
||||
collapsing
|
||||
>{`${entry.id}: ${entry.name}`}</Table.Cell>
|
||||
<Table.Cell collapsing>
|
||||
<Button.Checkbox
|
||||
checked={entry.has_req}
|
||||
onClick={() => act('req_all', { set_id: entry.id })}
|
||||
>
|
||||
Requires
|
||||
</Button.Checkbox>
|
||||
</Table.Cell>
|
||||
<Table.Cell collapsing>
|
||||
<Button.Checkbox
|
||||
checked={entry.has_req_one}
|
||||
onClick={() => act('req_one', { set_id: entry.id })}
|
||||
>
|
||||
Have Any
|
||||
</Button.Checkbox>
|
||||
</Table.Cell>
|
||||
<Table.Cell collapsing color="label">
|
||||
<AccessTypeDisplay type={entry.access_type} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { BooleanLike } from 'tgui-core/react';
|
||||
|
||||
export type Data = {
|
||||
access_list: Access[];
|
||||
name?: string;
|
||||
coords?: string;
|
||||
req_access?: number[];
|
||||
req_one_access?: number[];
|
||||
};
|
||||
|
||||
export type Access = {
|
||||
name: string;
|
||||
id: number;
|
||||
region: number;
|
||||
access_type: number;
|
||||
has_req: BooleanLike;
|
||||
has_req_one: BooleanLike;
|
||||
};
|
||||
@@ -2269,6 +2269,7 @@
|
||||
#include "code\game\turfs\unsimulated\walls.dm"
|
||||
#include "code\js\byjax.dm"
|
||||
#include "code\matrices\color_matrix.dm"
|
||||
#include "code\modules\admin\access_viewer.dm"
|
||||
#include "code\modules\admin\admin.dm"
|
||||
#include "code\modules\admin\admin_attack_log.dm"
|
||||
#include "code\modules\admin\admin_investigate.dm"
|
||||
|
||||
Reference in New Issue
Block a user