mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 19:17:32 +00:00
feat(admin-api): list events (#4989)
* docs: update cockroachdb version to 22.2 * feat(adminAPI): ListEventTypes returns the list of event types ZITADEL implements * feat(adminAPI): ListAggregateTypes returns the list of aggregate types ZITADEL implements * feat(adminAPI): ListEvents allows `IAM_OWNERS` to search for events
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -19,6 +20,8 @@ type Eventstore struct {
|
||||
repo repository.Repository
|
||||
interceptorMutex sync.Mutex
|
||||
eventInterceptors map[EventType]eventTypeInterceptors
|
||||
eventTypes []string
|
||||
aggregateTypes []string
|
||||
PushTimeout time.Duration
|
||||
}
|
||||
|
||||
@@ -73,6 +76,14 @@ func (es *Eventstore) NewInstance(ctx context.Context, instanceID string) error
|
||||
return es.repo.CreateInstance(ctx, instanceID)
|
||||
}
|
||||
|
||||
func (es *Eventstore) EventTypes() []string {
|
||||
return es.eventTypes
|
||||
}
|
||||
|
||||
func (es *Eventstore) AggregateTypes() []string {
|
||||
return es.aggregateTypes
|
||||
}
|
||||
|
||||
func commandsToRepository(instanceID string, cmds []Command) (events []*repository.Event, constraints []*repository.UniqueConstraint, err error) {
|
||||
events = make([]*repository.Event, len(cmds))
|
||||
for i, cmd := range cmds {
|
||||
@@ -224,13 +235,16 @@ func (es *Eventstore) FilterToQueryReducer(ctx context.Context, r QueryReducer)
|
||||
}
|
||||
|
||||
// RegisterFilterEventMapper registers a function for mapping an eventstore event to an event
|
||||
func (es *Eventstore) RegisterFilterEventMapper(eventType EventType, mapper func(*repository.Event) (Event, error)) *Eventstore {
|
||||
func (es *Eventstore) RegisterFilterEventMapper(aggregateType AggregateType, eventType EventType, mapper func(*repository.Event) (Event, error)) *Eventstore {
|
||||
if mapper == nil || eventType == "" {
|
||||
return es
|
||||
}
|
||||
es.interceptorMutex.Lock()
|
||||
defer es.interceptorMutex.Unlock()
|
||||
|
||||
es.appendEventType(eventType)
|
||||
es.appendAggregateType(aggregateType)
|
||||
|
||||
interceptor := es.eventInterceptors[eventType]
|
||||
interceptor.eventMapper = mapper
|
||||
es.eventInterceptors[eventType] = interceptor
|
||||
@@ -238,6 +252,22 @@ func (es *Eventstore) RegisterFilterEventMapper(eventType EventType, mapper func
|
||||
return es
|
||||
}
|
||||
|
||||
func (es *Eventstore) appendEventType(typ EventType) {
|
||||
i := sort.SearchStrings(es.eventTypes, string(typ))
|
||||
if i > 0 && es.eventTypes[i-1] == string(typ) {
|
||||
return
|
||||
}
|
||||
es.eventTypes = append(es.eventTypes[:i], append([]string{string(typ)}, es.eventTypes[i:]...)...)
|
||||
}
|
||||
|
||||
func (es *Eventstore) appendAggregateType(typ AggregateType) {
|
||||
i := sort.SearchStrings(es.aggregateTypes, string(typ))
|
||||
if len(es.aggregateTypes) > i && es.aggregateTypes[i] == string(typ) {
|
||||
return
|
||||
}
|
||||
es.aggregateTypes = append(es.aggregateTypes[:i], append([]string{string(typ)}, es.aggregateTypes[i:]...)...)
|
||||
}
|
||||
|
||||
func EventData(event Command) ([]byte, error) {
|
||||
switch data := event.Data().(type) {
|
||||
case nil:
|
||||
|
@@ -156,7 +156,7 @@ func Test_eventstore_RegisterFilterEventMapper(t *testing.T) {
|
||||
es := &Eventstore{
|
||||
eventInterceptors: tt.fields.eventMapper,
|
||||
}
|
||||
es = es.RegisterFilterEventMapper(tt.args.eventType, tt.args.mapper)
|
||||
es = es.RegisterFilterEventMapper("test", tt.args.eventType, tt.args.mapper)
|
||||
if len(es.eventInterceptors) != tt.res.mapperCount {
|
||||
t.Errorf("unexpected mapper count: want %d, got %d", tt.res.mapperCount, len(es.eventInterceptors))
|
||||
return
|
||||
@@ -990,7 +990,7 @@ func TestEventstore_Push(t *testing.T) {
|
||||
eventInterceptors: map[EventType]eventTypeInterceptors{},
|
||||
}
|
||||
for eventType, mapper := range tt.fields.eventMapper {
|
||||
es = es.RegisterFilterEventMapper(eventType, mapper)
|
||||
es = es.RegisterFilterEventMapper("test", eventType, mapper)
|
||||
}
|
||||
if len(es.eventInterceptors) != len(tt.fields.eventMapper) {
|
||||
t.Errorf("register event mapper failed expected mapper amount: %d, got: %d", len(tt.fields.eventMapper), len(es.eventInterceptors))
|
||||
@@ -1130,7 +1130,7 @@ func TestEventstore_FilterEvents(t *testing.T) {
|
||||
}
|
||||
|
||||
for eventType, mapper := range tt.fields.eventMapper {
|
||||
es = es.RegisterFilterEventMapper(eventType, mapper)
|
||||
es = es.RegisterFilterEventMapper("test", eventType, mapper)
|
||||
}
|
||||
if len(es.eventInterceptors) != len(tt.fields.eventMapper) {
|
||||
t.Errorf("register event mapper failed expected mapper amount: %d, got: %d", len(tt.fields.eventMapper), len(es.eventInterceptors))
|
||||
@@ -1448,7 +1448,7 @@ func TestEventstore_FilterToReducer(t *testing.T) {
|
||||
eventInterceptors: map[EventType]eventTypeInterceptors{},
|
||||
}
|
||||
for eventType, mapper := range tt.fields.eventMapper {
|
||||
es = es.RegisterFilterEventMapper(eventType, mapper)
|
||||
es = es.RegisterFilterEventMapper("test", eventType, mapper)
|
||||
}
|
||||
if len(es.eventInterceptors) != len(tt.fields.eventMapper) {
|
||||
t.Errorf("register event mapper failed expected mapper amount: %d, got: %d", len(tt.fields.eventMapper), len(es.eventInterceptors))
|
||||
@@ -1589,7 +1589,7 @@ func TestEventstore_mapEvents(t *testing.T) {
|
||||
eventInterceptors: map[EventType]eventTypeInterceptors{},
|
||||
}
|
||||
for eventType, mapper := range tt.fields.eventMapper {
|
||||
es = es.RegisterFilterEventMapper(eventType, mapper)
|
||||
es = es.RegisterFilterEventMapper("test", eventType, mapper)
|
||||
}
|
||||
if len(es.eventInterceptors) != len(tt.fields.eventMapper) {
|
||||
t.Errorf("register event mapper failed expected mapper amount: %d, got: %d", len(tt.fields.eventMapper), len(es.eventInterceptors))
|
||||
|
@@ -43,8 +43,8 @@ func NewUserAddedEvent(id string, firstName string) *UserAddedEvent {
|
||||
}
|
||||
}
|
||||
|
||||
func UserAddedEventMapper() (eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user.added", func(event *repository.Event) (eventstore.Event, error) {
|
||||
func UserAddedEventMapper() (eventstore.AggregateType, eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user", "user.added", func(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &UserAddedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
@@ -88,8 +88,8 @@ func NewUserFirstNameChangedEvent(id, firstName string) *UserFirstNameChangedEve
|
||||
}
|
||||
}
|
||||
|
||||
func UserFirstNameChangedMapper() (eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user.firstName.changed", func(event *repository.Event) (eventstore.Event, error) {
|
||||
func UserFirstNameChangedMapper() (eventstore.AggregateType, eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user", "user.firstName.changed", func(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &UserFirstNameChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
@@ -130,8 +130,8 @@ func NewUserPasswordCheckedEvent(id string) *UserPasswordCheckedEvent {
|
||||
}
|
||||
}
|
||||
|
||||
func UserPasswordCheckedMapper() (eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user.password.checked", func(event *repository.Event) (eventstore.Event, error) {
|
||||
func UserPasswordCheckedMapper() (eventstore.AggregateType, eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user", "user.password.checked", func(event *repository.Event) (eventstore.Event, error) {
|
||||
return &UserPasswordCheckedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}, nil
|
||||
@@ -167,8 +167,8 @@ func NewUserDeletedEvent(id string) *UserDeletedEvent {
|
||||
}
|
||||
}
|
||||
|
||||
func UserDeletedMapper() (eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user.deleted", func(event *repository.Event) (eventstore.Event, error) {
|
||||
func UserDeletedMapper() (eventstore.AggregateType, eventstore.EventType, func(*repository.Event) (eventstore.Event, error)) {
|
||||
return "user", "user.deleted", func(event *repository.Event) (eventstore.Event, error) {
|
||||
return &UserDeletedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}, nil
|
||||
|
@@ -17,6 +17,7 @@ type SearchQueryBuilder struct {
|
||||
desc bool
|
||||
resourceOwner string
|
||||
instanceID string
|
||||
editorUser string
|
||||
queries []*SearchQuery
|
||||
tx *sql.Tx
|
||||
}
|
||||
@@ -124,6 +125,11 @@ func (builder *SearchQueryBuilder) SetTx(tx *sql.Tx) *SearchQueryBuilder {
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder *SearchQueryBuilder) EditorUser(id string) *SearchQueryBuilder {
|
||||
builder.editorUser = id
|
||||
return builder
|
||||
}
|
||||
|
||||
// AddQuery creates a new sub query.
|
||||
// All fields in the sub query are AND-connected in the storage request.
|
||||
// Multiple sub queries are OR-connected in the storage request.
|
||||
@@ -245,6 +251,7 @@ func (builder *SearchQueryBuilder) build(instanceID string) (*repository.SearchQ
|
||||
query.creationDateAfterFilter,
|
||||
query.builder.resourceOwnerFilter,
|
||||
query.builder.instanceIDFilter,
|
||||
query.builder.editorUserFilter,
|
||||
} {
|
||||
if filter := f(); filter != nil {
|
||||
if err := filter.Validate(); err != nil {
|
||||
@@ -353,6 +360,13 @@ func (builder *SearchQueryBuilder) instanceIDFilter() *repository.Filter {
|
||||
return repository.NewFilter(repository.FieldInstanceID, builder.instanceID, repository.OperationEquals)
|
||||
}
|
||||
|
||||
func (builder *SearchQueryBuilder) editorUserFilter() *repository.Filter {
|
||||
if builder.editorUser == "" {
|
||||
return nil
|
||||
}
|
||||
return repository.NewFilter(repository.FieldEditorUser, builder.editorUser, repository.OperationEquals)
|
||||
}
|
||||
|
||||
func (query *SearchQuery) creationDateAfterFilter() *repository.Filter {
|
||||
if query.creationDateAfter.IsZero() {
|
||||
return nil
|
||||
|
Reference in New Issue
Block a user