mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-23 04:51:32 +01:00
File Manager Refresh (#22649)
- Abstracts edit and rename function in the File Manager. - Files are now edited in the program and not a separate input box. - File editor now has an editor toolbar with formatting buttons and keybind functionality. - File descriptions can now be edited. - Forms can now be downloaded into a computer's file manager as a text file. - File browser now shows a file description. - Fixed an issue where copying to/from a USB would throw an error because it didn't read the ID of the device being held. I was planning to add folder functionality, but that requires far more work since we store our files directly into the hard drive, which does file manipulation. Meaning, in order to add folders, I'd need to completely redo how hard drives and the file structure works. I'll tackle that later. CCIA Forms currently generate the entire form, which can be edited without reservation. This is fine, however a future PR may be viable for converting forms to use limited edit-access on fields to streamline the form-filling process. That or just adding the ability for files to display [field] properly. Forms tested by Fabian :) - [x] Fix ID check for copying programs to/from work devices - [x] Add editor/formatting functionality - [x] Test Forms functionality (unless an ultra cool dev can for me :) ) - [x] Add description box for editing - [x] Add actually good formatting to editing - [x] Misc bugtesting with encrypting, decrypting - [x] Fix USB files sticking in browser after USB is removed <details><summary>Video</summary> <p> https://github.com/user-attachments/assets/c6c666de-18fd-41a0-9751-3961aeda48fc </p> </details> --------- Signed-off-by: CatsinHD <31459154+CatsinHD@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
#define MAX_TEXTFILE_LENGTH 128000 // 512GQ file
|
||||
#define FMS_FILEBROWSER 0
|
||||
#define FMS_SHOWFILE 1
|
||||
#define FMS_FORMS 2
|
||||
#define FMS_EDIT 3
|
||||
|
||||
/datum/computer_file/program/filemanager
|
||||
filename = "filemanager"
|
||||
filedesc = "NTOS File Manager"
|
||||
@@ -11,6 +16,10 @@
|
||||
available_on_ntnet = FALSE
|
||||
undeletable = TRUE
|
||||
tgui_id = "FileManager"
|
||||
//Current screen of file manager.
|
||||
var/screen = FMS_FILEBROWSER
|
||||
//Department filter for forms browser.
|
||||
var/sql_filter_dept = ""
|
||||
var/open_file
|
||||
var/open_file_is_usb = FALSE
|
||||
var/error
|
||||
@@ -21,61 +30,89 @@
|
||||
var/obj/item/computer_hardware/hard_drive/HDD
|
||||
var/obj/item/computer_hardware/hard_drive/portable/RHDD
|
||||
data["error"] = error
|
||||
data["screen"] = screen
|
||||
|
||||
if(!computer || !computer.hard_drive)
|
||||
data["error"] = "I/O ERROR: Unable to access hard drive."
|
||||
return data
|
||||
if(screen == FMS_FILEBROWSER)
|
||||
data["script_data"] = null
|
||||
data["file_data"] = null
|
||||
data["file_is_usb"] = FALSE
|
||||
data["file_name"] = null
|
||||
HDD = computer.hard_drive
|
||||
RHDD = computer.portable_drive
|
||||
var/list/files = list()
|
||||
for(var/datum/computer_file/F in HDD.stored_files)
|
||||
files.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"desc" = F.filedesc,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable,
|
||||
"password" = !!F.password
|
||||
)))
|
||||
data["files"] = files
|
||||
if(RHDD)
|
||||
data["usb_connected"] = TRUE
|
||||
var/list/usb_files = list()
|
||||
for(var/datum/computer_file/F in RHDD.stored_files)
|
||||
usb_files.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"desc" = F.filedesc,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable,
|
||||
"password" = !!F.password
|
||||
)))
|
||||
data["usb_files"] = usb_files
|
||||
else
|
||||
data["usb_connected"] = FALSE
|
||||
if(screen == FMS_FORMS)
|
||||
if(!SSdbcore.Connect())
|
||||
data["sql_error"] = 1
|
||||
else
|
||||
var/datum/db_query/query
|
||||
if(sql_filter_dept)
|
||||
query = SSdbcore.NewQuery(
|
||||
"SELECT id, name, department FROM ss13_forms WHERE department LIKE :filter ORDER BY id",
|
||||
list("filter" = "%[sql_filter_dept]%"))
|
||||
else
|
||||
query = SSdbcore.NewQuery("SELECT id, name, department FROM ss13_forms ORDER BY id")
|
||||
if(!query.Execute())
|
||||
data["sql_error"] = 1
|
||||
else
|
||||
var/list/forms = list()
|
||||
while(query.NextRow())
|
||||
forms += list(list("id" = query.item[1], "name" = query.item[2], "department" = query.item[3]))
|
||||
if(!forms.len)
|
||||
data["sql_error"] = 1
|
||||
data["forms"] = forms
|
||||
qdel(query)
|
||||
if(open_file)
|
||||
var/datum/computer_file/data/file
|
||||
var/datum/computer_file/script/script
|
||||
|
||||
if(!computer || !computer.hard_drive)
|
||||
data["error"] = "I/O ERROR: Unable to access hard drive."
|
||||
else
|
||||
HDD = open_file_is_usb ? computer.portable_drive : computer.hard_drive
|
||||
data["file_is_usb"] = open_file_is_usb
|
||||
if(!HDD)
|
||||
HDD = open_file_is_usb ? computer.portable_drive : computer.hard_drive
|
||||
data["file_is_usb"] = open_file_is_usb
|
||||
if(!HDD)
|
||||
data["error"] = "I/O ERROR: Unable to open file."
|
||||
return data
|
||||
file = HDD.find_file_by_name(open_file)
|
||||
script = file
|
||||
data["file_name"] = "[file.filename]"
|
||||
data["file_type"] = "[file.filetype]"
|
||||
data["file_desc"] = "[file.filedesc]"
|
||||
if(!istype(file))
|
||||
if(!istype(script))
|
||||
data["error"] = "I/O ERROR: Unable to open file."
|
||||
return data
|
||||
file = HDD.find_file_by_name(open_file)
|
||||
script = file
|
||||
if(!istype(file))
|
||||
if(!istype(script))
|
||||
data["error"] = "I/O ERROR: Unable to open file."
|
||||
else
|
||||
data["scriptdata"] = html_encode(script.code)
|
||||
data["filename"] = "[script.filename].[script.filetype]"
|
||||
else
|
||||
data["filedata"] = pencode2html(file.stored_data)
|
||||
data["filename"] = "[file.filename].[file.filetype]"
|
||||
else
|
||||
if(!computer || !computer.hard_drive)
|
||||
data["error"] = "I/O ERROR: Unable to access hard drive."
|
||||
data["script_data"] = html_encode(script.code)
|
||||
return data
|
||||
if(screen == FMS_EDIT)
|
||||
data["file_data"] = file.stored_data
|
||||
else
|
||||
data["scriptdata"] = null
|
||||
data["filedata"] = null
|
||||
data["file_is_usb"] = FALSE
|
||||
data["filename"] = null
|
||||
HDD = computer.hard_drive
|
||||
RHDD = computer.portable_drive
|
||||
var/list/files = list()
|
||||
for(var/datum/computer_file/F in HDD.stored_files)
|
||||
files.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable,
|
||||
"encrypted" = !!F.password
|
||||
)))
|
||||
data["files"] = files
|
||||
if(RHDD)
|
||||
data["usbconnected"] = TRUE
|
||||
var/list/usbfiles = list()
|
||||
for(var/datum/computer_file/F in RHDD.stored_files)
|
||||
usbfiles.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable,
|
||||
"encrypted" = !!F.password
|
||||
)))
|
||||
data["usbfiles"] = usbfiles
|
||||
data["file_data"] = pencode2html(file.stored_data)
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/filemanager/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
@@ -83,68 +120,87 @@
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("PRG_openfile")
|
||||
if("set_screen")
|
||||
. = TRUE
|
||||
var/new_screen = text2num(params["screen"])
|
||||
if(new_screen == FMS_EDIT)
|
||||
if(!open_file)
|
||||
return TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return TRUE
|
||||
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
|
||||
return TRUE
|
||||
screen = new_screen
|
||||
|
||||
if("PRG_open_file")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_openfile"])
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_open_file"])
|
||||
if(!F)
|
||||
return
|
||||
if(F.can_access_file(usr))
|
||||
open_file = params["PRG_openfile"]
|
||||
open_file = params["PRG_open_file"]
|
||||
open_file_is_usb = FALSE
|
||||
screen = FMS_SHOWFILE
|
||||
|
||||
if("PRG_usbopenfile")
|
||||
if("PRG_usb_open_file")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/RHDD = computer.portable_drive
|
||||
if(!RHDD)
|
||||
return
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(params["PRG_usbopenfile"])
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(params["PRG_usb_open_file"])
|
||||
if(!F)
|
||||
return
|
||||
if(F.can_access_file(usr))
|
||||
open_file = params["PRG_usbopenfile"]
|
||||
open_file = params["PRG_usb_open_file"]
|
||||
open_file_is_usb = TRUE
|
||||
screen = FMS_SHOWFILE
|
||||
|
||||
if("PRG_newtextfile")
|
||||
if("PRG_new_text_file")
|
||||
. = TRUE
|
||||
var/newname = sanitize_filename(tgui_input_text(usr, "Enter file name or leave blank to cancel:", "File rename"))
|
||||
if(!newname)
|
||||
return TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/data/F = new/datum/computer_file/data()
|
||||
F.filename = newname
|
||||
F.filename = "NewFile"
|
||||
F.filetype = "TXT"
|
||||
F.stored_data = ""
|
||||
if(!HDD.store_file(F))
|
||||
qdel(F)
|
||||
error = "I/O ERROR: Unable to create file. The hard drive may be full, read-only, or contain a conflicting file."
|
||||
open_file = F.filename
|
||||
screen = FMS_EDIT
|
||||
|
||||
if("PRG_deletefile")
|
||||
if("PRG_delete_file")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["PRG_deletefile"])
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["PRG_delete_file"])
|
||||
if(!file || file.undeletable)
|
||||
return TRUE
|
||||
HDD.remove_file(file)
|
||||
|
||||
if("PRG_usbdeletefile")
|
||||
if("PRG_usb_delete_file")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/RHDD = computer.portable_drive
|
||||
if(!RHDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/file = RHDD.find_file_by_name(params["PRG_usbdeletefile"])
|
||||
var/datum/computer_file/file = RHDD.find_file_by_name(params["PRG_usb_delete_file"])
|
||||
if(!file || file.undeletable)
|
||||
return TRUE
|
||||
RHDD.remove_file(file)
|
||||
|
||||
if("PRG_closefile")
|
||||
if("PRG_close_file")
|
||||
. = TRUE
|
||||
open_file = null
|
||||
open_file_is_usb = FALSE
|
||||
error = null
|
||||
screen = FMS_FILEBROWSER
|
||||
|
||||
if("PRG_clone")
|
||||
. = TRUE
|
||||
@@ -162,42 +218,29 @@
|
||||
qdel(C)
|
||||
error = "I/O ERROR: Unable to clone file. The hard drive may be full, read-only, or contain a conflicting file."
|
||||
|
||||
if("PRG_rename")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["PRG_rename"])
|
||||
if(!file || !istype(file))
|
||||
return TRUE
|
||||
var/newname = sanitize_filename(tgui_input_text(usr, "Enter new file name or leave blank to cancel:", "File rename", file.filename))
|
||||
if(file && newname)
|
||||
file.filename = newname
|
||||
|
||||
if("PRG_edit")
|
||||
. = TRUE
|
||||
if(!open_file)
|
||||
return TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return TRUE
|
||||
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
|
||||
return TRUE
|
||||
|
||||
var/oldtext = html_decode(F.stored_data)
|
||||
oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
|
||||
|
||||
var/newtext = sanitize_filename(replacetext(tgui_input_text(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext), "\n", "\[editorbr\]"), MAX_TEXTFILE_LENGTH)
|
||||
if(!newtext)
|
||||
if(params["PRG_rename"])
|
||||
var/newname = sanitize_filename(params["PRG_rename"])
|
||||
F.filename = newname
|
||||
open_file = newname
|
||||
return
|
||||
|
||||
if(F)
|
||||
if(params["PRG_desc"])
|
||||
F.filedesc = params["PRG_desc"]
|
||||
return
|
||||
|
||||
if(params["PRG_edit"])
|
||||
var/datum/computer_file/data/backup = F.clone()
|
||||
HDD.remove_file(F)
|
||||
F.stored_data = newtext
|
||||
F.stored_data = params["PRG_edit"]
|
||||
F.calculate_size()
|
||||
// We can't store the updated file, it's probably too large. Print an error and restore backed up version.
|
||||
// This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
|
||||
@@ -206,7 +249,7 @@
|
||||
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[html_decode(F.stored_data)]<br><br>"
|
||||
HDD.store_file(backup)
|
||||
|
||||
if("PRG_printfile")
|
||||
if("PRG_print_file")
|
||||
. = TRUE
|
||||
if(!open_file)
|
||||
return TRUE
|
||||
@@ -221,29 +264,26 @@
|
||||
if(!F)
|
||||
return TRUE
|
||||
if(istype(F))
|
||||
if(!computer.nano_printer.print_text(F.stored_data))
|
||||
if(!computer.nano_printer.print_text(F.stored_data, F.filename))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return FALSE
|
||||
else if(istype(S))
|
||||
if(!computer.nano_printer.print_text(S.code))
|
||||
if(!computer.nano_printer.print_text(S.code, S.filename))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return FALSE
|
||||
|
||||
if("PRG_copytousb")
|
||||
if("PRG_copy_to_usb")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
if(!HDD || !RHDD)
|
||||
return FALSE
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_copytousb"])
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_copy_to_usb"])
|
||||
if(!F || !istype(F))
|
||||
return FALSE
|
||||
var/is_usr_tech_support = FALSE
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
var/obj/item/card/id/ID = H.GetIdCard()
|
||||
if(ACCESS_IT in ID.access)
|
||||
is_usr_tech_support = TRUE
|
||||
if(can_run(usr,FALSE,ACCESS_IT))
|
||||
is_usr_tech_support = TRUE
|
||||
if(!is_usr_tech_support && computer.enrolled != DEVICE_PRIVATE && istype(F, /datum/computer_file/program))
|
||||
to_chat(usr, SPAN_WARNING("Work devices can't export programs to portable drives! Contact Tech Support to get them to load it."))
|
||||
return TRUE
|
||||
@@ -258,21 +298,18 @@
|
||||
return
|
||||
RHDD.store_file(C)
|
||||
|
||||
if("PRG_copyfromusb")
|
||||
if("PRG_copy_from_usb")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
|
||||
if(!HDD || !RHDD)
|
||||
return TRUE
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(params["PRG_copyfromusb"])
|
||||
var/datum/computer_file/F = RHDD.find_file_by_name(params["PRG_copy_from_usb"])
|
||||
if(!F || !istype(F))
|
||||
return TRUE
|
||||
var/is_usr_tech_support = FALSE
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
var/obj/item/card/id/ID = H.GetIdCard()
|
||||
if(ACCESS_IT in ID.access)
|
||||
is_usr_tech_support = TRUE
|
||||
if(can_run(usr,FALSE,ACCESS_IT))
|
||||
is_usr_tech_support = TRUE
|
||||
if(!is_usr_tech_support && computer.enrolled != DEVICE_PRIVATE && istype(F, /datum/computer_file/program))
|
||||
to_chat(usr, SPAN_WARNING("Work devices can't import programs from portable drives! Contact Tech Support to get them to load it."))
|
||||
return TRUE
|
||||
@@ -292,22 +329,72 @@
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if (!HDD)
|
||||
return
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_encrypt"])
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_file_to_encrypt"])
|
||||
if(!F || F.undeletable)
|
||||
return
|
||||
if(F.password)
|
||||
return
|
||||
F.password = sanitize_filename(tgui_input_text(usr, "Enter an encryption key:", "Encrypt File"))
|
||||
|
||||
if("PRG_decrypt")
|
||||
. = TRUE
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if (!HDD)
|
||||
return
|
||||
var/datum/computer_file/F = HDD.find_file_by_name(params["PRG_encrypt"])
|
||||
if(!F || F.undeletable)
|
||||
return
|
||||
if (F.can_access_file(usr))
|
||||
if(F.password && F.password == params["PRG_encrypt"])
|
||||
F.password = ""
|
||||
return
|
||||
F.password = params["PRG_encrypt"]
|
||||
|
||||
if("PRG_sort_forms")
|
||||
sql_filter_dept = sanitize(params["department"])
|
||||
return TRUE
|
||||
|
||||
if("PRG_reset_sql")
|
||||
sql_filter_dept = ""
|
||||
return TRUE
|
||||
|
||||
if("PRG_generate_form")
|
||||
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
var/printid = text2num(params["id"])
|
||||
if(!printid)
|
||||
return TRUE
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, SPAN_WARNING("Connection to the database lost. Aborting."))
|
||||
return TRUE
|
||||
var/datum/db_query/query = SSdbcore.NewQuery(
|
||||
"SELECT id, name, data FROM ss13_forms WHERE id = :id",
|
||||
list("id" = printid))
|
||||
if(!query.Execute())
|
||||
to_chat(usr, SPAN_WARNING("Connection to the database lost. Aborting."))
|
||||
qdel(query)
|
||||
return TRUE
|
||||
while(query.NextRow())
|
||||
var/datum/computer_file/data/F = new/datum/computer_file/data()
|
||||
F.filename = "SCCF-[query.item[1]]-[query.item[2]]"
|
||||
F.filetype = "TXT"
|
||||
F.stored_data = query.item[3]
|
||||
if(!HDD.store_file(F))
|
||||
qdel(F)
|
||||
error = "I/O ERROR: Unable to create file. The hard drive may be full, read-only, or contain a conflicting file."
|
||||
qdel(query)
|
||||
screen = FMS_FILEBROWSER
|
||||
return TRUE
|
||||
|
||||
if("PRG_whatis")
|
||||
var/whatisid = text2num(params["id"])
|
||||
if(!whatisid)
|
||||
return TRUE
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, SPAN_WARNING("Connection to the database lost. Aborting."))
|
||||
return TRUE
|
||||
var/datum/db_query/query = SSdbcore.NewQuery(
|
||||
"SELECT id, name, department, info FROM ss13_forms WHERE id = :id",
|
||||
list("id" = whatisid))
|
||||
if(!query.Execute())
|
||||
to_chat(usr, SPAN_WARNING("Connection to the database lost. Aborting."))
|
||||
qdel(query)
|
||||
return TRUE
|
||||
var/dat = "<center><b>Stellar Corporate Conglomerate Form</b><br>"
|
||||
while(query.NextRow())
|
||||
dat += "<b>SCCF-[query.item[1]]</b><br><br>"
|
||||
dat += "<b>[query.item[2]]</b><br>"
|
||||
dat += "<b>[query.item[3]] Department</b><hr>"
|
||||
dat += "[query.item[4]]"
|
||||
dat += "</center>"
|
||||
qdel(query)
|
||||
usr << browse(HTML_SKELETON(dat), "window=Information;size=560x240")
|
||||
return TRUE
|
||||
|
||||
#undef MAX_TEXTFILE_LENGTH
|
||||
|
||||
Reference in New Issue
Block a user