diff --git a/docu/login_server.api.md b/docu/login_server.api.md index b466be7fc..fb9409cf0 100644 --- a/docu/login_server.api.md +++ b/docu/login_server.api.md @@ -89,6 +89,56 @@ In case of success returns: nginx was wrong configured. - `session_id`: can be also negative +## Check username +### Request +`GET http://localhost/login_api/checkUsername?username=&group_id=` + +`POST http://localhost/login_api/checkUsername` +with +```json +{ + "username": "Maxilein", + "group_id": 1, + "group_alias": "gdd1" +} +``` + +group_id or group_alias, one of both is enough. +group_id is better, because one db request less + +### Response + +If username is not already taken +```json +{ + "state":"success" +} +``` + +If username is already taken +```json +{ + "state":"warning", + "msg":"username already in use" +} +``` + +If only group_alias was given and group with that alias was found in db +```json +{ + "state":"success", + "group_id": 1 +} +``` + +If group_id or group_alias unknown +```json +{ + "state":"error", + "msg": "unknown group" +} +``` + ## Create user Register a new User diff --git a/login_server/src/cpp/JSONInterface/JsonCheckUsername.cpp b/login_server/src/cpp/JSONInterface/JsonCheckUsername.cpp new file mode 100644 index 000000000..cf19ae69d --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonCheckUsername.cpp @@ -0,0 +1,93 @@ +#include "JsonCheckUsername.h" +#include "Poco/URI.h" +#include "controller/User.h" +#include "lib/DataTypeConverter.h" + +Poco::JSON::Object* JsonCheckUsername::handle(Poco::Dynamic::Var params) +{ + std::string username; + int group_id = 0; + std::string group_alias; + + // 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. + + auto username_obj = paramJsonObject->get("username"); + auto group_id_obj = paramJsonObject->get("group_id"); + auto group_alias_obj = paramJsonObject->get("group_alias"); + + try { + paramJsonObject->get("username").convert(username); + + if (!username_obj.isEmpty()) { + username_obj.convert(username); + } + + if (!group_id_obj.isEmpty()) { + group_id_obj.convert(group_id); + } + if (!group_alias_obj.isEmpty()) { + group_alias_obj.convert(group_alias); + } + + } + catch (Poco::Exception& ex) { + return stateError("username not found or invalid"); + } + + } + else if (params.isVector()) { + const Poco::URI::QueryParameters queryParams = params.extract(); + for (auto it = queryParams.begin(); it != queryParams.end(); it++) { + if (it->first == "username") { + username = it->second; + } + else if (it->first == "group_id") { + DataTypeConverter::strToInt(it->second, group_id); + } + else if (it->first == "group_alias") { + group_alias = it->second; + } + } + } + else { + return stateError("format not implemented", std::string(params.type().name())); + } + + if (!group_id && group_alias == "") { + return stateError("no group given"); + } + if (!group_id) { + auto groups = controller::Group::load(group_alias); + if (groups.size() > 1) { + return stateError("group is ambiguous"); + } + if (!groups.size()) { + return stateError("unknown group"); + } + group_id = groups[0]->getModel()->getID(); + } + auto group = controller::Group::load(group_id); + if (group.isNull()) { + return stateError("unknown group"); + } + auto user = controller::User::create(); + user->getModel()->setGroupId(group_id); + if (username == "") { + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "success"); + result->set("group_id", group_id); + return result; + } + if (user->isUsernameAlreadyUsed(username)) { + return stateWarning("username already in use"); + } + return stateSuccess(); + +} \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonCheckUsername.h b/login_server/src/cpp/JSONInterface/JsonCheckUsername.h new file mode 100644 index 000000000..71873a6ac --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonCheckUsername.h @@ -0,0 +1,16 @@ +#ifndef __JSON_INTERFACE_JSON_CHECK_USERNAME_ +#define __JSON_INTERFACE_JSON_CHECK_USERNAME_ + +#include "JsonRequestHandler.h" + +class JsonCheckUsername : public JsonRequestHandler +{ +public: + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_INTERFACE_JSON_CHECK_USERNAME_ \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp index 4f0e10d6f..3f8536a74 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp @@ -7,6 +7,7 @@ #include "JsonAdminEmailVerificationResend.h" #include "JsonCheckSessionState.h" +#include "JsonCheckUsername.h" #include "JsonAppLogin.h" #include "JsonAquireAccessToken.h" #include "JsonCreateTransaction.h" @@ -74,6 +75,9 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c else if (url_first_part == "/checkSessionState") { return new JsonCheckSessionState; } + else if (url_first_part == "/checkUsername") { + return new JsonCheckUsername; + } else if (url_first_part == "/createTransaction") { return new JsonCreateTransaction; } diff --git a/login_server/src/cpp/controller/User.cpp b/login_server/src/cpp/controller/User.cpp index cd71da96b..5c26e3a12 100644 --- a/login_server/src/cpp/controller/User.cpp +++ b/login_server/src/cpp/controller/User.cpp @@ -108,7 +108,9 @@ namespace controller { bool User::isUsernameAlreadyUsed(const std::string& username) { auto db = getModel(); - return db->loadFromDB({ "username", "group_id" }, username, db->getGroupId(), model::table::MYSQL_CONDITION_AND) > 0; + auto results = db->loadMultipleFromDB({ "username", "group_id" }, username, db->getGroupId(), model::table::MYSQL_CONDITION_AND); + return results.size() > 0; + } int User::load(const unsigned char* pubkey_array) diff --git a/login_server/src/cpp/model/table/ModelBase.h b/login_server/src/cpp/model/table/ModelBase.h index 15f08f66c..c769dcfd9 100644 --- a/login_server/src/cpp/model/table/ModelBase.h +++ b/login_server/src/cpp/model/table/ModelBase.h @@ -61,6 +61,12 @@ namespace model { template size_t loadFromDB(const std::vector& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType = MYSQL_CONDITION_AND); + template + std::vector loadMultipleFromDB( + const std::vector& fieldNames, + const T1& field1Value, const T2& field2Value, + MysqlConditionType conditionType = MYSQL_CONDITION_AND); + template std::vector loadMultipleFromDB( const std::vector& fieldNames, @@ -290,6 +296,43 @@ namespace model { return resultCount; } + template + std::vector ModelBase::loadMultipleFromDB( + const std::vector& fieldNames, + const T1& field1Value, const T2& field2Value, + MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) + { + auto cm = ConnectionManager::getInstance(); + std::vector results; + if (fieldNames.size() != 2) { + addError(new Error(getTableName(), "error in loadFromDB with 2 different field values, fieldNames count isn't 2")); + return results; + } + Poco::ScopedLock _lock(mWorkMutex); + + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + Poco::Data::Statement select = _loadMultipleFromDB(session, fieldNames, conditionType); + select, Poco::Data::Keywords::into(results), + Poco::Data::Keywords::useRef(field1Value), Poco::Data::Keywords::useRef(field2Value); + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + lock(); + addError(new ParamError(getTableName(), "mysql error by selecting with 2 different field types", ex.displayText())); + int count = 0; + for (auto it = fieldNames.begin(); it != fieldNames.end(); it++) { + addError(new ParamError(getTableName(), "field name for select: ", *it)); + } + + //addError(new ParamError(getTableName(), "field name for select: ", fieldName.data())); + unlock(); + } + return results; + } + template std::vector ModelBase::loadMultipleFromDB( const std::vector& fieldNames,