4 Commits

10 changed files with 227 additions and 45 deletions
+5
View File
@@ -59,6 +59,11 @@ add_executable(App ./src/main.cpp
src/DAO/IMedicationsDAO.h src/DAO/IMedicationsDAO.h
src/DAO/MySQLMedicationsDAO.h src/DAO/MySQLMedicationsDAO.h
src/DAO/MySQLMedicationsDAO.cpp src/DAO/MySQLMedicationsDAO.cpp
src/dtos/user_treatment_scheme_dto.h
src/DAO/IUserTreatmentSchemesDAO.h
src/DAO/MySQLUserTreatmentSchemesDAO.cpp
src/DAO/MySQLUserTreatmentSchemesDAO.h
src/endpoints_handlers/GetUserTreatmentSchemeExecutor.h
) )
target_link_libraries(App PRIVATE Boost::boost target_link_libraries(App PRIVATE Boost::boost
+8 -28
View File
@@ -175,7 +175,7 @@ null
* Пользователю доступны операции добавления, модификации и удаления записей, а также схем лечения * Пользователю доступны операции добавления, модификации и удаления записей, а также схем лечения
### 8.API-Маршруты ### 8.API-Маршруты
* `GET /api/v1/User/Diaries` - получить кусок дневника пользователя (требует Authorization: Bearer <token>) query-параметры: from (int, по умолч. 0), count (int, по умолч. 20) * `GET /api/v1/User/Diaries` - получить кусок дневника пользователя (требует Authorization: Bearer <token>) query-параметры: from (int, по умолч. 0), count (int, по умолч. 20)
* `GET /api/v1/User/TreatmentSchemes` - получить список схем пользователя (требует Authorization: Bearer <token>) query-параметры: from (int, по умолч. 0), count (int, по умолч. 20) * `GET /api/v1/UserTreatmentSchemes` - получить список схем пользователя (требует Authorization: Bearer <token>) query-параметры: from (int, по умолч. 0), count (int, по умолч. 20)
### 9.Контракт ### 9.Контракт
#### Diaries-Request #### Diaries-Request
##### Response - 200 - OK ##### Response - 200 - OK
@@ -193,27 +193,7 @@ null
"dream_level": 6, "dream_level": 6,
"anxiety_level": 7, "anxiety_level": 7,
"comment": "Накрыл психоз. Выпил одну таблетку аминазина" "comment": "Накрыл психоз. Выпил одну таблетку аминазина"
"treatment_scheme": { "treatment_scheme_uuid": bf6d1555-39e9-4d73-8928-4763627f4dd5
"uuid": "bf6d1555-39e9-4d73-8928-4763627f4dd5",
"treatment_name": "Bipolar I Scheme",
"instructions": "Контроль лития в крови раз в 2 месяца. Анализ крови через вену."
"medications": [
{
"uuid": "9bf2dfa9-3add-413c-9a0e-ff605088f1d5",
name: "Haloperidol",
dose: 10
unit: "mg",
"is_urgent": false
},
{
"uuid": "8af2dfa9-3add-413c-9a0e-ff605088f1d5",
"name": "Litii Carbonate",
"dose": 1800,
"unit": "mg",
"is_urgent": false
}
]
}
} }
] ]
} }
@@ -221,15 +201,15 @@ null
##### Errors ##### Errors
* `401 TOKEN_REQUIRED|TOKEN_EXPIRED` — токен недействителен, либо отсутствует * `401 TOKEN_REQUIRED|TOKEN_EXPIRED` — токен недействителен, либо отсутствует
* `500 DATA_LOAD_FAILED` — ошибка при загрузке данных (`B1`) * `500 DATA_LOAD_FAILED` — ошибка при загрузке данных (`B1`)
#### TreatmentSchemes-Request #### UserTreatmentSchemes-Request
##### Response - 200 - OK ##### Response - 200 - OK
``` ```
{ {
"treatment_schemes": [ "user_treatment_schemes": [
{ {
"uuid": "248313cb-a75e-4331-8379-d3f2fc36b68d" "uuid": "248313cb-a75e-4331-8379-d3f2fc36b68d"
"treatment_name": "Bipolar I Scheme Urgent", "treatment_name": "Bipolar I Scheme Urgent",
"instructions": "Схема для бытрого и жесткого купирования психозов. Аминазин пить каждый день.", "instructions": "Схема для быстрого и жесткого купирования психозов. Аминазин пить каждый день.",
"medications": [ "medications": [
{ {
"uuid": "eda5a5f7-167a-44b9-900d-c5c6acfc249b", "uuid": "eda5a5f7-167a-44b9-900d-c5c6acfc249b",
@@ -281,7 +261,7 @@ null
### 7.Постусловия ### 7.Постусловия
* Пользователь добавил запись с указанной датой и прочими состояниями в БД * Пользователь добавил запись с указанной датой и прочими состояниями в БД
### 8.API-Маршруты ### 8.API-Маршруты
* `POST /api/v1/Auth/Diaries` - Создание записи в дневнике * `POST /api/v1/User/Diaries` - Создание записи в дневнике
### 9.Контракт ### 9.Контракт
#### Diaries-Request #### Diaries-Request
``` ```
@@ -367,7 +347,7 @@ null
### 7.Постусловия ### 7.Постусловия
* Пользователь изменил запись соглсано условиям выше в БД * Пользователь изменил запись соглсано условиям выше в БД
### 8.API-Маршруты ### 8.API-Маршруты
* `PUT /api/v1/Auth/Diaries/:diary_guid` - Изменение записи в дневнике * `PUT /api/v1/User/Diaries/:diary_guid` - Изменение записи в дневнике
### 9.Контракт ### 9.Контракт
#### Diaries-Request #### Diaries-Request
``` ```
@@ -450,7 +430,7 @@ null
### 7.Постусловия ### 7.Постусловия
* Целевая запись отсутствует в БД * Целевая запись отсутствует в БД
### 8.API-Маршруты ### 8.API-Маршруты
* `DELETE /api/v1/Auth/Diaries/:diary_guid` - удаление записи в дневнике * `DELETE /api/v1/User/Diaries/:diary_guid` - удаление записи в дневнике
### 9.Контракт ### 9.Контракт
#### Diaries-Request #### Diaries-Request
##### Требования к валидации: ##### Требования к валидации:
+10 -10
View File
@@ -1,11 +1,11 @@
-- Заполнение пользователями -- Заполнение пользователями
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('ab555fcb-b9ee-45f4-9de8-8f16daa5d03c', 'login1', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('ab555fcb-b9ee-45f4-9de8-8f16daa5d03c', 'login1', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('56b7c993-392f-41f8-adb1-9766842dc5fd', 'login2', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('56b7c993-392f-41f8-adb1-9766842dc5fd', 'login2', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('a243b5f2-e265-4c25-82a9-dde4cc70643f', 'login3', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('a243b5f2-e265-4c25-82a9-dde4cc70643f', 'login3', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('51351bb1-7563-479d-a8e9-201d0ff934c2', 'login4', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('51351bb1-7563-479d-a8e9-201d0ff934c2', 'login4', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b6', 'login5', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b6', 'login5', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b7', 'login6', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b7', 'login6', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b8', 'login7', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b8', 'login7', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b9', 'login8', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b9', 'login8', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b0', 'login9', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b0', 'login9', '649111DF29DD8B55');
INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b1', 'login10', '56EED90A26203A6E'); INSERT INTO `up_and_down`.`users` (`uuid`, `login`, `hashed_password`) VALUES ('c792bbe6-2bf2-4fe0-a781-ba96bfeaa3b1', 'login10', '649111DF29DD8B55');
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <vector>
#include <string>
#include "./../dtos/user_treatment_scheme_dto.h"
namespace uad
{
class IUserTreatmentSchemeDAO {
public:
virtual std::vector<user_treatment_scheme_dto> FindByUserLogin(const std::string& login) = 0;
virtual ~IUserTreatmentSchemeDAO() = default;
};
}
+63
View File
@@ -0,0 +1,63 @@
#include <mysqlx/xdevapi.h>
#include <unordered_map>
#include "MySQLUserTreatmentSchemesDAO.h"
namespace uad
{
MySQLUserTreatmentSchemesDAO::MySQLUserTreatmentSchemesDAO(mysqlx::Session& session)
: session_(session)
{
}
std::vector<user_treatment_scheme_dto> MySQLUserTreatmentSchemesDAO::FindByUserLogin(
const std::string& login)
{
static const std::string query = R"(
SELECT
uts.uuid,
uts.treatment_name,
uts.instructions,
ts.medication_uuid
FROM up_and_down.users u
JOIN up_and_down.user_treatment_schemes uts
ON uts.user_uuid = u.uuid
LEFT JOIN up_and_down.treatment_schemes ts
ON ts.user_treatment_schemes_uuid = uts.uuid
WHERE u.login = ?
ORDER BY uts.uuid
)";
mysqlx::SqlResult result = session_.sql(query).bind(login).execute();
std::unordered_map<std::string, user_treatment_scheme_dto> scheme_map;
for (const mysqlx::Row& row : result) {
const std::string scheme_uuid = row[0].get<std::string>();
if (scheme_map.find(scheme_uuid) == scheme_map.end()) {
user_treatment_scheme_dto dto;
dto.uuid = scheme_uuid;
dto.treatment_name = row[1].isNull() ? "" : row[1].get<std::string>();
dto.instructions = row[2].isNull() ? "" : row[2].get<std::string>();
scheme_map.emplace(scheme_uuid, std::move(dto));
}
if (!row[3].isNull()) {
scheme_map[scheme_uuid]
.medication_uuids
.push_back(row[3].get<std::string>());
}
}
std::vector<user_treatment_scheme_dto> schemes;
schemes.reserve(scheme_map.size());
for (auto& [_, dto] : scheme_map) {
schemes.push_back(std::move(dto));
}
return schemes;
}
} // uad
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "IUserTreatmentSchemesDAO.h"
#include <mysqlx/xdevapi.h>
namespace uad
{
class MySQLUserTreatmentSchemesDAO : public IUserTreatmentSchemeDAO
{
mysqlx::Session& session_;
public:
explicit MySQLUserTreatmentSchemesDAO(mysqlx::Session& session);
std::vector<user_treatment_scheme_dto> FindByUserLogin(const std::string& login) override;
};
} // uad
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <string>
#include <vector>
namespace uad
{
struct user_treatment_scheme_dto {
std::string uuid;
std::string user_uuid;
std::string treatment_name;
std::string instructions;
std::vector<std::string> medication_uuids;
};
}
@@ -0,0 +1,66 @@
#pragma once
#include <boost/log/trivial.hpp>
#include <regex>
#include <boost/json.hpp>
#include <boost/mpl/vector/vector0.hpp>
#include <mysqlx/xdevapi.h>
#include "IExecutor.h"
#include "../DAO/IAuthDAO.h"
#include "../DAO/IUserTreatmentSchemesDAO.h"
#include "../exceptions/session_exception.h"
namespace uad
{
template <class Body, class Allocator, class ResponseType>
class GetUserTreatmentSchemeExecutor : public IExecutor<Body, Allocator, ResponseType>
{
mysqlx::Session& session_;
const std::shared_ptr<IAuthDAO>& auth_dao_;
const std::shared_ptr<IUserTreatmentSchemeDAO>& user_treatment_scheme_dao_;
public:
GetUserTreatmentSchemeExecutor(
mysqlx::Session& session,
const std::shared_ptr<IAuthDAO>& auth_dao,
const std::shared_ptr<IUserTreatmentSchemeDAO>& user_treatment_scheme_dao
): session_(session), auth_dao_(auth_dao), user_treatment_scheme_dao_(user_treatment_scheme_dao)
{
}
boost::beast::http::response<ResponseType> operator ()(
boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>>&& 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 = "GET /api/v1/User/Medications - Response 401: Unauthorized"s;
BOOST_LOG_TRIVIAL(info) << "GET /api/v1/User/Medications - 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");
}
http::response<ResponseType> res{http::status::ok, req.version()};
return res;
}
};
}
+4 -1
View File
@@ -5,6 +5,7 @@
#include "../db/mysql_connector.h" #include "../db/mysql_connector.h"
#include "../DAO/IUserDAO.h" #include "../DAO/IUserDAO.h"
#include "../DAO/IMedicationsDAO.h" #include "../DAO/IMedicationsDAO.h"
#include "../DAO/MySQLUserTreatmentSchemesDAO.h"
#include "AuthRegistrationExecutor.h" #include "AuthRegistrationExecutor.h"
#include "RootExecutor.h" #include "RootExecutor.h"
#include "../DAO/MemoryAuthDAO.h" #include "../DAO/MemoryAuthDAO.h"
@@ -22,12 +23,14 @@ void HandleRequest(
static std::shared_ptr<IUserDAO> user_dao = std::make_shared<MySQLUserDAO>(GetMySqlSession()); static std::shared_ptr<IUserDAO> user_dao = std::make_shared<MySQLUserDAO>(GetMySqlSession());
static std::shared_ptr<IAuthDAO> auth_dao = std::make_shared<MemoryAuthDAO>(GetMySqlSession()); static std::shared_ptr<IAuthDAO> auth_dao = std::make_shared<MemoryAuthDAO>(GetMySqlSession());
static std::shared_ptr<IMedicationsDAO> medications_dao = std::make_shared<MySQLMedicationsDAO>(GetMySqlSession()); static std::shared_ptr<IMedicationsDAO> medications_dao = std::make_shared<MySQLMedicationsDAO>(GetMySqlSession());
static std::shared_ptr<IUserTreatmentSchemeDAO> user_treatment_schemes_dao = std::make_shared<MySQLUserTreatmentSchemesDAO>(GetMySqlSession());
static RootExecutor<Body, Allocator, boost::beast::http::string_body, Send> root_executor( static RootExecutor<Body, Allocator, boost::beast::http::string_body, Send> root_executor(
GetMySqlSession(), GetMySqlSession(),
user_dao, user_dao,
auth_dao, auth_dao,
medications_dao medications_dao,
user_treatment_schemes_dao
); );
root_executor(doc_root, std::move(req), std::forward<Send>(send)); root_executor(doc_root, std::move(req), std::forward<Send>(send));
+24 -6
View File
@@ -8,10 +8,12 @@
#include "AuthLoginExecutor.h" #include "AuthLoginExecutor.h"
#include "AuthLogoutExecutor.h" #include "AuthLogoutExecutor.h"
#include "GetUserMedicationsExecutor.h" #include "GetUserMedicationsExecutor.h"
#include "GetUserTreatmentSchemeExecutor.h"
#include "PostUserMedicationsExecutor.h" #include "PostUserMedicationsExecutor.h"
#include "../DAO/IUserDAO.h" #include "../DAO/IUserDAO.h"
#include "../DAO/IAuthDAO.h" #include "../DAO/IAuthDAO.h"
#include "../DAO/IMedicationsDAO.h" #include "../DAO/IMedicationsDAO.h"
#include "../DAO/IUserTreatmentSchemesDAO.h"
#include "./../helpers/helpers.h" #include "./../helpers/helpers.h"
#include "./../exceptions/session_exception.h" #include "./../exceptions/session_exception.h"
@@ -27,9 +29,11 @@ class RootExecutor
Body, Allocator, boost::beast::http::string_body>; Body, Allocator, boost::beast::http::string_body>;
using RouteAuthLogoutExecutor = AuthLogoutExecutor< using RouteAuthLogoutExecutor = AuthLogoutExecutor<
Body, Allocator, boost::beast::http::string_body>; Body, Allocator, boost::beast::http::string_body>;
using RouteUserGetMedicationsExecutor = GetUserMedicationsExecutor< using RouteGetUserMedicationsExecutor = GetUserMedicationsExecutor<
Body, Allocator, boost::beast::http::string_body>; Body, Allocator, boost::beast::http::string_body>;
using RouteUserPostMedicationsExecutor = PostUserMedicationsExecutor< using RoutePostUserMedicationsExecutor = PostUserMedicationsExecutor<
Body, Allocator, boost::beast::http::string_body>;
using RouteGetUserTreatmentSchemeExecutor = GetUserTreatmentSchemeExecutor<
Body, Allocator, boost::beast::http::string_body>; Body, Allocator, boost::beast::http::string_body>;
using IRouteController = IController<Body, Allocator, boost::beast::http::string_body>; using IRouteController = IController<Body, Allocator, boost::beast::http::string_body>;
using RouteController = Controller<Body, Allocator, boost::beast::http::string_body>; using RouteController = Controller<Body, Allocator, boost::beast::http::string_body>;
@@ -45,14 +49,19 @@ private:
const std::shared_ptr<IUserDAO>& user_dao_; const std::shared_ptr<IUserDAO>& user_dao_;
const std::shared_ptr<IAuthDAO>& auth_dao_; const std::shared_ptr<IAuthDAO>& auth_dao_;
const std::shared_ptr<IMedicationsDAO>& medications_dao_; const std::shared_ptr<IMedicationsDAO>& medications_dao_;
const std::shared_ptr<IUserTreatmentSchemeDAO>& user_treatment_scheme_dao_;
public: public:
RootExecutor( RootExecutor(
mysqlx::Session& session, mysqlx::Session& session,
const std::shared_ptr<IUserDAO>& user_dao, const std::shared_ptr<IUserDAO>& user_dao,
const std::shared_ptr<IAuthDAO>& auth_dao, const std::shared_ptr<IAuthDAO>& auth_dao,
const std::shared_ptr<IMedicationsDAO>& medications_dao) : const std::shared_ptr<IMedicationsDAO>& medications_dao,
session_(session), user_dao_(user_dao), auth_dao_(auth_dao), medications_dao_(medications_dao) const std::shared_ptr<IUserTreatmentSchemeDAO>& user_treatment_scheme_dao
) :
session_(session), user_dao_(user_dao),
auth_dao_(auth_dao), medications_dao_(medications_dao),
user_treatment_scheme_dao_(user_treatment_scheme_dao)
{ {
routes_pathes_["/api/v1/Auth/Register"] = std::make_unique<RouteController>( routes_pathes_["/api/v1/Auth/Register"] = std::make_unique<RouteController>(
typename RouteController::HTTPMethodsToExecutors{ typename RouteController::HTTPMethodsToExecutors{
@@ -87,11 +96,20 @@ public:
typename RouteController::HTTPMethodsToExecutors{ typename RouteController::HTTPMethodsToExecutors{
{ {
boost::beast::http::verb::get, boost::beast::http::verb::get,
std::make_shared<RouteUserGetMedicationsExecutor>(session_, auth_dao_, medications_dao_) std::make_shared<RouteGetUserMedicationsExecutor>(session_, auth_dao_, medications_dao_)
}, },
{ {
boost::beast::http::verb::post, boost::beast::http::verb::post,
std::make_shared<RouteUserPostMedicationsExecutor>(session_, auth_dao_, medications_dao_) std::make_shared<RoutePostUserMedicationsExecutor>(session_, auth_dao_, medications_dao_)
},
}
);
routes_pathes_["api/v1/UserTreatmentSchemes"] = std::make_unique<RouteController>(
typename RouteController::HTTPMethodsToExecutors{
{
boost::beast::http::verb::get,
std::make_shared<RouteGetUserTreatmentSchemeExecutor>(session_, auth_dao_, user_treatment_scheme_dao_)
}, },
} }
); );