mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-22 19:47:22 +01:00
Creates login plugin for TGUI to streamline and unify login frontend and backend
This commit is contained in:
@@ -14,9 +14,6 @@
|
||||
icon_screen = "medcomp"
|
||||
req_one_access = list(ACCESS_MEDICAL, ACCESS_FORENSICS_LOCKERS)
|
||||
circuit = /obj/item/circuitboard/med_data
|
||||
var/obj/item/card/id/scan = null
|
||||
var/authenticated = null
|
||||
var/rank = null
|
||||
var/screen = null
|
||||
var/datum/data/record/active1 = null
|
||||
var/datum/data/record/active2 = null
|
||||
@@ -65,11 +62,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/med_data/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/card/id) && !scan)
|
||||
usr.drop_item()
|
||||
O.forceMove(src)
|
||||
scan = O
|
||||
tgui_interact(user)
|
||||
if(tgui_login_attackby(O, user))
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -92,14 +85,10 @@
|
||||
/obj/machinery/computer/med_data/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["temp"] = temp
|
||||
data["scan"] = scan ? scan.name : null
|
||||
data["authenticated"] = authenticated
|
||||
data["rank"] = rank
|
||||
data["screen"] = screen
|
||||
data["printing"] = printing
|
||||
data["isAI"] = isAI(user)
|
||||
data["isRobot"] = isrobot(user)
|
||||
if(authenticated)
|
||||
tgui_login_data(data, user)
|
||||
if(data["loginState"]["logged_in"])
|
||||
switch(screen)
|
||||
if(MED_DATA_R_LIST)
|
||||
if(!isnull(GLOB.data_core.general))
|
||||
@@ -199,58 +188,21 @@
|
||||
. = TRUE
|
||||
if(tgui_act_modal(action, params))
|
||||
return
|
||||
if(tgui_login_act(action, params))
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("cleartemp")
|
||||
temp = null
|
||||
if("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("login")
|
||||
var/login_type = text2num(params["login_type"])
|
||||
if(login_type == LOGIN_TYPE_NORMAL && istype(scan))
|
||||
if(check_access(scan))
|
||||
authenticated = scan.registered_name
|
||||
rank = scan.assignment
|
||||
else if(login_type == LOGIN_TYPE_AI && isAI(usr))
|
||||
authenticated = usr.name
|
||||
rank = "AI"
|
||||
else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr))
|
||||
authenticated = usr.name
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
rank = "[R.modtype] [R.braintype]"
|
||||
if(authenticated)
|
||||
active1 = null
|
||||
active2 = null
|
||||
screen = MED_DATA_R_LIST
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(authenticated)
|
||||
if(tgui_login_get().logged_in)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("logout")
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
authenticated = null
|
||||
screen = null
|
||||
active1 = null
|
||||
active2 = null
|
||||
if("screen")
|
||||
screen = clamp(text2num(params["screen"]) || 0, MED_DATA_R_LIST, MED_DATA_MEDBOT)
|
||||
active1 = null
|
||||
@@ -403,10 +355,11 @@
|
||||
else if(istype(active1) && (field in active1.fields))
|
||||
active1.fields[field] = answer
|
||||
if("add_c")
|
||||
if(!length(answer) || !istype(active2) || !length(authenticated))
|
||||
var/datum/tgui_login/state = tgui_login_get()
|
||||
if(!length(answer) || !istype(active2) || !length(state.name))
|
||||
return
|
||||
active2.fields["comments"] += list(list(
|
||||
header = "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]",
|
||||
header = "Made by [state.name] ([state.name]) on [GLOB.current_date_string] [station_time_timestamp()]",
|
||||
text = answer
|
||||
))
|
||||
else
|
||||
@@ -493,6 +446,10 @@
|
||||
|
||||
..(severity)
|
||||
|
||||
/obj/machinery/computer/med_data/tgui_login_on_login(datum/tgui_login/state)
|
||||
active1 = null
|
||||
active2 = null
|
||||
screen = MED_DATA_R_LIST
|
||||
|
||||
/obj/machinery/computer/med_data/laptop
|
||||
name = "medical laptop"
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* tgui login
|
||||
*
|
||||
* Allows the handling of logins using IDs within tgui.
|
||||
*
|
||||
* Two key procs:
|
||||
* * [/obj/proc/tgui_login_act] - Call in your tgui_act() proc to catch any login actions and handle them.
|
||||
* * [/obj/proc/tgui_login_data] - Call in your tgui_data() proc to pass login info.
|
||||
*
|
||||
* How to use (DM side):
|
||||
* 1. Call [/obj/proc/tgui_login_act] at the start of your tgui_act() proc
|
||||
* 2. Call [/obj/proc/tgui_login_data] in your tgui_data() proc while passing the data list
|
||||
* 3. In your object, call [/obj/proc/tgui_login_get] to get the current login state.
|
||||
* 4. Optional: call [/obj/proc/tgui_login_attackby] in your attackby() to make the login process easier.
|
||||
*
|
||||
* How to use (JS side): Use the <LoginScreen /> and <LoginInfo /> interfaces.
|
||||
*/
|
||||
|
||||
GLOBAL_LIST(tgui_logins)
|
||||
|
||||
/**
|
||||
* Call this from a proc that is called in tgui_act() to process login actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The called action
|
||||
* * params - The params to the action
|
||||
*/
|
||||
/obj/proc/tgui_login_act(action = "", params)
|
||||
. = null
|
||||
switch(action)
|
||||
if("login_insert")
|
||||
var/datum/tgui_login/state = tgui_login_get()
|
||||
if(state.id) // An ID is already inserted, eject it
|
||||
return tgui_login_eject(state = state)
|
||||
else // No ID, attempt to insert one in
|
||||
return tgui_login_insert(usr.get_active_hand(), state = state)
|
||||
if("login_eject")
|
||||
return tgui_login_eject()
|
||||
if("login_login")
|
||||
return tgui_login_login(text2num(params["login_type"]))
|
||||
if("login_logout")
|
||||
return tgui_login_logout()
|
||||
|
||||
/**
|
||||
* Adds login state data.
|
||||
*
|
||||
* Arguments:
|
||||
* * data - The data list to be returned
|
||||
* * user - The user calling tgui_data()
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_data(list/data, mob/user, datum/tgui_login/state = tgui_login_get())
|
||||
data["loginState"] = list(
|
||||
"id" = state.id ? state.id.name : null,
|
||||
"name" = state.name,
|
||||
"rank" = state.rank,
|
||||
"logged_in" = state.logged_in,
|
||||
)
|
||||
data["isAI"] = isAI(user)
|
||||
data["isRobot"] = isrobot(user)
|
||||
|
||||
/**
|
||||
* Convenience function to perform login actions when
|
||||
* the source object is hit by specific items.
|
||||
*
|
||||
* Arguments:
|
||||
* * O - The object
|
||||
* * user - The user
|
||||
*/
|
||||
/obj/proc/tgui_login_attackby(obj/item/O, mob/user)
|
||||
if(istype(O, /obj/item/card/id) && tgui_login_insert(O))
|
||||
tgui_interact(user)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Attempts to insert an object as an ID.
|
||||
*
|
||||
* Arguments:
|
||||
* * O - The object to try inserting
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_insert(obj/item/O, datum/tgui_login/state = tgui_login_get())
|
||||
if(state.id)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/card/id))
|
||||
// Move the ID inside
|
||||
usr.drop_item()
|
||||
O.forceMove(src)
|
||||
|
||||
// Update the state
|
||||
state.id = O
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Attempts to eject the inserted ID.
|
||||
*
|
||||
* Arguments:
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_eject(datum/tgui_login/state = tgui_login_get())
|
||||
if(!state.id)
|
||||
return
|
||||
|
||||
// Drop the ID
|
||||
state.id.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(state.id)
|
||||
|
||||
// Update the state
|
||||
state.id = null
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* 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
|
||||
* * 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)
|
||||
return
|
||||
|
||||
if(login_type == LOGIN_TYPE_NORMAL)
|
||||
if(check_access(state.id))
|
||||
state.name = state.id.registered_name
|
||||
state.rank = state.id.assignment
|
||||
else if(login_type == LOGIN_TYPE_AI && isAI(usr))
|
||||
state.name = usr.name
|
||||
state.rank = "AI"
|
||||
else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr))
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
state.name = usr.name
|
||||
state.rank = "[R.modtype] [R.braintype]"
|
||||
|
||||
state.logged_in = TRUE
|
||||
tgui_login_on_login(state = state)
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Attempts to log out.
|
||||
*
|
||||
* Arguments:
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_logout(datum/tgui_login/state = tgui_login_get())
|
||||
if(!state.logged_in)
|
||||
return
|
||||
|
||||
state.name = state.rank = ""
|
||||
state.logged_in = FALSE
|
||||
tgui_login_on_logout(state = state)
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Returns (or creates) the login state for the source object.
|
||||
*
|
||||
* Arguments:
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_get()
|
||||
. = LAZYACCESS(GLOB.tgui_logins, UID())
|
||||
if(!.)
|
||||
LAZYINITLIST(GLOB.tgui_logins)
|
||||
. = GLOB.tgui_logins[UID()] = new /datum/tgui_login
|
||||
|
||||
/**
|
||||
* Called on successful login.
|
||||
*
|
||||
* Arguments:
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_on_login(datum/tgui_login/state = tgui_login_get())
|
||||
return
|
||||
|
||||
/**
|
||||
* Called on successful logout.
|
||||
*
|
||||
* Arguments:
|
||||
* * state - The current login state
|
||||
*/
|
||||
/obj/proc/tgui_login_on_logout(datum/tgui_login/state = tgui_login_get())
|
||||
return
|
||||
|
||||
/**
|
||||
* Login state (there should be only one for one datum)
|
||||
*/
|
||||
/datum/tgui_login
|
||||
var/obj/item/card/id/id = null
|
||||
var/name = ""
|
||||
var/rank = ""
|
||||
var/logged_in = FALSE
|
||||
|
||||
/datum/tgui_login/New(id, name, rank)
|
||||
src.id = id
|
||||
src.name = name
|
||||
src.rank = rank
|
||||
+2
-1
@@ -2472,12 +2472,13 @@
|
||||
#include "code\modules\telesci\telepad.dm"
|
||||
#include "code\modules\telesci\telesci_computer.dm"
|
||||
#include "code\modules\tgui\external.dm"
|
||||
#include "code\modules\tgui\modal.dm"
|
||||
#include "code\modules\tgui\states.dm"
|
||||
#include "code\modules\tgui\tgui.dm"
|
||||
#include "code\modules\tgui\modules\_base.dm"
|
||||
#include "code\modules\tgui\modules\crew_monitor.dm"
|
||||
#include "code\modules\tgui\modules\ert_manager.dm"
|
||||
#include "code\modules\tgui\plugins\login.dm"
|
||||
#include "code\modules\tgui\plugins\modal.dm"
|
||||
#include "code\modules\tgui\states\admin.dm"
|
||||
#include "code\modules\tgui\states\always.dm"
|
||||
#include "code\modules\tgui\states\conscious.dm"
|
||||
|
||||
@@ -57,10 +57,10 @@ const virusModalBodyOverride = (modal, context) => {
|
||||
export const MedicalRecords = (_properties, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
authenticated,
|
||||
loginState,
|
||||
screen,
|
||||
} = data;
|
||||
if (!authenticated) {
|
||||
if (!loginState.logged_in) {
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content>
|
||||
|
||||
@@ -2,18 +2,16 @@ import { useBackend } from '../../backend';
|
||||
import { Box, Button, NoticeBox } from '../../components';
|
||||
|
||||
/**
|
||||
* Displays a notice box showing the
|
||||
* `authenticated` and `rank` data fields if they exist.
|
||||
* Displays a notice box displaying the current login state.
|
||||
*
|
||||
* Also gives an option to log off (calls `logout` TGUI action)
|
||||
* Also gives an option to log off (calls `login_logout` TGUI action)
|
||||
* @param {object} _properties
|
||||
* @param {object} context
|
||||
*/
|
||||
export const LoginInfo = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
authenticated,
|
||||
rank,
|
||||
loginState,
|
||||
} = data;
|
||||
if (!data) {
|
||||
return;
|
||||
@@ -21,14 +19,22 @@ export const LoginInfo = (_properties, context) => {
|
||||
return (
|
||||
<NoticeBox info>
|
||||
<Box display="inline-block" verticalAlign="middle">
|
||||
Logged in as: {authenticated} ({rank})
|
||||
Logged in as: {loginState.name} ({loginState.rank})
|
||||
</Box>
|
||||
<Button
|
||||
icon="sign-out-alt"
|
||||
content="Logout and Eject ID"
|
||||
content="Logout"
|
||||
color="good"
|
||||
float="right"
|
||||
onClick={() => act('logout')}
|
||||
onClick={() => act('login_logout')}
|
||||
/>
|
||||
<Button
|
||||
icon="sign-out-alt"
|
||||
disabled={!loginState.id}
|
||||
content="Eject ID"
|
||||
color="good"
|
||||
float="right"
|
||||
onClick={() => act('login_eject')}
|
||||
/>
|
||||
<Box clear="both" />
|
||||
</NoticeBox>
|
||||
|
||||
@@ -5,19 +5,19 @@ import { Box, Button, Flex, Icon, Section } from '../../components';
|
||||
* Displays a login screen that users can interact with
|
||||
* using an ID card in their hand.
|
||||
* Required data fields:
|
||||
* * `scan` — The name of the currently inserted ID
|
||||
* * `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"
|
||||
*
|
||||
* Clicking the main button calls the `scan` TGUI act.
|
||||
* Clicking the main button calls the `login_insert` TGUI act.
|
||||
* Clicking either the AI or normal login button calls
|
||||
* the `login` TGUI act with the a `login_type` parameter with the value:
|
||||
* the `login_login` TGUI act with a `login_type` parameter:
|
||||
* * 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
|
||||
*
|
||||
* You will have to handle the AI login case in the same action.
|
||||
* The normal login button is only available when `scan` is not null.
|
||||
* 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
|
||||
* @param {object} _properties
|
||||
* @param {object} context
|
||||
@@ -25,7 +25,7 @@ import { Box, Button, Flex, Icon, Section } from '../../components';
|
||||
export const LoginScreen = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
scan,
|
||||
loginState,
|
||||
isAI,
|
||||
isRobot,
|
||||
} = data;
|
||||
@@ -46,16 +46,16 @@ export const LoginScreen = (_properties, context) => {
|
||||
ID:
|
||||
<Button
|
||||
icon="id-card"
|
||||
content={scan ? scan : "----------"}
|
||||
content={loginState.id ? loginState.id : "----------"}
|
||||
ml="0.5rem"
|
||||
onClick={() => act('scan')}
|
||||
onClick={() => act('login_insert')}
|
||||
/>
|
||||
</Box>
|
||||
<Button
|
||||
icon="sign-in-alt"
|
||||
disabled={!scan}
|
||||
disabled={!loginState.id}
|
||||
content="Login"
|
||||
onClick={() => act('login', {
|
||||
onClick={() => act('login_login', {
|
||||
login_type: 1,
|
||||
})}
|
||||
/>
|
||||
@@ -63,7 +63,7 @@ export const LoginScreen = (_properties, context) => {
|
||||
<Button
|
||||
icon="sign-in-alt"
|
||||
content="Login as AI"
|
||||
onClick={() => act('login', {
|
||||
onClick={() => act('login_login', {
|
||||
login_type: 2,
|
||||
})}
|
||||
/>
|
||||
@@ -72,7 +72,7 @@ export const LoginScreen = (_properties, context) => {
|
||||
<Button
|
||||
icon="sign-in-alt"
|
||||
content="Login as Cyborg"
|
||||
onClick={() => act('login', {
|
||||
onClick={() => act('login_login', {
|
||||
login_type: 3,
|
||||
})}
|
||||
/>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user