From 0f322e75840ff5f8f65dad6b758d72d7ddb26d84 Mon Sep 17 00:00:00 2001 From: Julian Sehne Date: Sat, 6 Nov 2021 11:03:25 +0100 Subject: [PATCH 1/4] Post Colum settings update --- .vscode/settings.json | 73 ++++++------ .../src/Api/Parser/JsonParser.cpp | 107 +++++++++++++++++- .../src/Api/Parser/JsonParser.hpp | 8 ++ .../src/Repository/SQLite/BoardRepository.cpp | 41 ++++++- 4 files changed, 191 insertions(+), 38 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b5b4b57..d9d7794 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,33 +1,42 @@ { - "editor.formatOnSave": true, - "editor.tabSize": 4, - "editor.codeActionsOnSave": { - "source.organizeImports": true, - "source.fixAll": true - }, - "terminal.integrated.env.linux": { - "PATH": "${env:PATH}:${workspaceFolder}/kanban-board-service/node_modules/.bin" - }, - "terminal.integrated.env.osx": { - "PATH": "${env:PATH}:${workspaceFolder}/kanban-board-service/node_modules/.bin" - }, - "terminal.integrated.env.windows": { - "PATH": "${env:PATH};${workspaceFolder}\\kanban-board-service\\node_modules\\.bin" - }, - "git.inputValidationLength": 100, - "git.inputValidationSubjectLength": 100, - "cmake.sourceDirectory": "${workspaceFolder}/kanban-board-service", - "cmake.buildDirectory": "${workspaceFolder}/kanban-board-service/build", - "cmake.debugConfig": { - "cwd": "${workspaceFolder}/kanban-board-service/build" - }, - "C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: LLVM, IndentWidth: 4, ColumnLimit: 0}", - "python.testing.pytestArgs": [ - "-v", - "-s" - ], - "python.testing.unittestEnabled": false, - "python.testing.nosetestsEnabled": false, - "python.testing.pytestEnabled": true, - "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" -} \ No newline at end of file + "editor.formatOnSave": true, + "editor.tabSize": 4, + "editor.codeActionsOnSave": { + "source.organizeImports": true, + "source.fixAll": true + }, + "terminal.integrated.env.linux": { + "PATH": "${env:PATH}:${workspaceFolder}/kanban-board-service/node_modules/.bin" + }, + "terminal.integrated.env.osx": { + "PATH": "${env:PATH}:${workspaceFolder}/kanban-board-service/node_modules/.bin" + }, + "terminal.integrated.env.windows": { + "PATH": "${env:PATH};${workspaceFolder}\\kanban-board-service\\node_modules\\.bin" + }, + "git.inputValidationLength": 100, + "git.inputValidationSubjectLength": 100, + "cmake.sourceDirectory": "${workspaceFolder}/kanban-board-service", + "cmake.buildDirectory": "${workspaceFolder}/kanban-board-service/build", + "cmake.debugConfig": { + "cwd": "${workspaceFolder}/kanban-board-service/build" + }, + "C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: LLVM, IndentWidth: 4, ColumnLimit: 0}", + "python.testing.pytestArgs": [ + "-v", + "-s" + ], + "python.testing.unittestEnabled": false, + "python.testing.nosetestsEnabled": false, + "python.testing.pytestEnabled": true, + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + + "cmake.generator": "MinGW Makefiles", + "cmake.cmakePath": "C:/msys64/mingw64/bin/cmake.exe", + "cmake.mingwSearchDirs": [ + "C:/msys64/mingw64", + ], + "cmake.preferredGenerators": [ + "MinGW Makefiles" + ], +} diff --git a/kanban-board-service/src/Api/Parser/JsonParser.cpp b/kanban-board-service/src/Api/Parser/JsonParser.cpp index de8f91e..ff40f32 100644 --- a/kanban-board-service/src/Api/Parser/JsonParser.cpp +++ b/kanban-board-service/src/Api/Parser/JsonParser.cpp @@ -16,7 +16,48 @@ string JsonParser::convertToApiString(Board &board) { } string JsonParser::convertToApiString(Column &column) { - throw NotImplementedException(); + Document document(kObjectType); + + Value jsonColumn = getJsonValueFromModel(column, document.GetAllocator()); + return jsonValueToString(jsonColumn); +} + +rapidjson::Value JsonParser::getJsonValueFromModel(Column const &column, rapidjson::Document::AllocatorType &allocator) { + Value jsonColumn(kObjectType); + + jsonColumn.AddMember("id", column.getId(), allocator); + jsonColumn.AddMember("name", Value(column.getName().c_str(), allocator), allocator); + jsonColumn.AddMember("position", column.getPos(), allocator); + + Value jsonItems(kArrayType); + + for (Item const &item : column.getItems()) { + Value jsonItem = getJsonValueFromModel(item, allocator); + jsonItems.PushBack(jsonItem, allocator); + } + + jsonColumn.AddMember("items", jsonItems, allocator); + + return jsonColumn; +} + +rapidjson::Value JsonParser::getJsonValueFromModel(Item const &item, rapidjson::Document::AllocatorType &allocator) { + Value jsonItem(kObjectType); + + jsonItem.AddMember("id", item.getId(), allocator); + jsonItem.AddMember("title", Value(item.getTitle().c_str(), allocator), allocator); + jsonItem.AddMember("position", item.getPos(), allocator); + jsonItem.AddMember("timestamp", Value(item.getTimestamp().c_str(), allocator), allocator); + + return jsonItem; +} + +string JsonParser::jsonValueToString(rapidjson::Value const &json) { + StringBuffer buffer; + Writer writer(buffer); + json.Accept(writer); + + return buffer.GetString(); } string JsonParser::convertToApiString(std::vector &columns) { @@ -24,7 +65,12 @@ string JsonParser::convertToApiString(std::vector &columns) { } string JsonParser::convertToApiString(Item &item) { - throw NotImplementedException(); + string result = EMPTY_JSON; + Document document(kObjectType); + + Value jsonItem = getJsonValueFromModel(item, document.GetAllocator()); + result = jsonValueToString(jsonItem); + return result; } string JsonParser::convertToApiString(std::vector &items) { @@ -32,9 +78,62 @@ string JsonParser::convertToApiString(std::vector &items) { } std::optional JsonParser::convertColumnToModel(int columnId, std::string &request) { - throw NotImplementedException(); + std::optional resultColumn; + Document document; + document.Parse(request.c_str()); + + if (true == isValidColumn(document)) { + std::string name = document["name"].GetString(); + int position = document["position"].GetInt(); + resultColumn = Column(columnId, name, position); + } + return resultColumn; } std::optional JsonParser::convertItemToModel(int itemId, std::string &request) { - throw NotImplementedException(); + std::optional resultItem; + + Document document; + document.Parse(request.c_str()); + + if (true == isValidItem(document)) { + std::string title = document["title"].GetString(); + int position = document["position"].GetInt(); + resultItem = Item(itemId, title, position, ""); + } + return resultItem; +} + +bool JsonParser::isValidColumn(rapidjson::Document const &document) { + + bool isValid = true; + + if (document.HasParseError()) { + isValid = false; + } + if (false == document["name"].IsString()) { + isValid = false; + } + if (false == document["position"].IsInt()) { + isValid = false; + } + + return isValid; +} + +bool JsonParser::isValidItem(rapidjson::Document const &document) { + + bool isValid = true; + + if (document.HasParseError()) { + isValid = false; + } + if (false == document["title"].IsString()) { + isValid = false; + } + if (false == document["position"].IsInt()) { + isValid = false; + } + + return isValid; } diff --git a/kanban-board-service/src/Api/Parser/JsonParser.hpp b/kanban-board-service/src/Api/Parser/JsonParser.hpp index 07a8d86..3955732 100644 --- a/kanban-board-service/src/Api/Parser/JsonParser.hpp +++ b/kanban-board-service/src/Api/Parser/JsonParser.hpp @@ -11,6 +11,14 @@ class JsonParser : public ParserIf { private: static inline std::string const EMPTY_JSON = "{}"; + bool isValidColumn(rapidjson::Document const &document); + bool isValidItem(rapidjson::Document const &document); + + rapidjson::Value getJsonValueFromModel(Prog3::Core::Model::Item const &item, rapidjson::Document::AllocatorType &allocator); + rapidjson::Value getJsonValueFromModel(Prog3::Core::Model::Column const &column, rapidjson::Document::AllocatorType &allocator); + + std::string jsonValueToString(rapidjson::Value const &json); + public: JsonParser(){}; virtual ~JsonParser(){}; diff --git a/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp b/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp index 6ff062a..8c2c248 100644 --- a/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp +++ b/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp @@ -1,5 +1,6 @@ #include "BoardRepository.hpp" #include "Core/Exception/NotImplementedException.hpp" +#include #include #include @@ -77,7 +78,23 @@ std::optional BoardRepository::getColumn(int id) { } std::optional BoardRepository::postColumn(std::string name, int position) { - throw NotImplementedException(); + string sqlPostItem = + "INSERT INTO column('name', 'position') " + "VALUES('" + + name + "', '" + to_string(position) + "')"; + + int result = 0; + char *errorMessage = nullptr; + + result = sqlite3_exec(database, sqlPostItem.c_str(), NULL, 0, &errorMessage); + handleSQLError(result, errorMessage); + + if (SQLITE_OK == result) { + int columnId = sqlite3_last_insert_rowid(database); + return Column(columnId, name, position); + } + + return std::nullopt; } std::optional BoardRepository::putColumn(int id, std::string name, int position) { @@ -97,7 +114,27 @@ std::optional BoardRepository::getItem(int columnId, int itemId) { } std::optional BoardRepository::postItem(int columnId, std::string title, int position) { - throw NotImplementedException(); + + time_t now = time(0); + char *datetime = ctime(&now); + + string sqlPostItem = + "INSERT INTO item ('title', 'date', 'position', 'column_id') " + "VALUES ('" + + title + "', '" + datetime + "', " + to_string(position) + ", " + to_string(columnId) + ");"; + + int result = 0; + char *errorMessage = nullptr; + + result = sqlite3_exec(database, sqlPostItem.c_str(), NULL, 0, &errorMessage); + handleSQLError(result, errorMessage); + + int itemId = INVALID_ID; + if (SQLITE_OK == result) { + itemId = sqlite3_last_insert_rowid(database); + return Item(itemId, title, position, datetime); + } + return std::nullopt; } std::optional BoardRepository::putItem(int columnId, int itemId, std::string title, int position) { From e7aba68bfe47c05f43fbdbb6f35fd0e2c321c79a Mon Sep 17 00:00:00 2001 From: Julian Sehne Date: Wed, 10 Nov 2021 10:41:50 +0100 Subject: [PATCH 2/4] Implemented Delete Item and Column --- .../src/Repository/SQLite/BoardRepository.cpp | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp b/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp index 8c2c248..a2a7457 100644 --- a/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp +++ b/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp @@ -102,11 +102,30 @@ std::optional BoardRepository::putColumn(int id, std } void BoardRepository::deleteColumn(int id) { - throw NotImplementedException(); + int result = 0; + char *errorMessage = nullptr; + + string sqlDeleteColumn = + "delete from column " + "where id = " + + std::to_string(id); + + result = sqlite3_exec(database, sqlDeleteColumn.c_str(), NULL, 0, &errorMessage); + handleSQLError(result, errorMessage); } -std::vector BoardRepository::getItems(int columnId) { - throw NotImplementedException(); +void BoardRepository::deleteItem(int columnId, int itemId) { + int result = 0; + char *errorMessage = nullptr; + + string sqlDeleteItem = + "delete from item " + "where id = " + + std::to_string(itemId) + + " and column_id = " + std::to_string(columnId); + + result = sqlite3_exec(database, sqlDeleteItem.c_str(), NULL, 0, &errorMessage); + handleSQLError(result, errorMessage); } std::optional BoardRepository::getItem(int columnId, int itemId) { From 114821ec7dc8a040fa77eb51b6d9b186b0c521a7 Mon Sep 17 00:00:00 2001 From: Julian Sehne Date: Wed, 10 Nov 2021 10:43:06 +0100 Subject: [PATCH 3/4] updated Settings.json maybe incorrect --- .vscode/settings.json | 76 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d9d7794..6c2a385 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -38,5 +38,79 @@ ], "cmake.preferredGenerators": [ "MinGW Makefiles" - ], +], +"files.associations": { + "optional": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "strstream": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "coroutine": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "source_location": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "variant": "cpp" +}, } From 991497084907812f1065e392ced27850b98bc464 Mon Sep 17 00:00:00 2001 From: Julian Sehne Date: Sat, 13 Nov 2021 21:42:36 +0100 Subject: [PATCH 4/4] putColumn, Quer callback, putItem --- .../src/Repository/SQLite/BoardRepository.cpp | 111 +++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp b/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp index a2a7457..b0d748c 100644 --- a/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp +++ b/kanban-board-service/src/Repository/SQLite/BoardRepository.cpp @@ -65,6 +65,21 @@ void BoardRepository::initialize() { //createDummyData(); } +template +void split(const std::string &s, char delim, Out result) { + std::istringstream iss(s); + std::string item; + while (std::getline(iss, item, delim)) { + *result++ = item; + } +} + +std::vector split(const std::string &s, char delim) { + std::vector elems; + split(s, delim, std::back_inserter(elems)); + return elems; +} + Board BoardRepository::getBoard() { throw NotImplementedException(); } @@ -98,7 +113,62 @@ std::optional BoardRepository::postColumn(std::string name, int position } std::optional BoardRepository::putColumn(int id, std::string name, int position) { - throw NotImplementedException(); + int result = 0; + char *errorMessage = nullptr; + string emptyString = ""; + string emptyStringThisColumn = ""; + void *selectResult = static_cast(&emptyString); + void *thisColumn = static_cast(&emptyStringThisColumn); + + string sqlSelectItems = "SELECT * from item WHERE column_id=" + to_string(id) + ";"; + string sqlPutColumn = "UPDATE column SET name= \"" + name + "\", position = " + to_string(position) + " WHERE id = " + to_string(id) + ";"; + string sqlSelectColumn = "SELECT * from column WHERE id=" + to_string(id) + ";"; + + // CHECK IF COLUMN EXISTS + result = sqlite3_exec(database, sqlSelectColumn.c_str(), BoardRepository::queryCallback, thisColumn, &errorMessage); + handleSQLError(result, errorMessage); + string *tempPointer = static_cast(thisColumn); + string thisColumnString = *tempPointer; + if (thisColumnString == "") + return nullopt; + // GET ALL ITEMS OUT OF THE COLUMN + result = sqlite3_exec(database, sqlSelectItems.c_str(), BoardRepository::queryCallback, selectResult, &errorMessage); + handleSQLError(result, errorMessage); + string *sp = static_cast(selectResult); + string data = *sp; + vector items = split(data, ';'); + vector realItems{}; + for (auto item : items) { + vector tuples = split(item, ','); + + string itemIdString = split(tuples[0], ':')[1]; + int itemId = stoi(itemIdString); + + string title = split(tuples[1], ':')[1]; + + string datetime = split(tuples[2], ':')[1]; + + string positionString = split(tuples[3], ':')[1]; + int position = stoi(positionString); + + // cout << "Id: " + to_string(itemId) + " title: " + title + " position: " + to_string(position) + " datetime: " + datetime << endl; + realItems.push_back(Item(itemId, title, position, datetime)); + } + // UPDATE COLUMN + errorMessage = nullptr; + result = sqlite3_exec(database, sqlPutColumn.c_str(), NULL, 0, &errorMessage); + handleSQLError(result, errorMessage); + + if (SQLITE_OK != result) { + cout << "Could not edit column with id " + to_string(id) + "." << endl; + return nullopt; + } + cout << "Column with id " + to_string(id) + " sucessfully edited" << endl; + Column column(id, name, position); + for (auto item : realItems) { + column.addItem(item); + } + return column; } void BoardRepository::deleteColumn(int id) { @@ -157,7 +227,36 @@ std::optional BoardRepository::postItem(int columnId, std::string title, i } std::optional BoardRepository::putItem(int columnId, int itemId, std::string title, int position) { - throw NotImplementedException(); + time_t now = time(0); + char *datetime = ctime(&now); + + char *errorMessage = nullptr; + int result = 0; + + // COMMENT THIS IS IN IF YOU WANT TO PREVENT USERS CREATING RESOURCES VIA PUT INSTEAD OF POST + string emptyString = ""; + void *selectResult = static_cast(&emptyString); + string sqlSelect = "SELECT * FROM item WHERE id =" + to_string(itemId) + ";"; + int selectAnswer = sqlite3_exec(database, sqlSelect.c_str(), BoardRepository::queryCallback, selectResult, &errorMessage); + handleSQLError(selectAnswer, errorMessage); + + string *tempPointer = static_cast(selectResult); + string thisItemString = *tempPointer; + if (thisItemString == "") { + return nullopt; + } + + string sqlPutItem = "UPDATE item SET title =\"" + title + "\"" + ", position =" + to_string(position) + ", column_id= " + to_string(columnId) + " WHERE id = " + to_string(itemId) + ";"; + + result = sqlite3_exec(database, sqlPutItem.c_str(), NULL, 0, &errorMessage); + handleSQLError(result, errorMessage); + + if (SQLITE_OK != result) { + cout << "Could not edit item with id " + to_string(itemId) + "." << endl; + return nullopt; + } + std::cout << "Item with id " + to_string(itemId) + " sucessfully edited" << endl; + return Item(itemId, title, position, datetime); } void BoardRepository::deleteItem(int columnId, int itemId) { @@ -206,5 +305,13 @@ void BoardRepository::createDummyData() { I want to show you how the signature of this "callback function" may look like in order to work with sqlite3_exec() */ int BoardRepository::queryCallback(void *data, int numberOfColumns, char **fieldValues, char **columnNames) { + string *stringPointer = static_cast(data); + int size = sizeof(columnNames) / sizeof(columnNames[0]); + for (int i = 0; i < numberOfColumns; i++) { + *stringPointer = *stringPointer + columnNames[i] + ":" + fieldValues[i]; + if (i < numberOfColumns - 1) + *stringPointer = *stringPointer + ","; + } + *stringPointer = *stringPointer + ";"; return 0; }