Skip to content
Merged
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
88 changes: 51 additions & 37 deletions src/controllers/app-controller.cpp
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
#include "app-controller.h"
#include "services/to-dos.service.h"
#include "data/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 AppController::createInternalServerErrorResponse(const std::string& error) const
{
Json::Value jsonResponse;
jsonResponse["status"] = "Error";
jsonResponse["message"] = "Internal server error";
jsonResponse["error"] = error;

auto resp = HttpResponse::newHttpJsonResponse(jsonResponse);
resp->setStatusCode(k500InternalServerError);
return resp;
}

void AppController::getToDos(const HttpRequestPtr& req,
std::function<void(const HttpResponsePtr&)>&& callback) {
Json::Value jsonResponse;
AppController::AppController()
{
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_);
}

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

auto resp = HttpResponse::newHttpJsonResponse(toDos.toJson());
try
{
auto resp = HttpResponse::newHttpJsonResponse(todo_service_->getToDos());
resp->setStatusCode(k200OK);
callback(resp);

} catch (const std::exception& e) {
}
catch (const std::exception& e)
{
callback(createInternalServerErrorResponse(e.what()));
}
}

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

try {
try
{
auto json = req->getJsonObject();

if (!json || !json->isMember("description")) {
if (!json || !json->isMember("name"))
{
Json::Value result;
result["status"] = "error";
result["message"] = "Invalid JSON";
Expand All @@ -49,26 +59,28 @@ void AppController::addToDo(const HttpRequestPtr& req,
return;
}

ToDoService toDos;
toDos.addToDo(json->get("description", "").asString());
todo_service_->addToDo(json->get("name", "").asString());

auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k201Created);
callback(resp);

} catch (const std::exception& e) {
}
catch (const std::exception& e)
{
callback(createInternalServerErrorResponse(e.what()));
}
}

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

try {
try
{
auto json = req->getJsonObject();

if (!json || !json->isMember("toDosIds")) {
if (!json || !json->isMember("toDosIds"))
{
Json::Value result;
result["status"] = "error";
result["message"] = "Invalid JSON";
Expand All @@ -80,38 +92,40 @@ void AppController::completeToDos(const HttpRequestPtr& req,
return;
}

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

for (const auto& id : toDosIds) {
toDos.completeToDo(id.asInt());
for (const auto& id : toDosIds)
{
todo_service_->completeToDo(id.asInt());
}

auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k200OK);
callback(resp);

} catch (const std::exception& e) {
}
catch (const std::exception& e)
{
callback(createInternalServerErrorResponse(e.what()));
}
}

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

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

ToDoService toDos;
toDos.completeToDo(toDoId);

todo_service_->deleteToDo(toDoId);

auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k200OK);
callback(resp);

} catch (const std::exception& e) {
}
catch (const std::exception& e)
{
callback(createInternalServerErrorResponse(e.what()));
}
}
41 changes: 25 additions & 16 deletions src/controllers/app-controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,37 @@

#include <drogon/HttpController.h>

#include "data/commands/todo-commands.h"
#include "data/queries/todo-queries.h"
#include "services/to-dos.service.h"

using namespace drogon;

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

METHOD_LIST_BEGIN
ADD_METHOD_TO(AppController::getToDos, "/to-dos", Get); // Getting a list of tasks
ADD_METHOD_TO(AppController::addToDo, "/to-dos", Post); // Adding a new task
ADD_METHOD_TO(AppController::completeToDos, "/to-dos/complete", Post); // Executing (deleting) a task list
ADD_METHOD_TO(AppController::deleteToDo, "/to-dos", Delete); // Deleting a specific task
ADD_METHOD_TO(AppController::getToDos, "/to-dos", Get); // Getting a list of tasks
ADD_METHOD_TO(AppController::addToDo, "/to-dos", Post); // Adding a new task
ADD_METHOD_TO(AppController::completeToDos, "/to-dos/complete", Post); // Executing (deleting) a task list
ADD_METHOD_TO(AppController::deleteToDo, "/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);
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<ToDoQueries> queries_;
std::unique_ptr<ToDoCommands> commands_;
std::unique_ptr<ToDoService> todo_service_;
};
5 changes: 3 additions & 2 deletions src/data/commands/todo-commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
class ToDoCommands
{
public:
ToDoCommands
(odb::database& db) : db_(db) {}
ToDoCommands(odb::database& db)
: db_(db)
{}

uint64_t create_todo(const std::string& name, std::time_t createdAtUtc);
uint64_t delete_todo(int id);
Expand Down
30 changes: 30 additions & 0 deletions src/data/db_connection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "db_connection.h"

#include <cstdlib>
#include <stdexcept>

#include <odb/pgsql/database.hxx>

std::shared_ptr<odb::database> DbConnection::instance_ = nullptr;

std::shared_ptr<odb::database> DbConnection::get()
{
static std::once_flag flag;
std::call_once(
flag,
[]()
{
const std::string user = std::getenv("POSTGRES_USER");
const std::string password = std::getenv("POSTGRES_PASSWORD");
const std::string db_name = std::getenv("POSTGRES_DB");
const std::string host = std::getenv("POSTGRES_HOST");
const std::string port = std::getenv("POSTGRES_PORT");

std::string conninfo = "host=" + host + " port=" + port + " dbname=" + db_name + " user=" + user + " password=" + password;

instance_ = std::shared_ptr<odb::database>(new odb::pgsql::database(conninfo));
}
);

return instance_;
}
14 changes: 14 additions & 0 deletions src/data/db_connection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <memory>
#include <odb/database.hxx>

class DbConnection
{
public:
static std::shared_ptr<odb::database> get();

private:
DbConnection() = default;
static std::shared_ptr<odb::database> instance_;
};
52 changes: 0 additions & 52 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,6 @@

int main()
{
try
{
// TODO(https://github.com/TourmalineCore/to-dos-api-cpp/issues/27): add migration update on startup

const std::string user = std::getenv("POSTGRES_USER");
const std::string password = std::getenv("POSTGRES_PASSWORD");
const std::string db_name = std::getenv("POSTGRES_DB");
const std::string host = std::getenv("POSTGRES_HOST");
const std::string port = std::getenv("POSTGRES_PORT");

std::string conninfo = "host=" + host + " port=" + port + " dbname=" + db_name + " user=" + user + " password=" + password;

std::unique_ptr<odb::database> db(new odb::pgsql::database(conninfo));

ToDoQueries todo_queries(*db);
ToDoCommands todo_commands(*db);
const std::time_t now_utc = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
uint64_t added_todo = todo_commands.create_todo("random_todo", now_utc);
std::cout << "Added TODO:" << added_todo << std::endl;
uint64_t soft_removed_todo = todo_commands.soft_delete_todo(added_todo);
std::cout << "Soft Removed TODO:" << soft_removed_todo << std::endl;
uint64_t removed_todo = todo_commands.delete_todo(added_todo);
std::cout << "Removed TODO:" << removed_todo << std::endl;

std::shared_ptr<std::vector<ToDo>> todos = todo_queries.get_all_todos();
std::shared_ptr<ToDo> todo = todo_queries.get_todo_by_id(1);


if (todos && todo)
{
std::cout << "Found TODOs:" << todos->size() << std::endl;
const std::time_t t = todo->createdAtUtc();
std::tm tm {};
gmtime_r(&t, &tm);
std::cout << "Found TODO id:" << todo->id() << " createdAtUtc: " << std::put_time(&tm, "%Y-%m-%d %H:%M:%S UTC") << std::endl;
}
else
{
std::cout << "TODO or TODOs not founded" << std::endl;
}
}
catch (const odb::exception& e)
{
std::cerr << "Error ODB: " << e.what() << std::endl;
return 1;
}
catch (const std::exception& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}

drogon::app().addListener("127.0.0.1", 8080);
drogon::app().run();

Expand Down
5 changes: 3 additions & 2 deletions src/services/dtos/to-dos-dto.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include "to-dos-dto.h"

Json::Value ToDoDTO::toJson() const {
Json::Value ToDoDTO::toJson() const
{
Json::Value json;
json["id"] = id;
json["description"] = description;
json["name"] = name;

return json;
}
8 changes: 4 additions & 4 deletions src/services/dtos/to-dos-dto.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#pragma once

#include <string>
#include <json/json.h>
#include <string>

struct ToDoDTO
{
int id;
std::string description;
int id;
std::string name;

Json::Value toJson() const;
Json::Value toJson() const;
};
Loading