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) {
user, err := s.user.DeactivateUser(ctx, in.Id)
user, err := s.command.DeactivateUser(ctx, in.Id)
if err != nil {
return nil, err
}
return userFromModel(user), nil
return userFromDomain(user), nil
}
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 {
return nil, err
}
return userFromModel(user), nil
return userFromDomain(user), nil
}
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 {
return nil, err
}
return userFromModel(user), nil
return userFromDomain(user), nil
}
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 {
return nil, err
}
return userFromModel(user), nil
return userFromDomain(user), nil
}
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
}
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 {
return nil, err
}
return machineFromModel(machine), nil
return machineFromDomain(machine), nil
}
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) {
profile, err := s.user.ChangeProfile(ctx, updateProfileToModel(request))
profile, err := s.command.ChangeHumanProfile(ctx, updateProfileToDomain(request))
if err != nil {
return nil, err
}
return profileFromModel(profile), nil
return profileFromDomain(profile), nil
}
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) {
email, err := s.user.ChangeEmail(ctx, updateEmailToModel(request))
email, err := s.command.ChangeHumanEmail(ctx, updateEmailToDomain(request))
if err != nil {
return nil, err
}
return emailFromModel(email), nil
return emailFromDomain(email), nil
}
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) {
address, err := s.user.ChangeAddress(ctx, updateAddressToModel(request))
address, err := s.command.ChangeHumanAddress(ctx, updateAddressToDomain(request))
if err != nil {
return nil, err
}
return addressFromModel(address), nil
return addressFromDomain(address), nil
}
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
}
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 {
var human *domain.Human
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)
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)
logging.Log("GRPC-d8k2s").OnError(err).Debug("language malformed")
return &usr_model.Profile{
return &domain.Profile{
ObjectRoot: models.ObjectRoot{AggregateID: u.Id},
FirstName: u.FirstName,
LastName: u.LastName,
NickName: u.NickName,
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)
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 {
return &usr_model.Email{
func updateEmailToDomain(e *management.UpdateUserEmailRequest) *domain.Email {
return &domain.Email{
ObjectRoot: models.ObjectRoot{AggregateID: e.Id},
EmailAddress: e.Email,
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)
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 {
return &usr_model.Address{
func updateAddressToDomain(address *management.UpdateUserAddressRequest) *domain.Address {
return &domain.Address{
ObjectRoot: models.ObjectRoot{AggregateID: address.Id},
Country: address.Country,
StreetAddress: address.StreetAddress,

View File

@ -20,9 +20,10 @@ func machineCreateToDomain(machine *management.CreateMachineRequest) *domain.Mac
}
}
func updateMachineToModel(machine *management.UpdateMachineRequest) *usr_model.Machine {
return &usr_model.Machine{
func updateMachineToDomain(machine *management.UpdateMachineRequest) *domain.Machine {
return &domain.Machine{
ObjectRoot: models.ObjectRoot{AggregateID: machine.Id},
Name: machine.Name,
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 {
lastKeyAdded, err := ptypes.TimestampProto(machine.LastKeyAdded)
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 {
dataBytes, err := json.Marshal(event.Data())
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
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,8 +21,12 @@ func (wm *PasswordLockoutPolicyWriteModel) Reduce() error {
wm.ShowLockOutFailures = e.ShowLockOutFailures
wm.IsActive = true
case *policy.PasswordLockoutPolicyChangedEvent:
wm.MaxAttempts = e.MaxAttempts
wm.ShowLockOutFailures = e.ShowLockOutFailures
if e.MaxAttempts != nil {
wm.MaxAttempts = *e.MaxAttempts
}
if e.ShowLockOutFailures != nil {
wm.ShowLockOutFailures = *e.ShowLockOutFailures
}
case *policy.PasswordLockoutPolicyRemovedEvent:
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
} 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")
}
@ -31,9 +35,11 @@ func (r *CommandSide) RegisterUser(ctx context.Context, user *domain.User) (*dom
}
if user.Human != nil {
} else if user.Machine != nil {
human, err := r.RegisterHuman(ctx, user.ResourceOwner, user.UserName, user.Human, 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")
}
@ -122,6 +128,21 @@ func (r *CommandSide) UnlockUser(ctx context.Context, userID string) (*domain.Us
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) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()

View File

@ -1,7 +1,6 @@
package command
import (
"github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain"
)
@ -38,28 +37,28 @@ func writeModelToHuman(wm *HumanWriteModel) *domain.Human {
}
}
func writeModelToProfile(wm *HumanProfileWriteModel) *model.Profile {
return &model.Profile{
func writeModelToProfile(wm *HumanProfileWriteModel) *domain.Profile {
return &domain.Profile{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
FirstName: wm.FirstName,
LastName: wm.LastName,
NickName: wm.NickName,
DisplayName: wm.DisplayName,
PreferredLanguage: wm.PreferredLanguage,
Gender: model.Gender(wm.Gender),
Gender: wm.Gender,
}
}
func writeModelToEmail(wm *HumanEmailWriteModel) *model.Email {
return &model.Email{
func writeModelToEmail(wm *HumanEmailWriteModel) *domain.Email {
return &domain.Email{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
EmailAddress: wm.Email,
IsEmailVerified: wm.IsEmailVerified,
}
}
func writeModelToAddress(wm *HumanAddressWriteModel) *model.Address {
return &model.Address{
func writeModelToAddress(wm *HumanAddressWriteModel) *domain.Address {
return &domain.Address{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
Country: wm.Country,
Locality: wm.Locality,
@ -68,3 +67,11 @@ func writeModelToAddress(wm *HumanAddressWriteModel) *model.Address {
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)
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
userAgg.PushEvents(
user.NewHumanAddedEvent(
ctx,
username,
human.FirstName,
human.LastName,
human.NickName,
human.DisplayName,
human.PreferredLanguage,
human.Gender,
human.EmailAddress,
human.PhoneNumber,
addEvent := user.NewHumanAddedEvent(
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,
),
)
//TODO: HashPassword If existing
//TODO: Generate Init Code if needed
//TODO: Generate Phone Code if needed
human.StreetAddress)
}
if human.Password != nil {
addEvent.AddPasswordData(human.SecretCrypto, human.ChangeRequired)
}
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 {
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))
}
@ -68,3 +86,82 @@ func (r *CommandSide) AddHuman(ctx context.Context, orgID, username string, huma
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"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"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)
if err != nil {
return nil, err

View File

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

View File

@ -4,11 +4,10 @@ import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"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() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M9sf", "Errors.Email.Invalid")
}

View File

@ -1,6 +1,7 @@
package command
import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
@ -31,6 +32,9 @@ type HumanWriteModel struct {
Region string
StreetAddress string
Secret *crypto.CryptoValue
SecretChangeRequired bool
UserState domain.UserState
}
@ -45,21 +49,20 @@ func NewHumanWriteModel(userID string) *HumanWriteModel {
func (wm *HumanWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.HumanEmailChangedEvent:
wm.AppendEvents(e)
case *user.HumanEmailVerifiedEvent:
wm.AppendEvents(e)
case *user.HumanAddedEvent, *user.HumanRegisteredEvent:
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:
case *user.HumanAddedEvent,
*user.HumanRegisteredEvent,
*user.HumanProfileChangedEvent,
*user.HumanEmailChangedEvent,
*user.HumanEmailVerifiedEvent,
*user.HumanPhoneChangedEvent,
*user.HumanPhoneVerifiedEvent,
*user.HumanAddressChangedEvent,
*user.HumanPasswordChangedEvent,
*user.UserDeactivatedEvent,
*user.UserReactivatedEvent,
*user.UserLockedEvent,
*user.UserUnlockedEvent,
*user.UserRemovedEvent:
wm.AppendEvents(e)
}
}
@ -70,11 +73,21 @@ func (wm *HumanWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateInitial
wm.reduceHumanAddedEvent(e)
case *user.HumanRegisteredEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateInitial
wm.reduceHumanRegisteredEvent(e)
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:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateLocked
@ -102,3 +115,105 @@ func (wm *HumanWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
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"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"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() {
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.UserState = domain.UserStateActive
case *user.HumanProfileChangedEvent:
wm.FirstName = e.FirstName
wm.LastName = e.LastName
wm.NickName = e.NickName
wm.DisplayName = e.DisplayName
wm.PreferredLanguage = e.PreferredLanguage
wm.Gender = e.Gender
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
}
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}
@ -101,19 +113,19 @@ func (wm *HumanProfileWriteModel) NewChangedEvent(
}
if wm.NickName != nickName {
hasChanged = true
changedEvent.NickName = nickName
changedEvent.NickName = &nickName
}
if wm.DisplayName != displayName {
hasChanged = true
changedEvent.DisplayName = displayName
changedEvent.DisplayName = &displayName
}
if wm.PreferredLanguage != preferredLanguage {
hasChanged = true
changedEvent.PreferredLanguage = preferredLanguage
changedEvent.PreferredLanguage = &preferredLanguage
}
if gender.Valid() && wm.Gender != gender {
hasChanged = true
changedEvent.Gender = gender
changedEvent.Gender = &gender
}
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
*Address
ExternalIDPs []*ExternalIDP
InitCode *InitUserCode
EmailCode *EmailCode
PhoneCode *PhoneCode
PasswordCode *PasswordCode
OTP *OTP
U2FTokens []*WebAuthNToken
PasswordlessTokens []*WebAuthNToken
@ -79,3 +75,18 @@ func (u *Human) HashPasswordIfExisting(policy *PasswordComplexityPolicy, passwor
}
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)
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
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.IsActive = true
case *policy.LabelPolicyChangedEvent:
rm.PrimaryColor = e.PrimaryColor
rm.SecondaryColor = e.SecondaryColor
if e.PrimaryColor != nil {
rm.PrimaryColor = *e.PrimaryColor
}
if e.SecondaryColor != nil {
rm.SecondaryColor = *e.SecondaryColor
}
case *policy.LabelPolicyRemovedEvent:
rm.IsActive = false
}

View File

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

View File

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

View File

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

View File

@ -25,11 +25,21 @@ func (rm *PasswordComplexityPolicyReadModel) Reduce() error {
rm.HasNumber = e.HasNumber
rm.HasSymbol = e.HasSymbol
case *policy.PasswordComplexityPolicyChangedEvent:
rm.MinLength = e.MinLength
rm.HasLowercase = e.HasLowercase
rm.HasUpperCase = e.HasUpperCase
rm.HasNumber = e.HasNumber
rm.HasSymbol = e.HasSymbol
if e.MinLength != nil {
rm.MinLength = *e.MinLength
}
if e.HasLowercase != nil {
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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,11 +16,11 @@ const (
type HumanAddressChangedEvent struct {
eventstore.BaseEvent `json:"-"`
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"`
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 (e *HumanAddressChangedEvent) Data() interface{} {

View File

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

View File

@ -18,19 +18,20 @@ const (
type HumanProfileChangedEvent struct {
eventstore.BaseEvent `json:"-"`
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 domain.Gender `json:"gender,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 *domain.Gender `json:"gender,omitempty"`
}
func (e *HumanProfileChangedEvent) Data() interface{} {
return e
}
func NewHumanProfileChangedEvent(ctx context.Context) *HumanProfileChangedEvent {
func NewHumanProfileChangedEvent(
ctx context.Context) *HumanProfileChangedEvent {
return &HumanProfileChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,

View File

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

View File

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

View File

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