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

@@ -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,
),
}
}