feat: user v3 api update (#8582)

# Which Problems Are Solved

Users are not yet able to update their information an status in user API
v3.

# How the Problems Are Solved

Add endpoints and functionality to update users and their status in user
API v3.

# Additional Changes

Aggregate_type and event_types are updated with "userschema" to avoid
conflicts with old events.

# Additional Context

closes #7898
This commit is contained in:
Stefan Benz
2024-09-17 10:27:48 +02:00
committed by GitHub
parent c297a62c4f
commit 5fdad7b8f4
20 changed files with 4265 additions and 412 deletions

View File

@@ -250,16 +250,26 @@ func TestServer_ExecutionTarget(t *testing.T) {
require.NoError(t, err)
defer close()
}
got, err := instance.Client.ActionV3Alpha.GetTarget(tt.ctx, tt.req)
if tt.wantErr {
require.Error(t, err)
return
retryDuration := 5 * time.Second
if ctxDeadline, ok := isolatedIAMOwnerCTX.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.NoError(t, err)
integration.AssertResourceDetails(t, tt.want.GetTarget().GetDetails(), got.GetTarget().GetDetails())
assert.Equal(t, tt.want.GetTarget().GetConfig(), got.GetTarget().GetConfig())
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
got, err := instance.Client.ActionV3Alpha.GetTarget(tt.ctx, tt.req)
if tt.wantErr {
assert.Error(ttt, err, "Error: "+err.Error())
} else {
assert.NoError(ttt, err)
}
if err != nil {
return
}
integration.AssertResourceDetails(t, tt.want.GetTarget().GetDetails(), got.GetTarget().GetDetails())
assert.Equal(t, tt.want.GetTarget().GetConfig(), got.GetTarget().GetConfig())
}, retryDuration, time.Millisecond*100, "timeout waiting for expected execution result")
if tt.clean != nil {
tt.clean(tt.ctx)
}

View File

@@ -75,3 +75,18 @@ func SearchQueryPbToQuery(defaults systemdefaults.SystemDefaults, query *resourc
}
return offset, limit, asc, nil
}
func ResourceOwnerFromOrganization(organization *object.Organization) string {
if organization == nil {
return ""
}
if organization.GetOrgId() != "" {
return organization.GetOrgId()
}
if organization.GetOrgDomain() != "" {
// TODO get org from domain
return ""
}
return ""
}

View File

@@ -14,50 +14,41 @@ import (
"github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
user "github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
)
var (
IAMOwnerCTX, SystemCTX context.Context
UserCTX context.Context
Instance *integration.Instance
Client user.ZITADELUsersClient
CTX context.Context
)
func TestMain(m *testing.M) {
os.Exit(func() int {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()
Instance = integration.NewInstance(ctx)
IAMOwnerCTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner)
SystemCTX = integration.WithSystemAuthorization(ctx)
UserCTX = Instance.WithAuthorization(ctx, integration.UserTypeLogin)
Client = Instance.Client.UserV3Alpha
CTX = ctx
return m.Run()
}())
}
func ensureFeatureEnabled(t *testing.T, iamOwnerCTX context.Context) {
f, err := Instance.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
func ensureFeatureEnabled(t *testing.T, instance *integration.Instance) {
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
require.NoError(t, err)
if f.UserSchema.GetEnabled() {
return
}
_, err = Instance.Client.FeatureV2.SetInstanceFeatures(iamOwnerCTX, &feature.SetInstanceFeaturesRequest{
_, err = instance.Client.FeatureV2.SetInstanceFeatures(ctx, &feature.SetInstanceFeaturesRequest{
UserSchema: gu.Ptr(true),
})
require.NoError(t, err)
retryDuration := time.Minute
if ctxDeadline, ok := iamOwnerCTX.Deadline(); ok {
if ctxDeadline, ok := ctx.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t,
func(ttt *assert.CollectT) {
f, err := Instance.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
require.NoError(ttt, err)

View File

@@ -8,6 +8,7 @@ import (
"github.com/zitadel/zitadel/internal/api/authz"
resource_object "github.com/zitadel/zitadel/internal/api/grpc/resources/object/v3alpha"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/zerrors"
object "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
"github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
@@ -26,7 +27,7 @@ func (s *Server) CreateUser(ctx context.Context, req *user.CreateUserRequest) (_
return nil, err
}
return &user.CreateUserResponse{
Details: resource_object.DomainToDetailsPb(schemauser.Details, object.OwnerType_OWNER_TYPE_ORG, schemauser.ResourceOwner),
Details: resource_object.DomainToDetailsPb(schemauser.Details, object.OwnerType_OWNER_TYPE_ORG, schemauser.Details.ResourceOwner),
EmailCode: gu.Ptr(schemauser.ReturnCodeEmail),
PhoneCode: gu.Ptr(schemauser.ReturnCodePhone),
}, nil
@@ -37,19 +38,35 @@ func createUserRequestToCreateSchemaUser(ctx context.Context, req *user.CreateUs
if err != nil {
return nil, err
}
return &command.CreateSchemaUser{
ResourceOwner: authz.GetCtxData(ctx).OrgID,
ResourceOwner: organizationToCreateResourceOwner(ctx, req.Organization),
SchemaID: req.GetUser().GetSchemaId(),
ID: req.GetUser().GetUserId(),
Data: data,
}, nil
}
func organizationToCreateResourceOwner(ctx context.Context, org *object.Organization) string {
resourceOwner := authz.GetCtxData(ctx).OrgID
if resourceOwnerReq := resource_object.ResourceOwnerFromOrganization(org); resourceOwnerReq != "" {
return resourceOwnerReq
}
return resourceOwner
}
func organizationToUpdateResourceOwner(org *object.Organization) string {
if resourceOwnerReq := resource_object.ResourceOwnerFromOrganization(org); resourceOwnerReq != "" {
return resourceOwnerReq
}
return ""
}
func (s *Server) DeleteUser(ctx context.Context, req *user.DeleteUserRequest) (_ *user.DeleteUserResponse, err error) {
if err := checkUserSchemaEnabled(ctx); err != nil {
return nil, err
}
details, err := s.command.DeleteSchemaUser(ctx, req.GetUserId())
details, err := s.command.DeleteSchemaUser(ctx, organizationToUpdateResourceOwner(req.Organization), req.GetId())
if err != nil {
return nil, err
}
@@ -64,3 +81,126 @@ func checkUserSchemaEnabled(ctx context.Context) error {
}
return zerrors.ThrowPreconditionFailed(nil, "TODO", "Errors.UserSchema.NotEnabled")
}
func (s *Server) PatchUser(ctx context.Context, req *user.PatchUserRequest) (_ *user.PatchUserResponse, err error) {
if err := checkUserSchemaEnabled(ctx); err != nil {
return nil, err
}
schemauser, err := patchUserRequestToChangeSchemaUser(req)
if err != nil {
return nil, err
}
if err := s.command.ChangeSchemaUser(ctx, schemauser, s.userCodeAlg); err != nil {
return nil, err
}
return &user.PatchUserResponse{
Details: resource_object.DomainToDetailsPb(schemauser.Details, object.OwnerType_OWNER_TYPE_ORG, schemauser.Details.ResourceOwner),
EmailCode: gu.Ptr(schemauser.ReturnCodeEmail),
PhoneCode: gu.Ptr(schemauser.ReturnCodePhone),
}, nil
}
func patchUserRequestToChangeSchemaUser(req *user.PatchUserRequest) (_ *command.ChangeSchemaUser, err error) {
var data []byte
if req.GetUser().Data != nil {
data, err = req.GetUser().GetData().MarshalJSON()
if err != nil {
return nil, err
}
}
var email *command.Email
var phone *command.Phone
if req.GetUser().GetContact() != nil {
if req.GetUser().GetContact().GetEmail() != nil {
email = &command.Email{
Address: domain.EmailAddress(req.GetUser().GetContact().Email.Address),
}
if req.GetUser().GetContact().Email.GetIsVerified() {
email.Verified = true
}
if req.GetUser().GetContact().Email.GetReturnCode() != nil {
email.ReturnCode = true
}
if req.GetUser().GetContact().Email.GetSendCode() != nil {
email.URLTemplate = req.GetUser().GetContact().Email.GetSendCode().GetUrlTemplate()
}
}
if req.GetUser().GetContact().Phone != nil {
phone = &command.Phone{
Number: domain.PhoneNumber(req.GetUser().GetContact().Phone.Number),
}
if req.GetUser().GetContact().Phone.GetIsVerified() {
phone.Verified = true
}
if req.GetUser().GetContact().Phone.GetReturnCode() != nil {
phone.ReturnCode = true
}
}
}
return &command.ChangeSchemaUser{
ResourceOwner: organizationToUpdateResourceOwner(req.Organization),
ID: req.GetId(),
SchemaID: req.GetUser().SchemaId,
Data: data,
Email: email,
Phone: phone,
}, nil
}
func (s *Server) DeactivateUser(ctx context.Context, req *user.DeactivateUserRequest) (_ *user.DeactivateUserResponse, err error) {
if err := checkUserSchemaEnabled(ctx); err != nil {
return nil, err
}
details, err := s.command.DeactivateSchemaUser(ctx, organizationToUpdateResourceOwner(req.Organization), req.GetId())
if err != nil {
return nil, err
}
return &user.DeactivateUserResponse{
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_ORG, details.ResourceOwner),
}, nil
}
func (s *Server) ActivateUser(ctx context.Context, req *user.ActivateUserRequest) (_ *user.ActivateUserResponse, err error) {
if err := checkUserSchemaEnabled(ctx); err != nil {
return nil, err
}
details, err := s.command.ActivateSchemaUser(ctx, organizationToUpdateResourceOwner(req.Organization), req.GetId())
if err != nil {
return nil, err
}
return &user.ActivateUserResponse{
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_ORG, details.ResourceOwner),
}, nil
}
func (s *Server) LockUser(ctx context.Context, req *user.LockUserRequest) (_ *user.LockUserResponse, err error) {
if err := checkUserSchemaEnabled(ctx); err != nil {
return nil, err
}
details, err := s.command.LockSchemaUser(ctx, organizationToUpdateResourceOwner(req.Organization), req.GetId())
if err != nil {
return nil, err
}
return &user.LockUserResponse{
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_ORG, details.ResourceOwner),
}, nil
}
func (s *Server) UnlockUser(ctx context.Context, req *user.UnlockUserRequest) (_ *user.UnlockUserResponse, err error) {
if err := checkUserSchemaEnabled(ctx); err != nil {
return nil, err
}
details, err := s.command.UnlockSchemaUser(ctx, organizationToUpdateResourceOwner(req.Organization), req.GetId())
if err != nil {
return nil, err
}
return &user.UnlockUserResponse{
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_ORG, details.ResourceOwner),
}, nil
}

View File

@@ -20,7 +20,10 @@ import (
)
func TestServer_ListUserSchemas(t *testing.T) {
ensureFeatureEnabled(t, IAMOwnerCTX)
t.Parallel()
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
userSchema := new(structpb.Struct)
err := userSchema.UnmarshalJSON([]byte(`{
@@ -43,7 +46,7 @@ func TestServer_ListUserSchemas(t *testing.T) {
{
name: "missing permission",
args: args{
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
ctx: instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
req: &schema.SearchUserSchemasRequest{},
},
wantErr: true,
@@ -51,7 +54,7 @@ func TestServer_ListUserSchemas(t *testing.T) {
{
name: "not found, error",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.SearchUserSchemasRequest{
Filters: []*schema.SearchFilter{
{
@@ -75,11 +78,11 @@ func TestServer_ListUserSchemas(t *testing.T) {
{
name: "single (id), ok",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.SearchUserSchemasRequest{},
prepare: func(request *schema.SearchUserSchemasRequest, resp *schema.SearchUserSchemasResponse) error {
schemaType := gofakeit.Name()
createResp := Instance.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType)
createResp := instance.CreateUserSchemaEmptyWithType(isolatedIAMOwnerCTX, schemaType)
request.Filters = []*schema.SearchFilter{
{
Filter: &schema.SearchFilter_IdFilter{
@@ -121,14 +124,14 @@ func TestServer_ListUserSchemas(t *testing.T) {
{
name: "multiple (type), ok",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.SearchUserSchemasRequest{},
prepare: func(request *schema.SearchUserSchemasRequest, resp *schema.SearchUserSchemasResponse) error {
schemaType := gofakeit.Name()
schemaType1 := schemaType + "_1"
schemaType2 := schemaType + "_2"
createResp := Instance.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType1)
createResp2 := Instance.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType2)
createResp := instance.CreateUserSchemaEmptyWithType(isolatedIAMOwnerCTX, schemaType1)
createResp2 := instance.CreateUserSchemaEmptyWithType(isolatedIAMOwnerCTX, schemaType2)
request.SortingColumn = gu.Ptr(schema.FieldName_FIELD_NAME_TYPE)
request.Query = &object.SearchQuery{Desc: false}
@@ -186,12 +189,12 @@ func TestServer_ListUserSchemas(t *testing.T) {
}
retryDuration := 20 * time.Second
if ctxDeadline, ok := IAMOwnerCTX.Deadline(); ok {
if ctxDeadline, ok := isolatedIAMOwnerCTX.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
got, err := Client.SearchUserSchemas(tt.args.ctx, tt.args.req)
got, err := instance.Client.UserSchemaV3.SearchUserSchemas(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(ttt, err)
return
@@ -215,7 +218,10 @@ func TestServer_ListUserSchemas(t *testing.T) {
}
func TestServer_GetUserSchema(t *testing.T) {
ensureFeatureEnabled(t, IAMOwnerCTX)
t.Parallel()
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
userSchema := new(structpb.Struct)
err := userSchema.UnmarshalJSON([]byte(`{
@@ -238,11 +244,11 @@ func TestServer_GetUserSchema(t *testing.T) {
{
name: "missing permission",
args: args{
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
ctx: instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
req: &schema.GetUserSchemaRequest{},
prepare: func(request *schema.GetUserSchemaRequest, resp *schema.GetUserSchemaResponse) error {
schemaType := gofakeit.Name()
createResp := Instance.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType)
createResp := instance.CreateUserSchemaEmptyWithType(isolatedIAMOwnerCTX, schemaType)
request.Id = createResp.GetDetails().GetId()
return nil
},
@@ -252,7 +258,7 @@ func TestServer_GetUserSchema(t *testing.T) {
{
name: "not existing, error",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.GetUserSchemaRequest{
Id: "notexisting",
},
@@ -262,11 +268,11 @@ func TestServer_GetUserSchema(t *testing.T) {
{
name: "get, ok",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.GetUserSchemaRequest{},
prepare: func(request *schema.GetUserSchemaRequest, resp *schema.GetUserSchemaResponse) error {
schemaType := gofakeit.Name()
createResp := Instance.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType)
createResp := instance.CreateUserSchemaEmptyWithType(isolatedIAMOwnerCTX, schemaType)
request.Id = createResp.GetDetails().GetId()
resp.UserSchema.Config.Type = schemaType
@@ -295,12 +301,12 @@ func TestServer_GetUserSchema(t *testing.T) {
}
retryDuration := 5 * time.Second
if ctxDeadline, ok := IAMOwnerCTX.Deadline(); ok {
if ctxDeadline, ok := isolatedIAMOwnerCTX.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
got, err := Client.GetUserSchema(tt.args.ctx, tt.args.req)
got, err := instance.Client.UserSchemaV3.GetUserSchema(tt.args.ctx, tt.args.req)
if tt.wantErr {
assert.Error(t, err, "Error: "+err.Error())
} else {

View File

@@ -14,49 +14,41 @@ import (
"github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
schema "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
)
var (
IAMOwnerCTX, SystemCTX context.Context
Instance *integration.Instance
Client schema.ZITADELUserSchemasClient
CTX context.Context
)
func TestMain(m *testing.M) {
os.Exit(func() int {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()
Instance = integration.NewInstance(ctx)
IAMOwnerCTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner)
SystemCTX = integration.WithSystemAuthorization(ctx)
Client = Instance.Client.UserSchemaV3
CTX = ctx
return m.Run()
}())
}
func ensureFeatureEnabled(t *testing.T, iamOwnerCTX context.Context) {
f, err := Instance.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
func ensureFeatureEnabled(t *testing.T, instance *integration.Instance) {
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
require.NoError(t, err)
if f.UserSchema.GetEnabled() {
return
}
_, err = Instance.Client.FeatureV2.SetInstanceFeatures(iamOwnerCTX, &feature.SetInstanceFeaturesRequest{
_, err = instance.Client.FeatureV2.SetInstanceFeatures(ctx, &feature.SetInstanceFeaturesRequest{
UserSchema: gu.Ptr(true),
})
require.NoError(t, err)
retryDuration := time.Minute
if ctxDeadline, ok := iamOwnerCTX.Deadline(); ok {
if ctxDeadline, ok := ctx.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t,
func(ttt *assert.CollectT) {
f, err := Instance.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
f, err := instance.Client.FeatureV2.GetInstanceFeatures(ctx, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
require.NoError(ttt, err)

View File

@@ -19,7 +19,10 @@ import (
)
func TestServer_CreateUserSchema(t *testing.T) {
ensureFeatureEnabled(t, IAMOwnerCTX)
t.Parallel()
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
tests := []struct {
name string
@@ -30,7 +33,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
}{
{
name: "missing permission, error",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
ctx: instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -40,7 +43,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
},
{
name: "empty type",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: "",
@@ -50,7 +53,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
},
{
name: "empty schema, error",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -60,7 +63,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
},
{
name: "invalid schema, error",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -91,7 +94,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
},
{
name: "no authenticators, ok",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -123,14 +126,14 @@ func TestServer_CreateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
},
{
name: "invalid authenticator, error",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -164,7 +167,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
},
{
name: "with authenticator, ok",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -199,14 +202,14 @@ func TestServer_CreateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
},
{
name: "with invalid permission, error",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -241,7 +244,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
},
{
name: "with valid permission, ok",
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.CreateUserSchemaRequest{
UserSchema: &schema.UserSchema{
Type: gofakeit.Name(),
@@ -280,7 +283,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -288,7 +291,7 @@ func TestServer_CreateUserSchema(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Client.CreateUserSchema(tt.ctx, tt.req)
got, err := instance.Client.UserSchemaV3.CreateUserSchema(tt.ctx, tt.req)
if tt.wantErr {
require.Error(t, err)
return
@@ -301,7 +304,10 @@ func TestServer_CreateUserSchema(t *testing.T) {
}
func TestServer_UpdateUserSchema(t *testing.T) {
ensureFeatureEnabled(t, IAMOwnerCTX)
t.Parallel()
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
@@ -317,12 +323,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "missing permission, error",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
ctx: instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
Type: gu.Ptr(gofakeit.Name()),
@@ -337,7 +343,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{},
},
wantErr: true,
@@ -349,7 +355,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{},
},
wantErr: true,
@@ -357,12 +363,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "empty type, error",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
Type: gu.Ptr(""),
@@ -374,12 +380,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "update type, ok",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
Type: gu.Ptr(gofakeit.Name()),
@@ -391,7 +397,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -399,12 +405,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "empty schema, ok",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
DataType: &schema.PatchUserSchema_Schema{},
@@ -416,7 +422,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -424,12 +430,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "invalid schema, error",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
DataType: &schema.PatchUserSchema_Schema{
@@ -462,12 +468,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "update schema, ok",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
DataType: &schema.PatchUserSchema_Schema{
@@ -500,7 +506,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -508,12 +514,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "invalid authenticator, error",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
PossibleAuthenticators: []schema.AuthenticatorType{
@@ -527,12 +533,12 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "update authenticator, ok",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
PossibleAuthenticators: []schema.AuthenticatorType{
@@ -546,7 +552,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -554,8 +560,8 @@ func TestServer_UpdateUserSchema(t *testing.T) {
{
name: "inactive, error",
prepare: func(request *schema.PatchUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
_, err := Client.DeactivateUserSchema(IAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
_, err := instance.Client.UserSchemaV3.DeactivateUserSchema(isolatedIAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
Id: schemaID,
})
require.NoError(t, err)
@@ -563,7 +569,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
return nil
},
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.PatchUserSchemaRequest{
UserSchema: &schema.PatchUserSchema{
Type: gu.Ptr(gofakeit.Name()),
@@ -578,7 +584,7 @@ func TestServer_UpdateUserSchema(t *testing.T) {
err := tt.prepare(tt.args.req)
require.NoError(t, err)
got, err := Client.PatchUserSchema(tt.args.ctx, tt.args.req)
got, err := instance.Client.UserSchemaV3.PatchUserSchema(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(t, err)
return
@@ -590,7 +596,10 @@ func TestServer_UpdateUserSchema(t *testing.T) {
}
func TestServer_DeactivateUserSchema(t *testing.T) {
ensureFeatureEnabled(t, IAMOwnerCTX)
t.Parallel()
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
@@ -606,7 +615,7 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
{
name: "not existing, error",
args: args{
IAMOwnerCTX,
isolatedIAMOwnerCTX,
&schema.DeactivateUserSchemaRequest{
Id: "notexisting",
},
@@ -617,10 +626,10 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
{
name: "active, ok",
args: args{
IAMOwnerCTX,
isolatedIAMOwnerCTX,
&schema.DeactivateUserSchemaRequest{},
func(request *schema.DeactivateUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
@@ -630,7 +639,7 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -638,12 +647,12 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
{
name: "inactive, error",
args: args{
IAMOwnerCTX,
isolatedIAMOwnerCTX,
&schema.DeactivateUserSchemaRequest{},
func(request *schema.DeactivateUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
_, err := Client.DeactivateUserSchema(IAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
_, err := instance.Client.UserSchemaV3.DeactivateUserSchema(isolatedIAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
Id: schemaID,
})
return err
@@ -657,7 +666,7 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
err := tt.args.prepare(tt.args.req)
require.NoError(t, err)
got, err := Client.DeactivateUserSchema(tt.args.ctx, tt.args.req)
got, err := instance.Client.UserSchemaV3.DeactivateUserSchema(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(t, err)
return
@@ -669,7 +678,10 @@ func TestServer_DeactivateUserSchema(t *testing.T) {
}
func TestServer_ReactivateUserSchema(t *testing.T) {
ensureFeatureEnabled(t, IAMOwnerCTX)
t.Parallel()
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
@@ -685,7 +697,7 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
{
name: "not existing, error",
args: args{
IAMOwnerCTX,
isolatedIAMOwnerCTX,
&schema.ReactivateUserSchemaRequest{
Id: "notexisting",
},
@@ -696,10 +708,10 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
{
name: "active, error",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.ReactivateUserSchemaRequest{},
prepare: func(request *schema.ReactivateUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
@@ -709,12 +721,12 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
{
name: "inactive, ok",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.ReactivateUserSchemaRequest{},
prepare: func(request *schema.ReactivateUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
_, err := Client.DeactivateUserSchema(IAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
_, err := instance.Client.UserSchemaV3.DeactivateUserSchema(isolatedIAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
Id: schemaID,
})
return err
@@ -725,7 +737,7 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -736,7 +748,7 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
err := tt.args.prepare(tt.args.req)
require.NoError(t, err)
got, err := Client.ReactivateUserSchema(tt.args.ctx, tt.args.req)
got, err := instance.Client.UserSchemaV3.ReactivateUserSchema(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(t, err)
return
@@ -748,7 +760,10 @@ func TestServer_ReactivateUserSchema(t *testing.T) {
}
func TestServer_DeleteUserSchema(t *testing.T) {
ensureFeatureEnabled(t, IAMOwnerCTX)
t.Parallel()
instance := integration.NewInstance(CTX)
ensureFeatureEnabled(t, instance)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
type args struct {
ctx context.Context
@@ -764,7 +779,7 @@ func TestServer_DeleteUserSchema(t *testing.T) {
{
name: "not existing, error",
args: args{
IAMOwnerCTX,
isolatedIAMOwnerCTX,
&schema.DeleteUserSchemaRequest{
Id: "notexisting",
},
@@ -775,10 +790,10 @@ func TestServer_DeleteUserSchema(t *testing.T) {
{
name: "delete, ok",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.DeleteUserSchemaRequest{},
prepare: func(request *schema.DeleteUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
return nil
},
@@ -788,7 +803,7 @@ func TestServer_DeleteUserSchema(t *testing.T) {
Changed: timestamppb.Now(),
Owner: &object.Owner{
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
Id: Instance.ID(),
Id: instance.ID(),
},
},
},
@@ -796,12 +811,12 @@ func TestServer_DeleteUserSchema(t *testing.T) {
{
name: "deleted, error",
args: args{
ctx: IAMOwnerCTX,
ctx: isolatedIAMOwnerCTX,
req: &schema.DeleteUserSchemaRequest{},
prepare: func(request *schema.DeleteUserSchemaRequest) error {
schemaID := Instance.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
schemaID := instance.CreateUserSchemaEmpty(isolatedIAMOwnerCTX).GetDetails().GetId()
request.Id = schemaID
_, err := Client.DeleteUserSchema(IAMOwnerCTX, &schema.DeleteUserSchemaRequest{
_, err := instance.Client.UserSchemaV3.DeleteUserSchema(isolatedIAMOwnerCTX, &schema.DeleteUserSchemaRequest{
Id: schemaID,
})
return err
@@ -815,7 +830,7 @@ func TestServer_DeleteUserSchema(t *testing.T) {
err := tt.args.prepare(tt.args.req)
require.NoError(t, err)
got, err := Client.DeleteUserSchema(tt.args.ctx, tt.args.req)
got, err := instance.Client.UserSchemaV3.DeleteUserSchema(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(t, err)
return

View File

@@ -186,7 +186,7 @@ func validateUserSchema(userSchema json.RawMessage) error {
}
func (c *Commands) getSchemaWriteModelByID(ctx context.Context, resourceOwner, id string) (*UserSchemaWriteModel, error) {
writeModel := NewUserSchemaWriteModel(resourceOwner, id, "")
writeModel := NewUserSchemaWriteModel(resourceOwner, id)
if err := c.eventstore.FilterToQueryReducer(ctx, writeModel); err != nil {
return nil, err
}

View File

@@ -19,16 +19,15 @@ type UserSchemaWriteModel struct {
Schema json.RawMessage
PossibleAuthenticators []domain.AuthenticatorType
State domain.UserSchemaState
Revision uint64
SchemaRevision uint64
}
func NewUserSchemaWriteModel(resourceOwner, schemaID, ty string) *UserSchemaWriteModel {
func NewUserSchemaWriteModel(resourceOwner, schemaID string) *UserSchemaWriteModel {
return &UserSchemaWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: schemaID,
ResourceOwner: resourceOwner,
},
SchemaType: ty,
}
}
@@ -40,13 +39,13 @@ func (wm *UserSchemaWriteModel) Reduce() error {
wm.Schema = e.Schema
wm.PossibleAuthenticators = e.PossibleAuthenticators
wm.State = domain.UserSchemaStateActive
wm.Revision = 1
wm.SchemaRevision = 1
case *schema.UpdatedEvent:
if e.SchemaType != nil {
wm.SchemaType = *e.SchemaType
}
if e.SchemaRevision != nil {
wm.Revision = *e.SchemaRevision
wm.SchemaRevision = *e.SchemaRevision
}
if len(e.Schema) > 0 {
wm.Schema = e.Schema
@@ -79,10 +78,6 @@ func (wm *UserSchemaWriteModel) Query() *eventstore.SearchQueryBuilder {
schema.DeletedType,
)
if wm.SchemaType != "" {
query = query.EventData(map[string]interface{}{"schemaType": wm.SchemaType})
}
return query.Builder()
}
func (wm *UserSchemaWriteModel) NewUpdatedEvent(
@@ -99,7 +94,7 @@ func (wm *UserSchemaWriteModel) NewUpdatedEvent(
if !bytes.Equal(wm.Schema, userSchema) {
changes = append(changes, schema.ChangeSchema(userSchema))
// change revision if the content of the schema changed
changes = append(changes, schema.IncreaseRevision(wm.Revision))
changes = append(changes, schema.IncreaseRevision(wm.SchemaRevision))
}
if len(possibleAuthenticators) > 0 && slices.Compare(wm.PossibleAuthenticators, possibleAuthenticators) != 0 {
changes = append(changes, schema.ChangePossibleAuthenticators(possibleAuthenticators))

View File

@@ -15,14 +15,14 @@ import (
)
type CreateSchemaUser struct {
Details *domain.ObjectDetails
ResourceOwner string
Details *domain.ObjectDetails
SchemaID string
schemaRevision uint64
ID string
Data json.RawMessage
ResourceOwner string
ID string
Data json.RawMessage
Email *Email
ReturnCodeEmail string
@@ -45,7 +45,7 @@ func (s *CreateSchemaUser) Valid(ctx context.Context, c *Commands) (err error) {
if !schemaWriteModel.Exists() {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-N9QOuN4F7o", "Errors.UserSchema.NotExists")
}
s.schemaRevision = schemaWriteModel.Revision
s.schemaRevision = schemaWriteModel.SchemaRevision
if s.ID == "" {
s.ID, err = c.idGenerator.Next()
@@ -120,13 +120,13 @@ func (c *Commands) CreateSchemaUser(ctx context.Context, user *CreateSchemaUser,
),
}
if user.Email != nil {
events, user.ReturnCodeEmail, err = c.updateSchemaUserEmail(ctx, events, userAgg, user.Email, alg)
events, user.ReturnCodeEmail, err = c.updateSchemaUserEmail(ctx, writeModel, events, userAgg, user.Email, alg)
if err != nil {
return err
}
}
if user.Phone != nil {
events, user.ReturnCodePhone, err = c.updateSchemaUserPhone(ctx, events, userAgg, user.Phone, alg)
events, user.ReturnCodePhone, err = c.updateSchemaUserPhone(ctx, writeModel, events, userAgg, user.Phone, alg)
if err != nil {
return err
}
@@ -139,11 +139,11 @@ func (c *Commands) CreateSchemaUser(ctx context.Context, user *CreateSchemaUser,
return nil
}
func (c *Commands) DeleteSchemaUser(ctx context.Context, id string) (*domain.ObjectDetails, error) {
func (c *Commands) DeleteSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
if id == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Vs4wJCME7T", "Errors.IDMissing")
}
writeModel, err := c.getSchemaUserExists(ctx, "", id)
writeModel, err := c.getSchemaUserExists(ctx, resourceOwner, id)
if err != nil {
return nil, err
}
@@ -161,7 +161,235 @@ func (c *Commands) DeleteSchemaUser(ctx context.Context, id string) (*domain.Obj
return writeModelToObjectDetails(&writeModel.WriteModel), nil
}
func (c *Commands) updateSchemaUserEmail(ctx context.Context, events []eventstore.Command, agg *eventstore.Aggregate, email *Email, alg crypto.EncryptionAlgorithm) (_ []eventstore.Command, plainCode string, err error) {
type ChangeSchemaUser struct {
Details *domain.ObjectDetails
SchemaID *string
schemaWriteModel *UserSchemaWriteModel
ResourceOwner string
ID string
Data json.RawMessage
Email *Email
ReturnCodeEmail string
Phone *Phone
ReturnCodePhone string
}
func (s *ChangeSchemaUser) Valid(ctx context.Context, c *Commands) (err error) {
if s.ID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-gEJR1QOGHb", "Errors.IDMissing")
}
if s.SchemaID != nil {
s.schemaWriteModel, err = c.getSchemaWriteModelByID(ctx, "", *s.SchemaID)
if err != nil {
return err
}
if !s.schemaWriteModel.Exists() {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists")
}
}
if s.Email != nil && s.Email.Address != "" {
if err := s.Email.Validate(); err != nil {
return err
}
}
if s.Phone != nil && s.Phone.Number != "" {
if s.Phone.Number, err = s.Phone.Number.Normalize(); err != nil {
return err
}
}
return nil
}
func (s *ChangeSchemaUser) ValidData(ctx context.Context, c *Commands, existingUser *UserV3WriteModel) (err error) {
// get role for permission check in schema through extension
role, err := c.getSchemaRoleForWrite(ctx, existingUser.ResourceOwner, existingUser.AggregateID)
if err != nil {
return err
}
if s.schemaWriteModel == nil {
s.schemaWriteModel, err = c.getSchemaWriteModelByID(ctx, "", existingUser.SchemaID)
if err != nil {
return err
}
}
schema, err := domain_schema.NewSchema(role, bytes.NewReader(s.schemaWriteModel.Schema))
if err != nil {
return err
}
// if data not changed but a new schema or revision should be used
data := s.Data
if s.Data == nil {
data = existingUser.Data
}
var v interface{}
if err := json.Unmarshal(data, &v); err != nil {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-7o3ZGxtXUz", "Errors.User.Invalid")
}
if err := schema.Validate(v); err != nil {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-SlKXqLSeL6", "Errors.UserSchema.Data.Invalid")
}
return nil
}
func (c *Commands) ChangeSchemaUser(ctx context.Context, user *ChangeSchemaUser, alg crypto.EncryptionAlgorithm) (err error) {
if err := user.Valid(ctx, c); err != nil {
return err
}
writeModel, err := c.getSchemaUserWriteModelByID(ctx, user.ResourceOwner, user.ID)
if err != nil {
return err
}
if !writeModel.Exists() {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-Nn8CRVlkeZ", "Errors.User.NotFound")
}
userAgg := UserV3AggregateFromWriteModel(&writeModel.WriteModel)
events := make([]eventstore.Command, 0)
if user.Data != nil || user.SchemaID != nil {
if err := user.ValidData(ctx, c, writeModel); err != nil {
return err
}
updateEvent := writeModel.NewUpdatedEvent(ctx,
userAgg,
user.schemaWriteModel.AggregateID,
user.schemaWriteModel.SchemaRevision,
user.Data,
)
if updateEvent != nil {
events = append(events, updateEvent)
}
}
if user.Email != nil {
events, user.ReturnCodeEmail, err = c.updateSchemaUserEmail(ctx, writeModel, events, userAgg, user.Email, alg)
if err != nil {
return err
}
}
if user.Phone != nil {
events, user.ReturnCodePhone, err = c.updateSchemaUserPhone(ctx, writeModel, events, userAgg, user.Phone, alg)
if err != nil {
return err
}
}
if len(events) == 0 {
user.Details = writeModelToObjectDetails(&writeModel.WriteModel)
return nil
}
if err := c.pushAppendAndReduce(ctx, writeModel, events...); err != nil {
return err
}
user.Details = writeModelToObjectDetails(&writeModel.WriteModel)
return nil
}
func (c *Commands) checkPermissionUpdateUserState(ctx context.Context, resourceOwner, userID string) error {
return c.checkPermission(ctx, domain.PermissionUserWrite, resourceOwner, userID)
}
func (c *Commands) LockSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
if id == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Eu8I2VAfjF", "Errors.IDMissing")
}
writeModel, err := c.getSchemaUserExists(ctx, resourceOwner, id)
if err != nil {
return nil, err
}
if !writeModel.Exists() || writeModel.Locked {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-G4LOrnjY7q", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewLockedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
}
func (c *Commands) UnlockSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
if id == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-krXtYscQZh", "Errors.IDMissing")
}
writeModel, err := c.getSchemaUserExists(ctx, resourceOwner, id)
if err != nil {
return nil, err
}
if !writeModel.Exists() || !writeModel.Locked {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-gpBv46Lh9m", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewUnlockedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
}
func (c *Commands) DeactivateSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
if id == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-pjJhge86ZV", "Errors.IDMissing")
}
writeModel, err := c.getSchemaUserExists(ctx, resourceOwner, id)
if err != nil {
return nil, err
}
if writeModel.State != domain.UserStateActive {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-Ob6lR5iFTe", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewDeactivatedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
}
func (c *Commands) ActivateSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
if id == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-17XupGvxBJ", "Errors.IDMissing")
}
writeModel, err := c.getSchemaUserExists(ctx, "", id)
if err != nil {
return nil, err
}
if writeModel.State != domain.UserStateInactive {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-rQjbBr4J3j", "Errors.User.NotFound")
}
if err := c.checkPermissionUpdateUserState(ctx, writeModel.ResourceOwner, writeModel.AggregateID); err != nil {
return nil, err
}
if err := c.pushAppendAndReduce(ctx, writeModel,
schemauser.NewActivatedEvent(ctx, UserV3AggregateFromWriteModel(&writeModel.WriteModel)),
); err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
}
func (c *Commands) updateSchemaUserEmail(ctx context.Context, existing *UserV3WriteModel, events []eventstore.Command, agg *eventstore.Aggregate, email *Email, alg crypto.EncryptionAlgorithm) (_ []eventstore.Command, plainCode string, err error) {
if existing.Email == string(email.Address) {
return events, plainCode, nil
}
events = append(events, schemauser.NewEmailUpdatedEvent(ctx,
agg,
@@ -187,8 +415,12 @@ func (c *Commands) updateSchemaUserEmail(ctx context.Context, events []eventstor
return events, plainCode, nil
}
func (c *Commands) updateSchemaUserPhone(ctx context.Context, events []eventstore.Command, agg *eventstore.Aggregate, phone *Phone, alg crypto.EncryptionAlgorithm) (_ []eventstore.Command, plainCode string, err error) {
events = append(events, schemauser.NewPhoneChangedEvent(ctx,
func (c *Commands) updateSchemaUserPhone(ctx context.Context, existing *UserV3WriteModel, events []eventstore.Command, agg *eventstore.Aggregate, phone *Phone, alg crypto.EncryptionAlgorithm) (_ []eventstore.Command, plainCode string, err error) {
if existing.Phone == string(phone.Number) {
return events, plainCode, nil
}
events = append(events, schemauser.NewPhoneUpdatedEvent(ctx,
agg,
phone.Number,
))
@@ -218,3 +450,11 @@ func (c *Commands) getSchemaUserExists(ctx context.Context, resourceOwner, id st
}
return writeModel, nil
}
func (c *Commands) getSchemaUserWriteModelByID(ctx context.Context, resourceOwner, id string) (*UserV3WriteModel, error) {
writeModel := NewUserV3WriteModel(resourceOwner, id)
if err := c.eventstore.FilterToQueryReducer(ctx, writeModel); err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -29,7 +29,8 @@ type UserV3WriteModel struct {
Data json.RawMessage
State domain.UserState
Locked bool
State domain.UserState
}
func NewExistsUserV3WriteModel(resourceOwner, userID string) *UserV3WriteModel {
@@ -61,8 +62,9 @@ func (wm *UserV3WriteModel) Reduce() error {
switch e := event.(type) {
case *schemauser.CreatedEvent:
wm.SchemaID = e.SchemaID
wm.SchemaRevision = 1
wm.SchemaRevision = e.SchemaRevision
wm.Data = e.Data
wm.Locked = false
wm.State = domain.UserStateActive
case *schemauser.UpdatedEvent:
@@ -79,6 +81,8 @@ func (wm *UserV3WriteModel) Reduce() error {
wm.State = domain.UserStateDeleted
case *schemauser.EmailUpdatedEvent:
wm.Email = string(e.EmailAddress)
wm.IsEmailVerified = false
wm.EmailVerifiedFailedCount = 0
case *schemauser.EmailCodeAddedEvent:
wm.IsEmailVerified = false
wm.EmailVerifiedFailedCount = 0
@@ -87,8 +91,10 @@ func (wm *UserV3WriteModel) Reduce() error {
wm.EmailVerifiedFailedCount = 0
case *schemauser.EmailVerificationFailedEvent:
wm.EmailVerifiedFailedCount += 1
case *schemauser.PhoneChangedEvent:
case *schemauser.PhoneUpdatedEvent:
wm.Phone = string(e.PhoneNumber)
wm.IsPhoneVerified = false
wm.PhoneVerifiedFailedCount = 0
case *schemauser.PhoneCodeAddedEvent:
wm.IsPhoneVerified = false
wm.PhoneVerifiedFailedCount = 0
@@ -97,28 +103,39 @@ func (wm *UserV3WriteModel) Reduce() error {
wm.IsPhoneVerified = true
case *schemauser.PhoneVerificationFailedEvent:
wm.PhoneVerifiedFailedCount += 1
case *schemauser.LockedEvent:
wm.Locked = true
case *schemauser.UnlockedEvent:
wm.Locked = false
case *schemauser.DeactivatedEvent:
wm.State = domain.UserStateInactive
case *schemauser.ActivatedEvent:
wm.State = domain.UserStateActive
}
}
return wm.WriteModel.Reduce()
}
func (wm *UserV3WriteModel) Query() *eventstore.SearchQueryBuilder {
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateTypes(schemauser.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(
schemauser.CreatedType,
schemauser.DeletedType,
)
builder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent)
if wm.ResourceOwner != "" {
builder = builder.ResourceOwner(wm.ResourceOwner)
}
eventtypes := []eventstore.EventType{
schemauser.CreatedType,
schemauser.DeletedType,
schemauser.ActivatedType,
schemauser.DeactivatedType,
schemauser.LockedType,
schemauser.UnlockedType,
}
if wm.DataWM {
query = query.EventTypes(
eventtypes = append(eventtypes,
schemauser.UpdatedType,
)
}
if wm.EmailWM {
query = query.EventTypes(
eventtypes = append(eventtypes,
schemauser.EmailUpdatedType,
schemauser.EmailVerifiedType,
schemauser.EmailCodeAddedType,
@@ -126,31 +143,34 @@ func (wm *UserV3WriteModel) Query() *eventstore.SearchQueryBuilder {
)
}
if wm.PhoneWM {
query = query.EventTypes(
eventtypes = append(eventtypes,
schemauser.PhoneUpdatedType,
schemauser.PhoneVerifiedType,
schemauser.PhoneCodeAddedType,
schemauser.PhoneVerificationFailedType,
)
}
return query.Builder()
return builder.AddQuery().
AggregateTypes(schemauser.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(eventtypes...).Builder()
}
func (wm *UserV3WriteModel) NewUpdatedEvent(
ctx context.Context,
agg *eventstore.Aggregate,
schemaID *string,
schemaRevision *uint64,
schemaID string,
schemaRevision uint64,
data json.RawMessage,
) *schemauser.UpdatedEvent {
changes := make([]schemauser.Changes, 0)
if schemaID != nil && wm.SchemaID != *schemaID {
changes = append(changes, schemauser.ChangeSchemaID(wm.SchemaID, *schemaID))
if wm.SchemaID != schemaID {
changes = append(changes, schemauser.ChangeSchemaID(schemaID))
}
if schemaRevision != nil && wm.SchemaRevision != *schemaRevision {
changes = append(changes, schemauser.ChangeSchemaRevision(wm.SchemaRevision, *schemaRevision))
if wm.SchemaRevision != schemaRevision {
changes = append(changes, schemauser.ChangeSchemaRevision(schemaRevision))
}
if !bytes.Equal(wm.Data, data) {
if data != nil && !bytes.Equal(wm.Data, data) {
changes = append(changes, schemauser.ChangeData(data))
}
if len(changes) == 0 {

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ import (
object_v3alpha "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2"
oidc_pb_v2beta "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta"
org "github.com/zitadel/zitadel/pkg/grpc/org/v2"
"github.com/zitadel/zitadel/pkg/grpc/org/v2"
org_v2beta "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
action "github.com/zitadel/zitadel/pkg/grpc/resources/action/v3alpha"
user_v3alpha "github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
@@ -784,3 +784,55 @@ func (i *Instance) CreateInviteCode(ctx context.Context, userID string) *user_v2
logging.OnError(err).Fatal("create invite code")
return user
}
func (i *Instance) LockSchemaUser(ctx context.Context, orgID string, userID string) *user_v3alpha.LockUserResponse {
var org *object_v3alpha.Organization
if orgID != "" {
org = &object_v3alpha.Organization{Property: &object_v3alpha.Organization_OrgId{OrgId: orgID}}
}
user, err := i.Client.UserV3Alpha.LockUser(ctx, &user_v3alpha.LockUserRequest{
Organization: org,
Id: userID,
})
logging.OnError(err).Fatal("lock user")
return user
}
func (i *Instance) UnlockSchemaUser(ctx context.Context, orgID string, userID string) *user_v3alpha.UnlockUserResponse {
var org *object_v3alpha.Organization
if orgID != "" {
org = &object_v3alpha.Organization{Property: &object_v3alpha.Organization_OrgId{OrgId: orgID}}
}
user, err := i.Client.UserV3Alpha.UnlockUser(ctx, &user_v3alpha.UnlockUserRequest{
Organization: org,
Id: userID,
})
logging.OnError(err).Fatal("unlock user")
return user
}
func (i *Instance) DeactivateSchemaUser(ctx context.Context, orgID string, userID string) *user_v3alpha.DeactivateUserResponse {
var org *object_v3alpha.Organization
if orgID != "" {
org = &object_v3alpha.Organization{Property: &object_v3alpha.Organization_OrgId{OrgId: orgID}}
}
user, err := i.Client.UserV3Alpha.DeactivateUser(ctx, &user_v3alpha.DeactivateUserRequest{
Organization: org,
Id: userID,
})
logging.OnError(err).Fatal("deactivate user")
return user
}
func (i *Instance) ActivateSchemaUser(ctx context.Context, orgID string, userID string) *user_v3alpha.ActivateUserResponse {
var org *object_v3alpha.Organization
if orgID != "" {
org = &object_v3alpha.Organization{Property: &object_v3alpha.Organization_OrgId{OrgId: orgID}}
}
user, err := i.Client.UserV3Alpha.ActivateUser(ctx, &user_v3alpha.ActivateUserRequest{
Organization: org,
Id: userID,
})
logging.OnError(err).Fatal("reactivate user")
return user
}

View File

@@ -5,8 +5,8 @@ import (
)
const (
AggregateType = "user"
AggregateVersion = "v3"
AggregateType = "schemauser"
AggregateVersion = "v1"
)
type Aggregate struct {

View File

@@ -8,7 +8,6 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/zerrors"
)
const (
@@ -21,11 +20,15 @@ const (
)
type EmailUpdatedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
EmailAddress domain.EmailAddress `json:"email,omitempty"`
}
func (e *EmailUpdatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *EmailUpdatedEvent) Payload() interface{} {
return e
}
@@ -36,7 +39,7 @@ func (e *EmailUpdatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
func NewEmailUpdatedEvent(ctx context.Context, aggregate *eventstore.Aggregate, emailAddress domain.EmailAddress) *EmailUpdatedEvent {
return &EmailUpdatedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
EmailUpdatedType,
@@ -45,24 +48,16 @@ func NewEmailUpdatedEvent(ctx context.Context, aggregate *eventstore.Aggregate,
}
}
func EmailUpdatedEventMapper(event eventstore.Event) (eventstore.Event, error) {
emailChangedEvent := &EmailUpdatedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(emailChangedEvent)
if err != nil {
return nil, zerrors.ThrowInternal(err, "USER-4M0sd", "unable to unmarshal human password changed")
}
return emailChangedEvent, nil
}
type EmailVerifiedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
IsEmailVerified bool `json:"-"`
}
func (e *EmailVerifiedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *EmailVerifiedEvent) Payload() interface{} {
return nil
}
@@ -73,7 +68,7 @@ func (e *EmailVerifiedEvent) UniqueConstraints() []*eventstore.UniqueConstraint
func NewEmailVerifiedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *EmailVerifiedEvent {
return &EmailVerifiedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
EmailVerifiedType,
@@ -81,18 +76,13 @@ func NewEmailVerifiedEvent(ctx context.Context, aggregate *eventstore.Aggregate)
}
}
func HumanVerifiedEventMapper(event eventstore.Event) (eventstore.Event, error) {
emailVerified := &EmailVerifiedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
IsEmailVerified: true,
}
return emailVerified, nil
}
type EmailVerificationFailedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
}
func (e *EmailVerificationFailedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *EmailVerificationFailedEvent) Payload() interface{} {
return nil
}
@@ -101,9 +91,9 @@ func (e *EmailVerificationFailedEvent) UniqueConstraints() []*eventstore.UniqueC
return nil
}
func NewHumanEmailVerificationFailedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *EmailVerificationFailedEvent {
func NewEmailVerificationFailedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *EmailVerificationFailedEvent {
return &EmailVerificationFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
EmailVerificationFailedType,
@@ -111,14 +101,8 @@ func NewHumanEmailVerificationFailedEvent(ctx context.Context, aggregate *events
}
}
func EmailVerificationFailedEventMapper(event eventstore.Event) (eventstore.Event, error) {
return &EmailVerificationFailedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}, nil
}
type EmailCodeAddedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
Code *crypto.CryptoValue `json:"code,omitempty"`
Expiry time.Duration `json:"expiry,omitempty"`
@@ -127,6 +111,10 @@ type EmailCodeAddedEvent struct {
TriggeredAtOrigin string `json:"triggerOrigin,omitempty"`
}
func (e *EmailCodeAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *EmailCodeAddedEvent) Payload() interface{} {
return e
}
@@ -148,7 +136,7 @@ func NewEmailCodeAddedEvent(
codeReturned bool,
) *EmailCodeAddedEvent {
return &EmailCodeAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
EmailCodeAddedType,
@@ -161,22 +149,13 @@ func NewEmailCodeAddedEvent(
}
}
func EmailCodeAddedEventMapper(event eventstore.Event) (eventstore.Event, error) {
codeAdded := &EmailCodeAddedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(codeAdded)
if err != nil {
return nil, zerrors.ThrowInternal(err, "USER-3M0sd", "unable to unmarshal human email code added")
}
return codeAdded, nil
}
type EmailCodeSentEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
}
func (e *EmailCodeSentEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *EmailCodeSentEvent) Payload() interface{} {
return nil
}
@@ -185,18 +164,12 @@ func (e *EmailCodeSentEvent) UniqueConstraints() []*eventstore.UniqueConstraint
return nil
}
func NewHumanEmailCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate) *EmailCodeSentEvent {
func NewEmailCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate) *EmailCodeSentEvent {
return &EmailCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
EmailCodeSentType,
),
}
}
func EmailCodeSentEventMapper(event eventstore.Event) (eventstore.Event, error) {
return &EmailCodeSentEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}, nil
}

View File

@@ -6,4 +6,18 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, CreatedType, eventstore.GenericEventMapper[CreatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, UpdatedType, eventstore.GenericEventMapper[UpdatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, DeletedType, eventstore.GenericEventMapper[DeletedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, LockedType, eventstore.GenericEventMapper[LockedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, UnlockedType, eventstore.GenericEventMapper[UnlockedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, ActivatedType, eventstore.GenericEventMapper[ActivatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, DeactivatedType, eventstore.GenericEventMapper[DeactivatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, EmailUpdatedType, eventstore.GenericEventMapper[EmailUpdatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, EmailCodeAddedType, eventstore.GenericEventMapper[EmailCodeAddedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, EmailCodeSentType, eventstore.GenericEventMapper[EmailCodeSentEvent])
eventstore.RegisterFilterEventMapper(AggregateType, EmailVerifiedType, eventstore.GenericEventMapper[EmailVerifiedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, EmailVerificationFailedType, eventstore.GenericEventMapper[EmailVerificationFailedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, PhoneUpdatedType, eventstore.GenericEventMapper[PhoneUpdatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, PhoneCodeAddedType, eventstore.GenericEventMapper[PhoneCodeAddedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, PhoneCodeSentType, eventstore.GenericEventMapper[PhoneCodeSentEvent])
eventstore.RegisterFilterEventMapper(AggregateType, PhoneVerifiedType, eventstore.GenericEventMapper[PhoneVerifiedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, PhoneVerificationFailedType, eventstore.GenericEventMapper[PhoneVerificationFailedEvent])
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/zerrors"
)
const (
@@ -20,23 +19,27 @@ const (
PhoneCodeSentType = phoneEventPrefix + "code.sent"
)
type PhoneChangedEvent struct {
eventstore.BaseEvent `json:"-"`
type PhoneUpdatedEvent struct {
*eventstore.BaseEvent `json:"-"`
PhoneNumber domain.PhoneNumber `json:"phone,omitempty"`
}
func (e *PhoneChangedEvent) Payload() interface{} {
func (e *PhoneUpdatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *PhoneUpdatedEvent) Payload() interface{} {
return e
}
func (e *PhoneChangedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
func (e *PhoneUpdatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
func NewPhoneChangedEvent(ctx context.Context, aggregate *eventstore.Aggregate, phone domain.PhoneNumber) *PhoneChangedEvent {
return &PhoneChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
func NewPhoneUpdatedEvent(ctx context.Context, aggregate *eventstore.Aggregate, phone domain.PhoneNumber) *PhoneUpdatedEvent {
return &PhoneUpdatedEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
PhoneUpdatedType,
@@ -45,24 +48,15 @@ func NewPhoneChangedEvent(ctx context.Context, aggregate *eventstore.Aggregate,
}
}
func PhoneChangedEventMapper(event eventstore.Event) (eventstore.Event, error) {
phoneChangedEvent := &PhoneChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(phoneChangedEvent)
if err != nil {
return nil, zerrors.ThrowInternal(err, "USER-5M0pd", "unable to unmarshal phone changed")
}
return phoneChangedEvent, nil
}
type PhoneVerifiedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
IsPhoneVerified bool `json:"-"`
}
func (e *PhoneVerifiedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *PhoneVerifiedEvent) Payload() interface{} {
return nil
}
@@ -73,7 +67,7 @@ func (e *PhoneVerifiedEvent) UniqueConstraints() []*eventstore.UniqueConstraint
func NewPhoneVerifiedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *PhoneVerifiedEvent {
return &PhoneVerifiedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
PhoneVerifiedType,
@@ -81,15 +75,12 @@ func NewPhoneVerifiedEvent(ctx context.Context, aggregate *eventstore.Aggregate)
}
}
func PhoneVerifiedEventMapper(event eventstore.Event) (eventstore.Event, error) {
return &PhoneVerifiedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
IsPhoneVerified: true,
}, nil
type PhoneVerificationFailedEvent struct {
*eventstore.BaseEvent `json:"-"`
}
type PhoneVerificationFailedEvent struct {
eventstore.BaseEvent `json:"-"`
func (e *PhoneVerificationFailedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *PhoneVerificationFailedEvent) Payload() interface{} {
@@ -102,7 +93,7 @@ func (e *PhoneVerificationFailedEvent) UniqueConstraints() []*eventstore.UniqueC
func NewPhoneVerificationFailedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *PhoneVerificationFailedEvent {
return &PhoneVerificationFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
PhoneVerificationFailedType,
@@ -110,14 +101,8 @@ func NewPhoneVerificationFailedEvent(ctx context.Context, aggregate *eventstore.
}
}
func PhoneVerificationFailedEventMapper(event eventstore.Event) (eventstore.Event, error) {
return &PhoneVerificationFailedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}, nil
}
type PhoneCodeAddedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
Code *crypto.CryptoValue `json:"code,omitempty"`
Expiry time.Duration `json:"expiry,omitempty"`
@@ -137,6 +122,10 @@ func (e *PhoneCodeAddedEvent) TriggerOrigin() string {
return e.TriggeredAtOrigin
}
func (e *PhoneCodeAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func NewPhoneCodeAddedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
@@ -145,7 +134,7 @@ func NewPhoneCodeAddedEvent(
codeReturned bool,
) *PhoneCodeAddedEvent {
return &PhoneCodeAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
PhoneCodeAddedType,
@@ -157,20 +146,8 @@ func NewPhoneCodeAddedEvent(
}
}
func PhoneCodeAddedEventMapper(event eventstore.Event) (eventstore.Event, error) {
codeAdded := &PhoneCodeAddedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(codeAdded)
if err != nil {
return nil, zerrors.ThrowInternal(err, "USER-6Ms9d", "unable to unmarshal phone code added")
}
return codeAdded, nil
}
type PhoneCodeSentEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
}
func (e *PhoneCodeSentEvent) Payload() interface{} {
@@ -181,18 +158,16 @@ func (e *PhoneCodeSentEvent) UniqueConstraints() []*eventstore.UniqueConstraint
return nil
}
func (e *PhoneCodeSentEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func NewPhoneCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate) *PhoneCodeSentEvent {
return &PhoneCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
PhoneCodeSentType,
),
}
}
func PhoneCodeSentEventMapper(event eventstore.Event) (eventstore.Event, error) {
return &PhoneCodeSentEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}, nil
}

View File

@@ -8,10 +8,14 @@ import (
)
const (
eventPrefix = "user."
CreatedType = eventPrefix + "created"
UpdatedType = eventPrefix + "updated"
DeletedType = eventPrefix + "deleted"
eventPrefix = "schemauser."
CreatedType = eventPrefix + "created"
UpdatedType = eventPrefix + "updated"
DeletedType = eventPrefix + "deleted"
LockedType = eventPrefix + "locked"
UnlockedType = eventPrefix + "unlocked"
DeactivatedType = eventPrefix + "deactivated"
ActivatedType = eventPrefix + "activated"
)
type CreatedEvent struct {
@@ -60,8 +64,6 @@ type UpdatedEvent struct {
SchemaID *string `json:"schemaID,omitempty"`
SchemaRevision *uint64 `json:"schemaRevision,omitempty"`
Data json.RawMessage `json:"schema,omitempty"`
oldSchemaID string
oldRevision uint64
}
func (e *UpdatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
@@ -95,16 +97,14 @@ func NewUpdatedEvent(
type Changes func(event *UpdatedEvent)
func ChangeSchemaID(oldSchemaID, schemaID string) func(event *UpdatedEvent) {
func ChangeSchemaID(schemaID string) func(event *UpdatedEvent) {
return func(e *UpdatedEvent) {
e.SchemaID = &schemaID
e.oldSchemaID = oldSchemaID
}
}
func ChangeSchemaRevision(oldSchemaRevision, schemaRevision uint64) func(event *UpdatedEvent) {
func ChangeSchemaRevision(schemaRevision uint64) func(event *UpdatedEvent) {
return func(e *UpdatedEvent) {
e.SchemaRevision = &schemaRevision
e.oldRevision = oldSchemaRevision
}
}
@@ -142,3 +142,119 @@ func NewDeletedEvent(
),
}
}
type LockedEvent struct {
*eventstore.BaseEvent `json:"-"`
}
func (e *LockedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *LockedEvent) Payload() interface{} {
return e
}
func (e *LockedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
func NewLockedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
) *LockedEvent {
return &LockedEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
LockedType,
),
}
}
type UnlockedEvent struct {
*eventstore.BaseEvent `json:"-"`
}
func (e *UnlockedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *UnlockedEvent) Payload() interface{} {
return e
}
func (e *UnlockedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
func NewUnlockedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
) *UnlockedEvent {
return &UnlockedEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
UnlockedType,
),
}
}
type DeactivatedEvent struct {
*eventstore.BaseEvent `json:"-"`
}
func (e *DeactivatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *DeactivatedEvent) Payload() interface{} {
return e
}
func (e *DeactivatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
func NewDeactivatedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
) *DeactivatedEvent {
return &DeactivatedEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
DeactivatedType,
),
}
}
type ActivatedEvent struct {
*eventstore.BaseEvent `json:"-"`
}
func (e *ActivatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *ActivatedEvent) Payload() interface{} {
return e
}
func (e *ActivatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
func NewActivatedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
) *ActivatedEvent {
return &ActivatedEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
ActivatedType,
),
}
}