mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 02:09:41 +00:00
Merge pull request #2056 from CHOMPStationBot/upstream-merge-10316
[MIRROR] [MIRROR] Ports Nebula's Discord Webhook Integration
This commit is contained in:
@@ -166,3 +166,9 @@
|
||||
|
||||
#define COLOR_ASTEROID_ROCK "#735555"
|
||||
#define COLOR_GOLD "#ffcc33"
|
||||
|
||||
// Discord requires colors to be in decimal instead of hexadecimal.
|
||||
#define COLOR_WEBHOOK_DEFAULT 0x8bbbd5 // "#8bbbd5"
|
||||
#define COLOR_WEBHOOK_GOOD 0x2ECC71 // "#2ECC71"
|
||||
#define COLOR_WEBHOOK_POOR 0xE67E22 // "#E67E22"
|
||||
#define COLOR_WEBHOOK_BAD 0xE74C3C // "#E74C3C"
|
||||
@@ -448,4 +448,17 @@ GLOBAL_LIST_INIT(all_volume_channels, list(
|
||||
|
||||
#define LOADOUT_WHITELIST_OFF 0
|
||||
#define LOADOUT_WHITELIST_LAX 1
|
||||
#define LOADOUT_WHITELIST_STRICT 2
|
||||
#define LOADOUT_WHITELIST_STRICT 2
|
||||
|
||||
|
||||
#ifndef WINDOWS_HTTP_POST_DLL_LOCATION
|
||||
#define WINDOWS_HTTP_POST_DLL_LOCATION "lib/byhttp.dll"
|
||||
#endif
|
||||
|
||||
#ifndef UNIX_HTTP_POST_DLL_LOCATION
|
||||
#define UNIX_HTTP_POST_DLL_LOCATION "lib/libbyhttp.so"
|
||||
#endif
|
||||
|
||||
#ifndef HTTP_POST_DLL_LOCATION
|
||||
#define HTTP_POST_DLL_LOCATION (world.system_type == MS_WINDOWS ? WINDOWS_HTTP_POST_DLL_LOCATION : UNIX_HTTP_POST_DLL_LOCATION)
|
||||
#endif
|
||||
@@ -52,6 +52,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
|
||||
// Subsystem init_order, from highest priority to lowest priority
|
||||
// Subsystems shutdown in the reverse of the order they initialize in
|
||||
// The numbers just define the ordering, they are meaningless otherwise.
|
||||
#define INIT_ORDER_WEBHOOKS 50
|
||||
#define INIT_ORDER_DBCORE 41 //CHOMPEdit
|
||||
#define INIT_ORDER_SQLITE 40
|
||||
#define INIT_ORDER_CHEMISTRY 35
|
||||
|
||||
10
code/__defines/webhooks.dm
Normal file
10
code/__defines/webhooks.dm
Normal file
@@ -0,0 +1,10 @@
|
||||
// Please don't forget to update the webhooks page on the GitHub Wiki page with your new webhook ID.
|
||||
#define WEBHOOK_ROUNDEND "webhook_roundend"
|
||||
#define WEBHOOK_ROUNDPREP "webhook_roundprep"
|
||||
#define WEBHOOK_ROUNDSTART "webhook_roundstart"
|
||||
|
||||
#define WEBHOOK_SUBMAP_LOADED "webhook_submap_loaded"
|
||||
#define WEBHOOK_CUSTOM_EVENT "webhook_custom_event"
|
||||
#define WEBHOOK_ELEVATOR_FALL "webhook_elevator_fall"
|
||||
#define WEBHOOK_AHELP_SENT "webhook_ahelp_sent"
|
||||
#define WEBHOOK_FAX_SENT "webhook_fax_sent"
|
||||
@@ -855,4 +855,15 @@ proc/dd_sortedTextList(list/incoming)
|
||||
result += pick(shifts)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
var/global/list/json_cache = list()
|
||||
/proc/cached_json_decode(var/json_to_decode)
|
||||
if(!json_to_decode || !length(json_to_decode))
|
||||
return list()
|
||||
try
|
||||
if(isnull(global.json_cache[json_to_decode]))
|
||||
global.json_cache[json_to_decode] = json_decode(json_to_decode)
|
||||
. = global.json_cache[json_to_decode]
|
||||
catch(var/exception/e)
|
||||
log_error("Exception during JSON decoding ([json_to_decode]): [e]")
|
||||
return list()
|
||||
@@ -509,3 +509,23 @@ proc/TextPreview(var/string,var/len=40)
|
||||
var/charcount = count - length_char(text)
|
||||
var/list/chars_to_add[max(charcount + 1, 0)]
|
||||
return text + jointext(chars_to_add, char)
|
||||
|
||||
//Readds quotes and apostrophes to HTML-encoded strings
|
||||
/proc/readd_quotes(var/t)
|
||||
var/list/repl_chars = list(""" = "\"","'" = "'")
|
||||
for(var/char in repl_chars)
|
||||
var/index = findtext(t, char)
|
||||
while(index)
|
||||
t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index+5)
|
||||
index = findtext(t, char)
|
||||
return t
|
||||
|
||||
// Rips out paper HTML but tries to keep it semi-readable.
|
||||
/proc/paper_html_to_plaintext(paper_text)
|
||||
paper_text = replacetext(paper_text, "<hr>", "-----")
|
||||
paper_text = replacetext(paper_text, "<li>", "- ") // This makes ordered lists turn into unordered but fixing that is too much effort.
|
||||
paper_text = replacetext(paper_text, "</li>", "\n")
|
||||
paper_text = replacetext(paper_text, "<p>", "\n")
|
||||
paper_text = replacetext(paper_text, "<br>", "\n")
|
||||
paper_text = strip_html_properly(paper_text) // Get rid of everything else entirely.
|
||||
return paper_text
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//Readds quotes and apostrophes to HTML-encoded strings
|
||||
/proc/readd_quotes(var/t)
|
||||
var/list/repl_chars = list(""" = "\"","'" = "'")
|
||||
for(var/char in repl_chars)
|
||||
var/index = findtext(t, char)
|
||||
while(index)
|
||||
t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index+5)
|
||||
index = findtext(t, char)
|
||||
return t
|
||||
@@ -397,3 +397,17 @@
|
||||
return /datum
|
||||
|
||||
return text2path(copytext(string_type, 1, last_slash))
|
||||
|
||||
//checks if a file exists and contains text
|
||||
//returns text as a string if these conditions are met
|
||||
/proc/safe_file2text(filename, error_on_invalid_return = TRUE)
|
||||
try
|
||||
if(fexists(filename))
|
||||
. = file2text(filename)
|
||||
if(!. && error_on_invalid_return)
|
||||
error("File empty ([filename])")
|
||||
else if(error_on_invalid_return)
|
||||
error("File not found ([filename])")
|
||||
catch(var/exception/E)
|
||||
if(error_on_invalid_return)
|
||||
error("Exception when loading file as string: [E]")
|
||||
@@ -292,6 +292,8 @@ var/list/gamemode_cache = list()
|
||||
|
||||
var/static/vgs_access_identifier = null // VOREStation Edit - VGS
|
||||
var/static/vgs_server_port = null // VOREStation Edit - VGS
|
||||
|
||||
var/disable_webhook_embeds = FALSE
|
||||
|
||||
/datum/configuration/New()
|
||||
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
|
||||
@@ -1017,6 +1019,9 @@ var/list/gamemode_cache = list()
|
||||
|
||||
if("use_loyalty_implants")
|
||||
config.use_loyalty_implants = 1
|
||||
|
||||
if("loadout_whitelist")
|
||||
config.loadout_whitelist = text2num(value)
|
||||
|
||||
else
|
||||
log_misc("Unknown setting in configuration: '[name]'")
|
||||
|
||||
@@ -49,6 +49,13 @@ var/global/datum/controller/subsystem/ticker/ticker
|
||||
/datum/controller/subsystem/ticker/Initialize()
|
||||
pregame_timeleft = config.pregame_time
|
||||
send2mainirc("Server lobby is loaded and open at byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]")
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_ROUNDPREP,
|
||||
list(
|
||||
"map" = station_name(),
|
||||
"url" = get_world_url()
|
||||
)
|
||||
)
|
||||
GLOB.autospeaker = new (null, null, null, 1) //Set up Global Announcer
|
||||
return ..()
|
||||
|
||||
|
||||
94
code/controllers/subsystems/webhooks.dm
Normal file
94
code/controllers/subsystems/webhooks.dm
Normal file
@@ -0,0 +1,94 @@
|
||||
SUBSYSTEM_DEF(webhooks)
|
||||
name = "Webhooks"
|
||||
init_order = INIT_ORDER_WEBHOOKS
|
||||
flags = SS_NO_FIRE
|
||||
var/list/webhook_decls = list()
|
||||
|
||||
/datum/controller/subsystem/webhooks/Initialize()
|
||||
load_webhooks()
|
||||
. = ..()
|
||||
|
||||
/datum/controller/subsystem/webhooks/proc/load_webhooks()
|
||||
|
||||
if(!fexists(HTTP_POST_DLL_LOCATION))
|
||||
to_world_log("Unable to locate HTTP POST lib at [HTTP_POST_DLL_LOCATION], webhooks will not function on this run.")
|
||||
return
|
||||
|
||||
var/list/all_webhooks_by_id = list()
|
||||
var/list/all_webhooks = decls_repository.get_decls_of_subtype(/decl/webhook)
|
||||
for(var/wid in all_webhooks)
|
||||
var/decl/webhook/webhook = all_webhooks[wid]
|
||||
if(webhook.id)
|
||||
all_webhooks_by_id[webhook.id] = webhook
|
||||
|
||||
webhook_decls.Cut()
|
||||
var/webhook_config = safe_file2text("config/webhooks.json")
|
||||
if(webhook_config)
|
||||
for(var/webhook_data in cached_json_decode(webhook_config))
|
||||
var/wid = webhook_data["id"]
|
||||
var/wurl = webhook_data["url"]
|
||||
var/list/wmention = webhook_data["mentions"]
|
||||
if(wmention && !islist(wmention))
|
||||
wmention = list(wmention)
|
||||
to_world_log("Setting up webhook [wid].")
|
||||
if(wid && wurl && all_webhooks_by_id[wid])
|
||||
var/decl/webhook/webhook = all_webhooks_by_id[wid]
|
||||
webhook.urls = islist(wurl) ? wurl : list(wurl)
|
||||
for(var/url in webhook.urls)
|
||||
if(!webhook.urls[url])
|
||||
webhook.urls[url] = list()
|
||||
else if(!islist(webhook.urls[url]))
|
||||
webhook.urls[url] = list(webhook.urls[url])
|
||||
if(wmention)
|
||||
webhook.mentions = wmention?.Copy()
|
||||
webhook_decls[wid] = webhook
|
||||
to_world_log("Webhook [wid] ready.")
|
||||
else
|
||||
to_world_log("Failed to set up webhook [wid].")
|
||||
|
||||
/datum/controller/subsystem/webhooks/proc/send(var/wid, var/wdata)
|
||||
var/decl/webhook/webhook = webhook_decls[wid]
|
||||
if(webhook)
|
||||
if(webhook.send(wdata))
|
||||
to_world_log("Sent webhook [webhook.id].")
|
||||
log_debug("Webhook sent: [webhook.id].")
|
||||
else
|
||||
to_world_log("Failed to send webhook [webhook.id].")
|
||||
log_debug("Webhook failed to send: [webhook.id].")
|
||||
|
||||
/client/proc/reload_webhooks()
|
||||
set name = "Reload Webhooks"
|
||||
set category = "Debug"
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
if(!SSwebhooks.subsystem_initialized)
|
||||
to_chat(usr, SPAN_WARNING("Let the webhook subsystem initialize before trying to reload it."))
|
||||
return
|
||||
|
||||
to_world_log("[usr.key] has reloaded webhooks.")
|
||||
log_and_message_admins("has reloaded webhooks.")
|
||||
SSwebhooks.load_webhooks()
|
||||
|
||||
/client/proc/ping_webhook()
|
||||
set name = "Ping Webhook"
|
||||
set category = "Debug"
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
if(!length(SSwebhooks.webhook_decls))
|
||||
to_chat(usr, SPAN_WARNING("Webhook list is empty; either webhooks are disabled, webhooks aren't configured, or the subsystem hasn't initialized."))
|
||||
return
|
||||
|
||||
var/choice = input(usr, "Select a webhook to ping.", "Ping Webhook") as null|anything in SSwebhooks.webhook_decls
|
||||
if(choice && SSwebhooks.webhook_decls[choice])
|
||||
var/decl/webhook/webhook = SSwebhooks.webhook_decls[choice]
|
||||
log_and_message_admins("has pinged webhook [choice].", usr)
|
||||
to_world_log("[usr.key] has pinged webhook [choice].")
|
||||
webhook.send()
|
||||
|
||||
/hook/roundstart/proc/run_webhook()
|
||||
SSwebhooks.send(WEBHOOK_ROUNDSTART, list("url" = get_world_url()))
|
||||
return 1
|
||||
@@ -396,6 +396,15 @@ var/global/list/additional_antag_types = list()
|
||||
feedback_set("escaped_on_cryopod",escaped_on_cryopod)
|
||||
|
||||
send2mainirc("A round of [src.name] has ended - [surviving_total] survivors, [ghosts] ghosts.")
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_ROUNDEND,
|
||||
list(
|
||||
"survivors" = surviving_total,
|
||||
"escaped" = escaped_total,
|
||||
"ghosts" = ghosts,
|
||||
"clients" = clients
|
||||
)
|
||||
)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@@ -712,3 +712,39 @@ proc/establish_old_db_connection()
|
||||
SStimer?.reset_buckets()
|
||||
|
||||
#undef FAILED_DB_CONNECTION_CUTOFF
|
||||
|
||||
/proc/get_world_url()
|
||||
. = "byond://"
|
||||
if(config.serverurl)
|
||||
. += config.serverurl
|
||||
else if(config.server)
|
||||
. += config.server
|
||||
else
|
||||
. += "[world.address]:[world.port]"
|
||||
|
||||
var/global/game_id = null
|
||||
|
||||
/hook/startup/proc/generate_gameid()
|
||||
if(game_id != null)
|
||||
return
|
||||
game_id = ""
|
||||
|
||||
var/list/c = list(
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
|
||||
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
||||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"
|
||||
)
|
||||
var/l = c.len
|
||||
|
||||
var/t = world.timeofday
|
||||
for(var/_ = 1 to 4)
|
||||
game_id = "[c[(t % l) + 1]][game_id]"
|
||||
t = round(t / l)
|
||||
game_id = "-[game_id]"
|
||||
t = round(world.realtime / (10 * 60 * 60 * 24))
|
||||
for(var/_ = 1 to 3)
|
||||
game_id = "[c[(t % l) + 1]][game_id]"
|
||||
t = round(t / l)
|
||||
return 1
|
||||
@@ -1632,6 +1632,19 @@ datum/admins/var/obj/item/weapon/paper/admin/faxreply // var to hold fax replies
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN | R_MOD | R_EVENT) & C.holder.rights)
|
||||
to_chat(C, "<span class='log_message'><span class='prefix'>FAX LOG:</span>[key_name_admin(src.owner)] has sent a fax message to [destination.department] (<a href='?_src_=holder;AdminFaxView=\ref[rcvdcopy]'>VIEW</a>)</span>")
|
||||
|
||||
var/plaintext_title = P.sender ? "replied to [key_name(P.sender)]'s fax" : "sent a fax message to [destination.department]"
|
||||
var/fax_text = paper_html_to_plaintext(P.info)
|
||||
log_game(plaintext_title)
|
||||
log_game(fax_text)
|
||||
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_FAX_SENT,
|
||||
list(
|
||||
"name" = "[key_name(owner)] [plaintext_title].",
|
||||
"body" = fax_text
|
||||
)
|
||||
)
|
||||
|
||||
else
|
||||
to_chat(src.owner, "<span class='warning'>Message reply failed.</span>")
|
||||
|
||||
@@ -239,7 +239,9 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/admin_give_modifier,
|
||||
/client/proc/simple_DPS,
|
||||
/datum/admins/proc/view_feedback,
|
||||
/client/proc/debug_global_variables
|
||||
/client/proc/debug_global_variables,
|
||||
/client/proc/ping_webhook,
|
||||
/client/proc/reload_webhooks
|
||||
)
|
||||
|
||||
var/list/admin_verbs_paranoid_debug = list(
|
||||
|
||||
@@ -213,6 +213,17 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
else
|
||||
ahelp_discord_message("ADMINHELP: FROM: [initiator_ckey]/[initiator_key_name] - MSG: **[msg]** - Heard by [activeMins] NON-AFK staff members.") //CHOMPEdit
|
||||
//YW EDIT END
|
||||
|
||||
// Also send it to discord since that's the hip cool thing now.
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) ticket opened.",
|
||||
"body" = "[key_name(initiator)] has opened a ticket. \n[msg]",
|
||||
"color" = COLOR_WEBHOOK_POOR
|
||||
)
|
||||
)
|
||||
|
||||
GLOB.ahelp_tickets.active_tickets += src
|
||||
|
||||
/datum/admin_help/Destroy()
|
||||
@@ -305,6 +316,14 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
feedback_inc("ahelp_reopen")
|
||||
TicketPanel() //can only be done from here, so refresh it
|
||||
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) reopened.",
|
||||
"body" = "Reopened by [key_name(usr)]."
|
||||
)
|
||||
)
|
||||
|
||||
//private
|
||||
/datum/admin_help/proc/RemoveActive()
|
||||
if(state != AHELP_ACTIVE)
|
||||
@@ -330,6 +349,14 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
var/msg = "Ticket [TicketHref("#[id]")] closed by [key_name_admin(usr)]."
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) closed.",
|
||||
"body" = "Closed by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_BAD
|
||||
)
|
||||
)
|
||||
|
||||
//Mark open ticket as resolved/legitimate, returns ahelp verb
|
||||
/datum/admin_help/proc/Resolve(silent = FALSE)
|
||||
@@ -347,6 +374,14 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
var/msg = "Ticket [TicketHref("#[id]")] resolved by [key_name_admin(usr)]"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) resolved.",
|
||||
"body" = "Marked as Resolved by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_GOOD
|
||||
)
|
||||
)
|
||||
|
||||
//Close and return ahelp verb, use if ticket is incoherent
|
||||
/datum/admin_help/proc/Reject(key_name = key_name_admin(usr))
|
||||
@@ -367,6 +402,14 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
log_admin(msg)
|
||||
AddInteraction("Rejected by [key_name_admin(usr)].")
|
||||
Close(silent = TRUE)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) rejected.",
|
||||
"body" = "Rejected by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_BAD
|
||||
)
|
||||
)
|
||||
|
||||
//Resolve ticket with IC Issue message
|
||||
/datum/admin_help/proc/ICIssue(key_name = key_name_admin(usr))
|
||||
@@ -386,6 +429,14 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
log_admin(msg)
|
||||
AddInteraction("Marked as IC issue by [key_name_admin(usr)]")
|
||||
Resolve(silent = TRUE)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) marked as IC issue.",
|
||||
"body" = "Marked as IC Issue by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_BAD
|
||||
)
|
||||
)
|
||||
|
||||
//Resolve ticket with IC Issue message
|
||||
/datum/admin_help/proc/HandleIssue()
|
||||
@@ -397,11 +448,18 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
feedback_inc("ahelp_icissue")
|
||||
feedback_inc("ahelp_handling")
|
||||
msg = "Ticket [TicketHref("#[id]")] being handled by [key_name(usr,FALSE,FALSE)]"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
AddInteraction("[key_name_admin(usr)] is now handling this ticket.")
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) being handled.",
|
||||
"body" = "[key_name(usr)] is now handling the ticket."
|
||||
)
|
||||
)
|
||||
|
||||
//Show the ticket panel
|
||||
/datum/admin_help/proc/TicketPanel()
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
to_world("<span class='alert'>[custom_event_msg]</span>")
|
||||
to_world("<br>")
|
||||
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_CUSTOM_EVENT,
|
||||
list(
|
||||
"text" = custom_event_msg,
|
||||
)
|
||||
)
|
||||
|
||||
// normal verb for players to view info
|
||||
/client/verb/cmd_view_custom_event()
|
||||
set category = "OOC"
|
||||
|
||||
@@ -227,6 +227,21 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
|
||||
sleep(50)
|
||||
visible_message("[src] beeps, \"Message transmitted successfully.\"")
|
||||
|
||||
// Turns objects into just text.
|
||||
/obj/machinery/photocopier/faxmachine/proc/make_summary(obj/item/sent)
|
||||
if(istype(sent, /obj/item/weapon/paper))
|
||||
var/obj/item/weapon/paper/P = sent
|
||||
return P.info
|
||||
if(istype(sent, /obj/item/weapon/paper_bundle))
|
||||
. = ""
|
||||
var/obj/item/weapon/paper_bundle/B = sent
|
||||
for(var/i in 1 to B.pages.len)
|
||||
var/obj/item/weapon/paper/P = B.pages[i]
|
||||
if(istype(P)) // Photos can show up here too.
|
||||
if(.) // Space out different pages.
|
||||
. += "<br>"
|
||||
. += "PAGE [i] - [P.name]<br>"
|
||||
. += P.info
|
||||
|
||||
/obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/obj/item/sent, var/reply_type, font_colour="#006100")
|
||||
var/msg = "<span class='notice'><b><font color='[font_colour]'>[faxname]: </font>[get_options_bar(sender, 2,1,1)]"
|
||||
@@ -242,3 +257,24 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
|
||||
var/faxid = export_fax(sent)
|
||||
message_chat_admins(sender, faxname, sent, faxid, font_colour)
|
||||
// VoreStation Edit End
|
||||
|
||||
// Webhooks don't parse the HTML on the paper, so we gotta strip them out so it's still readable.
|
||||
var/summary = make_summary(sent)
|
||||
summary = paper_html_to_plaintext(summary)
|
||||
|
||||
log_game("Fax to [lowertext(faxname)] was sent by [key_name(sender)].")
|
||||
log_game(summary)
|
||||
|
||||
var/webhook_length_limit = 1900 // The actual limit is a little higher.
|
||||
if(length(summary) > webhook_length_limit)
|
||||
summary = copytext(summary, 1, webhook_length_limit + 1)
|
||||
summary += "\n\[Truncated\]"
|
||||
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_FAX_SENT,
|
||||
list(
|
||||
"name" = "[faxname] '[sent.name]' sent from [key_name(sender)]",
|
||||
"body" = summary
|
||||
)
|
||||
)
|
||||
|
||||
72
code/modules/webhooks/_webhook.dm
Normal file
72
code/modules/webhooks/_webhook.dm
Normal file
@@ -0,0 +1,72 @@
|
||||
/decl/webhook
|
||||
var/id
|
||||
var/list/urls
|
||||
var/list/mentions
|
||||
|
||||
/decl/webhook/proc/get_message(var/list/data)
|
||||
. = list()
|
||||
|
||||
/decl/webhook/proc/http_post(var/target_url, var/payload)
|
||||
if (!target_url)
|
||||
return -1
|
||||
|
||||
var/result = call(HTTP_POST_DLL_LOCATION, "send_post_request")(target_url, payload, json_encode(list("Content-Type" = "application/json")))
|
||||
|
||||
result = cached_json_decode(result)
|
||||
if (result["error_code"])
|
||||
log_debug("byhttp error: [result["error"]] ([result["error_code"]])")
|
||||
return result["error_code"]
|
||||
|
||||
return list(
|
||||
"status_code" = result["status_code"],
|
||||
"body" = result["body"]
|
||||
)
|
||||
|
||||
/decl/webhook/proc/send(var/list/data)
|
||||
var/list/message = get_message(data)
|
||||
if(!length(message))
|
||||
return FALSE
|
||||
|
||||
if(config.disable_webhook_embeds)
|
||||
var/list/embed_content
|
||||
for(var/list/embed in message["embeds"])
|
||||
if(embed["title"])
|
||||
LAZYADD(embed_content, "**[embed["title"]]**")
|
||||
if(embed["description"])
|
||||
LAZYADD(embed_content, embed["description"])
|
||||
if(length(embed_content))
|
||||
if(message["content"])
|
||||
message["content"] = "[message["content"]]\n[jointext(embed_content, "\n")]"
|
||||
else
|
||||
message["content"] = jointext(embed_content, "\n")
|
||||
message -= "embeds"
|
||||
|
||||
. = TRUE
|
||||
for(var/target_url in urls)
|
||||
|
||||
var/url_message = message.Copy()
|
||||
var/list/url_mentions = get_mentions(target_url)
|
||||
if(islist(url_mentions) && length(url_mentions))
|
||||
if(url_message["content"])
|
||||
url_message["content"] = "[jointext(url_mentions, ", ")]: [url_message["content"]]"
|
||||
else
|
||||
url_message["content"] = "[jointext(url_mentions, ", ")]"
|
||||
|
||||
var/list/httpresponse = http_post(target_url, json_encode(url_message))
|
||||
if(!islist(httpresponse))
|
||||
. = FALSE
|
||||
continue
|
||||
switch(httpresponse["status_code"])
|
||||
if (200 to 299)
|
||||
continue
|
||||
if (400 to 599)
|
||||
log_debug("Webhooks: HTTP error code while sending to '[target_url]': [httpresponse["status_code"]]. Data: [httpresponse["body"]].")
|
||||
else
|
||||
log_debug("Webhooks: unknown HTTP code while sending to '[target_url]': [httpresponse["status_code"]]. Data: [httpresponse["body"]].")
|
||||
. = FALSE
|
||||
|
||||
/decl/webhook/proc/get_mentions(var/mentioning_url)
|
||||
. = mentions?.Copy()
|
||||
var/url_mentions = LAZYACCESS(urls, mentioning_url)
|
||||
if(length(url_mentions))
|
||||
LAZYDISTINCTADD(., url_mentions)
|
||||
13
code/modules/webhooks/webhook_ahelp2discord.dm
Normal file
13
code/modules/webhooks/webhook_ahelp2discord.dm
Normal file
@@ -0,0 +1,13 @@
|
||||
/decl/webhook/ahelp_sent
|
||||
id = WEBHOOK_AHELP_SENT
|
||||
|
||||
/decl/webhook/ahelp_sent/get_message(var/list/data)
|
||||
.= ..()
|
||||
.["embeds"] = list(list(
|
||||
"title" = "[data["name"]]",
|
||||
"description" = data["body"],
|
||||
"color" = data["color"] || COLOR_WEBHOOK_DEFAULT
|
||||
))
|
||||
|
||||
/decl/webhook/ahelp_sent/get_mentions()
|
||||
. = !length(GLOB.admins) && ..() // VOREStation Edit - GLOB admins
|
||||
11
code/modules/webhooks/webhook_custom_event.dm
Normal file
11
code/modules/webhooks/webhook_custom_event.dm
Normal file
@@ -0,0 +1,11 @@
|
||||
/decl/webhook/custom_event
|
||||
id = WEBHOOK_CUSTOM_EVENT
|
||||
|
||||
// Data expects a "text" field containing the new custom event text.
|
||||
/decl/webhook/custom_event/get_message(var/list/data)
|
||||
. = ..()
|
||||
.["embeds"] = list(list(
|
||||
"title" = "A custom event is beginning.",
|
||||
"description" = (data && data["text"]) || "undefined",
|
||||
"color" = COLOR_WEBHOOK_DEFAULT
|
||||
))
|
||||
10
code/modules/webhooks/webhook_fax2discord.dm
Normal file
10
code/modules/webhooks/webhook_fax2discord.dm
Normal file
@@ -0,0 +1,10 @@
|
||||
/decl/webhook/fax_sent
|
||||
id = WEBHOOK_FAX_SENT
|
||||
|
||||
/decl/webhook/fax_sent/get_message(var/list/data)
|
||||
.= ..()
|
||||
.["embeds"] = list(list(
|
||||
"title" = "[data["name"]]",
|
||||
"description" = data["body"],
|
||||
"color" = COLOR_WEBHOOK_DEFAULT
|
||||
))
|
||||
26
code/modules/webhooks/webhook_roundend.dm
Normal file
26
code/modules/webhooks/webhook_roundend.dm
Normal file
@@ -0,0 +1,26 @@
|
||||
/decl/webhook/roundend
|
||||
id = WEBHOOK_ROUNDEND
|
||||
|
||||
// Data expects three numerical fields: "survivors", "escaped", "ghosts", "clients"
|
||||
/decl/webhook/roundend/get_message(var/list/data)
|
||||
. = ..()
|
||||
var/desc = "A round of **[SSticker.mode ? SSticker.mode.name : "Unknown"]** ([game_id]) has ended.\n\n"
|
||||
if(data)
|
||||
var/s_escaped = "Escaped"
|
||||
if(!emergency_shuttle.evac)
|
||||
s_escaped = "Transferred"
|
||||
if(data["survivors"] > 0)
|
||||
desc += "Survivors: **[data["survivors"]]**\n"
|
||||
desc += "[s_escaped]: **[data["escaped"]]**\n"
|
||||
else
|
||||
desc += "There were **no survivors**.\n\n"
|
||||
desc += "Ghosts: **[data["ghosts"]]**\n"
|
||||
desc += "Players: **[data["clients"]]**\n"
|
||||
desc += "Round duration: **[roundduration2text()]**"
|
||||
|
||||
.["embeds"] = list(list(
|
||||
// "title" = global.end_credits_title,
|
||||
"title" = "Round Has Ended",
|
||||
"description" = desc,
|
||||
"color" = COLOR_WEBHOOK_DEFAULT
|
||||
))
|
||||
17
code/modules/webhooks/webhook_roundprep.dm
Normal file
17
code/modules/webhooks/webhook_roundprep.dm
Normal file
@@ -0,0 +1,17 @@
|
||||
/decl/webhook/roundprep
|
||||
id = WEBHOOK_ROUNDPREP
|
||||
|
||||
// Data expects "url" and field pointing to the current hosted server and port to connect on.
|
||||
/decl/webhook/roundprep/get_message(var/list/data)
|
||||
. = ..()
|
||||
var/desc = "The server has been started!\n"
|
||||
if(data && data["map"])
|
||||
desc += "Map: **[data["map"]]**\n"
|
||||
if(data && data["url"])
|
||||
desc += "Address: <[data["url"]]>"
|
||||
|
||||
.["embeds"] = list(list(
|
||||
"title" = "New round is being set up.",
|
||||
"description" = desc,
|
||||
"color" = COLOR_WEBHOOK_DEFAULT
|
||||
))
|
||||
16
code/modules/webhooks/webhook_roundstart.dm
Normal file
16
code/modules/webhooks/webhook_roundstart.dm
Normal file
@@ -0,0 +1,16 @@
|
||||
/decl/webhook/roundstart
|
||||
id = WEBHOOK_ROUNDSTART
|
||||
|
||||
// Data expects a "url" field pointing to the current hosted server and port to connect on.
|
||||
/decl/webhook/roundstart/get_message(var/list/data)
|
||||
. = ..()
|
||||
var/desc = "Gamemode: **[SSticker.mode.name]**\n"
|
||||
desc += "Players: **[global.player_list.len]**"
|
||||
if(data && data["url"])
|
||||
desc += "\nAddress: <[data["url"]]>"
|
||||
|
||||
.["embeds"] = list(list(
|
||||
"title" = "Round has started.",
|
||||
"description" = desc,
|
||||
"color" = COLOR_WEBHOOK_DEFAULT
|
||||
))
|
||||
12
config/example/webhooks.json
Normal file
12
config/example/webhooks.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"id" : "webhook_roundend",
|
||||
"url" : {
|
||||
"someurl0" : [],
|
||||
"someurl1" : [],
|
||||
"someurl2" : "somemention0",
|
||||
"someurl3" : [ "somemention1", "somemention2" ]
|
||||
},
|
||||
"mentions" : [ "somemention3", "somemention4" ]
|
||||
}
|
||||
]
|
||||
@@ -104,6 +104,7 @@
|
||||
#include "code\__defines\unit_tests.dm"
|
||||
#include "code\__defines\vote.dm"
|
||||
#include "code\__defines\vv.dm"
|
||||
#include "code\__defines\webhooks.dm"
|
||||
#include "code\__defines\wires.dm"
|
||||
#include "code\__defines\xenoarcheaology.dm"
|
||||
#include "code\__defines\ZAS.dm"
|
||||
@@ -145,7 +146,6 @@
|
||||
#include "code\_helpers\storage.dm"
|
||||
#include "code\_helpers\string_lists.dm"
|
||||
#include "code\_helpers\text.dm"
|
||||
#include "code\_helpers\text_vr.dm"
|
||||
#include "code\_helpers\time.dm"
|
||||
#include "code\_helpers\turfs.dm"
|
||||
#include "code\_helpers\type2type.dm"
|
||||
@@ -309,6 +309,7 @@
|
||||
#include "code\controllers\subsystems\timer.dm"
|
||||
#include "code\controllers\subsystems\transcore_vr.dm"
|
||||
#include "code\controllers\subsystems\vote.dm"
|
||||
#include "code\controllers\subsystems\webhooks.dm"
|
||||
#include "code\controllers\subsystems\xenoarch.dm"
|
||||
#include "code\controllers\subsystems\processing\bellies_vr.dm"
|
||||
#include "code\controllers\subsystems\processing\fastprocess.dm"
|
||||
@@ -4162,6 +4163,13 @@
|
||||
#include "code\modules\vore\resizing\sizegun_vr.dm"
|
||||
#include "code\modules\vore\smoleworld\smoleworld_vr.dm"
|
||||
#include "code\modules\vore\weight\fitness_machines_vr.dm"
|
||||
#include "code\modules\webhooks\_webhook.dm"
|
||||
#include "code\modules\webhooks\webhook_ahelp2discord.dm"
|
||||
#include "code\modules\webhooks\webhook_custom_event.dm"
|
||||
#include "code\modules\webhooks\webhook_fax2discord.dm"
|
||||
#include "code\modules\webhooks\webhook_roundend.dm"
|
||||
#include "code\modules\webhooks\webhook_roundprep.dm"
|
||||
#include "code\modules\webhooks\webhook_roundstart.dm"
|
||||
#include "code\modules\xenoarcheaology\anomaly_container.dm"
|
||||
#include "code\modules\xenoarcheaology\boulder.dm"
|
||||
#include "code\modules\xenoarcheaology\effect.dm"
|
||||
|
||||
Reference in New Issue
Block a user