feat: New user (#1153)

* fix: use pointer in events

* fix: change user requests to command side

* fix: org policy

* fix: profile
This commit is contained in:
Fabi 2021-01-06 11:12:56 +01:00 committed by GitHub
parent 61d16e4621
commit 65a8efeb0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 810 additions and 283 deletions

View File

@ -60,48 +60,48 @@ func (s *Server) CreateUser(ctx context.Context, in *management.CreateUserReques
} }
func (s *Server) DeactivateUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { func (s *Server) DeactivateUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) {
user, err := s.user.DeactivateUser(ctx, in.Id) user, err := s.command.DeactivateUser(ctx, in.Id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return userFromModel(user), nil return userFromDomain(user), nil
} }
func (s *Server) ReactivateUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { func (s *Server) ReactivateUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) {
user, err := s.user.ReactivateUser(ctx, in.Id) user, err := s.command.ReactivateUser(ctx, in.Id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return userFromModel(user), nil return userFromDomain(user), nil
} }
func (s *Server) LockUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { func (s *Server) LockUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) {
user, err := s.user.LockUser(ctx, in.Id) user, err := s.command.LockUser(ctx, in.Id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return userFromModel(user), nil return userFromDomain(user), nil
} }
func (s *Server) UnlockUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) { func (s *Server) UnlockUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) {
user, err := s.user.UnlockUser(ctx, in.Id) user, err := s.command.UnlockUser(ctx, in.Id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return userFromModel(user), nil return userFromDomain(user), nil
} }
func (s *Server) DeleteUser(ctx context.Context, in *management.UserID) (*empty.Empty, error) { func (s *Server) DeleteUser(ctx context.Context, in *management.UserID) (*empty.Empty, error) {
err := s.user.RemoveUser(ctx, in.Id) err := s.command.RemoveUser(ctx, in.Id)
return &empty.Empty{}, err return &empty.Empty{}, err
} }
func (s *Server) UpdateUserMachine(ctx context.Context, in *management.UpdateMachineRequest) (*management.MachineResponse, error) { func (s *Server) UpdateUserMachine(ctx context.Context, in *management.UpdateMachineRequest) (*management.MachineResponse, error) {
machine, err := s.user.ChangeMachine(ctx, updateMachineToModel(in)) machine, err := s.command.ChangeMachine(ctx, updateMachineToDomain(in))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return machineFromModel(machine), nil return machineFromDomain(machine), nil
} }
func (s *Server) GetUserProfile(ctx context.Context, in *management.UserID) (*management.UserProfileView, error) { func (s *Server) GetUserProfile(ctx context.Context, in *management.UserID) (*management.UserProfileView, error) {
@ -117,11 +117,11 @@ func (s *Server) ChangeUserUserName(ctx context.Context, request *management.Upd
} }
func (s *Server) UpdateUserProfile(ctx context.Context, request *management.UpdateUserProfileRequest) (*management.UserProfile, error) { func (s *Server) UpdateUserProfile(ctx context.Context, request *management.UpdateUserProfileRequest) (*management.UserProfile, error) {
profile, err := s.user.ChangeProfile(ctx, updateProfileToModel(request)) profile, err := s.command.ChangeHumanProfile(ctx, updateProfileToDomain(request))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return profileFromModel(profile), nil return profileFromDomain(profile), nil
} }
func (s *Server) GetUserEmail(ctx context.Context, in *management.UserID) (*management.UserEmailView, error) { func (s *Server) GetUserEmail(ctx context.Context, in *management.UserID) (*management.UserEmailView, error) {
@ -133,11 +133,11 @@ func (s *Server) GetUserEmail(ctx context.Context, in *management.UserID) (*mana
} }
func (s *Server) ChangeUserEmail(ctx context.Context, request *management.UpdateUserEmailRequest) (*management.UserEmail, error) { func (s *Server) ChangeUserEmail(ctx context.Context, request *management.UpdateUserEmailRequest) (*management.UserEmail, error) {
email, err := s.user.ChangeEmail(ctx, updateEmailToModel(request)) email, err := s.command.ChangeHumanEmail(ctx, updateEmailToDomain(request))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return emailFromModel(email), nil return emailFromDomain(email), nil
} }
func (s *Server) ResendEmailVerificationMail(ctx context.Context, in *management.UserID) (*empty.Empty, error) { func (s *Server) ResendEmailVerificationMail(ctx context.Context, in *management.UserID) (*empty.Empty, error) {
@ -180,11 +180,11 @@ func (s *Server) GetUserAddress(ctx context.Context, in *management.UserID) (*ma
} }
func (s *Server) UpdateUserAddress(ctx context.Context, request *management.UpdateUserAddressRequest) (*management.UserAddress, error) { func (s *Server) UpdateUserAddress(ctx context.Context, request *management.UpdateUserAddressRequest) (*management.UserAddress, error) {
address, err := s.user.ChangeAddress(ctx, updateAddressToModel(request)) address, err := s.command.ChangeHumanAddress(ctx, updateAddressToDomain(request))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return addressFromModel(address), nil return addressFromDomain(address), nil
} }
func (s *Server) SendSetPasswordNotification(ctx context.Context, request *management.SetPasswordNotificationRequest) (*empty.Empty, error) { func (s *Server) SendSetPasswordNotification(ctx context.Context, request *management.SetPasswordNotificationRequest) (*empty.Empty, error) {

View File

@ -43,32 +43,6 @@ func userFromDomain(user *domain.User) *management.UserResponse {
return userResp return userResp
} }
func userFromModel(user *usr_model.User) *management.UserResponse {
creationDate, err := ptypes.TimestampProto(user.CreationDate)
logging.Log("GRPC-8duwe").OnError(err).Debug("unable to parse timestamp")
changeDate, err := ptypes.TimestampProto(user.ChangeDate)
logging.Log("GRPC-ckoe3d").OnError(err).Debug("unable to parse timestamp")
userResp := &management.UserResponse{
Id: user.AggregateID,
State: management.UserState(user.State),
CreationDate: creationDate,
ChangeDate: changeDate,
Sequence: user.Sequence,
UserName: user.UserName,
}
if user.Machine != nil {
userResp.User = &management.UserResponse_Machine{Machine: machineFromModel(user.Machine)}
}
if user.Human != nil {
userResp.User = &management.UserResponse_Human{Human: humanFromModel(user.Human)}
}
return userResp
}
func userCreateToDomain(user *management.CreateUserRequest) *domain.User { func userCreateToDomain(user *management.CreateUserRequest) *domain.User {
var human *domain.Human var human *domain.Human
var machine *domain.Machine var machine *domain.Machine
@ -232,7 +206,7 @@ func userMembershipSearchKeyToModel(key management.UserMembershipSearchKey) usr_
} }
} }
func profileFromModel(profile *usr_model.Profile) *management.UserProfile { func profileFromDomain(profile *domain.Profile) *management.UserProfile {
creationDate, err := ptypes.TimestampProto(profile.CreationDate) creationDate, err := ptypes.TimestampProto(profile.CreationDate)
logging.Log("GRPC-dkso3").OnError(err).Debug("unable to parse timestamp") logging.Log("GRPC-dkso3").OnError(err).Debug("unable to parse timestamp")
@ -276,21 +250,21 @@ func profileViewFromModel(profile *usr_model.Profile) *management.UserProfileVie
} }
} }
func updateProfileToModel(u *management.UpdateUserProfileRequest) *usr_model.Profile { func updateProfileToDomain(u *management.UpdateUserProfileRequest) *domain.Profile {
preferredLanguage, err := language.Parse(u.PreferredLanguage) preferredLanguage, err := language.Parse(u.PreferredLanguage)
logging.Log("GRPC-d8k2s").OnError(err).Debug("language malformed") logging.Log("GRPC-d8k2s").OnError(err).Debug("language malformed")
return &usr_model.Profile{ return &domain.Profile{
ObjectRoot: models.ObjectRoot{AggregateID: u.Id}, ObjectRoot: models.ObjectRoot{AggregateID: u.Id},
FirstName: u.FirstName, FirstName: u.FirstName,
LastName: u.LastName, LastName: u.LastName,
NickName: u.NickName, NickName: u.NickName,
PreferredLanguage: preferredLanguage, PreferredLanguage: preferredLanguage,
Gender: usr_model.Gender(u.Gender), Gender: genderToDomain(u.Gender),
} }
} }
func emailFromModel(email *usr_model.Email) *management.UserEmail { func emailFromDomain(email *domain.Email) *management.UserEmail {
creationDate, err := ptypes.TimestampProto(email.CreationDate) creationDate, err := ptypes.TimestampProto(email.CreationDate)
logging.Log("GRPC-d9ow2").OnError(err).Debug("unable to parse timestamp") logging.Log("GRPC-d9ow2").OnError(err).Debug("unable to parse timestamp")
@ -324,8 +298,8 @@ func emailViewFromModel(email *usr_model.Email) *management.UserEmailView {
} }
} }
func updateEmailToModel(e *management.UpdateUserEmailRequest) *usr_model.Email { func updateEmailToDomain(e *management.UpdateUserEmailRequest) *domain.Email {
return &usr_model.Email{ return &domain.Email{
ObjectRoot: models.ObjectRoot{AggregateID: e.Id}, ObjectRoot: models.ObjectRoot{AggregateID: e.Id},
EmailAddress: e.Email, EmailAddress: e.Email,
IsEmailVerified: e.IsEmailVerified, IsEmailVerified: e.IsEmailVerified,
@ -373,7 +347,7 @@ func updatePhoneToModel(e *management.UpdateUserPhoneRequest) *usr_model.Phone {
} }
} }
func addressFromModel(address *usr_model.Address) *management.UserAddress { func addressFromDomain(address *domain.Address) *management.UserAddress {
creationDate, err := ptypes.TimestampProto(address.CreationDate) creationDate, err := ptypes.TimestampProto(address.CreationDate)
logging.Log("GRPC-ud8w7").OnError(err).Debug("unable to parse timestamp") logging.Log("GRPC-ud8w7").OnError(err).Debug("unable to parse timestamp")
@ -413,8 +387,8 @@ func addressViewFromModel(address *usr_model.Address) *management.UserAddressVie
} }
} }
func updateAddressToModel(address *management.UpdateUserAddressRequest) *usr_model.Address { func updateAddressToDomain(address *management.UpdateUserAddressRequest) *domain.Address {
return &usr_model.Address{ return &domain.Address{
ObjectRoot: models.ObjectRoot{AggregateID: address.Id}, ObjectRoot: models.ObjectRoot{AggregateID: address.Id},
Country: address.Country, Country: address.Country,
StreetAddress: address.StreetAddress, StreetAddress: address.StreetAddress,

View File

@ -20,9 +20,10 @@ func machineCreateToDomain(machine *management.CreateMachineRequest) *domain.Mac
} }
} }
func updateMachineToModel(machine *management.UpdateMachineRequest) *usr_model.Machine { func updateMachineToDomain(machine *management.UpdateMachineRequest) *domain.Machine {
return &usr_model.Machine{ return &domain.Machine{
ObjectRoot: models.ObjectRoot{AggregateID: machine.Id}, ObjectRoot: models.ObjectRoot{AggregateID: machine.Id},
Name: machine.Name,
Description: machine.Description, Description: machine.Description,
} }
} }
@ -34,13 +35,6 @@ func machineFromDomain(account *domain.Machine) *management.MachineResponse {
} }
} }
func machineFromModel(account *usr_model.Machine) *management.MachineResponse {
return &management.MachineResponse{
Name: account.Name,
Description: account.Description,
}
}
func machineViewFromModel(machine *usr_model.MachineView) *management.MachineView { func machineViewFromModel(machine *usr_model.MachineView) *management.MachineView {
lastKeyAdded, err := ptypes.TimestampProto(machine.LastKeyAdded) lastKeyAdded, err := ptypes.TimestampProto(machine.LastKeyAdded)
logging.Log("MANAG-wGcAQ").OnError(err).Debug("unable to parse date") logging.Log("MANAG-wGcAQ").OnError(err).Debug("unable to parse date")

View File

@ -207,7 +207,7 @@ func eventData(event EventPusher) ([]byte, error) {
if dataType.Kind() == reflect.Struct { if dataType.Kind() == reflect.Struct {
dataBytes, err := json.Marshal(event.Data()) dataBytes, err := json.Marshal(event.Data())
if err != nil { if err != nil {
return nil, errors.ThrowInvalidArgument(err, "V2-xG87M", "could not marhsal data") return nil, errors.ThrowInvalidArgument(err, "V2-xG87M", "could not marshal data")
} }
return dataBytes, nil return dataBytes, nil
} }

View File

@ -45,16 +45,15 @@ func (wm *IAMLabelPolicyWriteModel) NewChangedEvent(
primaryColor, primaryColor,
secondaryColor string, secondaryColor string,
) (*iam.LabelPolicyChangedEvent, bool) { ) (*iam.LabelPolicyChangedEvent, bool) {
hasChanged := false hasChanged := false
changedEvent := iam.NewLabelPolicyChangedEvent(ctx) changedEvent := iam.NewLabelPolicyChangedEvent(ctx)
if wm.PrimaryColor != primaryColor { if wm.PrimaryColor != primaryColor {
hasChanged = true hasChanged = true
changedEvent.PrimaryColor = primaryColor changedEvent.PrimaryColor = &primaryColor
} }
if wm.SecondaryColor != secondaryColor { if wm.SecondaryColor != secondaryColor {
hasChanged = true hasChanged = true
changedEvent.SecondaryColor = secondaryColor changedEvent.SecondaryColor = &secondaryColor
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -58,23 +58,23 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
changedEvent := iam.NewLoginPolicyChangedEvent(ctx) changedEvent := iam.NewLoginPolicyChangedEvent(ctx)
if wm.AllowUserNamePassword == allowUsernamePassword { if wm.AllowUserNamePassword == allowUsernamePassword {
hasChanged = true hasChanged = true
changedEvent.AllowUserNamePassword = allowUsernamePassword changedEvent.AllowUserNamePassword = &allowUsernamePassword
} }
if wm.AllowRegister == allowRegister { if wm.AllowRegister == allowRegister {
hasChanged = true hasChanged = true
changedEvent.AllowRegister = allowRegister changedEvent.AllowRegister = &allowRegister
} }
if wm.AllowExternalIDP == allowExternalIDP { if wm.AllowExternalIDP == allowExternalIDP {
hasChanged = true hasChanged = true
changedEvent.AllowExternalIDP = allowExternalIDP changedEvent.AllowExternalIDP = &allowExternalIDP
} }
if wm.ForceMFA != forceMFA { if wm.ForceMFA != forceMFA {
hasChanged = true hasChanged = true
changedEvent.ForceMFA = forceMFA changedEvent.ForceMFA = &forceMFA
} }
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType { if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
hasChanged = true hasChanged = true
changedEvent.PasswordlessType = passwordlessType changedEvent.PasswordlessType = &passwordlessType
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -45,7 +45,7 @@ func (wm *IAMOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLo
changedEvent := iam.NewOrgIAMPolicyChangedEvent(ctx) changedEvent := iam.NewOrgIAMPolicyChangedEvent(ctx)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain { if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
hasChanged = true hasChanged = true
changedEvent.UserLoginMustBeDomain = userLoginMustBeDomain changedEvent.UserLoginMustBeDomain = &userLoginMustBeDomain
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -45,11 +45,11 @@ func (wm *IAMPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, e
changedEvent := iam.NewPasswordAgePolicyChangedEvent(ctx) changedEvent := iam.NewPasswordAgePolicyChangedEvent(ctx)
if wm.ExpireWarnDays != expireWarnDays { if wm.ExpireWarnDays != expireWarnDays {
hasChanged = true hasChanged = true
changedEvent.ExpireWarnDays = expireWarnDays changedEvent.ExpireWarnDays = &expireWarnDays
} }
if wm.MaxAgeDays != maxAgeDays { if wm.MaxAgeDays != maxAgeDays {
hasChanged = true hasChanged = true
changedEvent.MaxAgeDays = maxAgeDays changedEvent.MaxAgeDays = &maxAgeDays
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -53,23 +53,23 @@ func (wm *IAMPasswordComplexityPolicyWriteModel) NewChangedEvent(
changedEvent := iam.NewPasswordComplexityPolicyChangedEvent(ctx) changedEvent := iam.NewPasswordComplexityPolicyChangedEvent(ctx)
if wm.MinLength != minLength { if wm.MinLength != minLength {
hasChanged = true hasChanged = true
changedEvent.MinLength = minLength changedEvent.MinLength = &minLength
} }
if wm.HasLowercase != hasLowercase { if wm.HasLowercase != hasLowercase {
hasChanged = true hasChanged = true
changedEvent.HasLowercase = hasLowercase changedEvent.HasLowercase = &hasLowercase
} }
if wm.HasUpperCase != hasUppercase { if wm.HasUpperCase != hasUppercase {
hasChanged = true hasChanged = true
changedEvent.HasUpperCase = hasUppercase changedEvent.HasUpperCase = &hasUppercase
} }
if wm.HasNumber != hasNumber { if wm.HasNumber != hasNumber {
hasChanged = true hasChanged = true
changedEvent.HasNumber = hasNumber changedEvent.HasNumber = &hasNumber
} }
if wm.HasSymbol != hasSymbol { if wm.HasSymbol != hasSymbol {
hasChanged = true hasChanged = true
changedEvent.HasSymbol = hasSymbol changedEvent.HasSymbol = &hasSymbol
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -45,11 +45,11 @@ func (wm *IAMPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Contex
changedEvent := iam.NewPasswordLockoutPolicyChangedEvent(ctx) changedEvent := iam.NewPasswordLockoutPolicyChangedEvent(ctx)
if wm.MaxAttempts != maxAttempts { if wm.MaxAttempts != maxAttempts {
hasChanged = true hasChanged = true
changedEvent.MaxAttempts = maxAttempts changedEvent.MaxAttempts = &maxAttempts
} }
if wm.ShowLockOutFailures != showLockoutFailure { if wm.ShowLockOutFailures != showLockoutFailure {
hasChanged = true hasChanged = true
changedEvent.ShowLockOutFailures = showLockoutFailure changedEvent.ShowLockOutFailures = &showLockoutFailure
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -45,7 +45,7 @@ func (wm *ORGOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLo
changedEvent := org.NewOrgIAMPolicyChangedEvent(ctx) changedEvent := org.NewOrgIAMPolicyChangedEvent(ctx)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain { if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
hasChanged = true hasChanged = true
changedEvent.UserLoginMustBeDomain = userLoginMustBeDomain changedEvent.UserLoginMustBeDomain = &userLoginMustBeDomain
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -53,23 +53,23 @@ func (wm *OrgPasswordComplexityPolicyWriteModel) NewChangedEvent(
changedEvent := org.NewPasswordComplexityPolicyChangedEvent(ctx) changedEvent := org.NewPasswordComplexityPolicyChangedEvent(ctx)
if wm.MinLength != minLength { if wm.MinLength != minLength {
hasChanged = true hasChanged = true
changedEvent.MinLength = minLength changedEvent.MinLength = &minLength
} }
if wm.HasLowercase != hasLowercase { if wm.HasLowercase != hasLowercase {
hasChanged = true hasChanged = true
changedEvent.HasLowercase = hasLowercase changedEvent.HasLowercase = &hasLowercase
} }
if wm.HasUpperCase != hasUppercase { if wm.HasUpperCase != hasUppercase {
hasChanged = true hasChanged = true
changedEvent.HasUpperCase = hasUppercase changedEvent.HasUpperCase = &hasUppercase
} }
if wm.HasNumber != hasNumber { if wm.HasNumber != hasNumber {
hasChanged = true hasChanged = true
changedEvent.HasNumber = hasNumber changedEvent.HasNumber = &hasNumber
} }
if wm.HasSymbol != hasSymbol { if wm.HasSymbol != hasSymbol {
hasChanged = true hasChanged = true
changedEvent.HasSymbol = hasSymbol changedEvent.HasSymbol = &hasSymbol
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -21,8 +21,12 @@ func (wm *LabelPolicyWriteModel) Reduce() error {
wm.SecondaryColor = e.SecondaryColor wm.SecondaryColor = e.SecondaryColor
wm.IsActive = true wm.IsActive = true
case *policy.LabelPolicyChangedEvent: case *policy.LabelPolicyChangedEvent:
wm.PrimaryColor = e.PrimaryColor if e.PrimaryColor != nil {
wm.SecondaryColor = e.SecondaryColor wm.PrimaryColor = *e.PrimaryColor
}
if e.SecondaryColor != nil {
wm.SecondaryColor = *e.SecondaryColor
}
case *policy.LabelPolicyRemovedEvent: case *policy.LabelPolicyRemovedEvent:
wm.IsActive = false wm.IsActive = false
} }

View File

@ -28,11 +28,21 @@ func (wm *LoginPolicyWriteModel) Reduce() error {
wm.PasswordlessType = e.PasswordlessType wm.PasswordlessType = e.PasswordlessType
wm.IsActive = true wm.IsActive = true
case *policy.LoginPolicyChangedEvent: case *policy.LoginPolicyChangedEvent:
wm.AllowRegister = e.AllowRegister if e.AllowRegister != nil {
wm.AllowUserNamePassword = e.AllowUserNamePassword wm.AllowRegister = *e.AllowRegister
wm.AllowExternalIDP = e.AllowExternalIDP }
wm.ForceMFA = e.ForceMFA if e.AllowUserNamePassword != nil {
wm.PasswordlessType = e.PasswordlessType wm.AllowUserNamePassword = *e.AllowUserNamePassword
}
if e.AllowExternalIDP != nil {
wm.AllowExternalIDP = *e.AllowExternalIDP
}
if e.ForceMFA != nil {
wm.ForceMFA = *e.ForceMFA
}
if e.PasswordlessType != nil {
wm.PasswordlessType = *e.PasswordlessType
}
case *policy.LoginPolicyRemovedEvent: case *policy.LoginPolicyRemovedEvent:
wm.IsActive = false wm.IsActive = false
} }

View File

@ -19,7 +19,9 @@ func (wm *PolicyOrgIAMWriteModel) Reduce() error {
wm.UserLoginMustBeDomain = e.UserLoginMustBeDomain wm.UserLoginMustBeDomain = e.UserLoginMustBeDomain
wm.IsActive = true wm.IsActive = true
case *policy.OrgIAMPolicyChangedEvent: case *policy.OrgIAMPolicyChangedEvent:
wm.UserLoginMustBeDomain = e.UserLoginMustBeDomain if e.UserLoginMustBeDomain != nil {
wm.UserLoginMustBeDomain = *e.UserLoginMustBeDomain
}
} }
} }
return wm.WriteModel.Reduce() return wm.WriteModel.Reduce()

View File

@ -21,8 +21,12 @@ func (wm *PasswordAgePolicyWriteModel) Reduce() error {
wm.MaxAgeDays = e.MaxAgeDays wm.MaxAgeDays = e.MaxAgeDays
wm.IsActive = true wm.IsActive = true
case *policy.PasswordAgePolicyChangedEvent: case *policy.PasswordAgePolicyChangedEvent:
wm.ExpireWarnDays = e.ExpireWarnDays if e.ExpireWarnDays != nil {
wm.MaxAgeDays = e.MaxAgeDays wm.ExpireWarnDays = *e.ExpireWarnDays
}
if e.ExpireWarnDays != nil {
wm.ExpireWarnDays = *e.ExpireWarnDays
}
case *policy.PasswordAgePolicyRemovedEvent: case *policy.PasswordAgePolicyRemovedEvent:
wm.IsActive = false wm.IsActive = false
} }

View File

@ -27,11 +27,21 @@ func (wm *PasswordComplexityPolicyWriteModel) Reduce() error {
wm.HasSymbol = e.HasSymbol wm.HasSymbol = e.HasSymbol
wm.IsActive = true wm.IsActive = true
case *policy.PasswordComplexityPolicyChangedEvent: case *policy.PasswordComplexityPolicyChangedEvent:
wm.MinLength = e.MinLength if e.MinLength != nil {
wm.HasLowercase = e.HasLowercase wm.MinLength = *e.MinLength
wm.HasUpperCase = e.HasUpperCase }
wm.HasNumber = e.HasNumber if e.HasLowercase != nil {
wm.HasSymbol = e.HasSymbol wm.HasLowercase = *e.HasLowercase
}
if e.HasUpperCase != nil {
wm.HasUpperCase = *e.HasUpperCase
}
if e.HasNumber != nil {
wm.HasNumber = *e.HasNumber
}
if e.HasSymbol != nil {
wm.HasSymbol = *e.HasSymbol
}
case *policy.PasswordComplexityPolicyRemovedEvent: case *policy.PasswordComplexityPolicyRemovedEvent:
wm.IsActive = false wm.IsActive = false
} }

View File

@ -21,8 +21,12 @@ func (wm *PasswordLockoutPolicyWriteModel) Reduce() error {
wm.ShowLockOutFailures = e.ShowLockOutFailures wm.ShowLockOutFailures = e.ShowLockOutFailures
wm.IsActive = true wm.IsActive = true
case *policy.PasswordLockoutPolicyChangedEvent: case *policy.PasswordLockoutPolicyChangedEvent:
wm.MaxAttempts = e.MaxAttempts if e.MaxAttempts != nil {
wm.ShowLockOutFailures = e.ShowLockOutFailures wm.MaxAttempts = *e.MaxAttempts
}
if e.ShowLockOutFailures != nil {
wm.ShowLockOutFailures = *e.ShowLockOutFailures
}
case *policy.PasswordLockoutPolicyRemovedEvent: case *policy.PasswordLockoutPolicyRemovedEvent:
wm.IsActive = false wm.IsActive = false
} }

View File

@ -20,7 +20,11 @@ func (r *CommandSide) AddUser(ctx context.Context, user *domain.User) (*domain.U
} }
return &domain.User{UserName: user.UserName, Human: human}, nil return &domain.User{UserName: user.UserName, Human: human}, nil
} else if user.Machine != nil { } else if user.Machine != nil {
machine, err := r.AddMachine(ctx, user.ResourceOwner, user.UserName, user.Machine)
if err != nil {
return nil, err
}
return &domain.User{UserName: user.UserName, Machine: machine}, nil
} }
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-8K0df", "Errors.User.TypeUndefined") return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-8K0df", "Errors.User.TypeUndefined")
} }
@ -31,9 +35,11 @@ func (r *CommandSide) RegisterUser(ctx context.Context, user *domain.User) (*dom
} }
if user.Human != nil { if user.Human != nil {
human, err := r.RegisterHuman(ctx, user.ResourceOwner, user.UserName, user.Human, nil)
} else if user.Machine != nil { if err != nil {
return nil, err
}
return &domain.User{UserName: user.UserName, Human: human}, nil
} }
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-8K0df", "Errors.User.TypeUndefined") return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-8K0df", "Errors.User.TypeUndefined")
} }
@ -122,6 +128,21 @@ func (r *CommandSide) UnlockUser(ctx context.Context, userID string) (*domain.Us
return writeModelToUser(existingUser), nil return writeModelToUser(existingUser), nil
} }
func (r *CommandSide) RemoveUser(ctx context.Context, userID string) error {
existingUser, err := r.userWriteModelByID(ctx, userID)
if err != nil {
return err
}
if existingUser.UserState != domain.UserStateDeleted {
return caos_errs.ThrowAlreadyExists(nil, "COMMAND-5M0od", "Errors.User.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserRemovedEvent(ctx))
//TODO: release unqie username
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
}
func (r *CommandSide) userWriteModelByID(ctx context.Context, userID string) (writeModel *UserWriteModel, err error) { func (r *CommandSide) userWriteModelByID(ctx context.Context, userID string) (writeModel *UserWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()

View File

@ -1,7 +1,6 @@
package command package command
import ( import (
"github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/domain"
) )
@ -38,28 +37,28 @@ func writeModelToHuman(wm *HumanWriteModel) *domain.Human {
} }
} }
func writeModelToProfile(wm *HumanProfileWriteModel) *model.Profile { func writeModelToProfile(wm *HumanProfileWriteModel) *domain.Profile {
return &model.Profile{ return &domain.Profile{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel), ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
FirstName: wm.FirstName, FirstName: wm.FirstName,
LastName: wm.LastName, LastName: wm.LastName,
NickName: wm.NickName, NickName: wm.NickName,
DisplayName: wm.DisplayName, DisplayName: wm.DisplayName,
PreferredLanguage: wm.PreferredLanguage, PreferredLanguage: wm.PreferredLanguage,
Gender: model.Gender(wm.Gender), Gender: wm.Gender,
} }
} }
func writeModelToEmail(wm *HumanEmailWriteModel) *model.Email { func writeModelToEmail(wm *HumanEmailWriteModel) *domain.Email {
return &model.Email{ return &domain.Email{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel), ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
EmailAddress: wm.Email, EmailAddress: wm.Email,
IsEmailVerified: wm.IsEmailVerified, IsEmailVerified: wm.IsEmailVerified,
} }
} }
func writeModelToAddress(wm *HumanAddressWriteModel) *model.Address { func writeModelToAddress(wm *HumanAddressWriteModel) *domain.Address {
return &model.Address{ return &domain.Address{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel), ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
Country: wm.Country, Country: wm.Country,
Locality: wm.Locality, Locality: wm.Locality,
@ -68,3 +67,11 @@ func writeModelToAddress(wm *HumanAddressWriteModel) *model.Address {
StreetAddress: wm.StreetAddress, StreetAddress: wm.StreetAddress,
} }
} }
func writeModelToMachine(wm *MachineWriteModel) *domain.Machine {
return &domain.Machine{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
Name: wm.Name,
Description: wm.Description,
}
}

View File

@ -32,32 +32,50 @@ func (r *CommandSide) AddHuman(ctx context.Context, orgID, username string, huma
human.HashPasswordIfExisting(pwPolicy, r.userPasswordAlg, true) human.HashPasswordIfExisting(pwPolicy, r.userPasswordAlg, true)
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel) userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
userAgg.PushEvents( addEvent := user.NewHumanAddedEvent(
user.NewHumanAddedEvent( ctx,
ctx, username,
username, human.FirstName,
human.FirstName, human.LastName,
human.LastName, human.NickName,
human.NickName, human.DisplayName,
human.DisplayName, human.PreferredLanguage,
human.PreferredLanguage, human.Gender,
human.Gender, human.EmailAddress,
human.EmailAddress, )
human.PhoneNumber, if human.Phone != nil {
addEvent.AddPhoneData(human.PhoneNumber)
}
if human.Address != nil {
addEvent.AddAddressData(
human.Country, human.Country,
human.Locality, human.Locality,
human.PostalCode, human.PostalCode,
human.Region, human.Region,
human.StreetAddress, human.StreetAddress)
), }
) if human.Password != nil {
//TODO: HashPassword If existing addEvent.AddPasswordData(human.SecretCrypto, human.ChangeRequired)
//TODO: Generate Init Code if needed }
//TODO: Generate Phone Code if needed userAgg.PushEvents(addEvent)
if human.IsInitialState() {
initCode, err := domain.NewInitUserCode(r.initializeUserCode)
if err != nil {
return nil, err
}
user.NewHumanInitialCodeAddedEvent(ctx, initCode.Code, initCode.Expiry)
}
if human.Email != nil && human.EmailAddress != "" && human.IsEmailVerified { if human.Email != nil && human.EmailAddress != "" && human.IsEmailVerified {
userAgg.PushEvents(user.NewHumanEmailVerifiedEvent(ctx)) userAgg.PushEvents(user.NewHumanEmailVerifiedEvent(ctx))
} }
if human.Phone != nil && human.PhoneNumber != "" && human.IsPhoneVerified { if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
phoneCode, err := domain.NewPhoneCode(r.phoneVerificationCode)
if err != nil {
return nil, err
}
user.NewHumanPhoneCodeAddedEvent(ctx, phoneCode.Code, phoneCode.Expiry)
} else if human.Phone != nil && human.PhoneNumber != "" && human.IsPhoneVerified {
userAgg.PushEvents(user.NewHumanPhoneVerifiedEvent(ctx)) userAgg.PushEvents(user.NewHumanPhoneVerifiedEvent(ctx))
} }
@ -68,3 +86,82 @@ func (r *CommandSide) AddHuman(ctx context.Context, orgID, username string, huma
return writeModelToHuman(addedHuman), nil return writeModelToHuman(addedHuman), nil
} }
func (r *CommandSide) RegisterHuman(ctx context.Context, orgID, username string, human *domain.Human, externalIDP *domain.ExternalIDP) (*domain.Human, error) {
if !human.IsValid() || externalIDP == nil && (human.Password == nil || human.SecretString == "") {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-9dk45", "Errors.User.Invalid")
}
userID, err := r.idGenerator.Next()
if err != nil {
return nil, err
}
human.AggregateID = userID
orgIAMPolicy, err := r.GetOrgIAMPolicy(ctx, orgID)
if err != nil {
return nil, err
}
pwPolicy, err := r.GetOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil {
return nil, err
}
addedHuman := NewHumanWriteModel(human.AggregateID)
//TODO: Check Unique Username or unique external idp
human.CheckOrgIAMPolicy(username, orgIAMPolicy)
human.SetNamesAsDisplayname()
human.HashPasswordIfExisting(pwPolicy, r.userPasswordAlg, true)
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
addEvent := user.NewHumanRegisteredEvent(
ctx,
username,
human.FirstName,
human.LastName,
human.NickName,
human.DisplayName,
human.PreferredLanguage,
human.Gender,
human.EmailAddress,
)
if human.Phone != nil {
addEvent.AddPhoneData(human.PhoneNumber)
}
if human.Address != nil {
addEvent.AddAddressData(
human.Country,
human.Locality,
human.PostalCode,
human.Region,
human.StreetAddress)
}
if human.Password != nil {
addEvent.AddPasswordData(human.SecretCrypto, human.ChangeRequired)
}
userAgg.PushEvents(addEvent)
//TODO: Add External IDP Event
if human.IsInitialState() {
initCode, err := domain.NewInitUserCode(r.initializeUserCode)
if err != nil {
return nil, err
}
user.NewHumanInitialCodeAddedEvent(ctx, initCode.Code, initCode.Expiry)
}
if human.Email != nil && human.EmailAddress != "" && human.IsEmailVerified {
userAgg.PushEvents(user.NewHumanEmailVerifiedEvent(ctx))
}
if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
phoneCode, err := domain.NewPhoneCode(r.phoneVerificationCode)
if err != nil {
return nil, err
}
user.NewHumanPhoneCodeAddedEvent(ctx, phoneCode.Code, phoneCode.Expiry)
}
err = r.eventstore.PushAggregate(ctx, addedHuman, userAgg)
if err != nil {
return nil, err
}
return writeModelToHuman(addedHuman), nil
}

View File

@ -4,11 +4,10 @@ import (
"context" "context"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/domain"
) )
func (r *CommandSide) ChangeHumanAddress(ctx context.Context, address *usr_model.Address) (*usr_model.Address, error) { func (r *CommandSide) ChangeHumanAddress(ctx context.Context, address *domain.Address) (*domain.Address, error) {
existingAddress, err := r.addressWriteModel(ctx, address.AggregateID) existingAddress, err := r.addressWriteModel(ctx, address.AggregateID)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -58,11 +58,21 @@ func (wm *HumanAddressWriteModel) Reduce() error {
wm.StreetAddress = e.StreetAddress wm.StreetAddress = e.StreetAddress
wm.UserState = domain.UserStateActive wm.UserState = domain.UserStateActive
case *user.HumanAddressChangedEvent: case *user.HumanAddressChangedEvent:
wm.Country = e.Country if e.Country != nil {
wm.Locality = e.Locality wm.Country = *e.Country
wm.PostalCode = e.PostalCode }
wm.Region = e.Region if e.Locality != nil {
wm.StreetAddress = e.StreetAddress wm.Locality = *e.Locality
}
if e.PostalCode != nil {
wm.PostalCode = *e.PostalCode
}
if e.Region != nil {
wm.Region = *e.Region
}
if e.StreetAddress != nil {
wm.StreetAddress = *e.StreetAddress
}
case *user.UserRemovedEvent: case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted wm.UserState = domain.UserStateDeleted
} }
@ -87,23 +97,23 @@ func (wm *HumanAddressWriteModel) NewChangedEvent(
changedEvent := user.NewHumanAddressChangedEvent(ctx) changedEvent := user.NewHumanAddressChangedEvent(ctx)
if wm.Country != country { if wm.Country != country {
hasChanged = true hasChanged = true
changedEvent.Country = country changedEvent.Country = &country
} }
if wm.Locality != locality { if wm.Locality != locality {
hasChanged = true hasChanged = true
changedEvent.Locality = locality changedEvent.Locality = &locality
} }
if wm.PostalCode != postalCode { if wm.PostalCode != postalCode {
hasChanged = true hasChanged = true
changedEvent.PostalCode = postalCode changedEvent.PostalCode = &postalCode
} }
if wm.Region != region { if wm.Region != region {
hasChanged = true hasChanged = true
changedEvent.Region = region changedEvent.Region = &region
} }
if wm.StreetAddress != streetAddress { if wm.StreetAddress != streetAddress {
hasChanged = true hasChanged = true
changedEvent.StreetAddress = streetAddress changedEvent.StreetAddress = &streetAddress
} }
return changedEvent, hasChanged return changedEvent, hasChanged
} }

View File

@ -4,11 +4,10 @@ import (
"context" "context"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/domain"
) )
func (r *CommandSide) ChangeHumanEmail(ctx context.Context, email *usr_model.Email) (*usr_model.Email, error) { func (r *CommandSide) ChangeHumanEmail(ctx context.Context, email *domain.Email) (*domain.Email, error) {
if !email.IsValid() { if !email.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M9sf", "Errors.Email.Invalid") return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M9sf", "Errors.Email.Invalid")
} }

View File

@ -1,6 +1,7 @@
package command package command
import ( import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user" "github.com/caos/zitadel/internal/v2/repository/user"
@ -31,6 +32,9 @@ type HumanWriteModel struct {
Region string Region string
StreetAddress string StreetAddress string
Secret *crypto.CryptoValue
SecretChangeRequired bool
UserState domain.UserState UserState domain.UserState
} }
@ -45,21 +49,20 @@ func NewHumanWriteModel(userID string) *HumanWriteModel {
func (wm *HumanWriteModel) AppendEvents(events ...eventstore.EventReader) { func (wm *HumanWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events { for _, event := range events {
switch e := event.(type) { switch e := event.(type) {
case *user.HumanEmailChangedEvent: case *user.HumanAddedEvent,
wm.AppendEvents(e) *user.HumanRegisteredEvent,
case *user.HumanEmailVerifiedEvent: *user.HumanProfileChangedEvent,
wm.AppendEvents(e) *user.HumanEmailChangedEvent,
case *user.HumanAddedEvent, *user.HumanRegisteredEvent: *user.HumanEmailVerifiedEvent,
wm.AppendEvents(e) *user.HumanPhoneChangedEvent,
case *user.UserDeactivatedEvent: *user.HumanPhoneVerifiedEvent,
wm.AppendEvents(e) *user.HumanAddressChangedEvent,
case *user.UserReactivatedEvent: *user.HumanPasswordChangedEvent,
wm.AppendEvents(e) *user.UserDeactivatedEvent,
case *user.UserLockedEvent: *user.UserReactivatedEvent,
wm.AppendEvents(e) *user.UserLockedEvent,
case *user.UserUnlockedEvent: *user.UserUnlockedEvent,
wm.AppendEvents(e) *user.UserRemovedEvent:
case *user.UserRemovedEvent:
wm.AppendEvents(e) wm.AppendEvents(e)
} }
} }
@ -70,11 +73,21 @@ func (wm *HumanWriteModel) Reduce() error {
for _, event := range wm.Events { for _, event := range wm.Events {
switch e := event.(type) { switch e := event.(type) {
case *user.HumanAddedEvent: case *user.HumanAddedEvent:
wm.UserName = e.UserName wm.reduceHumanAddedEvent(e)
wm.UserState = domain.UserStateInitial
case *user.HumanRegisteredEvent: case *user.HumanRegisteredEvent:
wm.UserName = e.UserName wm.reduceHumanRegisteredEvent(e)
wm.UserState = domain.UserStateInitial case *user.HumanProfileChangedEvent:
wm.reduceHumanProfileChangedEvent(e)
case *user.HumanEmailChangedEvent:
wm.reduceHumanEmailChangedEvent(e)
case *user.HumanEmailVerifiedEvent:
wm.reduceHumanEmailVerifiedEvent()
case *user.HumanPhoneChangedEvent:
wm.reduceHumanPhoneChangedEvent(e)
case *user.HumanPhoneVerifiedEvent:
wm.reduceHumanPhoneVerifiedEvent()
case *user.HumanPasswordChangedEvent:
wm.reduceHumanPasswordChangedEvent(e)
case *user.UserLockedEvent: case *user.UserLockedEvent:
if wm.UserState != domain.UserStateDeleted { if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateLocked wm.UserState = domain.UserStateLocked
@ -102,3 +115,105 @@ func (wm *HumanWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType). return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID) AggregateIDs(wm.AggregateID)
} }
func (wm *HumanWriteModel) reduceHumanAddedEvent(e *user.HumanAddedEvent) {
wm.UserName = e.UserName
wm.FirstName = e.FirstName
wm.LastName = e.LastName
wm.NickName = e.NickName
wm.DisplayName = e.DisplayName
wm.PreferredLanguage = e.PreferredLanguage
wm.Gender = e.Gender
wm.Email = e.EmailAddress
wm.Phone = e.PhoneNumber
wm.Country = e.Country
wm.Locality = e.Locality
wm.PostalCode = e.PostalCode
wm.Region = e.Region
wm.StreetAddress = e.StreetAddress
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired
wm.UserState = domain.UserStateInitial
}
func (wm *HumanWriteModel) reduceHumanRegisteredEvent(e *user.HumanRegisteredEvent) {
wm.UserName = e.UserName
wm.FirstName = e.FirstName
wm.LastName = e.LastName
wm.NickName = e.NickName
wm.DisplayName = e.DisplayName
wm.PreferredLanguage = e.PreferredLanguage
wm.Gender = e.Gender
wm.Email = e.EmailAddress
wm.Phone = e.PhoneNumber
wm.Country = e.Country
wm.Locality = e.Locality
wm.PostalCode = e.PostalCode
wm.Region = e.Region
wm.StreetAddress = e.StreetAddress
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired
wm.UserState = domain.UserStateInitial
}
func (wm *HumanWriteModel) reduceHumanProfileChangedEvent(e *user.HumanProfileChangedEvent) {
if e.FirstName != "" {
wm.FirstName = e.FirstName
}
if e.LastName != "" {
wm.LastName = e.LastName
}
if e.NickName != nil {
wm.NickName = *e.NickName
}
if e.DisplayName != nil {
wm.DisplayName = *e.DisplayName
}
if e.PreferredLanguage != nil {
wm.PreferredLanguage = *e.PreferredLanguage
}
if e.Gender != nil {
wm.Gender = *e.Gender
}
}
func (wm *HumanWriteModel) reduceHumanEmailChangedEvent(e *user.HumanEmailChangedEvent) {
wm.Email = e.EmailAddress
wm.IsEmailVerified = false
}
func (wm *HumanWriteModel) reduceHumanEmailVerifiedEvent() {
wm.IsEmailVerified = true
}
func (wm *HumanWriteModel) reduceHumanPhoneChangedEvent(e *user.HumanPhoneChangedEvent) {
wm.Phone = e.PhoneNumber
wm.IsPhoneVerified = false
}
func (wm *HumanWriteModel) reduceHumanPhoneVerifiedEvent() {
wm.IsPhoneVerified = true
}
func (wm *HumanWriteModel) reduceHumanAddressChangedEvent(e *user.HumanAddressChangedEvent) {
if e.Country != nil {
wm.Country = *e.Country
}
if e.Locality != nil {
wm.Locality = *e.Locality
}
if e.PostalCode != nil {
wm.PostalCode = *e.PostalCode
}
if e.Region != nil {
wm.Region = *e.Region
}
if e.StreetAddress != nil {
wm.StreetAddress = *e.StreetAddress
}
}
func (wm *HumanWriteModel) reduceHumanPasswordChangedEvent(e *user.HumanPasswordChangedEvent) {
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired
}

View File

@ -4,11 +4,10 @@ import (
"context" "context"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/domain"
) )
func (r *CommandSide) ChangeHumanProfile(ctx context.Context, profile *usr_model.Profile) (*usr_model.Profile, error) { func (r *CommandSide) ChangeHumanProfile(ctx context.Context, profile *domain.Profile) (*domain.Profile, error) {
if !profile.IsValid() { if !profile.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-8io0d", "Errors.User.Profile.Invalid") return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-8io0d", "Errors.User.Profile.Invalid")
} }

View File

@ -62,12 +62,24 @@ func (wm *HumanProfileWriteModel) Reduce() error {
wm.Gender = e.Gender wm.Gender = e.Gender
wm.UserState = domain.UserStateActive wm.UserState = domain.UserStateActive
case *user.HumanProfileChangedEvent: case *user.HumanProfileChangedEvent:
wm.FirstName = e.FirstName if e.FirstName != "" {
wm.LastName = e.LastName wm.FirstName = e.FirstName
wm.NickName = e.NickName }
wm.DisplayName = e.DisplayName if e.LastName != "" {
wm.PreferredLanguage = e.PreferredLanguage wm.LastName = e.LastName
wm.Gender = e.Gender }
if e.NickName != nil {
wm.NickName = *e.NickName
}
if e.DisplayName != nil {
wm.DisplayName = *e.DisplayName
}
if e.PreferredLanguage != nil {
wm.PreferredLanguage = *e.PreferredLanguage
}
if e.Gender != nil {
wm.Gender = *e.Gender
}
case *user.UserRemovedEvent: case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted wm.UserState = domain.UserStateDeleted
} }
@ -101,19 +113,19 @@ func (wm *HumanProfileWriteModel) NewChangedEvent(
} }
if wm.NickName != nickName { if wm.NickName != nickName {
hasChanged = true hasChanged = true
changedEvent.NickName = nickName changedEvent.NickName = &nickName
} }
if wm.DisplayName != displayName { if wm.DisplayName != displayName {
hasChanged = true hasChanged = true
changedEvent.DisplayName = displayName changedEvent.DisplayName = &displayName
} }
if wm.PreferredLanguage != preferredLanguage { if wm.PreferredLanguage != preferredLanguage {
hasChanged = true hasChanged = true
changedEvent.PreferredLanguage = preferredLanguage changedEvent.PreferredLanguage = &preferredLanguage
} }
if gender.Valid() && wm.Gender != gender { if gender.Valid() && wm.Gender != gender {
hasChanged = true hasChanged = true
changedEvent.Gender = gender changedEvent.Gender = &gender
} }
return changedEvent, hasChanged return changedEvent, hasChanged

View File

@ -0,0 +1,78 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
)
func (r *CommandSide) AddMachine(ctx context.Context, orgID, username string, machine *domain.Machine) (*domain.Machine, error) {
if !machine.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5M0ds", "Errors.User.Invalid")
}
userID, err := r.idGenerator.Next()
if err != nil {
return nil, err
}
//TODO: Check Unique username
machine.AggregateID = userID
orgIAMPolicy, err := r.GetOrgIAMPolicy(ctx, orgID)
if err != nil {
return nil, err
}
if !orgIAMPolicy.UserLoginMustBeDomain {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-6M0ds", "Errors.User.Invalid")
}
addedMachine := NewMachineWriteModel(machine.AggregateID)
userAgg := UserAggregateFromWriteModel(&addedMachine.WriteModel)
userAgg.PushEvents(
user.NewMachineAddedEvent(
ctx,
username,
machine.Name,
machine.Description,
),
)
return writeModelToMachine(addedMachine), nil
}
func (r *CommandSide) ChangeMachine(ctx context.Context, machine *domain.Machine) (*domain.Machine, error) {
existingUser, err := r.machineWriteModelByID(ctx, machine.AggregateID)
if err != nil {
return nil, err
}
if existingUser.UserState == domain.UserStateDeleted || existingUser.UserState == domain.UserStateUnspecified {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-5M0od", "Errors.User.NotFound")
}
changedEvent, hasChanged := existingUser.NewChangedEvent(ctx, machine.Name, machine.Description)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-2M9fs", "Errors.User.Email.NotChanged")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingUser, userAgg)
if err != nil {
return nil, err
}
return writeModelToMachine(existingUser), nil
}
func (r *CommandSide) machineWriteModelByID(ctx context.Context, userID string) (writeModel *MachineWriteModel, err error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5M0ds", "Errors.User.UserIDMissing")
}
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewMachineWriteModel(userID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@ -0,0 +1,109 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
)
type MachineWriteModel struct {
eventstore.WriteModel
UserName string
Name string
Description string
UserState domain.UserState
}
func NewMachineWriteModel(userID string) *MachineWriteModel {
return &MachineWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: userID,
},
}
}
func (wm *MachineWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.MachineAddedEvent:
wm.AppendEvents(e)
case *user.MachineChangedEvent:
wm.AppendEvents(e)
case *user.UserDeactivatedEvent:
wm.AppendEvents(e)
case *user.UserReactivatedEvent:
wm.AppendEvents(e)
case *user.UserLockedEvent:
wm.AppendEvents(e)
case *user.UserUnlockedEvent:
wm.AppendEvents(e)
case *user.UserRemovedEvent:
wm.AppendEvents(e)
}
}
}
//TODO: Compute State? initial/active
func (wm *MachineWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.MachineAddedEvent:
wm.UserName = e.UserName
wm.Name = e.Name
wm.Description = e.Description
wm.UserState = domain.UserStateActive
case *user.MachineChangedEvent:
if e.Name != nil {
wm.Name = *e.Name
}
if e.Description != nil {
wm.Description = *e.Description
}
case *user.UserLockedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateLocked
}
case *user.UserUnlockedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateActive
}
case *user.UserDeactivatedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateInactive
}
case *user.UserReactivatedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateActive
}
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}
}
return wm.WriteModel.Reduce()
}
func (wm *MachineWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID)
}
func (wm *MachineWriteModel) NewChangedEvent(
ctx context.Context,
name,
description string,
) (*user.MachineChangedEvent, bool) {
hasChanged := false
changedEvent := user.NewMachineChangedEvent(ctx)
if wm.Name != name {
hasChanged = true
changedEvent.Name = &name
}
if wm.Description != description {
hasChanged = true
changedEvent.Description = &description
}
return changedEvent, hasChanged
}

View File

@ -17,10 +17,6 @@ type Human struct {
*Phone *Phone
*Address *Address
ExternalIDPs []*ExternalIDP ExternalIDPs []*ExternalIDP
InitCode *InitUserCode
EmailCode *EmailCode
PhoneCode *PhoneCode
PasswordCode *PasswordCode
OTP *OTP OTP *OTP
U2FTokens []*WebAuthNToken U2FTokens []*WebAuthNToken
PasswordlessTokens []*WebAuthNToken PasswordlessTokens []*WebAuthNToken
@ -79,3 +75,18 @@ func (u *Human) HashPasswordIfExisting(policy *PasswordComplexityPolicy, passwor
} }
return nil return nil
} }
func (u *Human) IsInitialState() bool {
return u.Email == nil || !u.IsEmailVerified || (u.ExternalIDPs == nil || len(u.ExternalIDPs) == 0) && (u.Password == nil || u.SecretString == "")
}
func NewInitUserCode(generator crypto.Generator) (*InitUserCode, error) {
initCodeCrypto, _, err := crypto.NewCode(generator)
if err != nil {
return nil, err
}
return &InitUserCode{
Code: initCodeCrypto,
Expiry: generator.Expiry(),
}, nil
}

View File

@ -39,3 +39,14 @@ func (p *Phone) formatPhone() error {
p.PhoneNumber = libphonenumber.Format(phoneNr, libphonenumber.E164) p.PhoneNumber = libphonenumber.Format(phoneNr, libphonenumber.E164)
return nil return nil
} }
func NewPhoneCode(phoneGenerator crypto.Generator) (*PhoneCode, error) {
phoneCodeCrypto, _, err := crypto.NewCode(phoneGenerator)
if err != nil {
return nil, err
}
return &PhoneCode{
Code: phoneCodeCrypto,
Expiry: phoneGenerator.Expiry(),
}, nil
}

View File

@ -17,3 +17,7 @@ type Profile struct {
PreferredLoginName string PreferredLoginName string
LoginNames []string LoginNames []string
} }
func (p *Profile) IsValid() bool {
return p.FirstName != "" && p.LastName != ""
}

View File

@ -21,8 +21,12 @@ func (rm *LabelPolicyReadModel) Reduce() error {
rm.SecondaryColor = e.SecondaryColor rm.SecondaryColor = e.SecondaryColor
rm.IsActive = true rm.IsActive = true
case *policy.LabelPolicyChangedEvent: case *policy.LabelPolicyChangedEvent:
rm.PrimaryColor = e.PrimaryColor if e.PrimaryColor != nil {
rm.SecondaryColor = e.SecondaryColor rm.PrimaryColor = *e.PrimaryColor
}
if e.SecondaryColor != nil {
rm.SecondaryColor = *e.SecondaryColor
}
case *policy.LabelPolicyRemovedEvent: case *policy.LabelPolicyRemovedEvent:
rm.IsActive = false rm.IsActive = false
} }

View File

@ -28,11 +28,21 @@ func (rm *LoginPolicyReadModel) Reduce() error {
rm.PasswordlessType = e.PasswordlessType rm.PasswordlessType = e.PasswordlessType
rm.IsActive = true rm.IsActive = true
case *policy.LoginPolicyChangedEvent: case *policy.LoginPolicyChangedEvent:
rm.AllowUserNamePassword = e.AllowUserNamePassword if e.AllowUserNamePassword != nil {
rm.AllowExternalIDP = e.AllowExternalIDP rm.AllowUserNamePassword = *e.AllowUserNamePassword
rm.AllowRegister = e.AllowRegister }
rm.ForceMFA = e.ForceMFA if e.AllowExternalIDP != nil {
rm.PasswordlessType = e.PasswordlessType rm.AllowExternalIDP = *e.AllowExternalIDP
}
if e.AllowRegister != nil {
rm.AllowRegister = *e.AllowRegister
}
if e.ForceMFA != nil {
rm.ForceMFA = *e.ForceMFA
}
if e.PasswordlessType != nil {
rm.PasswordlessType = *e.PasswordlessType
}
case *policy.LoginPolicyRemovedEvent: case *policy.LoginPolicyRemovedEvent:
rm.IsActive = false rm.IsActive = false
} }

View File

@ -17,7 +17,9 @@ func (rm *OrgIAMPolicyReadModel) Reduce() error {
case *policy.OrgIAMPolicyAddedEvent: case *policy.OrgIAMPolicyAddedEvent:
rm.UserLoginMustBeDomain = e.UserLoginMustBeDomain rm.UserLoginMustBeDomain = e.UserLoginMustBeDomain
case *policy.OrgIAMPolicyChangedEvent: case *policy.OrgIAMPolicyChangedEvent:
rm.UserLoginMustBeDomain = e.UserLoginMustBeDomain if e.UserLoginMustBeDomain != nil {
rm.UserLoginMustBeDomain = *e.UserLoginMustBeDomain
}
} }
} }
return rm.ReadModel.Reduce() return rm.ReadModel.Reduce()

View File

@ -19,8 +19,12 @@ func (rm *PasswordAgePolicyReadModel) Reduce() error {
rm.ExpireWarnDays = e.ExpireWarnDays rm.ExpireWarnDays = e.ExpireWarnDays
rm.MaxAgeDays = e.MaxAgeDays rm.MaxAgeDays = e.MaxAgeDays
case *policy.PasswordAgePolicyChangedEvent: case *policy.PasswordAgePolicyChangedEvent:
rm.ExpireWarnDays = e.ExpireWarnDays if e.ExpireWarnDays != nil {
rm.MaxAgeDays = e.MaxAgeDays rm.ExpireWarnDays = *e.ExpireWarnDays
}
if e.MaxAgeDays != nil {
rm.MaxAgeDays = *e.MaxAgeDays
}
} }
} }
return rm.ReadModel.Reduce() return rm.ReadModel.Reduce()

View File

@ -25,11 +25,21 @@ func (rm *PasswordComplexityPolicyReadModel) Reduce() error {
rm.HasNumber = e.HasNumber rm.HasNumber = e.HasNumber
rm.HasSymbol = e.HasSymbol rm.HasSymbol = e.HasSymbol
case *policy.PasswordComplexityPolicyChangedEvent: case *policy.PasswordComplexityPolicyChangedEvent:
rm.MinLength = e.MinLength if e.MinLength != nil {
rm.HasLowercase = e.HasLowercase rm.MinLength = *e.MinLength
rm.HasUpperCase = e.HasUpperCase }
rm.HasNumber = e.HasNumber if e.HasLowercase != nil {
rm.HasSymbol = e.HasSymbol rm.HasLowercase = *e.HasLowercase
}
if e.HasUpperCase != nil {
rm.HasUpperCase = *e.HasUpperCase
}
if e.HasNumber != nil {
rm.HasNumber = *e.HasNumber
}
if e.HasSymbol != nil {
rm.HasSymbol = *e.HasSymbol
}
} }
} }
return rm.ReadModel.Reduce() return rm.ReadModel.Reduce()

View File

@ -19,8 +19,12 @@ func (rm *PasswordLockoutPolicyReadModel) Reduce() error {
rm.MaxAttempts = e.MaxAttempts rm.MaxAttempts = e.MaxAttempts
rm.ShowLockOutFailures = e.ShowLockOutFailures rm.ShowLockOutFailures = e.ShowLockOutFailures
case *policy.PasswordLockoutPolicyChangedEvent: case *policy.PasswordLockoutPolicyChangedEvent:
rm.MaxAttempts = e.MaxAttempts if e.MaxAttempts != nil {
rm.ShowLockOutFailures = e.ShowLockOutFailures rm.MaxAttempts = *e.MaxAttempts
}
if e.ShowLockOutFailures != nil {
rm.ShowLockOutFailures = *e.ShowLockOutFailures
}
} }
} }
return rm.ReadModel.Reduce() return rm.ReadModel.Reduce()

View File

@ -53,8 +53,8 @@ func LabelPolicyAddedEventMapper(event *repository.Event) (eventstore.EventReade
type LabelPolicyChangedEvent struct { type LabelPolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
PrimaryColor string `json:"primaryColor,omitempty"` PrimaryColor *string `json:"primaryColor,omitempty"`
SecondaryColor string `json:"secondaryColor,omitempty"` SecondaryColor *string `json:"secondaryColor,omitempty"`
} }
func (e *LabelPolicyChangedEvent) Data() interface{} { func (e *LabelPolicyChangedEvent) Data() interface{} {

View File

@ -63,11 +63,11 @@ func LoginPolicyAddedEventMapper(event *repository.Event) (eventstore.EventReade
type LoginPolicyChangedEvent struct { type LoginPolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
AllowUserNamePassword bool `json:"allowUsernamePassword,omitempty"` AllowUserNamePassword *bool `json:"allowUsernamePassword,omitempty"`
AllowRegister bool `json:"allowRegister,omitempty"` AllowRegister *bool `json:"allowRegister,omitempty"`
AllowExternalIDP bool `json:"allowExternalIdp,omitempty"` AllowExternalIDP *bool `json:"allowExternalIdp,omitempty"`
ForceMFA bool `json:"forceMFA,omitempty"` ForceMFA *bool `json:"forceMFA,omitempty"`
PasswordlessType domain.PasswordlessType `json:"passwordlessType,omitempty"` PasswordlessType *domain.PasswordlessType `json:"passwordlessType,omitempty"`
} }
type LoginPolicyEventData struct { type LoginPolicyEventData struct {

View File

@ -49,7 +49,7 @@ func OrgIAMPolicyAddedEventMapper(event *repository.Event) (eventstore.EventRead
type OrgIAMPolicyChangedEvent struct { type OrgIAMPolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
UserLoginMustBeDomain bool `json:"userLoginMustBeDomain,omitempty"` UserLoginMustBeDomain *bool `json:"userLoginMustBeDomain,omitempty"`
} }
func (e *OrgIAMPolicyChangedEvent) Data() interface{} { func (e *OrgIAMPolicyChangedEvent) Data() interface{} {

View File

@ -53,8 +53,8 @@ func PasswordAgePolicyAddedEventMapper(event *repository.Event) (eventstore.Even
type PasswordAgePolicyChangedEvent struct { type PasswordAgePolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
ExpireWarnDays uint64 `json:"expireWarnDays,omitempty"` ExpireWarnDays *uint64 `json:"expireWarnDays,omitempty"`
MaxAgeDays uint64 `json:"maxAgeDays,omitempty"` MaxAgeDays *uint64 `json:"maxAgeDays,omitempty"`
} }
func (e *PasswordAgePolicyChangedEvent) Data() interface{} { func (e *PasswordAgePolicyChangedEvent) Data() interface{} {

View File

@ -61,11 +61,11 @@ func PasswordComplexityPolicyAddedEventMapper(event *repository.Event) (eventsto
type PasswordComplexityPolicyChangedEvent struct { type PasswordComplexityPolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
MinLength uint64 `json:"minLength,omitempty"` MinLength *uint64 `json:"minLength,omitempty"`
HasLowercase bool `json:"hasLowercase,omitempty"` HasLowercase *bool `json:"hasLowercase,omitempty"`
HasUpperCase bool `json:"hasUppercase,omitempty"` HasUpperCase *bool `json:"hasUppercase,omitempty"`
HasNumber bool `json:"hasNumber,omitempty"` HasNumber *bool `json:"hasNumber,omitempty"`
HasSymbol bool `json:"hasSymbol,omitempty"` HasSymbol *bool `json:"hasSymbol,omitempty"`
} }
func (e *PasswordComplexityPolicyChangedEvent) Data() interface{} { func (e *PasswordComplexityPolicyChangedEvent) Data() interface{} {

View File

@ -53,8 +53,8 @@ func PasswordLockoutPolicyAddedEventMapper(event *repository.Event) (eventstore.
type PasswordLockoutPolicyChangedEvent struct { type PasswordLockoutPolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
MaxAttempts uint64 `json:"maxAttempts,omitempty"` MaxAttempts *uint64 `json:"maxAttempts,omitempty"`
ShowLockOutFailures bool `json:"showLockOutFailures,omitempty"` ShowLockOutFailures *bool `json:"showLockOutFailures,omitempty"`
} }
func (e *PasswordLockoutPolicyChangedEvent) Data() interface{} { func (e *PasswordLockoutPolicyChangedEvent) Data() interface{} {

View File

@ -53,6 +53,34 @@ func (e *HumanAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanAddedEvent) AddAddressData(
country,
locality,
postalCode,
region,
streetAddress string,
) {
e.Country = country
e.Locality = locality
e.PostalCode = postalCode
e.Region = region
e.StreetAddress = streetAddress
}
func (e *HumanAddedEvent) AddPhoneData(
phoneNumber string,
) {
e.PhoneNumber = phoneNumber
}
func (e *HumanAddedEvent) AddPasswordData(
secret *crypto.CryptoValue,
changeRequired bool,
) {
e.Secret = secret
e.ChangeRequired = changeRequired
}
func NewHumanAddedEvent( func NewHumanAddedEvent(
ctx context.Context, ctx context.Context,
userName, userName,
@ -62,13 +90,7 @@ func NewHumanAddedEvent(
displayName string, displayName string,
preferredLanguage language.Tag, preferredLanguage language.Tag,
gender domain.Gender, gender domain.Gender,
emailAddress, emailAddress string,
phoneNumber,
country,
locality,
postalCode,
region,
streetAddress string,
) *HumanAddedEvent { ) *HumanAddedEvent {
return &HumanAddedEvent{ return &HumanAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -83,12 +105,6 @@ func NewHumanAddedEvent(
PreferredLanguage: preferredLanguage, PreferredLanguage: preferredLanguage,
Gender: gender, Gender: gender,
EmailAddress: emailAddress, EmailAddress: emailAddress,
PhoneNumber: phoneNumber,
Country: country,
Locality: locality,
PostalCode: postalCode,
Region: region,
StreetAddress: streetAddress,
} }
} }
@ -125,12 +141,43 @@ type HumanRegisteredEvent struct {
PostalCode string `json:"postalCode,omitempty"` PostalCode string `json:"postalCode,omitempty"`
Region string `json:"region,omitempty"` Region string `json:"region,omitempty"`
StreetAddress string `json:"streetAddress,omitempty"` StreetAddress string `json:"streetAddress,omitempty"`
Secret *crypto.CryptoValue `json:"secret,omitempty"`
ChangeRequired bool `json:"changeRequired,omitempty"`
} }
func (e *HumanRegisteredEvent) Data() interface{} { func (e *HumanRegisteredEvent) Data() interface{} {
return e return e
} }
func (e *HumanRegisteredEvent) AddAddressData(
country,
locality,
postalCode,
region,
streetAddress string,
) {
e.Country = country
e.Locality = locality
e.PostalCode = postalCode
e.Region = region
e.StreetAddress = streetAddress
}
func (e *HumanRegisteredEvent) AddPhoneData(
phoneNumber string,
) {
e.PhoneNumber = phoneNumber
}
func (e *HumanRegisteredEvent) AddPasswordData(
secret *crypto.CryptoValue,
changeRequired bool,
) {
e.Secret = secret
e.ChangeRequired = changeRequired
}
func NewHumanRegisteredEvent( func NewHumanRegisteredEvent(
ctx context.Context, ctx context.Context,
userName, userName,
@ -140,13 +187,7 @@ func NewHumanRegisteredEvent(
displayName string, displayName string,
preferredLanguage language.Tag, preferredLanguage language.Tag,
gender domain.Gender, gender domain.Gender,
emailAddress, emailAddress string,
phoneNumber,
country,
locality,
postalCode,
region,
streetAddress string,
) *HumanRegisteredEvent { ) *HumanRegisteredEvent {
return &HumanRegisteredEvent{ return &HumanRegisteredEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -161,12 +202,6 @@ func NewHumanRegisteredEvent(
PreferredLanguage: preferredLanguage, PreferredLanguage: preferredLanguage,
Gender: gender, Gender: gender,
EmailAddress: emailAddress, EmailAddress: emailAddress,
PhoneNumber: phoneNumber,
Country: country,
Locality: locality,
PostalCode: postalCode,
Region: region,
StreetAddress: streetAddress,
} }
} }

View File

@ -16,11 +16,11 @@ const (
type HumanAddressChangedEvent struct { type HumanAddressChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
Country string `json:"country,omitempty"` Country *string `json:"country,omitempty"`
Locality string `json:"locality,omitempty"` Locality *string `json:"locality,omitempty"`
PostalCode string `json:"postalCode,omitempty"` PostalCode *string `json:"postalCode,omitempty"`
Region string `json:"region,omitempty"` Region *string `json:"region,omitempty"`
StreetAddress string `json:"streetAddress,omitempty"` StreetAddress *string `json:"streetAddress,omitempty"`
} }
func (e *HumanAddressChangedEvent) Data() interface{} { func (e *HumanAddressChangedEvent) Data() interface{} {

View File

@ -20,14 +20,14 @@ const (
HumanPasswordCheckFailedType = passwordEventPrefix + "check.failed" HumanPasswordCheckFailedType = passwordEventPrefix + "check.failed"
) )
type HumanPasswordChangedChangedEvent struct { type HumanPasswordChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
Secret *crypto.CryptoValue `json:"secret,omitempty"` Secret *crypto.CryptoValue `json:"secret,omitempty"`
ChangeRequired bool `json:"changeRequired,omitempty"` ChangeRequired bool `json:"changeRequired"`
} }
func (e *HumanPasswordChangedChangedEvent) Data() interface{} { func (e *HumanPasswordChangedEvent) Data() interface{} {
return e return e
} }
@ -35,8 +35,8 @@ func NewHumanPasswordChangedEvent(
ctx context.Context, ctx context.Context,
secret *crypto.CryptoValue, secret *crypto.CryptoValue,
changeRequired bool, changeRequired bool,
) *HumanPasswordChangedChangedEvent { ) *HumanPasswordChangedEvent {
return &HumanPasswordChangedChangedEvent{ return &HumanPasswordChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
ctx, ctx,
HumanPasswordChangedType, HumanPasswordChangedType,
@ -47,7 +47,7 @@ func NewHumanPasswordChangedEvent(
} }
func HumanPasswordChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) { func HumanPasswordChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
humanAdded := &HumanPasswordChangedChangedEvent{ humanAdded := &HumanPasswordChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),
} }
err := json.Unmarshal(event.Data, humanAdded) err := json.Unmarshal(event.Data, humanAdded)

View File

@ -18,19 +18,20 @@ const (
type HumanProfileChangedEvent struct { type HumanProfileChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
FirstName string `json:"firstName,omitempty"` FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"` LastName string `json:"lastName,omitempty"`
NickName string `json:"nickName,omitempty"` NickName *string `json:"nickName,omitempty"`
DisplayName string `json:"displayName,omitempty"` DisplayName *string `json:"displayName,omitempty"`
PreferredLanguage language.Tag `json:"preferredLanguage,omitempty"` PreferredLanguage *language.Tag `json:"preferredLanguage,omitempty"`
Gender domain.Gender `json:"gender,omitempty"` Gender *domain.Gender `json:"gender,omitempty"`
} }
func (e *HumanProfileChangedEvent) Data() interface{} { func (e *HumanProfileChangedEvent) Data() interface{} {
return e return e
} }
func NewHumanProfileChangedEvent(ctx context.Context) *HumanProfileChangedEvent { func NewHumanProfileChangedEvent(
ctx context.Context) *HumanProfileChangedEvent {
return &HumanProfileChangedEvent{ return &HumanProfileChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
ctx, ctx,

View File

@ -61,8 +61,8 @@ type MachineChangedEvent struct {
UserName string `json:"userName"` UserName string `json:"userName"`
Name string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
Description string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
} }
func (e *MachineChangedEvent) Data() interface{} { func (e *MachineChangedEvent) Data() interface{} {

View File

@ -190,8 +190,8 @@ func NewUserV1PasswordChangedEvent(
ctx context.Context, ctx context.Context,
secret *crypto.CryptoValue, secret *crypto.CryptoValue,
changeRequired bool, changeRequired bool,
) *HumanPasswordChangedChangedEvent { ) *HumanPasswordChangedEvent {
return &HumanPasswordChangedChangedEvent{ return &HumanPasswordChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
ctx, ctx,
UserV1PasswordChangedType, UserV1PasswordChangedType,
@ -360,24 +360,12 @@ func NewUserV1PhoneCodeSentEvent(ctx context.Context) *HumanPhoneCodeSentEvent {
func NewUserV1ProfileChangedEvent( func NewUserV1ProfileChangedEvent(
ctx context.Context, ctx context.Context,
firstName,
lastName,
nickName,
displayName string,
preferredLanguage language.Tag,
gender domain.Gender,
) *HumanProfileChangedEvent { ) *HumanProfileChangedEvent {
return &HumanProfileChangedEvent{ return &HumanProfileChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
ctx, ctx,
UserV1ProfileChangedType, UserV1ProfileChangedType,
), ),
FirstName: firstName,
LastName: lastName,
NickName: nickName,
DisplayName: displayName,
PreferredLanguage: preferredLanguage,
Gender: gender,
} }
} }
@ -394,11 +382,6 @@ func NewUserV1AddressChangedEvent(
ctx, ctx,
UserV1AddressChangedType, UserV1AddressChangedType,
), ),
Country: country,
Locality: locality,
PostalCode: postalCode,
Region: region,
StreetAddress: streetAddress,
} }
} }

View File

@ -1842,6 +1842,7 @@ message MachineView {
message UpdateMachineRequest { message UpdateMachineRequest {
string id = 1 [(validate.rules).string.min_len = 1]; string id = 1 [(validate.rules).string.min_len = 1];
string description = 2 [(validate.rules).string.max_len = 500]; string description = 2 [(validate.rules).string.max_len = 500];
string name = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
} }
message AddMachineKeyRequest { message AddMachineKeyRequest {