diff --git a/src/cpp/JSONInterface/JsonGetLogin.cpp b/src/cpp/JSONInterface/JsonGetLogin.cpp index cf7b85028..0f5001a9e 100644 --- a/src/cpp/JSONInterface/JsonGetLogin.cpp +++ b/src/cpp/JSONInterface/JsonGetLogin.cpp @@ -102,7 +102,7 @@ Poco::JSON::Object* JsonGetLogin::handle(Poco::Dynamic::Var params) } else { result->set("state", "not found"); - result->set("msg", "Session not found"); + result->set("msg", "session not found"); return result; } diff --git a/src/cpp/JSONInterface/JsonGetUsers.cpp b/src/cpp/JSONInterface/JsonGetUsers.cpp index d77546040..1173ca35c 100644 --- a/src/cpp/JSONInterface/JsonGetUsers.cpp +++ b/src/cpp/JSONInterface/JsonGetUsers.cpp @@ -1,16 +1,39 @@ #include "JsonGetUsers.h" #include "Poco/URI.h" +#include "Poco/JSON/Array.h" #include "../SingletonManager/SessionManager.h" -#include "../model/table/User.h" +#include "../controller/User.h" Poco::JSON::Object* JsonGetUsers::handle(Poco::Dynamic::Var params) { int session_id = 0; + std::string searchString; Poco::JSON::Object* result = new Poco::JSON::Object; - if (params.isStruct()) { + // if is json object + if (params.type() == typeid(Poco::JSON::Object::Ptr)) { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + /// Throws a RangeException if the value does not fit + /// into the result variable. + /// Throws a NotImplementedException if conversion is + /// not available for the given type. + /// Throws InvalidAccessException if Var is empty. + try { + paramJsonObject->get("search").convert(searchString); + paramJsonObject->get("session_id").convert(session_id); + } + catch (Poco::Exception& ex) { + printf("[JsonGetUsers::handle] try to use params as jsonObject: %s\n", ex.displayText().data()); + result->set("state", "error"); + result->set("msg", "json exception"); + result->set("details", ex.displayText()); + return result; + } + } + else if (params.isStruct()) { session_id = params["session_id"]; + searchString = params["search"].toString(); //std::string miau = params["miau"]; } else if (params.isVector()) { @@ -19,7 +42,9 @@ Poco::JSON::Object* JsonGetUsers::handle(Poco::Dynamic::Var params) for (auto it = queryParams.begin(); it != queryParams.end(); it++) { if (it->first == "session_id") { session_id = stoi(it->second); - break; + } + else if (it->first == "search") { + searchString = it->second; } } //auto var = params[0]; @@ -56,26 +81,42 @@ Poco::JSON::Object* JsonGetUsers::handle(Poco::Dynamic::Var params) auto session = sm->getSession(session_id); //Session* session = nullptr; if (session) { - auto user = session->getUser(); - if (!user) { + auto user = session->getNewUser(); + if (user.isNull()) { result->set("state", "not found"); result->set("msg", "Session didn't contain user"); return result; } - result->set("state", "success"); - result->set("clientIP", session->getClientIp().toString()); - Poco::JSON::Object usersObj; - model::table::User newUser; - //auto newUsers = newUser.loadFromDB("email_checked", 0, 0); - result->set("user", user->getJson()); - result->set("Transaction.pending", session->getProcessingTransactionCount()); - //printf("pending: %d\n", session->getProcessingTransactionCount()); - return result; + else if (searchString == "") { + result->set("state", "not found"); + result->set("msg", "search string is empty"); + return result; + } + else if (user->getModel()->getRole() != model::table::ROLE_ADMIN) { + result->set("state", "wrong role"); + result->set("msg", "User hasn't correct role"); + return result; + } + + auto results = controller::User::search(searchString); + if (results.size() > 0) { + result->set("state", "success"); + + //Poco::JSON::Object jsonResultObject; + Poco::JSON::Array jsonUsersArray; + + for (auto it = results.begin(); it != results.end(); it++) { + jsonUsersArray.add((*it)->getJson()); + (*it)->release(); + } + results.clear(); + result->set("users", jsonUsersArray); + } + } else { result->set("state", "not found"); - result->set("msg", "Session not found"); - return result; + result->set("msg", "session not found"); } } diff --git a/src/cpp/JSONInterface/JsonGetUsers.h b/src/cpp/JSONInterface/JsonGetUsers.h index 37cbe47f2..9349adb39 100644 --- a/src/cpp/JSONInterface/JsonGetUsers.h +++ b/src/cpp/JSONInterface/JsonGetUsers.h @@ -1,5 +1,5 @@ -#ifndef __JSON_INTERFACE_JSON_GET_LOGIN_ -#define __JSON_INTERFACE_JSON_GET_LOGIN_ +#ifndef __JSON_INTERFACE_JSON_GET_USERS_ +#define __JSON_INTERFACE_JSON_GET_USERS_ #include "JsonRequestHandler.h" @@ -13,4 +13,4 @@ protected: }; -#endif // __JSON_INTERFACE_JSON_GET_LOGIN_ \ No newline at end of file +#endif // __JSON_INTERFACE_JSON_GET_USERS_ \ No newline at end of file diff --git a/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp b/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp index 3445ab43b..03aaeba64 100644 --- a/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp +++ b/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp @@ -8,6 +8,7 @@ #include "JsonUnknown.h" #include "JsonTransaction.h" #include "JsonGetRunningUserTasks.h" +#include "JsonGetUsers.h" JsonRequestHandlerFactory::JsonRequestHandlerFactory() : mRemoveGETParameters("^/([a-zA-Z0-9_-]*)") @@ -29,6 +30,9 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c else if (url_first_part == "/getRunningUserTasks") { return new JsonGetRunningUserTasks; } + else if (url_first_part == "/getUsers") { + return new JsonGetUsers; + } return new JsonUnknown; } diff --git a/src/cpp/controller/User.cpp b/src/cpp/controller/User.cpp index bd179b281..3e3b1bddf 100644 --- a/src/cpp/controller/User.cpp +++ b/src/cpp/controller/User.cpp @@ -2,6 +2,8 @@ #include "sodium.h" +#include "../SingletonManager/SessionManager.h" + namespace controller { User::User(model::table::User* dbModel) { @@ -27,6 +29,36 @@ namespace controller { return Poco::AutoPtr(user); } + std::vector User::search(const std::string& searchString) + { + + auto sm = SessionManager::getInstance(); + auto db = new model::table::User(); + + std::string globalSearch = "%" + searchString + "%"; + + std::vector resultFromDB; + // check if search string is email + if (sm->isValid(searchString, VALIDATE_EMAIL)) { + resultFromDB = db->loadFromDB ("email", globalSearch); + } + else { + std::vector fieldNames = { "first_name", "last_name" }; + std::vector fieldValues = { globalSearch, globalSearch }; + resultFromDB = db->loadFromDB(fieldNames, fieldValues, model::table::MYSQL_CONDITION_OR); + } + + db->release(); + db = nullptr; + + std::vector resultVector; + resultVector.reserve(resultFromDB.size()); + for (auto it = resultFromDB.begin(); it != resultFromDB.end(); it++) { + resultVector.push_back(new User(new model::table::User(*it))); + } + return resultVector; + + } int User::load(const unsigned char* pubkey_array) { @@ -41,8 +73,6 @@ namespace controller { } auto mm = MemoryManager::getInstance(); - auto pubkeyHex = mm->getFreeMemory(65); - memset(*pubkeyHex, 0, 65); lock("User::getJson"); Poco::JSON::Object userObj; @@ -50,21 +80,31 @@ namespace controller { auto pubkey = getModel()->getPublicKey(); if (pubkey) { + auto pubkeyHex = mm->getFreeMemory(65); + memset(*pubkeyHex, 0, 65); sodium_bin2hex(*pubkeyHex, 65, pubkey, 32); + mPublicHex = (char*)*pubkeyHex; + mm->releaseMemory(pubkeyHex); + unlock(); + return mPublicHex; } - mPublicHex = (char*)*pubkeyHex; - + else { + unlock(); + return ""; + } + unlock(); - - mm->releaseMemory(pubkeyHex); - - return mPublicHex; + return ""; + } Poco::JSON::Object User::getJson() { auto json = getModel()->getJson(); - json.set("public_hex", getPublicHex()); + auto pubkey = getPublicHex(); + if (pubkey != "") { + json.set("public_hex", pubkey); + } return json; } diff --git a/src/cpp/controller/User.h b/src/cpp/controller/User.h index 7fda9c641..5bebe3fc7 100644 --- a/src/cpp/controller/User.h +++ b/src/cpp/controller/User.h @@ -24,7 +24,7 @@ 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"); - + static std::vector search(const std::string& searchString); 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); } diff --git a/src/cpp/model/User.cpp b/src/cpp/model/User.cpp index ab6e90e63..0af7eb8ef 100644 --- a/src/cpp/model/User.cpp +++ b/src/cpp/model/User.cpp @@ -420,10 +420,25 @@ User::User(Poco::AutoPtr ctrl_user) mLanguage = LanguageManager::languageFromString(model->getLanguageKey()); mLanguageCatalog = LanguageManager::getInstance()->getFreeCatalog(mLanguage); - mState = USER_LOADED_FROM_DB; - if (!mEmailChecked) { mState = USER_EMAIL_NOT_ACTIVATED; } - else if (!mPrivateKey) { mState = USER_NO_PRIVATE_KEY; } - else { mState = USER_COMPLETE; } + /* + USER_EMPTY, + USER_LOADED_FROM_DB, + USER_PASSWORD_INCORRECT, + USER_PASSWORD_ENCRYPTION_IN_PROCESS, + USER_EMAIL_NOT_ACTIVATED, + USER_NO_KEYS, + USER_NO_PRIVATE_KEY, + USER_COMPLETE + */ + + if (mEmail != "") { + mState = USER_LOADED_FROM_DB; + + if (!mEmailChecked) { mState = USER_EMAIL_NOT_ACTIVATED; } + else if (!mPublicKey) { mState = USER_NO_KEYS; } + else if (!mPrivateKey) { mState = USER_NO_PRIVATE_KEY; } + else { mState = USER_COMPLETE; } + } } diff --git a/src/cpp/model/table/ModelBase.cpp b/src/cpp/model/table/ModelBase.cpp index 9f5737c40..daa340353 100644 --- a/src/cpp/model/table/ModelBase.cpp +++ b/src/cpp/model/table/ModelBase.cpp @@ -136,6 +136,13 @@ namespace model { throw Poco::Exception(message); } + Poco::Data::Statement ModelBase::_loadMultipleFromDB(Poco::Data::Session session, const std::vector fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + { + std::string message = getTableName(); + message += "::_loadMultipleFromDB multi not implemented"; + throw Poco::Exception(message); + } + Poco::DateTime ModelBase::parseElopageDate(std::string dateString) { std::string decodedDateString = ""; diff --git a/src/cpp/model/table/ModelBase.h b/src/cpp/model/table/ModelBase.h index 92ac17bb5..c5123e6cf 100644 --- a/src/cpp/model/table/ModelBase.h +++ b/src/cpp/model/table/ModelBase.h @@ -41,6 +41,8 @@ namespace model { std::vector loadFromDB(const std::string& fieldName, const WhereFieldType& fieldValue, int expectedResults = 0); template size_t loadFromDB(const std::vector& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType = MYSQL_CONDITION_AND); + template + std::vector loadFromDB(const std::vector& fieldNames, const std::vector& fieldValues, MysqlConditionType conditionType = MYSQL_CONDITION_AND, int expectedResults = 0); bool insertIntoDB(bool loadId); bool deleteFromDB(); @@ -58,6 +60,7 @@ namespace model { virtual Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName) = 0; virtual Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); virtual Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); + virtual Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::vector fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); virtual Poco::Data::Statement _insertIntoDB(Poco::Data::Session session) = 0; int mID; @@ -92,7 +95,7 @@ namespace model { { //printf("ModelBase::loadFromDB multi\n"); std::vector results; - return results; + //return results; if (expectedResults > 0) { results.reserve(expectedResults); } @@ -113,6 +116,42 @@ namespace model { return results; } + template + std::vector ModelBase::loadFromDB(const std::vector& fieldNames, const std::vector& fieldValues, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/, int expectedResults/* = 0*/) + { + std::vector results; + + if (fieldNames.size() != fieldValues.size() || fieldNames.size() <= 1) { + lock(); + addError(new Error(getTableName(), "fieldNames and fieldValues size don't match or smaller as 1")); + unlock(); + return results; + } + if (expectedResults > 0) { + results.reserve(expectedResults); + } + auto cm = ConnectionManager::getInstance(); + Poco::Data::Statement select = _loadMultipleFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER), fieldNames, conditionType); + select, Poco::Data::Keywords::into(results);// Poco::Data::Keywords::useRef(fieldValue); + for (auto it = fieldValues.begin(); it != fieldValues.end(); it++) { + select, Poco::Data::Keywords::useRef(*it); + } + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + lock(); + addError(new ParamError(getTableName(), "mysql error by multi selecting", ex.displayText().data())); + for (auto it = fieldNames.begin(); it != fieldNames.end(); it++) { + addError(new ParamError(getTableName(), "field name for select: ", (*it).data())); + } + unlock(); + } + return results; + } + template size_t ModelBase::loadFromDB(const std::vector& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) { diff --git a/src/cpp/model/table/User.cpp b/src/cpp/model/table/User.cpp index c59d8f432..4661bbfad 100644 --- a/src/cpp/model/table/User.cpp +++ b/src/cpp/model/table/User.cpp @@ -20,6 +20,13 @@ namespace model { : mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(passwordHashed), mEmailChecked(false), mLanguageKey(languageKey), mRole(ROLE_NOT_LOADED) { + } + //id, first_name, last_name, email, pubkey, email_checked + User::User(UserTuple tuple) + : ModelBase(tuple.get<0>()), mFirstName(tuple.get<1>()), mLastName(tuple.get<2>()), mEmail(tuple.get<3>()), mPublicKey(tuple.get<4>()), mEmailChecked(tuple.get<5>()), + mPasswordHashed(0), mLanguageKey("de"), mRole(ROLE_NOT_LOADED) + { + } User::~User() @@ -82,6 +89,45 @@ namespace model { return select; } + Poco::Data::Statement User::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + // typedef Poco::Tuple, int> UserTuple; + select << "SELECT id, first_name, last_name, email, pubkey, email_checked FROM " << getTableName() + << " where " << fieldName << " LIKE ?"; + + + return select; + } + + Poco::Data::Statement User::_loadMultipleFromDB(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("User::_loadMultipleFromDB fieldNames empty or contain only one field"); + } + + // typedef Poco::Tuple, int> UserTuple; + select << "SELECT id, first_name, last_name, email, pubkey, email_checked FROM " << getTableName() + << " where " << fieldNames[0] << " LIKE ?"; + if (conditionType == MYSQL_CONDITION_AND) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " AND " << fieldNames[i] << " LIKE ? "; + } + } + else if (conditionType == MYSQL_CONDITION_OR) { + for (int i = 1; i < fieldNames.size(); i++) { + select << " OR " << fieldNames[i] << " LIKE ? "; + } + } + else { + addError(new ParamError("User::_loadMultipleFromDB", "condition type not implemented", conditionType)); + } + + return select; + } + Poco::Data::Statement User::_loadIdFromDB(Poco::Data::Session session) { Poco::Data::Statement select(session); diff --git a/src/cpp/model/table/User.h b/src/cpp/model/table/User.h index 9406cecfb..e9e566455 100644 --- a/src/cpp/model/table/User.h +++ b/src/cpp/model/table/User.h @@ -4,6 +4,7 @@ #include "ModelBase.h" #include "../../SingletonManager/MemoryManager.h" +#include "Poco/Tuple.h" //#include "Poco/Nullable.h" //#include "Poco/Data/LOB.h" @@ -24,12 +25,13 @@ namespace model { USER_FIELDS_LANGUAGE }; - + typedef Poco::Tuple, int> UserTuple; class User : public ModelBase { public: User(); + User(UserTuple tuple); User(const std::string& email, const std::string& first_name, const std::string& last_name, Poco::UInt64 passwordHashed = 0, std::string languageKey = "de"); ~User(); @@ -67,6 +69,8 @@ namespace model { 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 _loadMultipleFromDB(Poco::Data::Session session, const std::vector fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); // insert only with email, first_name, last_name, password if exist and language Poco::Data::Statement _insertIntoDB(Poco::Data::Session session);