Merge pull request #482 from gradido/login_update_json

add new API Call checkUsername
This commit is contained in:
einhornimmond 2021-06-08 16:26:20 +02:00 committed by GitHub
commit 7d2cd44677
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 353 additions and 28 deletions

View File

@ -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=<username>&group_id=<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

View File

@ -170,6 +170,7 @@ FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h")
FILE(GLOB TEST_MODEL "src/cpp/test/model/*.cpp" "src/cpp/test/model/*.h")
FILE(GLOB TEST_MODEL_TABLE "src/cpp/test/model/table/*.cpp" "src/cpp/test/model/table/*.h")
FILE(GLOB TEST_CONTROLLER "src/cpp/test/controller/*.cpp" "src/cpp/test/controller/*.h")
FILE(GLOB TEST_JSON_INTERFACE "src/cpp/test/JSONInterface/*.cpp" "src/cpp/test/JSONInterface/*.h")
SET(LOCAL_SRCS
${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface} ${COMPILED_PAGES}
@ -179,7 +180,7 @@ SET(LOCAL_SRCS
${PROTO_GRADIDO}
)
SET(LOCAL_TEST_SRC
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER}
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER} ${TEST_JSON_INTERFACE}
)
aux_source_directory("src/cpp" LOCAL_SRCS)
@ -204,6 +205,7 @@ if(MSVC)
source_group("Test\\model\\table" FILES ${TEST_MODEL_TABLE})
source_group("Test\\model" FILES ${TEST_MODEL})
source_group("Test\\controller" FILES ${TEST_CONTROLLER})
source_group("Test\\Json-Interface" FILES ${TEST_JSON_INTERFACE})
source_group("Test" FILES ${TEST})
endif()
@ -341,7 +343,7 @@ target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD")
target_link_libraries(Gradido_LoginServer_Test ${GRPC_LIBS} )
if(WIN32)
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} )
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} libmariadb libprotobuf)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS})

View File

@ -2,6 +2,7 @@
Poco/1.9.4@pocoproject/stable
libsodium/1.0.18@bincrafters/stable
boost/1.71.0@conan/stable
gtest/1.10.0
[options]
Poco:enable_pagecompiler=True

View File

@ -0,0 +1,92 @@
#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<Poco::JSON::Object::Ptr>();
/// 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 {
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("Poco Exception", ex.displayText());
}
}
else if (params.isVector()) {
const Poco::URI::QueryParameters queryParams = params.extract<Poco::URI::QueryParameters>();
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();
}

View File

@ -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_

View File

@ -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;
}

View File

@ -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<model::table::UserTuple>({ "username", "group_id" }, username, db->getGroupId(), model::table::MYSQL_CONDITION_AND);
return results.size() > 0;
}
int User::load(const unsigned char* pubkey_array)

View File

@ -61,6 +61,12 @@ namespace model {
template<class T1, class T2>
size_t loadFromDB(const std::vector<std::string>& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType = MYSQL_CONDITION_AND);
template<class Tuple, class T1, class T2>
std::vector<Tuple> loadMultipleFromDB(
const std::vector<std::string>& fieldNames,
const T1& field1Value, const T2& field2Value,
MysqlConditionType conditionType = MYSQL_CONDITION_AND);
template<class Tuple, class T1, class T2, class T3, class T4>
std::vector<Tuple> loadMultipleFromDB(
const std::vector<std::string>& fieldNames,
@ -290,6 +296,43 @@ namespace model {
return resultCount;
}
template<class Tuple, class T1, class T2>
std::vector<Tuple> ModelBase::loadMultipleFromDB(
const std::vector<std::string>& fieldNames,
const T1& field1Value, const T2& field2Value,
MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/)
{
auto cm = ConnectionManager::getInstance();
std::vector<Tuple> 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<Poco::Mutex> _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<class Tuple, class T1, class T2, class T3, class T4>
std::vector<Tuple> ModelBase::loadMultipleFromDB(
const std::vector<std::string>& fieldNames,

View File

@ -0,0 +1,123 @@
#include "gtest/gtest.h"
#include "JSONInterface/JsonCheckUsername.h"
TEST(TestJsonCheckUsername, InvalidGroupAlias)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("group_alias", "robert");
auto result = jsonCall.handle(params);
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "unknown group");
delete result;
}
TEST(TestJsonCheckUsername, InvalidGroupId)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("group_id", "4");
auto result = jsonCall.handle(params);
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "unknown group");
delete result;
}
TEST(TestJsonCheckUsername, ValidGroupAlias)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("group_alias", "gdd1");
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
auto group_id = result->get("group_id");
ASSERT_FALSE(group_id.isEmpty());
ASSERT_TRUE(group_id.isInteger());
int group_id_int = 0;
group_id.convert(group_id_int);
ASSERT_EQ(group_id_int, 1);
delete result;
}
TEST(TestJsonCheckUsername, UsernameWithoutGroup)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "maxi");
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "error");
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "no group given");
delete result;
}
TEST(TestJsonCheckUsername, ExistingUsername)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "Erfinder");
params->set("group_id", 1);
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "warning");
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "username already in use");
}
TEST(TestJsonCheckUsername, NewUsername)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "Maxi");
params->set("group_id", 1);
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
}
TEST(TestJsonCheckUsername, UsernameExistInOtherGroup)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "Erfinder");
params->set("group_id", 2);
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
}

View File

@ -152,46 +152,38 @@ int load(int argc, char* argv[]) {
Profiler timeUsed;
// clean up and fill db
std::string tables[] = {
"hedera_accounts",
"hedera_ids",
"crypto_keys",
"hedera_topics",
std::string tables[] = {
"groups",
"node_servers",
"users"
};
for (int i = 0; i < 7; i++) {
for (int i = 0; i < 2; i++) {
runMysql("TRUNCATE " + tables[i]);
runMysql("ALTER TABLE " + tables[i] + " AUTO_INCREMENT = 1");
}
std::stringstream ss;
ss << "INSERT INTO `hedera_ids` (`id`, `shardNum`, `realmNum`, `num`) VALUES "
<< "(1, 0, 0, 37281), "
<< "(2, 0, 0, 21212), "
<< "(3, 0, 0, 212);";
ss << "INSERT INTO `users` (`id`, `email`, `first_name`, `last_name`, `username`, `password`, `pubkey`, `privkey`, `created`, `email_checked`, `passphrase_shown`, `language`, `disabled`, `group_id`) VALUES "
<< "(1, 'd_schultz32@gmx.de', 'DDD', 'Schultz', 'Diddel', 13134558453895551556, 0x146d3fb9e88abc0fca0b0091c1ab1b32b399be037436f340befa8bf004461889, 0x0dcc08960f45f631fe23bc7ddee0724cedc9ec0c861ce30f5091d20ffd96062d08ca215726fb9bd64860c754772e945eea4cc872ed0a36c7b640e8b0bf7a873ec6765fa510711622341347ce2307b5ce, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), "
<< "(2, 'Jeet_bb@gmail.com', 'Darios', 'Bruder', 'Jeet', 12910944485867375321, 0x952e215a21d4376b4ac252c4bf41e156e1498e1b6b8ccf2a6826d96712f4f461, 0x4d40bf0860655f728312140dc3741e897bc2d13d00ea80a63e2961046a5a7bd8315397dfb488b89377087bc1a5f4f3af8ffdcf203329ae23ba04be7d38ad3852699d90ff1fc00e5b1ca92b64cc59c01f, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), "
<< "(3, 'Tiger_231@yahoo.com', 'Dieter', 'Schultz', 'Tiger', 13528673707291575501, 0xb539944bf6444a2bfc988244f0c0c9dc326452be9b8a2a43fcd90663719f4f6d, 0x5461fda60b719b65ba00bd6298e48410c4cbf0e89deb13cc784ba8978cf047454e8556ee3eddc8487ee835c33a83163bc8d8babbf2a5c431876bc0a0c114ff0a0d6b57baa12cf8f23c64fb642c862db5, '2020-02-20 16:05:45', 1, 0, 'de', 0, 1), "
<< "(4, 'Nikola_Tesla@email.de', 'Nikola', 'Tesla', 'Erfinder', 15522411320147607375, 0x476b059744f08b0995522b484c90f8d2f47d9b59f4b3c96d9dc0ae6ab7b84979, 0x5277bf044cba4fec64e6f4d38da132755b029161231daefc9a7b4692ad37e05cdd88e0a2c2215baf854dd3a813578c214167af1113607e9f999ca848a7598ba5068e38f2a1afb097e4752a88024d79c8, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(5, 'Elfenhausen@arcor.de', 'Thomas', 'Markuk', 'Elf', 7022671043835614958, 0xb1584e169d60a7e771d3a348235dfd7b5f9e8235fcc26090761a0264b0daa6ff, 0xb46fb7110bf91e28f367aa80f84d1bbd639b6f689f4b0aa28c0f71529232df9bf9ee0fb02fa4c1b9f5a6799c82d119e5646f7231d011517379faaacf6513d973ac3043d4c786490ba62d56d75b86164d, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 'Test Username', 1548398919826089202, 0x4046ae49c1b620f2a321aba0c874fa2bc7ba844ab808bb0eeb18a908d468db14, 0x9522657ecd7456eedf86d065aa087ba7a94a8961a8e4950d044136155d38fe0840f2c0a2876ce055b3eaa6e9ab95c5feba89e535e0434fb2648d94d6e6ec68211aa2ea9e42d1ccd40b6b3c31e41f848e, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1), "
<< "(7, 'AlexWesper@gmail.com', 'Alex', 'Wesper', 'Wespe', 5822761891727948301, 0xb13ede3402abb8f29722b14fec0a2006ae7a3a51fb677cd6a2bbd797ac6905a5, 0x6aa39d7670c64a31639c7d89b874ad929b2eaeb2e5992dbad71b6cea700bf9e3c6cf866d0f0fdc22b44a0ebf51a860799e880ef86266199931dd0a301e5552db44b9b7fa99ed5945652bc7b31eff767c, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1); ";
runMysql(ss.str());
ss.str(std::string());
ss << "INSERT INTO `crypto_keys` (`id`, `private_key`, `public_key`, `crypto_key_type_id`) VALUES "
<< "(1, 0x263f1da712c3b47286b463c2de3784f364f2534d2c34722a3b483c3f3e36476857564f564d476c32d3e342f5ef2763cd23e23a2b429bab62e352f46ba273e2f2, 0xfe5237c2d1ab1361b33163f15634e261c1d217ae32b327cbd88db8ebffedb271, 3), "
<< "(2, 0x721f3e73e3263f1da712c3b47286b463c2de3784f364f2534d2c34722a3b483c3f3e36476857564f564d476c32d3e342f5ef2763cd23e23a2b429bab62e352f46ba273e2f2ef3264fe2452da62bc2739, 0xe3f253d1a2deb25362d2e374baf37bc1d3ef3781cfe1e127f3cd0abcdf372ea6, 1); ";
ss << "INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `description`) VALUES"
<< "(1, 'gdd1', 'Gradido1', 'gdd1.gradido.com', 'Der erste offizielle Gradido Server (zum Testen)'), "
<< "(2, 'gdd_test', 'Gradido Test', 'gdd1.gradido.com', 'Testgroup (zum Testen)'); ";
runMysql(ss.str());
ss.str(std::string());
ss << "INSERT INTO `hedera_accounts` (`id`, `user_id`, `account_hedera_id`, `account_key_id`, `balance`, `network_type`, `updated`) VALUES "
<< "(1, 1, 1, 1, 1000000000000, 1, '2019-09-03 11:13:52'), "
<< "(2, 1, 2, 2, 4312881211, 0, '2019-09-03 11:13:56'); ";
runMysql(ss.str());
ss.str(std::string());
ss << "INSERT INTO `hedera_topics` (`id`, `topic_hedera_id`, `name`, `auto_renew_account_hedera_id`, `auto_renew_period`, `group_id`, `admin_key_id`, `submit_key_id`, `current_timeout`, `sequence_number`, `updated`) VALUES "
<< "(1, 3, 'gdd_test_topic', 1, 0, 1, NULL, NULL, '1999-12-31 23:00:00', 0, '2020-09-14 18:29:04'); ";
runMysql(ss.str());
ss.str(std::string());
std::clog << "after inserting everything in db" << std::endl;
printf("init db in : %s\n", timeUsed.string().data());
fillTests();
for (std::list<Test*>::iterator it = gTests.begin(); it != gTests.end(); it++)
{