Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: SSCentral #1839

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions config/example/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -930,8 +930,6 @@ ffmpeg_cpuaffinity = ""
[ss220_misc_configuration]
# This section contains everything that should be in general_configuration

# Force discord verification
force_discord_verification = false
# Respawn delay in minutes before one may respawn as a crew member
respawn_delay = 20
# Players needed to enable advanced communication (common channel limitations).
Expand Down Expand Up @@ -1227,3 +1225,9 @@ job_species_blacklist = [
]

################################################################

[central_configuration]
api_url = "https://my_api_url.com/v1"
api_token = "12345678"
server_type = "default"
force_discord_verification = false
4 changes: 0 additions & 4 deletions modular_ss220/_defines220/code/donor.dm
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
// Special tiers for ss220 staff
#define BIG_WORKER_TIER 220
#define LITTLE_WORKER_TIER 110

// What TTS level does it give access to?
#define BIG_WORKER_TTS_LEVEL 3
#define LITTLE_WORKER_TTS_LEVEL 1
Expand Down
76 changes: 2 additions & 74 deletions modular_ss220/discord_link/code/discord.dm
Original file line number Diff line number Diff line change
@@ -1,48 +1,3 @@
/datum/preferences
var/discord_id

/datum/configuration_section/ss220_misc_configuration
/// Force discord verification
var/force_discord_verification = FALSE

/datum/configuration_section/ss220_misc_configuration/load_data(list/data)
. = ..()
CONFIG_LOAD_BOOL(force_discord_verification, data["force_discord_verification"])

/client/verb/link_discord_account()
set name = "Привязка Discord"
set category = "Special Verbs"
set desc = "Привязать аккаунт Discord для удобного просмотра игровой статистики на нашем Discord-сервере."

if(!GLOB.configuration.url.discord_url)
return

if(IsGuestKey(key))
to_chat(usr, "Гостевой аккаунт не может быть связан.")
return

if(prefs.get_discord_id() && prefs.discord_id)
to_chat(usr, span_darkmblue("Аккаунт Discord уже привязан!"))
return

if(!SSdbcore.IsConnected())
return

var/token = "WyccStation_" + md5("[world.time+rand(1000,1000000)]")
var/datum/db_query/query_replace_token = SSdbcore.NewQuery("REPLACE INTO discord_links (ckey, timestamp, one_time_token) VALUES (:ckey, NOW(), :token)", list(
"token" = token,
"ckey" = ckey
))

if(!query_replace_token.warn_execute())
to_chat(usr, span_warning("Ошибка записи токена в БД! Обратитесь к администрации."))
log_debug("link_discord_account: failed db update discord_id for ckey [ckey]")
qdel(query_replace_token)
return

qdel(query_replace_token)
to_chat(usr, chat_box_notice(span_darkmblue("Для завершения, вставьте это: <br>") + span_good("<b>/привязать token:[token]</b>") + span_darkmblue("<br>В канал <b><a href='https://discord.com/channels/1097181193939730453/1162068725168623696'>#paradise-бот</a></b> в Discord-сообществе!<br>") + span_notice("<br>Чтобы канал открылся, вам необходимо перейти в <a href='https://discord.com/channels/1097181193939730453/1178197552013770752/1178209983452692590'>#выбор-роли</a> и получить роль '<b>Space Station 13 Paradise</b>'.")))

/mob/new_player/Topic(href, href_list)
if(src != usr)
return
Expand All @@ -51,36 +6,9 @@
return

if(href_list["observe"] || href_list["ready"] || href_list["late_join"])
if(GLOB.configuration.database.enabled && GLOB.configuration.ss220_misc.force_discord_verification)
if(!client.prefs.discord_id || !(client.prefs.get_discord_id() && client.prefs.discord_id))
if(GLOB.configuration.central.api_url && GLOB.configuration.central.force_discord_verification)
if(!SScentral.is_player_discord_linked(client))
to_chat(usr, chat_box_red(span_danger("Вам необходимо привязать дискорд-профиль к аккаунту!<br>") + span_warning("<br>Перейдите во вкладку '<b>Special Verbs</b>', она справа сверху, и нажмите '<b>Привязка Discord</b>' для получения инструкций.")))
return FALSE

. = ..()

/datum/preferences/proc/get_discord_id()
. = TRUE
if(discord_id)
return

var/datum/db_query/discord_query = SSdbcore.NewQuery("SELECT discord_id, valid FROM discord_links WHERE ckey=:ckey", list(
"ckey" = parent.ckey
))

if(!discord_query.warn_execute())
qdel(discord_query)
return FALSE

while(discord_query.NextRow())
var/valid = discord_query.item[2]
if(valid)
discord_id = discord_query.item[1]

qdel(discord_query)

/datum/preferences/load_preferences(datum/db_query/query)
. = ..()
if(!.)
return

return get_discord_id()
68 changes: 24 additions & 44 deletions modular_ss220/donor/code/client_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
var/static/list/big_worker = list("Администратор", "Старший Разработчик", "Разработчик", "Бригадир Мапперов", "Маппер", "Ведущий Редактор Вики", "Администратор СС14")

if(C.holder)
C.donator_level = (C.holder.rank in ultimate_worker) ? DONATOR_LEVEL_MAX : (C.holder.rank in big_worker) ? BIG_WORKER_TIER : LITTLE_WORKER_TIER
C.donator_level = (C.holder.rank in ultimate_worker) ? DONATOR_LEVEL_MAX : (C.holder.rank in big_worker) ? BIG_WORKER_LEVEL : LITTLE_WORKER_LEVEL
return

var/is_wl = GLOB.configuration.overflow.reroute_cap == 0.5 ? TRUE : FALSE
Expand All @@ -21,53 +21,33 @@
return

while(rank_ckey_read.NextRow())
C.donator_level = (rank_ckey_read.item[1] in ultimate_worker) ? DONATOR_LEVEL_MAX : (rank_ckey_read.item[1] in big_worker) ? BIG_WORKER_TIER : LITTLE_WORKER_TIER
C.donator_level = (rank_ckey_read.item[1] in ultimate_worker) ? DONATOR_LEVEL_MAX : (rank_ckey_read.item[1] in big_worker) ? BIG_WORKER_LEVEL : LITTLE_WORKER_LEVEL

qdel(rank_ckey_read)

/datum/client_login_processor/donator_check/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT 1", list()) // La stampella
return query

/datum/client_login_processor/donator_check/process_result(datum/db_query/Q, client/C)
if(IsGuestKey(C.ckey))
return

CheckAutoDonatorLevel(C)

while(Q.NextRow())
var/total = Q.item[1]
var/donator_level = 0
switch(total)
if(220 to 439)
donator_level = 1
if(440 to 999)
donator_level = 2
if(1000 to 2219)
donator_level = 3
if(2220 to 9999)
donator_level = 4
if(10000 to INFINITY)
donator_level = DONATOR_LEVEL_MAX

switch(C.donator_level)
if(LITTLE_WORKER_TIER)
C.donator_level = LITTLE_WORKER_TTS_LEVEL > donator_level ? C.donator_level : donator_level
if(BIG_WORKER_TIER)
C.donator_level = BIG_WORKER_TTS_LEVEL > donator_level ? C.donator_level : donator_level
else
C.donator_level = max(C.donator_level, donator_level)

C.donor_loadout_points()
C.donor_character_slots()
var/donator_level = SScentral.get_player_donate_tier_blocking(C)

/datum/client_login_processor/donator_check/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery({"
SELECT CAST(SUM(amount) as UNSIGNED INTEGER) FROM budget
WHERE ckey=:ckey
AND is_valid=true
AND date_start <= NOW()
AND (NOW() < date_end OR date_end IS NULL)
GROUP BY ckey
"}, list("ckey" = C.ckey))
switch(C.donator_level)
if(LITTLE_WORKER_LEVEL)
C.donator_level = LITTLE_WORKER_TTS_LEVEL > donator_level ? C.donator_level : donator_level
if(BIG_WORKER_LEVEL)
C.donator_level = BIG_WORKER_TTS_LEVEL > donator_level ? C.donator_level : donator_level
else
C.donator_level = max(C.donator_level, donator_level)

return query
C.donor_loadout_points()
C.donor_character_slots()

/client/donor_loadout_points()
if(!prefs)
Expand All @@ -86,9 +66,9 @@
prefs.max_gear_slots += 12
if(5)
prefs.max_gear_slots += 16
if(LITTLE_WORKER_TIER)
if(LITTLE_WORKER_LEVEL)
prefs.max_gear_slots += 1
if(BIG_WORKER_TIER)
if(BIG_WORKER_LEVEL)
prefs.max_gear_slots += 5

/client/proc/donor_character_slots()
Expand All @@ -98,21 +78,21 @@
prefs.max_save_slots = MAX_SAVE_SLOTS_SS220 + 5 * donator_level

switch(donator_level)
if(LITTLE_WORKER_TIER)
if(LITTLE_WORKER_LEVEL)
prefs.max_save_slots = 7
if(BIG_WORKER_TIER)
if(BIG_WORKER_LEVEL)
prefs.max_save_slots = 10

prefs.character_saves.len = prefs.max_save_slots

#undef MAX_SAVE_SLOTS_SS220

/client/proc/is_donor_allowed(required_donator_level)
switch(donator_level)
if(LITTLE_WORKER_TIER)
if(LITTLE_WORKER_LEVEL)
if(required_donator_level > LITTLE_WORKER_LEVEL)
return FALSE
if(BIG_WORKER_TIER)
if(BIG_WORKER_LEVEL)
if(required_donator_level > BIG_WORKER_LEVEL)
return FALSE
return required_donator_level <= donator_level

#undef MAX_SAVE_SLOTS_SS220
4 changes: 4 additions & 0 deletions modular_ss220/metaserver/_metaserver.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/datum/modpack/metaserver
name = "Metaserver"
desc = "Общая инфраструктура для серверов"
author = "furior"
6 changes: 6 additions & 0 deletions modular_ss220/metaserver/_metaserver.dme
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "_metaserver.dm"

#include "code/discord_link.dm"
#include "code/donate.dm"
#include "code/http.dm"
#include "code/ss_central.dm"
42 changes: 42 additions & 0 deletions modular_ss220/metaserver/code/discord_link.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/datum/preferences
var/discord_id

/client/New()
. = ..()
SScentral.get_player_discord_async(src)

/client/verb/verify_in_discord_central()
set category = "Special Verbs"
set name = "Привязать Discord"
set desc = "Привязка аккаунта Discord к BYOND"

if(!SScentral.initialized)
to_chat(src, span_warning("Привязка Discord сейчас недоступна."))
return

if(SScentral.is_player_discord_linked(src))
to_chat(src, span_warning("Вы уже привязали свою учетную запись Discord."))
return

to_chat(src, span_notice("Пытаемся получить токен для входа в Discord..."))
SScentral.verify_in_discord(src)

/datum/controller/subsystem/central/proc/verify_in_discord(client/player)
var/endpoint = "[GLOB.configuration.central.api_url]/oauth/token?ckey=[player.ckey]"
var/list/headers = list(
"Authorization" = "Bearer [GLOB.configuration.central.api_token]"
)
SShttp.create_async_request(RUSTG_HTTP_METHOD_POST, endpoint, "", headers, CALLBACK(SScentral, PROC_REF(verify_in_discord_callback), player))

/datum/controller/subsystem/central/proc/verify_in_discord_callback(client/player, datum/http_response/response)
if(response.errored || response.status_code != 201)
stack_trace("Failed to get discord verification token: HTTP status code [response.status_code] - [response.error]")
return

var/list/data = json_decode(response.body)
var/login_endpoint = "[GLOB.configuration.central.api_url]/oauth/login?token=[data]"

to_chat(player, chat_box_regular("Авторизуйтесь в открывшемся окне и ожидайте 30 секунд.<br/>Если окно не открывается, можете открыть ссылку в браузере самостоятельно:<br/><a href='[login_endpoint]'>Привязать дискорд.</a>."))
player << link(login_endpoint)
SScentral.get_player_discord_async(player)
addtimer(CALLBACK(SScentral, TYPE_PROC_REF(/datum/controller/subsystem/central, get_player_discord_async), player), 30 SECONDS)
3 changes: 3 additions & 0 deletions modular_ss220/metaserver/code/donate.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/client/New()
. = ..()
SScentral.update_player_donate_tier_async(src)
66 changes: 66 additions & 0 deletions modular_ss220/metaserver/code/http.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Blocking request creator
*
* Generates a blocking request, executes it, logs the info then cleanly returns the response
* Uses UNTIL, so is VERY dangerous to use.
*/
/datum/controller/subsystem/http/proc/make_sync_request(method, url, body = "", list/headers)
var/datum/http_request/req = new()
req.prepare(method, url, body, headers)
req.begin_async()
active_async_requests += req
total_requests++
log_request(req)

UNTIL(req.is_complete())
active_async_requests -= req
var/datum/http_response/res = req.into_response()
log_response(res, req.id)
return res

/datum/controller/subsystem/http/proc/log_request(datum/http_request/req, type = "ASYNC")
if(!logging_enabled)
return

var/list/log_data = list()
log_data += "REQUEST (ID: [req.id]) ([type])"
log_data += "\t[uppertext(req.method)] [req.url]"
log_data += "\tRequest body: [req.body]"
log_data += "\tRequest headers: [req.headers]"
rustg_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]"))

/datum/controller/subsystem/http/proc/log_response(datum/http_response/res, id)
if(!logging_enabled)
return

var/list/log_data = list()
log_data += "RESPONSE (ID: [id])"
if(res.errored)
log_data += "\t ----- RESPONSE ERROR -----"
log_data += "\t [res.error]"
else
log_data += "\tResponse status code: [res.status_code]"
log_data += "\tResponse body: [res.body]"
log_data += "\tResponse headers: [json_encode(res.headers)]"
rustg_log_write(GLOB.http_log, log_data.Join("\n[GLOB.log_end]"))


/datum/http_request/into_response()
. = ..()
var/datum/http_response/R = .
if(!R.errored)
return R
// Handle the 4xx and 5xx codes. BS version is much better because saves the body
var/static/regex/status_code_detector = new(@": status code (\d{3})$")
var/actually_errored = status_code_detector.Find(R.error) == 0

if(actually_errored)
return R

R.status_code = text2num(status_code_detector.group[1])
R.errored = FALSE
R.error = null

return R


Loading