package project import ( "context" "encoding/json" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore/repository" ) const ( UniqueProjectnameType = "project_names" projectEventTypePrefix = eventstore.EventType("project.") ProjectAddedType = projectEventTypePrefix + "added" ProjectChangedType = projectEventTypePrefix + "changed" ProjectDeactivatedType = projectEventTypePrefix + "deactivated" ProjectReactivatedType = projectEventTypePrefix + "reactivated" ProjectRemovedType = projectEventTypePrefix + "removed" ) func NewAddProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( UniqueProjectnameType, projectName+resourceOwner, "Errors.Project.AlreadyExists") } func NewRemoveProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( UniqueProjectnameType, projectName+resourceOwner) } type ProjectAddedEvent struct { eventstore.BaseEvent `json:"-"` Name string `json:"name,omitempty"` ProjectRoleAssertion bool `json:"projectRoleAssertion,omitempty"` ProjectRoleCheck bool `json:"projectRoleCheck,omitempty"` HasProjectCheck bool `json:"hasProjectCheck,omitempty"` PrivateLabelingSetting domain.PrivateLabelingSetting `json:"privateLabelingSetting,omitempty"` } func (e *ProjectAddedEvent) Data() interface{} { return e } func (e *ProjectAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { return []*eventstore.EventUniqueConstraint{NewAddProjectNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner)} } func NewProjectAddedEvent( ctx context.Context, aggregate *eventstore.Aggregate, name string, projectRoleAssertion, projectRoleCheck, hasProjectCheck bool, privateLabelingSetting domain.PrivateLabelingSetting, ) *ProjectAddedEvent { return &ProjectAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, ProjectAddedType, ), Name: name, ProjectRoleAssertion: projectRoleAssertion, ProjectRoleCheck: projectRoleCheck, HasProjectCheck: hasProjectCheck, PrivateLabelingSetting: privateLabelingSetting, } } func ProjectAddedEventMapper(event *repository.Event) (eventstore.Event, error) { e := &ProjectAddedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } err := json.Unmarshal(event.Data, e) if err != nil { return nil, errors.ThrowInternal(err, "PROJECT-Bfg2f", "unable to unmarshal project") } return e, nil } type ProjectChangeEvent struct { eventstore.BaseEvent `json:"-"` Name *string `json:"name,omitempty"` ProjectRoleAssertion *bool `json:"projectRoleAssertion,omitempty"` ProjectRoleCheck *bool `json:"projectRoleCheck,omitempty"` HasProjectCheck *bool `json:"hasProjectCheck,omitempty"` PrivateLabelingSetting *domain.PrivateLabelingSetting `json:"privateLabelingSetting,omitempty"` oldName string } func (e *ProjectChangeEvent) Data() interface{} { return e } func (e *ProjectChangeEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { if e.oldName != "" { return []*eventstore.EventUniqueConstraint{ NewRemoveProjectNameUniqueConstraint(e.oldName, e.Aggregate().ResourceOwner), NewAddProjectNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner), } } return nil } func NewProjectChangeEvent( ctx context.Context, aggregate *eventstore.Aggregate, oldName string, changes []ProjectChanges, ) (*ProjectChangeEvent, error) { if len(changes) == 0 { return nil, errors.ThrowPreconditionFailed(nil, "PROJECT-mV9xc", "Errors.NoChangesFound") } changeEvent := &ProjectChangeEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, ProjectChangedType, ), oldName: oldName, } for _, change := range changes { change(changeEvent) } return changeEvent, nil } type ProjectChanges func(event *ProjectChangeEvent) func ChangeName(name string) func(event *ProjectChangeEvent) { return func(e *ProjectChangeEvent) { e.Name = &name } } func ChangeProjectRoleAssertion(projectRoleAssertion bool) func(event *ProjectChangeEvent) { return func(e *ProjectChangeEvent) { e.ProjectRoleAssertion = &projectRoleAssertion } } func ChangeProjectRoleCheck(projectRoleCheck bool) func(event *ProjectChangeEvent) { return func(e *ProjectChangeEvent) { e.ProjectRoleCheck = &projectRoleCheck } } func ChangeHasProjectCheck(ChangeHasProjectCheck bool) func(event *ProjectChangeEvent) { return func(e *ProjectChangeEvent) { e.HasProjectCheck = &ChangeHasProjectCheck } } func ChangePrivateLabelingSetting(ChangePrivateLabelingSetting domain.PrivateLabelingSetting) func(event *ProjectChangeEvent) { return func(e *ProjectChangeEvent) { e.PrivateLabelingSetting = &ChangePrivateLabelingSetting } } func ProjectChangeEventMapper(event *repository.Event) (eventstore.Event, error) { e := &ProjectChangeEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } err := json.Unmarshal(event.Data, e) if err != nil { return nil, errors.ThrowInternal(err, "PROJECT-M9osd", "unable to unmarshal project") } return e, nil } type ProjectDeactivatedEvent struct { eventstore.BaseEvent `json:"-"` } func (e *ProjectDeactivatedEvent) Data() interface{} { return nil } func (e *ProjectDeactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { return nil } func NewProjectDeactivatedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *ProjectDeactivatedEvent { return &ProjectDeactivatedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, ProjectDeactivatedType, ), } } func ProjectDeactivatedEventMapper(event *repository.Event) (eventstore.Event, error) { return &ProjectDeactivatedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), }, nil } type ProjectReactivatedEvent struct { eventstore.BaseEvent `json:"-"` } func (e *ProjectReactivatedEvent) Data() interface{} { return nil } func (e *ProjectReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { return nil } func NewProjectReactivatedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *ProjectReactivatedEvent { return &ProjectReactivatedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, ProjectReactivatedType, ), } } func ProjectReactivatedEventMapper(event *repository.Event) (eventstore.Event, error) { return &ProjectReactivatedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), }, nil } type ProjectRemovedEvent struct { eventstore.BaseEvent `json:"-"` Name string entityIDUniqueContraints []*eventstore.EventUniqueConstraint } func (e *ProjectRemovedEvent) Data() interface{} { return nil } func (e *ProjectRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { constraints := []*eventstore.EventUniqueConstraint{NewRemoveProjectNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner)} if e.entityIDUniqueContraints != nil { for _, constraint := range e.entityIDUniqueContraints { constraints = append(constraints, constraint) } } return constraints } func NewProjectRemovedEvent( ctx context.Context, aggregate *eventstore.Aggregate, name string, entityIDUniqueContraints []*eventstore.EventUniqueConstraint, ) *ProjectRemovedEvent { return &ProjectRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, ProjectRemovedType, ), Name: name, entityIDUniqueContraints: entityIDUniqueContraints, } } func ProjectRemovedEventMapper(event *repository.Event) (eventstore.Event, error) { return &ProjectRemovedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), }, nil }