feat(tgbot-back): Add functions for processing user authentication

This commit is contained in:
Kirill 2025-12-19 17:48:16 +03:00
parent d6194ec8be
commit f045eb22b2
6 changed files with 122 additions and 21 deletions

View file

@ -11,6 +11,9 @@ list(APPEND SOURCES ${SRC_BACK})
file(GLOB_RECURSE SRC_API "generated-client/src/*.cpp") file(GLOB_RECURSE SRC_API "generated-client/src/*.cpp")
list(APPEND SOURCES ${SRC_API}) list(APPEND SOURCES ${SRC_API})
file(GLOB_RECURSE SRC_AUTH "generated-client-auth/src/*.cpp")
list(APPEND SOURCES ${SRC_AUTH})
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
@ -26,6 +29,7 @@ include_directories(/usr/local/include ${OPENSSL_INCLUDE_DIR} ${Boost_INCLUDE_DI
include_directories(front/include/) include_directories(front/include/)
include_directories(back/include) include_directories(back/include)
include_directories(generated-client/include) include_directories(generated-client/include)
include_directories(generated-client-auth/include)
if (CURL_FOUND) if (CURL_FOUND)
include_directories(${CURL_INCLUDE_DIRS}) include_directories(${CURL_INCLUDE_DIRS})
add_definitions(-DHAVE_CURL) add_definitions(-DHAVE_CURL)

View file

@ -0,0 +1,35 @@
// AuthImpersonationClient.hpp
#pragma once
#include <memory>
#include <string>
#include <stdexcept>
#include <cstdlib>
#include <map>
#include <cpprest/asyncrt_utils.h>
#include "AuthClient/ApiClient.h"
#include "AuthClient/ApiConfiguration.h"
#include "AuthClient/api/AuthApi.h"
#include "AuthClient/model/GetImpersonationToken_request.h"
#include "AuthClient/model/GetImpersonationToken_200_response.h"
namespace nyanimed {
class AuthImpersonationClient {
public:
AuthImpersonationClient();
// Потокобезопасный вызов — не модифицирует состояние
pplx::task<std::shared_ptr<nyanimed::meow::auth::model::GetImpersonationToken_200_response>>
getImpersonationToken(int64_t userId) const;
private:
std::string m_baseUrl;
std::string m_authToken;
std::shared_ptr<nyanimed::meow::auth::api::ApiClient> m_apiClient;
std::shared_ptr<nyanimed::meow::auth::api::AuthApi> m_authApi;
};
} // namespace nyanimed

View file

@ -15,6 +15,8 @@
#include <cpprest/asyncrt_utils.h> #include <cpprest/asyncrt_utils.h>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include "AuthImpersonation.hpp"
using namespace org::openapitools::client::api; using namespace org::openapitools::client::api;
class BotToServer { class BotToServer {
@ -28,4 +30,6 @@ private:
std::shared_ptr<org::openapitools::client::api::ApiConfiguration> apiconfiguration; std::shared_ptr<org::openapitools::client::api::ApiConfiguration> apiconfiguration;
std::shared_ptr<org::openapitools::client::api::ApiClient> apiclient; std::shared_ptr<org::openapitools::client::api::ApiClient> apiclient;
std::shared_ptr<org::openapitools::client::api::DefaultApi> api; std::shared_ptr<org::openapitools::client::api::DefaultApi> api;
nyanimed::AuthImpersonationClient authClient;
}; };

View file

@ -0,0 +1,34 @@
#include "AuthImpersonation.hpp"
nyanimed::AuthImpersonationClient::AuthImpersonationClient() {
const char* baseUrlEnv = std::getenv("NYANIMEDBAUTHURL");
const char* tokenEnv = std::getenv("NYANIMEDBAUTHTOKEN");
if (!baseUrlEnv || std::string(baseUrlEnv).empty()) {
throw std::runtime_error("Missing required environment variable: NYANIMEDBAUTHURL");
}
if (!tokenEnv || std::string(tokenEnv).empty()) {
throw std::runtime_error("Missing required environment variable: NYANIMEDBAUTHTOKEN");
}
m_baseUrl = baseUrlEnv;
m_authToken = tokenEnv;
auto config = std::make_shared<nyanimed::meow::auth::api::ApiConfiguration>();
config->setBaseUrl(utility::conversions::to_string_t(m_baseUrl));
m_apiClient = std::make_shared<nyanimed::meow::auth::api::ApiClient>(config);
m_authApi = std::make_shared<nyanimed::meow::auth::api::AuthApi>(m_apiClient);
}
pplx::task<std::shared_ptr<nyanimed::meow::auth::model::GetImpersonationToken_200_response>>
nyanimed::AuthImpersonationClient::getImpersonationToken(int64_t userId) const {
auto request = std::make_shared<nyanimed::meow::auth::model::GetImpersonationToken_request>();
request->setUserId(userId);
//request->setExternalId(externalId);
std::map<utility::string_t, utility::string_t> headers;
headers[U("Authorization")] = U("Bearer ") + utility::conversions::to_string_t(m_authToken);
return m_authApi->getImpersonationToken(request, headers);
}

View file

@ -45,28 +45,52 @@ static BotStructs::Title mapUserTitleToBotTitle(
} }
pplx::task<std::vector<BotStructs::Title>> BotToServer::fetchUserTitlesAsync(const std::string& userId) { pplx::task<std::vector<BotStructs::Title>> BotToServer::fetchUserTitlesAsync(const std::string& userId) {
utility::string_t userIdW = utility::conversions::to_string_t(userId); // Шаг 1: Получаем impersonation-токен
int32_t limit = static_cast<int32_t>(BotConstants::DISP_TITLES_NUM); auto impersonationTask = authClient.getImpersonationToken(std::stoi(userId));
auto responseTask = api->getUserTitles( // Шаг 2: После получения токена — делаем запрос getUserTitles с этим токеном
userIdW, return impersonationTask.then([=](pplx::task<std::shared_ptr<nyanimed::meow::auth::model::GetImpersonationToken_200_response>> tokenTask) {
boost::none, // cursor
boost::none, // sort
boost::none, // sortForward
boost::none, // word
boost::none, // status
boost::none, // watchStatus
boost::none, // rating
boost::none, // myRate
boost::none, // releaseYear
boost::none, // releaseSeason
limit,
boost::none // fields
);
return responseTask.then([=](pplx::task<std::shared_ptr<org::openapitools::client::model::GetUserTitles_200_response>> task) {
try { try {
auto response = task.get(); auto tokenResponse = tokenTask.get();
if (!tokenResponse) {
throw std::runtime_error("Null response from getImpersonationToken");
}
utility::string_t accessToken = utility::conversions::to_string_t(tokenResponse->getAccessToken());
// Формируем заголовки с токеном
std::map<utility::string_t, utility::string_t> customHeaders;
customHeaders[U("Cookie")] = U("access_token=") + accessToken;
// Подготавливаем параметры запроса
utility::string_t userIdW = utility::conversions::to_string_t(userId);
int32_t limit = static_cast<int32_t>(BotConstants::DISP_TITLES_NUM);
// Шаг 3: Выполняем getUserTitles с кастомными заголовками
return api->getUserTitles(
userIdW,
boost::none, // cursor
boost::none, // sort
boost::none, // sortForward
boost::none, // word
boost::none, // status
boost::none, // watchStatus
boost::none, // rating
boost::none, // myRate
boost::none, // releaseYear
boost::none, // releaseSeason
limit,
boost::none, // fields
customHeaders
);
} catch (const std::exception& e) {
std::cerr << "Error obtaining impersonation token: " << e.what() << std::endl;
throw; // Пробрасываем, чтобы цепочка task.then завершилась с ошибкой
}
}).then([=](pplx::task<std::shared_ptr<org::openapitools::client::model::GetUserTitles_200_response>> responseTask) {
try {
auto response = responseTask.get();
if (!response) { if (!response) {
throw std::runtime_error("Null response from getUserTitles"); throw std::runtime_error("Null response from getUserTitles");
} }

View file

@ -78,7 +78,7 @@ void BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query) {
editMessage(chatId, messageId, showMainMenu()); editMessage(chatId, messageId, showMainMenu());
return; return;
case UserState::VIEWING_MY_TITLES: case UserState::VIEWING_MY_TITLES:
server_.fetchUserTitlesAsync(std::to_string(2)) // ALARM: тестовое значение вместо userId server_.fetchUserTitlesAsync(std::to_string(22)) // ALARM: тестовое значение вместо userId
.then([this, chatId, messageId](pplx::task<std::vector<BotStructs::Title>> t) { .then([this, chatId, messageId](pplx::task<std::vector<BotStructs::Title>> t) {
try { try {
auto titles = t.get(); auto titles = t.get();