diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 22369d5470d..87623cea1de 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -457,6 +457,23 @@ CREATE TABLE `erro_watch` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; --- Dump completed on 2013-03-24 18:02:35 --- Dump completed on 2015-05-28 19:57:44 +-- +-- Table structure for table `notes` +-- + +DROP TABLE IF EXISTS `erro_notes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `erro_notes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ckey` varchar(32) NOT NULL, + `notetext` text NOT NULL, + `timestamp` datetime NOT NULL, + `adminckey` varchar(32) NOT NULL, + `last_editor` varchar(32), + `edits` text, + `server` varchar(50) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; diff --git a/bin/bygex.dll b/bin/bygex.dll new file mode 100644 index 00000000000..b19c0f14b1e Binary files /dev/null and b/bin/bygex.dll differ diff --git a/code/__HELPERS/bygex/bygex.dm b/code/__HELPERS/bygex/bygex.dm new file mode 100644 index 00000000000..c5c4999ccca --- /dev/null +++ b/code/__HELPERS/bygex/bygex.dm @@ -0,0 +1,144 @@ +/* + This file is part of bygex. + + bygex is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + bygex is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with bygex. If not, see + + Based on code by Zac Stringham - Copyright 2009 (LGPL) + Written 6-Oct-2013 - carnie (elly1989@rocketmail.com), accreditation appreciated but not required. + Please do not remove this comment. + + Full source code is available at https://code.google.com/p/byond-regex/ + Please report any relevant issues on the tracker at the above address. + ~Carn +*/ + +#ifdef USE_BYGEX + +#ifndef LIBREGEX_LIBRARY + #define LIBREGEX_LIBRARY "bin/bygex" +#endif + +/proc + regEx_compare(str, exp) + return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_compare")(str, exp)) + + regex_compare(str, exp) + return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_compare")(str, exp)) + + regEx_find(str, exp) + return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_find")(str, exp)) + + regex_find(str, exp) + return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_find")(str, exp)) + + regEx_replaceall(str, exp, fmt) + return call(LIBREGEX_LIBRARY, "regEx_replaceall")(str, exp, fmt) + + regex_replaceall(str, exp, fmt) + return call(LIBREGEX_LIBRARY, "regex_replaceall")(str, exp, fmt) + + replacetextEx(str, exp, fmt) + return call(LIBREGEX_LIBRARY, "regEx_replaceallliteral")(str, exp, fmt) + + replacetext(str, exp, fmt) + return call(LIBREGEX_LIBRARY, "regex_replaceallliteral")(str, exp, fmt) + + regEx_replace(str, exp, fmt) + return call(LIBREGEX_LIBRARY, "regEx_replace")(str, exp, fmt) + + regex_replace(str, exp, fmt) + return call(LIBREGEX_LIBRARY, "regex_replace")(str, exp, fmt) + + regEx_findall(str, exp) + return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_findall")(str, exp)) + + regex_findall(str, exp) + return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_findall")(str, exp)) + + +//upon calling a regex match or search, a /datum/regex object is created with str(haystack) and exp(needle) variables set +//it also contains a list(matches) of /datum/match objects, each of which holds the position and length of the match +//matched strings are not returned from the dll, in order to save on memory allocation for large numbers of strings +//instead, you can use regex.str(matchnum) to fetch this string as needed. +//likewise you can also use regex.pos(matchnum) and regex.len(matchnum) as shorthands +/datum/regex + var/str + var/exp + var/error + var/anchors = 0 + var/list/matches = list() + + New(str, exp, results) + src.str = str + src.exp = exp + + if(findtext(results, "$Err$", 1, 6)) //error message + src.error = results + else + var/list/L = params2list(results) + var/list/M + var{i;j} + for(i in L) + M = L[i] + for(j=2, j<=M.len, j+=2) + matches += new /datum/match(text2num(M[j-1]),text2num(M[j])) + anchors = (j-2)/2 + return matches + + proc + str(i) + if(!i) return str + var/datum/match/M = matches[i] + if(i < 1 || i > matches.len) + throw EXCEPTION("str(): out of bounds") + return copytext(str, M.pos, M.pos+M.len) + + pos(i) + if(!i) return 1 + if(i < 1 || i > matches.len) + throw EXCEPTION("pos(): out of bounds") + var/datum/match/M = matches[i] + return M.pos + + len(i) + if(!i) return length(str) + if(i < 1 || i > matches.len) + throw EXCEPTION("len(): out of bounds") + var/datum/match/M = matches[i] + return M.len + + end(i) + if(!i) return length(str) + if(i < 1 || i > matches.len) + throw EXCEPTION("end() out of bounds") + var/datum/match/M = matches[i] + return M.pos + M.len + + report() //debug tool + . = ":: RESULTS ::\n:: str :: [html_encode(str)]\n:: exp :: [html_encode(exp)]\n:: anchors :: [anchors]" + if(error) + . += "\n[error]" + return + for(var/i=1, i<=matches.len, ++i) + . += "\nMatch[i]\n\t[html_encode(str(i))]\n\tpos=[pos(i)] len=[len(i)]" + +/datum/match + var/pos + var/len + + New(pos, len) + src.pos = pos + src.len = len + +#endif \ No newline at end of file diff --git a/code/__HELPERS/bygex/demo.dm b/code/__HELPERS/bygex/demo.dm new file mode 100644 index 00000000000..f89be30ded2 --- /dev/null +++ b/code/__HELPERS/bygex/demo.dm @@ -0,0 +1,54 @@ +/mob + var/expression = "\\S+" + var/format = "*" + + var/datum/regex/results + + verb + set_expression() + var/t = input(usr,"Input Expression","title",expression) as text|null + if(t != null) + expression = t + usr << "Expression set to:\t[html_encode(t)]" + + set_format() + var/t = input(usr,"Input Formatter","title",format) as text|null + if(t != null) + format = t + usr << "Format set to:\t[html_encode(t)]" + + compare_casesensitive(t as text) + results = regEx_compare(t, expression) + world << results.report() + + compare(t as text) + results = regex_compare(t, expression) + world << results.report() + + find_casesensitive(t as text) + results = regEx_find(t, expression) + world << results.report() + + find(t as text) + results = regex_find(t, expression) + world << results.report() + + replaceall_casesensitive(t as text) + usr << regEx_replaceall(t, expression, format) + + replaceall(t as text) + usr << regex_replaceall(t, expression, format) + + replace_casesensitive(t as text) + usr << html_encode(regEx_replace(t, expression, format)) + + replace(t as text) + usr << regex_replace(t, expression, format) + + findall(t as text) + results = regex_findall(t, expression) + world << results.report() + + findall_casesensitive(t as text) + results = regEx_findall(t, expression) + world << results.report() \ No newline at end of file diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index a18a377b30c..5b720291b48 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -202,11 +202,14 @@ proc/checkhtml(var/t) /* * Text modification */ +// See bygex.dm +#ifndef USE_BYGEX /proc/replacetext(text, find, replacement) return list2text(text2list(text, find), replacement) /proc/replacetextEx(text, find, replacement) return list2text(text2listEx(text, find), replacement) +#endif /proc/replace_characters(var/t,var/list/repl_chars) for(var/char in repl_chars) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 84f3b3048c9..a2bf32f53c7 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -17,4 +17,6 @@ Due to BYOND features used in this codebase, you must update to version 508 or l This may require updating to a beta release. #endif -var/global/list/processing_objects = list() //This has to be initialized BEFORE world \ No newline at end of file +var/global/list/processing_objects = list() //This has to be initialized BEFORE world + +#define USE_BYGEX \ No newline at end of file diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm index 780f17a1b90..47e942225fc 100644 --- a/code/_globalvars/lists/misc.dm +++ b/code/_globalvars/lists/misc.dm @@ -1,4 +1,8 @@ -var/global/list/alphabet_uppercase = 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") //added for Xenoarchaeology, might be useful for other stuff +var/global/list/alphabet = 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") +var/global/list/alphabet_uppercase = 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") +var/global/list/zero_character_only = list("0") +var/global/list/hex_characters = list("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f") +var/global/list/binary = list("0","1") //Reagent stuff var/list/tachycardics = list("coffee", "methamphetamine", "nitroglycerin", "thirteenloko", "nicotine") //increase heart rate diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index a958c3b4eec..5f6f5c9978a 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -162,6 +162,8 @@ var/list/overflow_whitelist = list() //whitelist for overflow var/disable_away_missions = 0 // disable away missions + + var/autoconvert_notes = 0 //if all connecting player's notes should attempt to be converted to the database /datum/configuration/New() var/list/L = subtypesof(/datum/game_mode) @@ -526,6 +528,9 @@ if("disable_away_missions") config.disable_away_missions = 1 + if("autoconvert_notes") + config.autoconvert_notes = 1 + else diary << "Unknown setting in configuration: '[name]'" diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index ecc2a812bf0..b871ada026d 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -120,9 +120,9 @@ var/savefile/Banlist if (temp) Banlist["minutes"] << bantimestamp if(!temp) - notes_add(ckey, "Permanently banned - [reason]") + add_note(ckey, "Permanently banned - [reason]", null, bannedby, 0) else - notes_add(ckey, "Banned for [minutes] minutes - [reason]") + add_note(ckey, "Banned for [minutes] minutes - [reason]", null, bannedby, 0) return 1 /proc/RemoveBan(foldername) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index a4a836db6a6..7a17941ad1a 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -65,7 +65,7 @@ var/global/nologevent = 0 body += "Ban | " body += "Jobban | " body += "Appearance Ban | " - body += "Notes | " + body += "Notes | " if(M.client) if(M.client.check_watchlist(M.client.ckey)) body += "Remove from Watchlist | " @@ -215,112 +215,29 @@ var/global/nologevent = 0 /datum/admins/proc/PlayerNotes() set category = "Admin" set name = "Player Notes" - if (!istype(src,/datum/admins)) - src = usr.client.holder - if (!istype(src,/datum/admins)) - usr << "Error: you are not an admin!" + + if(!check_rights(R_ADMIN)) return - PlayerNotesPage(1) + + show_note() -/datum/admins/proc/PlayerNotesPage(page) - var/dat = "Player notes
" - var/savefile/S=new("data/player_notes.sav") - var/list/note_keys - S >> note_keys - if(!note_keys) - dat += "No notes found." - else - dat += "" - note_keys = sortList(note_keys) - - // Display the notes on the current page - var/number_pages = note_keys.len / PLAYER_NOTES_ENTRIES_PER_PAGE - // Emulate ceil(why does BYOND not have ceil) - if(number_pages != round(number_pages)) - number_pages = round(number_pages) + 1 - var/page_index = page - 1 - if(page_index < 0 || page_index >= number_pages) - return - - var/lower_bound = page_index * PLAYER_NOTES_ENTRIES_PER_PAGE + 1 - var/upper_bound = (page_index + 1) * PLAYER_NOTES_ENTRIES_PER_PAGE - upper_bound = min(upper_bound, note_keys.len) - for(var/index = lower_bound, index <= upper_bound, index++) - var/t = note_keys[index] - dat += "" - - dat += "
[t]

" - - // Display a footer to select different pages - for(var/index = 1, index <= number_pages, index++) - if(index == page) - dat += "" - dat += "[index] " - if(index == page) - dat += "" - - usr << browse(dat, "window=player_notes;size=400x400") - - -/datum/admins/proc/player_has_info(var/key as text) - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos || !infos.len) return 0 - else return 1 - - -/datum/admins/proc/show_player_info(var/key as text) +/datum/admins/proc/show_player_notes(var/key as text) set category = "Admin" - set name = "Show Player Info" - if (!istype(src,/datum/admins)) - src = usr.client.holder - if (!istype(src,/datum/admins)) - usr << "Error: you are not an admin!" + set name = "Show Player Notes" + + if(!check_rights(R_ADMIN)) return - var/dat = "Info on [key]" - dat += "" - - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos) - dat += "No information found on the given key.
" - else - var/update_file = 0 - var/i = 0 - for(var/datum/player_info/I in infos) - i += 1 - if(!I.timestamp) - I.timestamp = "Pre-4/3/2012" - update_file = 1 - if(!I.rank) - I.rank = "N/A" - update_file = 1 - dat += "[I.content] by [I.author] ([I.rank]) on [I.timestamp] " - if(I.author == usr.key) - dat += "Remove" - dat += "

" - if(update_file) info << infos - - dat += "
" - dat += "Add Comment
" - - dat += "" - usr << browse(dat, "window=adminplayerinfo;size=480x480") - - - + + show_note(key) + /datum/admins/proc/access_news_network() //MARKER set category = "Event" set name = "Access Newscaster Network" set desc = "Allows you to view, add and edit news feeds." - if (!istype(src,/datum/admins)) - src = usr.client.holder - if (!istype(src,/datum/admins)) - usr << "Error: you are not an admin!" + if(!check_rights(R_EVENT)) return + var/dat dat = text("Admin Newscaster

Admin Newscaster Unit

") diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 0fc31b8848a..04a86404ccb 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -26,7 +26,7 @@ F << "[time_stamp()] \ref[src] ([x],[y],[z]) || [src] [message]
" //ADMINVERBS -/client/proc/investigate_show( subject in list("hrefs","pda","singulo","atmos","watchlist","ntsl","gold core","cult") ) +/client/proc/investigate_show( subject in list("hrefs","notes","pda","singulo","atmos","watchlist","ntsl","gold core","cult") ) set name = "Investigate" set category = "Admin" if(!holder) return @@ -78,4 +78,7 @@ src << browse(F,"window=investigate[subject];size=800x300") if("watchlist") - watchlist_show() \ No newline at end of file + watchlist_show() + + if("notes") + show_note() \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c0b1aba0a61..77b7ae94bda 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -55,7 +55,7 @@ var/list/admin_verbs_admin = list( /client/proc/cmd_admin_say, /*admin-only ooc chat*/ /datum/admins/proc/PlayerNotes, /client/proc/cmd_mod_say, - /datum/admins/proc/show_player_info, + /datum/admins/proc/show_player_notes, /client/proc/free_slot, /*frees slot for chosen job*/ /client/proc/toggleattacklogs, /client/proc/toggledebuglogs, diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm deleted file mode 100644 index 8b439ea6fe9..00000000000 --- a/code/modules/admin/player_notes.dm +++ /dev/null @@ -1,167 +0,0 @@ -//This stuff was originally intended to be integrated into the ban-system I was working on -//but it's safe to say that'll never be finished. So I've merged it into the current player panel. -//enjoy ~Carn -/* -#define NOTESFILE "data/player_notes.sav" //where the player notes are saved - -datum/admins/proc/notes_show(var/ckey) - usr << browse("Player Notes[notes_gethtml(ckey)]","window=player_notes;size=700x400") - - -datum/admins/proc/notes_gethtml(var/ckey) - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return "Error: Cannot access [NOTESFILE]" - if(ckey) - . = "Notes for [ckey]: \[+\] \[-\]
" - notesfile.cd = "/[ckey]" - var/index = 1 - while( !notesfile.eof ) - var/note - notesfile >> note - . += "[note] \[-\]
" - index++ - else - . = "All Notes: \[+\] \[-\]
" - notesfile.cd = "/" - for(var/dir in notesfile.dir) - . += "[dir]
" - return - - -//handles adding notes to the end of a ckey's buffer -//originally had seperate entries such as var/by to record who left the note and when -//but the current bansystem is a heap of dung. -/proc/notes_add(var/ckey, var/note) - if(!ckey) - ckey = ckey(input(usr,"Who would you like to add notes for?","Enter a ckey",null) as text|null) - if(!ckey) return - - if(!note) - note = html_encode(input(usr,"Enter your note:","Enter some text",null) as message|null) - if(!note) return - - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return - notesfile.cd = "/[ckey]" - notesfile.eof = 1 //move to the end of the buffer - notesfile << "[time2text(world.realtime,"DD-MMM-YYYY")] | [note][(usr && usr.ckey)?" ~[usr.ckey]":""]" - return - -//handles removing entries from the buffer, or removing the entire directory if no start_index is given -/proc/notes_remove(var/ckey, var/start_index, var/end_index) - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return - - if(!ckey) - notesfile.cd = "/" - ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir) - if(!ckey) return - - if(start_index) - notesfile.cd = "/[ckey]" - var/list/noteslist = list() - if(!end_index) end_index = start_index - var/index = 0 - while( !notesfile.eof ) - index++ - var/temp - notesfile >> temp - if( (start_index <= index) && (index <= end_index) ) - continue - noteslist += temp - - notesfile.eof = -2 //Move to the start of the buffer and then erase. - - for( var/note in noteslist ) - notesfile << note - else - notesfile.cd = "/" - if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes") - notesfile.dir.Remove(ckey) - return - -#undef NOTESFILE -*/ - -//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky. - -/proc/notes_add(var/key, var/note, var/mob/usr) - if (!key || !note) - return - - //Loading list of notes for this key - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos) infos = list() - - //Overly complex timestamp creation - var/modifyer = "th" - switch(time2text(world.timeofday, "DD")) - if("01","21","31") - modifyer = "st" - if("02","22",) - modifyer = "nd" - if("03","23") - modifyer = "rd" - var/day_string = "[time2text(world.timeofday, "DD")][modifyer]" - if(copytext(day_string,1,2) == "0") - day_string = copytext(day_string,2) - var/full_date = time2text(world.timeofday, "DDD, Month DD of YYYY") - var/day_loc = findtext(full_date, time2text(world.timeofday, "DD")) - - var/datum/player_info/P = new - if (usr) - P.author = usr.key - P.rank = usr.client.holder.rank - else - P.author = "Adminbot" - P.rank = "Friendly Robot" - P.content = note - P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]" - - infos += P - info << infos - - message_admins("\blue [key_name_admin(usr)] has edited [key]'s notes.") - log_admin("[key_name(usr)] has edited [key]'s notes.") - - del(info) - - //Updating list of keys with notes on them - var/savefile/note_list = new("data/player_notes.sav") - var/list/note_keys - note_list >> note_keys - if(!note_keys) note_keys = list() - if(!note_keys.Find(key)) note_keys += key - note_list << note_keys - del(note_list) - - -/proc/notes_del(var/key, var/index) - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos || infos.len < index) return - - var/datum/player_info/item = infos[index] - infos.Remove(item) - info << infos - - message_admins("\blue [key_name_admin(usr)] deleted one of [key]'s notes.") - log_admin("[key_name(usr)] deleted one of [key]'s notes.") - - del(info) - -/proc/show_player_info_irc(var/key as text) - var/dat = " Info on [key]%0D%0A" - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos) - dat = "No information found on the given key." - else - for(var/datum/player_info/I in infos) - dat += "[I.content]%0D%0Aby [I.author] ([I.rank]) on [I.timestamp]%0D%0A%0D%0A" - - return dat diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index a345f9df321..7e6ebcf4c5a 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -76,7 +76,7 @@ body += ""; body += "PP - " - body += "N - " + body += "N - " body += "VV - " body += "TP - " body += "PM - " diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm new file mode 100644 index 00000000000..2a76ed97f90 --- /dev/null +++ b/code/modules/admin/sql_notes.dm @@ -0,0 +1,226 @@ +/proc/add_note(target_ckey, notetext, timestamp, adminckey, logged = 1, server) + if(!dbcon.IsConnected()) + usr << "Failed to establish database connection." + return + if(!target_ckey) + var/new_ckey = ckey(input(usr,"Who would you like to add a note for?","Enter a ckey",null) as text|null) + if(!new_ckey) + return + new_ckey = sanitizeSQL(new_ckey) + var/DBQuery/query_find_ckey = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[new_ckey]'") + if(!query_find_ckey.Execute()) + var/err = query_find_ckey.ErrorMsg() + log_game("SQL ERROR obtaining ckey from player table. Error : \[[err]\]\n") + return + if(!query_find_ckey.NextRow()) + usr << "[new_ckey] has not been seen before, you can only add notes to known players." + return + else + target_ckey = new_ckey + var/target_sql_ckey = sanitizeSQL(target_ckey) + if(!notetext) + notetext = input(usr,"Write your Note","Add Note") as message + if(!notetext) + return + notetext = sanitizeSQL(notetext) + if(!timestamp) + timestamp = SQLtime() + if(!adminckey) + adminckey = usr.ckey + if(!adminckey) + return + var/admin_sql_ckey = sanitizeSQL(adminckey) + if(!server) + if (config && config.server_name) + server = config.server_name + server = sanitizeSQL(server) + var/DBQuery/query_noteadd = dbcon.NewQuery("INSERT INTO [format_table_name("notes")] (ckey, timestamp, notetext, adminckey, server) VALUES ('[target_sql_ckey]', '[timestamp]', '[notetext]', '[admin_sql_ckey]', '[server]')") + if(!query_noteadd.Execute()) + var/err = query_noteadd.ErrorMsg() + log_game("SQL ERROR adding new note to table. Error : \[[err]\]\n") + return + if(logged) + log_admin("[key_name(usr)] has added a note to [target_ckey]: [notetext]") + message_admins("[key_name_admin(usr)] has added a note to [target_ckey]:
[notetext]") + show_note(target_ckey) + +/proc/remove_note(note_id) + var/ckey + var/notetext + var/adminckey + if(!dbcon.IsConnected()) + usr << "Failed to establish database connection." + return + if(!note_id) + return + note_id = text2num(note_id) + var/DBQuery/query_find_note_del = dbcon.NewQuery("SELECT ckey, notetext, adminckey FROM [format_table_name("notes")] WHERE id = [note_id]") + if(!query_find_note_del.Execute()) + var/err = query_find_note_del.ErrorMsg() + log_game("SQL ERROR obtaining ckey, notetext, adminckey from player table. Error : \[[err]\]\n") + return + if(query_find_note_del.NextRow()) + ckey = query_find_note_del.item[1] + notetext = query_find_note_del.item[2] + adminckey = query_find_note_del.item[3] + var/DBQuery/query_del_note = dbcon.NewQuery("DELETE FROM [format_table_name("notes")] WHERE id = [note_id]") + if(!query_del_note.Execute()) + var/err = query_del_note.ErrorMsg() + log_game("SQL ERROR removing note from table. Error : \[[err]\]\n") + return + log_admin("[key_name(usr)] has removed a note made by [adminckey] from [ckey]: [notetext]") + message_admins("[key_name_admin(usr)] has removed a note made by [adminckey] from [ckey]:
[notetext]") + show_note(ckey) + +/proc/edit_note(note_id) + if(!dbcon.IsConnected()) + usr << "Failed to establish database connection." + return + if(!note_id) + return + note_id = text2num(note_id) + var/target_ckey + var/sql_ckey = sanitizeSQL(usr.ckey) + var/DBQuery/query_find_note_edit = dbcon.NewQuery("SELECT ckey, notetext, adminckey FROM [format_table_name("notes")] WHERE id = [note_id]") + if(!query_find_note_edit.Execute()) + var/err = query_find_note_edit.ErrorMsg() + log_game("SQL ERROR obtaining notetext from notes table. Error : \[[err]\]\n") + return + if(query_find_note_edit.NextRow()) + target_ckey = query_find_note_edit.item[1] + var/old_note = query_find_note_edit.item[2] + var/adminckey = query_find_note_edit.item[3] + var/new_note = input("Input new note", "New Note", "[old_note]") as message + if(!new_note) + return + new_note = sanitizeSQL(new_note) + var/edit_text = "Edited by [sql_ckey] on [SQLtime()] from '[old_note]' to '[new_note]'
" + edit_text = sanitizeSQL(edit_text) + var/DBQuery/query_update_note = dbcon.NewQuery("UPDATE [format_table_name("notes")] SET notetext = '[new_note]', last_editor = '[sql_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [note_id]") + if(!query_update_note.Execute()) + var/err = query_update_note.ErrorMsg() + log_game("SQL ERROR editing note. Error : \[[err]\]\n") + return + log_admin("[key_name(usr)] has edited [target_ckey]'s note made by [adminckey] from [old_note] to [new_note]") + message_admins("[key_name_admin(usr)] has edited [target_ckey]'s note made by [adminckey] from '[old_note]' to '[new_note]'") + show_note(target_ckey) + +/proc/show_note(target_ckey, index, linkless = 0) + var/output + var/navbar + var/ruler + ruler = "
" + navbar = "\[All\]|\[#\]" + for(var/letter in alphabet) + navbar += "|\[[letter]\]" + navbar += "
\ + \ + \ +
" + if(!linkless) + output = navbar + if(target_ckey) + var/target_sql_ckey = sanitizeSQL(target_ckey) + var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id, timestamp, notetext, adminckey, last_editor, server FROM [format_table_name("notes")] WHERE ckey = '[target_sql_ckey]' ORDER BY timestamp") + if(!query_get_notes.Execute()) + var/err = query_get_notes.ErrorMsg() + log_game("SQL ERROR obtaining ckey, notetext, adminckey, last_editor, server from notes table. Error : \[[err]\]\n") + return + output += "

Notes of [target_ckey]

" + if(!linkless) + output += "
\[Add Note\]
" + output += ruler + while(query_get_notes.NextRow()) + var/id = query_get_notes.item[1] + var/timestamp = query_get_notes.item[2] + var/notetext = query_get_notes.item[3] + var/adminckey = query_get_notes.item[4] + var/last_editor = query_get_notes.item[5] + var/server = query_get_notes.item[6] + output += "[timestamp] | [server] | [adminckey]" + if(!linkless) + output += " \[Remove Note\] \[Edit Note\]" + if(last_editor) + output += " Last edit by [last_editor] (Click here to see edit log)" + output += "
[notetext]
" + else if(index) + var/index_ckey + var/search + output += "
\[Add Note\]
" + output += ruler + if(!isnum(index)) + index = sanitizeSQL(index) + switch(index) + if(1) + search = "^." + if(2) + search = "^\[^\[:alpha:\]\]" + else + search = "^[index]" + var/DBQuery/query_list_notes = dbcon.NewQuery("SELECT DISTINCT ckey FROM [format_table_name("notes")] WHERE ckey REGEXP '[search]' ORDER BY ckey") + if(!query_list_notes.Execute()) + var/err = query_list_notes.ErrorMsg() + log_game("SQL ERROR obtaining ckey from notes table. Error : \[[err]\]\n") + return + while(query_list_notes.NextRow()) + index_ckey = query_list_notes.item[1] + output += "[index_ckey]
" + else + output += "
\[Add Note\]
" + output += ruler + usr << browse(output, "window=show_notes;size=900x500") + +/proc/regex_note_sql_extract(str, exp) + return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_find")(str, exp)) + +#define NOTESFILE "data/player_notes.sav" +//if the AUTOCONVERT_NOTES is turned on, anytime a player connects this will be run to try and add all their notes to the databas +/proc/convert_notes_sql(ckey) + var/savefile/notesfile = new(NOTESFILE) + if(!notesfile) + log_game("Error: Cannot access [NOTESFILE]") + return + notesfile.cd = "/[ckey]" + while(!notesfile.eof) + var/notetext + notesfile >> notetext + var/server + if (config && config.server_name) + server = config.server_name + var/regex = "^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$" + var/datum/regex/results = regex_note_sql_extract(notetext, regex) + var/timestamp = results.str(2) + notetext = results.str(3) + var/adminckey = results.str(4) + var/DBQuery/query_convert_time = dbcon.NewQuery("SELECT ADDTIME(STR_TO_DATE('[timestamp]','%d-%b-%Y'), '0')") + if(!query_convert_time.Execute()) + var/err = query_convert_time.ErrorMsg() + log_game("SQL ERROR converting timestamp. Error : \[[err]\]\n") + return + if(query_convert_time.NextRow()) + timestamp = query_convert_time.item[1] + if(ckey && notetext && timestamp && adminckey && server) + add_note(ckey, notetext, timestamp, adminckey, 0, server) + notesfile.cd = "/" + notesfile.dir.Remove(ckey) + +/*alternatively this proc can be run once to pass through every note and attempt to convert it before deleting the file, if done then AUTOCONVERT_NOTES should be turned off +this proc can take several minutes to execute fully if converting and cause DD to hang if converting a lot of notes; it's not advised to do so while a server is live +/proc/mass_convert_notes() + world << "Beginning mass note conversion" + var/savefile/notesfile = new(NOTESFILE) + if(!notesfile) + log_game("Error: Cannot access [NOTESFILE]") + return + notesfile.cd = "/" + for(var/ckey in notesfile.dir) + convert_notes_sql(ckey) + world << "Deleting NOTESFILE" + fdel(NOTESFILE) + world << "Finished mass note conversion, remember to turn off AUTOCONVERT_NOTES"*/ + +/proc/show_player_info_irc(var/key as text) + var/notes = show_note(key, linkless = 1) + return notes + +#undef NOTESFILE \ No newline at end of file diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 32cd8fb90ba..c48041774bd 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -445,7 +445,7 @@ feedback_inc("ban_appearance",1) DB_ban_record(BANTYPE_APPEARANCE, M, -1, reason) appearance_fullban(M, "[reason]; By [usr.ckey] on [time2text(world.realtime)]") - notes_add(M.ckey, "Appearance banned - [reason]") + add_note(M.ckey, "Appearance banned - [reason]", null, usr, 0) message_admins("\blue [key_name_admin(usr)] appearance banned [key_name_admin(M)]", 1) M << "\redYou have been appearance banned by [usr.client.ckey]." M << "\red The reason is: [reason]" @@ -886,7 +886,7 @@ msg = job else msg += ", [job]" - notes_add(M.ckey, "Banned from [msg] - [reason]") + add_note(M.ckey, "Banned from [msg] - [reason]", null, usr, 0) message_admins("\blue [key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes", 1) M << "\redYou have been jobbanned by [usr.client.ckey] from: [msg]." M << "\red The reason is: [reason]" @@ -905,8 +905,8 @@ feedback_add_details("ban_job","- [job]") jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]") if(!msg) msg = job - else msg += ", [job]" - notes_add(M.ckey, "Banned from [msg] - [reason]") + else msg += ", [job]" + add_note(M.ckey, "Banned from [msg] - [reason]", null, usr, 0) message_admins("\blue [key_name_admin(usr)] banned [key_name_admin(M)] from [msg]", 1) M << "\redYou have been jobbanned by [usr.client.ckey] from: [msg]." M << "\red The reason is: [reason]" @@ -956,25 +956,51 @@ message_admins("\blue [key_name_admin(usr)] booted [key_name_admin(M)].", 1) //M.client = null del(M.client) -/* - //Player Notes - else if(href_list["notes"]) - var/ckey = href_list["ckey"] - if(!ckey) - var/mob/M = locate(href_list["mob"]) - if(ismob(M)) - ckey = M.ckey - switch(href_list["notes"]) - if("show") - notes_show(ckey) - if("add") - notes_add(ckey,href_list["text"]) - notes_show(ckey) - if("remove") - notes_remove(ckey,text2num(href_list["from"]),text2num(href_list["to"])) - notes_show(ckey) -*/ + //Player Notes + else if(href_list["addnote"]) + var/target_ckey = href_list["addnote"] + add_note(target_ckey) + + else if(href_list["addnoteempty"]) + add_note() + + else if(href_list["removenote"]) + var/note_id = href_list["removenote"] + remove_note(note_id) + + else if(href_list["editnote"]) + var/note_id = href_list["editnote"] + edit_note(note_id) + + else if(href_list["shownote"]) + var/target = href_list["shownote"] + show_note(index = target) + + else if(href_list["nonalpha"]) + var/target = href_list["nonalpha"] + target = text2num(target) + show_note(index = target) + + else if(href_list["shownoteckey"]) + var/target_ckey = href_list["shownoteckey"] + show_note(target_ckey) + + else if(href_list["notessearch"]) + var/target = href_list["notessearch"] + show_note(index = target) + + else if(href_list["noteedits"]) + var/note_id = sanitizeSQL("[href_list["noteedits"]]") + var/DBQuery/query_noteedits = dbcon.NewQuery("SELECT edits FROM [format_table_name("notes")] WHERE id = '[note_id]'") + if(!query_noteedits.Execute()) + var/err = query_noteedits.ErrorMsg() + log_game("SQL ERROR obtaining edits from notes table. Error : \[[err]\]\n") + return + if(query_noteedits.NextRow()) + var/edit_log = query_noteedits.item[1] + usr << browse(edit_log,"window=noteedits") + else if(href_list["removejobban"]) if(!check_rights(R_BAN)) return @@ -3031,35 +3057,6 @@ src.admincaster_signature = adminscrub(input(usr, "Provide your desired signature", "Network Identity Handler", "")) src.access_news_network() - if(href_list["add_player_info"]) - var/key = href_list["add_player_info"] - var/add = input("Add Player Info") as null|text - if(!add) return - - notes_add(key,add,usr) - show_player_info(key) - - if(href_list["remove_player_info"]) - var/key = href_list["remove_player_info"] - var/index = text2num(href_list["remove_index"]) - - notes_del(key, index) - show_player_info(key) - - if(href_list["notes"]) - var/ckey = href_list["ckey"] - if(!ckey) - var/mob/M = locate(href_list["mob"]) - if(ismob(M)) - ckey = M.ckey - - switch(href_list["notes"]) - if("show") - show_player_info(ckey) - if("list") - PlayerNotesPage(text2num(href_list["index"])) - return - if(href_list["secretsmenu"]) switch(href_list["secretsmenu"]) if("tab") diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index cc97f6193f7..3bd236ee42b 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -282,6 +282,9 @@ winset(src, null, "command=\".configure graphics-hwmode on\"") log_client_to_db() + + if (config && config.autoconvert_notes) + convert_notes_sql(ckey) send_resources() diff --git a/config/example/config.txt b/config/example/config.txt index 1ee86a8a09c..b1ae26f6803 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -271,8 +271,8 @@ EVENT_DELAY_UPPER 15;45;70 ## The delay until the first time an event of the given severity runs in minutes. ## Unset setting use the EVENT_DELAY_LOWER and EVENT_DELAY_UPPER values instead. -# EVENT_CUSTOM_START_MINOR 10;15 -# EVENT_CUSTOM_START_MODERATE 30;45 +#EVENT_CUSTOM_START_MINOR 10;15 +#EVENT_CUSTOM_START_MODERATE 30;45 EVENT_CUSTOM_START_MAJOR 80;100 ## Strength of ambient star light. Set to 0 or less to turn off. @@ -288,4 +288,7 @@ PLAYER_REROUTE_CAP 0 #OVERFLOW_SERVER_URL byond://example.org:1111 ## Disable the loading of away missions -# DISABLE_AWAY_MISSIONS \ No newline at end of file +#DISABLE_AWAY_MISSIONS + +## Comment this out if you've used the mass conversion sql proc for notes or want to stop converting notes +AUTOCONVERT_NOTES \ No newline at end of file diff --git a/paradise.dme b/paradise.dme index 12deff3c44e..3024d97fff4 100644 --- a/paradise.dme +++ b/paradise.dme @@ -55,6 +55,7 @@ #include "code\__HELPERS\timed_alerts.dm" #include "code\__HELPERS\type2type.dm" #include "code\__HELPERS\unsorted.dm" +#include "code\__HELPERS\bygex\bygex.dm" #include "code\_globalvars\configuration.dm" #include "code\_globalvars\database.dm" #include "code\_globalvars\game_modes.dm" @@ -910,9 +911,9 @@ #include "code\modules\admin\machine_upgrade.dm" #include "code\modules\admin\NewBan.dm" #include "code\modules\admin\newbanjob.dm" -#include "code\modules\admin\player_notes.dm" #include "code\modules\admin\player_panel.dm" #include "code\modules\admin\secrets.dm" +#include "code\modules\admin\sql_notes.dm" #include "code\modules\admin\topic.dm" #include "code\modules\admin\ToRban.dm" #include "code\modules\admin\watchlist.dm"