diff --git a/src/endpoints_handlers/AuthLoginExecutor.h b/src/endpoints_handlers/AuthLoginExecutor.h new file mode 100644 index 0000000..7f34958 --- /dev/null +++ b/src/endpoints_handlers/AuthLoginExecutor.h @@ -0,0 +1,138 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "IExecutor.h" +#include "../DAO/IUserDAO.h" +#include "../DAO/IAuthDAO.h" + +namespace uad +{ +template +class AuthLoginExecutor : public IExecutor +{ + mysqlx::Session& session_; + std::shared_ptr user_dao_; + std::shared_ptr auth_dao_; + +public: + AuthLoginExecutor(mysqlx::Session& session, + std::shared_ptr user_dao, + std::shared_ptr auth_dao) + : session_(session), user_dao_(user_dao), auth_dao_(auth_dao) + { + } + + 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; + + auto body = req.body(); + value req_json; + value response_body; + + response_body.emplace_object(); + + try + { + req_json = json::parse(body); + } + catch (const system::system_error& err) + { + http::response res{http::status::bad_request, req.version()}; + response_body.as_object().emplace("Result", "cannot deserialize json"); + + res.body() = serialize(response_body); + res.set(http::field::content_type, "application/json"); + res.content_length(res.body().size()); + + return res; + } + + std::string login = req_json.as_object().at("login").as_string().c_str(); + std::string password = req_json.as_object().at("password").as_string().c_str(); + + if (!ValidateLogin(login) || !ValidatePassword(password)) + { + http::response res{http::status::unprocessable_entity, req.version()}; + + response_body.as_object().emplace( + "Result", + "Validations failed. Login should have length from 3 to 50. Password from 5 characters length." + ); + + res.body() = serialize(response_body); + res.set(http::field::content_type, "application/json"); + res.content_length(res.body().size()); + + return res; + } + + if (user_dao_->GetByLogin(login).has_value()) + { + http::response res{http::status::conflict, req.version()}; + + response_body.as_object().emplace( + "Result", + "user with login "s + login + " exists"s + ); + + res.body() = serialize(response_body); + res.set(http::field::content_type, "application/json"); + res.content_length(res.body().size()); + + return res; + } + + User user; + + user.SetLogin(login); + user.SetPassword(password); + + const auto uuid_stringified = user_dao_->Create(user); + + http::response res{ + http::status::created, req.version() + }; + + response_body.as_object().emplace( + "uuid", + uuid_stringified + ); + response_body.as_object().emplace( + "login", + user.GetLogin() + ); + + res.body() = serialize(response_body); + res.set(http::field::content_type, "application/json"); + res.content_length(res.body().size()); + + return res; + } + +private: + bool ValidateLogin(const std::string& login) + { + if (login.size() < 3 || login.size() > 50) return false; + + std::regex pattern(std::string("^[A-Za-z0-9_]+$")); + + return std::regex_match(login, pattern); + } + + bool ValidatePassword(const std::string& password) + { + return password.size() >= 5; + } +}; +} diff --git a/src/endpoints_handlers/HandleRequest.h b/src/endpoints_handlers/HandleRequest.h index 2ab452d..860faf6 100644 --- a/src/endpoints_handlers/HandleRequest.h +++ b/src/endpoints_handlers/HandleRequest.h @@ -6,6 +6,7 @@ #include "../DAO/IUserDAO.h" #include "AuthRegistrationExecutor.h" #include "RootExecutor.h" +#include "../DAO/MemoryAuthDAO.h" #include "../DAO/MySQLUserDAO.h" namespace uad @@ -17,7 +18,9 @@ void HandleRequest( Send&& send) { static RootExecutor root_executor( - GetMySqlSession(), std::make_shared(GetMySqlSession()) + GetMySqlSession(), + std::make_shared(GetMySqlSession()), + std::make_shared(GetMySqlSession()) ); root_executor(doc_root, std::move(req), std::forward(send)); diff --git a/src/endpoints_handlers/RootExecutor.h b/src/endpoints_handlers/RootExecutor.h index 0c7581f..aa03fd0 100644 --- a/src/endpoints_handlers/RootExecutor.h +++ b/src/endpoints_handlers/RootExecutor.h @@ -2,7 +2,9 @@ #include "IController.h" #include "Controller.h" #include "AuthRegistrationExecutor.h" +#include "AuthLoginExecutor.h" #include "../DAO/IUserDAO.h" +#include "../DAO/IAuthDAO.h" #include "./../helpers/helpers.h" namespace uad @@ -13,6 +15,8 @@ class RootExecutor using IRouteExecutor = IExecutor; using RouteAuthRegistrationExecutor = AuthRegistrationExecutor< Body, Allocator, boost::beast::http::string_body>; + using RouteAuthLoginExecutor = AuthLoginExecutor< + Body, Allocator, boost::beast::http::string_body>; using IRouteController = IController; using RouteController = Controller; using RoutesPathes = std::unordered_map>; @@ -25,15 +29,30 @@ private: RoutesPathes routes_pathes_; mysqlx::Session& session_; std::shared_ptr user_dao_; + std::shared_ptr auth_dao_; public: - RootExecutor(mysqlx::Session& session, std::shared_ptr user_dao) -: session_(session), user_dao_(user_dao) + RootExecutor( + mysqlx::Session& session, + std::shared_ptr user_dao, + std::shared_ptr auth_dao) : + session_(session), user_dao_(user_dao), auth_dao_(auth_dao) + { routes_pathes_["/api/v1/Auth/Register"] = std::make_unique( - typename RouteController::HTTPMethodsToExecutors{ - {boost::beast::http::verb::post, std::make_shared(session_, user_dao_)} - } + typename RouteController::HTTPMethodsToExecutors{ + {boost::beast::http::verb::post, std::make_shared( + session_, + user_dao_ + )} + } + ); + + routes_pathes_["/api/v1/Auth/Login"] = std::make_unique( + typename RouteController::HTTPMethodsToExecutors{ + {boost::beast::http::verb::post, + std::make_shared(session_, user_dao_, auth_dao_)} + } ); } @@ -41,7 +60,7 @@ public: boost::beast::string_view doc_root, Request&& req, Send&& send - ) + ) { const std::string& route = req.target(); const bool is_match_route = routes_pathes_.count(route); @@ -77,7 +96,7 @@ public: body.open(path.c_str(), boost::beast::file_mode::scan, ec); if (ec == boost::beast::errc::no_such_file_or_directory) - return send(SendNotFound(std::move(req),req.target())); + return send(SendNotFound(std::move(req), req.target())); if (ec) return send(SendServerError(std::move(req), ec.message())); @@ -112,7 +131,7 @@ private: StringResponse SendBadRequest( Request&& req, boost::beast::string_view why - ) + ) { StringResponse res{ boost::beast::http::status::bad_request, req.version() @@ -128,7 +147,7 @@ private: StringResponse SendNotFound( Request&& req, boost::beast::string_view target - ) + ) { StringResponse res{ boost::beast::http::status::not_found, req.version() @@ -144,7 +163,7 @@ private: StringResponse SendServerError( Request&& req, boost::beast::string_view what - ) + ) { StringResponse res{ boost::beast::http::status::internal_server_error, req.version()