package projection import ( "context" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" "github.com/zitadel/zitadel/internal/eventstore/handler/crdb" "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/session" ) const ( SessionsProjectionTable = "projections.sessions" SessionColumnID = "id" SessionColumnCreationDate = "creation_date" SessionColumnChangeDate = "change_date" SessionColumnSequence = "sequence" SessionColumnState = "state" SessionColumnResourceOwner = "resource_owner" SessionColumnInstanceID = "instance_id" SessionColumnCreator = "creator" SessionColumnUserID = "user_id" SessionColumnUserCheckedAt = "user_checked_at" SessionColumnPasswordCheckedAt = "password_checked_at" SessionColumnMetadata = "metadata" SessionColumnTokenID = "token_id" ) type sessionProjection struct { crdb.StatementHandler } func newSessionProjection(ctx context.Context, config crdb.StatementHandlerConfig) *sessionProjection { p := new(sessionProjection) config.ProjectionName = SessionsProjectionTable config.Reducers = p.reducers() config.InitCheck = crdb.NewMultiTableCheck( crdb.NewTable([]*crdb.Column{ crdb.NewColumn(SessionColumnID, crdb.ColumnTypeText), crdb.NewColumn(SessionColumnCreationDate, crdb.ColumnTypeTimestamp), crdb.NewColumn(SessionColumnChangeDate, crdb.ColumnTypeTimestamp), crdb.NewColumn(SessionColumnSequence, crdb.ColumnTypeInt64), crdb.NewColumn(SessionColumnState, crdb.ColumnTypeEnum), crdb.NewColumn(SessionColumnResourceOwner, crdb.ColumnTypeText), crdb.NewColumn(SessionColumnInstanceID, crdb.ColumnTypeText), crdb.NewColumn(SessionColumnCreator, crdb.ColumnTypeText), crdb.NewColumn(SessionColumnUserID, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(SessionColumnUserCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), crdb.NewColumn(SessionColumnPasswordCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), crdb.NewColumn(SessionColumnMetadata, crdb.ColumnTypeJSONB, crdb.Nullable()), crdb.NewColumn(SessionColumnTokenID, crdb.ColumnTypeText, crdb.Nullable()), }, crdb.NewPrimaryKey(SessionColumnInstanceID, SessionColumnID), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) return p } func (p *sessionProjection) reducers() []handler.AggregateReducer { return []handler.AggregateReducer{ { Aggregate: session.AggregateType, EventRedusers: []handler.EventReducer{ { Event: session.AddedType, Reduce: p.reduceSessionAdded, }, { Event: session.UserCheckedType, Reduce: p.reduceUserChecked, }, { Event: session.PasswordCheckedType, Reduce: p.reducePasswordChecked, }, { Event: session.TokenSetType, Reduce: p.reduceTokenSet, }, { Event: session.MetadataSetType, Reduce: p.reduceMetadataSet, }, { Event: session.TerminateType, Reduce: p.reduceSessionTerminated, }, }, }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ { Event: instance.InstanceRemovedEventType, Reduce: reduceInstanceRemovedHelper(SMSColumnInstanceID), }, }, }, } } func (p *sessionProjection) reduceSessionAdded(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*session.AddedEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Sfrgf", "reduce.wrong.event.type %s", session.AddedType) } return crdb.NewCreateStatement( e, []handler.Column{ handler.NewCol(SessionColumnID, e.Aggregate().ID), handler.NewCol(SessionColumnInstanceID, e.Aggregate().InstanceID), handler.NewCol(SessionColumnCreationDate, e.CreationDate()), handler.NewCol(SessionColumnChangeDate, e.CreationDate()), handler.NewCol(SessionColumnResourceOwner, e.Aggregate().ResourceOwner), handler.NewCol(SessionColumnState, domain.SessionStateActive), handler.NewCol(SessionColumnSequence, e.Sequence()), handler.NewCol(SessionColumnCreator, e.User), }, ), nil } func (p *sessionProjection) reduceUserChecked(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*session.UserCheckedEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-saDg5", "reduce.wrong.event.type %s", session.UserCheckedType) } return crdb.NewUpdateStatement( e, []handler.Column{ handler.NewCol(SessionColumnChangeDate, e.CreationDate()), handler.NewCol(SessionColumnSequence, e.Sequence()), handler.NewCol(SessionColumnUserID, e.UserID), handler.NewCol(SessionColumnUserCheckedAt, e.CheckedAt), }, []handler.Condition{ handler.NewCond(SessionColumnID, e.Aggregate().ID), handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID), }, ), nil } func (p *sessionProjection) reducePasswordChecked(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*session.PasswordCheckedEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-SDgrb", "reduce.wrong.event.type %s", session.PasswordCheckedType) } return crdb.NewUpdateStatement( e, []handler.Column{ handler.NewCol(SessionColumnChangeDate, e.CreationDate()), handler.NewCol(SessionColumnSequence, e.Sequence()), handler.NewCol(SessionColumnPasswordCheckedAt, e.CheckedAt), }, []handler.Condition{ handler.NewCond(SessionColumnID, e.Aggregate().ID), handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID), }, ), nil } func (p *sessionProjection) reduceTokenSet(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*session.TokenSetEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-SAfd3", "reduce.wrong.event.type %s", session.TokenSetType) } return crdb.NewUpdateStatement( e, []handler.Column{ handler.NewCol(SessionColumnChangeDate, e.CreationDate()), handler.NewCol(SessionColumnSequence, e.Sequence()), handler.NewCol(SessionColumnTokenID, e.TokenID), }, []handler.Condition{ handler.NewCond(SessionColumnID, e.Aggregate().ID), handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID), }, ), nil } func (p *sessionProjection) reduceMetadataSet(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*session.MetadataSetEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-SAfd3", "reduce.wrong.event.type %s", session.MetadataSetType) } return crdb.NewUpdateStatement( e, []handler.Column{ handler.NewCol(SessionColumnChangeDate, e.CreationDate()), handler.NewCol(SessionColumnSequence, e.Sequence()), handler.NewCol(SessionColumnMetadata, e.Metadata), }, []handler.Condition{ handler.NewCond(SessionColumnID, e.Aggregate().ID), handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID), }, ), nil } func (p *sessionProjection) reduceSessionTerminated(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*session.TerminateEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-SAftn", "reduce.wrong.event.type %s", session.TerminateType) } return crdb.NewDeleteStatement( e, []handler.Condition{ handler.NewCond(SessionColumnID, e.Aggregate().ID), handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID), }, ), nil }