feat: user commands (#75)

* feat: eventstore repository

* fix: remove gorm

* version

* feat: pkg

* feat: add some files for project

* feat: eventstore without eventstore-lib

* rename files

* gnueg

* fix: key json

* fix: add object

* fix: change imports

* fix: internal models

* fix: some imports

* fix: global model

* feat: add global view functions

* fix: add some functions on repo

* feat(eventstore): sdk

* fix(eventstore): search query

* fix(eventstore): rename app to eventstore

* delete empty test

* remove unused func

* merge master

* fix(eventstore): tests

* fix(models): delete unused struct

* fix: some funcitons

* feat(eventstore): implemented push events

* fix: move project eventstore to project package

* fix: change project eventstore funcs

* feat(eventstore): overwrite context data

* fix: change project eventstore

* fix: add project repo to mgmt server

* feat(types): SQL-config

* fix: commented code

* feat(eventstore): options to overwrite editor

* feat: auth interceptor and cockroach migrations

* fix: migrations

* fix: fix filter

* fix: not found on getbyid

* fix: use global sql config

* fix: add sequence

* fix: add some tests

* fix(eventstore): nullable sequence

* fix: add some tests

* merge

* fix: add some tests

* fix(migrations): correct statements for sequence

* fix: add some tests

* fix: add some tests

* fix: changes from mr

* fix: changes from mr

* fix: add some tests

* Update internal/eventstore/models/field.go

Co-Authored-By: livio-a <livio.a@gmail.com>

* fix(eventstore): code quality

* fix: add types to aggregate/Event-types

* fix: try tests

* fix(eventstore): rename modifier* to editor*

* fix(eventstore): delete editor_org

* fix(migrations): remove editor_org field,
rename modifier_* to editor_*

* fix: query tests

* fix: use prepare funcs

* fix: go mod

* fix: generate files

* fix(eventstore): tests

* fix(eventstore): rename modifier to editor

* fix(migrations): add cluster migration,
fix(migrations): fix typo of host in clean clsuter

* fix(eventstore): move health

* fix(eventstore): AggregateTypeFilter aggregateType as param

* code quality

* fix: go tests

* feat: add member funcs

* feat: add member model

* feat: add member events

* feat: add member repo model

* fix: better error func testing

* fix: project member funcs

* fix: add tests

* fix: add tests

* feat: implement member requests

* fix: merge master

* fix: merge master

* fix: read existing in project repo

* fix: fix tests

* feat: add internal cache

* feat: add cache mock

* fix: return values of cache mock

* feat: add project role

* fix: add cache config

* fix: add role to eventstore

* fix: use eventstore sdk

* fix: use eventstore sdk

* fix: add project role grpc requests

* fix: fix getby id

* fix: changes for mr

* fix: change value to interface

* feat: add app event creations

* fix: searchmethods

* Update internal/project/model/project_member.go

Co-Authored-By: Silvan <silvan.reusser@gmail.com>

* fix: use get project func

* fix: append events

* fix: check if value is string on equal ignore case

* fix: add changes test

* fix: add go mod

* fix: add some tests

* fix: return err not nil

* fix: return err not nil

* fix: add aggregate funcs and tests

* fix: add oidc aggregate funcs and tests

* fix: add oidc

* fix: add some tests

* fix: tests

* fix: oidc validation

* fix: generate client secret

* fix: generate client id

* fix: test change app

* fix: deactivate/reactivate application

* fix: change oidc config

* fix: change oidc config secret

* fix: implement grpc app funcs

* fix: add application requests

* fix: converter

* fix: converter

* fix: converter and generate clientid

* fix: tests

* feat: project grant aggregate

* feat: project grant

* fix: project grant check if role existing

* fix: project grant requests

* fix: project grant fixes

* fix: project grant member model

* fix: project grant member aggregate

* fix: project grant member eventstore

* fix: project grant member requests

* feat: user model

* feat: user command side

* user command side

* profile requests

* local config with gopass and more

* Update internal/user/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/address.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/address.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/email.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/email.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/email.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/mfa.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/mfa.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/password.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/password.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/password.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/phone.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/phone.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/phone.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/usergrant/repository/eventsourcing/model/user_grant.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/usergrant/repository/eventsourcing/model/user_grant.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/usergrant/repository/eventsourcing/user_grant.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/user_test.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* Update internal/user/repository/eventsourcing/eventstore_mock_test.go

Co-Authored-By: Livio Amstutz <livio.a@gmail.com>

* changes from mr review

* save files into basedir

* changes from mr review

* changes from mr review

* Update internal/usergrant/repository/eventsourcing/cache.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update internal/usergrant/repository/eventsourcing/cache.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* changes requested on mr

* fix generate codes

* fix return if no events

* password code

* Update internal/user/repository/eventsourcing/model/password.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update internal/user/repository/eventsourcing/model/user.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* requests of mr

* check email

Co-authored-by: adlerhurst <silvan.reusser@gmail.com>
Co-authored-by: livio-a <livio.a@gmail.com>
This commit is contained in:
Fabi
2020-05-11 10:16:27 +02:00
committed by GitHub
parent 380e4d0643
commit 49d86fdabb
71 changed files with 12791 additions and 2916 deletions

View File

@@ -0,0 +1,77 @@
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"
"github.com/caos/zitadel/internal/user/model"
)
type Address struct {
es_models.ObjectRoot
Country string `json:"country,omitempty"`
Locality string `json:"locality,omitempty"`
PostalCode string `json:"postalCode,omitempty"`
Region string `json:"region,omitempty"`
StreetAddress string `json:"streetAddress,omitempty"`
}
func (a *Address) Changes(changed *Address) map[string]interface{} {
changes := make(map[string]interface{}, 1)
if a.Country != changed.Country {
changes["country"] = changed.Country
}
if a.Locality != changed.Locality {
changes["locality"] = changed.Locality
}
if a.PostalCode != changed.PostalCode {
changes["postalCode"] = changed.PostalCode
}
if a.Region != changed.Region {
changes["region"] = changed.Region
}
if a.StreetAddress != changed.StreetAddress {
changes["streetAddress"] = changed.StreetAddress
}
return changes
}
func AddressFromModel(address *model.Address) *Address {
return &Address{
ObjectRoot: address.ObjectRoot,
Country: address.Country,
Locality: address.Locality,
PostalCode: address.PostalCode,
Region: address.Region,
StreetAddress: address.StreetAddress,
}
}
func AddressToModel(address *Address) *model.Address {
return &model.Address{
ObjectRoot: address.ObjectRoot,
Country: address.Country,
Locality: address.Locality,
PostalCode: address.PostalCode,
Region: address.Region,
StreetAddress: address.StreetAddress,
}
}
func (u *User) appendUserAddressChangedEvent(event *es_models.Event) error {
if u.Address == nil {
u.Address = new(Address)
}
return u.Address.setData(event)
}
func (a *Address) setData(event *es_models.Event) error {
a.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, a); err != nil {
logging.Log("EVEN-clos0").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-so92s", "could not unmarshal event")
}
return nil
}

View File

@@ -0,0 +1,92 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"testing"
)
func TestAddressChanges(t *testing.T) {
type args struct {
existing *Address
new *Address
}
type res struct {
changesLen int
}
tests := []struct {
name string
args args
res res
}{
{
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"},
},
res: res{
changesLen: 5,
},
},
{
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"},
},
res: res{
changesLen: 0,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
changes := tt.args.existing.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))
}
})
}
}
func TestAppendUserAddressChangedEvent(t *testing.T) {
type args struct {
user *User
address *Address
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user address event",
args: args{
user: &User{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"}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.address != nil {
data, _ := json.Marshal(tt.args.address)
tt.args.event.Data = data
}
tt.args.user.appendUserAddressChangedEvent(tt.args.event)
if tt.args.user.Address.Locality != tt.result.Address.Locality {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
if tt.args.user.Address.Country != tt.result.Address.Country {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
if tt.args.user.Address.PostalCode != tt.result.Address.PostalCode {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}

View File

@@ -0,0 +1,102 @@
package model
import (
"encoding/json"
"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 {
es_models.ObjectRoot
EmailAddress string `json:"email,omitempty"`
IsEmailVerified bool `json:"-"`
isEmailUnique bool `json:"-"`
}
type EmailCode struct {
es_models.ObjectRoot
Code *crypto.CryptoValue `json:"code,omitempty"`
Expiry time.Duration `json:"expiry,omitempty"`
}
func (e *Email) Changes(changed *Email) map[string]interface{} {
changes := make(map[string]interface{}, 1)
if changed.EmailAddress != "" && e.EmailAddress != changed.EmailAddress {
changes["email"] = changed.EmailAddress
}
return changes
}
func EmailFromModel(email *model.Email) *Email {
return &Email{
ObjectRoot: email.ObjectRoot,
EmailAddress: email.EmailAddress,
IsEmailVerified: email.IsEmailVerified,
}
}
func EmailToModel(email *Email) *model.Email {
return &model.Email{
ObjectRoot: email.ObjectRoot,
EmailAddress: email.EmailAddress,
IsEmailVerified: email.IsEmailVerified,
}
}
func EmailCodeFromModel(code *model.EmailCode) *EmailCode {
if code == nil {
return nil
}
return &EmailCode{
ObjectRoot: code.ObjectRoot,
Expiry: code.Expiry,
Code: code.Code,
}
}
func EmailCodeToModel(code *EmailCode) *model.EmailCode {
return &model.EmailCode{
ObjectRoot: code.ObjectRoot,
Expiry: code.Expiry,
Code: code.Code,
}
}
func (u *User) appendUserEmailChangedEvent(event *es_models.Event) error {
u.Email = new(Email)
return u.Email.setData(event)
}
func (u *User) appendUserEmailCodeAddedEvent(event *es_models.Event) error {
u.EmailCode = new(EmailCode)
return u.EmailCode.setData(event)
}
func (u *User) appendUserEmailVerifiedEvent() {
u.IsEmailVerified = true
}
func (a *Email) setData(event *es_models.Event) error {
a.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, a); err != nil {
logging.Log("EVEN-dlo9s").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-sl9xw", "could not unmarshal event")
}
return nil
}
func (a *EmailCode) setData(event *es_models.Event) error {
a.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, a); err != nil {
logging.Log("EVEN-lo9s").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-s8uws", "could not unmarshal event")
}
return nil
}

View File

@@ -0,0 +1,152 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"testing"
"time"
)
func TestEmailChanges(t *testing.T) {
type args struct {
existing *Email
new *Email
}
type res struct {
changesLen int
}
tests := []struct {
name string
args args
res res
}{
{
name: "all fields changed",
args: args{
existing: &Email{EmailAddress: "Email", IsEmailVerified: true},
new: &Email{EmailAddress: "EmailChanged", IsEmailVerified: false},
},
res: res{
changesLen: 1,
},
},
{
name: "no fields changed",
args: args{
existing: &Email{EmailAddress: "Email", IsEmailVerified: true},
new: &Email{EmailAddress: "Email", IsEmailVerified: false},
},
res: res{
changesLen: 0,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
changes := tt.args.existing.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))
}
})
}
}
func TestAppendUserEmailChangedEvent(t *testing.T) {
type args struct {
user *User
email *Email
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user email event",
args: args{
user: &User{Email: &Email{EmailAddress: "EmailAddress"}},
email: &Email{EmailAddress: "EmailAddressChanged"},
event: &es_models.Event{},
},
result: &User{Email: &Email{EmailAddress: "EmailAddressChanged"}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.email != nil {
data, _ := json.Marshal(tt.args.email)
tt.args.event.Data = data
}
tt.args.user.appendUserEmailChangedEvent(tt.args.event)
if tt.args.user.Email.EmailAddress != tt.result.Email.EmailAddress {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendUserEmailCodeAddedEvent(t *testing.T) {
type args struct {
user *User
code *EmailCode
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user email code added event",
args: args{
user: &User{Email: &Email{EmailAddress: "EmailAddress"}},
code: &EmailCode{Expiry: time.Hour * 1},
event: &es_models.Event{},
},
result: &User{EmailCode: &EmailCode{Expiry: time.Hour * 1}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.code != nil {
data, _ := json.Marshal(tt.args.code)
tt.args.event.Data = data
}
tt.args.user.appendUserEmailCodeAddedEvent(tt.args.event)
if tt.args.user.EmailCode.Expiry != tt.result.EmailCode.Expiry {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendUserEmailVerifiedEvent(t *testing.T) {
type args struct {
user *User
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user email event",
args: args{
user: &User{Email: &Email{EmailAddress: "EmailAddress"}},
event: &es_models.Event{},
},
result: &User{Email: &Email{EmailAddress: "EmailAddress", IsEmailVerified: true}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.user.appendUserEmailVerifiedEvent()
if tt.args.user.Email.IsEmailVerified != tt.result.Email.IsEmailVerified {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}

View File

@@ -0,0 +1,57 @@
package model
import (
"encoding/json"
"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 OTP struct {
es_models.ObjectRoot
Secret *crypto.CryptoValue `json:"otpSecret,omitempty"`
State int32 `json:"-"`
}
func OTPFromModel(otp *model.OTP) *OTP {
return &OTP{
ObjectRoot: otp.ObjectRoot,
Secret: otp.Secret,
State: int32(otp.State),
}
}
func OTPToModel(otp *OTP) *model.OTP {
return &model.OTP{
ObjectRoot: otp.ObjectRoot,
Secret: otp.Secret,
State: model.MfaState(otp.State),
}
}
func (u *User) appendOtpAddedEvent(event *es_models.Event) error {
u.OTP = &OTP{
State: int32(model.MFASTATE_NOTREADY),
}
return u.OTP.setData(event)
}
func (u *User) appendOtpVerifiedEvent() {
u.OTP.State = int32(model.MFASTATE_READY)
}
func (u *User) appendOtpRemovedEvent() {
u.OTP = nil
}
func (o *OTP) setData(event *es_models.Event) error {
o.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, o); err != nil {
logging.Log("EVEN-d9soe").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-lo023", "could not unmarshal event")
}
return nil
}

View File

@@ -0,0 +1,109 @@
package model
import (
"encoding/json"
"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
otp *OTP
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user otp event",
args: args{
user: &User{},
otp: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}},
event: &es_models.Event{},
},
result: &User{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MFASTATE_NOTREADY)}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.otp != nil {
data, _ := json.Marshal(tt.args.otp)
tt.args.event.Data = data
}
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)
}
})
}
}
func TestAppendMfaOTPVerifyEvent(t *testing.T) {
type args struct {
user *User
otp *OTP
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append otp verify event",
args: args{
user: &User{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.MFASTATE_READY)}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.otp != nil {
data, _ := json.Marshal(tt.args.otp)
tt.args.event.Data = data
}
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)
}
})
}
}
func TestAppendMfaOTPRemoveEvent(t *testing.T) {
type args struct {
user *User
otp *OTP
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append otp verify event",
args: args{
user: &User{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}}},
event: &es_models.Event{},
},
result: &User{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.user.appendOtpRemovedEvent()
if tt.args.user.OTP != nil {
t.Errorf("got wrong result: actual: %v ", tt.result.OTP)
}
})
}
}

View File

@@ -0,0 +1,84 @@
package model
import (
"encoding/json"
"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 {
es_models.ObjectRoot
Secret *crypto.CryptoValue `json:"secret,omitempty"`
ChangeRequired bool `json:"changeRequired,omitempty"`
}
type PasswordCode struct {
es_models.ObjectRoot
Code *crypto.CryptoValue `json:"code,omitempty"`
Expiry time.Duration `json:"expiry,omitempty"`
NotificationType int32 `json:"notificationType,omitempty"`
}
func PasswordFromModel(password *model.Password) *Password {
return &Password{
ObjectRoot: password.ObjectRoot,
Secret: password.SecretCrypto,
ChangeRequired: password.ChangeRequired,
}
}
func PasswordToModel(password *Password) *model.Password {
return &model.Password{
ObjectRoot: password.ObjectRoot,
SecretCrypto: password.Secret,
ChangeRequired: password.ChangeRequired,
}
}
func PasswordCodeToModel(code *PasswordCode) *model.PasswordCode {
return &model.PasswordCode{
ObjectRoot: code.ObjectRoot,
Expiry: code.Expiry,
Code: code.Code,
NotificationType: model.NotificationType(code.NotificationType),
}
}
func (u *User) appendUserPasswordChangedEvent(event *es_models.Event) error {
u.Password = new(Password)
err := u.Password.setData(event)
if err != nil {
return err
}
u.Password.ObjectRoot.CreationDate = event.CreationDate
return nil
}
func (u *User) appendPasswordSetRequestedEvent(event *es_models.Event) error {
u.PasswordCode = new(PasswordCode)
return u.PasswordCode.setData(event)
}
func (pw *Password) setData(event *es_models.Event) error {
pw.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, pw); err != nil {
logging.Log("EVEN-dks93").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-sl9xlo2rsw", "could not unmarshal event")
}
return nil
}
func (a *PasswordCode) setData(event *es_models.Event) error {
a.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, a); err != nil {
logging.Log("EVEN-lo0y2").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-q21dr", "could not unmarshal event")
}
return nil
}

View File

@@ -0,0 +1,78 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"testing"
"time"
)
func TestAppendUserPasswordChangedEvent(t *testing.T) {
type args struct {
user *User
pw *Password
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append init user code event",
args: args{
user: &User{},
pw: &Password{ChangeRequired: true},
event: &es_models.Event{},
},
result: &User{Password: &Password{ChangeRequired: true}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.pw != nil {
data, _ := json.Marshal(tt.args.pw)
tt.args.event.Data = data
}
tt.args.user.appendUserPasswordChangedEvent(tt.args.event)
if tt.args.user.Password.ChangeRequired != tt.result.Password.ChangeRequired {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendPasswordSetRequestedEvent(t *testing.T) {
type args struct {
user *User
code *PasswordCode
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user phone code added event",
args: args{
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
code: &PasswordCode{Expiry: time.Hour * 1},
event: &es_models.Event{},
},
result: &User{PasswordCode: &PasswordCode{Expiry: time.Hour * 1}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.code != nil {
data, _ := json.Marshal(tt.args.code)
tt.args.event.Data = data
}
tt.args.user.appendPasswordSetRequestedEvent(tt.args.event)
if tt.args.user.PasswordCode.Expiry != tt.result.PasswordCode.Expiry {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}

View File

@@ -0,0 +1,100 @@
package model
import (
"encoding/json"
"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 {
es_models.ObjectRoot
PhoneNumber string `json:"phone,omitempty"`
IsPhoneVerified bool `json:"-"`
}
type PhoneCode struct {
es_models.ObjectRoot
Code *crypto.CryptoValue `json:"code,omitempty"`
Expiry time.Duration `json:"expiry,omitempty"`
}
func (p *Phone) Changes(changed *Phone) map[string]interface{} {
changes := make(map[string]interface{}, 1)
if changed.PhoneNumber != "" && p.PhoneNumber != changed.PhoneNumber {
changes["phone"] = changed.PhoneNumber
}
return changes
}
func PhoneFromModel(phone *model.Phone) *Phone {
return &Phone{
ObjectRoot: phone.ObjectRoot,
PhoneNumber: phone.PhoneNumber,
IsPhoneVerified: phone.IsPhoneVerified,
}
}
func PhoneToModel(phone *Phone) *model.Phone {
return &model.Phone{
ObjectRoot: phone.ObjectRoot,
PhoneNumber: phone.PhoneNumber,
IsPhoneVerified: phone.IsPhoneVerified,
}
}
func PhoneCodeFromModel(code *model.PhoneCode) *PhoneCode {
if code == nil {
return nil
}
return &PhoneCode{
ObjectRoot: code.ObjectRoot,
Expiry: code.Expiry,
Code: code.Code,
}
}
func PhoneCodeToModel(code *PhoneCode) *model.PhoneCode {
return &model.PhoneCode{
ObjectRoot: code.ObjectRoot,
Expiry: code.Expiry,
Code: code.Code,
}
}
func (u *User) appendUserPhoneChangedEvent(event *es_models.Event) error {
u.Phone = new(Phone)
return u.Phone.setData(event)
}
func (u *User) appendUserPhoneCodeAddedEvent(event *es_models.Event) error {
u.PhoneCode = new(PhoneCode)
return u.PhoneCode.setData(event)
}
func (u *User) appendUserPhoneVerifiedEvent() {
u.IsPhoneVerified = true
}
func (p *Phone) setData(event *es_models.Event) error {
p.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, p); err != nil {
logging.Log("EVEN-lco9s").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-lre56", "could not unmarshal event")
}
return nil
}
func (a *PhoneCode) setData(event *es_models.Event) error {
a.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, a); err != nil {
logging.Log("EVEN-sk8ws").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-7hdj3", "could not unmarshal event")
}
return nil
}

View File

@@ -0,0 +1,152 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"testing"
"time"
)
func TestPhoneChanges(t *testing.T) {
type args struct {
existing *Phone
new *Phone
}
type res struct {
changesLen int
}
tests := []struct {
name string
args args
res res
}{
{
name: "all fields changed",
args: args{
existing: &Phone{PhoneNumber: "Phone", IsPhoneVerified: true},
new: &Phone{PhoneNumber: "PhoneChanged", IsPhoneVerified: false},
},
res: res{
changesLen: 1,
},
},
{
name: "no fields changed",
args: args{
existing: &Phone{PhoneNumber: "Phone", IsPhoneVerified: true},
new: &Phone{PhoneNumber: "Phone", IsPhoneVerified: false},
},
res: res{
changesLen: 0,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
changes := tt.args.existing.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))
}
})
}
}
func TestAppendUserPhoneChangedEvent(t *testing.T) {
type args struct {
user *User
phone *Phone
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user phone event",
args: args{
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
phone: &Phone{PhoneNumber: "PhoneNumberChanged"},
event: &es_models.Event{},
},
result: &User{Phone: &Phone{PhoneNumber: "PhoneNumberChanged"}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.phone != nil {
data, _ := json.Marshal(tt.args.phone)
tt.args.event.Data = data
}
tt.args.user.appendUserPhoneChangedEvent(tt.args.event)
if tt.args.user.Phone.PhoneNumber != tt.result.Phone.PhoneNumber {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendUserPhoneCodeAddedEvent(t *testing.T) {
type args struct {
user *User
code *PhoneCode
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user phone code added event",
args: args{
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
code: &PhoneCode{Expiry: time.Hour * 1},
event: &es_models.Event{},
},
result: &User{PhoneCode: &PhoneCode{Expiry: time.Hour * 1}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.code != nil {
data, _ := json.Marshal(tt.args.code)
tt.args.event.Data = data
}
tt.args.user.appendUserPhoneCodeAddedEvent(tt.args.event)
if tt.args.user.PhoneCode.Expiry != tt.result.PhoneCode.Expiry {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendUserPhoneVerifiedEvent(t *testing.T) {
type args struct {
user *User
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append user phone event",
args: args{
user: &User{Phone: &Phone{PhoneNumber: "PhoneNumber"}},
event: &es_models.Event{},
},
result: &User{Phone: &Phone{PhoneNumber: "PhoneNumber", IsPhoneVerified: true}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.user.appendUserPhoneVerifiedEvent()
if tt.args.user.Phone.IsPhoneVerified != tt.result.Phone.IsPhoneVerified {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}

View File

@@ -0,0 +1,70 @@
package model
import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/model"
"golang.org/x/text/language"
)
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"`
DisplayName string `json:"displayName,omitempty"`
PreferredLanguage language.Tag `json:"preferredLanguage,omitempty"`
Gender int32 `json:"gender,omitempty"`
isUserNameUnique bool `json:"-"`
}
func (p *Profile) Changes(changed *Profile) map[string]interface{} {
changes := make(map[string]interface{}, 1)
if changed.FirstName != "" && p.FirstName != changed.FirstName {
changes["firstName"] = changed.FirstName
}
if changed.LastName != "" && p.LastName != changed.LastName {
changes["lastName"] = changed.LastName
}
if changed.NickName != p.NickName {
changes["nickName"] = changed.NickName
}
if changed.DisplayName != p.DisplayName {
changes["displayName"] = changed.DisplayName
}
if p.PreferredLanguage != language.Und && changed.PreferredLanguage != p.PreferredLanguage {
changes["preferredLanguage"] = changed.PreferredLanguage
}
if p.Gender > 0 && changed.Gender != p.Gender {
changes["gender"] = changed.Gender
}
return changes
}
func ProfileFromModel(profile *model.Profile) *Profile {
return &Profile{
ObjectRoot: profile.ObjectRoot,
UserName: profile.UserName,
FirstName: profile.FirstName,
LastName: profile.LastName,
NickName: profile.NickName,
DisplayName: profile.DisplayName,
PreferredLanguage: profile.PreferredLanguage,
Gender: int32(profile.Gender),
}
}
func ProfileToModel(profile *Profile) *model.Profile {
return &model.Profile{
ObjectRoot: profile.ObjectRoot,
UserName: profile.UserName,
FirstName: profile.FirstName,
LastName: profile.LastName,
NickName: profile.NickName,
DisplayName: profile.DisplayName,
PreferredLanguage: profile.PreferredLanguage,
Gender: model.Gender(profile.Gender),
}
}

View File

@@ -0,0 +1,71 @@
package model
import (
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
}
type res struct {
changesLen int
}
tests := []struct {
name string
args args
res res
}{
{
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.GENDER_FEMALE)},
new: &Profile{UserName: "UserNameChanged", FirstName: "FirstNameChanged", LastName: "LastNameChanged", NickName: "NickNameChanged", DisplayName: "DisplayNameChanged", PreferredLanguage: language.English, Gender: int32(user_model.GENDER_MALE)},
},
res: res{
changesLen: 6,
},
},
{
name: "no changes",
args: args{
existing: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GENDER_FEMALE)},
new: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GENDER_FEMALE)},
},
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.GENDER_FEMALE)},
new: &Profile{UserName: "UserNameChanged", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GENDER_FEMALE)},
},
res: res{
changesLen: 0,
},
},
{
name: "empty names",
args: args{
existing: &Profile{UserName: "UserName", FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GENDER_FEMALE)},
new: &Profile{UserName: "UserName", FirstName: "", LastName: "", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GENDER_FEMALE)},
},
res: res{
changesLen: 0,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
changes := tt.args.existing.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))
}
})
}
}

View File

@@ -0,0 +1,47 @@
package model
import "github.com/caos/zitadel/internal/eventstore/models"
const (
UserAggregate models.AggregateType = "user"
UserUserNameAggregate models.AggregateType = "user.username"
UserEmailAggregate models.AggregateType = "user.email"
UserAdded models.EventType = "user.added"
UserRegistered models.EventType = "user.selfregistered"
InitializedUserCodeAdded models.EventType = "user.initialization.code.added"
InitializedUserCodeSent models.EventType = "user.initialization.code.sent"
UserUserNameReserved models.EventType = "user.username.reserved"
UserUserNameReleased models.EventType = "user.username.released"
UserEmailReserved models.EventType = "user.email.reserved"
UserEmailReleased models.EventType = "user.email.released"
UserLocked models.EventType = "user.locked"
UserUnlocked models.EventType = "user.unlocked"
UserDeactivated models.EventType = "user.deactivated"
UserReactivated models.EventType = "user.reactivated"
UserDeleted models.EventType = "user.deleted"
UserPasswordChanged models.EventType = "user.password.changed"
UserPasswordCodeAdded models.EventType = "user.password.code.added"
UserPasswordCodeSent models.EventType = "user.password.code.sent"
UserEmailChanged models.EventType = "user.email.changed"
UserEmailVerified models.EventType = "user.email.verified"
UserEmailCodeAdded models.EventType = "user.email.code.added"
UserEmailCodeSent models.EventType = "user.email.code.sent"
UserPhoneChanged models.EventType = "user.phone.changed"
UserPhoneVerified models.EventType = "user.phone.verified"
UserPhoneCodeAdded models.EventType = "user.phone.code.added"
UserPhoneCodeSent models.EventType = "user.phone.code.sent"
UserProfileChanged models.EventType = "user.profile.changed"
UserAddressChanged models.EventType = "user.address.changed"
MfaOtpAdded models.EventType = "user.mfa.otp.added"
MfaOtpVerified models.EventType = "user.mfa.otp.verified"
MfaOtpRemoved models.EventType = "user.mfa.otp.removed"
MfaInitSkipped models.EventType = "user.mfa.init.skipped"
)

View File

@@ -0,0 +1,246 @@
package model
import (
"encoding/json"
"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"
)
const (
UserVersion = "v1"
)
type User struct {
es_models.ObjectRoot
State int32 `json:"-"`
*Password
*Profile
*Email
*Phone
*Address
InitCode *InitUserCode
EmailCode *EmailCode
PhoneCode *PhoneCode
PasswordCode *PasswordCode
OTP *OTP
}
type InitUserCode struct {
es_models.ObjectRoot
Code *crypto.CryptoValue `json:"code,omitempty"`
Expiry time.Duration `json:"expiry,omitempty"`
}
func UserFromModel(user *model.User) *User {
converted := &User{
ObjectRoot: user.ObjectRoot,
State: int32(user.State),
}
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{
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,
}
}
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 {
for _, event := range events {
if err := p.AppendEvent(event); err != nil {
return err
}
}
return nil
}
func (u *User) AppendEvent(event *es_models.Event) (err error) {
u.ObjectRoot.AppendEvent(event)
switch event.Type {
case UserAdded,
UserRegistered,
UserProfileChanged:
u.setData(event)
case UserDeactivated:
u.appendDeactivatedEvent()
case UserReactivated:
u.appendReactivatedEvent()
case UserLocked:
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 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.USERSTATE_ACTIVE)
} else {
u.State = int32(model.USERSTATE_INITIAL)
}
}
if u.Password != nil && u.Password.ObjectRoot.IsZero() {
u.Password.ObjectRoot = u.ObjectRoot
}
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
}
}
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")
}
return nil
}
func (u *User) appendDeactivatedEvent() {
u.State = int32(model.USERSTATE_INACTIVE)
}
func (u *User) appendReactivatedEvent() {
u.State = int32(model.USERSTATE_ACTIVE)
}
func (u *User) appendLockedEvent() {
u.State = int32(model.USERSTATE_LOCKED)
}
func (u *User) appendUnlockedEvent() {
u.State = int32(model.USERSTATE_ACTIVE)
}
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
}

View File

@@ -0,0 +1,152 @@
package model
import (
"encoding/json"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/model"
"testing"
"time"
)
func TestAppendDeactivatedEvent(t *testing.T) {
type args struct {
user *User
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append deactivate event",
args: args{
user: &User{},
},
result: &User{State: int32(model.USERSTATE_INACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.user.appendDeactivatedEvent()
if tt.args.user.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendReactivatedEvent(t *testing.T) {
type args struct {
user *User
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append reactivate event",
args: args{
user: &User{},
},
result: &User{State: int32(model.USERSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.user.appendReactivatedEvent()
if tt.args.user.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendLockEvent(t *testing.T) {
type args struct {
user *User
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append lock event",
args: args{
user: &User{},
},
result: &User{State: int32(model.USERSTATE_LOCKED)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.user.appendLockedEvent()
if tt.args.user.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendUnlockEvent(t *testing.T) {
type args struct {
user *User
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append unlock event",
args: args{
user: &User{},
},
result: &User{State: int32(model.USERSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.user.appendUnlockedEvent()
if tt.args.user.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}
func TestAppendInitUserCodeEvent(t *testing.T) {
type args struct {
user *User
code *InitUserCode
event *es_models.Event
}
tests := []struct {
name string
args args
result *User
}{
{
name: "append init user code event",
args: args{
user: &User{},
code: &InitUserCode{Expiry: time.Hour * 30},
event: &es_models.Event{},
},
result: &User{InitCode: &InitUserCode{Expiry: time.Hour * 30}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.code != nil {
data, _ := json.Marshal(tt.args.code)
tt.args.event.Data = data
}
tt.args.user.appendInitUsercodeCreatedEvent(tt.args.event)
if tt.args.user.InitCode.Expiry != tt.result.InitCode.Expiry {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user)
}
})
}
}