From 44f21210429396cdaf410407859fa24d53f952e6 Mon Sep 17 00:00:00 2001 From: skull132 Date: Wed, 2 Mar 2016 22:44:00 +0200 Subject: [PATCH 01/21] Remove forumdb Unused object and vars. Cleans them up, as well as removes the config file. --- code/controllers/configuration.dm | 42 ------------------------------- code/global.dm | 10 -------- code/world.dm | 1 - config/example/forumdbconfig.txt | 19 -------------- 4 files changed, 72 deletions(-) delete mode 100644 config/example/forumdbconfig.txt diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index ea01ad942fa..c7e24f54627 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -777,48 +777,6 @@ var/list/gamemode_cache = list() else log_misc("Unknown setting in configuration: '[name]'") -/datum/configuration/proc/loadforumsql(filename) // -- TLE - var/list/Lines = file2list(filename) - for(var/t in Lines) - if(!t) continue - - t = trim(t) - if (length(t) == 0) - continue - else if (copytext(t, 1, 2) == "#") - continue - - var/pos = findtext(t, " ") - var/name = null - var/value = null - - if (pos) - name = lowertext(copytext(t, 1, pos)) - value = copytext(t, pos + 1) - else - name = lowertext(t) - - if (!name) - continue - - switch (name) - if ("address") - forumsqladdress = value - if ("port") - forumsqlport = value - if ("database") - forumsqldb = value - if ("login") - forumsqllogin = value - if ("password") - forumsqlpass = value - if ("activatedgroup") - forum_activated_group = value - if ("authenticatedgroup") - forum_authenticated_group = value - else - log_misc("Unknown setting in configuration: '[name]'") - /datum/configuration/proc/pick_mode(mode_name) // I wish I didn't have to instance the game modes in order to look up // their information, but it is the only way (at least that I know of). diff --git a/code/global.dm b/code/global.dm index 626960698b1..f701cfef194 100644 --- a/code/global.dm +++ b/code/global.dm @@ -195,16 +195,6 @@ var/sqllogin = "root" var/sqlpass = "" var/sqllogging = 0 // Should we log deaths, population stats, etc.? -// Forum MySQL configuration. (for use with forum account/key authentication) -// These are all default values that will load should the forumdbconfig.txt file fail to read for whatever reason. -var/forumsqladdress = "localhost" -var/forumsqlport = "3306" -var/forumsqldb = "tgstation" -var/forumsqllogin = "root" -var/forumsqlpass = "" -var/forum_activated_group = "2" -var/forum_authenticated_group = "10" - // For FTP requests. (i.e. downloading runtime logs.) // However it'd be ok to use for accessing attack logs and such too, which are even laggier. var/fileaccess_timer = 0 diff --git a/code/world.dm b/code/world.dm index 88dea018a5f..afdaa5bfa6b 100644 --- a/code/world.dm +++ b/code/world.dm @@ -535,7 +535,6 @@ var/world_topic_spam_protect_time = world.timeofday config.load("config/config.txt") config.load("config/game_options.txt","game_options") config.loadsql("config/dbconfig.txt") - config.loadforumsql("config/forumdbconfig.txt") /hook/startup/proc/loadMods() world.load_mods() diff --git a/config/example/forumdbconfig.txt b/config/example/forumdbconfig.txt deleted file mode 100644 index 61a2a2d6ecd..00000000000 --- a/config/example/forumdbconfig.txt +++ /dev/null @@ -1,19 +0,0 @@ -# This configuration file is for the forum database, if you need to set up -# population, death, etc. tracking see 'dbconfig.txt' -# The login credentials for this will likely differ from those in dbconfig.txt! - -# Server the MySQL database can be found at -# Examples: localhost, 200.135.5.43, www.mysqldb.com, etc. -ADDRESS localhost - -# MySQL server port (default is 3306) -PORT 3306 - -# Database the forum data may be found in -DATABASE tgstation13 - -# Username/Login used to access the database -LOGIN mylogin - -# Password used to access the database -PASSWORD mypassword \ No newline at end of file From d46499a310962389aa594df91827fcc54effb91f Mon Sep 17 00:00:00 2001 From: skull132 Date: Thu, 3 Mar 2016 06:55:18 +0200 Subject: [PATCH 02/21] DBConnection object modifications Renames the variables of the DBConnection object to make differentiating them easier. Reworks the `DBConnection/New()` and `Connect()` methods to allow for the automatic creation of the dbi handler string. Adds a con_database variable to DBConnection to enable this. DBConnection objects now also house the current database they're using for this purpose. Moves the constructor for dbcon under `/hook/startup/proc/connectDB()`, as it needs to be called after the SQL config has been read by `datum/global_init/New()` --- code/defines/procs/dbcore.dm | 56 +++++++++++++++++++----------------- code/global.dm | 3 +- code/world.dm | 11 +++---- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm index cd5f5dcdbd9..c1915051633 100644 --- a/code/defines/procs/dbcore.dm +++ b/code/defines/procs/dbcore.dm @@ -31,39 +31,40 @@ #define BLOB 14 // TODO: Investigate more recent type additions and see if I can handle them. - Nadrew - -// Deprecated! See global.dm for new configuration vars -/* -var/DB_SERVER = "" // This is the location of your MySQL server (localhost is USUALLY fine) -var/DB_PORT = 3306 // This is the port your MySQL server is running on (3306 is the default) -*/ - DBConnection var/_db_con // This variable contains a reference to the actual database connection. - var/dbi // This variable is a string containing the DBI MySQL requires. - var/user // This variable contains the username data. - var/password // This variable contains the password data. - var/default_cursor // This contains the default database cursor data. - // - var/server = "" - var/port = 3306 + var/con_dbi // This variable is a string containing the DBI MySQL requires. + var/con_user // This variable contains the username data. + var/con_password // This variable contains the password data. + var/con_cursor // This contains the default database cursor data. + var/con_server = "" + var/con_port = 3306 + var/con_database = "" + +DBConnection/New(server, port = 3306, database, username, password_handler, cursor_handler = Default_Cursor, dbi_handler) + con_user = username + con_password = password_handler + con_cursor = cursor_handler + con_server = server + con_port = port + con_database = database + + if (dbi_handler) + con_dbi = dbi_handler + else + con_dbi = "dbi:mysql:[database]:[server]:[port]" -DBConnection/New(dbi_handler, username, password_handler, cursor_handler) - dbi = dbi_handler - user = username - password = password_handler - default_cursor = cursor_handler _db_con = _dm_db_new_con() -DBConnection/proc/Connect(dbi_handler = dbi, user_handler = user, password_handler = password, cursor_handler) +DBConnection/proc/Connect(dbi_handler = con_dbi, user_handler = con_user, password_handler = con_password, cursor_handler) if (!sqllogging) return 0 if (!src) return 0 - cursor_handler = default_cursor + cursor_handler = con_cursor if (!cursor_handler) cursor_handler = Default_Cursor - return _dm_db_connect(_db_con,dbi_handler, user_handler, password_handler, cursor_handler, null) + return _dm_db_connect(_db_con, dbi_handler, user_handler, password_handler, cursor_handler, null) DBConnection/proc/Disconnect() return _dm_db_close(_db_con) @@ -80,12 +81,13 @@ DBConnection/proc/Quote(str) DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con) -DBConnection/proc/SelectDB(database_name,dbi) - if(IsConnected()) Disconnect() - //return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password) - return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[sqladdress]:[sqlport]"]", user, password) +DBConnection/proc/SelectDB(database_name, new_dbi) + if (IsConnected()) + Disconnect() + con_database = database_name + return Connect(new_dbi ? new_dbi : "dbi:mysql:[database_name]:[con_server]:[con_port]", con_user, con_password) -DBConnection/proc/NewQuery(sql_query, cursor_handler = default_cursor) +DBConnection/proc/NewQuery(sql_query, cursor_handler = con_cursor) return new/DBQuery(sql_query, src, cursor_handler) DBQuery diff --git a/code/global.dm b/code/global.dm index f701cfef194..ed69df69f45 100644 --- a/code/global.dm +++ b/code/global.dm @@ -202,7 +202,8 @@ var/custom_event_msg = null // Database connections. A connection is established on world creation. // Ideally, the connection dies when the server restarts (After feedback logging.). -var/DBConnection/dbcon = new() // Feedback database (New database) +// Feedback database. Constructor in /hook/startup/proc/connectDB() +var/DBConnection/dbcon // Reference list for disposal sort junctions. Filled up by sorting junction's New() /var/list/tagger_locations = list() diff --git a/code/world.dm b/code/world.dm index afdaa5bfa6b..f0315fde9c0 100644 --- a/code/world.dm +++ b/code/world.dm @@ -646,6 +646,9 @@ var/failed_db_connections = 0 var/failed_old_db_connections = 0 /hook/startup/proc/connectDB() + //Construct the database object now that configs are loaded + dbcon = new(sqladdress, sqlport, sqldb, sqllogin, sqlpass) + if(!setup_database_connection()) world.log << "Your server failed to establish a connection with the feedback database." else @@ -660,13 +663,7 @@ proc/setup_database_connection() if(!dbcon) dbcon = new() - var/user = sqllogin - var/pass = sqlpass - var/db = sqldb - var/address = sqladdress - var/port = sqlport - - dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") + dbcon.Connect() . = dbcon.IsConnected() if ( . ) failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter. From 8383f1c03b2f15d5ed71b6be49c8de915ac1f7c3 Mon Sep 17 00:00:00 2001 From: skull132 Date: Thu, 3 Mar 2016 07:04:49 +0200 Subject: [PATCH 03/21] Generalizing establish_db_connection() and setup_database_connection() Both procs are now generalized, and accept a DBConnection object as an argument. Due to this generalization, all instances of `establish_db_connection()` must be renamed to `establish_db_connection(dbcon)`. Also added variable `failed_connections` to the definition of DBConnection. --- code/controllers/news_controller.dm | 4 +-- code/defines/procs/dbcore.dm | 1 + code/defines/procs/statistics.dm | 8 ++--- code/game/jobs/whitelist.dm | 4 +-- code/game/machinery/requests_console.dm | 6 ++-- code/modules/admin/DB ban/ban_mirroring.dm | 2 +- code/modules/admin/DB ban/functions.dm | 8 ++--- code/modules/admin/IsBanned.dm | 2 +- code/modules/admin/admin_ranks.dm | 2 +- code/modules/admin/banjob.dm | 2 +- .../admin/permissionverbs/permissionedit.dm | 4 +-- code/modules/admin/player_notes_sql.dm | 10 +++--- .../admin/verbs/check_customitem_activity.dm | 2 +- code/modules/admin/verbs/warning.dm | 12 +++---- code/modules/client/client procs.dm | 4 +-- code/modules/library/lib_machines.dm | 8 ++--- code/modules/mob/new_player/new_player.dm | 4 +-- code/modules/mob/new_player/poll.dm | 12 +++---- code/modules/research/message_server.dm | 2 +- code/world.dm | 32 ++++++++++--------- 20 files changed, 66 insertions(+), 63 deletions(-) diff --git a/code/controllers/news_controller.dm b/code/controllers/news_controller.dm index 1598fc8a226..f8d9ce3c808 100644 --- a/code/controllers/news_controller.dm +++ b/code/controllers/news_controller.dm @@ -27,7 +27,7 @@ var/global/datum/news_controller/news_controller //Stores a new article for publishing. /datum/news_controller/proc/update() - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) error("SQL database connection failed. News_controller failed to retreive information.") fails++ @@ -52,7 +52,7 @@ var/global/datum/news_controller/news_controller //Publish the stored article. /datum/news_controller/proc/publish() - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) error("SQL database connection failed. News_controller failed to retreive information.") fails++ diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm index c1915051633..88335bd0aa4 100644 --- a/code/defines/procs/dbcore.dm +++ b/code/defines/procs/dbcore.dm @@ -40,6 +40,7 @@ DBConnection var/con_server = "" var/con_port = 3306 var/con_database = "" + var/failed_connections = 0 DBConnection/New(server, port = 3306, database, username, password_handler, cursor_handler = Default_Cursor, dbi_handler) con_user = username diff --git a/code/defines/procs/statistics.dm b/code/defines/procs/statistics.dm index 01c97f4fcfc..8eaf7a90a27 100644 --- a/code/defines/procs/statistics.dm +++ b/code/defines/procs/statistics.dm @@ -6,7 +6,7 @@ proc/sql_poll_population() for(var/mob/M in player_list) if(M.client) playercount += 1 - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) log_game("SQL ERROR during population polling. Failed to connect.") else @@ -49,7 +49,7 @@ proc/sql_report_death(var/mob/living/carbon/human/H) var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") var/coord = "[H.x], [H.y], [H.z]" //world << "INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()])" - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) log_game("SQL ERROR during death reporting. Failed to connect.") else @@ -83,7 +83,7 @@ proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H) var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") var/coord = "[H.x], [H.y], [H.z]" //world << "INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()])" - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) log_game("SQL ERROR during death reporting. Failed to connect.") else @@ -113,7 +113,7 @@ proc/sql_commit_feedback() log_game("Round ended without any feedback being generated. No feedback was sent to the database.") return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) log_game("SQL ERROR during feedback reporting. Failed to connect.") else diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm index b6f16388be7..28b216654d3 100644 --- a/code/game/jobs/whitelist.dm +++ b/code/game/jobs/whitelist.dm @@ -9,7 +9,7 @@ var/list/whitelist = list() /proc/load_whitelist() if (config.sql_whitelists) - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) //Continue with the old code if we have no database. @@ -43,7 +43,7 @@ var/list/whitelist = list() /proc/load_alienwhitelist() if (config.sql_whitelists) - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) //Continue with the old code if we have no database. diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 7f24da000a9..7fc553fdf81 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -211,7 +211,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() if(11) //form database dat += text("NanoTrasen Corporate Forms

") - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) dat += text("ERROR: Unable to contact external database. Please contact your system administrator for assistance.") log_game("SQL database connection failed. Attempted to fetch form information.") @@ -377,7 +377,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() if(href_list["print"]) var/printid = sanitizeSQL(href_list["print"]) - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) alert("Connection to the database lost. Aborting.") @@ -405,7 +405,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() if(href_list["whatis"]) var/whatisid = sanitizeSQL(href_list["whatis"]) - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) alert("Connection to the database lost. Aborting.") if(!whatisid) diff --git a/code/modules/admin/DB ban/ban_mirroring.dm b/code/modules/admin/DB ban/ban_mirroring.dm index 588acbdfccb..d6af7bafbba 100644 --- a/code/modules/admin/DB ban/ban_mirroring.dm +++ b/code/modules/admin/DB ban/ban_mirroring.dm @@ -6,7 +6,7 @@ if (!ckey || !address || !computer_id || !ban_id) return - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) error("Ban database connection failure while attempting to mirror. Key passed for mirror handling: [ckey].") diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index e36fc4ff21f..d266eaf7295 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -4,7 +4,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = if(!check_rights(R_MOD,0) && !check_rights(R_BAN)) return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return @@ -122,7 +122,7 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") if(job) sql += " AND job = '[job]'" - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return @@ -217,7 +217,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) var/sql = "SELECT ckey FROM ss13_ban WHERE id = [id]" - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return @@ -269,7 +269,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) if(!check_rights(R_BAN)) return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) usr << "\red Failed to establish database connection" return diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index da4f2af534b..37eb7cc691b 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -34,7 +34,7 @@ world/IsBanned(key,address,computer_id) var/ckeytext = ckey(key) - if(!establish_db_connection()) + if(!establish_db_connection(dbcon)) error("Ban database connection failure. Key [ckeytext] not checked") log_misc("Ban database connection failure. Key [ckeytext] not checked") return diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index 27eb8b6d3f3..3049976dfad 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -102,7 +102,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights else //The current admin system uses SQL - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) error("Failed to connect to database in load_admins(). Reverting to legacy system.") log_misc("Failed to connect to database in load_admins(). Reverting to legacy system.") diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm index ae04799354c..96899fc6d9c 100644 --- a/code/modules/admin/banjob.dm +++ b/code/modules/admin/banjob.dm @@ -65,7 +65,7 @@ DEBUG jobban_keylist=list() log_admin("jobban_keylist was empty") else - if(!establish_db_connection()) + if(!establish_db_connection(dbcon)) error("Database connection failed. Reverting to the legacy ban system.") log_misc("Database connection failed. Reverting to the legacy ban system.") config.ban_legacy_system = 1 diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm index 0969fa35d88..1af56750311 100644 --- a/code/modules/admin/permissionverbs/permissionedit.dm +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -54,7 +54,7 @@ usr << "\red You do not have permission to do this!" return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) usr << "\red Failed to establish database connection" @@ -104,7 +104,7 @@ usr << "\red You do not have permission to do this!" return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) usr << "\red Failed to establish database connection" return diff --git a/code/modules/admin/player_notes_sql.dm b/code/modules/admin/player_notes_sql.dm index 1d447110771..cfd42df4b7c 100644 --- a/code/modules/admin/player_notes_sql.dm +++ b/code/modules/admin/player_notes_sql.dm @@ -12,7 +12,7 @@ else query_details[":a_ckey"] = user.ckey - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) alert("SQL connection failed while trying to add a note!") return @@ -36,7 +36,7 @@ if (!note_id || !note_edit) return - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) error("SQL connection failed while attempting to delete a note!") return @@ -93,7 +93,7 @@ player_ckey = ckey(player_ckey) admin_ckey = ckey(admin_ckey) - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) error("SQL connection failed while attempting to view a player's notes!") return @@ -187,7 +187,7 @@ if (!ckey) return "No ckey given!" - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) return "Unable to establish database connection! Aborting!" @@ -231,7 +231,7 @@ note_list >> note_keys msg_scopes("Establishing DB connection!") - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) msg_scopes("No DB connection!") return diff --git a/code/modules/admin/verbs/check_customitem_activity.dm b/code/modules/admin/verbs/check_customitem_activity.dm index 8d701e26734..e9bbaded60b 100644 --- a/code/modules/admin/verbs/check_customitem_activity.dm +++ b/code/modules/admin/verbs/check_customitem_activity.dm @@ -29,7 +29,7 @@ var/inactive_keys = "None
" if(checked_for_inactives) return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return diff --git a/code/modules/admin/verbs/warning.dm b/code/modules/admin/verbs/warning.dm index b19454d04de..3ad7a81bfff 100644 --- a/code/modules/admin/verbs/warning.dm +++ b/code/modules/admin/verbs/warning.dm @@ -9,7 +9,7 @@ if (!warned_ckey || !istext(warned_ckey)) return - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) usr << "Error: warn(): Database Connection failed, reverting to legacy systems." usr.client.warn_legacy(warned_ckey) @@ -110,7 +110,7 @@ var/dcolor = "#ffaaaa" //dark colour, severity = 1 var/ecolor = "#e3e3e3" //gray colour, expired = 1 - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) alert("Connection to the SQL database lost. Aborting. Please alert an Administrator or a member of staff.") return @@ -172,7 +172,7 @@ if (!warning_id) return - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) alert("Connection to SQL database failed while attempting to update your warning's status!") return @@ -191,7 +191,7 @@ var/count = 0 var/count_expire = 0 - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) return @@ -239,7 +239,7 @@ var/dcolor = "#ffdddd" //dark colour, severity = 1 var/ecolor = "#e3e3e3" //gray colour, expired = 1 - establish_db_connection() + establish_db_connection(dbcon) if (!dbcon.IsConnected()) alert("Connection to the SQL database lost. Aborting. Please alert the database admin!") return @@ -342,7 +342,7 @@ if(!warning_id || !warning_edit) return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) alert("Connection to the SQL database lost. Aborting. Please alert the database admin!") return diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 09127b10095..672c15387fe 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -203,7 +203,7 @@ // Returns null if no DB connection can be established, or -1 if the requested key was not found in the database /proc/get_player_age(key) - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return null @@ -223,7 +223,7 @@ if ( IsGuestKey(src.key) ) return - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index fd86f484ac9..7bbdaed4749 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -43,7 +43,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f Filter by Author: [author]
\[Start Search\]
"} if(1) - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance.
" else if(!SQLquery) @@ -189,7 +189,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f (Return to main menu)
"} if(4) dat += "

External Archive

" - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance." else @@ -332,7 +332,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f if(scanner.cache.unique) alert("This book has been rejected from the database. Aborting!") else - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) alert("Connection to Archive has been severed. Aborting.") else @@ -355,7 +355,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f if(href_list["targetid"]) var/sqlid = sanitizeSQL(href_list["targetid"]) - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) alert("Connection to Archive has been severed. Aborting.") if(bibledelay) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index c5716172a08..ca7d753590c 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -41,7 +41,7 @@ output += "

Observe

" if(!IsGuestKey(src.key)) - establish_db_connection() + establish_db_connection(dbcon) if(dbcon.IsConnected()) var/isadmin = 0 @@ -181,7 +181,7 @@ return if(href_list["privacy_poll"]) - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return var/voted = 0 diff --git a/code/modules/mob/new_player/poll.dm b/code/modules/mob/new_player/poll.dm index 953119961e0..6051d178b4b 100644 --- a/code/modules/mob/new_player/poll.dm +++ b/code/modules/mob/new_player/poll.dm @@ -1,6 +1,6 @@ /mob/new_player/proc/handle_privacy_poll() - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return var/voted = 0 @@ -47,7 +47,7 @@ var/optiontext /mob/new_player/proc/handle_player_polling() - establish_db_connection() + establish_db_connection(dbcon) if(dbcon.IsConnected()) var/isadmin = 0 if(src.client && src.client.holder) @@ -81,7 +81,7 @@ /mob/new_player/proc/poll_player(var/pollid = -1) if(pollid == -1) return - establish_db_connection() + establish_db_connection(dbcon) if(dbcon.IsConnected()) var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM ss13_poll_question WHERE id = [pollid]") @@ -342,7 +342,7 @@ if(!isnum(pollid) || !isnum(optionid)) return - establish_db_connection() + establish_db_connection(dbcon) if(dbcon.IsConnected()) var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM ss13_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") @@ -412,7 +412,7 @@ if(!isnum(pollid) || !istext(replytext)) return - establish_db_connection() + establish_db_connection(dbcon) if(dbcon.IsConnected()) var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM ss13_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") @@ -470,7 +470,7 @@ if(!isnum(pollid) || !isnum(optionid)) return - establish_db_connection() + establish_db_connection(dbcon) if(dbcon.IsConnected()) var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM ss13_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index 9655f3b3dcd..9144cd11d98 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -297,7 +297,7 @@ var/obj/machinery/blackbox_recorder/blackbox if(!feedback) return round_end_data_gathering() //round_end time logging and some other data processing - establish_db_connection() + establish_db_connection(dbcon) if(!dbcon.IsConnected()) return var/round_id diff --git a/code/world.dm b/code/world.dm index f0315fde9c0..bc23a3a54ea 100644 --- a/code/world.dm +++ b/code/world.dm @@ -649,37 +649,39 @@ var/failed_old_db_connections = 0 //Construct the database object now that configs are loaded dbcon = new(sqladdress, sqlport, sqldb, sqllogin, sqlpass) - if(!setup_database_connection()) + if (!setup_database_connection(dbcon)) world.log << "Your server failed to establish a connection with the feedback database." else world.log << "Feedback database connection established." return 1 -proc/setup_database_connection() - - if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. +/proc/setup_database_connection(var/DBConnection/con) + if (!con) return 0 - if(!dbcon) - dbcon = new() + if (con.failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. + return 0 - dbcon.Connect() - . = dbcon.IsConnected() + con.Connect() + . = con.IsConnected() if ( . ) - failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter. + con.failed_connections = 0 //If this connection succeeded, reset the failed connections counter. else - failed_db_connections++ //If it failed, increase the failed connections counter. - world.log << dbcon.ErrorMsg() + con.failed_connections++ //If it failed, increase the failed connections counter. + world.log << con.ErrorMsg() return . //This proc ensures that the connection to the feedback database (global variable dbcon) is established -proc/establish_db_connection() - if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) +/proc/establish_db_connection(var/DBConnection/con) + if (!con) return 0 - if(!dbcon || !dbcon.IsConnected()) - return setup_database_connection() + if (con.failed_connections > FAILED_DB_CONNECTION_CUTOFF) + return 0 + + if (!con.IsConnected()) + return setup_database_connection(con) else return 1 From 202b21609245db3ba2d697c793543ca79b3d1509 Mon Sep 17 00:00:00 2001 From: skull132 Date: Fri, 4 Mar 2016 01:37:41 +0200 Subject: [PATCH 04/21] More reworking of DB handling sqllogging depracted in favour of config.sql_enabled. Database loading is done through /hook/startup/proc/load_databases, with initialize_database_object() being a generalized proc to read any generic database config file. (TODO: config examples in relaiton to last remark.) --- code/controllers/configuration.dm | 42 +------------------------- code/defines/procs/dbcore.dm | 4 +-- code/defines/procs/statistics.dm | 12 ++++---- code/global.dm | 11 +------ code/world.dm | 50 +++++++++++++++++++++++++++---- 5 files changed, 54 insertions(+), 65 deletions(-) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index c7e24f54627..f347605febe 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -277,7 +277,7 @@ var/list/gamemode_cache = list() config.log_access = 1 if ("sql_enabled") - config.sql_enabled = text2num(value) + config.sql_enabled = 1 if ("log_say") config.log_say = 1 @@ -737,46 +737,6 @@ var/list/gamemode_cache = list() else log_misc("Unknown setting in configuration: '[name]'") -/datum/configuration/proc/loadsql(filename) // -- TLE - var/list/Lines = file2list(filename) - for(var/t in Lines) - if(!t) continue - - t = trim(t) - if (length(t) == 0) - continue - else if (copytext(t, 1, 2) == "#") - continue - - var/pos = findtext(t, " ") - var/name = null - var/value = null - - if (pos) - name = lowertext(copytext(t, 1, pos)) - value = copytext(t, pos + 1) - else - name = lowertext(t) - - if (!name) - continue - - switch (name) - if ("address") - sqladdress = value - if ("port") - sqlport = value - if ("database") - sqldb = value - if ("login") - sqllogin = value - if ("password") - sqlpass = value - if ("enable_stat_tracking") - sqllogging = 1 - else - log_misc("Unknown setting in configuration: '[name]'") - /datum/configuration/proc/pick_mode(mode_name) // I wish I didn't have to instance the game modes in order to look up // their information, but it is the only way (at least that I know of). diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm index 88335bd0aa4..67dc76a8e24 100644 --- a/code/defines/procs/dbcore.dm +++ b/code/defines/procs/dbcore.dm @@ -58,7 +58,7 @@ DBConnection/New(server, port = 3306, database, username, password_handler, curs _db_con = _dm_db_new_con() DBConnection/proc/Connect(dbi_handler = con_dbi, user_handler = con_user, password_handler = con_password, cursor_handler) - if (!sqllogging) + if (!config.sql_enabled) return 0 if (!src) return 0 @@ -71,7 +71,7 @@ DBConnection/proc/Disconnect() return _dm_db_close(_db_con) DBConnection/proc/IsConnected() - if(!sqllogging) + if(!config.sql_enabled) return 0 var/success = _dm_db_is_connected(_db_con) return success diff --git a/code/defines/procs/statistics.dm b/code/defines/procs/statistics.dm index 8eaf7a90a27..e807e4cbbce 100644 --- a/code/defines/procs/statistics.dm +++ b/code/defines/procs/statistics.dm @@ -1,5 +1,5 @@ proc/sql_poll_population() - if(!sqllogging) + if(!config.sql_enabled) return var/admincount = admins.len var/playercount = 0 @@ -18,15 +18,15 @@ proc/sql_poll_population() proc/sql_report_round_start() // TODO - if(!sqllogging) + if(!config.sql_enabled) return proc/sql_report_round_end() // TODO - if(!sqllogging) + if(!config.sql_enabled) return proc/sql_report_death(var/mob/living/carbon/human/H) - if(!sqllogging) + if(!config.sql_enabled) return if(!H) return @@ -60,7 +60,7 @@ proc/sql_report_death(var/mob/living/carbon/human/H) proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H) - if(!sqllogging) + if(!config.sql_enabled) return if(!H) return @@ -94,7 +94,7 @@ proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H) proc/statistic_cycle() - if(!sqllogging) + if(!config.sql_enabled) return while(1) sql_poll_population() diff --git a/code/global.dm b/code/global.dm index ed69df69f45..ccb57713b0e 100644 --- a/code/global.dm +++ b/code/global.dm @@ -187,22 +187,13 @@ var/datum/subsystem/alarm/alarm_manager = new() // Alarm Manager, the manager fo var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to. -// MySQL configuration -var/sqladdress = "localhost" -var/sqlport = "3306" -var/sqldb = "tgstation" -var/sqllogin = "root" -var/sqlpass = "" -var/sqllogging = 0 // Should we log deaths, population stats, etc.? - // For FTP requests. (i.e. downloading runtime logs.) // However it'd be ok to use for accessing attack logs and such too, which are even laggier. var/fileaccess_timer = 0 var/custom_event_msg = null -// Database connections. A connection is established on world creation. +// Database connections. A connection is established along with /hook/startup/proc/load_databases(). // Ideally, the connection dies when the server restarts (After feedback logging.). -// Feedback database. Constructor in /hook/startup/proc/connectDB() var/DBConnection/dbcon // Reference list for disposal sort junctions. Filled up by sorting junction's New() diff --git a/code/world.dm b/code/world.dm index bc23a3a54ea..6148324b93b 100644 --- a/code/world.dm +++ b/code/world.dm @@ -534,7 +534,6 @@ var/world_topic_spam_protect_time = world.timeofday config = new /datum/configuration() config.load("config/config.txt") config.load("config/game_options.txt","game_options") - config.loadsql("config/dbconfig.txt") /hook/startup/proc/loadMods() world.load_mods() @@ -642,12 +641,10 @@ var/world_topic_spam_protect_time = world.timeofday src.status = s #define FAILED_DB_CONNECTION_CUTOFF 5 -var/failed_db_connections = 0 -var/failed_old_db_connections = 0 -/hook/startup/proc/connectDB() - //Construct the database object now that configs are loaded - dbcon = new(sqladdress, sqlport, sqldb, sqllogin, sqlpass) +/hook/startup/proc/load_databases() + //Construct the database object from an init file. + dbcon = initialize_database_object("config/dbconfig.txt") if (!setup_database_connection(dbcon)) world.log << "Your server failed to establish a connection with the feedback database." @@ -655,8 +652,48 @@ var/failed_old_db_connections = 0 world.log << "Feedback database connection established." return 1 +/proc/initialize_database_object(var/filename) + if (!filename) + return 0 + + var/list/data = list("address", "port", "database", "login", "password") + + var/list/Lines = file2list(filename) + for (var/t in Lines) + if (!t) + continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + name = lowertext(copytext(t, 1, pos)) + value = copytext(t, pos + 1) + + if (!name) + continue + + if (name in data) + data[name] = value + else + log_misc("Unknown setting while setting up database connection. Filename: '[filename]', value: '[value]'.") + + //Validate the data before proceeding. + for (var/d in data) + if (!data[d] || data[d] == null) + return 0 + + return new/DBConnection(data["address"], data["port"], data["database"], data["login"], data["password"]) + /proc/setup_database_connection(var/DBConnection/con) if (!con) + error("No DBConnection object passed to setup_database_connection().") return 0 if (con.failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. @@ -675,6 +712,7 @@ var/failed_old_db_connections = 0 //This proc ensures that the connection to the feedback database (global variable dbcon) is established /proc/establish_db_connection(var/DBConnection/con) if (!con) + error("No DBConnection object passed to establish_db_connection() proc.") return 0 if (con.failed_connections > FAILED_DB_CONNECTION_CUTOFF) From 8c30b617e3f55ffe910c83f701b934caf42746da Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 5 Mar 2016 00:53:36 +0200 Subject: [PATCH 05/21] Webinterface Config Settings Configuration settings for using the webinterface in future updates. --- code/controllers/configuration.dm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index f347605febe..94d55548fbc 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -208,6 +208,10 @@ var/list/gamemode_cache = list() var/aggressive_changelog = 0 + //Webinterface settings + var/webinterface_enabled = 0 + var/webinterface_url = "" + /datum/configuration/New() var/list/L = typesof(/datum/game_mode) - /datum/game_mode for (var/T in L) @@ -674,6 +678,12 @@ var/list/gamemode_cache = list() if("show_auxiliary_roles") config.show_auxiliary_roles = 1 + if("use_webinterface") + config.webinterface_enabled = 1 + + if("webinterface_url") + config.webinterface_url = 1 + else log_misc("Unknown setting in configuration: '[name]'") From ce5d2009a2040cca61656e9bcf812d8c4a5389b1 Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 5 Mar 2016 00:54:16 +0200 Subject: [PATCH 06/21] User Linking With Webinterface Enables the user to link their account to a forum account, for use later. --- code/modules/client/client procs.dm | 98 ++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 672c15387fe..5bcafd01bb9 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -74,7 +74,63 @@ if(href_list["warnview"]) warnings_check() - ..() //redirect to hsrc.Topic() + if(href_list["linkingrequest"]) + if (!config.webinterface_enabled) + return + + if (!href_list["linkingaction"]) + return + + var/request_id = text2num(href_list["linkingrequest"]) + + establish_db_connection(dbcon) + if (!dbcon.IsConnected()) + usr << "\red Action failed! Database link could not be established!" + return + + + var/DBQuery/check_query = dbcon.NewQuery("SELECT player_ckey, status FROM ss13_player_linking WHERE id = :id") + check_query.Execute(list(":id" = request_id)) + + if (!check_query.NextRow()) + usr << "\red No request found!" + return + + if (ckey(check_query.item[1]) != ckey || check_query.item[2] != "new") + usr << "\red Request authentication failed!" + return + + var/query_contents = "" + var/list/query_details[] + var/feedback_message = "" + switch (href_list["linkingaction"]) + if ("accept") + query_contents = "UPDATE ss13_player_linking SET status = :new_status, updated_at = NOW() WHERE id = :id" + query_details[":new_status"] = "confirmed" + query_details[":id"] = request_id + + feedback_message = "Account successfully linked!" + if ("deny") + query_contents = "UPDATE ss13_player_linking SET status = :new_status, deleted_at = NOW() WHERE id = :id" + query_details[":new_status"] = "rejected" + query_details[":id"] = request_id + + feedback_message = "Link request rejected!" + else + usr << "\red Invalid command sent." + return + + var/DBQuery/update_query = dbcon.NewQuery(query_contents) + update_query.Execute(query_details) + + if (href_list["linkingaction"] == "accept" && config.webinterface_url) + if(alert("To complete the process, you have to visit the website. Do you ",,"Yes","No") == "Yes") + usr << link("[config.webinterface_url]user/link") + + usr << feedback_message + return + + ..() //redirect to hsrc.() /client/proc/handle_spam_prevention(var/message, var/mute_type) if(config.automute_on && !holder && src.last_message == message) @@ -175,6 +231,8 @@ log_client_to_db() + check_linking_requests() + send_resources() nanomanager.send_resources(src) @@ -288,6 +346,44 @@ #undef UPLOAD_LIMIT #undef MIN_CLIENT_VERSION +/client/proc/check_linking_requests() + if (!config.webinterface_enabled || !config.sql_enabled) + return + + establish_db_connection(dbcon) + if (!dbcon.IsConnected()) + return + + var/list/requests = list() + var/list/query_details = list(":ckey" = ckey) + + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, forum_id, forum_username, datediff(Now(), created_at) as request_age FROM ss13_player_linking WHERE status = 'new' AND player_ckey = :ckey AND deleted_at IS NULL") + select_query.Execute(query_details) + + while (select_query.NextRow()) + requests.Add(list(list("id" = text2num(select_query.item[1]), "forum_id" = text2num(select_query.item[2]), "forum_username" = select_query.item[3], "request_age" = select_query.item[4]))) + + if (!requests.len) + return + + var/dat = "
You have active requests to check!
" + var/i = 0 + for (var/list/request in requests) + var/linked_forum_name = null + if (config.forumurl) + linked_forum_name = "[request["forum_username"]]" + + dat += "
" + dat += "#[i] - Request to link [key] to a forum account with the username of: [linked_forum_name ? linked_forum_name : request["forum_username"]].
" + dat += "The request is [request["request_age"]] days old.
" + dat += "OPTIONS: Accept Request | Deny Request" + + i++ + + usr << browse(dat, "window=LinkingRequests") + return + + //checks if a client is afk //3000 frames = 5 minutes /client/proc/is_afk(duration=3000) From 62f3eae9fd4516d1a73687afa1c49a66182f7255 Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 5 Mar 2016 01:36:11 +0200 Subject: [PATCH 07/21] Fix linkingaction Fixes the data it sends via the request. --- code/modules/client/client procs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 5bcafd01bb9..9e567160b61 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -376,7 +376,7 @@ dat += "
" dat += "#[i] - Request to link [key] to a forum account with the username of: [linked_forum_name ? linked_forum_name : request["forum_username"]].
" dat += "The request is [request["request_age"]] days old.
" - dat += "OPTIONS: Accept Request | Deny Request" + dat += "OPTIONS: Accept Request | Deny Request" i++ From e64f0de1551a69e301357d2a550943926fab67f0 Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 5 Mar 2016 01:44:28 +0200 Subject: [PATCH 08/21] routeAPI attribute Do this as a standalone proc, and in a more secure fashion later! --- code/modules/client/client procs.dm | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 9e567160b61..f32656b1749 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -130,6 +130,26 @@ usr << feedback_message return + if (href_list["routeAPI"]) + var/linkURI = "" + + switch (href_list["routeAPI"]) + if ("forums/members") + if (!href_list["routeAttribute"]) + return + + if (!config.forumurl) + return + + linkURI = "[config.forumurl]memberlist.php?" + + linkURI += list2params(list("mode" = "viewprofile", "u" = href_list["routeAttribute"])) + + if (linkURI) + usr << link(linkURI) + else + return + ..() //redirect to hsrc.() /client/proc/handle_spam_prevention(var/message, var/mute_type) @@ -369,17 +389,17 @@ var/dat = "
You have active requests to check!
" var/i = 0 for (var/list/request in requests) + i++ + var/linked_forum_name = null if (config.forumurl) - linked_forum_name = "[request["forum_username"]]" + linked_forum_name = "[request["forum_username"]]" dat += "
" dat += "#[i] - Request to link [key] to a forum account with the username of: [linked_forum_name ? linked_forum_name : request["forum_username"]].
" dat += "The request is [request["request_age"]] days old.
" dat += "OPTIONS: Accept Request | Deny Request" - i++ - usr << browse(dat, "window=LinkingRequests") return From 5fd128b63791a2aa452a2e4f568ab218875d2550 Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 5 Mar 2016 01:52:53 +0200 Subject: [PATCH 09/21] usr -> src fix --- code/modules/client/client procs.dm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index f32656b1749..5abc3cc2a1c 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -85,7 +85,7 @@ establish_db_connection(dbcon) if (!dbcon.IsConnected()) - usr << "\red Action failed! Database link could not be established!" + src << "\red Action failed! Database link could not be established!" return @@ -93,11 +93,11 @@ check_query.Execute(list(":id" = request_id)) if (!check_query.NextRow()) - usr << "\red No request found!" + src << "\red No request found!" return if (ckey(check_query.item[1]) != ckey || check_query.item[2] != "new") - usr << "\red Request authentication failed!" + src << "\red Request authentication failed!" return var/query_contents = "" @@ -117,7 +117,7 @@ feedback_message = "Link request rejected!" else - usr << "\red Invalid command sent." + src << "\red Invalid command sent." return var/DBQuery/update_query = dbcon.NewQuery(query_contents) @@ -125,9 +125,9 @@ if (href_list["linkingaction"] == "accept" && config.webinterface_url) if(alert("To complete the process, you have to visit the website. Do you ",,"Yes","No") == "Yes") - usr << link("[config.webinterface_url]user/link") + src << link("[config.webinterface_url]user/link") - usr << feedback_message + src << feedback_message return if (href_list["routeAPI"]) @@ -146,7 +146,7 @@ linkURI += list2params(list("mode" = "viewprofile", "u" = href_list["routeAttribute"])) if (linkURI) - usr << link(linkURI) + src << link(linkURI) else return @@ -400,7 +400,7 @@ dat += "The request is [request["request_age"]] days old.
" dat += "OPTIONS: Accept Request | Deny Request" - usr << browse(dat, "window=LinkingRequests") + src << browse(dat, "window=LinkingRequests") return From ed0e7ca4118ba20598b54267159796b58edd8c38 Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 5 Mar 2016 02:58:35 +0200 Subject: [PATCH 10/21] Infrastructure for Processing Weblinks Should make the functions that rely on feeding links for the user about the webinterface easier and faster. Simply need to modify the `process_webAPI_link()` proc and call the specific hyperlinks. --- code/modules/client/client procs.dm | 138 ++++++++++++++++------------ 1 file changed, 77 insertions(+), 61 deletions(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 5abc3cc2a1c..82f11d47365 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -101,7 +101,7 @@ return var/query_contents = "" - var/list/query_details[] + var/list/query_details = list(":new_status", ":id") var/feedback_message = "" switch (href_list["linkingaction"]) if ("accept") @@ -123,32 +123,17 @@ var/DBQuery/update_query = dbcon.NewQuery(query_contents) update_query.Execute(query_details) - if (href_list["linkingaction"] == "accept" && config.webinterface_url) - if(alert("To complete the process, you have to visit the website. Do you ",,"Yes","No") == "Yes") - src << link("[config.webinterface_url]user/link") + if (href_list["linkingaction"] == "accept" && alert("To complete the process, you have to visit the website. Do you want to do so now?",,"Yes","No") == "Yes") + process_webAPI_link("interface/user/link") src << feedback_message + check_linking_requests() return if (href_list["routeAPI"]) - var/linkURI = "" + process_webAPI_link(href_list["routeAPI"], href_list["routeAttributes"]) - switch (href_list["routeAPI"]) - if ("forums/members") - if (!href_list["routeAttribute"]) - return - - if (!config.forumurl) - return - - linkURI = "[config.forumurl]memberlist.php?" - - linkURI += list2params(list("mode" = "viewprofile", "u" = href_list["routeAttribute"])) - - if (linkURI) - src << link(linkURI) - else - return + return ..() //redirect to hsrc.() @@ -366,44 +351,6 @@ #undef UPLOAD_LIMIT #undef MIN_CLIENT_VERSION -/client/proc/check_linking_requests() - if (!config.webinterface_enabled || !config.sql_enabled) - return - - establish_db_connection(dbcon) - if (!dbcon.IsConnected()) - return - - var/list/requests = list() - var/list/query_details = list(":ckey" = ckey) - - var/DBQuery/select_query = dbcon.NewQuery("SELECT id, forum_id, forum_username, datediff(Now(), created_at) as request_age FROM ss13_player_linking WHERE status = 'new' AND player_ckey = :ckey AND deleted_at IS NULL") - select_query.Execute(query_details) - - while (select_query.NextRow()) - requests.Add(list(list("id" = text2num(select_query.item[1]), "forum_id" = text2num(select_query.item[2]), "forum_username" = select_query.item[3], "request_age" = select_query.item[4]))) - - if (!requests.len) - return - - var/dat = "
You have active requests to check!
" - var/i = 0 - for (var/list/request in requests) - i++ - - var/linked_forum_name = null - if (config.forumurl) - linked_forum_name = "[request["forum_username"]]" - - dat += "
" - dat += "#[i] - Request to link [key] to a forum account with the username of: [linked_forum_name ? linked_forum_name : request["forum_username"]].
" - dat += "The request is [request["request_age"]] days old.
" - dat += "OPTIONS: Accept Request | Deny Request" - - src << browse(dat, "window=LinkingRequests") - return - - //checks if a client is afk //3000 frames = 5 minutes /client/proc/is_afk(duration=3000) @@ -460,12 +407,81 @@ ) -mob/proc/MayRespawn() +/mob/proc/MayRespawn() return 0 -client/proc/MayRespawn() +/client/proc/MayRespawn() if(mob) return mob.MayRespawn() // Something went wrong, client is usually kicked or transfered to a new mob at this point return 0 + +/client/proc/check_linking_requests() + if (!config.webinterface_enabled || !config.sql_enabled) + return + + establish_db_connection(dbcon) + if (!dbcon.IsConnected()) + return + + var/list/requests = list() + var/list/query_details = list(":ckey" = ckey) + + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, forum_id, forum_username, datediff(Now(), created_at) as request_age FROM ss13_player_linking WHERE status = 'new' AND player_ckey = :ckey AND deleted_at IS NULL") + select_query.Execute(query_details) + + while (select_query.NextRow()) + requests.Add(list(list("id" = text2num(select_query.item[1]), "forum_id" = text2num(select_query.item[2]), "forum_username" = select_query.item[3], "request_age" = select_query.item[4]))) + + if (!requests.len) + return + + var/dat = "
You have active requests to check!
" + var/i = 0 + for (var/list/request in requests) + i++ + + var/linked_forum_name = null + if (config.forumurl) + var/route_attributes = list2params(list("mode" = "viewprofile", "u" = request["forum_id"])) + linked_forum_name = "[request["forum_username"]]" + + dat += "
" + dat += "#[i] - Request to link your current key ([key]) to a forum account with the username of: [linked_forum_name ? linked_forum_name : request["forum_username"]].
" + dat += "The request is [request["request_age"]] days old.
" + dat += "OPTIONS: Accept Request | Deny Request" + + src << browse(dat, "window=LinkingRequests") + return + +/client/proc/process_webAPI_link(var/route, var/attributes) + if (!route) + return + + var/linkURI = "" + + switch (route) + if ("forums/members") + if (!attributes) + return + + if (!config.forumurl) + return + + linkURI = "[config.forumurl]memberlist.php?" + + linkURI += attributes + + if ("interface/user/link") + if (!config.webinterface_url) + return + + linkURI = "[config.webinterface_url]user/link" + + else + log_misc("Unrecognized routeAPI call used. Route sent: '[route]'.") + return + + src << link(linkURI) + return From bc26d508e118e3eb2d60b0ddb1da32b38694196d Mon Sep 17 00:00:00 2001 From: skull132 Date: Sat, 5 Mar 2016 03:10:48 +0200 Subject: [PATCH 11/21] view_linking_requests() verb Adds the verb to call the proc whenever. --- code/modules/client/client procs.dm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 82f11d47365..92234716690 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -417,6 +417,14 @@ // Something went wrong, client is usually kicked or transfered to a new mob at this point return 0 +//I honestly can't find a good place for this atm. +//If the webinterface interaction gets more features, I'll move it. - Skull132 +/client/verb/view_linking_requests() + set name = "View Linking Requests" + set category = "OOC" + + check_linking_requests() + /client/proc/check_linking_requests() if (!config.webinterface_enabled || !config.sql_enabled) return From 9143d5077a4220d30061d8fdea0ad64548488523 Mon Sep 17 00:00:00 2001 From: skull132 Date: Mon, 7 Mar 2016 19:00:28 +0200 Subject: [PATCH 12/21] webint_procs.dm Initial Commit Starting to create a bit of a library to hold functions related to the web interface. --- baystation12.dme | 1 + code/modules/web_interface/webint_procs.dm | 35 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 code/modules/web_interface/webint_procs.dm diff --git a/baystation12.dme b/baystation12.dme index aede49368ad..7b37efa3483 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1715,6 +1715,7 @@ #include "code\modules\virus2\helpers.dm" #include "code\modules\virus2\isolator.dm" #include "code\modules\virus2\items_devices.dm" +#include "code\modules\web_interface\webint_procs.dm" #include "code\TriDimension\controller.dm" #include "code\TriDimension\controller_presets.dm" #include "code\TriDimension\Movement.dm" diff --git a/code/modules/web_interface/webint_procs.dm b/code/modules/web_interface/webint_procs.dm new file mode 100644 index 00000000000..236a0ae0623 --- /dev/null +++ b/code/modules/web_interface/webint_procs.dm @@ -0,0 +1,35 @@ +/* + * Contains general purpose procs used with Aurora's web interface and related functions. + */ + +/* + * /proc/validate_webint_attributes() + * Used to validate parametres sent to procs that are meant to communicate with the web interface. + * Most commonly in Topic() calls, so that href tomfoolery is negated. + * + * Arguments: + * - var/list/required_attributes - A list of required attributes. This is what the other arguments will be tested against. Cannot be null. + * - var/list/attributes_list - The attributes to be validated, passed in a list form. Can be null. + * - var/attributes_text - The attributes to be validated, passed in a text form. (Formatted according to list2params() convention.) + * This overrides attributes_list if both are present. Can be null. + * + * Returns: + * 1 - if all required attributes are present, and no erronious ones exist. + * 0 - if certain required attributes are missing, or there are extras. + */ + +/proc/webint_validate_attributes(var/list/required_attributes, var/list/attributes_list, var/attributes_text) + if (!required_attributes || !istype(required_attributes) || !required_attributes.len) + return 0 + + if (attributes_text) + attributes_list = params2list(attributes_text) + + if (!attributes_list || !attributes_list.len) + return 0 + + for (var/attribute in attributes_list) + if (!(attribute in required_attributes)) + return 0 + + return 1 From 61e93b1d790996587f545b090637ef7db19d984d Mon Sep 17 00:00:00 2001 From: skull132 Date: Mon, 7 Mar 2016 19:01:03 +0200 Subject: [PATCH 13/21] Naming Standardization webint shall be the common word used now, replaced all instances of webinterface or webAPI with that one phrase. Should make it easier to read and search. --- code/controllers/configuration.dm | 14 ++++++------- code/modules/client/client procs.dm | 32 ++++++++++++++--------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 94d55548fbc..4a9f8c3bd55 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -208,9 +208,9 @@ var/list/gamemode_cache = list() var/aggressive_changelog = 0 - //Webinterface settings - var/webinterface_enabled = 0 - var/webinterface_url = "" + //Web interface settings + var/webint_enabled = 0 + var/webint_url = "" /datum/configuration/New() var/list/L = typesof(/datum/game_mode) - /datum/game_mode @@ -678,11 +678,11 @@ var/list/gamemode_cache = list() if("show_auxiliary_roles") config.show_auxiliary_roles = 1 - if("use_webinterface") - config.webinterface_enabled = 1 + if("use_webint") + config.webint_enabled = 1 - if("webinterface_url") - config.webinterface_url = 1 + if("webint_url") + config.webint_url = 1 else log_misc("Unknown setting in configuration: '[name]'") diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 92234716690..b4197f621e8 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -75,7 +75,7 @@ warnings_check() if(href_list["linkingrequest"]) - if (!config.webinterface_enabled) + if (!config.webint_enabled) return if (!href_list["linkingaction"]) @@ -124,14 +124,14 @@ update_query.Execute(query_details) if (href_list["linkingaction"] == "accept" && alert("To complete the process, you have to visit the website. Do you want to do so now?",,"Yes","No") == "Yes") - process_webAPI_link("interface/user/link") + process_webint_link("interface/user/link") src << feedback_message check_linking_requests() return - if (href_list["routeAPI"]) - process_webAPI_link(href_list["routeAPI"], href_list["routeAttributes"]) + if (href_list["routeWebInt"]) + process_webint_link(href_list["routeWebInt"], href_list["routeAttributes"]) return @@ -418,7 +418,7 @@ return 0 //I honestly can't find a good place for this atm. -//If the webinterface interaction gets more features, I'll move it. - Skull132 +//If the webint interaction gets more features, I'll move it. - Skull132 /client/verb/view_linking_requests() set name = "View Linking Requests" set category = "OOC" @@ -426,7 +426,7 @@ check_linking_requests() /client/proc/check_linking_requests() - if (!config.webinterface_enabled || !config.sql_enabled) + if (!config.webint_enabled || !config.sql_enabled) return establish_db_connection(dbcon) @@ -453,7 +453,7 @@ var/linked_forum_name = null if (config.forumurl) var/route_attributes = list2params(list("mode" = "viewprofile", "u" = request["forum_id"])) - linked_forum_name = "[request["forum_username"]]" + linked_forum_name = "[request["forum_username"]]" dat += "
" dat += "#[i] - Request to link your current key ([key]) to a forum account with the username of: [linked_forum_name ? linked_forum_name : request["forum_username"]].
" @@ -463,33 +463,33 @@ src << browse(dat, "window=LinkingRequests") return -/client/proc/process_webAPI_link(var/route, var/attributes) +/client/proc/process_webint_link(var/route, var/attributes) if (!route) return - var/linkURI = "" + var/linkURL = "" switch (route) if ("forums/members") - if (!attributes) + if (!webint_validate_attributes(list("mode", "u"), attributes_text = attributes)) return if (!config.forumurl) return - linkURI = "[config.forumurl]memberlist.php?" + linkURL = "[config.forumurl]memberlist.php?" - linkURI += attributes + linkURL += attributes if ("interface/user/link") - if (!config.webinterface_url) + if (!config.webint_url) return - linkURI = "[config.webinterface_url]user/link" + linkURL = "[config.webint_url]user/link" else - log_misc("Unrecognized routeAPI call used. Route sent: '[route]'.") + log_misc("Unrecognized process_webint_link() call used. Route sent: '[route]'.") return - src << link(linkURI) + src << link(linkURL) return From 6bb74a7a87c775012701c5c7bb81ada61717d0a8 Mon Sep 17 00:00:00 2001 From: skull132 Date: Mon, 14 Mar 2016 19:24:49 +0200 Subject: [PATCH 14/21] dbcore.dm - Better INT Management `parseArguments()` will now identify 0 as an itneger properly, instead of slotting it under null. --- code/defines/procs/dbcore.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm index 67dc76a8e24..166896587cf 100644 --- a/code/defines/procs/dbcore.dm +++ b/code/defines/procs/dbcore.dm @@ -197,12 +197,12 @@ DBQuery/proc/parseArguments(var/query_to_parse = null, var/list/argument_list, v var/argument = argument_list[placeholder] - if (isnull(argument)) - argument = "NULL" - else if (istext(argument)) + if (istext(argument)) argument = dbcon.Quote(argument) else if (isnum(argument)) - argument = "'[argument]'" + argument = "[argument]" + else if (isnull(argument)) + argument = "NULL" else log_debug("parseArguments() failed! Cannot identify argument!") return 0 From 997665bca7d8e9585e9bf4a334d20a9f2ee41bc5 Mon Sep 17 00:00:00 2001 From: skull132 Date: Mon, 21 Mar 2016 23:04:10 +0200 Subject: [PATCH 15/21] webint_procs.dm - webint_start_singlesignon() Proc for creating a unique signin token for the website and shoving it into the database. --- code/modules/web_interface/webint_procs.dm | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/code/modules/web_interface/webint_procs.dm b/code/modules/web_interface/webint_procs.dm index 236a0ae0623..332dcf19a54 100644 --- a/code/modules/web_interface/webint_procs.dm +++ b/code/modules/web_interface/webint_procs.dm @@ -32,4 +32,65 @@ if (!(attribute in required_attributes)) return 0 + if (attributes_list[attribute] && required_attributes[attribute]) + if (istype(required_attributes, /list)) + if (!(attributes_list[attribute] in required_attributes[attribute])) + return 0 + + else + if (attributes_list[attribute] != required_attributes[attribute]) + return 0 + return 1 + +/* + * /proc/webint_start_singlesignon() + * Used to insert a token into the web_sso database and to enable a user to navigate to a page on the website and be automatically logged in. Hashes the user's save file for a unique token. Additional security managed on the website's end. + * + * Arguments: + * - var/user - Must be a mob or a client. The player object that's going to be using the request. + * - var/list/attributes - The attributes to which we route the URL as we call user.process_webint_link(). + * Validated here with webint_validate_attributes(). + * Must contain the 'location' key. + * + * Returns: + * 0 - if one of the checks is failed and the operation cancelled. + * string - if everything works, it will return the attributes with the added token and ckey value. + */ + +/proc/webint_start_singlesignon(var/client/user, var/attributes) + if (!istype(user)) + return 0 + + var/list/permitted_locations = list("user_dashboard", "contract_overview", "contract_details") + + if (!webint_validate_attributes(list("location" = permitted_locations, "contract"), attributes_text = attributes)) + return 0 + + var/token = "" + var/list/alphabet = alphabet_uppercase + alphabet.Add(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")) + alphabet.Add(list("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")) + + for (var/i = 0, i <= 24, i++) + token += alphabet[rand(1, alphabet.len)] + + attributes += "&" + attributes += list2params(list("ckey" = user.ckey, "token" = token)) + + establish_db_connection(dbcon) + if (!dbcon.IsConnected()) + alert("An error occured while attempting to connect to the database!") + return 0 + + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO ss13_web_sso (ckey, token, ip, created_at) VALUES (:ckey, :token, :ip, NOW())") + insert_query.Execute(list(":ckey" = user.ckey, ":token" = token, ":ip" = user.address)) + + if (insert_query.ErrorMsg()) + alert("An error occured while trying to upload the session data!") + return 0 + + if (alert("This will take you to the webpage and log you in. Do you wish to proceed?",,"Yes","No") == "No") + return 0 + + return attributes From e03eaa86a55dc969cc84ed7ab6f98c714ceaf7e2 Mon Sep 17 00:00:00 2001 From: skull132 Date: Mon, 21 Mar 2016 23:05:31 +0200 Subject: [PATCH 16/21] client procs.dm - sso_server addition Adds a new route for the webint url parser. Also reverts to checking for config.webint_url as opposed to running double checks for config.webint_enabled and then for the url. If the URL is present, we're enabling the webint. --- code/modules/client/client procs.dm | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index b4197f621e8..3a936f7eb0c 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -75,7 +75,7 @@ warnings_check() if(href_list["linkingrequest"]) - if (!config.webint_enabled) + if (!config.webint_url) return if (!href_list["linkingaction"]) @@ -426,7 +426,7 @@ check_linking_requests() /client/proc/check_linking_requests() - if (!config.webint_enabled || !config.sql_enabled) + if (!config.webint_url || !config.sql_enabled) return establish_db_connection(dbcon) @@ -487,8 +487,20 @@ linkURL = "[config.webint_url]user/link" + if ("interface/login/sso_server") + //This also validates the attributes as it runs + var/new_attributes = webint_start_singlesignon(src, attributes) + if (!new_attributes) + return + + if (!config.webint_url) + return + + linkURL = "[config.webint_url]login/sso_server?" + linkURL += new_attributes + else - log_misc("Unrecognized process_webint_link() call used. Route sent: '[route]'.") + log_debug("Unrecognized process_webint_link() call used. Route sent: '[route]'.") return src << link(linkURL) From a5cb959166c6a75e77b11c58f6c0d641ebed8c3a Mon Sep 17 00:00:00 2001 From: skull132 Date: Mon, 21 Mar 2016 23:06:02 +0200 Subject: [PATCH 17/21] Remove config.webint_enabled Depracted in favour of using config.webint_url in general. Just checks if it's defined, and if so, we'll consider it active and in use. --- code/controllers/configuration.dm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 4a9f8c3bd55..c5e6c42c38a 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -209,7 +209,6 @@ var/list/gamemode_cache = list() var/aggressive_changelog = 0 //Web interface settings - var/webint_enabled = 0 var/webint_url = "" /datum/configuration/New() @@ -678,11 +677,8 @@ var/list/gamemode_cache = list() if("show_auxiliary_roles") config.show_auxiliary_roles = 1 - if("use_webint") - config.webint_enabled = 1 - if("webint_url") - config.webint_url = 1 + config.webint_url = value else log_misc("Unknown setting in configuration: '[name]'") From 7e266649ea010a6a5f1666e9bdeeb0ed7ac0c211 Mon Sep 17 00:00:00 2001 From: skull132 Date: Mon, 21 Mar 2016 23:07:04 +0200 Subject: [PATCH 18/21] Syndicate Contracts - Initial Implementation Adds SQL database based syndicate contracts to be viewed from any uplink. These can be used as IC traitor objectives, but hopefully with more RP and stuff. --- code/game/objects/items/devices/uplinks.dm | 115 +++++++++++++++++++++ nano/templates/uplink.tmpl | 80 +++++++++++++- 2 files changed, 190 insertions(+), 5 deletions(-) diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index c8f23054e4d..888dd0bb4de 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -257,6 +257,16 @@ datum/nano_item_lists if(href_list["menu"]) nanoui_menu = text2num(href_list["menu"]) update_nano_data(href_list["id"]) + if(href_list["contract_interact"]) + var/list/params = list("location" = "contract_details", "contract" = href_list["contract_interact"]) + usr.client.process_webint_link("interface/login/sso_server", list2params(params)) + if(href_list["contract_page"]) + nanoui_data["contracts_current_page"] = text2num(href_list["contract_page"]) + update_nano_data() + if(href_list["contract_view"]) + nanoui_data["contracts_view"] = text2num(href_list["contract_view"]) + nanoui_data["contracts_current_page"] = 1 + update_nano_data() interact(usr) return 1 @@ -292,6 +302,111 @@ datum/nano_item_lists nanoui_data["exploit_exists"] = 1 break + if(nanoui_menu == 2) + nanoui_data["contracts_found"] = 0 + + establish_db_connection(dbcon) + + if (dbcon.IsConnected()) + nanoui_data["contracts"] = list() + + if (!nanoui_data["contracts_current_page"]) + nanoui_data["contracts_current_page"] = 1 + + if (!nanoui_data["contracts_view"]) + nanoui_data["contracts_view"] = 1 + + var/query_details[0] + + switch (nanoui_data["contracts_view"]) + if (1) + query_details[":status"] = "open" + if (2) + query_details[":status"] = "closed" + else + nanoui_data["contracts_view"] = 1 + query_details[":status"] = "open" + + var/DBQuery/index_query = dbcon.NewQuery("SELECT count(*) as Total_Contracts FROM ss13_syndie_contracts WHERE deleted_at IS NULL AND status = :status") + index_query.Execute(query_details) + + var/pages = 0 + + if (index_query.NextRow()) + var/total_contracts = text2num(index_query.item[1]) + + pages = total_contracts / 10 + + if (total_contracts % 10) + pages++ + + pages = round(pages) + + var/list/contracts_pages = list() + + for (var/i = 1, i <= pages, i++) + contracts_pages.Add(i) + + for (var/a in contracts_pages) + + nanoui_data["contracts_pages"] = contracts_pages + + if (nanoui_data["contracts_current_page"] > pages) + return + + query_details[":offset"] = (nanoui_data["contracts_current_page"] - 1) * 10 + + var/DBQuery/list_query = dbcon.NewQuery("SELECT contract_id, contractee_name, title FROM ss13_syndie_contracts WHERE deleted_at IS NULL AND status = :status LIMIT 10 OFFSET :offset") + list_query.Execute(query_details) + + var/list/contracts = list() + while (list_query.NextRow()) + contracts.Add(list(list("id" = list_query.item[1], + "contractee" = list_query.item[2], + "title" = list_query.item[3]))) + + nanoui_data["contracts"] = contracts + + nanoui_data["contracts_found"] = 1 + + if(nanoui_menu == 21) + nanoui_data["contracts_found"] = 0 + + establish_db_connection(dbcon) + + if (dbcon.IsConnected()) + var/query_details[0] + query_details[":contract_id"] = text2num(id) + + var/DBQuery/select_query = dbcon.NewQuery("SELECT contract_id, contractee_name, status, title, description, reward_other FROM ss13_syndie_contracts WHERE contract_id = :contract_id") + select_query.Execute(query_details) + + if (select_query.NextRow()) + nanoui_data["contracts_found"] = 1 + + var/contract[0] + contract["id"] = select_query.item[1] + contract["contractee"] = select_query.item[2] + + switch (select_query.item[3]) + if ("open") + contract["status"] = "1" + else + contract["status"] = "0" + + contract["title"] = html_encode(select_query.item[4]) + contract["description"] = select_query.item[5] + + var/list/nano_blacklist = list("/" = " ", "_" = " ", "\n" = "
") + + for (var/a in nano_blacklist) + contract["description"] = replacetext(contract["description"], a, nano_blacklist[a]) + + contract["description"] = html_encode(contract["description"]) + contract["reward_other"] = select_query.item[6] + + nanoui_data["contract"] = contract + // I placed this here because of how relevant it is. // You place this in your uplinkable item to check if an uplink is active or not. // If it is, it will display the uplink menu and return 1, else it'll return false. diff --git a/nano/templates/uplink.tmpl b/nano/templates/uplink.tmpl index e981155622d..d51aebcbc3a 100644 --- a/nano/templates/uplink.tmpl +++ b/nano/templates/uplink.tmpl @@ -1,5 +1,5 @@ - @@ -13,12 +13,13 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm
{{:helper.link('Request Items', 'gear', {'menu' : 0}, null, 'fixedLeftWider')}} {{:helper.link('Exploitable Information', 'gear', {'menu' : 1}, null, 'fixedLeftWider')}} + {{:helper.link('Extranet Contract Database', 'gear', {'menu' : 2}, null, 'fixedLeftWider')}} {{:helper.link('Return', 'arrowreturn-1-w', {'return' : 1}, null, 'fixedLeft')}} {{:helper.link('Close', 'gear', {'lock' : "1"}, null, 'fixedLeft')}}

- + {{if data.menu == 0}}

Request items:

Each item costs a number of tele-crystals as indicated by the number following their name. @@ -39,7 +40,7 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm
{{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - {{:itemValue.Cost}}
- + {{if itemValue.Cost <= data.crystals}}
{{:itemValue.Description}} @@ -52,7 +53,7 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm
{{:helper.link('Buy Random (??)' , 'gear', {'buy_item' : 'random'}, data.crystals <= 0 ? 'disabled' : null, null)}}
- + {{else data.menu == 1}}

Information Record List:


@@ -65,7 +66,7 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm {{:helper.link(value.Name, 'gear', {'menu' : 11, 'id' : value.id}, null, null)}}
{{/for}} - + {{else data.menu == 11}}

Information Record:


@@ -96,4 +97,73 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm + +{{else data.menu == 2}} +

Available Contracts:

+
+ {{if data.contracts_found == 1}} +
+
+ + {{if data.contracts_view == 1}} + + {{else}} + + {{/if}} + {{for data.contracts}} + + {{/for}} +
IDContractorTitle
Available Contracts
Closed Contracts
{{:value.id}}{{:value.contractee}}{{:value.title}}{{:helper.link('View', null, {'menu' : 21, 'id' : value.id}, null, 'fixedLeft')}}
+
+
+ {{for data.contracts_pages}} + {{:helper.link(value, null, {'contract_page' : value}, null, null)}} + {{/for}} +

+ {{if data.contracts_view == 1}} + {{:helper.link('View Expired Contracts', 'gear', {'contract_view' : 2}, null, null)}} + {{else}} + {{:helper.link('View Open Contracts', 'gear', {'contract_view' : 1}, null, null)}} + {{/if}} +
+
+
+
+ {{else}} +
+
No Contracts Available.
+
+ {{/if}} + +{{else data.menu == 21}} +

Viewing Contract:

+
+
+
+
+ {{if data.contracts_found == 1}} + ID: #{{:data.contract.id}}
+ Contractee: {{:data.contract.contractee}}
+ Status: + {{if data.contract.status == 1}} + Open
+ {{else}} + Closed
+ {{/if}} + Title: {{:data.contract.title}}
+
+ Description: {{:data.contract.description}}
+ Reward: {{:data.contract.reward_other}}
+ {{else}} + Failed to retreive contract information! + {{/if}} +
+ +
+
+

+ {{if data.contracts_found == 1}} + {{:helper.link('View Reports And Updates', 'extlink', {'contract_interact' : data.contract.id}, null, null)}} + {{/if}} + {{/if}} From 899f8cdbec5234fe705f0375d6d05f0a1a17d6d1 Mon Sep 17 00:00:00 2001 From: skull132 Date: Wed, 23 Mar 2016 16:36:46 +0200 Subject: [PATCH 19/21] contract_uplink device & data parsing fix A contract_uplink device has been added, for rounds where no TCs are to be given to antags, but access to the database is neat. Namely: heist. The blacklist was removed, the issue proved to be carriage return characters breaking nanoUI. They are now removed. --- code/game/objects/items/devices/uplinks.dm | 32 ++++++++++++++++++---- maps/exodus-2.dmm | 3 +- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index 888dd0bb4de..2fbf1f99732 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -213,6 +213,9 @@ datum/nano_item_lists data["welcome"] = welcome data["crystals"] = uses data["menu"] = nanoui_menu + //Small hack for the contract_uplink device, to make sure the data is initialized properly. + if(nanoui_menu == 2) + update_nano_data() if(!nanoui_items) generate_items() data["nano_items"] = nanoui_items @@ -397,12 +400,9 @@ datum/nano_item_lists contract["title"] = html_encode(select_query.item[4]) contract["description"] = select_query.item[5] - var/list/nano_blacklist = list("/" = " ", "_" = " ", "\n" = "
") - - for (var/a in nano_blacklist) - contract["description"] = replacetext(contract["description"], a, nano_blacklist[a]) - contract["description"] = html_encode(contract["description"]) + contract["description"] = replacetext(contract["description"], "\n", "
") + contract["description"] = replacetext(contract["description"], ascii2text(13), "") contract["reward_other"] = select_query.item[6] nanoui_data["contract"] = contract @@ -447,3 +447,25 @@ datum/nano_item_lists ..() hidden_uplink = new(src) hidden_uplink.uses = 10 + +/* + * A simple device for accessing the SQL based contract database + */ + +/obj/item/device/contract_uplink + name = "contract uplink" + desc = "A small device used for access restricted sites in the remote corners of the Extranet." + icon = 'icons/obj/radio.dmi' + icon_state = "radio" + flags = CONDUCT + w_class = 2 + +/obj/item/device/contract_uplink/New() + ..() + hidden_uplink = new(src) + hidden_uplink.uses = 0 + hidden_uplink.nanoui_menu = 2 + +/obj/item/device/contract_uplink/attack_self(mob/user as mob) + if (hidden_uplink) + hidden_uplink.trigger(user) diff --git a/maps/exodus-2.dmm b/maps/exodus-2.dmm index 89715d75d1c..41c60b2de09 100644 --- a/maps/exodus-2.dmm +++ b/maps/exodus-2.dmm @@ -1977,6 +1977,7 @@ "Ma" = (/obj/machinery/vending/cigarette{name = "hacked cigarette machine"; prices = list(); products = list(/obj/item/weapon/storage/fancy/cigarettes = 10, /obj/item/weapon/storage/box/matches = 10, /obj/item/weapon/flame/lighter/zippo = 4, /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 2)},/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start) "Mb" = (/obj/structure/bed/chair,/obj/effect/landmark{name = "CCIAAgent"},/turf/unsimulated/floor{icon_state = "floor"},/area/centcom/control) "Mc" = (/obj/machinery/suit_cycler/syndicate{locked = 0},/turf/simulated/shuttle/plating,/area/skipjack_station/start) +"Md" = (/obj/item/device/contract_uplink,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) "Mj" = (/turf/unsimulated/beach/sand{tag = "icon-desert"; icon_state = "desert"},/turf/unsimulated/beach/sand{tag = "icon-coconuts"; icon_state = "coconuts"},/area/centcom/holding) "Mk" = (/obj/structure/table/standard,/obj/item/weapon/FixOVein{pixel_x = -6; pixel_y = 1},/turf/unsimulated/floor{tag = "icon-whitecorner"; name = "plating"; icon_state = "whitecorner"},/area/centcom/holding) "Ml" = (/obj/structure/table/standard,/obj/item/weapon/retractor{pixel_x = 0; pixel_y = 6},/obj/item/weapon/scalpel,/turf/unsimulated/floor{dir = 2; icon_state = "whitehall"; tag = "icon-whitehall (SOUTHEAST)"},/area/centcom/holding) @@ -2234,7 +2235,7 @@ dCmumumumumumumumuaMaMaMaMaMlwKjKjlxaMaMaMlwaMaMaMaMaMlxaMaMaMlwKjKjlxaMaMaMaMmt dCmumumumumuaMaMaMaMaMaMaMaMlylDlClyaMaMaMlylFlGlGlGlHlyaMaMaMlylIlJlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJULiLjKaLlLkEFEGEGEGEHEHEHEIEJLmELEMEHEHEHCNCNCNLnDVDVEwEPEQExERESCNaMaMaMaMaMaMaMETEVEVBVDYDZEaNtNsEAEVEVEWaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumuaMaMaMaMaMaMaMaMlylLlKlyaMaMlwlylylNlMlPlOlylxaMaMlylQlRlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJUJUJULlLWEZEZEZEZEZEHLXFbFcFdFeFfFgFbLXEHCNCNCNCNCNCNLYFiNqFkERESCNaMaMaMaMaMaMaMaMaMaMETATEUEUEUATEWaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumuaMaMaMaMaMaMaMaMlylTlSlyaMaMlylylUlWlVlWlXlylyaMaMlylYlZlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNMjJULlLWEZEZEZEZEZEZEHFbFmFnFdFeFfFnFoFbEHMkMmMlMoMnCNDVFhFkDVDVEwFuaMaMaMaMaMaMaMaMaMaMaMETEVEVEVEWaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -dCmumumumumuaMaMaMaMaMaMaMaMlymalylylylylymcmbmbmbmbmbmdlylylylylymelyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJULlLWEZEZEZEZEZEZEZEHFvFbFvFdFeFfFvFbFvEHFwDVDVDVDVMuDVDVDVDVDVFyFzaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM +dCmumumumumuaMaMaMaMaMaMaMaMlymalylylylylymcmbmbMdmbmbmdlylylylylymelyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJULlLWEZEZEZEZEZEZEZEHFvFbFvFdFeFfFvFbFvEHFwDVDVDVDVMuDVDVDVDVDVFyFzaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumuaMaMaMaMaMaMaMaMlymgmfmjmhmllymmmbmbmbmbmbmmlymomnmqmpoTlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNLlLWEZEZEZEZEZEZEZEZEHFAFbFbFdFeFfFbFbFBEHFCFDFEFFMGCNDVDVDVDVDVMHFIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumuaMaMaMaMaMaMaMaMaMaMaMlypvpspspspwlypNpEpPpOpNpEpPlyqBpspsqNpvlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMAHCNCNCNCNCNCNCNCNCNCNCNEHFJFKFKFdFeFfFLFLFMEHMTFOFPFQMUCNFSFTFUMWMVMXCNaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumuaMaMaMaMaMaMaMaMaMaMaMsUpvpspspspspOmbmbmbmbmbmbmbpOpspstEpspvsUaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMEHFeFeFeFeFeFeFeFeFeFeFeEHEHNbEHEHFeEHEHNbEHEHEHEHEHEHEHCNCNCNCNCNCNCNCNaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM From 610070184479e5b46731b22de531e99ff6baf0ac Mon Sep 17 00:00:00 2001 From: skull132 Date: Thu, 24 Mar 2016 02:08:05 +0200 Subject: [PATCH 20/21] Contract Uplink Fix The uplink is now spawned per raider, instead of being on the map. can't have it on the map as its init causes issues. --- code/game/antagonist/outsider/raider.dm | 3 ++- maps/exodus-2.dmm | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/antagonist/outsider/raider.dm b/code/game/antagonist/outsider/raider.dm index fcb0e1d2b73..42b481970a0 100644 --- a/code/game/antagonist/outsider/raider.dm +++ b/code/game/antagonist/outsider/raider.dm @@ -220,6 +220,8 @@ var/datum/antagonist/raider/raiders player.equip_to_slot_or_del(new new_suit(player),slot_wear_suit) equip_weapons(player) + player.equip_to_storage(new /obj/item/device/contract_uplink) + var/obj/item/weapon/card/id/id = create_id("Visitor", player, equip = 0) id.name = "[player.real_name]'s Passport" id.assignment = "Visitor" @@ -311,4 +313,3 @@ var/datum/antagonist/raider/raiders player.internals.icon_state = "internal1" return 1 - diff --git a/maps/exodus-2.dmm b/maps/exodus-2.dmm index 41c60b2de09..89715d75d1c 100644 --- a/maps/exodus-2.dmm +++ b/maps/exodus-2.dmm @@ -1977,7 +1977,6 @@ "Ma" = (/obj/machinery/vending/cigarette{name = "hacked cigarette machine"; prices = list(); products = list(/obj/item/weapon/storage/fancy/cigarettes = 10, /obj/item/weapon/storage/box/matches = 10, /obj/item/weapon/flame/lighter/zippo = 4, /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 2)},/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start) "Mb" = (/obj/structure/bed/chair,/obj/effect/landmark{name = "CCIAAgent"},/turf/unsimulated/floor{icon_state = "floor"},/area/centcom/control) "Mc" = (/obj/machinery/suit_cycler/syndicate{locked = 0},/turf/simulated/shuttle/plating,/area/skipjack_station/start) -"Md" = (/obj/item/device/contract_uplink,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) "Mj" = (/turf/unsimulated/beach/sand{tag = "icon-desert"; icon_state = "desert"},/turf/unsimulated/beach/sand{tag = "icon-coconuts"; icon_state = "coconuts"},/area/centcom/holding) "Mk" = (/obj/structure/table/standard,/obj/item/weapon/FixOVein{pixel_x = -6; pixel_y = 1},/turf/unsimulated/floor{tag = "icon-whitecorner"; name = "plating"; icon_state = "whitecorner"},/area/centcom/holding) "Ml" = (/obj/structure/table/standard,/obj/item/weapon/retractor{pixel_x = 0; pixel_y = 6},/obj/item/weapon/scalpel,/turf/unsimulated/floor{dir = 2; icon_state = "whitehall"; tag = "icon-whitehall (SOUTHEAST)"},/area/centcom/holding) @@ -2235,7 +2234,7 @@ dCmumumumumumumumuaMaMaMaMaMlwKjKjlxaMaMaMlwaMaMaMaMaMlxaMaMaMlwKjKjlxaMaMaMaMmt dCmumumumumuaMaMaMaMaMaMaMaMlylDlClyaMaMaMlylFlGlGlGlHlyaMaMaMlylIlJlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJULiLjKaLlLkEFEGEGEGEHEHEHEIEJLmELEMEHEHEHCNCNCNLnDVDVEwEPEQExERESCNaMaMaMaMaMaMaMETEVEVBVDYDZEaNtNsEAEVEVEWaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumuaMaMaMaMaMaMaMaMlylLlKlyaMaMlwlylylNlMlPlOlylxaMaMlylQlRlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJUJUJULlLWEZEZEZEZEZEHLXFbFcFdFeFfFgFbLXEHCNCNCNCNCNCNLYFiNqFkERESCNaMaMaMaMaMaMaMaMaMaMETATEUEUEUATEWaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumuaMaMaMaMaMaMaMaMlylTlSlyaMaMlylylUlWlVlWlXlylyaMaMlylYlZlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNMjJULlLWEZEZEZEZEZEZEHFbFmFnFdFeFfFnFoFbEHMkMmMlMoMnCNDVFhFkDVDVEwFuaMaMaMaMaMaMaMaMaMaMaMETEVEVEVEWaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -dCmumumumumuaMaMaMaMaMaMaMaMlymalylylylylymcmbmbMdmbmbmdlylylylylymelyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJULlLWEZEZEZEZEZEZEZEHFvFbFvFdFeFfFvFbFvEHFwDVDVDVDVMuDVDVDVDVDVFyFzaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM +dCmumumumumuaMaMaMaMaMaMaMaMlymalylylylylymcmbmbmbmbmbmdlylylylylymelyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNJULlLWEZEZEZEZEZEZEZEHFvFbFvFdFeFfFvFbFvEHFwDVDVDVDVMuDVDVDVDVDVFyFzaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumuaMaMaMaMaMaMaMaMlymgmfmjmhmllymmmbmbmbmbmbmmlymomnmqmpoTlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMCNLlLWEZEZEZEZEZEZEZEZEHFAFbFbFdFeFfFbFbFBEHFCFDFEFFMGCNDVDVDVDVDVMHFIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumuaMaMaMaMaMaMaMaMaMaMaMlypvpspspspwlypNpEpPpOpNpEpPlyqBpspsqNpvlyaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMAHCNCNCNCNCNCNCNCNCNCNCNEHFJFKFKFdFeFfFLFLFMEHMTFOFPFQMUCNFSFTFUMWMVMXCNaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumuaMaMaMaMaMaMaMaMaMaMaMsUpvpspspspspOmbmbmbmbmbmbmbpOpspstEpspvsUaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMEHFeFeFeFeFeFeFeFeFeFeFeEHEHNbEHEHFeEHEHNbEHEHEHEHEHEHEHCNCNCNCNCNCNCNCNaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM From 2855adee1e539c78bc0f6dc0cd3c85423dcbf9bf Mon Sep 17 00:00:00 2001 From: skull132 Date: Thu, 24 Mar 2016 20:44:53 +0200 Subject: [PATCH 21/21] The changelogging Log harder. --- html/changelogs/skull132-webinterface.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 html/changelogs/skull132-webinterface.yml diff --git a/html/changelogs/skull132-webinterface.yml b/html/changelogs/skull132-webinterface.yml new file mode 100644 index 00000000000..a7b6f19766f --- /dev/null +++ b/html/changelogs/skull132-webinterface.yml @@ -0,0 +1,8 @@ +author: Skull132 + +delete-after: True + +changes: + - rscadd: "Integrated the web interface with the game. Players can now create linking requests from the web interface, and accept them ingame. This will be used for more feature integration between the two later." + - rscadd: "Integrated the syndicate contract database with the game. Players can interact with contracts from the web interface (create new ones, post comments, report completion, etcetera), and review the contracts from syndicate uplinks. This means that antags with access to an uplink can now roleplay with contracts, fulfilling missions and so forth." + - rscadd: "Heisters now spawn with contract uplinks, which are effectively syndicate uplinks without the telecrystals, for checking up on the contracts database."