From 28900e04fec90476ff6184a35ddc8f2416358887 Mon Sep 17 00:00:00 2001 From: Dario Date: Wed, 15 Jan 2020 09:16:59 +0100 Subject: [PATCH] adding code for loading user role --- src/cpp/controller/User.cpp | 2 + src/cpp/controller/User.h | 14 ++++ src/cpp/model/Session.cpp | 10 ++- src/cpp/model/Session.h | 1 + src/cpp/model/table/ModelBase.h | 7 +- src/cpp/model/table/Roles.cpp | 0 src/cpp/model/table/Roles.h | 60 ++++++++++++++ src/cpp/model/table/User.cpp | 41 ++++++++-- src/cpp/model/table/User.h | 8 +- src/cpp/model/table/UserRoles.cpp | 127 ++++++++++++++++++++++++++++++ src/cpp/model/table/UserRoles.h | 54 +++++++++++++ 11 files changed, 315 insertions(+), 9 deletions(-) create mode 100644 src/cpp/model/table/Roles.cpp create mode 100644 src/cpp/model/table/Roles.h create mode 100644 src/cpp/model/table/UserRoles.cpp create mode 100644 src/cpp/model/table/UserRoles.h diff --git a/src/cpp/controller/User.cpp b/src/cpp/controller/User.cpp index fbf39cc16..e35e1579f 100644 --- a/src/cpp/controller/User.cpp +++ b/src/cpp/controller/User.cpp @@ -2,6 +2,7 @@ namespace controller { User::User(model::table::User* dbModel) + : mUserRole(USER_ROLE_NOT_LOADED) { mDBModel = dbModel; } @@ -31,4 +32,5 @@ namespace controller { Poco::Data::BLOB pubkey(pubkey_array, 32); return getModel()->loadFromDB("pubkey", pubkey); } + } \ No newline at end of file diff --git a/src/cpp/controller/User.h b/src/cpp/controller/User.h index 1bd3ed62c..720b9cba8 100644 --- a/src/cpp/controller/User.h +++ b/src/cpp/controller/User.h @@ -3,9 +3,18 @@ #include "../model/table/User.h" + #include "TableControllerBase.h" namespace controller { + + enum UserLoadedRole { + USER_ROLE_NOT_LOADED, + USER_ROLE_CURRENTLY_LOADING, + USER_ROLE_NONE, + USER_ROLE_ADMIN + }; + class User : public TableControllerBase { public: @@ -15,6 +24,8 @@ namespace controller { static Poco::AutoPtr create(); static Poco::AutoPtr create(const std::string& email, const std::string& first_name, const std::string& last_name, Poco::UInt64 passwordHashed = 0, std::string languageKey = "de"); + + inline size_t load(const std::string& email) { return getModel()->loadFromDB("email", email); } inline size_t load(int user_id) { return getModel()->loadFromDB("id", user_id); } int load(const unsigned char* pubkey_array); @@ -22,8 +33,11 @@ namespace controller { inline Poco::AutoPtr getModel() { return _getModel(); } inline const model::table::User* getModel() const { return _getModel(); } + + protected: User(model::table::User* dbModel); + UserLoadedRole mUserRole; }; } diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index 09bf4fd24..637fac5c5 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -576,10 +576,16 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo lock("Session::loadUser"); if (mSessionUser && mSessionUser->getEmail() != email) { mSessionUser = nullptr; + mNewUser = nullptr; } - if (!mSessionUser) { + //if (!mSessionUser) { + if (mNewUser.isNull()) { + mNewUser = controller::User::create(); + // load user for email only once from db - mSessionUser = new User(email.data()); + mNewUser->load(email); + mSessionUser = new User(mNewUser); + //mSessionUser = new User(email.data()); } if (mSessionUser->getUserState() >= USER_LOADED_FROM_DB) { if (!mSessionUser->validatePwd(password, this)) { diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index 9ccb349ee..f1e5ae33a 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -64,6 +64,7 @@ public: // set new model objects inline void setUser(Poco::AutoPtr user) { mNewUser = user; } + inline Poco::AutoPtr getNewUser() { return mNewUser; } // ---------------- User functions ---------------------------- // TODO: automatic redirect after some time, median profiled time for register diff --git a/src/cpp/model/table/ModelBase.h b/src/cpp/model/table/ModelBase.h index b35811d27..92ac17bb5 100644 --- a/src/cpp/model/table/ModelBase.h +++ b/src/cpp/model/table/ModelBase.h @@ -11,6 +11,8 @@ #include "../../ServerConfig.h" +#include "Poco/JSON/Object.h" + //using namespace Poco::Data::Keywords; namespace model { @@ -166,6 +168,8 @@ namespace model { // ******************** Generic Tasks ************************************ + + // -------- Insert --------------- class ModelInsertTask : public UniLib::controller::CPUTask { public: @@ -180,7 +184,7 @@ namespace model { bool mLoadId; }; - + // -------- Update --------------- template class ModelUpdateTask : public UniLib::controller::CPUTask @@ -210,6 +214,7 @@ namespace model { bool mEmailErrors; }; + // -------- Load --------------- } } diff --git a/src/cpp/model/table/Roles.cpp b/src/cpp/model/table/Roles.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/cpp/model/table/Roles.h b/src/cpp/model/table/Roles.h new file mode 100644 index 000000000..01775b58c --- /dev/null +++ b/src/cpp/model/table/Roles.h @@ -0,0 +1,60 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_ROLES_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_ROLES_INCLUDE + +#include "ModelBase.h" +#include "Poco/Types.h" +#include "Poco/Tuple.h" + +namespace model { + namespace table { + + enum RoleType { + ROLE_ADMIN = 1 + }; + + class Roles : public ModelBase + { + + }; + /* + typedef Poco::Tuple EmailOptInTuple; + + class EmailOptIn : public ModelBase + { + public: + EmailOptIn(const Poco::UInt64& code, int user_id, EmailOptInType type); + EmailOptIn(const Poco::UInt64& code, EmailOptInType type); + EmailOptIn(const EmailOptInTuple& tuple); + EmailOptIn(); + ~EmailOptIn(); + + // generic db operations + const char* getTableName() { return "email_opt_in"; } + std::string toString(); + + inline Poco::UInt64 getCode() const { return mEmailVerificationCode; } + inline int getUserId() const { return mUserId; } + inline EmailOptInType getType() const { return static_cast(mType); } + inline void setCode(Poco::UInt64 code) { mEmailVerificationCode = code; } + inline void setUserId(int user_Id) { mUserId = user_Id; } + + static const char* typeToString(EmailOptInType type); + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(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); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + int mUserId; + // data type must be a multiple of 4 + Poco::UInt64 mEmailVerificationCode; + int mType; + + }; + */ + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_ROLES_INCLUDE \ No newline at end of file diff --git a/src/cpp/model/table/User.cpp b/src/cpp/model/table/User.cpp index 0eb7f202a..f2e2fd06a 100644 --- a/src/cpp/model/table/User.cpp +++ b/src/cpp/model/table/User.cpp @@ -12,12 +12,12 @@ namespace model { namespace table { User::User() - : mPasswordHashed(0), mEmailChecked(false), mLanguageKey("de") + : mPasswordHashed(0), mEmailChecked(false), mLanguageKey("de"), mRole(ROLE_NOT_LOADED) { } User::User(const std::string& email, const std::string& first_name, const std::string& last_name, Poco::UInt64 passwordHashed/* = 0*/, std::string languageKey/* = "de"*/) - : mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(passwordHashed), mEmailChecked(false), mLanguageKey(languageKey) + : mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(passwordHashed), mEmailChecked(false), mLanguageKey(languageKey), mRole(ROLE_NOT_LOADED) { } @@ -69,9 +69,11 @@ namespace model { { Poco::Data::Statement select(session); - - select << "SELECT id, email, first_name, last_name, password, pubkey, privkey, email_checked, language from " << getTableName() << " where " << fieldName << " = ?", - into(mID), into(mEmail), into(mFirstName), into(mLastName), into(mPasswordHashed), into(mPublicKey), into(mPrivateKey), into(mEmailChecked), into(mLanguageKey); + select << "SELECT id, email, first_name, last_name, password, pubkey, privkey, email_checked, language, user_roles.role_id " + << " FROM " << getTableName() + << " LEFT JOIN user_roles ON " << getTableName() << ".id = user_roles.user_id " + << " WHERE " << fieldName << " = ?" + ,into(mID), into(mEmail), into(mFirstName), into(mLastName), into(mPasswordHashed), into(mPublicKey), into(mPrivateKey), into(mEmailChecked), into(mLanguageKey), into(mRole); return select; @@ -138,5 +140,34 @@ namespace model { return ss.str(); } + + + Poco::JSON::Object User::getJson() + { + auto mm = MemoryManager::getInstance(); + auto pubkeyHex = mm->getFreeMemory(65); + memset(*pubkeyHex, 0, 65); + + lock("User::getJson"); + Poco::JSON::Object userObj; + + if (!mPublicKey.isNull()) { + sodium_bin2hex(*pubkeyHex, 65, mPublicKey.value().content().data(), mPublicKey.value().content().size()); + } + + userObj.set("first_name", mFirstName); + userObj.set("last_name", mLastName); + userObj.set("email", mEmail); + userObj.set("public_hex", (char*)*pubkeyHex); + //userObj.set("state", userStateToString(mState)); + userObj.set("email_checked", mEmailChecked); + userObj.set("ident_hash", DRMakeStringHash(mEmail.data(), mEmail.size())); + userObj.set("role", UserRoles::typeToString(getRole())); + unlock(); + + mm->releaseMemory(pubkeyHex); + + return userObj; + } } } \ No newline at end of file diff --git a/src/cpp/model/table/User.h b/src/cpp/model/table/User.h index bbe1da92d..9406cecfb 100644 --- a/src/cpp/model/table/User.h +++ b/src/cpp/model/table/User.h @@ -7,6 +7,8 @@ //#include "Poco/Nullable.h" //#include "Poco/Data/LOB.h" +#include "UserRoles.h" + namespace model { namespace table { enum UserFields @@ -41,6 +43,7 @@ namespace model { inline const std::string& getFirstName() const { return mFirstName; } inline const std::string& getLastName() const { return mLastName; } inline const Poco::UInt64& getPasswordHashed() const { return mPasswordHashed; } + inline RoleType getRole() const { if (mRole.isNull()) return ROLE_NONE; return static_cast(mRole.value()); } inline const unsigned char* getPublicKey() const { if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); } inline bool existPrivateKeyCrypted() const { return !mPrivateKey.isNull(); } inline const std::vector& getPrivateKeyCrypted() const { return mPrivateKey.value().content(); } @@ -58,7 +61,7 @@ namespace model { inline void setEmailChecked(bool emailChecked) { mEmailChecked = emailChecked; } inline void setLanguageKey(const std::string& languageKey) { mLanguageKey = languageKey; } - + Poco::JSON::Object getJson(); protected: @@ -80,6 +83,9 @@ namespace model { bool mEmailChecked; std::string mLanguageKey; + // from neighbor tables + Poco::Nullable mRole; + }; } } diff --git a/src/cpp/model/table/UserRoles.cpp b/src/cpp/model/table/UserRoles.cpp new file mode 100644 index 000000000..0d1f673e9 --- /dev/null +++ b/src/cpp/model/table/UserRoles.cpp @@ -0,0 +1,127 @@ +#include "UserRoles.h" + +using namespace Poco::Data::Keywords; + +namespace model { + namespace table { + + + UserRoles::UserRoles(int user_id, RoleType type) + : mUserId(user_id), mType(type) + { + + } + + UserRoles::UserRoles(const UserRolesTuple& tuple) + : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mType(tuple.get<2>()) + { + + } + UserRoles::UserRoles() + { + + } + + UserRoles::~UserRoles() + { + + } + + Poco::Data::Statement UserRoles::_insertIntoDB(Poco::Data::Session session) + { + Poco::Data::Statement insert(session); + + lock(); + insert << "INSERT INTO " << getTableName() + << " (user_id, role_id) VALUES(?,?)" + , use(mUserId), bind(mType); + unlock(); + return insert; + } + + + Poco::Data::Statement UserRoles::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, role_id FROM " << getTableName() + << " where " << fieldName << " = ?" + , into(mID), into(mUserId), into(mType); + + + return select; + } + + Poco::Data::Statement UserRoles::_loadIdFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id FROM " << getTableName() + << " where user_id = ? and role_id = ?" + , into(mID), use(mUserId), use(mType); + + return select; + } + + Poco::Data::Statement UserRoles::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + + select << "SELECT id, user_id, role_id FROM " << getTableName() + << " where " << fieldName << " = ?"; + + + return select; + } + + Poco::Data::Statement UserRoles::_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("UserRoles::_loadFromDB fieldNames empty or contain only one field"); + } + + select << "SELECT user_id, role_id 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("UserRoles::_loadFromDB", "condition type not implemented", conditionType)); + } + //<< " where " << fieldName << " = ?" + select, into(mUserId), into(mType); + + + return select; + } + + // generic db operations + std::string UserRoles::toString() + { + std::stringstream ss; + ss << "user_id: " << mUserId << std::endl; + ss << "role: " << typeToString(static_cast(mType)); + return ss.str(); + } + + const char* UserRoles::typeToString(RoleType type) + { + switch (type) { + case ROLE_NOT_LOADED: return "not loaded"; + case ROLE_NONE: return "none"; + case ROLE_ADMIN: return "admin"; + default: return "unknown"; + } + } + + } +} + diff --git a/src/cpp/model/table/UserRoles.h b/src/cpp/model/table/UserRoles.h new file mode 100644 index 000000000..f44bf9885 --- /dev/null +++ b/src/cpp/model/table/UserRoles.h @@ -0,0 +1,54 @@ +#ifndef GRADIDO_LOGIN_SERVER_MODEL_TABLE_USER_ROLES_INCLUDE +#define GRADIDO_LOGIN_SERVER_MODEL_TABLE_USER_ROLES_INCLUDE + +#include "ModelBase.h" +#include "Poco/Types.h" +#include "Poco/Tuple.h" +//#include "Roles.h" + +namespace model { + namespace table { + + enum RoleType { + ROLE_NOT_LOADED = -1, + ROLE_NONE = 0, + ROLE_ADMIN = 1 + }; + + typedef Poco::Tuple UserRolesTuple; + + class UserRoles : public ModelBase + { + public: + UserRoles(int user_id, RoleType type); + UserRoles(const UserRolesTuple& tuple); + UserRoles(); + ~UserRoles(); + + // generic db operations + const char* getTableName() { return "user_roles"; } + std::string toString(); + + inline int getUserId() const { return mUserId; } + inline RoleType getType() const { return static_cast(mType); } + + inline void setUserId(int user_Id) { mUserId = user_Id; } + + static const char* typeToString(RoleType type); + protected: + Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadIdFromDB(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); + Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); + + int mUserId; + int mType; + + }; + + } +} + + +#endif //GRADIDO_LOGIN_SERVER_MODEL_TABLE_USER_ROLES_INCLUDE \ No newline at end of file