From 7c4adaf45043212adb96f25170c7fd228c5bf9ac Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 17 Apr 2024 18:37:15 -0300 Subject: [PATCH] update delete and list transaction requests --- database/interface.h | 2 +- database/mysql/mysql.cpp | 10 ++++- database/mysql/mysql.h | 2 +- handler/CMakeLists.txt | 6 +++ handler/deletetransaction.cpp | 59 ++++++++++++++++++++++++ handler/deletetransaction.h | 21 +++++++++ handler/transactions.cpp | 51 +++++++++++++++++++++ handler/transactions.h | 20 +++++++++ handler/updatetransaction.cpp | 84 +++++++++++++++++++++++++++++++++++ handler/updatetransaction.h | 20 +++++++++ server/server.cpp | 6 +++ 11 files changed, 277 insertions(+), 4 deletions(-) create mode 100644 handler/deletetransaction.cpp create mode 100644 handler/deletetransaction.h create mode 100644 handler/transactions.cpp create mode 100644 handler/transactions.h create mode 100644 handler/updatetransaction.cpp create mode 100644 handler/updatetransaction.h diff --git a/database/interface.h b/database/interface.h index 1f1aee2..a0c2821 100644 --- a/database/interface.h +++ b/database/interface.h @@ -59,7 +59,7 @@ public: virtual DB::Transaction addTransaction(const DB::Transaction& transaction) = 0; virtual std::vector listTransactions(uint32_t owner) = 0; virtual void updateTransaction(const DB::Transaction& transaction) = 0; - virtual void deleteTransaction(uint32_t id) = 0; + virtual bool deleteTransaction(uint32_t id, uint32_t actorId) = 0; protected: Interface(Type type); diff --git a/database/mysql/mysql.cpp b/database/mysql/mysql.cpp index 4707352..ab8b004 100644 --- a/database/mysql/mysql.cpp +++ b/database/mysql/mysql.cpp @@ -39,7 +39,7 @@ constexpr const char* updateTransactionQuery = "UPDATE transactions SET" " `initiator` = ?, `type` = 1, `asset` = ?," " `parent` = ?, `value` = ?, `performed` = ?" " WHERE `id` = ?"; -constexpr const char* deleteTransactionQuery = "DELETE FROM transactions where `id` = ? OR `parent` = ?"; +constexpr const char* deleteTransactionQuery = "DELETE FROM transactions where (`id` = ? OR `parent` = ?) AND `initiator` = ?"; constexpr const char* selectAllTransactions = "WITH RECURSIVE AllTransactions AS (" " SELECT t.id, t.initiator, t.asset, t.parent, t.value, t.modified, t.performed t.notes FROM transactions t" " JOIN assets a ON t.asset = a.id" @@ -475,13 +475,19 @@ void DB::MySQL::updateTransaction(const DB::Transaction& transaction) { upd.execute(); } -void DB::MySQL::deleteTransaction(uint32_t id) { +bool DB::MySQL::deleteTransaction(uint32_t id, uint32_t actorId) { MYSQL* con = &connection; Statement del(con, deleteTransactionQuery); del.bind(&id, MYSQL_TYPE_LONG, true); //for actual transactions del.bind(&id, MYSQL_TYPE_LONG, true); //for potential children + del.bind(&actorId, MYSQL_TYPE_LONG, true); //for preventing unauthorized removal, but it needs to be improved del.execute(); //need to think of a parent with no children transactions... + + if (del.affectedRows() == 0) + return false; + + return true; } std::vector DB::MySQL::listTransactions(uint32_t owner) { diff --git a/database/mysql/mysql.h b/database/mysql/mysql.h index d7962df..a739fa6 100644 --- a/database/mysql/mysql.h +++ b/database/mysql/mysql.h @@ -46,7 +46,7 @@ public: DB::Transaction addTransaction(const DB::Transaction& transaction) override; std::vector listTransactions(uint32_t owner) override; void updateTransaction(const DB::Transaction& transaction) override; - void deleteTransaction(uint32_t id) override; + bool deleteTransaction(uint32_t id, uint32_t actorId) override; private: void executeFile (const std::filesystem::path& relativePath); diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 91bd69f..1971c0e 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -14,6 +14,9 @@ set(HEADERS updateasset.h currencies.h addtransaction.h + transactions.h + deletetransaction.h + updatetransaction.h ) set(SOURCES @@ -29,6 +32,9 @@ set(SOURCES updateasset.cpp currencies.cpp addtransaction.cpp + transactions.cpp + deletetransaction.cpp + updatetransaction.cpp ) target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) diff --git a/handler/deletetransaction.cpp b/handler/deletetransaction.cpp new file mode 100644 index 0000000..6d73529 --- /dev/null +++ b/handler/deletetransaction.cpp @@ -0,0 +1,59 @@ +//SPDX-FileCopyrightText: 2024 Yury Gubich +//SPDX-License-Identifier: GPL-3.0-or-later + +#include "deletetransaction.h" + +#include "server/server.h" +#include "server/session.h" +#include "database/exceptions.h" + +Handler::DeleteTransaction::DeleteTransaction (const std::shared_ptr& server): + Handler("deleteTransaction", Request::Method::post), + server(server) +{} + +void Handler::DeleteTransaction::handle (Request& request) { + std::string access = request.getAuthorizationToken(); + if (access.empty()) + return error(request, Response::Status::unauthorized); + + if (access.size() != 32) + return error(request, Response::Status::badRequest); + + std::shared_ptr srv = server.lock(); + if (!srv) + return error(request, Response::Status::internalError); + + std::map form = request.getForm(); + std::map::const_iterator itr = form.find("id"); + if (itr == form.end()) + return error(request, Response::Status::badRequest); + + unsigned int txnId; + try { + txnId = std::stoul(itr->second); + } catch (const std::exception& e) { + return error(request, Response::Status::badRequest); + } + + try { + Session& session = srv->getSession(access); + bool success = srv->getDatabase()->deleteTransaction(txnId, session.owner); + if (!success) + return error(request, Response::Status::forbidden); + + Response& res = request.createResponse(Response::Status::ok); + res.send(); + + session.transactionRemoved(txnId); + + } catch (const DB::NoSession& e) { + return error(request, Response::Status::unauthorized); + } catch (const std::exception& e) { + std::cerr << "Exception on " << path << ":\n\t" << e.what() << std::endl; + return error(request, Response::Status::internalError); + } catch (...) { + std::cerr << "Unknown exception on " << path << std::endl; + return error(request, Response::Status::internalError); + } +} diff --git a/handler/deletetransaction.h b/handler/deletetransaction.h new file mode 100644 index 0000000..b1b6ab3 --- /dev/null +++ b/handler/deletetransaction.h @@ -0,0 +1,21 @@ +//SPDX-FileCopyrightText: 2024 Yury Gubich +//SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "handler.h" + +class Server; +namespace Handler { +class DeleteTransaction : public Handler { +public: + DeleteTransaction (const std::shared_ptr& server); + + virtual void handle (Request& request) override; + +private: + std::weak_ptr server; +}; +} diff --git a/handler/transactions.cpp b/handler/transactions.cpp new file mode 100644 index 0000000..c7d574a --- /dev/null +++ b/handler/transactions.cpp @@ -0,0 +1,51 @@ +//SPDX-FileCopyrightText: 2024 Yury Gubich +//SPDX-License-Identifier: GPL-3.0-or-later + +#include "transactions.h" + +#include "server/server.h" +#include "server/session.h" +#include "database/exceptions.h" + +Handler::Transactions::Transactions (const std::shared_ptr& server): + Handler("transactions", Request::Method::get), + server(server) +{} + +void Handler::Transactions::handle (Request& request) { + std::string access = request.getAuthorizationToken(); + if (access.empty()) + return error(request, Response::Status::unauthorized); + + if (access.size() != 32) + return error(request, Response::Status::badRequest); + + std::shared_ptr srv = server.lock(); + if (!srv) + return error(request, Response::Status::internalError); + + try { + Session& session = srv->getSession(access); + std::vector transactions = srv->getDatabase()->listTransactions(session.owner); + + nlohmann::json arr = nlohmann::json::array(); + for (const DB::Transaction& transaction : transactions) + arr.push_back(transaction.toJSON()); + + nlohmann::json body = nlohmann::json::object(); + body["transactions"] = arr; + + Response& res = request.createResponse(Response::Status::ok); + res.setBody(body); + res.send(); + + } catch (const DB::NoSession& e) { + return error(request, Response::Status::unauthorized); + } catch (const std::exception& e) { + std::cerr << "Exception on " << path << ":\n\t" << e.what() << std::endl; + return error(request, Response::Status::internalError); + } catch (...) { + std::cerr << "Unknown exception on " << path << std::endl; + return error(request, Response::Status::internalError); + } +} diff --git a/handler/transactions.h b/handler/transactions.h new file mode 100644 index 0000000..21c016f --- /dev/null +++ b/handler/transactions.h @@ -0,0 +1,20 @@ +//SPDX-FileCopyrightText: 2024 Yury Gubich +//SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "handler.h" + +class Server; +namespace Handler { +class Transactions : public Handler::Handler { +public: + Transactions (const std::shared_ptr& server); + void handle (Request& request) override; + +private: + std::weak_ptr server; +}; +} diff --git a/handler/updatetransaction.cpp b/handler/updatetransaction.cpp new file mode 100644 index 0000000..f27ef7e --- /dev/null +++ b/handler/updatetransaction.cpp @@ -0,0 +1,84 @@ +//SPDX-FileCopyrightText: 2024 Yury Gubich +//SPDX-License-Identifier: GPL-3.0-or-later + +#include "updatetransaction.h" + +#include + +#include "server/server.h" +#include "server/session.h" +#include "database/exceptions.h" + +Handler::UpdateTransaction::UpdateTransaction (const std::shared_ptr& server): + Handler("updateTransaction", Request::Method::post), + server(server) +{} + +void Handler::UpdateTransaction::handle (Request& request) { + std::string access = request.getAuthorizationToken(); + if (access.empty()) + return error(request, Response::Status::unauthorized); + + if (access.size() != 32) + return error(request, Response::Status::badRequest); + + std::shared_ptr srv = server.lock(); + if (!srv) + return error(request, Response::Status::internalError); + + std::map form = request.getForm(); + std::map::const_iterator itr = form.find("id"); + if (itr == form.end()) + return error(request, Response::Status::badRequest); + + DB::Transaction txn; + txn.id = std::stoul(itr->second); + + itr = form.find("asset"); + if (itr == form.end()) + return error(request, Response::Status::badRequest); + + txn.asset = std::stoul(itr->second); + //TODO validate the asset + + itr = form.find("value"); + if (itr == form.end()) + return error(request, Response::Status::badRequest); + + txn.value = std::stod(itr->second); + + itr = form.find("performed"); + if (itr == form.end()) + return error(request, Response::Status::badRequest); + + txn.performed = std::stoul(itr->second); + + itr = form.find("notes"); + if (itr != form.end()) + txn.notes = itr->second; + + itr = form.find("parent"); + if (itr != form.end()) + txn.parent = std::stoul(itr->second); + + try { + Session& session = srv->getSession(access); + + txn.initiator = session.owner; + srv->getDatabase()->updateTransaction(txn); + + Response& res = request.createResponse(Response::Status::ok); + res.send(); + + session.transactionChanged(txn); + + } catch (const DB::NoSession& e) { + return error(request, Response::Status::unauthorized); + } catch (const std::exception& e) { + std::cerr << "Exception on " << path << ":\n\t" << e.what() << std::endl; + return error(request, Response::Status::internalError); + } catch (...) { + std::cerr << "Unknown exception on " << path << std::endl; + return error(request, Response::Status::internalError); + } +} diff --git a/handler/updatetransaction.h b/handler/updatetransaction.h new file mode 100644 index 0000000..3fc68dd --- /dev/null +++ b/handler/updatetransaction.h @@ -0,0 +1,20 @@ +//SPDX-FileCopyrightText: 2024 Yury Gubich +//SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "handler.h" + +class Server; +namespace Handler { +class UpdateTransaction : public Handler { +public: + UpdateTransaction (const std::shared_ptr& server); + virtual void handle (Request& request) override; + +private: + std::weak_ptr server; +}; +} diff --git a/server/server.cpp b/server/server.cpp index cfbe9ef..bb5191a 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -18,6 +18,9 @@ #include "handler/currencies.h" #include "handler/updateasset.h" #include "handler/addtransaction.h" +#include "handler/transactions.h" +#include "handler/deletetransaction.h" +#include "handler/updatetransaction.h" #include "taskmanager/route.h" @@ -81,6 +84,9 @@ void Server::run (int socketDescriptor) { router->addRoute(std::make_unique(srv)); router->addRoute(std::make_unique(srv)); router->addRoute(std::make_unique(srv)); + router->addRoute(std::make_unique(srv)); + router->addRoute(std::make_unique(srv)); + router->addRoute(std::make_unique(srv)); taskManager->start(); scheduler->start();