From 5323052300a07c3de6de2c134abb18fb84b0fff3 Mon Sep 17 00:00:00 2001 From: Dario Date: Mon, 30 Nov 2020 15:38:27 +0100 Subject: [PATCH] add app access token table, model and controller --- skeema/gradido_login/app_access_tokens.sql | 9 ++ src/cpp/controller/AppAccessToken.cpp | 65 +++++++++++ src/cpp/controller/AppAccessToken.h | 34 ++++++ src/cpp/model/table/AppAccessToken.cpp | 125 +++++++++++++++++++++ src/cpp/model/table/AppAccessToken.h | 53 +++++++++ 5 files changed, 286 insertions(+) create mode 100644 skeema/gradido_login/app_access_tokens.sql create mode 100644 src/cpp/controller/AppAccessToken.cpp create mode 100644 src/cpp/controller/AppAccessToken.h create mode 100644 src/cpp/model/table/AppAccessToken.cpp create mode 100644 src/cpp/model/table/AppAccessToken.h diff --git a/skeema/gradido_login/app_access_tokens.sql b/skeema/gradido_login/app_access_tokens.sql new file mode 100644 index 000000000..d320bba5c --- /dev/null +++ b/skeema/gradido_login/app_access_tokens.sql @@ -0,0 +1,9 @@ +CREATE TABLE `app_access_tokens` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `access_code` bigint unsigned NOT NULL, + `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `access_code` (`access_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/src/cpp/controller/AppAccessToken.cpp b/src/cpp/controller/AppAccessToken.cpp new file mode 100644 index 000000000..1da6ddd0b --- /dev/null +++ b/src/cpp/controller/AppAccessToken.cpp @@ -0,0 +1,65 @@ +#include "AppAccessToken.h" + +#include "sodium.h" + +namespace controller +{ + AppAccessToken::AppAccessToken(model::table::AppAccessToken* dbModel) + { + mDBModel = dbModel; + } + + AppAccessToken::~AppAccessToken() + { + + } + + Poco::AutoPtr AppAccessToken::create(int user_id) + { + auto code = createAppAccessCode(); + auto db = new model::table::AppAccessToken(code, user_id); + return Poco::AutoPtr(new AppAccessToken(db)); + } + + Poco::AutoPtr AppAccessToken::load(const Poco::UInt64& code) + { + auto db = new model::table::AppAccessToken(); + if (db->loadFromDB("app_access_tokens", code) == 1) { + return Poco::AutoPtr(new AppAccessToken(db)); + } + db->release(); + return nullptr; + } + + std::vector> AppAccessToken::load(int user_id) + { + auto db = new model::table::AppAccessToken(); + auto results = db->loadFromDB("user_id", user_id, 2); + + std::vector> resultObjects; + if (db->errorCount()) { + db->sendErrorsAsEmail(); + db->release(); + return resultObjects; + } + db->release(); + if (results.size() == 0) { + return resultObjects; + } + for (auto it = results.begin(); it != results.end(); it++) { + resultObjects.push_back(new AppAccessToken(new model::table::AppAccessToken(*it))); + } + + return resultObjects; + } + + Poco::UInt64 AppAccessToken::createAppAccessCode() + { + Poco::UInt64 resultCode; + uint32_t* code_p = (uint32_t*)&resultCode; + for (int i = 0; i < sizeof(resultCode) / 4; i++) { + code_p[i] = randombytes_random(); + } + return resultCode; + } +} \ No newline at end of file diff --git a/src/cpp/controller/AppAccessToken.h b/src/cpp/controller/AppAccessToken.h new file mode 100644 index 000000000..35093c442 --- /dev/null +++ b/src/cpp/controller/AppAccessToken.h @@ -0,0 +1,34 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_APP_ACCESS_TOKEN_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_APP_ACCESS_TOKEN_INCLUDE + +#include "../model/table/AppAccessToken.h" + +#include "TableControllerBase.h" + +namespace controller { + class AppAccessToken : public TableControllerBase + { + public: + + ~AppAccessToken(); + + static Poco::AutoPtr create(int user_id); + + static Poco::AutoPtr load(const Poco::UInt64& code); + static std::vector> load(int user_id); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + + inline Poco::Timespan getAge() { return Poco::DateTime() - getModel()->getCreated(); } + + protected: + AppAccessToken(model::table::AppAccessToken* dbModel); + static Poco::UInt64 createAppAccessCode(); + + //table::EmailOptIn* mDBModel; + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_APP_ACCESS_TOKEN_INCLUDE \ No newline at end of file diff --git a/src/cpp/model/table/AppAccessToken.cpp b/src/cpp/model/table/AppAccessToken.cpp new file mode 100644 index 000000000..615dbb361 --- /dev/null +++ b/src/cpp/model/table/AppAccessToken.cpp @@ -0,0 +1,125 @@ +#include "AppAccessToken.h" + + +using namespace Poco::Data::Keywords; + +namespace model +{ + namespace table { + + + + AppAccessToken::AppAccessToken() + : mUserId(0), mAccessCode(0) + { + + } + + AppAccessToken::AppAccessToken(int user_id, const Poco::UInt64& code) + : mUserId(user_id), mAccessCode(code) + { + + } + + AppAccessToken::AppAccessToken(const AppAccessCodeTuple& tuple) + : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mAccessCode(tuple.get<2>()), mCreated(tuple.get<3>()), mUpdated(tuple.get<4>()) + { + + } + + AppAccessToken::~AppAccessToken() + { + + } + + std::string AppAccessToken::toString() + { + std::stringstream ss; + ss << "id: " << std::to_string(mID) << std::endl; + ss << "user id: " << std::to_string(mUserId) << std::endl; + ss << "code: " << std::to_string(mAccessCode) << std::endl; + + return ss.str(); + } + + Poco::Data::Statement AppAccessToken::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + + lock(); + assert(mUserId > 0); + assert(mAccessCode > 0); + + insert << "INSERT INTO " << getTableName() + << " (user_id, access_code) VALUES(?,?)" + , use(mUserId), use(mAccessCode); + unlock(); + mUpdated = Poco::DateTime(); + mCreated = Poco::DateTime(); + return insert; + } + + + Poco::Data::Statement AppAccessToken::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, access_code, created, updated FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mUserId), into(mAccessCode), into(mCreated), into(mUpdated); + + + return select; + } + + Poco::Data::Statement AppAccessToken::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id FROM " << getTableName() + << " where access_code = ?" + , into(mID), use(mAccessCode); + + return select; + } + Poco::Data::Statement AppAccessToken::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, access_code, created, updated FROM " << getTableName() + << " where " << fieldName << " = ?"; + + + return select; + } + + Poco::Data::Statement AppAccessToken::_loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + { + Poco::Data::Statement select(session); + if (fieldNames.size() <= 1) { + throw Poco::NullValueException("AppAccessToken::_loadFromDB fieldNames empty or contain only one field"); + } + + select << "SELECT id, user_id, access_code, created, updated FROM " << getTableName() + << " where " << fieldNames[0] << " = ? "; + if (conditionType == MYSQL_CONDITION_AND) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " AND " << fieldNames[i] << " = ? "; + } + } + else if (conditionType == MYSQL_CONDITION_OR) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " OR " << fieldNames[i] << " = ? "; + } + } + else { + addError(new ParamError("AppAccessToken::_loadFromDB", "condition type not implemented", conditionType)); + } + //<< " where " << fieldName << " = ?" + select, into(mID), into(mUserId), into(mAccessCode), into(mCreated), into(mUpdated); + + + return select; + } + } +} \ No newline at end of file diff --git a/src/cpp/model/table/AppAccessToken.h b/src/cpp/model/table/AppAccessToken.h new file mode 100644 index 000000000..1bca2c351 --- /dev/null +++ b/src/cpp/model/table/AppAccessToken.h @@ -0,0 +1,53 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_APP_ACCESS_TOKEN_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_APP_ACCESS_TOKEN_INCLUDE + +#include "ModelBase.h" +#include "Poco/Types.h" +#include "Poco/Tuple.h" + +namespace model { + namespace table { + + typedef Poco::Tuple AppAccessCodeTuple; + + class AppAccessToken : public ModelBase + { + public: + AppAccessToken(int user_id, const Poco::UInt64& code); + AppAccessToken(const AppAccessCodeTuple& tuple); + AppAccessToken(); + ~AppAccessToken(); + + // generic db operations + const char* getTableName() const { return "app_access_tokens"; } + std::string toString(); + + inline Poco::UInt64 getCode() const { return mAccessCode; } + inline int getUserId() const { return mUserId; } + inline Poco::DateTime getCreated() const { return mCreated; } + inline Poco::DateTime getUpdated() const { Poco::ScopedLock _lock(mWorkMutex); return mUpdated; } + inline void setCode(Poco::UInt64 code) { mAccessCode = code; } + inline void setUserId(int user_Id) { mUserId = user_Id; } + + + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); + + int mUserId; + // data type must be a multiple of 4 + Poco::UInt64 mAccessCode; + Poco::DateTime mCreated; + Poco::DateTime mUpdated; + + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_EMAIL_OPT_IN_INCLUDE \ No newline at end of file