feat(tgbot-back): start to develop back

Implemented fetchUserTitlesAsync func and embedded it in the code of the front in the trial mode. It needs to be restructured
This commit is contained in:
Kirill 2025-12-05 12:38:34 +03:00
parent 4ca8b19adb
commit 847aec7bdd
9 changed files with 190 additions and 13 deletions

View file

@ -1,7 +1,16 @@
cmake_minimum_required(VERSION 3.10.2)
project(AnimeBot)
file(GLOB SOURCES "src/*.cpp")
set(SOURCES "")
file(GLOB_RECURSE SRC_FRONT "src/*.cpp")
list(APPEND SOURCES ${SRC_FRONT})
file(GLOB_RECURSE SRC_BACK "../back/src/*.cpp")
list(APPEND SOURCES ${SRC_BACK})
file(GLOB_RECURSE SRC_API "../generated-client/src/*.cpp")
list(APPEND SOURCES ${SRC_API})
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
@ -12,8 +21,11 @@ find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(Boost COMPONENTS system REQUIRED)
find_package(CURL)
find_library(CPPREST_LIB cpprest REQUIRED)
include_directories(/usr/local/include ${OPENSSL_INCLUDE_DIR} ${Boost_INCLUDE_DIR})
include_directories(include/)
include_directories(../back/include)
include_directories(../generated-client/include)
if (CURL_FOUND)
include_directories(${CURL_INCLUDE_DIRS})
add_definitions(-DHAVE_CURL)
@ -21,4 +33,4 @@ endif()
add_executable(AnimeBot ${SOURCES})
target_link_libraries(AnimeBot /usr/local/lib/libTgBot.a ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES})
target_link_libraries(AnimeBot /usr/local/lib/libTgBot.a ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} ${CPPREST_LIB})

View file

@ -7,7 +7,7 @@ public:
static TgBot::InlineKeyboardMarkup::Ptr createMainMenu();
/// Create keyboard for My_Titles
static TgBot::InlineKeyboardMarkup::Ptr createMyTitles(std::vector<Title> titles);
static TgBot::InlineKeyboardMarkup::Ptr createMyTitles(std::vector<BotStructs::Title> titles);
/// Create keyboard for sendError
static TgBot::InlineKeyboardMarkup::Ptr createError(const std::string& errorCallback);

View file

@ -39,5 +39,6 @@ namespace BotConstants {
const std::string MAIN_MENU = "Вас приветствует nyanimedb бот:)\nЧего будем делать?";
const std::string SAD_ERROR = "У нас что-то случилось:(\nМы обязательно скоро исправимся";
const std::string AUTH_ERROR = "Проблемы с авторизацией, попробуйте авторизоваться повторно";
const std::string SERVER_ERROR = "Не удалось загрузить данные. Попробуйте позже.";
}
}

View file

@ -3,6 +3,7 @@
#include <string>
#include <structs.hpp>
#include <unordered_map>
#include "BotToServer.hpp"
/// @brief Структура возвращаемого значения класса BotHandlers для изменения текущего сообщения
struct HandlerResult {
@ -58,6 +59,7 @@ public:
private:
TgBot::Api botApi;
std::unordered_map<int64_t, UserContext> userContexts;
BotToServer server_;
void handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext& ctx);
@ -104,7 +106,7 @@ private:
/// @brief Отрисовка текущего экрана (соотв. контексту)
/// @param ctx - текущий контекст
/// @return HandlerResult для нового состояния сообщения
HandlerResult renderCurrent(const UserContext& ctx);
HandlerResult renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx);
/// @brief Логика переходов между контекстами (навигация на следующий шаг)
/// @param query - запрос
@ -120,4 +122,7 @@ private:
/// @brief Посылает интерфейс обработки ошибки на callback запрос
/// @param query запрос
void sendError(TgBot::CallbackQuery::Ptr query, const std::string& errText);
// Форматирование для отображения в сообщении
std::string formatTitlesList(const std::vector<BotStructs::Title>& titles);
};

View file

@ -1,8 +1,10 @@
#pragma once
namespace BotStructs {
struct Title {
int64_t id;
std::string name;
std::string description;
int64_t num;
};
}

View file

@ -15,13 +15,13 @@ TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMainMenu() {
}
// TODO: Переписать с учетом констант на количество отображаемых тайтлов и нового callback'a
TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMyTitles(std::vector<Title> titles) {
TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMyTitles(std::vector<BotStructs::Title> titles) {
auto keyboard = std::make_shared<TgBot::InlineKeyboardMarkup>();
std::vector<TgBot::InlineKeyboardButton::Ptr> row;
std::vector<std::vector<TgBot::InlineKeyboardButton::Ptr>> layout;
int counter = 0;
for(Title& title : titles) {
for(BotStructs::Title& title : titles) {
if(counter >= 6) {
break;
}

View file

@ -22,7 +22,7 @@ void BotHandlers::handleCallback(TgBot::CallbackQuery::Ptr query) {
HandlerResult BotHandlers::returnMyTitles(int64_t userId, int64_t payload) {
// Здесь должен происходить запрос на сервер
std::vector<Title> titles = {{123, "Школа мертвяков", "", 1}, {321, "KissXsis", "", 2}};
std::vector<BotStructs::Title> titles = {{123, "Школа мертвяков", "", 1}, {321, "KissXsis", "", 2}};
struct HandlerResult result;
result.keyboard = KeyboardFactory::createMyTitles(titles);
@ -85,7 +85,8 @@ void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext&
ctx.history.back().payload = newPayload;
auto result = renderCurrent(ctx);
auto result = renderCurrent(query, ctx);
if(result.message == "meow") return; // TODO: убрать
editMessage(query, result);
return;
}
@ -96,7 +97,8 @@ void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext&
sendError(query, BotConstants::Text::SAD_ERROR);
return;
}
auto result = renderCurrent(ctx);
auto result = renderCurrent(query, ctx);
if(result.message == "meow") return; // TODO: убрать
editMessage(query, result);
return;
}
@ -109,7 +111,8 @@ void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext&
}
ctx.history.push_back(*newStepOpt);
auto result = renderCurrent(ctx);
auto result = renderCurrent(query, ctx);
if(result.message == "meow") return; // TODO: убрать
editMessage(query, result);
}
@ -161,15 +164,32 @@ void BotHandlers::editMessage(TgBot::CallbackQuery::Ptr query, HandlerResult res
);
}
HandlerResult BotHandlers::renderCurrent(const UserContext& ctx) {
HandlerResult BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx) {
const auto& step = ctx.history.back();
int64_t userId = query->from->id;
switch (step.state) {
case UserState::MAIN_MENU:
return showMainMenu();
case UserState::VIEWING_MY_TITLES:
return returnMyTitles(ctx.userId, step.payload); // payload = offset
server_.fetchUserTitlesAsync(std::to_string(2)) // ALARM: тестовое значение вместо userId
.then([this, query](pplx::task<std::vector<BotStructs::Title>> t) {
try {
auto titles = t.get();
std::string message = formatTitlesList(titles);
auto keyboard = KeyboardFactory::createMyTitles(titles);
editMessage(query, {message, keyboard});
} catch (const std::exception& e) {
sendError(query, BotConstants::Text::SERVER_ERROR);
// Логирование ошибки (например, в cerr)
}
});
return {"meow", nullptr};
/*
case UserState::VIEWING_TITLE_PAGE:
case UserState::VIEWING_TITLE_PAGE:
return returnTitlePage(step.payload); // payload = titleId
case UserState::VIEWING_REVIEW:
return returnReview(step.payload); // payload = reviewId
@ -256,4 +276,17 @@ void BotHandlers::handleError(TgBot::CallbackQuery::Ptr query, UserContext& ctx)
HandlerResult result = {BotConstants::Text::AUTH_ERROR, nullptr};
editMessage(query, result);
}
}
std::string BotHandlers::formatTitlesList(const std::vector<BotStructs::Title>& titles) {
if (titles.empty()) {
return "У вас пока нет тайтлов.";
}
std::string msg;
for (size_t i = 0; i < titles.size(); ++i) {
// num — 0-based, но в сообщении показываем 1-based
msg += std::to_string(i + 1) + ". " + titles[i].name + "\n";
}
return msg;
}