diff --git a/backend/src/graphql/inputs/LoginUserInput.ts b/backend/src/graphql/inputs/LoginUserInput.ts index 4a60d00e1..bafa6a851 100644 --- a/backend/src/graphql/inputs/LoginUserInput.ts +++ b/backend/src/graphql/inputs/LoginUserInput.ts @@ -59,6 +59,9 @@ export class UpdateUserInfosArgs { @Field({ nullable: true }) language?: string + @Field({ nullable: true }) + publisherId?: number + @Field({ nullable: true }) password?: string diff --git a/backend/src/graphql/models/User.ts b/backend/src/graphql/models/User.ts index ca7ed9cf2..8fa92fdc3 100644 --- a/backend/src/graphql/models/User.ts +++ b/backend/src/graphql/models/User.ts @@ -17,6 +17,7 @@ export class User { this.username = json.username this.description = json.description this.language = json.language + this.publisherId = json.publisher_id } @Field(() => String) @@ -60,11 +61,10 @@ export class User { /* I suggest to have a group as type here @Field(() => ID) groupId: number - - // what is puvlisherId? - @Field(() => ID) +*/ + // what is publisherId? + @Field(() => Number) publisherId: number - */ @Field(() => KlickTipp) klickTipp: KlickTipp diff --git a/backend/src/graphql/resolvers/UserResolver.ts b/backend/src/graphql/resolvers/UserResolver.ts index c95af2eae..7e618cf42 100644 --- a/backend/src/graphql/resolvers/UserResolver.ts +++ b/backend/src/graphql/resolvers/UserResolver.ts @@ -78,6 +78,7 @@ export class UserResolver { emailType: 2, login_after_register: true, language: language, + publisher_id: 0, } const result = await apiPost(CONFIG.LOGIN_API_URL + 'createUser', payload) if (!result.success) { @@ -131,6 +132,7 @@ export class UserResolver { description, username, language, + publisherId, password, passwordNew, }: UpdateUserInfosArgs, @@ -145,6 +147,7 @@ export class UserResolver { 'User.description': description || undefined, 'User.username': username || undefined, 'User.language': language || undefined, + 'User.publisher_id': publisherId || undefined, 'User.password': passwordNew || undefined, 'User.password_old': password || undefined, }, diff --git a/docu/login_server.api.md b/docu/login_server.api.md index 3682f310e..569f3f426 100644 --- a/docu/login_server.api.md +++ b/docu/login_server.api.md @@ -151,7 +151,7 @@ with: { "email":"max.musterman@gmail.de", "first_name":"Max", - "last_name":"Musterman", + "last_name":"Musterman" , "username": "Maxilein", "description": "Tischler", "emailType": 2, @@ -231,7 +231,8 @@ with: "User.disabled": 0, "User.language": "de", "User.password": "1234", - "User.password_old": "4321" + "User.password_old": "4321", + "User.publisher_id": "1" } } ``` @@ -304,7 +305,8 @@ with: "user.description", "user.disabled", "user.email_checked", - "user.language" + "user.language", + "user.publisher_id" ] } ``` @@ -342,6 +344,7 @@ Return only the fields which are defined in request is in db only saved in state_users so if we delete this entry, validating all transactions is no longer possible. Disabled User cannot login and cannot receive transactions. - `email_checked`: If user has clicked on link in verification email (register), can only transfer gradidos if email_checked is 1 - `language`: Language Key for User, currently 'de' or 'en' +- `publisher_id`: elopage publisher ip - `errors`: array of strings if error occure ## Login by Email Verification Code diff --git a/login_server/skeema/gradido_login/users.sql b/login_server/skeema/gradido_login/users.sql index bedb5c2d4..95b6acec1 100644 --- a/login_server/skeema/gradido_login/users.sql +++ b/login_server/skeema/gradido_login/users.sql @@ -15,6 +15,7 @@ CREATE TABLE `users` ( `language` varchar(4) NOT NULL DEFAULT 'de', `disabled` tinyint DEFAULT '0', `group_id` int unsigned DEFAULT 0, + `publisher_id` int DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp b/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp index b822c22ec..97cb4ea3a 100644 --- a/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp +++ b/login_server/src/cpp/JSONInterface/JsonCreateUser.cpp @@ -23,6 +23,7 @@ Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params) bool login_after_register = false; int emailType; int group_id = 1; + int publisher_id = 0; bool group_was_not_set = false; auto em = EmailManager::getInstance(); @@ -43,6 +44,7 @@ Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params) paramJsonObject->get("emailType").convert(emailType); auto group_id_obj = paramJsonObject->get("group_id"); + auto publisher_id_obj = paramJsonObject->get("publisher_id"); auto username_obj = paramJsonObject->get("username"); auto description_obj = paramJsonObject->get("description"); auto language_obj = paramJsonObject->get("language"); @@ -50,6 +52,9 @@ Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params) if(!group_id_obj.isEmpty()) { group_id_obj.convert(group_id); } + if (!publisher_id_obj.isEmpty()) { + publisher_id_obj.convert(publisher_id); + } if (!username_obj.isEmpty()) { username_obj.convert(username); } @@ -116,6 +121,7 @@ Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params) if (LanguageManager::languageFromString(language) != LANG_NULL) { user_model->setLanguageKey(language); } + user_model->setPublisherId(publisher_id); auto userModel = user->getModel(); Session* session = nullptr; diff --git a/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp b/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp index 3bdafd283..8620c4dc3 100644 --- a/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp +++ b/login_server/src/cpp/JSONInterface/JsonGetUserInfos.cpp @@ -140,6 +140,9 @@ Poco::JSON::Object* JsonGetUserInfos::handle(Poco::Dynamic::Var params) else if (parameterString == "user.language") { jsonUser.set("language", user_model->getLanguageKey()); } + else if (parameterString == "user.publisher_id") { + jsonUser.set("publisher_id", user_model->getPublisherId()); + } } catch (Poco::Exception& ex) { jsonErrorsArray.add("ask parameter invalid"); diff --git a/login_server/src/cpp/JSONInterface/JsonUpdateUserInfos.cpp b/login_server/src/cpp/JSONInterface/JsonUpdateUserInfos.cpp index eb18bf8f7..6ea3ac21d 100644 --- a/login_server/src/cpp/JSONInterface/JsonUpdateUserInfos.cpp +++ b/login_server/src/cpp/JSONInterface/JsonUpdateUserInfos.cpp @@ -170,10 +170,20 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params) } } + else if ("User.publisher_id" == name) { + if (value.isInteger()) { + int publisher_id = 0; + value.convert(publisher_id); + user_model->setPublisherId(publisher_id); + extractet_values++; + } + else { + jsonErrorsArray.add("User.publisher_id isn't a valid integer"); + } + } else if ("User.password" == name && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS) == ServerConfig::UNSECURE_PASSWORD_REQUESTS) { std::string str_val = validateString(value, "User.password", jsonErrorsArray); - if (str_val.size() > 0) { if (!user->hasPassword()) { diff --git a/login_server/src/cpp/model/table/User.cpp b/login_server/src/cpp/model/table/User.cpp index 2b9dba755..6d76b3b9e 100644 --- a/login_server/src/cpp/model/table/User.cpp +++ b/login_server/src/cpp/model/table/User.cpp @@ -15,12 +15,12 @@ namespace model { namespace table { User::User() - : mPasswordHashed(0), mEmailChecked(false), mLanguageKey("de"), mDisabled(false), mRole(ROLE_NOT_LOADED) + : mPasswordHashed(0), mEmailChecked(false), mLanguageKey("de"), mDisabled(false), mPublisherId(0), mRole(ROLE_NOT_LOADED) { } User::User(const std::string& email, const std::string& first_name, const std::string& last_name, int group_id, Poco::UInt64 passwordHashed/* = 0*/, std::string languageKey/* = "de"*/) - : mFirstName(first_name), mLastName(last_name), mPasswordHashed(passwordHashed), mEmailChecked(false), mLanguageKey(languageKey), mDisabled(false), mGroupId(group_id), mRole(ROLE_NOT_LOADED) + : mFirstName(first_name), mLastName(last_name), mPasswordHashed(passwordHashed), mEmailChecked(false), mLanguageKey(languageKey), mDisabled(false), mGroupId(group_id), mPublisherId(0), mRole(ROLE_NOT_LOADED) { setEmail(email); @@ -29,9 +29,9 @@ namespace model { User::User(UserTuple tuple) : ModelBase(tuple.get<0>()), mFirstName(tuple.get<1>()), mLastName(tuple.get<2>()), mEmail(tuple.get<3>()), mUsername(tuple.get<4>()), - mDescription(tuple.get<5>()), - mPublicKey(tuple.get<6>()), mCreated(tuple.get<7>()), mEmailChecked(tuple.get<8>()), mDisabled(tuple.get<9>()), mGroupId(tuple.get<10>()), - mPasswordHashed(0), mLanguageKey("de"), mRole(ROLE_NOT_LOADED) + mDescription(tuple.get<5>()), mPublicKey(tuple.get<6>()), mCreated(tuple.get<7>()), + mEmailChecked(tuple.get<8>()), mDisabled(tuple.get<9>()), mGroupId(tuple.get<10>()), mPublisherId(tuple.get<11>()), + mPasswordHashed(0), mLanguageKey("de"), mRole(ROLE_NOT_LOADED) { } @@ -83,12 +83,13 @@ namespace model { if (mPasswordHashed) { - insert << "INSERT INTO users (email, first_name, last_name, username, description, password, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?,?,?);", - use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mDescription), bind(mPasswordHashed), use(mEmailHash), use(mLanguageKey), use(mGroupId); + insert << "INSERT INTO users (email, first_name, last_name, username, description, password, email_hash, language, group_id, publisher_id) VALUES(?,?,?,?,?,?,?,?,?,?);", + use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mDescription), bind(mPasswordHashed), use(mEmailHash), use(mLanguageKey), use(mGroupId), use(mPublisherId); } else { - insert << "INSERT INTO users (email, first_name, last_name, username, description, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?,?);", - use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mDescription), use(mEmailHash), use(mLanguageKey), use(mGroupId); + insert << "INSERT INTO users (email, first_name, last_name, username, description, email_hash, language, group_id, publisher_id) VALUES(?,?,?,?,?,?,?,?,?);", + use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mDescription), use(mEmailHash), use(mLanguageKey), use(mGroupId), use(mPublisherId); + } return insert; @@ -101,13 +102,14 @@ namespace model { _fieldName = getTableName() + std::string(".id"); } Poco::Data::Statement select(session); - select << "SELECT " << getTableName() << ".id, email, first_name, last_name, username, description, password, pubkey, privkey, email_hash, created, email_checked, language, disabled, group_id, user_roles.role_id " + + select << "SELECT " << getTableName() << ".id, email, first_name, last_name, username, description, password, pubkey, privkey, email_hash, created, email_checked, language, disabled, group_id, publisher_id, 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(mUsername), into(mDescription), into(mPasswordHashed), into(mPublicKey), into(mPrivateKey), into(mEmailHash), into(mCreated), into(mEmailChecked), - into(mLanguageKey), into(mDisabled), into(mGroupId), into(mRole); + into(mLanguageKey), into(mDisabled), into(mGroupId), into(mPublisherId), into(mRole); return select; @@ -117,9 +119,8 @@ namespace model { { Poco::Data::Statement select(session); // typedef Poco::Tuple, int> UserTuple; - select << "SELECT id, first_name, last_name, email, username, description, pubkey, created, email_checked, disabled, group_id FROM " << getTableName() - << " where " << fieldName << " LIKE ?"; - + select << "SELECT id, first_name, last_name, email, username, description, pubkey, created, email_checked, disabled, group_id, publisher_id FROM " << getTableName() + << " where " << fieldName << " LIKE ?"; return select; } @@ -133,8 +134,8 @@ namespace model { } // typedef Poco::Tuple, int> UserTuple; - select << "SELECT id, first_name, last_name, email, username, description, pubkey, created, email_checked, disabled, group_id FROM " << getTableName() - << " where " << fieldNames[0] << " LIKE ?"; + select << "SELECT id, first_name, last_name, email, username, description, pubkey, created, email_checked, disabled, group_id, publisher_id FROM " << getTableName() + << " where " << fieldNames[0] << " LIKE ?"; if (conditionType == MYSQL_CONDITION_AND) { for (int i = 1; i < fieldNames.size(); i++) { select << " AND " << fieldNames[i] << " LIKE ? "; @@ -245,9 +246,8 @@ namespace model { auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); Poco::Data::Statement update(session); - update << "UPDATE users SET first_name = ?, last_name = ?, username = ?, description = ?, disabled = ?, language = ? where id = ?;", - use(mFirstName), use(mLastName), use(mUsername), use(mDescription), use(mDisabled), use(mLanguageKey), use(mID); - + update << "UPDATE users SET first_name = ?, last_name = ?, username = ?, description = ?, disabled = ?, language = ?, publisher_id = ? where id = ?;", + use(mFirstName), use(mLastName), use(mUsername), use(mDescription), use(mDisabled), use(mLanguageKey), use(mPublisherId), use(mID); try { return update.execute(); @@ -317,6 +317,7 @@ namespace model { ss << "language key: " << mLanguageKey << std::endl; ss << "disabled: " << mDisabled << std::endl; ss << "group id: " << std::to_string(mGroupId) << std::endl; + ss << "publisher id: " << std::to_string(mPublisherId) << std::endl; mm->releaseMemory(pubkeyHex); mm->releaseMemory(privkeyHex); @@ -355,7 +356,8 @@ namespace model { ss << "language key: " << mLanguageKey << "
"; ss << "role: " << UserRole::typeToString(getRole()) << "
"; ss << "disabled: " << mDisabled << "
"; - ss << "group_id: " << std::to_string(mGroupId) << std::endl; + ss << "group_id: " << std::to_string(mGroupId) << "
"; + ss << "publisher_id" << std::to_string(mPublisherId) << "
"; mm->releaseMemory(pubkeyHex); mm->releaseMemory(email_hash); @@ -429,6 +431,7 @@ namespace model { userObj.set("ident_hash", DRMakeStringHash(mEmail.data(), mEmail.size())); userObj.set("language", mLanguageKey); userObj.set("disabled", mDisabled); + userObj.set("publisher_id", mPublisherId); try { userObj.set("role", UserRole::typeToString(getRole())); } diff --git a/login_server/src/cpp/model/table/User.h b/login_server/src/cpp/model/table/User.h index 96d85565d..ac756434b 100644 --- a/login_server/src/cpp/model/table/User.h +++ b/login_server/src/cpp/model/table/User.h @@ -30,7 +30,20 @@ namespace model { USER_FIELDS_LANGUAGE }; - typedef Poco::Tuple, Poco::DateTime, int, int, int> UserTuple; + typedef Poco::Tuple< + int, // id + std::string, // first name + std::string, // last name + std::string, // email + std::string, // username + std::string, // description + Poco::Nullable, // public key + Poco::DateTime, // created + int, // check email + int, // disabled + int, // group_id + int // publisher_id + > UserTuple; class User : public ModelBase { @@ -63,6 +76,7 @@ namespace model { inline std::string getNameWithEmailHtml() const { SHARED_LOCK; return mFirstName + " " + mLastName + " <" + mEmail + ">"; } inline const Poco::UInt64 getPasswordHashed() const { SHARED_LOCK; return mPasswordHashed; } inline int getGroupId() const { SHARED_LOCK; return mGroupId; } + inline int getPublisherId() const { SHARED_LOCK; return mPublisherId; } inline RoleType getRole() const { SHARED_LOCK; if (mRole.isNull()) return ROLE_NONE; return static_cast(mRole.value()); } inline const unsigned char* getPublicKey() const { SHARED_LOCK; if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); } MemoryBin* getPublicKeyCopy() const; @@ -93,6 +107,7 @@ namespace model { inline void setLanguageKey(const std::string& languageKey) { UNIQUE_LOCK; mLanguageKey = languageKey; } inline void setDisabled(bool disabled) { UNIQUE_LOCK; mDisabled = disabled; } inline void setGroupId(int groupId) { UNIQUE_LOCK; mGroupId = groupId; } + inline void setPublisherId(int publisherId) { UNIQUE_LOCK; mPublisherId = publisherId; } Poco::JSON::Object getJson(); @@ -126,6 +141,7 @@ namespace model { bool mDisabled; int mGroupId; + int mPublisherId; // from neighbor tables Poco::Nullable mRole;