mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-30 07:27:57 +01:00
Async SQL + SSdbcore (#15007)
* Initial Commit - Async SQL * First batch of queries * More progress * Nukes DB Polls * More work * oops * One push * Notes work now * Ok these work * Watchlist done * Async Bans! * Async Permissions * Async client procs * I officially hate preference datums * Also these * Async Custom Items * Async Karma * Async Library * Async TOS * Cleans out the old SQL code * CI Sanity * Apparently MySQL doesnt support this * What about this * Maybe this * Review pass 1 * This too * Fixes job ban loading * Fix undeleted queries * Prevents sensitive queries being logged * Documentation + tweaks * Adds a verb to force reconnect the DB * More review tweaks * Farie tweaks * Fixes this
This commit is contained in:
+149
-143
@@ -188,73 +188,6 @@
|
||||
if("prefs") return prefs.process_link(usr,href_list)
|
||||
if("vars") return view_var_Topic(href,href_list,hsrc)
|
||||
|
||||
//Polls and shit
|
||||
if(href_list["showpoll"])
|
||||
handle_player_polling()
|
||||
return
|
||||
if(href_list["createpollwindow"])
|
||||
create_poll_window()
|
||||
return
|
||||
if(href_list["createpoll"])
|
||||
create_poll_function(href_list)
|
||||
return
|
||||
if(href_list["pollid"])
|
||||
var/pollid = href_list["pollid"]
|
||||
if(istext(pollid))
|
||||
pollid = text2num(pollid)
|
||||
if(isnum(pollid))
|
||||
poll_player(pollid)
|
||||
return
|
||||
if(href_list["pollresults"])
|
||||
var/pollid = href_list["pollresults"]
|
||||
if(istext(pollid))
|
||||
pollid = text2num(pollid)
|
||||
if(isnum(pollid))
|
||||
poll_results(pollid)
|
||||
if(href_list["votepollid"] && href_list["votetype"])
|
||||
if(!can_vote())
|
||||
return // No voting.
|
||||
var/pollid = text2num(href_list["votepollid"])
|
||||
var/votetype = href_list["votetype"]
|
||||
switch(votetype)
|
||||
if("OPTION")
|
||||
var/optionid = text2num(href_list["voteoptionid"])
|
||||
vote_on_poll(pollid, optionid)
|
||||
if("TEXT")
|
||||
var/replytext = href_list["replytext"]
|
||||
log_text_poll_reply(pollid, replytext)
|
||||
if("NUMVAL")
|
||||
var/id_min = text2num(href_list["minid"])
|
||||
var/id_max = text2num(href_list["maxid"])
|
||||
|
||||
if( (id_max - id_min) > 100 ) //Basic exploit prevention
|
||||
to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.")
|
||||
return
|
||||
|
||||
for(var/optionid = id_min; optionid <= id_max; optionid++)
|
||||
if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to
|
||||
var/rating
|
||||
if(href_list["o[optionid]"] == "abstain")
|
||||
rating = null
|
||||
else
|
||||
rating = text2num(href_list["o[optionid]"])
|
||||
if(!isnum(rating))
|
||||
return
|
||||
|
||||
vote_on_numval_poll(pollid, optionid, rating)
|
||||
if("MULTICHOICE")
|
||||
var/id_min = text2num(href_list["minoptionid"])
|
||||
var/id_max = text2num(href_list["maxoptionid"])
|
||||
|
||||
if( (id_max - id_min) > 100 ) //Basic exploit prevention
|
||||
to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.")
|
||||
return
|
||||
|
||||
for(var/optionid = id_min; optionid <= id_max; optionid++)
|
||||
if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected
|
||||
vote_on_poll(pollid, optionid, 1)
|
||||
src << browse(null, "window=playerpoll")
|
||||
handle_player_polling()
|
||||
if(href_list["ssdwarning"])
|
||||
ssd_warning_acknowledged = TRUE
|
||||
to_chat(src, "<span class='notice'>SSD warning acknowledged.</span>")
|
||||
@@ -337,8 +270,6 @@
|
||||
|
||||
to_chat(src, "<span class='warning'>If the title screen is black, resources are still downloading. Please be patient until the title screen appears.</span>")
|
||||
|
||||
|
||||
GLOB.clients += src
|
||||
GLOB.directory[ckey] = src
|
||||
//Admin Authorisation
|
||||
// Automatically makes localhost connection an admin
|
||||
@@ -362,6 +293,12 @@
|
||||
if(world.byond_version >= 511 && byond_version >= 511 && prefs.clientfps)
|
||||
fps = prefs.clientfps
|
||||
|
||||
// This has to go here to avoid issues
|
||||
// If you sleep past this point, you will get SSinput errors as well as goonchat errors
|
||||
// DO NOT STUFF RANDOM SQL QUERIES BELOW THIS POINT WITHOUT USING `INVOKE_ASYNC()` OR SIMILAR
|
||||
// YOU WILL BREAK STUFF. SERIOUSLY. -aa07
|
||||
GLOB.clients += src
|
||||
|
||||
spawn() // Goonchat does some non-instant checks in start()
|
||||
chatOutput.start()
|
||||
|
||||
@@ -372,7 +309,8 @@
|
||||
if(holder)
|
||||
on_holder_add()
|
||||
add_admin_verbs()
|
||||
admin_memo_output("Show", 0, 1)
|
||||
// Must be async because any sleeps (happen in sql queries) will break connectings clients
|
||||
INVOKE_ASYNC(src, .proc/admin_memo_output, "Show", FALSE, TRUE)
|
||||
|
||||
// Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays.
|
||||
// (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise)
|
||||
@@ -382,7 +320,6 @@
|
||||
winset(src, null, "command=\".configure graphics-hwmode on\"")
|
||||
|
||||
log_client_to_db(tdata)
|
||||
|
||||
. = ..() //calls mob.Login()
|
||||
|
||||
|
||||
@@ -406,11 +343,9 @@
|
||||
|
||||
|
||||
if(prefs.toggles & PREFTOGGLE_DISABLE_KARMA) // activates if karma is disabled
|
||||
if(establish_db_connection())
|
||||
to_chat(src,"<span class='notice'>You have disabled karma gains.") // reminds those who have it disabled
|
||||
to_chat(src,"<span class='notice'>You have disabled karma gains.") // reminds those who have it disabled
|
||||
else
|
||||
if(establish_db_connection())
|
||||
to_chat(src,"<span class='notice'>You have enabled karma gains.")
|
||||
to_chat(src,"<span class='notice'>You have enabled karma gains.")
|
||||
|
||||
generate_clickcatcher()
|
||||
apply_clickcatcher()
|
||||
@@ -482,11 +417,11 @@
|
||||
|
||||
|
||||
/client/proc/donator_check()
|
||||
set waitfor = FALSE // This needs to run async because any sleep() inside /client/New() breaks stuff badly
|
||||
if(IsGuestKey(key))
|
||||
return
|
||||
|
||||
establish_db_connection()
|
||||
if(!GLOB.dbcon.IsConnected())
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
|
||||
if(check_rights(R_ADMIN, 0, mob)) // Yes, the mob is required, regardless of other examples in this file, it won't work otherwise
|
||||
@@ -495,33 +430,44 @@
|
||||
return
|
||||
|
||||
//Donator stuff.
|
||||
var/DBQuery/query_donor_select = GLOB.dbcon.NewQuery("SELECT ckey, tier, active FROM `[format_table_name("donators")]` WHERE ckey = '[ckey]'")
|
||||
query_donor_select.Execute()
|
||||
var/datum/db_query/query_donor_select = SSdbcore.NewQuery("SELECT ckey, tier, active FROM `[format_table_name("donators")]` WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
|
||||
if(!query_donor_select.warn_execute())
|
||||
qdel(query_donor_select)
|
||||
return
|
||||
|
||||
while(query_donor_select.NextRow())
|
||||
if(!text2num(query_donor_select.item[3]))
|
||||
// Inactive donator.
|
||||
donator_level = 0
|
||||
qdel(query_donor_select)
|
||||
return
|
||||
donator_level = text2num(query_donor_select.item[2])
|
||||
donor_loadout_points()
|
||||
break
|
||||
qdel(query_donor_select)
|
||||
|
||||
/client/proc/donor_loadout_points()
|
||||
if(donator_level > 0 && prefs)
|
||||
prefs.max_gear_slots = config.max_loadout_points + 5
|
||||
|
||||
/client/proc/log_client_to_db(connectiontopic)
|
||||
set waitfor = FALSE // This needs to run async because any sleep() inside /client/New() breaks stuff badly
|
||||
if(IsGuestKey(key))
|
||||
return
|
||||
|
||||
|
||||
establish_db_connection()
|
||||
if(!GLOB.dbcon.IsConnected())
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
qdel(query)
|
||||
return
|
||||
|
||||
var/DBQuery/query = GLOB.dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
|
||||
query.Execute()
|
||||
var/sql_id = 0
|
||||
player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if there is a record.
|
||||
while(query.NextRow())
|
||||
@@ -529,22 +475,33 @@
|
||||
player_age = text2num(query.item[2])
|
||||
break
|
||||
|
||||
|
||||
var/DBQuery/query_ip = GLOB.dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = '[address]'")
|
||||
query_ip.Execute()
|
||||
qdel(query)
|
||||
var/datum/db_query/query_ip = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip=:address", list(
|
||||
"address" = address
|
||||
))
|
||||
if(!query_ip.warn_execute())
|
||||
qdel(query_ip)
|
||||
return
|
||||
related_accounts_ip = list()
|
||||
while(query_ip.NextRow())
|
||||
if(ckey != query_ip.item[1])
|
||||
related_accounts_ip.Add("[query_ip.item[1]]")
|
||||
|
||||
qdel(query_ip)
|
||||
|
||||
var/datum/db_query/query_cid = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid=:cid", list(
|
||||
"cid" = computer_id
|
||||
))
|
||||
if(!query_cid.warn_execute())
|
||||
qdel(query_cid)
|
||||
return
|
||||
|
||||
var/DBQuery/query_cid = GLOB.dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid = '[computer_id]'")
|
||||
query_cid.Execute()
|
||||
related_accounts_cid = list()
|
||||
while(query_cid.NextRow())
|
||||
if(ckey != query_cid.item[1])
|
||||
related_accounts_cid.Add("[query_cid.item[1]]")
|
||||
|
||||
qdel(query_cid)
|
||||
|
||||
var/admin_rank = "Player"
|
||||
if(holder)
|
||||
@@ -573,18 +530,19 @@
|
||||
if(!isnum(sql_id))
|
||||
return
|
||||
|
||||
var/sql_ip = sanitizeSQL(address)
|
||||
var/sql_computerid = sanitizeSQL(computer_id)
|
||||
var/sql_admin_rank = sanitizeSQL(admin_rank)
|
||||
|
||||
|
||||
if(sql_id)
|
||||
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
|
||||
var/DBQuery/query_update = GLOB.dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]")
|
||||
if(!query_update.Execute())
|
||||
var/err = query_update.ErrorMsg()
|
||||
log_game("SQL ERROR during log_client_to_db (update). Error : \[[err]\]\n")
|
||||
message_admins("SQL ERROR during log_client_to_db (update). Error : \[[err]\]\n")
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
|
||||
"sql_ip" = address,
|
||||
"sql_cid" = computer_id,
|
||||
"sql_ar" = admin_rank,
|
||||
"sql_id" = sql_id
|
||||
))
|
||||
|
||||
if(!query_update.warn_execute())
|
||||
qdel(query_update)
|
||||
return
|
||||
qdel(query_update)
|
||||
// After the regular update
|
||||
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, FALSE) // Async to avoid other procs in the client chain being delayed by a web request
|
||||
else
|
||||
@@ -597,18 +555,30 @@
|
||||
qdel(src)
|
||||
return // Dont insert or they can just go in again
|
||||
|
||||
var/DBQuery/query_insert = GLOB.dbcon.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
|
||||
if(!query_insert.Execute())
|
||||
var/err = query_insert.ErrorMsg()
|
||||
log_game("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n")
|
||||
message_admins("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n")
|
||||
var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)", list(
|
||||
"ckey" = ckey,
|
||||
"ip" = address,
|
||||
"cid" = computer_id,
|
||||
"rank" = admin_rank
|
||||
))
|
||||
if(!query_insert.warn_execute())
|
||||
qdel(query_insert)
|
||||
return
|
||||
qdel(query_insert)
|
||||
// This is their first connection instance, so TRUE here to nofiy admins
|
||||
// This needs to happen here to ensure they actually have a row to update
|
||||
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, TRUE) // Async to avoid other procs in the client chain being delayed by a web request
|
||||
|
||||
// Log player connections to DB
|
||||
var/DBQuery/query_accesslog = GLOB.dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`datetime`,`ckey`,`ip`,`computerid`) VALUES(Now(),'[ckey]','[sql_ip]','[sql_computerid]');")
|
||||
query_accesslog.Execute()
|
||||
var/datum/db_query/query_accesslog = SSdbcore.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`datetime`,`ckey`,`ip`,`computerid`) VALUES(Now(), :ckey, :ip, :cid)", list(
|
||||
"ckey" = ckey,
|
||||
"ip" = address,
|
||||
"cid" = computer_id
|
||||
))
|
||||
// We do nothing with output here, or anything else after, so we dont need to if() wrap it
|
||||
// If you ever extend this proc below this point, please wrap these with an if() in the same way its done above
|
||||
query_accesslog.warn_execute()
|
||||
qdel(query_accesslog)
|
||||
|
||||
/client/proc/check_ip_intel()
|
||||
set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep
|
||||
@@ -655,16 +625,29 @@
|
||||
to_chat(src, "<B>You have no verified forum account. <a href='?src=[UID()];link_forum_account=true'>VERIFY FORUM ACCOUNT</a></B>")
|
||||
|
||||
/client/proc/create_oauth_token()
|
||||
var/DBQuery/query_find_token = GLOB.dbcon.NewQuery("SELECT token FROM [format_table_name("oauth_tokens")] WHERE ckey = '[ckey]' limit 1")
|
||||
if(!query_find_token.Execute())
|
||||
log_debug("create_oauth_token: failed db read")
|
||||
var/datum/db_query/query_find_token = SSdbcore.NewQuery("SELECT token FROM [format_table_name("oauth_tokens")] WHERE ckey=:ckey limit 1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
// These queries have log_error=FALSE to avoid auth tokens being in plaintext logs
|
||||
if(!query_find_token.warn_execute(log_error=FALSE))
|
||||
qdel(query_find_token)
|
||||
return
|
||||
if(query_find_token.NextRow())
|
||||
qdel(query_find_token)
|
||||
return query_find_token.item[1]
|
||||
qdel(query_find_token)
|
||||
|
||||
var/tokenstr = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]")
|
||||
var/DBQuery/query_insert_token = GLOB.dbcon.NewQuery("INSERT INTO [format_table_name("oauth_tokens")] (ckey, token) VALUES('[ckey]','[tokenstr]')")
|
||||
if(!query_insert_token.Execute())
|
||||
|
||||
var/datum/db_query/query_insert_token = SSdbcore.NewQuery("INSERT INTO [format_table_name("oauth_tokens")] (ckey, token) VALUES(:ckey, :tokenstr)", list(
|
||||
"ckey" = ckey,
|
||||
"tokenstr" = tokenstr,
|
||||
))
|
||||
// These queries have log_error=FALSE to avoid auth tokens being in plaintext logs
|
||||
if(!query_insert_token.warn_execute(log_error=FALSE))
|
||||
qdel(query_insert_token)
|
||||
return
|
||||
qdel(query_insert_token)
|
||||
return tokenstr
|
||||
|
||||
/client/proc/link_forum_account(fromban)
|
||||
@@ -677,15 +660,19 @@
|
||||
if(!fromban)
|
||||
to_chat(src, "Your forum account is already set.")
|
||||
return
|
||||
var/DBQuery/query_find_link = GLOB.dbcon.NewQuery("SELECT fuid FROM [format_table_name("player")] WHERE ckey = '[ckey]' limit 1")
|
||||
if(!query_find_link.Execute())
|
||||
log_debug("link_forum_account: failed db read")
|
||||
var/datum/db_query/query_find_link = SSdbcore.NewQuery("SELECT fuid FROM [format_table_name("player")] WHERE ckey=:ckey LIMIT 1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_find_link.warn_execute())
|
||||
qdel(query_find_link)
|
||||
return
|
||||
if(query_find_link.NextRow())
|
||||
if(query_find_link.item[1])
|
||||
if(!fromban)
|
||||
to_chat(src, "Your forum account is already set. (" + query_find_link.item[1] + ")")
|
||||
qdel(query_find_link)
|
||||
return
|
||||
qdel(query_find_link)
|
||||
var/tokenid = create_oauth_token()
|
||||
if(!tokenid)
|
||||
to_chat(src, "link_forum_account: unable to create token")
|
||||
@@ -705,6 +692,7 @@
|
||||
|
||||
// Returns true if a randomizer is being used
|
||||
/client/proc/check_randomizer(topic)
|
||||
set waitfor = FALSE // Yes I know this is already called from an async proc but someone may change that without thinking properly
|
||||
. = FALSE
|
||||
if(connection != "seeker") //Invalid connection type.
|
||||
return null
|
||||
@@ -721,12 +709,17 @@
|
||||
var/oldcid = cidcheck[ckey]
|
||||
|
||||
if(!oldcid)
|
||||
var/DBQuery/query_cidcheck = GLOB.dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
|
||||
query_cidcheck.Execute()
|
||||
var/datum/db_query/query_cidcheck = SSdbcore.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_cidcheck.warn_execute())
|
||||
qdel(query_cidcheck)
|
||||
return
|
||||
|
||||
var/lastcid = computer_id
|
||||
if(query_cidcheck.NextRow())
|
||||
lastcid = query_cidcheck.item[1]
|
||||
qdel(query_cidcheck)
|
||||
|
||||
if(computer_id != lastcid)
|
||||
// Their current CID does not match what the DB says - OFF WITH THEIR HEAD
|
||||
@@ -786,23 +779,30 @@
|
||||
var/const/adminckey = "CID-Error"
|
||||
|
||||
// Check for notes in the last day - only 1 note per 24 hours
|
||||
var/DBQuery/query_get_notes = GLOB.dbcon.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey = '[ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()")
|
||||
if(!query_get_notes.Execute())
|
||||
var/err = query_get_notes.ErrorMsg()
|
||||
log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n")
|
||||
var/datum/db_query/query_get_notes = SSdbcore.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey=:ckey AND adminckey=:adminckey AND timestamp + INTERVAL 1 DAY < NOW()", list(
|
||||
"ckey" = ckey,
|
||||
"adminckey" = adminckey
|
||||
))
|
||||
if(!query_get_notes.warn_execute())
|
||||
qdel(query_get_notes)
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
qdel(query_get_notes)
|
||||
return
|
||||
qdel(query_get_notes)
|
||||
|
||||
// Only add a note if their most recent note isn't from the randomizer blocker, either
|
||||
query_get_notes = GLOB.dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[ckey]' ORDER BY timestamp DESC LIMIT 1")
|
||||
if(!query_get_notes.Execute())
|
||||
var/err = query_get_notes.ErrorMsg()
|
||||
log_game("SQL ERROR obtaining adminckey from notes table. Error : \[[err]\]\n")
|
||||
var/datum/db_query/query_get_note = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey=:ckey ORDER BY timestamp DESC LIMIT 1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_get_note.warn_execute())
|
||||
qdel(query_get_note)
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
if(query_get_notes.item[1] == adminckey)
|
||||
if(query_get_note.NextRow())
|
||||
if(query_get_note.item[1] == adminckey)
|
||||
qdel(query_get_note)
|
||||
return
|
||||
qdel(query_get_note)
|
||||
add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0)
|
||||
|
||||
/client/proc/cid_check_reconnect()
|
||||
@@ -1043,17 +1043,19 @@
|
||||
|
||||
/client/proc/get_byond_account_date(notify = FALSE)
|
||||
// First we see if the client has a saved date in the DB
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/DBQuery/query_date = GLOB.dbcon.NewQuery("SELECT byond_date, DATEDIFF(Now(), byond_date) FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_date.Execute())
|
||||
var/err = query_date.ErrorMsg()
|
||||
log_game("SQL ERROR during get_byond_account_date (Line 1047). Error: \[[err]\]\n")
|
||||
message_admins("SQL ERROR during get_byond_account_date (Line 1047). Error: \[[err]\]\n")
|
||||
var/datum/db_query/query_date = SSdbcore.NewQuery("SELECT byond_date, DATEDIFF(Now(), byond_date) FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_date.warn_execute())
|
||||
qdel(query_date)
|
||||
return
|
||||
|
||||
while(query_date.NextRow())
|
||||
byondacc_date = query_date.item[1]
|
||||
byondacc_age = max(text2num(query_date.item[2]), 0) // Ensure account isnt negative days old
|
||||
|
||||
qdel(query_date)
|
||||
|
||||
// They have a date, lets bail
|
||||
if(byondacc_date)
|
||||
return
|
||||
@@ -1067,22 +1069,26 @@
|
||||
byondacc_date = byond_data["general"]["joined"]
|
||||
|
||||
// Now save it
|
||||
var/sql_date = sanitizeSQL(byondacc_date) // Yes, this is top level paranoia
|
||||
var/DBQuery/query_update = GLOB.dbcon.NewQuery("UPDATE [format_table_name("player")] SET byond_date = '[sql_date]' WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_update.Execute())
|
||||
var/err = query_update.ErrorMsg()
|
||||
log_game("SQL ERROR during get_byond_account_date (Line 1071). Error: \[[err]\]\n")
|
||||
message_admins("SQL ERROR during get_byond_account_date (Line 1071). Error: \[[err]\]\n")
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET byond_date=:date WHERE ckey=:ckey", list(
|
||||
"date" = byondacc_date,
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_update.warn_execute())
|
||||
qdel(query_update)
|
||||
return
|
||||
qdel(query_update)
|
||||
|
||||
// Now retrieve the age again because BYOND doesnt have native methods for this
|
||||
var/DBQuery/query_age = GLOB.dbcon.NewQuery("SELECT DATEDIFF(Now(), byond_date) FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_age.Execute())
|
||||
var/err = query_age.ErrorMsg()
|
||||
log_game("SQL ERROR during get_byond_account_date (Line 1078). Error: \[[err]\]\n")
|
||||
message_admins("SQL ERROR during get_byond_account_date (Line 1078). Error: \[[err]\]\n")
|
||||
var/datum/db_query/query_age = SSdbcore.NewQuery("SELECT DATEDIFF(Now(), byond_date) FROM [format_table_name("player")] WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_age.warn_execute())
|
||||
qdel(query_age)
|
||||
return
|
||||
|
||||
while(query_age.NextRow())
|
||||
byondacc_age = max(text2num(query_age.item[1]), 0) // Ensure account isnt negative days old
|
||||
qdel(query_age)
|
||||
|
||||
// Notify admins on new clients connecting, if the byond account age is less than a config value
|
||||
if(notify && (byondacc_age < config.byond_account_age_threshold))
|
||||
|
||||
Reference in New Issue
Block a user