mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:37:32 +00:00
feat: split users into human and machine (#470)
* feat(management): service accounts * chore: current go version * init * refactor: apis * feat(internal): start impl of service account * chore: start impl of machine/human users * code compiles * fix: tests * fix: tests * fix: add new event types to switches * chore: add cases to event types * fix(management): definitive proto messages * fix: machine/human * fix: add missing tables as todos * fix: remove unused permissions * fix: refactoring * fix: refactor * fix: human registered * fix: user id * fix: logid * fix: proto remove //equal * chore(management): remove no comment * fix: human mfas * fix: user subobjects * chore: rename existing to better name * fix: username in user (#634) * fix: username in user * fix: username * fix remove unused code * fix add validations * fix: use new user in all apis * fix: regexp for username in api * fix: fill user data for human and machine (#638) * fix: fill Display name grant/member handlers fix: add description to grant/member objects in api fix: check if user is human in login * fix: remove description from member and grant * chore: remove todos * feat: machine keys * fix: implement missing parts * feat: machine key management view * fix: remove keys from machine view * fix: set default expiration date * fix: get key by ids * feat: add machine keys in proto * feat: machine keys * fix: add migration * fix: mig * fix: correct method name * feat: user search * feat: user search * fix: log ids * fix partial authconfig prompt, domain c perm * membership read check * contributor refresh trigger, observe org write * fix: migrations * fix(console): machine build (#660) * frontend 1 * fix html bindings * trailing comma * user permissions, project deactivate * fix(console): human view (#661) * fix search user view, user detail form * rm log * feat(console): user services list and create (#663) * fix search user view, user detail form * rm log * machine list * generic table component * create user service * proove table for undefined values * tmp disable user link if machine * lint * lint styles * user table lint * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <florian@caos.ch> * feat(console): service user detail view, keys cr_d, fix search user autocomplete (#664) * service users for sidenav, routing * i18n * back routes * machine detail form * update machine detail, fix svc user grants * keys table * add key dialog, timestamp creation * check permission on create, delete, fix selection * lint ts, scss * Update console/src/assets/i18n/de.json * Apply suggestions from code review Co-authored-by: Florian Forster <florian@caos.ch> * allow user grants for project.write * management service * fix mgmt service * feat: Machine keys (#655) * fix: memberships (#633) * feat: add iam members to memberships * fix: search project grants * fix: rename * feat: idp and login policy configurations (#619) * feat: oidc config * fix: oidc configurations * feat: oidc idp config * feat: add oidc config test * fix: tests * fix: tests * feat: translate new events * feat: idp eventstore * feat: idp eventstore * fix: tests * feat: command side idp * feat: query side idp * feat: idp config on org * fix: tests * feat: authz idp on org * feat: org idps * feat: login policy * feat: login policy * feat: login policy * feat: add idp func on login policy * feat: add validation to loginpolicy and idp provider * feat: add default login policy * feat: login policy on org * feat: login policy on org * fix: id config handlers * fix: id config handlers * fix: create idp on org * fix: create idp on org * fix: not existing idp config * fix: default login policy * fix: add login policy on org * fix: idp provider search on org * fix: test * fix: remove idp on org * fix: test * fix: test * fix: remove admin idp * fix: logo src as byte * fix: migration * fix: tests * Update internal/iam/repository/eventsourcing/iam.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/iam_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/iam_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/org/repository/eventsourcing/org_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: pr comments * fix: tests * Update types.go * fix: merge request changes * fix: reduce optimization Co-authored-by: Silvan <silvan.reusser@gmail.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix: reread user mfas, preferred loginname as otp account name (#636) * fix: reread user mfas * fix: use preferred login name as otp account name * fix: tests * fix: reduce (#635) * fix: management reduce optimization * fix: reduce optimization * fix: reduce optimization * fix: merge master * chore(deps): bump github.com/gorilla/schema from 1.1.0 to 1.2.0 (#627) Bumps [github.com/gorilla/schema](https://github.com/gorilla/schema) from 1.1.0 to 1.2.0. - [Release notes](https://github.com/gorilla/schema/releases) - [Commits](https://github.com/gorilla/schema/compare/v1.1.0...v1.2.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump github.com/gorilla/mux from 1.7.4 to 1.8.0 (#624) Bumps [github.com/gorilla/mux](https://github.com/gorilla/mux) from 1.7.4 to 1.8.0. - [Release notes](https://github.com/gorilla/mux/releases) - [Commits](https://github.com/gorilla/mux/compare/v1.7.4...v1.8.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump github.com/DATA-DOG/go-sqlmock from 1.4.1 to 1.5.0 (#591) Bumps [github.com/DATA-DOG/go-sqlmock](https://github.com/DATA-DOG/go-sqlmock) from 1.4.1 to 1.5.0. - [Release notes](https://github.com/DATA-DOG/go-sqlmock/releases) - [Commits](https://github.com/DATA-DOG/go-sqlmock/compare/v1.4.1...v1.5.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: auto assign issues and PR to ZTIADEL project board (#643) * Create main.yml * Update main.yml Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix(console): project grant members, update deps (#645) * fix: searchprojectgrantmembers * chore(deps-dev): bump @angular/cli from 10.0.6 to 10.0.7 in /console (#622) Bumps [@angular/cli](https://github.com/angular/angular-cli) from 10.0.6 to 10.0.7. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/compare/v10.0.6...v10.0.7) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular-devkit/build-angular in /console (#626) Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1000.6 to 0.1000.7. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/commits) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> * chore(deps-dev): bump @types/jasmine from 3.5.12 to 3.5.13 in /console (#623) Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.5.12 to 3.5.13. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump ts-node from 8.10.2 to 9.0.0 in /console (#629) Bumps [ts-node](https://github.com/TypeStrong/ts-node) from 8.10.2 to 9.0.0. - [Release notes](https://github.com/TypeStrong/ts-node/releases) - [Commits](https://github.com/TypeStrong/ts-node/compare/v8.10.2...v9.0.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * update packlock Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: delete main.yml (#648) * fix: usergrant (#650) * fix(console): mfa refresh after verification, member eventemitter (#651) * refresh mfa * fix: detail link from contributors * lint * feat: add domain verification notification (#649) * fix: dont (re)generate client secret with auth type none * fix(cors): allow Origin from request * feat: add origin allow list and fix some core issues * rename migration * fix UserIDsByDomain * feat: send email to users after domain claim * username * check origin on userinfo * update oidc pkg * fix: add migration 1.6 * change username * change username * remove unique email aggregate * change username in mgmt * search global user by login name * fix test * change user search in angular * fix tests * merge * userview in angular * fix merge * Update pkg/grpc/management/proto/management.proto Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update internal/notification/static/i18n/de.yaml Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * fix Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * fix: translation (#647) * fix: translation * fix: translation * fix: translation * fix: remove unused code * fix: log err * fix: migration numbers (#652) * chore: issue / feature templates (#642) * feat: machine keys * fix: implement missing parts * feat: machine key management view * fix: remove keys from machine view * feat: global org read (#657) * fix: set default expiration date * fix: get key by ids * feat: add machine keys in proto * feat: machine keys * fix: add migration * fix: mig * fix: correct method name * feat: user search * feat: user search * fix: log ids * fix: migrations * fix(console): machine build (#660) * frontend 1 * fix html bindings * trailing comma * fix(console): human view (#661) * fix search user view, user detail form * rm log * feat(console): user services list and create (#663) * fix search user view, user detail form * rm log * machine list * generic table component * create user service * proove table for undefined values * tmp disable user link if machine * lint * lint styles * user table lint * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <florian@caos.ch> * feat(console): service user detail view, keys cr_d, fix search user autocomplete (#664) * service users for sidenav, routing * i18n * back routes * machine detail form * update machine detail, fix svc user grants * keys table * add key dialog, timestamp creation * check permission on create, delete, fix selection * lint ts, scss * Update console/src/assets/i18n/de.json * Apply suggestions from code review Co-authored-by: Florian Forster <florian@caos.ch> * refactor: protos * fix(management): key expiration date * fix: check if user is human * fix: marshal key details * fix: correct generate login names * fix: logid Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com> Co-authored-by: Florian Forster <florian@caos.ch> * fix: naming * refactor: findings * fix: username * fix: mfa upper case * fix: tests * fix: add translations * reactivatemyorg req typeö * fix: projectType for console * fix: user changes * fix: translate events * fix: event type translation * fix: remove unused types Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Florian Forster <florian@caos.ch> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
53
internal/user/model/machine_key.go
Normal file
53
internal/user/model/machine_key.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
)
|
||||
|
||||
type MachineKeyView struct {
|
||||
ID string
|
||||
UserID string
|
||||
Type MachineKeyType
|
||||
Sequence uint64
|
||||
CreationDate time.Time
|
||||
ExpirationDate time.Time
|
||||
}
|
||||
|
||||
type MachineKeySearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn MachineKeySearchKey
|
||||
Asc bool
|
||||
Queries []*MachineKeySearchQuery
|
||||
}
|
||||
|
||||
type MachineKeySearchKey int32
|
||||
|
||||
const (
|
||||
MachineKeyKeyUnspecified MachineKeySearchKey = iota
|
||||
MachineKeyKeyID
|
||||
MachineKeyKeyUserID
|
||||
)
|
||||
|
||||
type MachineKeySearchQuery struct {
|
||||
Key MachineKeySearchKey
|
||||
Method model.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type MachineKeySearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*MachineKeyView
|
||||
Sequence uint64
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func (r *MachineKeySearchRequest) EnsureLimit(limit uint64) {
|
||||
if r.Limit == 0 || r.Limit > limit {
|
||||
r.Limit = limit
|
||||
}
|
||||
}
|
@@ -8,7 +8,6 @@ import (
|
||||
type Profile struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
UserName string
|
||||
FirstName string
|
||||
LastName string
|
||||
NickName string
|
||||
|
@@ -1,51 +1,21 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
policy_model "github.com/caos/zitadel/internal/policy/model"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
es_models.ObjectRoot
|
||||
State UserState
|
||||
UserName string
|
||||
|
||||
State UserState
|
||||
*Password
|
||||
*Profile
|
||||
*Email
|
||||
*Phone
|
||||
*Address
|
||||
InitCode *InitUserCode
|
||||
EmailCode *EmailCode
|
||||
PhoneCode *PhoneCode
|
||||
PasswordCode *PasswordCode
|
||||
OTP *OTP
|
||||
}
|
||||
type UserChanges struct {
|
||||
Changes []*UserChange
|
||||
LastSequence uint64
|
||||
}
|
||||
|
||||
type UserChange struct {
|
||||
ChangeDate *timestamp.Timestamp `json:"changeDate,omitempty"`
|
||||
EventType string `json:"eventType,omitempty"`
|
||||
Sequence uint64 `json:"sequence,omitempty"`
|
||||
ModifierId string `json:"modifierUser,omitempty"`
|
||||
ModifierName string `json:"-"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type InitUserCode struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
Code *crypto.CryptoValue
|
||||
Expiry time.Duration
|
||||
*Human
|
||||
*Machine
|
||||
}
|
||||
|
||||
type UserState int32
|
||||
@@ -60,15 +30,6 @@ const (
|
||||
UserStateInitial
|
||||
)
|
||||
|
||||
type Gender int32
|
||||
|
||||
const (
|
||||
GenderUnspecified Gender = iota
|
||||
GenderFemale
|
||||
GenderMale
|
||||
GenderDiverse
|
||||
)
|
||||
|
||||
func (u *User) CheckOrgIAMPolicy(policy *org_model.OrgIAMPolicy) error {
|
||||
if policy == nil {
|
||||
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil")
|
||||
@@ -88,12 +49,18 @@ func (u *User) SetNamesAsDisplayname() {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) IsValid() bool {
|
||||
return u.Profile != nil && u.FirstName != "" && u.LastName != "" && u.UserName != "" && u.Email != nil && u.Email.IsValid() && u.Phone == nil || (u.Phone != nil && u.Phone.IsValid())
|
||||
type UserChanges struct {
|
||||
Changes []*UserChange
|
||||
LastSequence uint64
|
||||
}
|
||||
|
||||
func (u *User) IsInitialState() bool {
|
||||
return u.Email == nil || !u.IsEmailVerified || u.Password == nil || u.SecretString == ""
|
||||
type UserChange struct {
|
||||
ChangeDate *timestamp.Timestamp `json:"changeDate,omitempty"`
|
||||
EventType string `json:"eventType,omitempty"`
|
||||
Sequence uint64 `json:"sequence,omitempty"`
|
||||
ModifierID string `json:"modifierUser,omitempty"`
|
||||
ModifierName string `json:"-"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (u *User) IsActive() bool {
|
||||
@@ -112,47 +79,25 @@ func (u *User) IsLocked() bool {
|
||||
return u.State == UserStateLocked
|
||||
}
|
||||
|
||||
func (u *User) IsOTPReady() bool {
|
||||
return u.OTP != nil && u.OTP.State == MfaStateReady
|
||||
func (u *User) IsValid() bool {
|
||||
if u.Human == nil && u.Machine == nil || u.UserName == "" {
|
||||
return false
|
||||
}
|
||||
if u.Human != nil {
|
||||
return u.Human.IsValid()
|
||||
}
|
||||
return u.Machine.IsValid()
|
||||
}
|
||||
|
||||
func (u *User) HashPasswordIfExisting(policy *policy_model.PasswordComplexityPolicy, passwordAlg crypto.HashAlgorithm, onetime bool) error {
|
||||
if u.Password != nil {
|
||||
return u.Password.HashPasswordIfExisting(policy, passwordAlg, onetime)
|
||||
func (u *User) CheckOrgIamPolicy(policy *org_model.OrgIAMPolicy) error {
|
||||
if policy == nil {
|
||||
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil")
|
||||
}
|
||||
if policy.UserLoginMustBeDomain && strings.Contains(u.UserName, "@") {
|
||||
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed")
|
||||
}
|
||||
if !policy.UserLoginMustBeDomain && u.Profile != nil && u.UserName == "" && u.Email != nil {
|
||||
u.UserName = u.EmailAddress
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) GenerateInitCodeIfNeeded(initGenerator crypto.Generator) error {
|
||||
if !u.IsInitialState() {
|
||||
return nil
|
||||
}
|
||||
u.InitCode = new(InitUserCode)
|
||||
return u.InitCode.GenerateInitUserCode(initGenerator)
|
||||
}
|
||||
|
||||
func (u *User) GeneratePhoneCodeIfNeeded(phoneGenerator crypto.Generator) error {
|
||||
if u.Phone == nil || u.IsPhoneVerified {
|
||||
return nil
|
||||
}
|
||||
u.PhoneCode = new(PhoneCode)
|
||||
return u.PhoneCode.GeneratePhoneCode(phoneGenerator)
|
||||
}
|
||||
|
||||
func (u *User) GenerateEmailCodeIfNeeded(emailGenerator crypto.Generator) error {
|
||||
if u.Email == nil || u.IsEmailVerified {
|
||||
return nil
|
||||
}
|
||||
u.EmailCode = new(EmailCode)
|
||||
return u.EmailCode.GenerateEmailCode(emailGenerator)
|
||||
}
|
||||
|
||||
func (init *InitUserCode) GenerateInitUserCode(generator crypto.Generator) error {
|
||||
initCodeCrypto, _, err := crypto.NewCode(generator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
init.Code = initCodeCrypto
|
||||
init.Expiry = generator.Expiry()
|
||||
return nil
|
||||
}
|
||||
|
98
internal/user/model/user_human.go
Normal file
98
internal/user/model/user_human.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
policy_model "github.com/caos/zitadel/internal/policy/model"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type Human struct {
|
||||
*Password
|
||||
*Profile
|
||||
*Email
|
||||
*Phone
|
||||
*Address
|
||||
InitCode *InitUserCode
|
||||
EmailCode *EmailCode
|
||||
PhoneCode *PhoneCode
|
||||
PasswordCode *PasswordCode
|
||||
OTP *OTP
|
||||
}
|
||||
|
||||
type InitUserCode struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
Code *crypto.CryptoValue
|
||||
Expiry time.Duration
|
||||
}
|
||||
|
||||
type Gender int32
|
||||
|
||||
const (
|
||||
GenderUnspecified Gender = iota
|
||||
GenderFemale
|
||||
GenderMale
|
||||
GenderDiverse
|
||||
)
|
||||
|
||||
func (u *Human) SetNamesAsDisplayname() {
|
||||
if u.Profile != nil && u.DisplayName == "" && u.FirstName != "" && u.LastName != "" {
|
||||
u.DisplayName = u.FirstName + " " + u.LastName
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Human) IsValid() bool {
|
||||
return u.Profile != nil && u.FirstName != "" && u.LastName != "" && u.Email != nil && u.Email.IsValid() && u.Phone == nil || (u.Phone != nil && u.Phone.IsValid())
|
||||
}
|
||||
|
||||
func (u *Human) IsInitialState() bool {
|
||||
return u.Email == nil || !u.IsEmailVerified || u.Password == nil || u.SecretString == ""
|
||||
}
|
||||
|
||||
func (u *Human) IsOTPReady() bool {
|
||||
return u.OTP != nil && u.OTP.State == MfaStateReady
|
||||
}
|
||||
|
||||
func (u *Human) HashPasswordIfExisting(policy *policy_model.PasswordComplexityPolicy, passwordAlg crypto.HashAlgorithm, onetime bool) error {
|
||||
if u.Password != nil {
|
||||
return u.Password.HashPasswordIfExisting(policy, passwordAlg, onetime)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Human) GenerateInitCodeIfNeeded(initGenerator crypto.Generator) error {
|
||||
if !u.IsInitialState() {
|
||||
return nil
|
||||
}
|
||||
u.InitCode = new(InitUserCode)
|
||||
return u.InitCode.GenerateInitUserCode(initGenerator)
|
||||
}
|
||||
|
||||
func (u *Human) GeneratePhoneCodeIfNeeded(phoneGenerator crypto.Generator) error {
|
||||
if u.Phone == nil || u.IsPhoneVerified {
|
||||
return nil
|
||||
}
|
||||
u.PhoneCode = new(PhoneCode)
|
||||
return u.PhoneCode.GeneratePhoneCode(phoneGenerator)
|
||||
}
|
||||
|
||||
func (u *Human) GenerateEmailCodeIfNeeded(emailGenerator crypto.Generator) error {
|
||||
if u.Email == nil || u.IsEmailVerified {
|
||||
return nil
|
||||
}
|
||||
u.EmailCode = new(EmailCode)
|
||||
return u.EmailCode.GenerateEmailCode(emailGenerator)
|
||||
}
|
||||
|
||||
func (init *InitUserCode) GenerateInitUserCode(generator crypto.Generator) error {
|
||||
initCodeCrypto, _, err := crypto.NewCode(generator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
init.Code = initCodeCrypto
|
||||
init.Expiry = generator.Expiry()
|
||||
return nil
|
||||
}
|
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
func TestIsUserValid(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -17,9 +17,8 @@ func TestIsUserValid(t *testing.T) {
|
||||
{
|
||||
name: "user with minimal data",
|
||||
args: args{
|
||||
user: &User{
|
||||
user: &Human{
|
||||
Profile: &Profile{
|
||||
UserName: "UserName",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
},
|
||||
@@ -33,9 +32,8 @@ func TestIsUserValid(t *testing.T) {
|
||||
{
|
||||
name: "user with phone data",
|
||||
args: args{
|
||||
user: &User{
|
||||
user: &Human{
|
||||
Profile: &Profile{
|
||||
UserName: "UserName",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
},
|
||||
@@ -52,9 +50,8 @@ func TestIsUserValid(t *testing.T) {
|
||||
{
|
||||
name: "user with address data",
|
||||
args: args{
|
||||
user: &User{
|
||||
user: &Human{
|
||||
Profile: &Profile{
|
||||
UserName: "UserName",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
},
|
||||
@@ -74,9 +71,8 @@ func TestIsUserValid(t *testing.T) {
|
||||
{
|
||||
name: "user with all data",
|
||||
args: args{
|
||||
user: &User{
|
||||
user: &Human{
|
||||
Profile: &Profile{
|
||||
UserName: "UserName",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
},
|
34
internal/user/model/user_machine.go
Normal file
34
internal/user/model/user_machine.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type Machine struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
func (sa *Machine) IsValid() bool {
|
||||
return sa.Name != ""
|
||||
}
|
||||
|
||||
type MachineKey struct {
|
||||
models.ObjectRoot
|
||||
|
||||
KeyID string
|
||||
Type MachineKeyType
|
||||
ExpirationDate time.Time
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
type MachineKeyType int32
|
||||
|
||||
const (
|
||||
MachineKeyTypeNONE = iota
|
||||
MachineKeyTypeJSON
|
||||
)
|
@@ -3,28 +3,33 @@ package model
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
req_model "github.com/caos/zitadel/internal/auth_request/model"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type UserView struct {
|
||||
ID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
State UserState
|
||||
ResourceOwner string
|
||||
ID string
|
||||
UserName string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
State UserState
|
||||
Sequence uint64
|
||||
ResourceOwner string
|
||||
LastLogin time.Time
|
||||
PreferredLoginName string
|
||||
LoginNames []string
|
||||
*MachineView
|
||||
*HumanView
|
||||
}
|
||||
|
||||
type HumanView struct {
|
||||
PasswordSet bool
|
||||
PasswordChangeRequired bool
|
||||
UsernameChangeRequired bool
|
||||
PasswordChanged time.Time
|
||||
LastLogin time.Time
|
||||
UserName string
|
||||
PreferredLoginName string
|
||||
LoginNames []string
|
||||
FirstName string
|
||||
LastName string
|
||||
NickName string
|
||||
@@ -44,7 +49,12 @@ type UserView struct {
|
||||
MfaMaxSetUp req_model.MfaLevel
|
||||
MfaInitSkipped time.Time
|
||||
InitRequired bool
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
type MachineView struct {
|
||||
LastKeyAdded time.Time
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
type UserSearchRequest struct {
|
||||
@@ -69,6 +79,7 @@ const (
|
||||
UserSearchKeyState
|
||||
UserSearchKeyResourceOwner
|
||||
UserSearchKeyLoginNames
|
||||
UserSearchKeyType
|
||||
)
|
||||
|
||||
type UserSearchQuery struct {
|
||||
@@ -130,7 +141,10 @@ func (u *UserView) MfaTypesAllowed(level req_model.MfaLevel) []req_model.MfaType
|
||||
return types
|
||||
}
|
||||
|
||||
func (u *UserView) GetProfile() *Profile {
|
||||
func (u *UserView) GetProfile() (*Profile, error) {
|
||||
if u.HumanView == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-WLTce", "Errors.User.NotHuman")
|
||||
}
|
||||
return &Profile{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: u.ID,
|
||||
@@ -139,7 +153,6 @@ func (u *UserView) GetProfile() *Profile {
|
||||
CreationDate: u.CreationDate,
|
||||
ChangeDate: u.ChangeDate,
|
||||
},
|
||||
UserName: u.UserName,
|
||||
FirstName: u.FirstName,
|
||||
LastName: u.LastName,
|
||||
NickName: u.NickName,
|
||||
@@ -148,10 +161,13 @@ func (u *UserView) GetProfile() *Profile {
|
||||
Gender: u.Gender,
|
||||
PreferredLoginName: u.PreferredLoginName,
|
||||
LoginNames: u.LoginNames,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *UserView) GetPhone() *Phone {
|
||||
func (u *UserView) GetPhone() (*Phone, error) {
|
||||
if u.HumanView == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-him4a", "Errors.User.NotHuman")
|
||||
}
|
||||
return &Phone{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: u.ID,
|
||||
@@ -162,10 +178,13 @@ func (u *UserView) GetPhone() *Phone {
|
||||
},
|
||||
PhoneNumber: u.Phone,
|
||||
IsPhoneVerified: u.IsPhoneVerified,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *UserView) GetEmail() *Email {
|
||||
func (u *UserView) GetEmail() (*Email, error) {
|
||||
if u.HumanView == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-PWd6K", "Errors.User.NotHuman")
|
||||
}
|
||||
return &Email{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: u.ID,
|
||||
@@ -176,10 +195,13 @@ func (u *UserView) GetEmail() *Email {
|
||||
},
|
||||
EmailAddress: u.Email,
|
||||
IsEmailVerified: u.IsEmailVerified,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *UserView) GetAddress() *Address {
|
||||
func (u *UserView) GetAddress() (*Address, error) {
|
||||
if u.HumanView == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-DN61m", "Errors.User.NotHuman")
|
||||
}
|
||||
return &Address{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: u.ID,
|
||||
@@ -193,5 +215,5 @@ func (u *UserView) GetAddress() *Address {
|
||||
PostalCode: u.PostalCode,
|
||||
Region: u.Region,
|
||||
StreetAddress: u.StreetAddress,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
@@ -19,9 +19,9 @@ func StartCache(conf *config.CacheConfig) (*UserCache, error) {
|
||||
return &UserCache{userCache: userCache}, nil
|
||||
}
|
||||
|
||||
func (c *UserCache) getUser(ID string) *model.User {
|
||||
user := &model.User{ObjectRoot: models.ObjectRoot{AggregateID: ID}}
|
||||
if err := c.userCache.Get(ID, user); err != nil {
|
||||
func (c *UserCache) getUser(id string) *model.User {
|
||||
user := &model.User{ObjectRoot: models.ObjectRoot{AggregateID: id}}
|
||||
if err := c.userCache.Get(id, user); err != nil {
|
||||
logging.Log("EVENT-AtS0S").WithError(err).Debug("error in getting cache")
|
||||
}
|
||||
return user
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -69,7 +69,7 @@ func GetMockPwGenerator(ctrl *gomock.Controller) crypto.Generator {
|
||||
func GetMockUserByIDOK(ctrl *gomock.Controller, user model.User) *UserEventstore {
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -85,13 +85,16 @@ func GetMockUserByIDNoEvents(ctrl *gomock.Controller) *UserEventstore {
|
||||
|
||||
func GetMockManipulateUser(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
UserName: "UserName",
|
||||
Human: &model.Human{
|
||||
Profile: &model.Profile{
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -101,9 +104,9 @@ func GetMockManipulateUser(ctrl *gomock.Controller) *UserEventstore {
|
||||
}
|
||||
|
||||
func GetMockManipulateUserWithPWGenerator(ctrl *gomock.Controller, init, email, phone, password bool) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
Email: &model.Email{
|
||||
EmailAddress: "EmailAddress",
|
||||
@@ -114,7 +117,7 @@ func GetMockManipulateUserWithPWGenerator(ctrl *gomock.Controller, init, email,
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -126,7 +129,7 @@ func GetMockManipulateUserWithPWGenerator(ctrl *gomock.Controller, init, email,
|
||||
func GetMockManipulateUserWithInitCodeGen(ctrl *gomock.Controller, user model.User) *UserEventstore {
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -138,7 +141,7 @@ func GetMockManipulateUserWithInitCodeGen(ctrl *gomock.Controller, user model.Us
|
||||
func GetMockManipulateUserWithPasswordInitCodeGen(ctrl *gomock.Controller, user model.User) *UserEventstore {
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
&es_models.Event{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -150,7 +153,7 @@ func GetMockManipulateUserWithPasswordInitCodeGen(ctrl *gomock.Controller, user
|
||||
func GetMockManipulateUserWithPasswordAndEmailCodeGen(ctrl *gomock.Controller, user model.User) *UserEventstore {
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -162,7 +165,7 @@ func GetMockManipulateUserWithPasswordAndEmailCodeGen(ctrl *gomock.Controller, u
|
||||
func GetMockManipulateUserWithEmailCodeGen(ctrl *gomock.Controller, user model.User) *UserEventstore {
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -174,7 +177,7 @@ func GetMockManipulateUserWithEmailCodeGen(ctrl *gomock.Controller, user model.U
|
||||
func GetMockManipulateUserWithPhoneCodeGen(ctrl *gomock.Controller, user model.User) *UserEventstore {
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -187,8 +190,8 @@ func GetMockManipulateUserWithPasswordCodeGen(ctrl *gomock.Controller, user mode
|
||||
data, _ := json.Marshal(user)
|
||||
code, _ := json.Marshal(user.PasswordCode)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserPasswordCodeAdded, Data: code},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserPasswordCodeAdded, Data: code},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -199,13 +202,16 @@ func GetMockManipulateUserWithPasswordCodeGen(ctrl *gomock.Controller, user mode
|
||||
|
||||
func GetMockManipulateUserWithOTPGen(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
UserName: "UserName",
|
||||
Human: &model.Human{
|
||||
Profile: &model.Profile{
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -224,15 +230,15 @@ func GetMockManipulateUserWithOTPGen(ctrl *gomock.Controller) *UserEventstore {
|
||||
}
|
||||
|
||||
func GetMockManipulateInactiveUser(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 2, Type: model.UserDeactivated},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 2, Type: model.UserDeactivated},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -242,15 +248,15 @@ func GetMockManipulateInactiveUser(ctrl *gomock.Controller) *UserEventstore {
|
||||
}
|
||||
|
||||
func GetMockManipulateLockedUser(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserLocked},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserLocked},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -269,8 +275,8 @@ func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller, user model.User)
|
||||
dataUser, _ := json.Marshal(user)
|
||||
dataCode, _ := json.Marshal(code)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.InitializedUserCodeAdded, Data: dataCode},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.InitializedUserCodeAdded, Data: dataCode},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -280,9 +286,9 @@ func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller, user model.User)
|
||||
}
|
||||
|
||||
func GetMockManipulateUserWithEmailCode(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
Email: &model.Email{
|
||||
EmailAddress: "EmailAddress",
|
||||
@@ -297,8 +303,8 @@ func GetMockManipulateUserWithEmailCode(ctrl *gomock.Controller) *UserEventstore
|
||||
dataUser, _ := json.Marshal(user)
|
||||
dataCode, _ := json.Marshal(code)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserEmailCodeAdded, Data: dataCode},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserEmailCodeAdded, Data: dataCode},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -307,9 +313,9 @@ func GetMockManipulateUserWithEmailCode(ctrl *gomock.Controller) *UserEventstore
|
||||
return GetMockedEventstoreWithPw(ctrl, mockEs, false, true, false, false)
|
||||
}
|
||||
func GetMockManipulateUserVerifiedEmail(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
Email: &model.Email{
|
||||
EmailAddress: "EmailAddress",
|
||||
@@ -317,8 +323,8 @@ func GetMockManipulateUserVerifiedEmail(ctrl *gomock.Controller) *UserEventstore
|
||||
}
|
||||
dataUser, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserEmailVerified},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserEmailVerified},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -328,9 +334,9 @@ func GetMockManipulateUserVerifiedEmail(ctrl *gomock.Controller) *UserEventstore
|
||||
}
|
||||
|
||||
func GetMockManipulateUserWithPhoneCode(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
Phone: &model.Phone{
|
||||
PhoneNumber: "PhoneNumber",
|
||||
@@ -345,8 +351,8 @@ func GetMockManipulateUserWithPhoneCode(ctrl *gomock.Controller) *UserEventstore
|
||||
dataUser, _ := json.Marshal(user)
|
||||
dataCode, _ := json.Marshal(code)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserPhoneCodeAdded, Data: dataCode},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserPhoneCodeAdded, Data: dataCode},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -356,9 +362,9 @@ func GetMockManipulateUserWithPhoneCode(ctrl *gomock.Controller) *UserEventstore
|
||||
}
|
||||
|
||||
func GetMockManipulateUserVerifiedPhone(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
Phone: &model.Phone{
|
||||
PhoneNumber: "PhoneNumber",
|
||||
@@ -366,8 +372,8 @@ func GetMockManipulateUserVerifiedPhone(ctrl *gomock.Controller) *UserEventstore
|
||||
}
|
||||
dataUser, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserPhoneVerified},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserPhoneVerified},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -377,11 +383,11 @@ func GetMockManipulateUserVerifiedPhone(ctrl *gomock.Controller) *UserEventstore
|
||||
}
|
||||
|
||||
func GetMockManipulateUserFull(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
DisplayName: "DisplayName",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
},
|
||||
Password: &model.Password{
|
||||
Secret: &crypto.CryptoValue{Algorithm: "bcrypt", KeyID: "KeyID"},
|
||||
@@ -399,7 +405,7 @@ func GetMockManipulateUserFull(ctrl *gomock.Controller) *UserEventstore {
|
||||
}
|
||||
dataUser, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -409,9 +415,9 @@ func GetMockManipulateUserFull(ctrl *gomock.Controller) *UserEventstore {
|
||||
}
|
||||
|
||||
func GetMockManipulateUserWithOTP(ctrl *gomock.Controller, decrypt, verified bool) *UserEventstore {
|
||||
user := model.User{
|
||||
user := model.Human{
|
||||
Profile: &model.Profile{
|
||||
UserName: "UserName",
|
||||
DisplayName: "DisplayName",
|
||||
},
|
||||
}
|
||||
otp := model.OTP{
|
||||
@@ -425,11 +431,11 @@ func GetMockManipulateUserWithOTP(ctrl *gomock.Controller, decrypt, verified boo
|
||||
dataUser, _ := json.Marshal(user)
|
||||
dataOtp, _ := json.Marshal(otp)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.MfaOtpAdded, Data: dataOtp},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.UserAdded, Data: dataUser},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.MFAOTPAdded, Data: dataOtp},
|
||||
}
|
||||
if verified {
|
||||
events = append(events, &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.MfaOtpVerified})
|
||||
events = append(events, &es_models.Event{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, Type: model.MFAOTPVerified})
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
@@ -478,16 +484,16 @@ func GetMockedEventstoreComplexity(ctrl *gomock.Controller, mockEs *mock.MockEve
|
||||
|
||||
func GetMockChangesUserOK(ctrl *gomock.Controller) *UserEventstore {
|
||||
user := model.Profile{
|
||||
FirstName: "Hans",
|
||||
LastName: "Muster",
|
||||
UserName: "HansMuster",
|
||||
FirstName: "Hans",
|
||||
LastName: "Muster",
|
||||
DisplayName: "DisplayName",
|
||||
}
|
||||
data, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, AggregateType: model.UserAggregate, Data: data},
|
||||
{AggregateID: "AggregateID", AggregateVersion: "v1", Sequence: 1, AggregateType: model.UserAggregate, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
@@ -60,7 +61,7 @@ func AddressToModel(address *Address) *model.Address {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) appendUserAddressChangedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendUserAddressChangedEvent(event *es_models.Event) error {
|
||||
if u.Address == nil {
|
||||
u.Address = new(Address)
|
||||
}
|
||||
|
@@ -2,14 +2,15 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
func TestAddressChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *Address
|
||||
new *Address
|
||||
existingAddress *Address
|
||||
newAddress *Address
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
@@ -22,8 +23,8 @@ func TestAddressChanges(t *testing.T) {
|
||||
{
|
||||
name: "all fields changed",
|
||||
args: args{
|
||||
existing: &Address{Country: "Country", Locality: "Locality", PostalCode: "PostalCode", Region: "Region", StreetAddress: "StreetAddress"},
|
||||
new: &Address{Country: "CountryChanged", Locality: "LocalityChanged", PostalCode: "PostalCodeChanged", Region: "RegionChanged", StreetAddress: "StreetAddressChanged"},
|
||||
existingAddress: &Address{Country: "Country", Locality: "Locality", PostalCode: "PostalCode", Region: "Region", StreetAddress: "StreetAddress"},
|
||||
newAddress: &Address{Country: "CountryChanged", Locality: "LocalityChanged", PostalCode: "PostalCodeChanged", Region: "RegionChanged", StreetAddress: "StreetAddressChanged"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 5,
|
||||
@@ -32,8 +33,8 @@ func TestAddressChanges(t *testing.T) {
|
||||
{
|
||||
name: "no fields changed",
|
||||
args: args{
|
||||
existing: &Address{Country: "Country", Locality: "Locality", PostalCode: "PostalCode", Region: "Region", StreetAddress: "StreetAddress"},
|
||||
new: &Address{Country: "Country", Locality: "Locality", PostalCode: "PostalCode", Region: "Region", StreetAddress: "StreetAddress"},
|
||||
existingAddress: &Address{Country: "Country", Locality: "Locality", PostalCode: "PostalCode", Region: "Region", StreetAddress: "StreetAddress"},
|
||||
newAddress: &Address{Country: "Country", Locality: "Locality", PostalCode: "PostalCode", Region: "Region", StreetAddress: "StreetAddress"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
@@ -42,7 +43,7 @@ func TestAddressChanges(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
changes := tt.args.existingAddress.Changes(tt.args.newAddress)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
@@ -52,23 +53,23 @@ func TestAddressChanges(t *testing.T) {
|
||||
|
||||
func TestAppendUserAddressChangedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
address *Address
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user address event",
|
||||
args: args{
|
||||
user: &User{Address: &Address{Locality: "Locality", Country: "Country"}},
|
||||
user: &Human{Address: &Address{Locality: "Locality", Country: "Country"}},
|
||||
address: &Address{Locality: "LocalityChanged", PostalCode: "PostalCode"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{Address: &Address{Locality: "LocalityChanged", Country: "Country", PostalCode: "PostalCode"}},
|
||||
result: &Human{Address: &Address{Locality: "LocalityChanged", Country: "Country", PostalCode: "PostalCode"}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@@ -2,12 +2,13 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Email struct {
|
||||
@@ -69,17 +70,17 @@ func EmailCodeToModel(code *EmailCode) *model.EmailCode {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) appendUserEmailChangedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendUserEmailChangedEvent(event *es_models.Event) error {
|
||||
u.Email = new(Email)
|
||||
return u.Email.setData(event)
|
||||
}
|
||||
|
||||
func (u *User) appendUserEmailCodeAddedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendUserEmailCodeAddedEvent(event *es_models.Event) error {
|
||||
u.EmailCode = new(EmailCode)
|
||||
return u.EmailCode.SetData(event)
|
||||
}
|
||||
|
||||
func (u *User) appendUserEmailVerifiedEvent() {
|
||||
func (u *Human) appendUserEmailVerifiedEvent() {
|
||||
u.IsEmailVerified = true
|
||||
}
|
||||
|
||||
|
@@ -2,15 +2,16 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
func TestEmailChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *Email
|
||||
new *Email
|
||||
existingEmail *Email
|
||||
new *Email
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
@@ -23,8 +24,8 @@ func TestEmailChanges(t *testing.T) {
|
||||
{
|
||||
name: "all fields changed",
|
||||
args: args{
|
||||
existing: &Email{EmailAddress: "Email", IsEmailVerified: true},
|
||||
new: &Email{EmailAddress: "EmailChanged", IsEmailVerified: false},
|
||||
existingEmail: &Email{EmailAddress: "Email", IsEmailVerified: true},
|
||||
new: &Email{EmailAddress: "EmailChanged", IsEmailVerified: false},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
@@ -33,8 +34,8 @@ func TestEmailChanges(t *testing.T) {
|
||||
{
|
||||
name: "no fields changed",
|
||||
args: args{
|
||||
existing: &Email{EmailAddress: "Email", IsEmailVerified: true},
|
||||
new: &Email{EmailAddress: "Email", IsEmailVerified: false},
|
||||
existingEmail: &Email{EmailAddress: "Email", IsEmailVerified: true},
|
||||
new: &Email{EmailAddress: "Email", IsEmailVerified: false},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
@@ -43,7 +44,7 @@ func TestEmailChanges(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
changes := tt.args.existingEmail.Changes(tt.args.new)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
@@ -53,23 +54,23 @@ func TestEmailChanges(t *testing.T) {
|
||||
|
||||
func TestAppendUserEmailChangedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
email *Email
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user email event",
|
||||
args: args{
|
||||
user: &User{Email: &Email{EmailAddress: "EmailAddress"}},
|
||||
user: &Human{Email: &Email{EmailAddress: "EmailAddress"}},
|
||||
email: &Email{EmailAddress: "EmailAddressChanged"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{Email: &Email{EmailAddress: "EmailAddressChanged"}},
|
||||
result: &Human{Email: &Email{EmailAddress: "EmailAddressChanged"}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -88,23 +89,23 @@ func TestAppendUserEmailChangedEvent(t *testing.T) {
|
||||
|
||||
func TestAppendUserEmailCodeAddedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
code *EmailCode
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user email code added event",
|
||||
args: args{
|
||||
user: &User{Email: &Email{EmailAddress: "EmailAddress"}},
|
||||
user: &Human{Email: &Email{EmailAddress: "EmailAddress"}},
|
||||
code: &EmailCode{Expiry: time.Hour * 1},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{EmailCode: &EmailCode{Expiry: time.Hour * 1}},
|
||||
result: &Human{EmailCode: &EmailCode{Expiry: time.Hour * 1}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -123,21 +124,21 @@ func TestAppendUserEmailCodeAddedEvent(t *testing.T) {
|
||||
|
||||
func TestAppendUserEmailVerifiedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user email event",
|
||||
args: args{
|
||||
user: &User{Email: &Email{EmailAddress: "EmailAddress"}},
|
||||
user: &Human{Email: &Email{EmailAddress: "EmailAddress"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{Email: &Email{EmailAddress: "EmailAddress", IsEmailVerified: true}},
|
||||
result: &Human{Email: &Email{EmailAddress: "EmailAddress", IsEmailVerified: true}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@@ -2,6 +2,7 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
@@ -32,18 +33,18 @@ func OTPToModel(otp *OTP) *model.OTP {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) appendOtpAddedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendOTPAddedEvent(event *es_models.Event) error {
|
||||
u.OTP = &OTP{
|
||||
State: int32(model.MfaStateNotReady),
|
||||
}
|
||||
return u.OTP.setData(event)
|
||||
}
|
||||
|
||||
func (u *User) appendOtpVerifiedEvent() {
|
||||
func (u *Human) appendOTPVerifiedEvent() {
|
||||
u.OTP.State = int32(model.MfaStateReady)
|
||||
}
|
||||
|
||||
func (u *User) appendOtpRemovedEvent() {
|
||||
func (u *Human) appendOTPRemovedEvent() {
|
||||
u.OTP = nil
|
||||
}
|
||||
|
||||
|
@@ -2,31 +2,32 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppendMfaOTPAddedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
otp *OTP
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user otp event",
|
||||
args: args{
|
||||
user: &User{},
|
||||
user: &Human{},
|
||||
otp: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MfaStateNotReady)}},
|
||||
result: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MfaStateNotReady)}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -35,7 +36,7 @@ func TestAppendMfaOTPAddedEvent(t *testing.T) {
|
||||
data, _ := json.Marshal(tt.args.otp)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.user.appendOtpAddedEvent(tt.args.event)
|
||||
tt.args.user.appendOTPAddedEvent(tt.args.event)
|
||||
if tt.args.user.OTP.State != tt.result.OTP.State {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.OTP.State, tt.args.user.OTP.State)
|
||||
}
|
||||
@@ -45,23 +46,23 @@ func TestAppendMfaOTPAddedEvent(t *testing.T) {
|
||||
|
||||
func TestAppendMfaOTPVerifyEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
otp *OTP
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append otp verify event",
|
||||
args: args{
|
||||
user: &User{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}}},
|
||||
user: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}}},
|
||||
otp: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MfaStateReady)}},
|
||||
result: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MfaStateReady)}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -70,7 +71,7 @@ func TestAppendMfaOTPVerifyEvent(t *testing.T) {
|
||||
data, _ := json.Marshal(tt.args.otp)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.user.appendOtpVerifiedEvent()
|
||||
tt.args.user.appendOTPVerifiedEvent()
|
||||
if tt.args.user.OTP.State != tt.result.OTP.State {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.OTP.State, tt.args.user.OTP.State)
|
||||
}
|
||||
@@ -80,27 +81,27 @@ func TestAppendMfaOTPVerifyEvent(t *testing.T) {
|
||||
|
||||
func TestAppendMfaOTPRemoveEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
otp *OTP
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append otp verify event",
|
||||
args: args{
|
||||
user: &User{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}}},
|
||||
user: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{},
|
||||
result: &Human{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.args.user.appendOtpRemovedEvent()
|
||||
tt.args.user.appendOTPRemovedEvent()
|
||||
if tt.args.user.OTP != nil {
|
||||
t.Errorf("got wrong result: actual: %v ", tt.result.OTP)
|
||||
}
|
||||
|
@@ -2,12 +2,13 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Password struct {
|
||||
@@ -50,7 +51,7 @@ func PasswordCodeToModel(code *PasswordCode) *model.PasswordCode {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) appendUserPasswordChangedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendUserPasswordChangedEvent(event *es_models.Event) error {
|
||||
u.Password = new(Password)
|
||||
err := u.Password.setData(event)
|
||||
if err != nil {
|
||||
@@ -60,7 +61,7 @@ func (u *User) appendUserPasswordChangedEvent(event *es_models.Event) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) appendPasswordSetRequestedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendPasswordSetRequestedEvent(event *es_models.Event) error {
|
||||
u.PasswordCode = new(PasswordCode)
|
||||
return u.PasswordCode.SetData(event)
|
||||
}
|
||||
|
@@ -2,30 +2,31 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
func TestAppendUserPasswordChangedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
pw *Password
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append init user code event",
|
||||
args: args{
|
||||
user: &User{},
|
||||
user: &Human{},
|
||||
pw: &Password{ChangeRequired: true},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{Password: &Password{ChangeRequired: true}},
|
||||
result: &Human{Password: &Password{ChangeRequired: true}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -44,23 +45,23 @@ func TestAppendUserPasswordChangedEvent(t *testing.T) {
|
||||
|
||||
func TestAppendPasswordSetRequestedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
code *PasswordCode
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user phone code added event",
|
||||
args: args{
|
||||
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
user: &Human{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
code: &PasswordCode{Expiry: time.Hour * 1},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{PasswordCode: &PasswordCode{Expiry: time.Hour * 1}},
|
||||
result: &Human{PasswordCode: &PasswordCode{Expiry: time.Hour * 1}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@@ -2,12 +2,13 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Phone struct {
|
||||
@@ -67,21 +68,21 @@ func PhoneCodeToModel(code *PhoneCode) *model.PhoneCode {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) appendUserPhoneChangedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendUserPhoneChangedEvent(event *es_models.Event) error {
|
||||
u.Phone = new(Phone)
|
||||
return u.Phone.setData(event)
|
||||
}
|
||||
|
||||
func (u *User) appendUserPhoneCodeAddedEvent(event *es_models.Event) error {
|
||||
func (u *Human) appendUserPhoneCodeAddedEvent(event *es_models.Event) error {
|
||||
u.PhoneCode = new(PhoneCode)
|
||||
return u.PhoneCode.SetData(event)
|
||||
}
|
||||
|
||||
func (u *User) appendUserPhoneVerifiedEvent() {
|
||||
func (u *Human) appendUserPhoneVerifiedEvent() {
|
||||
u.IsPhoneVerified = true
|
||||
}
|
||||
|
||||
func (u *User) appendUserPhoneRemovedEvent() {
|
||||
func (u *Human) appendUserPhoneRemovedEvent() {
|
||||
u.Phone = nil
|
||||
u.PhoneCode = nil
|
||||
}
|
||||
|
@@ -2,15 +2,16 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
func TestPhoneChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *Phone
|
||||
new *Phone
|
||||
existingPhone *Phone
|
||||
newPhone *Phone
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
@@ -23,8 +24,8 @@ func TestPhoneChanges(t *testing.T) {
|
||||
{
|
||||
name: "all fields changed",
|
||||
args: args{
|
||||
existing: &Phone{PhoneNumber: "Phone", IsPhoneVerified: true},
|
||||
new: &Phone{PhoneNumber: "PhoneChanged", IsPhoneVerified: false},
|
||||
existingPhone: &Phone{PhoneNumber: "Phone", IsPhoneVerified: true},
|
||||
newPhone: &Phone{PhoneNumber: "PhoneChanged", IsPhoneVerified: false},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
@@ -33,8 +34,8 @@ func TestPhoneChanges(t *testing.T) {
|
||||
{
|
||||
name: "no fields changed",
|
||||
args: args{
|
||||
existing: &Phone{PhoneNumber: "Phone", IsPhoneVerified: true},
|
||||
new: &Phone{PhoneNumber: "Phone", IsPhoneVerified: false},
|
||||
existingPhone: &Phone{PhoneNumber: "Phone", IsPhoneVerified: true},
|
||||
newPhone: &Phone{PhoneNumber: "Phone", IsPhoneVerified: false},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
@@ -43,7 +44,7 @@ func TestPhoneChanges(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
changes := tt.args.existingPhone.Changes(tt.args.newPhone)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
@@ -53,23 +54,23 @@ func TestPhoneChanges(t *testing.T) {
|
||||
|
||||
func TestAppendUserPhoneChangedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
phone *Phone
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user phone event",
|
||||
args: args{
|
||||
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
user: &Human{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
phone: &Phone{PhoneNumber: "PhoneNumberChanged"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{Phone: &Phone{PhoneNumber: "PhoneNumberChanged"}},
|
||||
result: &Human{Phone: &Phone{PhoneNumber: "PhoneNumberChanged"}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -88,23 +89,23 @@ func TestAppendUserPhoneChangedEvent(t *testing.T) {
|
||||
|
||||
func TestAppendUserPhoneCodeAddedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
code *PhoneCode
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user phone code added event",
|
||||
args: args{
|
||||
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
user: &Human{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
code: &PhoneCode{Expiry: time.Hour * 1},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{PhoneCode: &PhoneCode{Expiry: time.Hour * 1}},
|
||||
result: &Human{PhoneCode: &PhoneCode{Expiry: time.Hour * 1}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -123,21 +124,21 @@ func TestAppendUserPhoneCodeAddedEvent(t *testing.T) {
|
||||
|
||||
func TestAppendUserPhoneVerifiedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append user phone event",
|
||||
args: args{
|
||||
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
user: &Human{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{Phone: &Phone{PhoneNumber: "PhoneNumber", IsPhoneVerified: true}},
|
||||
result: &Human{Phone: &Phone{PhoneNumber: "PhoneNumber", IsPhoneVerified: true}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@@ -10,7 +10,6 @@ import (
|
||||
type Profile struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
UserName string `json:"userName,omitempty"`
|
||||
FirstName string `json:"firstName,omitempty"`
|
||||
LastName string `json:"lastName,omitempty"`
|
||||
NickName string `json:"nickName,omitempty"`
|
||||
@@ -18,7 +17,7 @@ type Profile struct {
|
||||
PreferredLanguage language.Tag `json:"preferredLanguage,omitempty"`
|
||||
Gender int32 `json:"gender,omitempty"`
|
||||
|
||||
isUserNameUnique bool `json:"-"`
|
||||
isUserNameUnique bool
|
||||
}
|
||||
|
||||
func (p *Profile) Changes(changed *Profile) map[string]interface{} {
|
||||
@@ -47,7 +46,6 @@ func (p *Profile) Changes(changed *Profile) map[string]interface{} {
|
||||
func ProfileFromModel(profile *model.Profile) *Profile {
|
||||
return &Profile{
|
||||
ObjectRoot: profile.ObjectRoot,
|
||||
UserName: profile.UserName,
|
||||
FirstName: profile.FirstName,
|
||||
LastName: profile.LastName,
|
||||
NickName: profile.NickName,
|
||||
@@ -60,7 +58,6 @@ func ProfileFromModel(profile *model.Profile) *Profile {
|
||||
func ProfileToModel(profile *Profile) *model.Profile {
|
||||
return &model.Profile{
|
||||
ObjectRoot: profile.ObjectRoot,
|
||||
UserName: profile.UserName,
|
||||
FirstName: profile.FirstName,
|
||||
LastName: profile.LastName,
|
||||
NickName: profile.NickName,
|
||||
|
@@ -1,15 +1,16 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
user_model "github.com/caos/zitadel/internal/user/model"
|
||||
"golang.org/x/text/language"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProfileChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *Profile
|
||||
new *Profile
|
||||
existingProfile *Profile
|
||||
newProfile *Profile
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
@@ -22,8 +23,8 @@ func TestProfileChanges(t *testing.T) {
|
||||
{
|
||||
name: "all attributes changed",
|
||||
args: args{
|
||||
existing: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
new: &Profile{UserName: "UserNameChanged", FirstName: "FirstNameChanged", LastName: "LastNameChanged", NickName: "NickNameChanged", DisplayName: "DisplayNameChanged", PreferredLanguage: language.English, Gender: int32(user_model.GenderMale)},
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "FirstNameChanged", LastName: "LastNameChanged", NickName: "NickNameChanged", DisplayName: "DisplayNameChanged", PreferredLanguage: language.English, Gender: int32(user_model.GenderMale)},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 6,
|
||||
@@ -32,18 +33,8 @@ func TestProfileChanges(t *testing.T) {
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
||||
existing: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
new: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "username changed",
|
||||
args: args{
|
||||
existing: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
new: &Profile{UserName: "UserNameChanged", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
@@ -52,8 +43,8 @@ func TestProfileChanges(t *testing.T) {
|
||||
{
|
||||
name: "empty names",
|
||||
args: args{
|
||||
existing: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
new: &Profile{UserName: "UserName", FirstName: "", LastName: "", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "", LastName: "", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
@@ -62,7 +53,7 @@ func TestProfileChanges(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
changes := tt.args.existingProfile.Changes(tt.args.newProfile)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
|
@@ -2,10 +2,14 @@ package model
|
||||
|
||||
import "github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
//aggregates
|
||||
const (
|
||||
UserAggregate models.AggregateType = "user"
|
||||
UserUserNameAggregate models.AggregateType = "user.username"
|
||||
)
|
||||
|
||||
// the following consts are for user v1 events
|
||||
const (
|
||||
UserAdded models.EventType = "user.added"
|
||||
UserRegistered models.EventType = "user.selfregistered"
|
||||
InitializedUserCodeAdded models.EventType = "user.initialization.code.added"
|
||||
@@ -16,12 +20,6 @@ const (
|
||||
UserUserNameReserved models.EventType = "user.username.reserved"
|
||||
UserUserNameReleased models.EventType = "user.username.released"
|
||||
|
||||
UserLocked models.EventType = "user.locked"
|
||||
UserUnlocked models.EventType = "user.unlocked"
|
||||
UserDeactivated models.EventType = "user.deactivated"
|
||||
UserReactivated models.EventType = "user.reactivated"
|
||||
UserRemoved models.EventType = "user.removed"
|
||||
|
||||
UserPasswordChanged models.EventType = "user.password.changed"
|
||||
UserPasswordCodeAdded models.EventType = "user.password.code.added"
|
||||
UserPasswordCodeSent models.EventType = "user.password.code.sent"
|
||||
@@ -45,15 +43,77 @@ const (
|
||||
UserAddressChanged models.EventType = "user.address.changed"
|
||||
UserUserNameChanged models.EventType = "user.username.changed"
|
||||
|
||||
MfaOtpAdded models.EventType = "user.mfa.otp.added"
|
||||
MfaOtpVerified models.EventType = "user.mfa.otp.verified"
|
||||
MfaOtpRemoved models.EventType = "user.mfa.otp.removed"
|
||||
MFAOTPAdded models.EventType = "user.mfa.otp.added"
|
||||
MFAOTPVerified models.EventType = "user.mfa.otp.verified"
|
||||
MFAOTPRemoved models.EventType = "user.mfa.otp.removed"
|
||||
MfaOtpCheckSucceeded models.EventType = "user.mfa.otp.check.succeeded"
|
||||
MfaOtpCheckFailed models.EventType = "user.mfa.otp.check.failed"
|
||||
MfaInitSkipped models.EventType = "user.mfa.init.skipped"
|
||||
MFAInitSkipped models.EventType = "user.mfa.init.skipped"
|
||||
|
||||
SignedOut models.EventType = "user.signed.out"
|
||||
|
||||
DomainClaimed models.EventType = "user.domain.claimed"
|
||||
DomainClaimedSent models.EventType = "user.domain.claimed.sent"
|
||||
)
|
||||
|
||||
//the following consts are for user(v2)
|
||||
const (
|
||||
UserNameReserved models.EventType = "user.username.reserved"
|
||||
UserNameReleased models.EventType = "user.username.released"
|
||||
|
||||
UserLocked models.EventType = "user.locked"
|
||||
UserUnlocked models.EventType = "user.unlocked"
|
||||
UserDeactivated models.EventType = "user.deactivated"
|
||||
UserReactivated models.EventType = "user.reactivated"
|
||||
UserRemoved models.EventType = "user.removed"
|
||||
)
|
||||
|
||||
// the following consts are for user(v2).human
|
||||
const (
|
||||
HumanAdded models.EventType = "user.human.added"
|
||||
HumanRegistered models.EventType = "user.human.selfregistered"
|
||||
InitializedHumanCodeAdded models.EventType = "user.human.initialization.code.added"
|
||||
InitializedHumanCodeSent models.EventType = "user.human.initialization.code.sent"
|
||||
InitializedHumanCheckSucceeded models.EventType = "user.human.initialization.check.succeeded"
|
||||
InitializedHumanCheckFailed models.EventType = "user.human.initialization.check.failed"
|
||||
|
||||
HumanPasswordChanged models.EventType = "user.human.password.changed"
|
||||
HumanPasswordCodeAdded models.EventType = "user.human.password.code.added"
|
||||
HumanPasswordCodeSent models.EventType = "user.human.password.code.sent"
|
||||
HumanPasswordCheckSucceeded models.EventType = "user.human.password.check.succeeded"
|
||||
HumanPasswordCheckFailed models.EventType = "user.human.password.check.failed"
|
||||
|
||||
HumanEmailChanged models.EventType = "user.human.email.changed"
|
||||
HumanEmailVerified models.EventType = "user.human.email.verified"
|
||||
HumanEmailVerificationFailed models.EventType = "user.human.email.verification.failed"
|
||||
HumanEmailCodeAdded models.EventType = "user.human.email.code.added"
|
||||
HumanEmailCodeSent models.EventType = "user.human.email.code.sent"
|
||||
|
||||
HumanPhoneChanged models.EventType = "user.human.phone.changed"
|
||||
HumanPhoneRemoved models.EventType = "user.human.phone.removed"
|
||||
HumanPhoneVerified models.EventType = "user.human.phone.verified"
|
||||
HumanPhoneVerificationFailed models.EventType = "user.human.phone.verification.failed"
|
||||
HumanPhoneCodeAdded models.EventType = "user.human.phone.code.added"
|
||||
HumanPhoneCodeSent models.EventType = "user.human.phone.code.sent"
|
||||
|
||||
HumanProfileChanged models.EventType = "user.human.profile.changed"
|
||||
HumanAddressChanged models.EventType = "user.human.address.changed"
|
||||
|
||||
HumanMFAOTPAdded models.EventType = "user.human.mfa.otp.added"
|
||||
HumanMFAOTPVerified models.EventType = "user.human.mfa.otp.verified"
|
||||
HumanMFAOTPRemoved models.EventType = "user.human.mfa.otp.removed"
|
||||
HumanMfaOtpCheckSucceeded models.EventType = "user.human.mfa.otp.check.succeeded"
|
||||
HumanMfaOtpCheckFailed models.EventType = "user.human.mfa.otp.check.failed"
|
||||
HumanMfaInitSkipped models.EventType = "user.human.mfa.init.skipped"
|
||||
|
||||
HumanSignedOut models.EventType = "user.human.signed.out"
|
||||
)
|
||||
|
||||
// the following consts are for user(v2).machines
|
||||
const (
|
||||
MachineAdded models.EventType = "user.machine.added"
|
||||
MachineChanged models.EventType = "user.machine.changed"
|
||||
|
||||
MachineKeyAdded models.EventType = "user.machine.key.added"
|
||||
MachineKeyRemoved models.EventType = "user.machine.key.removed"
|
||||
)
|
||||
|
@@ -2,141 +2,90 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
)
|
||||
|
||||
const (
|
||||
UserVersion = "v1"
|
||||
UserVersion = "v2"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
es_models.ObjectRoot
|
||||
State int32 `json:"-"`
|
||||
*Password
|
||||
*Profile
|
||||
*Email
|
||||
*Phone
|
||||
*Address
|
||||
InitCode *InitUserCode `json:"-"`
|
||||
EmailCode *EmailCode `json:"-"`
|
||||
PhoneCode *PhoneCode `json:"-"`
|
||||
PasswordCode *PasswordCode `json:"-"`
|
||||
OTP *OTP `json:"-"`
|
||||
}
|
||||
State int32 `json:"-"`
|
||||
UserName string `json:"userName"`
|
||||
|
||||
type InitUserCode struct {
|
||||
es_models.ObjectRoot
|
||||
Code *crypto.CryptoValue `json:"code,omitempty"`
|
||||
Expiry time.Duration `json:"expiry,omitempty"`
|
||||
*Human
|
||||
*Machine
|
||||
}
|
||||
|
||||
func UserFromModel(user *model.User) *User {
|
||||
converted := &User{
|
||||
var human *Human
|
||||
if user.Human != nil {
|
||||
human = HumanFromModel(user.Human)
|
||||
}
|
||||
var machine *Machine
|
||||
if user.Machine != nil {
|
||||
machine = MachineFromModel(user.Machine)
|
||||
}
|
||||
return &User{
|
||||
ObjectRoot: user.ObjectRoot,
|
||||
State: int32(user.State),
|
||||
UserName: user.UserName,
|
||||
Human: human,
|
||||
Machine: machine,
|
||||
}
|
||||
if user.Password != nil {
|
||||
converted.Password = PasswordFromModel(user.Password)
|
||||
}
|
||||
if user.Profile != nil {
|
||||
converted.Profile = ProfileFromModel(user.Profile)
|
||||
}
|
||||
if user.Email != nil {
|
||||
converted.Email = EmailFromModel(user.Email)
|
||||
}
|
||||
if user.Phone != nil {
|
||||
converted.Phone = PhoneFromModel(user.Phone)
|
||||
}
|
||||
if user.Address != nil {
|
||||
converted.Address = AddressFromModel(user.Address)
|
||||
}
|
||||
if user.OTP != nil {
|
||||
converted.OTP = OTPFromModel(user.OTP)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func UserToModel(user *User) *model.User {
|
||||
converted := &model.User{
|
||||
var human *model.Human
|
||||
if user.Human != nil {
|
||||
human = HumanToModel(user.Human)
|
||||
}
|
||||
var machine *model.Machine
|
||||
if user.Machine != nil {
|
||||
machine = MachineToModel(user.Machine)
|
||||
}
|
||||
return &model.User{
|
||||
ObjectRoot: user.ObjectRoot,
|
||||
State: model.UserState(user.State),
|
||||
}
|
||||
if user.Password != nil {
|
||||
converted.Password = PasswordToModel(user.Password)
|
||||
}
|
||||
if user.Profile != nil {
|
||||
converted.Profile = ProfileToModel(user.Profile)
|
||||
}
|
||||
if user.Email != nil {
|
||||
converted.Email = EmailToModel(user.Email)
|
||||
}
|
||||
if user.Phone != nil {
|
||||
converted.Phone = PhoneToModel(user.Phone)
|
||||
}
|
||||
if user.Address != nil {
|
||||
converted.Address = AddressToModel(user.Address)
|
||||
}
|
||||
if user.InitCode != nil {
|
||||
converted.InitCode = InitCodeToModel(user.InitCode)
|
||||
}
|
||||
if user.EmailCode != nil {
|
||||
converted.EmailCode = EmailCodeToModel(user.EmailCode)
|
||||
}
|
||||
if user.PhoneCode != nil {
|
||||
converted.PhoneCode = PhoneCodeToModel(user.PhoneCode)
|
||||
}
|
||||
if user.PasswordCode != nil {
|
||||
converted.PasswordCode = PasswordCodeToModel(user.PasswordCode)
|
||||
}
|
||||
if user.OTP != nil {
|
||||
converted.OTP = OTPToModel(user.OTP)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func InitCodeFromModel(code *model.InitUserCode) *InitUserCode {
|
||||
if code == nil {
|
||||
return nil
|
||||
}
|
||||
return &InitUserCode{
|
||||
ObjectRoot: code.ObjectRoot,
|
||||
Expiry: code.Expiry,
|
||||
Code: code.Code,
|
||||
UserName: user.UserName,
|
||||
Human: human,
|
||||
Machine: machine,
|
||||
}
|
||||
}
|
||||
|
||||
func InitCodeToModel(code *InitUserCode) *model.InitUserCode {
|
||||
return &model.InitUserCode{
|
||||
ObjectRoot: code.ObjectRoot,
|
||||
Expiry: code.Expiry,
|
||||
Code: code.Code,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *User) AppendEvents(events ...*es_models.Event) error {
|
||||
func (u *User) AppendEvents(events ...*es_models.Event) error {
|
||||
for _, event := range events {
|
||||
if err := p.AppendEvent(event); err != nil {
|
||||
if err := u.AppendEvent(event); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) AppendEvent(event *es_models.Event) (err error) {
|
||||
func (u *User) AppendEvent(event *es_models.Event) error {
|
||||
u.ObjectRoot.AppendEvent(event)
|
||||
|
||||
switch event.Type {
|
||||
case UserAdded,
|
||||
HumanAdded,
|
||||
MachineAdded,
|
||||
UserRegistered,
|
||||
HumanRegistered,
|
||||
UserProfileChanged,
|
||||
DomainClaimed,
|
||||
UserUserNameChanged:
|
||||
u.setData(event)
|
||||
err := u.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case UserDeactivated:
|
||||
u.appendDeactivatedEvent()
|
||||
case UserReactivated:
|
||||
@@ -145,71 +94,31 @@ func (u *User) AppendEvent(event *es_models.Event) (err error) {
|
||||
u.appendLockedEvent()
|
||||
case UserUnlocked:
|
||||
u.appendUnlockedEvent()
|
||||
case InitializedUserCodeAdded:
|
||||
u.appendInitUsercodeCreatedEvent(event)
|
||||
case UserPasswordChanged:
|
||||
err = u.appendUserPasswordChangedEvent(event)
|
||||
case UserPasswordCodeAdded:
|
||||
err = u.appendPasswordSetRequestedEvent(event)
|
||||
case UserEmailChanged:
|
||||
err = u.appendUserEmailChangedEvent(event)
|
||||
case UserEmailCodeAdded:
|
||||
err = u.appendUserEmailCodeAddedEvent(event)
|
||||
case UserEmailVerified:
|
||||
u.appendUserEmailVerifiedEvent()
|
||||
case UserPhoneChanged:
|
||||
err = u.appendUserPhoneChangedEvent(event)
|
||||
case UserPhoneCodeAdded:
|
||||
err = u.appendUserPhoneCodeAddedEvent(event)
|
||||
case UserPhoneVerified:
|
||||
u.appendUserPhoneVerifiedEvent()
|
||||
case UserPhoneRemoved:
|
||||
u.appendUserPhoneRemovedEvent()
|
||||
case UserAddressChanged:
|
||||
err = u.appendUserAddressChangedEvent(event)
|
||||
case MfaOtpAdded:
|
||||
err = u.appendOtpAddedEvent(event)
|
||||
case MfaOtpVerified:
|
||||
u.appendOtpVerifiedEvent()
|
||||
case MfaOtpRemoved:
|
||||
u.appendOtpRemovedEvent()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.ComputeObject()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) ComputeObject() {
|
||||
if u.State == 0 {
|
||||
if u.Email != nil && u.IsEmailVerified {
|
||||
u.State = int32(model.UserStateActive)
|
||||
} else {
|
||||
u.State = int32(model.UserStateInitial)
|
||||
}
|
||||
if u.Human != nil {
|
||||
u.Human.User = u
|
||||
return u.Human.AppendEvent(event)
|
||||
} else if u.Machine != nil {
|
||||
u.Machine.User = u
|
||||
return u.Machine.AppendEvent(event)
|
||||
}
|
||||
if u.Password != nil && u.Password.ObjectRoot.IsZero() {
|
||||
u.Password.ObjectRoot = u.ObjectRoot
|
||||
if strings.HasPrefix(string(event.Type), "user.human") || event.AggregateVersion == "v1" {
|
||||
u.Human = &Human{User: u}
|
||||
return u.Human.AppendEvent(event)
|
||||
}
|
||||
if u.Profile != nil && u.Profile.ObjectRoot.IsZero() {
|
||||
u.Profile.ObjectRoot = u.ObjectRoot
|
||||
}
|
||||
if u.Email != nil && u.Email.ObjectRoot.IsZero() {
|
||||
u.Email.ObjectRoot = u.ObjectRoot
|
||||
}
|
||||
if u.Phone != nil && u.Phone.ObjectRoot.IsZero() {
|
||||
u.Phone.ObjectRoot = u.ObjectRoot
|
||||
}
|
||||
if u.Address != nil && u.Address.ObjectRoot.IsZero() {
|
||||
u.Address.ObjectRoot = u.ObjectRoot
|
||||
if strings.HasPrefix(string(event.Type), "user.machine") {
|
||||
u.Machine = &Machine{User: u}
|
||||
return u.Machine.AppendEvent(event)
|
||||
}
|
||||
|
||||
return errors.ThrowNotFound(nil, "MODEL-x9TaX", "Errors.UserType.Undefined")
|
||||
}
|
||||
|
||||
func (u *User) setData(event *es_models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, u); err != nil {
|
||||
logging.Log("EVEN-8ujgd").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-sj4jd", "could not unmarshal event")
|
||||
logging.Log("EVEN-ZDzQy").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-yGmhh", "could not unmarshal event")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -229,23 +138,3 @@ func (u *User) appendLockedEvent() {
|
||||
func (u *User) appendUnlockedEvent() {
|
||||
u.State = int32(model.UserStateActive)
|
||||
}
|
||||
|
||||
func (u *User) appendInitUsercodeCreatedEvent(event *es_models.Event) error {
|
||||
initCode := new(InitUserCode)
|
||||
err := initCode.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initCode.ObjectRoot.CreationDate = event.CreationDate
|
||||
u.InitCode = initCode
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *InitUserCode) SetData(event *es_models.Event) error {
|
||||
c.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, c); err != nil {
|
||||
logging.Log("EVEN-7duwe").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-lo34s", "could not unmarshal event")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
231
internal/user/repository/eventsourcing/model/user_human.go
Normal file
231
internal/user/repository/eventsourcing/model/user_human.go
Normal file
@@ -0,0 +1,231 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
)
|
||||
|
||||
type Human struct {
|
||||
*User `json:"-"`
|
||||
|
||||
*Password
|
||||
*Profile
|
||||
*Email
|
||||
*Phone
|
||||
*Address
|
||||
InitCode *InitUserCode `json:"-"`
|
||||
EmailCode *EmailCode `json:"-"`
|
||||
PhoneCode *PhoneCode `json:"-"`
|
||||
PasswordCode *PasswordCode `json:"-"`
|
||||
OTP *OTP `json:"-"`
|
||||
}
|
||||
|
||||
type InitUserCode struct {
|
||||
es_models.ObjectRoot
|
||||
Code *crypto.CryptoValue `json:"code,omitempty"`
|
||||
Expiry time.Duration `json:"expiry,omitempty"`
|
||||
}
|
||||
|
||||
func HumanFromModel(user *model.Human) *Human {
|
||||
human := new(Human)
|
||||
if user.Password != nil {
|
||||
human.Password = PasswordFromModel(user.Password)
|
||||
}
|
||||
if user.Profile != nil {
|
||||
human.Profile = ProfileFromModel(user.Profile)
|
||||
}
|
||||
if user.Email != nil {
|
||||
human.Email = EmailFromModel(user.Email)
|
||||
}
|
||||
if user.Phone != nil {
|
||||
human.Phone = PhoneFromModel(user.Phone)
|
||||
}
|
||||
if user.Address != nil {
|
||||
human.Address = AddressFromModel(user.Address)
|
||||
}
|
||||
if user.OTP != nil {
|
||||
human.OTP = OTPFromModel(user.OTP)
|
||||
}
|
||||
return human
|
||||
}
|
||||
|
||||
func HumanToModel(user *Human) *model.Human {
|
||||
human := new(model.Human)
|
||||
if user.Password != nil {
|
||||
human.Password = PasswordToModel(user.Password)
|
||||
}
|
||||
if user.Profile != nil {
|
||||
human.Profile = ProfileToModel(user.Profile)
|
||||
}
|
||||
if user.Email != nil {
|
||||
human.Email = EmailToModel(user.Email)
|
||||
}
|
||||
if user.Phone != nil {
|
||||
human.Phone = PhoneToModel(user.Phone)
|
||||
}
|
||||
if user.Address != nil {
|
||||
human.Address = AddressToModel(user.Address)
|
||||
}
|
||||
if user.InitCode != nil {
|
||||
human.InitCode = InitCodeToModel(user.InitCode)
|
||||
}
|
||||
if user.EmailCode != nil {
|
||||
human.EmailCode = EmailCodeToModel(user.EmailCode)
|
||||
}
|
||||
if user.PhoneCode != nil {
|
||||
human.PhoneCode = PhoneCodeToModel(user.PhoneCode)
|
||||
}
|
||||
if user.PasswordCode != nil {
|
||||
human.PasswordCode = PasswordCodeToModel(user.PasswordCode)
|
||||
}
|
||||
if user.OTP != nil {
|
||||
human.OTP = OTPToModel(user.OTP)
|
||||
}
|
||||
return human
|
||||
}
|
||||
|
||||
func InitCodeFromModel(code *model.InitUserCode) *InitUserCode {
|
||||
if code == nil {
|
||||
return nil
|
||||
}
|
||||
return &InitUserCode{
|
||||
ObjectRoot: code.ObjectRoot,
|
||||
Expiry: code.Expiry,
|
||||
Code: code.Code,
|
||||
}
|
||||
}
|
||||
|
||||
func InitCodeToModel(code *InitUserCode) *model.InitUserCode {
|
||||
return &model.InitUserCode{
|
||||
ObjectRoot: code.ObjectRoot,
|
||||
Expiry: code.Expiry,
|
||||
Code: code.Code,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Human) AppendEvents(events ...*es_models.Event) error {
|
||||
for _, event := range events {
|
||||
if err := p.AppendEvent(event); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Human) AppendEvent(event *es_models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case UserAdded,
|
||||
UserRegistered,
|
||||
UserProfileChanged,
|
||||
HumanAdded,
|
||||
HumanRegistered,
|
||||
HumanProfileChanged:
|
||||
h.setData(event)
|
||||
case InitializedUserCodeAdded,
|
||||
InitializedHumanCodeAdded:
|
||||
h.appendInitUsercodeCreatedEvent(event)
|
||||
case UserPasswordChanged,
|
||||
HumanPasswordChanged:
|
||||
err = h.appendUserPasswordChangedEvent(event)
|
||||
case UserPasswordCodeAdded,
|
||||
HumanPasswordCodeAdded:
|
||||
err = h.appendPasswordSetRequestedEvent(event)
|
||||
case UserEmailChanged,
|
||||
HumanEmailChanged:
|
||||
err = h.appendUserEmailChangedEvent(event)
|
||||
case UserEmailCodeAdded,
|
||||
HumanEmailCodeAdded:
|
||||
err = h.appendUserEmailCodeAddedEvent(event)
|
||||
case UserEmailVerified,
|
||||
HumanEmailVerified:
|
||||
h.appendUserEmailVerifiedEvent()
|
||||
case UserPhoneChanged,
|
||||
HumanPhoneChanged:
|
||||
err = h.appendUserPhoneChangedEvent(event)
|
||||
case UserPhoneCodeAdded,
|
||||
HumanPhoneCodeAdded:
|
||||
err = h.appendUserPhoneCodeAddedEvent(event)
|
||||
case UserPhoneVerified,
|
||||
HumanPhoneVerified:
|
||||
h.appendUserPhoneVerifiedEvent()
|
||||
case UserPhoneRemoved,
|
||||
HumanPhoneRemoved:
|
||||
h.appendUserPhoneRemovedEvent()
|
||||
case UserAddressChanged,
|
||||
HumanAddressChanged:
|
||||
err = h.appendUserAddressChangedEvent(event)
|
||||
case MFAOTPAdded,
|
||||
HumanMFAOTPAdded:
|
||||
err = h.appendOTPAddedEvent(event)
|
||||
case MFAOTPVerified,
|
||||
HumanMFAOTPVerified:
|
||||
h.appendOTPVerifiedEvent()
|
||||
case MFAOTPRemoved,
|
||||
HumanMFAOTPRemoved:
|
||||
h.appendOTPRemovedEvent()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.ComputeObject()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Human) ComputeObject() {
|
||||
if h.State == int32(model.UserStateUnspecified) {
|
||||
if h.Email != nil && h.IsEmailVerified {
|
||||
h.State = int32(model.UserStateActive)
|
||||
} else {
|
||||
h.State = int32(model.UserStateInitial)
|
||||
}
|
||||
}
|
||||
if h.Password != nil && h.Password.ObjectRoot.IsZero() {
|
||||
h.Password.ObjectRoot = h.User.ObjectRoot
|
||||
}
|
||||
if h.Profile != nil && h.Profile.ObjectRoot.IsZero() {
|
||||
h.Profile.ObjectRoot = h.User.ObjectRoot
|
||||
}
|
||||
if h.Email != nil && h.Email.ObjectRoot.IsZero() {
|
||||
h.Email.ObjectRoot = h.User.ObjectRoot
|
||||
}
|
||||
if h.Phone != nil && h.Phone.ObjectRoot.IsZero() {
|
||||
h.Phone.ObjectRoot = h.User.ObjectRoot
|
||||
}
|
||||
if h.Address != nil && h.Address.ObjectRoot.IsZero() {
|
||||
h.Address.ObjectRoot = h.User.ObjectRoot
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Human) setData(event *es_models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, u); err != nil {
|
||||
logging.Log("EVEN-8ujgd").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-sj4jd", "could not unmarshal event")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Human) appendInitUsercodeCreatedEvent(event *es_models.Event) error {
|
||||
initCode := new(InitUserCode)
|
||||
err := initCode.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initCode.ObjectRoot.CreationDate = event.CreationDate
|
||||
u.InitCode = initCode
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *InitUserCode) SetData(event *es_models.Event) error {
|
||||
c.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, c); err != nil {
|
||||
logging.Log("EVEN-7duwe").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-lo34s", "could not unmarshal event")
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -2,10 +2,11 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
)
|
||||
|
||||
func TestAppendDeactivatedEvent(t *testing.T) {
|
||||
@@ -118,23 +119,23 @@ func TestAppendUnlockEvent(t *testing.T) {
|
||||
|
||||
func TestAppendInitUserCodeEvent(t *testing.T) {
|
||||
type args struct {
|
||||
user *User
|
||||
user *Human
|
||||
code *InitUserCode
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *User
|
||||
result *Human
|
||||
}{
|
||||
{
|
||||
name: "append init user code event",
|
||||
args: args{
|
||||
user: &User{},
|
||||
user: &Human{},
|
||||
code: &InitUserCode{Expiry: time.Hour * 30},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &User{InitCode: &InitUserCode{Expiry: time.Hour * 30}},
|
||||
result: &Human{InitCode: &InitUserCode{Expiry: time.Hour * 30}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
134
internal/user/repository/eventsourcing/model/user_machine.go
Normal file
134
internal/user/repository/eventsourcing/model/user_machine.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
)
|
||||
|
||||
type Machine struct {
|
||||
*User `json:"-"`
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
func (sa *Machine) AppendEvents(events ...*models.Event) error {
|
||||
for _, event := range events {
|
||||
if err := sa.AppendEvent(event); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sa *Machine) AppendEvent(event *models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case MachineAdded, MachineChanged:
|
||||
err = sa.setData(event)
|
||||
case MachineKeyAdded:
|
||||
fallthrough
|
||||
case MachineKeyRemoved:
|
||||
logging.Log("MODEL-iBgOc").Warn("key unimplemented")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (sa *Machine) setData(event *models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, sa); err != nil {
|
||||
logging.Log("EVEN-8ujgd").WithError(err).Error("could not unmarshal event data")
|
||||
return errors.ThrowInternal(err, "MODEL-GwjY9", "could not unmarshal event")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sa *Machine) Changes(updatedAccount *Machine) map[string]interface{} {
|
||||
changes := make(map[string]interface{})
|
||||
if updatedAccount.Description != "" && updatedAccount.Description != sa.Description {
|
||||
changes["description"] = updatedAccount.Description
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
func MachineFromModel(machine *model.Machine) *Machine {
|
||||
return &Machine{
|
||||
Description: machine.Description,
|
||||
Name: machine.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func MachineToModel(machine *Machine) *model.Machine {
|
||||
return &model.Machine{
|
||||
Description: machine.Description,
|
||||
Name: machine.Name,
|
||||
}
|
||||
}
|
||||
|
||||
type MachineKey struct {
|
||||
es_models.ObjectRoot `json:"-"`
|
||||
KeyID string `json:"keyId,omitempty"`
|
||||
Type int32 `json:"type,omitempty"`
|
||||
ExpirationDate time.Time `json:"expirationDate,omitempty"`
|
||||
PublicKey *crypto.CryptoValue `json:"publicKey,omitempty"`
|
||||
privateKey []byte
|
||||
}
|
||||
|
||||
func (key *MachineKey) AppendEvents(events ...*es_models.Event) error {
|
||||
for _, event := range events {
|
||||
err := key.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (key *MachineKey) AppendEvent(event *es_models.Event) error {
|
||||
switch event.Type {
|
||||
case MachineKeyAdded:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func MachineKeyFromModel(machine *model.MachineKey) *MachineKey {
|
||||
return &MachineKey{
|
||||
ObjectRoot: machine.ObjectRoot,
|
||||
ExpirationDate: machine.ExpirationDate,
|
||||
KeyID: machine.KeyID,
|
||||
Type: int32(machine.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func MachineKeyToModel(machine *MachineKey) *model.MachineKey {
|
||||
return &model.MachineKey{
|
||||
ObjectRoot: machine.ObjectRoot,
|
||||
ExpirationDate: machine.ExpirationDate,
|
||||
KeyID: machine.KeyID,
|
||||
PrivateKey: machine.privateKey,
|
||||
Type: model.MachineKeyType(machine.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func (key *MachineKey) GenerateMachineKeyPair(keySize int, alg crypto.EncryptionAlgorithm) error {
|
||||
privateKey, publicKey, err := crypto.GenerateKeyPair(keySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
publicKeyBytes, err := crypto.PublicKeyToBytes(publicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key.PublicKey, err = crypto.Encrypt(publicKeyBytes, alg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key.privateKey = crypto.PrivateKeyToBytes(privateKey)
|
||||
return nil
|
||||
}
|
@@ -48,8 +48,8 @@ func UserAggregateOverwriteContext(ctx context.Context, aggCreator *es_models.Ag
|
||||
return aggCreator.NewAggregate(ctx, user.AggregateID, model.UserAggregate, model.UserVersion, user.Sequence, es_models.OverwriteResourceOwner(resourceOwnerID), es_models.OverwriteEditorUser(userID))
|
||||
}
|
||||
|
||||
func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, initCode *model.InitUserCode, phoneCode *model.PhoneCode, resourceOwner string, userLoginMustBeDomain bool) (_ []*es_models.Aggregate, err error) {
|
||||
if user == nil {
|
||||
func MachineCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, userLoginMustBeDomain bool) (_ []*es_models.Aggregate, err error) {
|
||||
if user == nil || user.Machine == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "Errors.Internal")
|
||||
}
|
||||
|
||||
@@ -71,7 +71,45 @@ func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
agg.SetPrecondition(validationQuery, validation)
|
||||
}
|
||||
|
||||
agg, err = agg.AppendEvent(model.UserAdded, user)
|
||||
agg, err = agg.AppendEvent(model.MachineAdded, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userNameAggregate, err := reservedUniqueUserNameAggregate(ctx, aggCreator, resourceOwner, user.UserName, userLoginMustBeDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*es_models.Aggregate{
|
||||
agg,
|
||||
userNameAggregate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func HumanCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, initCode *model.InitUserCode, phoneCode *model.PhoneCode, resourceOwner string, userLoginMustBeDomain bool) (_ []*es_models.Aggregate, err error) {
|
||||
if user == nil || user.Human == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "Errors.Internal")
|
||||
}
|
||||
|
||||
var agg *es_models.Aggregate
|
||||
if resourceOwner != "" {
|
||||
agg, err = UserAggregateOverwriteContext(ctx, aggCreator, user, resourceOwner, user.AggregateID)
|
||||
} else {
|
||||
agg, err = UserAggregate(ctx, aggCreator, user)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !userLoginMustBeDomain {
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(org_es_model.OrgAggregate).
|
||||
AggregateIDsFilter()
|
||||
|
||||
validation := addUserNameValidation(user.UserName)
|
||||
agg.SetPrecondition(validationQuery, validation)
|
||||
}
|
||||
|
||||
agg, err = agg.AppendEvent(model.HumanAdded, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -99,7 +137,8 @@ func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
uniqueAggregates, err := getUniqueUserAggregates(ctx, aggCreator, user, resourceOwner, userLoginMustBeDomain)
|
||||
|
||||
uniqueAggregates, err := getUniqueUserAggregates(ctx, aggCreator, user.UserName, user.EmailAddress, resourceOwner, userLoginMustBeDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -108,7 +147,11 @@ func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
|
||||
func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, initCode *model.InitUserCode, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
|
||||
if user == nil || resourceOwner == "" || initCode == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user, resourceowner, initcode should not be nothing")
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user, resourceowner, initcode must be set")
|
||||
}
|
||||
|
||||
if user.Human == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-ekuEA", "user must be type human")
|
||||
}
|
||||
|
||||
agg, err := UserAggregateOverwriteContext(ctx, aggCreator, user, resourceOwner, user.AggregateID)
|
||||
@@ -124,23 +167,23 @@ func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateC
|
||||
validation := addUserNameValidation(user.UserName)
|
||||
agg.SetPrecondition(validationQuery, validation)
|
||||
}
|
||||
agg, err = agg.AppendEvent(model.UserRegistered, user)
|
||||
agg, err = agg.AppendEvent(model.HumanRegistered, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg, err = agg.AppendEvent(model.InitializedUserCodeAdded, initCode)
|
||||
agg, err = agg.AppendEvent(model.InitializedHumanCodeAdded, initCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uniqueAggregates, err := getUniqueUserAggregates(ctx, aggCreator, user, resourceOwner, userLoginMustBeDomain)
|
||||
uniqueAggregates, err := getUniqueUserAggregates(ctx, aggCreator, user.UserName, user.EmailAddress, resourceOwner, userLoginMustBeDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(uniqueAggregates, agg), nil
|
||||
}
|
||||
|
||||
func getUniqueUserAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
|
||||
userNameAggregate, err := reservedUniqueUserNameAggregate(ctx, aggCreator, resourceOwner, user.UserName, userLoginMustBeDomain)
|
||||
func getUniqueUserAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, userName, emailAddress, resourceOwner string, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
|
||||
userNameAggregate, err := reservedUniqueUserNameAggregate(ctx, aggCreator, resourceOwner, userName, userLoginMustBeDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -149,11 +192,13 @@ func getUniqueUserAggregates(ctx context.Context, aggCreator *es_models.Aggregat
|
||||
userNameAggregate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func reservedUniqueUserNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, userName string, userLoginMustBeDomain bool) (*es_models.Aggregate, error) {
|
||||
uniqueUserName := userName
|
||||
if userLoginMustBeDomain {
|
||||
uniqueUserName = userName + resourceOwner
|
||||
}
|
||||
|
||||
aggregate, err := aggCreator.NewAggregate(ctx, uniqueUserName, model.UserUserNameAggregate, model.UserVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, uniqueUserName, model.UserUserNameAggregate, model.UserVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
@@ -225,173 +270,190 @@ func userStateAggregate(aggCreator *es_models.AggregateCreator, user *model.User
|
||||
}
|
||||
}
|
||||
|
||||
func UserInitCodeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, code *model.InitUserCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func UserInitCodeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, code *model.InitUserCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if code == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d8i23", "code should not be nil")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.InitializedUserCodeAdded, code)
|
||||
return agg.AppendEvent(model.InitializedHumanCodeAdded, code)
|
||||
}
|
||||
}
|
||||
|
||||
func UserInitCodeSentAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func UserInitCodeSentAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.InitializedUserCodeSent, nil)
|
||||
return agg.AppendEvent(model.InitializedHumanCodeSent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func InitCodeVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, password *model.Password) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func InitCodeVerifiedAggregate(aggCreator *es_models.AggregateCreator, user *model.User, password *model.Password) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.Email != nil && !existing.Email.IsEmailVerified {
|
||||
agg, err = agg.AppendEvent(model.UserEmailVerified, nil)
|
||||
if user.Email != nil && !user.Email.IsEmailVerified {
|
||||
agg, err = agg.AppendEvent(model.HumanEmailVerified, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if password != nil && password.Secret != nil {
|
||||
agg, err = agg.AppendEvent(model.UserPasswordChanged, password)
|
||||
agg, err = agg.AppendEvent(model.HumanPasswordChanged, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return agg.AppendEvent(model.InitializedUserCheckSucceeded, nil)
|
||||
return agg.AppendEvent(model.InitializedHumanCheckSucceeded, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func InitCodeCheckFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func InitCodeCheckFailedAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.InitializedUserCheckFailed, nil)
|
||||
return agg.AppendEvent(model.InitializedHumanCheckFailed, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func SkipMfaAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func SkipMfaAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.MfaInitSkipped, nil)
|
||||
return agg.AppendEvent(model.HumanMfaInitSkipped, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func PasswordChangeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, password *model.Password) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func PasswordChangeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, password *model.Password) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if password == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d9832", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPasswordChanged, password)
|
||||
return agg.AppendEvent(model.HumanPasswordChanged, password)
|
||||
}
|
||||
}
|
||||
|
||||
func PasswordCheckSucceededAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, check *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
func PasswordCheckSucceededAggregate(aggCreator *es_models.AggregateCreator, user *model.User, check *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPasswordCheckSucceeded, check)
|
||||
return agg.AppendEvent(model.HumanPasswordCheckSucceeded, check)
|
||||
}
|
||||
}
|
||||
func PasswordCheckFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, check *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
func PasswordCheckFailedAggregate(aggCreator *es_models.AggregateCreator, user *model.User, check *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPasswordCheckFailed, check)
|
||||
return agg.AppendEvent(model.HumanPasswordCheckFailed, check)
|
||||
}
|
||||
}
|
||||
|
||||
func RequestSetPassword(aggCreator *es_models.AggregateCreator, existing *model.User, request *model.PasswordCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func RequestSetPassword(aggCreator *es_models.AggregateCreator, user *model.User, request *model.PasswordCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if request == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d8ei2", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPasswordCodeAdded, request)
|
||||
return agg.AppendEvent(model.HumanPasswordCodeAdded, request)
|
||||
}
|
||||
}
|
||||
|
||||
func PasswordCodeSentAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func PasswordCodeSentAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPasswordCodeSent, nil)
|
||||
return agg.AppendEvent(model.HumanPasswordCodeSent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func ProfileChangeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, profile *model.Profile) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func MachineChangeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, machine *model.Machine) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if machine == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes := user.Machine.Changes(machine)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-0spow", "Errors.NoChangesFound")
|
||||
}
|
||||
return agg.AppendEvent(model.MachineChanged, changes)
|
||||
}
|
||||
}
|
||||
|
||||
func ProfileChangeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, profile *model.Profile) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if profile == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes := existing.Profile.Changes(profile)
|
||||
changes := user.Profile.Changes(profile)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-0spow", "Errors.NoChangesFound")
|
||||
}
|
||||
return agg.AppendEvent(model.UserProfileChanged, changes)
|
||||
return agg.AppendEvent(model.HumanProfileChanged, changes)
|
||||
}
|
||||
}
|
||||
|
||||
func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.User, email *model.Email, code *model.EmailCode) (*es_models.Aggregate, error) {
|
||||
func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, email *model.Email, code *model.EmailCode) (*es_models.Aggregate, error) {
|
||||
if email == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dki8s", "Errors.Internal")
|
||||
}
|
||||
if (!email.IsEmailVerified && code == nil) || (email.IsEmailVerified && code != nil) {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-id934", "Errors.Internal")
|
||||
}
|
||||
changes := existing.Email.Changes(email)
|
||||
changes := user.Email.Changes(email)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-s90pw", "Errors.NoChangesFound")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg, err = agg.AppendEvent(model.UserEmailChanged, changes)
|
||||
agg, err = agg.AppendEvent(model.HumanEmailChanged, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.Email == nil {
|
||||
existing.Email = new(model.Email)
|
||||
if user.Email == nil {
|
||||
user.Email = new(model.Email)
|
||||
}
|
||||
if email.IsEmailVerified {
|
||||
agg, err = agg.AppendEvent(model.UserEmailVerified, code)
|
||||
agg, err = agg.AppendEvent(model.HumanEmailVerified, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if code != nil {
|
||||
agg, err = agg.AppendEvent(model.UserEmailCodeAdded, code)
|
||||
agg, err = agg.AppendEvent(model.HumanEmailCodeAdded, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -399,50 +461,50 @@ func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCr
|
||||
return agg, nil
|
||||
}
|
||||
|
||||
func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc {
|
||||
func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, user *model.User) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserEmailVerified, nil)
|
||||
return agg.AppendEvent(model.HumanEmailVerified, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func EmailVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc {
|
||||
func EmailVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, user *model.User) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserEmailVerificationFailed, nil)
|
||||
return agg.AppendEvent(model.HumanEmailVerificationFailed, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func EmailVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, code *model.EmailCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func EmailVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, code *model.EmailCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if code == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dki8s", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserEmailCodeAdded, code)
|
||||
return agg.AppendEvent(model.HumanEmailCodeAdded, code)
|
||||
}
|
||||
}
|
||||
|
||||
func EmailCodeSentAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func EmailCodeSentAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserEmailCodeSent, nil)
|
||||
return agg.AppendEvent(model.HumanEmailCodeSent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func PhoneChangeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, phone *model.Phone, code *model.PhoneCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func PhoneChangeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, phone *model.Phone, code *model.PhoneCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if phone == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dkso3", "Errors.Internal")
|
||||
@@ -450,184 +512,184 @@ func PhoneChangeAggregate(aggCreator *es_models.AggregateCreator, existing *mode
|
||||
if (!phone.IsPhoneVerified && code == nil) || (phone.IsPhoneVerified && code != nil) {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dksi8", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.Phone == nil {
|
||||
existing.Phone = new(model.Phone)
|
||||
if user.Phone == nil {
|
||||
user.Phone = new(model.Phone)
|
||||
}
|
||||
changes := existing.Phone.Changes(phone)
|
||||
changes := user.Phone.Changes(phone)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sp0oc", "Errors.NoChangesFound")
|
||||
}
|
||||
agg, err = agg.AppendEvent(model.UserPhoneChanged, changes)
|
||||
agg, err = agg.AppendEvent(model.HumanPhoneChanged, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if phone.IsPhoneVerified {
|
||||
return agg.AppendEvent(model.UserPhoneVerified, code)
|
||||
return agg.AppendEvent(model.HumanPhoneVerified, code)
|
||||
}
|
||||
if code != nil {
|
||||
return agg.AppendEvent(model.UserPhoneCodeAdded, code)
|
||||
return agg.AppendEvent(model.HumanPhoneCodeAdded, code)
|
||||
}
|
||||
return agg, nil
|
||||
}
|
||||
}
|
||||
|
||||
func PhoneRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc {
|
||||
func PhoneRemovedAggregate(aggCreator *es_models.AggregateCreator, user *model.User) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPhoneRemoved, nil)
|
||||
return agg.AppendEvent(model.HumanPhoneRemoved, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc {
|
||||
func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, user *model.User) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPhoneVerified, nil)
|
||||
return agg.AppendEvent(model.HumanPhoneVerified, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func PhoneVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc {
|
||||
func PhoneVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, user *model.User) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPhoneVerificationFailed, nil)
|
||||
return agg.AppendEvent(model.HumanPhoneVerificationFailed, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func PhoneVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, code *model.PhoneCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func PhoneVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, code *model.PhoneCode) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if code == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dsue2", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPhoneCodeAdded, code)
|
||||
return agg.AppendEvent(model.HumanPhoneCodeAdded, code)
|
||||
}
|
||||
}
|
||||
|
||||
func PhoneCodeSentAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func PhoneCodeSentAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserPhoneCodeSent, nil)
|
||||
return agg.AppendEvent(model.HumanPhoneCodeSent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func AddressChangeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, address *model.Address) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func AddressChangeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, address *model.Address) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if address == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dkx9s", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.Address == nil {
|
||||
existing.Address = new(model.Address)
|
||||
if user.Address == nil {
|
||||
user.Address = new(model.Address)
|
||||
}
|
||||
changes := existing.Address.Changes(address)
|
||||
changes := user.Address.Changes(address)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-2tszw", "Errors.NoChangesFound")
|
||||
}
|
||||
return agg.AppendEvent(model.UserAddressChanged, changes)
|
||||
return agg.AppendEvent(model.HumanAddressChanged, changes)
|
||||
}
|
||||
}
|
||||
|
||||
func MfaOTPAddAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, otp *model.OTP) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func MFAOTPAddAggregate(aggCreator *es_models.AggregateCreator, user *model.User, otp *model.OTP) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if otp == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dkx9s", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.MfaOtpAdded, otp)
|
||||
return agg.AppendEvent(model.HumanMFAOTPAdded, otp)
|
||||
}
|
||||
}
|
||||
|
||||
func MfaOTPVerifyAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func MFAOTPVerifyAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.MfaOtpVerified, nil)
|
||||
return agg.AppendEvent(model.HumanMFAOTPVerified, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func MfaOTPCheckSucceededAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, authReq *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
func MFAOTPCheckSucceededAggregate(aggCreator *es_models.AggregateCreator, user *model.User, authReq *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if authReq == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sd5DA", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.MfaOtpCheckSucceeded, authReq)
|
||||
return agg.AppendEvent(model.HumanMfaOtpCheckSucceeded, authReq)
|
||||
}
|
||||
}
|
||||
|
||||
func MfaOTPCheckFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, authReq *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
func MFAOTPCheckFailedAggregate(aggCreator *es_models.AggregateCreator, user *model.User, authReq *model.AuthRequest) es_sdk.AggregateFunc {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if authReq == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-64sd6", "Errors.Internal")
|
||||
}
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.MfaOtpCheckFailed, authReq)
|
||||
return agg.AppendEvent(model.HumanMfaOtpCheckFailed, authReq)
|
||||
}
|
||||
}
|
||||
|
||||
func MfaOTPRemoveAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
func MFAOTPRemoveAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserAggregate(ctx, aggCreator, existing)
|
||||
agg, err := UserAggregate(ctx, aggCreator, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.MfaOtpRemoved, nil)
|
||||
return agg.AppendEvent(model.HumanMFAOTPRemoved, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func SignOutAggregates(aggCreator *es_models.AggregateCreator, existingUsers []*model.User, agentID string) func(ctx context.Context) ([]*es_models.Aggregate, error) {
|
||||
func SignOutAggregates(aggCreator *es_models.AggregateCreator, users []*model.User, agentID string) func(ctx context.Context) ([]*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) ([]*es_models.Aggregate, error) {
|
||||
aggregates := make([]*es_models.Aggregate, len(existingUsers))
|
||||
for i, existing := range existingUsers {
|
||||
agg, err := UserAggregateOverwriteContext(ctx, aggCreator, existing, existing.ResourceOwner, existing.AggregateID)
|
||||
aggregates := make([]*es_models.Aggregate, len(users))
|
||||
for i, user := range users {
|
||||
agg, err := UserAggregateOverwriteContext(ctx, aggCreator, user, user.ResourceOwner, user.AggregateID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg.AppendEvent(model.SignedOut, map[string]interface{}{"userAgentID": agentID})
|
||||
agg.AppendEvent(model.HumanSignedOut, map[string]interface{}{"userAgentID": agentID})
|
||||
aggregates[i] = agg
|
||||
}
|
||||
return aggregates, nil
|
||||
}
|
||||
}
|
||||
|
||||
func DomainClaimedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existingUser *model.User, tempName string) ([]*es_models.Aggregate, error) {
|
||||
aggregates, err := changeUniqueUserNameAggregate(ctx, aggCreator, existingUser.ResourceOwner, existingUser.UserName, tempName, false)
|
||||
func DomainClaimedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, tempName string) ([]*es_models.Aggregate, error) {
|
||||
aggregates, err := changeUniqueUserNameAggregate(ctx, aggCreator, user.ResourceOwner, user.UserName, tempName, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userAggregate, err := UserAggregateOverwriteContext(ctx, aggCreator, existingUser, existingUser.ResourceOwner, existingUser.AggregateID)
|
||||
userAggregate, err := UserAggregateOverwriteContext(ctx, aggCreator, user, user.ResourceOwner, user.AggregateID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
65
internal/user/repository/view/machine_key_view.go
Normal file
65
internal/user/repository/view/machine_key_view.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
func MachineKeyByIDs(db *gorm.DB, table, userID, keyID string) (*model.MachineKeyView, error) {
|
||||
key := new(model.MachineKeyView)
|
||||
query := repository.PrepareGetByQuery(table,
|
||||
model.MachineKeySearchQuery{Key: usr_model.MachineKeyKeyUserID, Method: global_model.SearchMethodEquals, Value: userID},
|
||||
model.MachineKeySearchQuery{Key: usr_model.MachineKeyKeyID, Method: global_model.SearchMethodEquals, Value: keyID},
|
||||
)
|
||||
err := query(db, key)
|
||||
if caos_errs.IsNotFound(err) {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-3Dk9s", "Errors.User.KeyNotFound")
|
||||
}
|
||||
return key, err
|
||||
}
|
||||
|
||||
func SearchMachineKeys(db *gorm.DB, table string, req *usr_model.MachineKeySearchRequest) ([]*model.MachineKeyView, uint64, error) {
|
||||
members := make([]*model.MachineKeyView, 0)
|
||||
query := repository.PrepareSearchQuery(table, model.MachineKeySearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||
count, err := query(db, &members)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return members, count, nil
|
||||
}
|
||||
|
||||
func MachineKeysByUserID(db *gorm.DB, table string, userID string) ([]*model.MachineKeyView, error) {
|
||||
keys := make([]*model.MachineKeyView, 0)
|
||||
queries := []*usr_model.MachineKeySearchQuery{
|
||||
{
|
||||
Key: usr_model.MachineKeyKeyUserID,
|
||||
Value: userID,
|
||||
Method: global_model.SearchMethodEquals,
|
||||
},
|
||||
}
|
||||
query := repository.PrepareSearchQuery(table, model.MachineKeySearchRequest{Queries: queries})
|
||||
_, err := query(db, &keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func PutMachineKey(db *gorm.DB, table string, role *model.MachineKeyView) error {
|
||||
save := repository.PrepareSave(table)
|
||||
return save(db, role)
|
||||
}
|
||||
|
||||
func DeleteMachineKey(db *gorm.DB, table, keyID string) error {
|
||||
delete := repository.PrepareDeleteByKey(table, model.MachineKeySearchKey(usr_model.MachineKeyKeyID), keyID)
|
||||
return delete(db)
|
||||
}
|
||||
|
||||
func DeleteMachineKeysByUserID(db *gorm.DB, table, userID string) error {
|
||||
delete := repository.PrepareDeleteByKey(table, model.MachineKeySearchKey(usr_model.MachineKeyKeyUserID), userID)
|
||||
return delete(db)
|
||||
}
|
81
internal/user/repository/view/model/machine_key.go
Normal file
81
internal/user/repository/view/model/machine_key.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
const (
|
||||
MachineKeyKeyID = "id"
|
||||
MachineKeyKeyUserID = "user_id"
|
||||
)
|
||||
|
||||
type MachineKeyView struct {
|
||||
ID string `json:"keyId" gorm:"column:id;primary_key"`
|
||||
UserID string `json:"-" gorm:"column:user_id;primary_key"`
|
||||
Type int32 `json:"type" gorm:"column:machine_type"`
|
||||
ExpirationDate time.Time `json:"expirationDate" gorm:"column:expiration_date"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
}
|
||||
|
||||
func MachineKeyViewFromModel(key *model.MachineKeyView) *MachineKeyView {
|
||||
return &MachineKeyView{
|
||||
ID: key.ID,
|
||||
UserID: key.UserID,
|
||||
Type: int32(key.Type),
|
||||
ExpirationDate: key.ExpirationDate,
|
||||
Sequence: key.Sequence,
|
||||
CreationDate: key.CreationDate,
|
||||
}
|
||||
}
|
||||
|
||||
func MachineKeyToModel(key *MachineKeyView) *model.MachineKeyView {
|
||||
return &model.MachineKeyView{
|
||||
ID: key.ID,
|
||||
UserID: key.UserID,
|
||||
Type: model.MachineKeyType(key.Type),
|
||||
ExpirationDate: key.ExpirationDate,
|
||||
Sequence: key.Sequence,
|
||||
CreationDate: key.CreationDate,
|
||||
}
|
||||
}
|
||||
|
||||
func MachineKeysToModel(keys []*MachineKeyView) []*model.MachineKeyView {
|
||||
result := make([]*model.MachineKeyView, len(keys))
|
||||
for i, key := range keys {
|
||||
result[i] = MachineKeyToModel(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (k *MachineKeyView) AppendEvent(event *models.Event) (err error) {
|
||||
k.Sequence = event.Sequence
|
||||
switch event.Type {
|
||||
case es_model.MachineKeyAdded:
|
||||
k.setRootData(event)
|
||||
k.CreationDate = event.CreationDate
|
||||
err = k.SetData(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (k *MachineKeyView) setRootData(event *models.Event) {
|
||||
k.UserID = event.AggregateID
|
||||
}
|
||||
|
||||
func (r *MachineKeyView) SetData(event *models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||
logging.Log("EVEN-Sj90d").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-lub6s", "Could not unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
61
internal/user/repository/view/model/machine_key_query.go
Normal file
61
internal/user/repository/view/model/machine_key_query.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
type MachineKeySearchRequest usr_model.MachineKeySearchRequest
|
||||
type MachineKeySearchQuery usr_model.MachineKeySearchQuery
|
||||
type MachineKeySearchKey usr_model.MachineKeySearchKey
|
||||
|
||||
func (req MachineKeySearchRequest) GetLimit() uint64 {
|
||||
return req.Limit
|
||||
}
|
||||
|
||||
func (req MachineKeySearchRequest) GetOffset() uint64 {
|
||||
return req.Offset
|
||||
}
|
||||
|
||||
func (req MachineKeySearchRequest) GetSortingColumn() repository.ColumnKey {
|
||||
if req.SortingColumn == usr_model.MachineKeyKeyUnspecified {
|
||||
return nil
|
||||
}
|
||||
return MachineKeySearchKey(req.SortingColumn)
|
||||
}
|
||||
|
||||
func (req MachineKeySearchRequest) GetAsc() bool {
|
||||
return req.Asc
|
||||
}
|
||||
|
||||
func (req MachineKeySearchRequest) GetQueries() []repository.SearchQuery {
|
||||
result := make([]repository.SearchQuery, len(req.Queries))
|
||||
for i, q := range req.Queries {
|
||||
result[i] = MachineKeySearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (req MachineKeySearchQuery) GetKey() repository.ColumnKey {
|
||||
return MachineKeySearchKey(req.Key)
|
||||
}
|
||||
|
||||
func (req MachineKeySearchQuery) GetMethod() global_model.SearchMethod {
|
||||
return req.Method
|
||||
}
|
||||
|
||||
func (req MachineKeySearchQuery) GetValue() interface{} {
|
||||
return req.Value
|
||||
}
|
||||
|
||||
func (key MachineKeySearchKey) ToColumnName() string {
|
||||
switch usr_model.MachineKeySearchKey(key) {
|
||||
case usr_model.MachineKeyKeyID:
|
||||
return MachineKeyKeyID
|
||||
case usr_model.MachineKeyKeyUserID:
|
||||
return MachineKeyKeyUserID
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
@@ -2,6 +2,8 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
@@ -9,7 +11,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
"github.com/lib/pq"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -112,7 +113,9 @@ func (u *NotifyUser) AppendEvent(event *models.Event) (err error) {
|
||||
u.Sequence = event.Sequence
|
||||
switch event.Type {
|
||||
case es_model.UserAdded,
|
||||
es_model.UserRegistered:
|
||||
es_model.UserRegistered,
|
||||
es_model.HumanRegistered,
|
||||
es_model.HumanAdded:
|
||||
u.CreationDate = event.CreationDate
|
||||
u.setRootData(event)
|
||||
err = u.setData(event)
|
||||
@@ -120,20 +123,25 @@ func (u *NotifyUser) AppendEvent(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
err = u.setPasswordData(event)
|
||||
case es_model.UserProfileChanged:
|
||||
case es_model.UserProfileChanged,
|
||||
es_model.UserEmailChanged,
|
||||
es_model.UserPhoneChanged,
|
||||
es_model.HumanProfileChanged,
|
||||
es_model.HumanEmailChanged,
|
||||
es_model.HumanPhoneChanged:
|
||||
err = u.setData(event)
|
||||
case es_model.UserEmailChanged:
|
||||
err = u.setData(event)
|
||||
case es_model.UserEmailVerified:
|
||||
case es_model.UserEmailVerified,
|
||||
es_model.HumanEmailVerified:
|
||||
u.VerifiedEmail = u.LastEmail
|
||||
case es_model.UserPhoneChanged:
|
||||
err = u.setData(event)
|
||||
case es_model.UserPhoneRemoved:
|
||||
case es_model.UserPhoneRemoved,
|
||||
es_model.HumanPhoneRemoved:
|
||||
u.VerifiedPhone = ""
|
||||
u.LastPhone = ""
|
||||
case es_model.UserPhoneVerified:
|
||||
case es_model.UserPhoneVerified,
|
||||
es_model.HumanPhoneVerified:
|
||||
u.VerifiedPhone = u.LastPhone
|
||||
case es_model.UserPasswordChanged:
|
||||
case es_model.UserPasswordChanged,
|
||||
es_model.HumanPasswordChanged:
|
||||
err = u.setPasswordData(event)
|
||||
}
|
||||
return err
|
||||
|
@@ -2,9 +2,10 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/lib/pq"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
@@ -26,118 +27,131 @@ const (
|
||||
UserKeyState = "user_state"
|
||||
UserKeyResourceOwner = "resource_owner"
|
||||
UserKeyLoginNames = "login_names"
|
||||
UserKeyType = "user_type"
|
||||
)
|
||||
|
||||
type userType string
|
||||
|
||||
const (
|
||||
userTypeHuman = "human"
|
||||
userTypeMachine = "machine"
|
||||
)
|
||||
|
||||
type UserView struct {
|
||||
ID string `json:"-" gorm:"column:id;primary_key"`
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
||||
State int32 `json:"-" gorm:"column:user_state"`
|
||||
PasswordSet bool `json:"-" gorm:"column:password_set"`
|
||||
PasswordChangeRequired bool `json:"-" gorm:"column:password_change_required"`
|
||||
UsernameChangeRequired bool `json:"-" gorm:"column:username_change_required"`
|
||||
PasswordChanged time.Time `json:"-" gorm:"column:password_change"`
|
||||
LastLogin time.Time `json:"-" gorm:"column:last_login"`
|
||||
UserName string `json:"userName" gorm:"column:user_name"`
|
||||
LoginNames pq.StringArray `json:"-" gorm:"column:login_names"`
|
||||
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
|
||||
FirstName string `json:"firstName" gorm:"column:first_name"`
|
||||
LastName string `json:"lastName" gorm:"column:last_name"`
|
||||
NickName string `json:"nickName" gorm:"column:nick_name"`
|
||||
DisplayName string `json:"displayName" gorm:"column:display_name"`
|
||||
PreferredLanguage string `json:"preferredLanguage" gorm:"column:preferred_language"`
|
||||
Gender int32 `json:"gender" gorm:"column:gender"`
|
||||
Email string `json:"email" gorm:"column:email"`
|
||||
IsEmailVerified bool `json:"-" gorm:"column:is_email_verified"`
|
||||
Phone string `json:"phone" gorm:"column:phone"`
|
||||
IsPhoneVerified bool `json:"-" gorm:"column:is_phone_verified"`
|
||||
Country string `json:"country" gorm:"column:country"`
|
||||
Locality string `json:"locality" gorm:"column:locality"`
|
||||
PostalCode string `json:"postalCode" gorm:"column:postal_code"`
|
||||
Region string `json:"region" gorm:"column:region"`
|
||||
StreetAddress string `json:"streetAddress" gorm:"column:street_address"`
|
||||
OTPState int32 `json:"-" gorm:"column:otp_state"`
|
||||
MfaMaxSetUp int32 `json:"-" gorm:"column:mfa_max_set_up"`
|
||||
MfaInitSkipped time.Time `json:"-" gorm:"column:mfa_init_skipped"`
|
||||
InitRequired bool `json:"-" gorm:"column:init_required"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
ID string `json:"-" gorm:"column:id;primary_key"`
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
||||
State int32 `json:"-" gorm:"column:user_state"`
|
||||
LastLogin time.Time `json:"-" gorm:"column:last_login"`
|
||||
LoginNames pq.StringArray `json:"-" gorm:"column:login_names"`
|
||||
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
Type userType `json:"-" gorm:"column:user_type"`
|
||||
UserName string `json:"userName" gorm:"column:user_name"`
|
||||
*MachineView
|
||||
*HumanView
|
||||
}
|
||||
|
||||
func UserFromModel(user *model.UserView) *UserView {
|
||||
return &UserView{
|
||||
ID: user.ID,
|
||||
ChangeDate: user.ChangeDate,
|
||||
CreationDate: user.CreationDate,
|
||||
ResourceOwner: user.ResourceOwner,
|
||||
State: int32(user.State),
|
||||
PasswordSet: user.PasswordSet,
|
||||
PasswordChangeRequired: user.PasswordChangeRequired,
|
||||
UsernameChangeRequired: user.UsernameChangeRequired,
|
||||
PasswordChanged: user.PasswordChanged,
|
||||
LastLogin: user.LastLogin,
|
||||
UserName: user.UserName,
|
||||
LoginNames: user.LoginNames,
|
||||
PreferredLoginName: user.PreferredLoginName,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
NickName: user.NickName,
|
||||
DisplayName: user.DisplayName,
|
||||
PreferredLanguage: user.PreferredLanguage,
|
||||
Gender: int32(user.Gender),
|
||||
Email: user.Email,
|
||||
IsEmailVerified: user.IsEmailVerified,
|
||||
Phone: user.Phone,
|
||||
IsPhoneVerified: user.IsPhoneVerified,
|
||||
Country: user.Country,
|
||||
Locality: user.Locality,
|
||||
PostalCode: user.PostalCode,
|
||||
Region: user.Region,
|
||||
StreetAddress: user.StreetAddress,
|
||||
OTPState: int32(user.OTPState),
|
||||
MfaMaxSetUp: int32(user.MfaMaxSetUp),
|
||||
MfaInitSkipped: user.MfaInitSkipped,
|
||||
InitRequired: user.InitRequired,
|
||||
Sequence: user.Sequence,
|
||||
}
|
||||
type UserState int32
|
||||
|
||||
const (
|
||||
UserStateUnspecified UserState = iota
|
||||
UserStateActive
|
||||
UserStateInactive
|
||||
UserStateDeleted
|
||||
UserStateLocked
|
||||
UserStateSuspend
|
||||
UserStateInitial
|
||||
)
|
||||
|
||||
type HumanView struct {
|
||||
FirstName string `json:"firstName" gorm:"column:first_name"`
|
||||
LastName string `json:"lastName" gorm:"column:last_name"`
|
||||
NickName string `json:"nickName" gorm:"column:nick_name"`
|
||||
DisplayName string `json:"displayName" gorm:"column:display_name"`
|
||||
PreferredLanguage string `json:"preferredLanguage" gorm:"column:preferred_language"`
|
||||
Gender int32 `json:"gender" gorm:"column:gender"`
|
||||
Email string `json:"email" gorm:"column:email"`
|
||||
IsEmailVerified bool `json:"-" gorm:"column:is_email_verified"`
|
||||
Phone string `json:"phone" gorm:"column:phone"`
|
||||
IsPhoneVerified bool `json:"-" gorm:"column:is_phone_verified"`
|
||||
Country string `json:"country" gorm:"column:country"`
|
||||
Locality string `json:"locality" gorm:"column:locality"`
|
||||
PostalCode string `json:"postalCode" gorm:"column:postal_code"`
|
||||
Region string `json:"region" gorm:"column:region"`
|
||||
StreetAddress string `json:"streetAddress" gorm:"column:street_address"`
|
||||
OTPState int32 `json:"-" gorm:"column:otp_state"`
|
||||
MfaMaxSetUp int32 `json:"-" gorm:"column:mfa_max_set_up"`
|
||||
MfaInitSkipped time.Time `json:"-" gorm:"column:mfa_init_skipped"`
|
||||
InitRequired bool `json:"-" gorm:"column:init_required"`
|
||||
|
||||
PasswordSet bool `json:"-" gorm:"column:password_set"`
|
||||
PasswordChangeRequired bool `json:"-" gorm:"column:password_change_required"`
|
||||
UsernameChangeRequired bool `json:"-" gorm:"column:username_change_required"`
|
||||
PasswordChanged time.Time `json:"-" gorm:"column:password_change"`
|
||||
}
|
||||
|
||||
func (h *HumanView) IsZero() bool {
|
||||
return h == nil || h.FirstName == ""
|
||||
}
|
||||
|
||||
type MachineView struct {
|
||||
Name string `json:"name" gorm:"column:machine_name"`
|
||||
Description string `json:"description" gorm:"column:machine_description"`
|
||||
}
|
||||
|
||||
func (m *MachineView) IsZero() bool {
|
||||
return m == nil || m.Name == ""
|
||||
}
|
||||
|
||||
func UserToModel(user *UserView) *model.UserView {
|
||||
return &model.UserView{
|
||||
ID: user.ID,
|
||||
ChangeDate: user.ChangeDate,
|
||||
CreationDate: user.CreationDate,
|
||||
ResourceOwner: user.ResourceOwner,
|
||||
State: model.UserState(user.State),
|
||||
PasswordSet: user.PasswordSet,
|
||||
PasswordChangeRequired: user.PasswordChangeRequired,
|
||||
UsernameChangeRequired: user.UsernameChangeRequired,
|
||||
PasswordChanged: user.PasswordChanged,
|
||||
LastLogin: user.LastLogin,
|
||||
PreferredLoginName: user.PreferredLoginName,
|
||||
LoginNames: user.LoginNames,
|
||||
UserName: user.UserName,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
NickName: user.NickName,
|
||||
DisplayName: user.DisplayName,
|
||||
PreferredLanguage: user.PreferredLanguage,
|
||||
Gender: model.Gender(user.Gender),
|
||||
Email: user.Email,
|
||||
IsEmailVerified: user.IsEmailVerified,
|
||||
Phone: user.Phone,
|
||||
IsPhoneVerified: user.IsPhoneVerified,
|
||||
Country: user.Country,
|
||||
Locality: user.Locality,
|
||||
PostalCode: user.PostalCode,
|
||||
Region: user.Region,
|
||||
StreetAddress: user.StreetAddress,
|
||||
OTPState: model.MfaState(user.OTPState),
|
||||
MfaMaxSetUp: req_model.MfaLevel(user.MfaMaxSetUp),
|
||||
MfaInitSkipped: user.MfaInitSkipped,
|
||||
InitRequired: user.InitRequired,
|
||||
Sequence: user.Sequence,
|
||||
userView := &model.UserView{
|
||||
ID: user.ID,
|
||||
UserName: user.UserName,
|
||||
ChangeDate: user.ChangeDate,
|
||||
CreationDate: user.CreationDate,
|
||||
ResourceOwner: user.ResourceOwner,
|
||||
State: model.UserState(user.State),
|
||||
LastLogin: user.LastLogin,
|
||||
PreferredLoginName: user.PreferredLoginName,
|
||||
LoginNames: user.LoginNames,
|
||||
Sequence: user.Sequence,
|
||||
}
|
||||
if !user.HumanView.IsZero() {
|
||||
userView.HumanView = &model.HumanView{
|
||||
PasswordSet: user.PasswordSet,
|
||||
PasswordChangeRequired: user.PasswordChangeRequired,
|
||||
PasswordChanged: user.PasswordChanged,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
NickName: user.NickName,
|
||||
DisplayName: user.DisplayName,
|
||||
PreferredLanguage: user.PreferredLanguage,
|
||||
Gender: model.Gender(user.Gender),
|
||||
Email: user.Email,
|
||||
IsEmailVerified: user.IsEmailVerified,
|
||||
Phone: user.Phone,
|
||||
IsPhoneVerified: user.IsPhoneVerified,
|
||||
Country: user.Country,
|
||||
Locality: user.Locality,
|
||||
PostalCode: user.PostalCode,
|
||||
Region: user.Region,
|
||||
StreetAddress: user.StreetAddress,
|
||||
OTPState: model.MfaState(user.OTPState),
|
||||
MfaMaxSetUp: req_model.MfaLevel(user.MfaMaxSetUp),
|
||||
MfaInitSkipped: user.MfaInitSkipped,
|
||||
InitRequired: user.InitRequired,
|
||||
}
|
||||
}
|
||||
|
||||
if !user.MachineView.IsZero() {
|
||||
userView.MachineView = &model.MachineView{
|
||||
Description: user.MachineView.Description,
|
||||
Name: user.MachineView.Name,
|
||||
}
|
||||
}
|
||||
return userView
|
||||
}
|
||||
|
||||
func UsersToModel(users []*UserView) []*model.UserView {
|
||||
@@ -172,19 +186,34 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) {
|
||||
u.ChangeDate = event.CreationDate
|
||||
u.Sequence = event.Sequence
|
||||
switch event.Type {
|
||||
case es_model.UserAdded,
|
||||
es_model.UserRegistered:
|
||||
case es_model.MachineAdded:
|
||||
u.CreationDate = event.CreationDate
|
||||
u.setRootData(event)
|
||||
u.Type = userTypeMachine
|
||||
err = u.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case es_model.UserAdded,
|
||||
es_model.UserRegistered,
|
||||
es_model.HumanRegistered,
|
||||
es_model.HumanAdded:
|
||||
u.CreationDate = event.CreationDate
|
||||
u.setRootData(event)
|
||||
u.Type = userTypeHuman
|
||||
err = u.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = u.setPasswordData(event)
|
||||
case es_model.UserPasswordChanged:
|
||||
case es_model.UserPasswordChanged,
|
||||
es_model.HumanPasswordChanged:
|
||||
err = u.setPasswordData(event)
|
||||
case es_model.UserProfileChanged,
|
||||
es_model.UserAddressChanged:
|
||||
es_model.HumanProfileChanged,
|
||||
es_model.UserAddressChanged,
|
||||
es_model.HumanAddressChanged,
|
||||
es_model.MachineChanged:
|
||||
err = u.setData(event)
|
||||
case es_model.DomainClaimed:
|
||||
u.UsernameChangeRequired = true
|
||||
@@ -192,17 +221,22 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) {
|
||||
case es_model.UserUserNameChanged:
|
||||
u.UsernameChangeRequired = false
|
||||
err = u.setData(event)
|
||||
case es_model.UserEmailChanged:
|
||||
case es_model.UserEmailChanged,
|
||||
es_model.HumanEmailChanged:
|
||||
u.IsEmailVerified = false
|
||||
err = u.setData(event)
|
||||
case es_model.UserEmailVerified:
|
||||
case es_model.UserEmailVerified,
|
||||
es_model.HumanEmailVerified:
|
||||
u.IsEmailVerified = true
|
||||
case es_model.UserPhoneChanged:
|
||||
case es_model.UserPhoneChanged,
|
||||
es_model.HumanPhoneChanged:
|
||||
u.IsPhoneVerified = false
|
||||
err = u.setData(event)
|
||||
case es_model.UserPhoneVerified:
|
||||
case es_model.UserPhoneVerified,
|
||||
es_model.HumanPhoneVerified:
|
||||
u.IsPhoneVerified = true
|
||||
case es_model.UserPhoneRemoved:
|
||||
case es_model.UserPhoneRemoved,
|
||||
es_model.HumanPhoneRemoved:
|
||||
u.Phone = ""
|
||||
u.IsPhoneVerified = false
|
||||
case es_model.UserDeactivated:
|
||||
@@ -212,18 +246,24 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) {
|
||||
u.State = int32(model.UserStateActive)
|
||||
case es_model.UserLocked:
|
||||
u.State = int32(model.UserStateLocked)
|
||||
case es_model.MfaOtpAdded:
|
||||
case es_model.MFAOTPAdded,
|
||||
es_model.HumanMFAOTPAdded:
|
||||
u.OTPState = int32(model.MfaStateNotReady)
|
||||
case es_model.MfaOtpVerified:
|
||||
case es_model.MFAOTPVerified,
|
||||
es_model.HumanMFAOTPVerified:
|
||||
u.OTPState = int32(model.MfaStateReady)
|
||||
u.MfaInitSkipped = time.Time{}
|
||||
case es_model.MfaOtpRemoved:
|
||||
case es_model.MFAOTPRemoved,
|
||||
es_model.HumanMFAOTPRemoved:
|
||||
u.OTPState = int32(model.MfaStateUnspecified)
|
||||
case es_model.MfaInitSkipped:
|
||||
case es_model.MFAInitSkipped,
|
||||
es_model.HumanMfaInitSkipped:
|
||||
u.MfaInitSkipped = event.CreationDate
|
||||
case es_model.InitializedUserCodeAdded:
|
||||
case es_model.InitializedUserCodeAdded,
|
||||
es_model.InitializedHumanCodeAdded:
|
||||
u.InitRequired = true
|
||||
case es_model.InitializedUserCheckSucceeded:
|
||||
case es_model.InitializedUserCheckSucceeded,
|
||||
es_model.InitializedHumanCheckSucceeded:
|
||||
u.InitRequired = false
|
||||
}
|
||||
u.ComputeObject()
|
||||
@@ -256,6 +296,12 @@ func (u *UserView) setPasswordData(event *models.Event) error {
|
||||
}
|
||||
|
||||
func (u *UserView) ComputeObject() {
|
||||
if u.MachineView != nil {
|
||||
if u.State == int32(model.UserStateUnspecified) {
|
||||
u.State = int32(model.UserStateActive)
|
||||
}
|
||||
return
|
||||
}
|
||||
if u.State == int32(model.UserStateUnspecified) || u.State == int32(model.UserStateInitial) {
|
||||
if u.IsEmailVerified {
|
||||
u.State = int32(model.UserStateActive)
|
||||
|
@@ -2,6 +2,8 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
@@ -10,7 +12,6 @@ import (
|
||||
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
"github.com/lib/pq"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@@ -71,6 +71,8 @@ func (key UserSearchKey) ToColumnName() string {
|
||||
return UserKeyResourceOwner
|
||||
case usr_model.UserSearchKeyLoginNames:
|
||||
return UserKeyLoginNames
|
||||
case usr_model.UserSearchKeyType:
|
||||
return UserKeyType
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
@@ -79,20 +79,27 @@ func (v *UserSessionView) AppendEvent(event *models.Event) {
|
||||
v.Sequence = event.Sequence
|
||||
v.ChangeDate = event.CreationDate
|
||||
switch event.Type {
|
||||
case es_model.UserPasswordCheckSucceeded:
|
||||
case es_model.UserPasswordCheckSucceeded,
|
||||
es_model.HumanPasswordCheckSucceeded:
|
||||
v.PasswordVerification = event.CreationDate
|
||||
v.State = int32(req_model.UserSessionStateActive)
|
||||
case es_model.UserPasswordCheckFailed,
|
||||
es_model.UserPasswordChanged:
|
||||
es_model.UserPasswordChanged,
|
||||
es_model.HumanPasswordCheckFailed,
|
||||
es_model.HumanPasswordChanged:
|
||||
v.PasswordVerification = time.Time{}
|
||||
case es_model.MfaOtpCheckSucceeded:
|
||||
case es_model.MfaOtpCheckSucceeded,
|
||||
es_model.HumanMfaOtpCheckSucceeded:
|
||||
v.MfaSoftwareVerification = event.CreationDate
|
||||
v.MfaSoftwareVerificationType = int32(req_model.MfaTypeOTP)
|
||||
v.State = int32(req_model.UserSessionStateActive)
|
||||
case es_model.MfaOtpCheckFailed,
|
||||
es_model.MfaOtpRemoved:
|
||||
es_model.MFAOTPRemoved,
|
||||
es_model.HumanMfaOtpCheckFailed,
|
||||
es_model.HumanMFAOTPRemoved:
|
||||
v.MfaSoftwareVerification = time.Time{}
|
||||
case es_model.SignedOut,
|
||||
es_model.HumanSignedOut,
|
||||
es_model.UserLocked,
|
||||
es_model.UserDeactivated:
|
||||
v.PasswordVerification = time.Time{}
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
func mockUserData(user *es_model.User) []byte {
|
||||
func mockUserData(user *es_model.Human) []byte {
|
||||
data, _ := json.Marshal(user)
|
||||
return data
|
||||
}
|
||||
@@ -41,10 +41,9 @@ func mockAddressData(address *es_model.Address) []byte {
|
||||
return data
|
||||
}
|
||||
|
||||
func getFullUser(password *es_model.Password) *es_model.User {
|
||||
return &es_model.User{
|
||||
func getFullUser(password *es_model.Password) *es_model.Human {
|
||||
return &es_model.Human{
|
||||
Profile: &es_model.Profile{
|
||||
UserName: "UserName",
|
||||
FirstName: "FirstName",
|
||||
LastName: "LastName",
|
||||
},
|
||||
@@ -77,7 +76,7 @@ func TestUserAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullUser(nil))},
|
||||
user: &UserView{},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInitial)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)},
|
||||
},
|
||||
{
|
||||
name: "append added user with password event",
|
||||
@@ -85,7 +84,7 @@ func TestUserAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullUser(&es_model.Password{Secret: &crypto.CryptoValue{}}))},
|
||||
user: &UserView{},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInitial), PasswordSet: true},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", PasswordSet: true}, State: int32(model.UserStateInitial)},
|
||||
},
|
||||
{
|
||||
name: "append added user with password but change required event",
|
||||
@@ -93,135 +92,135 @@ func TestUserAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullUser(&es_model.Password{ChangeRequired: true, Secret: &crypto.CryptoValue{}}))},
|
||||
user: &UserView{},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInitial), PasswordSet: true, PasswordChangeRequired: true},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", PasswordSet: true, PasswordChangeRequired: true}, State: int32(model.UserStateInitial)},
|
||||
},
|
||||
{
|
||||
name: "append password change event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserPasswordChanged, ResourceOwner: "OrgID", Data: mockPasswordData(&es_model.Password{Secret: &crypto.CryptoValue{}})},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), PasswordSet: true},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", PasswordSet: true}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append password change with change required event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserPasswordChanged, ResourceOwner: "OrgID", Data: mockPasswordData(&es_model.Password{ChangeRequired: true, Secret: &crypto.CryptoValue{}})},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), PasswordSet: true, PasswordChangeRequired: true},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", PasswordSet: true, PasswordChangeRequired: true}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append change user profile event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserProfileChanged, ResourceOwner: "OrgID", Data: mockProfileData(&es_model.Profile{FirstName: "FirstNameChanged"})},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInitial)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstNameChanged", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInitial)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstNameChanged", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)},
|
||||
},
|
||||
{
|
||||
name: "append change user email event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserEmailChanged, ResourceOwner: "OrgID", Data: mockEmailData(&es_model.Email{EmailAddress: "EmailChanged"})},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "EmailChanged", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "EmailChanged", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append verify user email event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserEmailVerified, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInitial)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append change user phone event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserPhoneChanged, ResourceOwner: "OrgID", Data: mockPhoneData(&es_model.Phone{PhoneNumber: "PhoneChanged"})},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "PhoneChanged", Country: "Country", State: int32(model.UserStateActive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "PhoneChanged", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append verify user phone event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserPhoneVerified, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", IsPhoneVerified: true, Country: "Country", State: int32(model.UserStateActive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", IsPhoneVerified: true, Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append change user address event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAddressChanged, ResourceOwner: "OrgID", Data: mockAddressData(&es_model.Address{Country: "CountryChanged"})},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "CountryChanged", State: int32(model.UserStateActive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "CountryChanged"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append user deactivate event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserDeactivated, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInactive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInactive)},
|
||||
},
|
||||
{
|
||||
name: "append user reactivate event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserReactivated, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateInactive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInactive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append user lock event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserLocked, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateLocked)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateLocked)},
|
||||
},
|
||||
{
|
||||
name: "append user unlock event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserUnlocked, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateLocked)},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateLocked)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append user add otp event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.MfaOtpAdded, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.MFAOTPAdded, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), OTPState: int32(model.MfaStateNotReady)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateNotReady)}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append user verify otp event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.MfaOtpVerified, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), OTPState: int32(model.MfaStateNotReady)},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.MFAOTPVerified, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateNotReady)}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), OTPState: int32(model.MfaStateReady)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateReady)}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append user remove otp event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.MfaOtpRemoved, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), OTPState: int32(model.MfaStateReady)},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.MFAOTPRemoved, ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateReady)}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), OTPState: int32(model.MfaStateUnspecified)},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateUnspecified)}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
{
|
||||
name: "append mfa init skipped event",
|
||||
args: args{
|
||||
event: &es_models.Event{Sequence: 1, CreationDate: time.Now().UTC(), Type: es_model.MfaInitSkipped, AggregateID: "AggregateID", ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive)},
|
||||
event: &es_models.Event{Sequence: 1, CreationDate: time.Now().UTC(), Type: es_model.MFAInitSkipped, AggregateID: "AggregateID", ResourceOwner: "OrgID"},
|
||||
user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", State: int32(model.UserStateActive), MfaInitSkipped: time.Now().UTC()},
|
||||
result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", MfaInitSkipped: time.Now().UTC()}, State: int32(model.UserStateActive)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@@ -111,15 +111,15 @@ func IsUserUnique(db *gorm.DB, table, userName, email string) (bool, error) {
|
||||
if err != nil && !caos_errs.IsNotFound(err) {
|
||||
return false, err
|
||||
}
|
||||
if user != nil {
|
||||
if user.UserName != "" {
|
||||
return false, nil
|
||||
}
|
||||
query = repository.PrepareGetByKey(table, model.UserSearchKey(usr_model.UserSearchKeyUserName), email)
|
||||
query = repository.PrepareGetByKey(table, model.UserSearchKey(usr_model.UserSearchKeyUserName), userName)
|
||||
err = query(db, user)
|
||||
if err != nil && !caos_errs.IsNotFound(err) {
|
||||
return false, err
|
||||
}
|
||||
return user == nil, nil
|
||||
return user.UserName == "", nil
|
||||
}
|
||||
|
||||
func UserMfas(db *gorm.DB, table, userID string) ([]*usr_model.MultiFactor, error) {
|
||||
|
Reference in New Issue
Block a user