Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 17 additions & 41 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,54 +1,30 @@
cmake_minimum_required(VERSION 3.15)
set(PROJECT_NAME "to-dos-api")
project(${PROJECT_NAME} CXX)

file(GLOB_RECURSE sources CONFIGURE_DEPENDS
${CMAKE_SOURCE_DIR}/src/*/*.cpp
${CMAKE_SOURCE_DIR}/src/data/models/odb-gen/*.cxx
${CMAKE_SOURCE_DIR}/src/utils/**/*.cpp
)

set(PROJECT_OBJECTS ${PROJECT_NAME}_lib)

add_library(${PROJECT_OBJECTS} OBJECT ${sources})

file(GLOB_RECURSE database_models
${CMAKE_CURRENT_SOURCE_DIR}/src/data/models/*.h
${CMAKE_CURRENT_SOURCE_DIR}/src/data/models/*.hxx
)

set(database_model_dirs "")
foreach(header ${database_models})
get_filename_component(dir ${header} DIRECTORY)
list(APPEND database_model_dirs ${dir})
endforeach()
list(REMOVE_DUPLICATES database_model_dirs)

target_include_directories(${PROJECT_OBJECTS} PUBLIC
${CMAKE_SOURCE_DIR}/src
/usr/include
${database_model_dirs}
)
project(to-dos-api CXX)

find_package(Drogon REQUIRED)
find_package(jsoncpp REQUIRED)
find_package(libodb REQUIRED)
find_package(libodb-pgsql REQUIRED)

target_link_libraries(${PROJECT_OBJECTS} PUBLIC
Drogon::Drogon
JsonCpp::JsonCpp
libodb::libodb
libodb-pgsql::libodb-pgsql
set(API_LIB api)
set(APPLICATION_LIB application)
set(CORE_LIB core)

add_subdirectory(src/core)
add_subdirectory(src/application)
add_subdirectory(src/api)

add_executable(${PROJECT_NAME}
src/main.cpp
src/utils/app-config/app-config.cpp
)

add_executable(${PROJECT_NAME}
${CMAKE_SOURCE_DIR}/src/main.cpp
$<TARGET_OBJECTS:${PROJECT_OBJECTS}>
target_include_directories(${PROJECT_NAME} PRIVATE
src/utils
)

target_link_libraries(${PROJECT_NAME} PUBLIC
${PROJECT_OBJECTS}
target_link_libraries(${PROJECT_NAME}
PRIVATE -Wl,--whole-archive ${API_LIB} -Wl,--no-whole-archive
)

# Tests
Expand All @@ -58,4 +34,4 @@ else()
message(STATUS "UNIT TEST ENABLED")
enable_testing()
add_subdirectory(test)
endif()
endif()
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
14 changes: 14 additions & 0 deletions src/api/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
file(GLOB_RECURSE api_sources
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)

add_library(${API_LIB} STATIC ${api_sources})

target_include_directories(${API_LIB} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)

target_link_libraries(${API_LIB}
PUBLIC ${APPLICATION_LIB}
Drogon::Drogon
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "app-controller.h"
#include "data/db_connection.h"
#include "todos-controller.h"
#include "db_connection.h"

// TODO(https://github.com/TourmalineCore/to-dos-api-cpp/issues/25): Create http exception handler or generic class for handling that type of errors
HttpResponsePtr AppController::createInternalServerErrorResponse(const std::string& error) const
HttpResponsePtr ToDosController::createInternalServerErrorResponse(const std::string& error) const
{
Json::Value jsonResponse;
jsonResponse["status"] = "Error";
Expand All @@ -14,21 +14,37 @@ HttpResponsePtr AppController::createInternalServerErrorResponse(const std::stri
return resp;
}

AppController::AppController()
ToDosController::ToDosController()
{
db_ = std::move(DbConnection::get());
queries_ = std::make_unique<ToDoQueries>(*db_);
commands_ = std::make_unique<ToDoCommands>(*db_);
todo_service_ = std::make_unique<ToDoService>(*queries_, *commands_);

createToDoCommand_ = std::make_unique<CreateToDoCommand>(*db_);
getAllToDosQuery_ = std::make_unique<GetAllToDosQuery>(*db_);
getToDoByIdQuery_ = std::make_unique<GetToDoById>(*db_);
hardDeleteToDoCommand_ = std::make_unique<HardDeleteToDoCommand>(*db_);
softDeleteCommand_ = std::make_unique<SoftDeleteCommand>(*db_);

createToDoHandler_ = std::make_unique<CreateToDoHandler>(*createToDoCommand_);
getAllToDosHandler_ = std::make_unique<GetAllToDosHandler>(*getAllToDosQuery_);
getToDoByIdHandler_ = std::make_unique<GetToDoByIdHandler>(*getToDoByIdQuery_);
hardDeleteToDoHandler_ = std::make_unique<HardDeleteToDoHandler>(*hardDeleteToDoCommand_);
softDeleteToDoHandler_ = std::make_unique<SoftDeleteToDoHandler>(*softDeleteCommand_);
}

void AppController::getToDos(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
void ToDosController::getToDos(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
{
Json::Value jsonResponse;

try
{
auto resp = HttpResponse::newHttpJsonResponse(todo_service_->getToDos());
auto result = getAllToDosHandler_->handle();

Json::Value toDosArray(Json::arrayValue);
for (const auto& dto : result.todos)
toDosArray.append(dto.toJson());

Json::Value json;
json["toDos"] = toDosArray;

auto resp = HttpResponse::newHttpJsonResponse(json);
resp->setStatusCode(k200OK);
callback(resp);
}
Expand All @@ -38,10 +54,8 @@ void AppController::getToDos(const HttpRequestPtr& req, std::function<void(const
}
}

void AppController::addToDo(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
void ToDosController::addToDo(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
{
Json::Value jsonResponse;

try
{
auto json = req->getJsonObject();
Expand All @@ -55,11 +69,11 @@ void AppController::addToDo(const HttpRequestPtr& req, std::function<void(const
auto resp = HttpResponse::newHttpJsonResponse(result);
resp->setStatusCode(k400BadRequest);
callback(resp);

return;
}

todo_service_->addToDo(json->get("name", "").asString());
CreateToDoRequest request { json->get("name", "").asString() };
(void) createToDoHandler_->handle(request);

auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k201Created);
Expand All @@ -71,10 +85,8 @@ void AppController::addToDo(const HttpRequestPtr& req, std::function<void(const
}
}

void AppController::completeToDos(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
void ToDosController::completeToDos(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
{
Json::Value jsonResponse;

try
{
auto json = req->getJsonObject();
Expand All @@ -88,15 +100,14 @@ void AppController::completeToDos(const HttpRequestPtr& req, std::function<void(
auto resp = HttpResponse::newHttpJsonResponse(result);
resp->setStatusCode(k400BadRequest);
callback(resp);

return;
}

auto toDosIds = json->get("toDoIds", Json::Value(Json::arrayValue));

for (const auto& id : toDosIds)
{
todo_service_->completeToDo(id.asInt());
// TODO(https://github.com/TourmalineCore/to-dos-api-cpp/issues/38): add here a check for not found todos
(void) softDeleteToDoHandler_->handle(static_cast<uint64_t>(id.asInt()));
}

auto resp = HttpResponse::newHttpResponse();
Expand All @@ -109,16 +120,15 @@ void AppController::completeToDos(const HttpRequestPtr& req, std::function<void(
}
}

void AppController::deleteToDo(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
void ToDosController::deleteToDo(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
{
Json::Value jsonResponse;

try
{
auto toDoIdStr = req->getParameter("toDoId");
int toDoId = std::stoi(toDoIdStr);
const uint64_t toDoId = static_cast<uint64_t>(std::stoi(toDoIdStr));

todo_service_->deleteToDo(toDoId);
// TODO(https://github.com/TourmalineCore/to-dos-api-cpp/issues/38): add here a check for not found todo
(void) hardDeleteToDoHandler_->handle(toDoId);

auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k200OK);
Expand All @@ -128,4 +138,4 @@ void AppController::deleteToDo(const HttpRequestPtr& req, std::function<void(con
{
callback(createInternalServerErrorResponse(e.what()));
}
}
}
49 changes: 49 additions & 0 deletions src/api/features/todos/todos-controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include <drogon/HttpController.h>

#include "features/create-to-do/create-to-do-handler.h"
#include "features/get-all-to-dos/get-all-to-dos-handler.h"
#include "features/get-to-do-by-id/get-to-do-by-id-handler.h"
#include "features/hard-delete-to-do/hard-delete-to-do-handler.h"
#include "features/soft-delete-to-do/soft-delete-to-do-handler.h"

using namespace drogon;

class ToDosController : public drogon::HttpController<ToDosController>
{
public:
explicit ToDosController();

METHOD_LIST_BEGIN
ADD_METHOD_TO(ToDosController::getToDos, "/api/to-dos", Get); // Getting a list of tasks
ADD_METHOD_TO(ToDosController::addToDo, "/api/to-dos", Post); // Adding a new task
ADD_METHOD_TO(ToDosController::completeToDos, "/api/to-dos/complete", Post); // Executing (deleting) a task list
ADD_METHOD_TO(ToDosController::deleteToDo, "/api/to-dos", Delete); // Deleting a specific task
METHOD_LIST_END

HttpResponsePtr createInternalServerErrorResponse(const std::string& error) const;

void getToDos(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback);

void addToDo(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback);

void completeToDos(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback);

void deleteToDo(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback);

private:
std::shared_ptr<odb::database> db_;

std::unique_ptr<CreateToDoCommand> createToDoCommand_;
std::unique_ptr<GetAllToDosQuery> getAllToDosQuery_;
std::unique_ptr<GetToDoById> getToDoByIdQuery_;
std::unique_ptr<HardDeleteToDoCommand> hardDeleteToDoCommand_;
std::unique_ptr<SoftDeleteCommand> softDeleteCommand_;

std::unique_ptr<CreateToDoHandler> createToDoHandler_;
std::unique_ptr<GetAllToDosHandler> getAllToDosHandler_;
std::unique_ptr<GetToDoByIdHandler> getToDoByIdHandler_;
std::unique_ptr<HardDeleteToDoHandler> hardDeleteToDoHandler_;
std::unique_ptr<SoftDeleteToDoHandler> softDeleteToDoHandler_;
};
19 changes: 19 additions & 0 deletions src/application/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
file(GLOB_RECURSE application_sources
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/odb-gen/*.cxx
)

add_library(${APPLICATION_LIB} STATIC ${application_sources})

target_include_directories(${APPLICATION_LIB} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/odb-gen
)

target_link_libraries(${APPLICATION_LIB}
PUBLIC ${CORE_LIB}
JsonCpp::JsonCpp
PRIVATE libodb::libodb
libodb-pgsql::libodb-pgsql
Drogon::Drogon
)
File renamed without changes.
File renamed without changes.
14 changes: 14 additions & 0 deletions src/application/features/create-to-do/create-to-do-command.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "create-to-do-command.h"
#include "odb-gen/to-do-odb.hxx"
#include <odb/transaction.hxx>

uint64_t CreateToDoCommand::execute(const std::string& name, std::time_t createdAtUtc)
{
ToDo todo(name, createdAtUtc);

odb::transaction t(db_.begin());
db_.persist(todo);
t.commit();

return todo.id();
}
18 changes: 18 additions & 0 deletions src/application/features/create-to-do/create-to-do-command.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "to-do.h"
#include <memory>
#include <odb/database.hxx>

class CreateToDoCommand
{
public:
CreateToDoCommand(odb::database& db)
: db_(db)
{}

uint64_t execute(const std::string& name, std::time_t createdAtUtc);

private:
odb::database& db_;
};
13 changes: 13 additions & 0 deletions src/application/features/create-to-do/create-to-do-handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "create-to-do-handler.h"
#include <chrono>
#include <ctime>

using std::string;

CreateToDoResponse CreateToDoHandler::handle(const CreateToDoRequest& request)
{
const std::time_t now_utc = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

const uint64_t id = _createToDoCommand.execute(request.name, now_utc);
return { id };
}
17 changes: 17 additions & 0 deletions src/application/features/create-to-do/create-to-do-handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once
#include "create-to-do-command.h"
#include "create-to-do-request.h"
#include "create-to-do-response.h"

class CreateToDoHandler
{
private:
CreateToDoCommand& _createToDoCommand;

public:
explicit CreateToDoHandler(CreateToDoCommand& createToDoCommand)
: _createToDoCommand(createToDoCommand)
{}

CreateToDoResponse handle(const CreateToDoRequest& request);
};
7 changes: 7 additions & 0 deletions src/application/features/create-to-do/create-to-do-request.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once
#include <string>

struct CreateToDoRequest
{
std::string name;
};
7 changes: 7 additions & 0 deletions src/application/features/create-to-do/create-to-do-response.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once
#include <cstdint>

struct CreateToDoResponse
{
uint64_t id;
};
Comment on lines +1 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems uint64_t is used from stdint.h, not cstdint. I suggest using std::uint64_t.

Loading
Loading