From 10f86a5a997f67d65669b10d96fa00b376351e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD?= Date: Sat, 24 Jan 2026 11:02:17 +0300 Subject: [PATCH] Post Diary --- CMakeLists.txt | 1 + src/DAO/IDiariesDAO.h | 5 + src/DAO/MySQLDiariesDAO.cpp | 56 ++++++++- src/DAO/MySQLDiariesDAO.h | 7 +- src/endpoints_handlers/PostDiaryExecutor.h | 140 +++++++++++++++++++++ src/endpoints_handlers/RootExecutor.h | 8 ++ 6 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 src/endpoints_handlers/PostDiaryExecutor.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b80368..43b4b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ add_executable(App ./src/main.cpp src/DAO/MySQLUserTreatmentSchemesDAO.h src/endpoints_handlers/GetUserTreatmentSchemeExecutor.h src/endpoints_handlers/GetDiariesExecutor.h + src/endpoints_handlers/PostDiaryExecutor.h src/DAO/IDiariesDAO.h src/dtos/diary_dto.h src/DAO/MySQLDiariesDao.cpp diff --git a/src/DAO/IDiariesDAO.h b/src/DAO/IDiariesDAO.h index a2bec92..d68a6ca 100644 --- a/src/DAO/IDiariesDAO.h +++ b/src/DAO/IDiariesDAO.h @@ -12,6 +12,11 @@ class IDiariesDAO public: virtual std::vector GetDiariesByUserUUID(const std::string& login) = 0; + virtual void СreateDiary( + const std::string& user_uuid, + const diary_dto& dto + ) const = 0; + virtual ~IDiariesDAO() = default; }; } diff --git a/src/DAO/MySQLDiariesDAO.cpp b/src/DAO/MySQLDiariesDAO.cpp index d746dfe..a489c76 100644 --- a/src/DAO/MySQLDiariesDAO.cpp +++ b/src/DAO/MySQLDiariesDAO.cpp @@ -48,15 +48,63 @@ std::vector MySqlDiariesDAO::GetDiariesByUserUUID(const std::string& dto.dream_level = row[7].get(); dto.anxiety_level = row[8].get(); - dto.comment = - row[9].isNull() ? "" : row[9].get(); + dto.comment = row[9].get(); - dto.user_treatment_scheme_uuid = - row[10].isNull() ? "" : row[10].get(); + dto.user_treatment_scheme_uuid = row[10].get(); diaries.push_back(std::move(dto)); } return diaries; } + +void MySqlDiariesDAO::СreateDiary(const std::string& user_uuid, const diary_dto& dto) const +{ + auto stmt = session_.sql(R"( + INSERT INTO `up_and_down`.`diaries` ( + uuid, + user_uuid, + time, + mania_level, + depression_level, + mood_level, + activity_level, + appetite_level, + dream_level, + anxiety_level, + comment, + user_treatment_schemes_uuid + ) VALUES ( + ?, + ?, + FROM_UNIXTIME(? / 1000), + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ? + ) + )"); + + stmt.bind( + dto.uuid, + user_uuid, + dto.time_ms, + dto.mania_level, + dto.depression_level, + dto.mood_level, + dto.activity_level, + dto.appetite_level, + dto.dream_level, + dto.anxiety_level, + dto.comment, + dto.user_treatment_scheme_uuid + ); + + stmt.execute(); +} } diff --git a/src/DAO/MySQLDiariesDAO.h b/src/DAO/MySQLDiariesDAO.h index 1aab731..6097898 100644 --- a/src/DAO/MySQLDiariesDAO.h +++ b/src/DAO/MySQLDiariesDAO.h @@ -11,10 +11,15 @@ namespace uad class MySqlDiariesDAO final : public IDiariesDAO { mysqlx::Session& session_; + public: explicit MySqlDiariesDAO(mysqlx::Session& session); std::vector GetDiariesByUserUUID(const std::string& user_uuid) override; + void СreateDiary( + const std::string& user_uuid, + const diary_dto& dto + ) const override; }; -} \ No newline at end of file +} diff --git a/src/endpoints_handlers/PostDiaryExecutor.h b/src/endpoints_handlers/PostDiaryExecutor.h new file mode 100644 index 0000000..3edcefe --- /dev/null +++ b/src/endpoints_handlers/PostDiaryExecutor.h @@ -0,0 +1,140 @@ +#pragma once +#include + +#include +#include +#include +#include + +#include "IExecutor.h" +#include "../DAO/IAuthDAO.h" +#include "../DAO/IDiariesDAO.h" +#include "../DAO/IUserTreatmentSchemesDAO.h" +#include "../exceptions/session_exception.h" + +namespace uad +{ +template +class PostDiaryExecutor : public IExecutor +{ + mysqlx::Session& session_; + const std::shared_ptr& auth_dao_; + const std::shared_ptr& diaries_dao_; + +public: + PostDiaryExecutor( + mysqlx::Session& session, + const std::shared_ptr& auth_dao, + const std::shared_ptr& diaries_dao + ) : session_(session), auth_dao_(auth_dao), diaries_dao_(diaries_dao) + { + } + + [[nodiscard]] boost::beast::http::response operator ()( + boost::beast::http::request>&& req + ) override + { + using namespace boost; + using namespace boost::json; + using namespace boost::beast; + using namespace std::string_literals; + using namespace std::string_view_literals; + + constexpr std::string_view auth_prefix = "Bearer "sv; + static const std::string invalid_token_message = + "POST /api/v1/Diary - Response 401: Unauthorized"s; + + BOOST_LOG_TRIVIAL(info) << "POST /api/v1/Diary - Request"; + + if (req[http::field::authorization].size() <= auth_prefix.size()) + { + BOOST_LOG_TRIVIAL(error) << invalid_token_message; + throw session_exception(http::status::unauthorized, "Unauthorized"); + } + + const std::string auth_token = { + req[http::field::authorization].begin() + auth_prefix.size(), + req[http::field::authorization].end() + }; + + if (!auth_dao_->HasAuthorized(auth_token)) + { + BOOST_LOG_TRIVIAL(error) << invalid_token_message; + throw session_exception(http::status::unauthorized, "Unauthorized"); + } + + std::string_view user_uuid_ref = auth_dao_->GetUUID(auth_token); + const std::string user_uuid{user_uuid_ref.begin(), user_uuid_ref.end()}; + + value val = json::parse(req.body()); + object& obj = val.as_object(); + + diary_dto dto; + + dto.uuid = obj["uuid"].as_string().c_str(); + dto.time_ms = obj["time_ms"].as_int64(); + dto.mania_level = obj["mania_level"].as_int64(); + dto.depression_level = obj["depression_level"].as_int64(); + dto.mood_level = obj["mood_level"].as_int64(); + dto.activity_level = obj["activity_level"].as_int64(); + dto.appetite_level = obj["appetite_level"].as_int64(); + dto.dream_level = obj["dream_level"].as_int64(); + dto.anxiety_level = obj["anxiety_level"].as_int64(); + + if (obj.contains("comment")) + dto.comment = obj["comment"].as_string().c_str(); + + if (obj.contains("user_treatment_scheme_uuid")) + dto.user_treatment_scheme_uuid = + obj["user_treatment_scheme_uuid"].as_string().c_str(); + + try + { + diaries_dao_->СreateDiary(user_uuid, dto); + } + catch (const mysqlx::Error& e) + { + BOOST_LOG_TRIVIAL(error) << "MySQL Error: " << e.what(); + throw session_exception(http::status::internal_server_error, "Internal Server Error"); + } + catch (const std::exception& e) + { + BOOST_LOG_TRIVIAL(error) << "Unexpected Error: " << e.what(); + throw session_exception(http::status::internal_server_error, "Internal Server Error"); + } + + http::response res{http::status::ok, req.version()}; + value response_body; + + response_body.emplace_object(); + response_body.as_object().emplace("diary", ToJSON(dto)); + + res.body() = serialize(response_body); + res.set(http::field::content_type, "application/json"); + res.content_length(res.body().size()); + + return res; + } + +private: + boost::json::object ToJSON(const diary_dto& diary) + { + boost::json::object diary_json; + + diary_json["uuid"] = diary.uuid; + diary_json["time"] = diary.time_ms; + diary_json["mania_level"] = diary.mania_level; + diary_json["depression_level"] = diary.depression_level; + diary_json["mood_level"] = diary.mood_level; + diary_json["activity_level"] = diary.activity_level; + diary_json["appetite_level"] = diary.appetite_level; + diary_json["dream_level"] = diary.dream_level; + diary_json["anxiety_level"] = diary.anxiety_level; + diary_json["comment"] = diary.comment; + diary_json["user_treatment_scheme_uuid"] = + diary.user_treatment_scheme_uuid; + + return diary_json; + } +}; +} diff --git a/src/endpoints_handlers/RootExecutor.h b/src/endpoints_handlers/RootExecutor.h index b5db07d..3327fb8 100644 --- a/src/endpoints_handlers/RootExecutor.h +++ b/src/endpoints_handlers/RootExecutor.h @@ -12,6 +12,7 @@ #include "PostUserTreatmentSchemeExecutor.h" #include "PostUserMedicationsExecutor.h" #include "GetDiariesExecutor.h" +#include "PostDiaryExecutor.h" #include "../DAO/IUserDAO.h" #include "../DAO/IAuthDAO.h" #include "../DAO/IDiariesDAO.h" @@ -42,6 +43,8 @@ class RootExecutor Body, Allocator, boost::beast::http::string_body>; using RouteGetDiariesExecutor = GetDiariesExecutor< Body, Allocator, boost::beast::http::string_body>; + using RoutePostDiaryExecutor = PostDiaryExecutor< + Body, Allocator, boost::beast::http::string_body>; using IRouteController = IController; using RouteController = Controller; using RoutesPathes = std::unordered_map>; @@ -139,6 +142,11 @@ public: std::make_shared(session_, auth_dao_, diaries_dao_) }, + { + boost::beast::http::verb::post, + std::make_shared(session_, auth_dao_, + diaries_dao_) + }, } ); }