From 9d9d438b5d933e2e5616aeb0193b4d8c0e9ebd2f Mon Sep 17 00:00:00 2001 From: Bugisoft <58910128+BugisoftRSG@users.noreply.github.com> Date: Thu, 22 Dec 2022 11:49:34 +0100 Subject: [PATCH] feat(Api): Add more api endpoints to the scui api (#714) * feat(Api): Add send message to player database * feat(cpr): Disabling test build * feat(Api): Fix max message length * feat(Api): Download job for creator menu --- scripts/cpr.cmake | 6 ++- src/services/api/api_service.cpp | 49 +++++++++++++++++-- src/services/api/api_service.hpp | 10 +++- .../creator_storage_service.cpp | 4 +- .../creator_storage_service.hpp | 2 +- src/views/network/view_player_database.cpp | 16 ++++++ src/views/world/view_creator.cpp | 33 +++++++++++++ 7 files changed, 110 insertions(+), 10 deletions(-) diff --git a/scripts/cpr.cmake b/scripts/cpr.cmake index bdc43245..ab61d5b9 100644 --- a/scripts/cpr.cmake +++ b/scripts/cpr.cmake @@ -1,6 +1,6 @@ include(FetchContent) -set(BUILD_CPR_TESTS OFF CACHE INTERNAL "") +set(BUILD_TESTING_BEFORE ${BUILD_TESTING}) FetchContent_Declare( cpr GIT_REPOSITORY https://github.com/libcpr/cpr.git @@ -8,4 +8,6 @@ FetchContent_Declare( GIT_PROGRESS TRUE ) message("cpr") -FetchContent_MakeAvailable(cpr) \ No newline at end of file +FetchContent_MakeAvailable(cpr) + +set(BUILD_TESTING ${BUILD_TESTING_BEFORE} CACHE INTERNAL "" FORCE) \ No newline at end of file diff --git a/src/services/api/api_service.cpp b/src/services/api/api_service.cpp index 8afaef7c..d1077890 100644 --- a/src/services/api/api_service.cpp +++ b/src/services/api/api_service.cpp @@ -1,5 +1,6 @@ #include "api_service.hpp" #include "pointers.hpp" +#include "services/creator_storage/creator_storage_service.hpp" namespace big { @@ -18,7 +19,7 @@ namespace big { cpr::Response response = cpr::Post( cpr::Url{ "https://scui.rockstargames.com/api/friend/accountsearch" }, - cpr::Header{ {"Authorization", AUTHORIZATION_TICKET) }, { "X-Requested-With", "XMLHttpRequest"}}, + cpr::Header{ {"Authorization", AUTHORIZATION_TICKET }, { "X-Requested-With", "XMLHttpRequest"} }, cpr::Body{ { std::format("searchNickname={}", username) } }); if (response.status_code == 200) @@ -38,10 +39,10 @@ namespace big { cpr::Response response = cpr::Post( cpr::Url{ "https://scui.rockstargames.com/api/friend/getprofile" }, - cpr::Header{ {"Authorization", AUTHORIZATION_TICKET) }, { "X-Requested-With", "XMLHttpRequest"}, {"Content-Type", "application/json"} }, + cpr::Header{ {"Authorization", AUTHORIZATION_TICKET }, { "X-Requested-With", "XMLHttpRequest"}, {"Content-Type", "application/json"} }, cpr::Body{ { std::format(R"({{"RockstarId":"{}"}})", rid) } }); - if (response.status_code == 200) + if (response.status_code == 200) { nlohmann::json obj = nlohmann::json::parse(response.text); result = obj["Accounts"].at(0)["RockstarAccount"]["Name"]; @@ -51,13 +52,53 @@ namespace big return false; } + // Ratelimit: 10 per Minute, if exceeded than 5 min cooldown bool api_service::send_socialclub_message(uint64_t rid, std::string_view message) { cpr::Response response = cpr::Post( cpr::Url{ "https://scui.rockstargames.com/api/messaging/sendmessage" }, - cpr::Header{ {"Authorization", AUTHORIZATION_TICKET) }, { "X-Requested-With", "XMLHttpRequest"}, {"Content-Type", "application/json"} }, + cpr::Header{ {"Authorization", AUTHORIZATION_TICKET }, { "X-Requested-With", "XMLHttpRequest"}, {"Content-Type", "application/json"} }, cpr::Body{ { std::format(R"({{"env":"prod","title":"gta5","version":11,"recipientRockstarId":"{}","messageText":"{}"}})", rid, message) } }); return response.status_code == 200; } + + bool api_service::get_job_details(std::string_view job_link, nlohmann::json& result) + { + if (job_link.starts_with("https://")) + job_link = job_link.substr(46); // https://socialclub.rockstargames.com/job/gtav/ + + cpr::Response response = cpr::Get( + cpr::Url{ "https://scapi.rockstargames.com/ugc/mission/details" }, + cpr::Header{ {"X-AMC", "true" }, { "X-Requested-With", "XMLHttpRequest"} }, + cpr::Parameters{ {"title", "gtav"}, {"contentId", job_link.data()} }); + + result = nlohmann::json::parse(response.text); + + return response.status_code == 200; + } + + bool api_service::download_job_metadata(std::string_view content_part) + { + for (int major = 0; major < 3; major++) + { + for (int minor = 0; minor < 3; minor++) + { + for (const auto& lang : languages) + { + cpr::Response response = cpr::Get(cpr::Url{ std::format("https://prod.cloud.rockstargames.com/ugc/gta5mission/{}/{}_{}_{}.json", content_part, major, minor, lang) }); + + if (response.status_code == 200) + { + std::ofstream of = creator_storage_service::create_file(std::string(content_part).substr(5) + ".json"); + cpr::Response r = cpr::Download(of, response.url); + + return true; + } + } + } + } + + return false; + } } \ No newline at end of file diff --git a/src/services/api/api_service.hpp b/src/services/api/api_service.hpp index d6a28d36..9e2bc3c6 100644 --- a/src/services/api/api_service.hpp +++ b/src/services/api/api_service.hpp @@ -1,7 +1,7 @@ #pragma once #include "pointers.hpp" #include -#define AUTHORIZATION_TICKET std::format("SCAUTH val=\"{}\"", get_ticket() +#define AUTHORIZATION_TICKET std::format("SCAUTH val=\"{}\"", get_ticket()) namespace big { @@ -19,7 +19,15 @@ namespace big // Returns true if the message has been successfully sended to the target bool send_socialclub_message(uint64_t rid, std::string_view message); + + // Returns true if the job data query was successfully + bool get_job_details(std::string_view job_link, nlohmann::json& result); + + // Returns true if the job metadata was successfully downloaded + bool download_job_metadata(std::string_view content_part); private: + const std::list languages = { "en", "fr", "de", "it", "es", "pt", "pl", "ru", "es-mx" }; + inline std::string get_ticket() { return g_pointers->m_sc_info->m_ticket; diff --git a/src/services/creator_storage/creator_storage_service.cpp b/src/services/creator_storage/creator_storage_service.cpp index bc48e05c..c8a85670 100644 --- a/src/services/creator_storage/creator_storage_service.cpp +++ b/src/services/creator_storage/creator_storage_service.cpp @@ -21,9 +21,9 @@ namespace big return file_paths; } - void creator_storage_service::create_file(std::string file) + std::ofstream creator_storage_service::create_file(std::string file) { - std::ofstream(check_jobs_folder().get_file(file).get_path()); + return std::ofstream(check_jobs_folder().get_file(file).get_path()); } void creator_storage_service::save_file(std::string_view filename) diff --git a/src/services/creator_storage/creator_storage_service.hpp b/src/services/creator_storage/creator_storage_service.hpp index b9abf44a..bae6c6a5 100644 --- a/src/services/creator_storage/creator_storage_service.hpp +++ b/src/services/creator_storage/creator_storage_service.hpp @@ -8,7 +8,7 @@ namespace big public: static std::vector list_files(); - static void create_file(std::string name); + static std::ofstream create_file(std::string name); static void load_file(std::string_view file_name); static void save_file(std::string_view file_name); diff --git a/src/views/network/view_player_database.cpp b/src/views/network/view_player_database.cpp index 9d440c4b..5601cd63 100644 --- a/src/views/network/view_player_database.cpp +++ b/src/views/network/view_player_database.cpp @@ -3,6 +3,7 @@ #include "pointers.hpp" #include "services/players/player_service.hpp" #include "services/player_database/player_database_service.hpp" +#include "services/api/api_service.hpp" #include "core/data/block_join_reasons.hpp" #include "core/data/infractions.hpp" #include "util/session.hpp" @@ -108,6 +109,21 @@ namespace big session::join_by_rockstar_id(current_player.rockstar_id); }); + static char message[256]; + ImGui::InputText("Input Message", message, sizeof(message)); + if (components::button("Send Message")) + { + g_thread_pool->push([selected] + { + if (g_api_service->send_socialclub_message(selected->rockstar_id, message)) + { + g_notification_service->push("SCAPI", "Message successfully sent"); + return; + } + g_notification_service->push_error("SCAPI", "Message not sent. Are you connected to the internet?"); + }); + }; + if (ImGui::Button("Save")) { if (current_player.rockstar_id != selected->rockstar_id) diff --git a/src/views/world/view_creator.cpp b/src/views/world/view_creator.cpp index 9318123d..7f497b5e 100644 --- a/src/views/world/view_creator.cpp +++ b/src/views/world/view_creator.cpp @@ -2,7 +2,9 @@ #include "script.hpp" #include "views/view.hpp" #include "services/creator_storage/creator_storage_service.hpp" +#include "services/api/api_service.hpp" #include "util/scripts.hpp" +#include "thread_pool.hpp" static bool cached_creator_files = false; static std::vector creator_files; @@ -72,6 +74,37 @@ namespace big cached_creator_files = false; }); + ImGui::Separator(); + + static char job_link[69]{}; + ImGui::InputText("SocialClub Job Link", job_link, sizeof(job_link)); + + components::button("Import", [] + { + g_thread_pool->push([] + { + nlohmann::json job_details; + if (g_api_service->get_job_details(job_link, job_details)) + { + std::string img_src = job_details["content"]["imgSrc"]; + std::string content_part = img_src.substr(53, 27); + + nlohmann::json job_metadata; + + if (g_api_service->download_job_metadata(content_part)) + { + cached_creator_files = false; + g_notification_service->push("Job Import", "Job Import successfully done"); + } + else { + g_notification_service->push_error("Job Import", "Couldn't download the job metadata"); + } + } else { + g_notification_service->push_error("Job Import", "Couldn't get the job details"); + } + }); + }); + ImGui::EndGroup(); components::sub_title("Launch Creator");