10 Commits

9 changed files with 184 additions and 179 deletions
+58 -43
View File
@@ -3,10 +3,10 @@ project(UpAndDown)
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-D_WIN32_WINNT=0x0602)
if(POLICY CMP0167) if (POLICY CMP0167)
cmake_policy(SET CMP0167 OLD) cmake_policy(SET CMP0167 OLD)
endif() endif ()
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON) set(Boost_USE_MULTITHREADED ON)
@@ -24,63 +24,78 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
add_executable(App ./src/main.cpp add_executable(App ./src/main.cpp
./src/helpers/helpers.h ./src/helpers/helpers.h
./src/helpers/helpers.cpp ./src/helpers/helpers.cpp
./src/endpoints_handlers/HandleRequest.h ./src/endpoints_handlers/HandleRequest.h
./src/endpoints_handlers/IController.h ./src/endpoints_handlers/IController.h
./src/endpoints_handlers/Controller.h ./src/endpoints_handlers/Controller.h
./src/session/HttpSession.h ./src/session/HttpSession.h
./src/session/HttpSession.cpp ./src/session/HttpSession.cpp
./src/session/WebsocketSession.h ./src/session/WebsocketSession.h
./src/session/WebsocketSession.cpp ./src/session/WebsocketSession.cpp
./src/listener/Listener.h ./src/listener/Listener.h
./src/listener/Listener.cpp ./src/listener/Listener.cpp
./src/db/mysql_connector.cpp ./src/db/mysql_connector.cpp
./src/db/mysql_connector.h ./src/db/mysql_connector.h
./src/DAO/IUserDAO.h ./src/DAO/IUserDAO.h
./src/entities/user.h ./src/entities/user.h
./src/DAO/MySQLUserDAO.cpp ./src/DAO/MySQLUserDAO.cpp
./src/DAO/MySQLUserDAO.h ./src/DAO/MySQLUserDAO.h
./src/endpoints_handlers/IExecutor.h ./src/endpoints_handlers/IExecutor.h
./src/endpoints_handlers/AuthRegistrationExecutor.h ./src/endpoints_handlers/AuthRegistrationExecutor.h
./src/endpoints_handlers/RootExecutor.h ./src/endpoints_handlers/RootExecutor.h
./src/DAO/IAuthDAO.h ./src/DAO/IAuthDAO.h
./src/DAO/MemoryAuthDAO.cpp ./src/DAO/MemoryAuthDAO.cpp
./src/DAO/MemoryAuthDAO.h ./src/DAO/MemoryAuthDAO.h
./src/endpoints_handlers/AuthLogoutExecutor.h ./src/endpoints_handlers/AuthLogoutExecutor.h
./src/exceptions/session_exception.cpp ./src/endpoints_handlers/AuthLoginExecutor.h
./src/exceptions/session_exception.h ./src/exceptions/session_exception.cpp
./src/exceptions/session_exception.h
src/log/Log.h src/log/Log.h
src/log/Log.cpp src/log/Log.cpp
) )
target_link_libraries(App PRIVATE Boost::boost target_link_libraries(App PRIVATE Boost::boost
Boost::json Boost::json
Boost::log Boost::log
Boost::system Boost::system
Boost::filesystem Boost::filesystem
Threads::Threads Threads::Threads
mysql::concpp) mysql::concpp)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
endif () endif ()
add_executable(HelpersTests ./tests/helpers/helpers_TEST.cpp add_executable(HelpersTests ./tests/helpers/helpers_TEST.cpp
./src/helpers/helpers.h ./src/helpers/helpers.h
./src/helpers/helpers.cpp) ./src/helpers/helpers.cpp)
target_link_libraries(HelpersTests PRIVATE Boost::boost) target_link_libraries(HelpersTests PRIVATE Boost::boost Boost::json Boost::log)
add_test(HelpersTests HelpersTests) add_test(HelpersTests HelpersTests)
add_executable(ControllerTests ./tests/endpoint_handlers/Controller_TEST.cpp add_executable(ControllerTests ./tests/endpoint_handlers/Controller_TEST.cpp
./src/endpoints_handlers/IController.h ./src/endpoints_handlers/IController.h
./src/endpoints_handlers/Controller.h) ./src/endpoints_handlers/Controller.h)
target_link_libraries(ControllerTests PRIVATE Boost::boost) target_link_libraries(ControllerTests PRIVATE Boost::boost)
add_test(ControllerTests ControllerTests) add_test(ControllerTests ControllerTests)
add_executable(AuthRegistrationExecutorTests ./tests/endpoint_handlers/AuthRegistrationExecutor_TEST.cpp add_executable(AuthRegistrationExecutorTests ./tests/endpoint_handlers/AuthRegistrationExecutor_TEST.cpp
./src/endpoints_handlers/AuthRegistrationExecutor.h) ./src/endpoints_handlers/AuthRegistrationExecutor.h
target_link_libraries(AuthRegistrationExecutorTests PRIVATE Boost::boost Boost::json mysql::concpp) ./src/exceptions/session_exception.cpp
./src/exceptions/session_exception.h
./src/helpers/helpers.h
./src/helpers/helpers.cpp
./src/DAO/MySQLUserDAO.h
./src/DAO/MySQLUserDAO.cpp
./src/db/mysql_connector.h
./src/db/mysql_connector.cpp)
target_link_libraries(AuthRegistrationExecutorTests PRIVATE Boost::boost
Boost::json
Boost::log
Boost::system
Boost::filesystem
Threads::Threads
mysql::concpp)
add_test(AuthRegistrationExecutorTests AuthRegistrationExecutorTests) add_test(AuthRegistrationExecutorTests AuthRegistrationExecutorTests)
if (WIN32) if (WIN32)
@@ -88,4 +103,4 @@ if (WIN32)
target_compile_definitions(HelpersTests PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) target_compile_definitions(HelpersTests PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
target_compile_definitions(ControllerTests PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) target_compile_definitions(ControllerTests PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
target_compile_definitions(AuthRegistrationExecutorTests PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) target_compile_definitions(AuthRegistrationExecutorTests PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
endif() endif ()
-72
View File
@@ -1,72 +0,0 @@
#include "Listener.h"
namespace uad
{
Listener::Listener(boost::asio::io_context& ioc,
boost::asio::ip::tcp::endpoint endpoint,
const std::shared_ptr<const std::string>& doc_root)
: ioc_(ioc), acceptor_(net::make_strand(ioc)), doc_root_(doc_root)
{
beast::error_code ec;
acceptor_.open(endpoint.protocol(), ec);
if (ec)
{
uad::Fail(ec, "open");
return;
}
acceptor_.set_option(net::socket_base::reuse_address(true), ec);
if (ec)
{
uad::Fail(ec, "set_option");
return;
}
acceptor_.bind(endpoint, ec);
if (ec)
{
uad::Fail(ec, "bind");
return;
}
acceptor_.listen(
net::socket_base::max_listen_connections, ec);
if (ec)
{
uad::Fail(ec, "listen");
return;
}
}
void Listener::Run()
{
DoAccept();
}
void Listener::DoAccept()
{
acceptor_.async_accept(
net::make_strand(ioc_),
beast::bind_front_handler(
&Listener::OnAccept,
shared_from_this()));
}
void Listener::OnAccept(beast::error_code ec, tcp::socket socket)
{
if (ec)
{
uad::Fail(ec, "accept");
return;
}
else
{
std::make_shared<uad::Session>(
std::move(socket),
doc_root_)->Run();
}
DoAccept();
}
}
-45
View File
@@ -1,45 +0,0 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/strand.hpp>
#include <boost/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include "helpers.h"
#include "Session.h"
namespace uad
{
namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = boost::asio::ip::tcp;
class Listener : public std::enable_shared_from_this<Listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
std::shared_ptr<std::string const> doc_root_;
public:
Listener(
net::io_context& ioc,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root);
void Run();
private:
void DoAccept();
void OnAccept(beast::error_code ec, tcp::socket socket);
};
}
+8 -2
View File
@@ -1,11 +1,12 @@
#pragma once #pragma once
#include <boost/log/trivial.hpp>
#include <regex> #include <regex>
#include <boost/json.hpp> #include <boost/json.hpp>
#include <mysqlx/xdevapi.h> #include <mysqlx/xdevapi.h>
#include <mysqlx/common/api.h> #include <mysqlx/common/api.h>
#include <boost/uuid.hpp>
#include <boost/uuid.hpp>
#include "IExecutor.h" #include "IExecutor.h"
#include "../DAO/IUserDAO.h" #include "../DAO/IUserDAO.h"
#include "../DAO/IAuthDAO.h" #include "../DAO/IAuthDAO.h"
@@ -38,6 +39,8 @@ public:
using namespace boost::beast; using namespace boost::beast;
using namespace std::string_literals; using namespace std::string_literals;
BOOST_LOG_TRIVIAL(info) << "POST /api/v1/Auth/Login - Request";
const auto body = req.body(); const auto body = req.body();
value req_json; value req_json;
@@ -47,7 +50,8 @@ public:
} }
catch (const system::system_error& err) catch (const system::system_error& err)
{ {
throw session_exception(http::status::bad_request, "cannot deserialize json"); BOOST_LOG_TRIVIAL(info) << "POST /api/v1/Auth/Login - Response 500: Cannot deserialize json";
throw session_exception(http::status::internal_server_error, "Cannot deserialize json");
} }
@@ -56,6 +60,7 @@ public:
if (login.empty() || password.empty()) if (login.empty() || password.empty())
{ {
BOOST_LOG_TRIVIAL(info) << "POST /api/v1/Auth/Login - Response 422: Login or password are empty";
throw session_exception(http::status::unprocessable_entity, "Login or password are empty"s); throw session_exception(http::status::unprocessable_entity, "Login or password are empty"s);
} }
@@ -63,6 +68,7 @@ public:
if (!maybe_user.has_value() && maybe_user.value().hashed_password != HashPassword(password)) if (!maybe_user.has_value() && maybe_user.value().hashed_password != HashPassword(password))
{ {
BOOST_LOG_TRIVIAL(info) << "POST /api/v1/Auth/Login - Response 403: Incorrect login or password";
throw session_exception(http::status::forbidden,"Incorrect login or password"); throw session_exception(http::status::forbidden,"Incorrect login or password");
} }
const std::string token = GenerateUUID(); const std::string token = GenerateUUID();
+6 -1
View File
@@ -1,4 +1,5 @@
#pragma once #pragma once
#include <boost/log/trivial.hpp>
#include <regex> #include <regex>
#include <boost/json.hpp> #include <boost/json.hpp>
@@ -35,6 +36,8 @@ public:
using namespace boost::beast; using namespace boost::beast;
using namespace std::string_literals; using namespace std::string_literals;
BOOST_LOG_TRIVIAL(info) << "POST /api/v1/Auth/Logout - Request";
const auto body = req.body(); const auto body = req.body();
value req_json; value req_json;
@@ -44,6 +47,7 @@ public:
} }
catch (const system::system_error& err) catch (const system::system_error& err)
{ {
BOOST_LOG_TRIVIAL(error) << "POST /api/v1/Auth/Logout - Response 500: Cannot deserialize json";
throw session_exception(http::status::internal_server_error, "cannot deserialize json"s); throw session_exception(http::status::internal_server_error, "cannot deserialize json"s);
} }
@@ -51,7 +55,8 @@ public:
if (!auth_dao_->Logout(token)) if (!auth_dao_->Logout(token))
{ {
throw session_exception(http::status::bad_request, "token is not authorized"s); BOOST_LOG_TRIVIAL(error) << "POST /api/v1/Auth/Logout - Response 400: Token is not authorized";
throw session_exception(http::status::bad_request, "Token is not authorized"s);
} }
http::response<ResponseType> res{http::status::ok, req.version()}; http::response<ResponseType> res{http::status::ok, req.version()};
@@ -1,4 +1,5 @@
#pragma once #pragma once
#include <boost/log/trivial.hpp>
#include <regex> #include <regex>
#include <boost/json.hpp> #include <boost/json.hpp>
@@ -32,6 +33,8 @@ public:
using namespace boost::beast; using namespace boost::beast;
using namespace std::string_literals; using namespace std::string_literals;
BOOST_LOG_TRIVIAL(info) << "POST /api/v1/Auth/Registration - Request";
const auto& body = req.body(); const auto& body = req.body();
value req_json; value req_json;
@@ -41,7 +44,8 @@ public:
} }
catch (const system::system_error& err) catch (const system::system_error& err)
{ {
throw session_exception(http::status::bad_request, "cannot deserialize json"); BOOST_LOG_TRIVIAL(error) << "POST /api/v1/Auth/Registration - Response 500: Cannot deserialize json";
throw session_exception(http::status::internal_server_error, "Cannot deserialize json");
} }
const std::string login = req_json.as_object().at("login").as_string().c_str(); const std::string login = req_json.as_object().at("login").as_string().c_str();
@@ -49,6 +53,7 @@ public:
if (!ValidateLogin(login) || !ValidatePassword(password)) if (!ValidateLogin(login) || !ValidatePassword(password))
{ {
BOOST_LOG_TRIVIAL(error) << "POST /api/v1/Auth/Registration - Response 422: Validations failed. Login should have length from 3 to 50. Password from 5 characters length.";
throw session_exception( throw session_exception(
http::status::unprocessable_entity, http::status::unprocessable_entity,
"Validations failed. Login should have length from 3 to 50. Password from 5 characters length."s "Validations failed. Login should have length from 3 to 50. Password from 5 characters length."s
@@ -57,7 +62,8 @@ public:
if (user_dao_->GetByLogin(login).has_value()) if (user_dao_->GetByLogin(login).has_value())
{ {
throw session_exception(http::status::conflict, "user with login "s + login + " exists"s); BOOST_LOG_TRIVIAL(error) << "POST /api/v1/Auth/Registration - Response 409: "s + "User with login "s + login + " exists"s;
throw session_exception(http::status::conflict, "User with login "s + login + " exists"s);
} }
user user; user user;
+6 -5
View File
@@ -11,11 +11,12 @@ namespace uad
void InitLogs() void InitLogs()
{ {
logging::add_file_log( logging::add_file_log(
logging::keywords::file_name = "app_%Y-%m-%d_%H-%M-%S.log", // Имя файла с timestamp logging::keywords::file_name = "app_%Y-%m-%d_%H-%M-%S.log",
logging::keywords::rotation_size = 10 * 1024 * 1024, // Ротация при достижении 10 МБ logging::keywords::rotation_size = 10 * 1024 * 1024,
logging::keywords::time_based_rotation = logging::keywords::time_based_rotation =
logging::sinks::file::rotation_at_time_point(0, 0, 0), // Ротация каждый день в полночь logging::sinks::file::rotation_at_time_point(0, 0, 0),
logging::keywords::format = "[%TimeStamp%] [%Severity%]: %Message%" // Формат записи logging::keywords::format = "[%TimeStamp%] [%Severity%]: %Message%"
); );
logging::add_common_attributes();
} }
} }
+3 -5
View File
@@ -1,7 +1,9 @@
#include <boost/log/trivial.hpp>
#ifdef WIN32 #ifdef WIN32
#include <sdkddkver.h> #include <sdkddkver.h>
#endif #endif
#include <algorithm> #include <algorithm>
#include <boost/asio/signal_set.hpp> #include <boost/asio/signal_set.hpp>
#include <boost/beast/core.hpp> #include <boost/beast/core.hpp>
@@ -14,9 +16,6 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include "./session/WebsocketSession.h" #include "./session/WebsocketSession.h"
#include "./listener/Listener.h" #include "./listener/Listener.h"
@@ -52,7 +51,6 @@ int main(int argc, char* argv[])
InitLogs(); InitLogs();
// Добавление общих атрибутов (включая время) // Добавление общих атрибутов (включая время)
logging::add_common_attributes();
uad::SetMySqlSession(new mysqlx::Session(mysql_credentials)); uad::SetMySqlSession(new mysqlx::Session(mysql_credentials));
@@ -63,7 +61,7 @@ int main(int argc, char* argv[])
net::signal_set signals(ioc, SIGINT, SIGTERM); net::signal_set signals(ioc, SIGINT, SIGTERM);
signals.async_wait([&](beast::error_code const&, int) { ioc.stop(); }); signals.async_wait([&](beast::error_code const&, int) { ioc.stop(); });
BOOST_LOG_TRIVIAL(error) << "Приложение запущено"; BOOST_LOG_TRIVIAL(info) << "Приложение запущено2";
std::vector<std::thread> v; std::vector<std::thread> v;
v.reserve(threads - 1); v.reserve(threads - 1);
@@ -6,22 +6,113 @@
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <string>
#include "./../../src/endpoints_handlers/AuthRegistrationExecutor.h" #include "./../../src/endpoints_handlers/AuthRegistrationExecutor.h"
#include "./../../src/DAO/MySQLUserDAO.h" #include "./../../src/DAO/MySQLUserDAO.h"
#include "./../../src/db/mysql_connector.h" #include "./../../src/db/mysql_connector.h"
#include "./../../src/exceptions/session_exception.h"
#include "./../../src/helpers/helpers.h"
using namespace std; using namespace std;
using namespace uad; using namespace uad;
using namespace boost; using namespace boost;
using namespace beast;
using namespace json;
using RouteAuthRegistrationExecutor = AuthRegistrationExecutor<beast::http::string_body, using RouteAuthRegistrationExecutor = AuthRegistrationExecutor<beast::http::string_body,
std::allocator<char>, std::allocator<char>,
beast::http::string_body>; beast::http::string_body>;
using Request = boost::beast::http::request<beast::http::string_body,
beast::http::basic_fields<std::allocator<char>>>;
BOOST_AUTO_TEST_CASE(AuthRegistrationExecutor_Succesful_Login) static const std::string kCreatedUserUUID = GenerateUUID();
BOOST_AUTO_TEST_CASE(AuthRegistrationExecutor_Failed_Parse_Payload)
{ {
auto user_dao = make_shared<MySQLUserDAO>(GetMySqlSession()); auto& argv = boost::unit_test::framework::master_test_suite().argv;
auto executor = make_shared<RouteAuthRegistrationExecutor>(GetMySqlSession(), user_dao);
BOOST_CHECK(true == true); const std::string mysql_credentials = argv[1];
mysqlx::Session* mysql_session = new mysqlx::Session(mysql_credentials);
uad::SetMySqlSession(mysql_session);
auto user_dao = make_shared<MySQLUserDAO>(GetMySqlSession());
auto executor = RouteAuthRegistrationExecutor(GetMySqlSession(), user_dao);
Request req;
req.body() = "{ \"login\": ABS3 }"s;
BOOST_CHECK_EXCEPTION(executor(std::move(req)), session_exception, [](const session_exception& e) -> bool
{
return e.code == beast::http::status::internal_server_error;
});
mysql_session->close();
delete mysql_session;
}
BOOST_AUTO_TEST_CASE(AuthRegistrationExecutor_Invalid_Login_Data)
{
auto& argv = boost::unit_test::framework::master_test_suite().argv;
const std::string mysql_credentials = argv[1];
mysqlx::Session* mysql_session = new mysqlx::Session(mysql_credentials);
uad::SetMySqlSession(mysql_session);
auto user_dao = make_shared<MySQLUserDAO>(GetMySqlSession());
auto executor = RouteAuthRegistrationExecutor(GetMySqlSession(), user_dao);
Request req;
value req_body;
req_body.emplace_object();
req_body.as_object().emplace("login"s, "wq");
req_body.as_object().emplace("password"s, "Qw");
req.body() = serialize(req_body);
BOOST_CHECK_EXCEPTION(executor(std::move(req)), session_exception, [](const session_exception& e) -> bool
{
return e.code == beast::http::status::unprocessable_entity;
});
mysql_session->close();
delete mysql_session;
}
BOOST_AUTO_TEST_CASE(AuthRegistrationExecutor_Succesfull_User_Login)
{
auto& argv = boost::unit_test::framework::master_test_suite().argv;
const std::string mysql_credentials = argv[1];
mysqlx::Session* mysql_session = new mysqlx::Session(mysql_credentials);
uad::SetMySqlSession(mysql_session);
auto user_dao = make_shared<MySQLUserDAO>(GetMySqlSession());
auto executor = RouteAuthRegistrationExecutor(GetMySqlSession(), user_dao);
Request req;
value req_body;
req_body.emplace_object();
req_body.as_object().emplace("login"s, "MyLogin12345678"s);
req_body.as_object().emplace("password"s, "Qwerty123456"s);
req.body() = serialize(req_body);
auto response = executor(std::move(req));
BOOST_CHECK_EQUAL(response.result(), http::status::created);
mysql_session->close();
delete mysql_session;
} }