From b5fa9dda9f1fa20dfbb10355679a73da857344f6 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sun, 4 May 2025 01:34:44 -0400 Subject: [PATCH] add admin verb for log access by round ID (#29174) * add admin verb for log access by round ID * Update code/modules/admin/verbs/getlogs.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: warriorstar-orion * add check_rights --------- Signed-off-by: warriorstar-orion Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> --- code/__DEFINES/misc_defines.dm | 3 ++ code/__HELPERS/files.dm | 7 ++- code/modules/admin/admin_verbs.dm | 1 + code/modules/admin/verbs/getlogs.dm | 82 +++++++++++++++++++---------- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index d485a10f8d7..3aebdd2d8ec 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -742,3 +742,6 @@ do { \ /// Economy account defines #define BANK_PIN_MIN 10000 #define BANK_PIN_MAX 99999 + +//! The number of seconds between the start of the UNIX and BYOND epochs. +#define BYOND_EPOCH_UNIX 946702800 diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm index 54c7f9f93aa..ac9129cfe43 100644 --- a/code/__HELPERS/files.dm +++ b/code/__HELPERS/files.dm @@ -34,8 +34,11 @@ return text /client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt", "log", "htm", "json")) - // wow why was this ever a parameter - root = "data/logs/" + if(!dd_hasprefix(root, "data/logs/") || findtext(root, "../")) + message_admins("/client/browse_files was called with a non-log or relative root `[root]`, please inform a headcoder!") + log_admin("/client/browse_files was called with a non-log or relative root `[root]`!") + + return var/path = root for(var/i=0, iLog Session" (or press the F3 key) - navigate the popup window to the data/logs/runtime/ folder from where your tgstation .dmb is located. - (you may have to make this folder yourself) - - OPTIONAL: you can select the little checkbox down the bottom to make dreamdeamon save the log everytime you - start a world. Just remember to repeat these steps with a new name when you update to a new revision! - - Save it with the name of the revision your server uses (e.g. r3459.txt). - Game Masters will now be able to grant access any runtime logs you have archived this way! - This will allow us to gather information on bugs across multiple servers and make maintaining the TG - codebase for the entire /TG/station commuity a TONNE easier :3 Thanks for your help! -*/ - - -//This proc allows download of past server logs saved within the data/logs/ folder. +/// This proc allows download of past server logs saved within the data/logs/ folder. /client/proc/getserverlogs() set name = "Get Server Logs" set desc = "View/retrieve logfiles." set category = "Admin" - var/path = browse_files("data/logs/") - if(!path) + if(!check_rights(R_ADMIN)) return - if(file_spam_check()) + access_file_by_browsing_path(usr, "data/logs/") + +/// This proc allows download of past server logs saved within the data/logs/ folder by specifying a specific round ID. +/client/proc/get_server_logs_by_round_id() + set name = "Get Round Logs" + set desc = "View/retrieve logfiles for a given round." + set category = "Admin" + + if(!check_rights(R_ADMIN)) return - message_admins("[key_name_admin(src)] accessed file: [path]") - switch(alert("View (in game), Open (in your system's text editor), or Download?", path, "View", "Open", "Download")) + var/round_id = input(usr, "Enter a round ID.", "Enter Round ID", "[GLOB.round_id]") as null|text + if(isnull(round_id)) + return + + var/round_path = "[GLOB.log_directory]/" + if(round_id != "[GLOB.round_id]") + var/datum/db_query/query = SSdbcore.NewQuery( + "SELECT UNIX_TIMESTAMP(initialize_datetime) AS dt FROM round WHERE id = :id", + list(id = round_id) + ) + if(!query.warn_execute()) + qdel(query) + to_chat(usr, "Could not check database for round [round_id].") + return + + if(!query.NextRow()) + qdel(query) + to_chat(usr, "Could not find round [round_id] in database.") + return + + // convert unix timestamp in seconds to byond timestamp in deciseconds + var/round_datetime = (query.item[1] - BYOND_EPOCH_UNIX) * 10 + round_path = "data/logs/[time2text(round_datetime, "YYYY/MM-Month/DD-Day")]/round-[round_id]/" + qdel(query) + + access_file_by_browsing_path(usr, round_path) + +/proc/access_file_by_browsing_path(mob/user, path) + if(!user.client) + return + + var/filename = user.client.browse_files(path) + if(!filename) + return + + if(user.client.file_spam_check()) + return + + message_admins("[key_name_admin(user)] accessed file: [filename]") + switch(alert("View (in game), Open (in your system's text editor), or Download?", filename, "View", "Open", "Download")) if("View") - src << browse("
[html_encode(wrap_file2text(wrap_file(path)))]
", list2params(list("window" = "viewfile.[path]"))) + user << browse("
[html_encode(wrap_file2text(wrap_file(filename)))]
", list2params(list("window" = "viewfile.[filename]"))) if("Open") - src << run(wrap_file(path)) + user << run(wrap_file(filename)) if("Download") - src << ftp(wrap_file(path)) + user << ftp(wrap_file(filename)) else return - to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.") - return + to_chat(user, "Attempting to send [filename], this may take a fair few minutes if the file is very large.")