mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 03:17:33 +00:00
fix(projections): user idp link projection (#2583)
* fix(projections): add app * fix(migration): add index for project_id * test: app projection * fix(projections): add idp_user_link * test: idp user link * fix: migration versions * refactor: rename externalIDP to UserIDPLink * fix: interface methods
This commit is contained in:
@@ -64,15 +64,15 @@ func assertReduce(t *testing.T, stmt *handler.Statement, err error, want wantRed
|
||||
return
|
||||
}
|
||||
if stmt.AggregateType != want.aggregateType {
|
||||
t.Errorf("wront aggregate type: want: %q got: %q", want.aggregateType, stmt.AggregateType)
|
||||
t.Errorf("wrong aggregate type: want: %q got: %q", want.aggregateType, stmt.AggregateType)
|
||||
}
|
||||
|
||||
if stmt.PreviousSequence != want.previousSequence {
|
||||
t.Errorf("wront previous sequence: want: %d got: %d", want.previousSequence, stmt.PreviousSequence)
|
||||
t.Errorf("wrong previous sequence: want: %d got: %d", want.previousSequence, stmt.PreviousSequence)
|
||||
}
|
||||
|
||||
if stmt.Sequence != want.sequence {
|
||||
t.Errorf("wront sequence: want: %d got: %d", want.sequence, stmt.Sequence)
|
||||
t.Errorf("wrong sequence: want: %d got: %d", want.sequence, stmt.Sequence)
|
||||
}
|
||||
if stmt.Execute == nil {
|
||||
want.executer.Validate(t)
|
||||
|
111
internal/query/projection/idp_user_link.go
Normal file
111
internal/query/projection/idp_user_link.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package projection
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/handler"
|
||||
"github.com/caos/zitadel/internal/eventstore/handler/crdb"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
)
|
||||
|
||||
type IDPUserLinkProjection struct {
|
||||
crdb.StatementHandler
|
||||
}
|
||||
|
||||
const (
|
||||
IDPUserLinkTable = "zitadel.projections.idp_user_links"
|
||||
)
|
||||
|
||||
func NewIDPUserLinkProjection(ctx context.Context, config crdb.StatementHandlerConfig) *IDPUserLinkProjection {
|
||||
p := &IDPUserLinkProjection{}
|
||||
config.ProjectionName = IDPUserLinkTable
|
||||
config.Reducers = p.reducers()
|
||||
p.StatementHandler = crdb.NewStatementHandler(ctx, config)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *IDPUserLinkProjection) reducers() []handler.AggregateReducer {
|
||||
return []handler.AggregateReducer{
|
||||
{
|
||||
Aggregate: user.AggregateType,
|
||||
EventRedusers: []handler.EventReducer{
|
||||
{
|
||||
Event: user.UserIDPLinkAddedType,
|
||||
Reduce: p.reduceAdded,
|
||||
},
|
||||
{
|
||||
Event: user.UserIDPLinkCascadeRemovedType,
|
||||
Reduce: p.reduceCascadeRemoved,
|
||||
},
|
||||
{
|
||||
Event: user.UserIDPLinkRemovedType,
|
||||
Reduce: p.reduceRemoved,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
IDPUserLinkIDPIDCol = "idp_id"
|
||||
IDPUserLinkUserIDCol = "user_id"
|
||||
IDPUserLinkExternalUserIDCol = "external_user_id"
|
||||
IDPUserLinkCreationDateCol = "creation_date"
|
||||
IDPUserLinkChangeDateCol = "change_date"
|
||||
IDPUserLinkSequenceCol = "sequence"
|
||||
IDPUserLinkResourceOwnerCol = "resource_owner"
|
||||
IDPUserLinkDisplayNameCol = "display_name"
|
||||
)
|
||||
|
||||
func (p *IDPUserLinkProjection) reduceAdded(event eventstore.EventReader) (*handler.Statement, error) {
|
||||
e, ok := event.(*user.UserIDPLinkAddedEvent)
|
||||
if !ok {
|
||||
logging.LogWithFields("HANDL-v2qC3", "seq", event.Sequence(), "expectedType", user.UserIDPLinkAddedType).Error("wrong event type")
|
||||
return nil, errors.ThrowInvalidArgument(nil, "HANDL-DpmXq", "reduce.wrong.event.type")
|
||||
}
|
||||
return crdb.NewCreateStatement(e,
|
||||
[]handler.Column{
|
||||
handler.NewCol(IDPUserLinkIDPIDCol, e.IDPConfigID),
|
||||
handler.NewCol(IDPUserLinkUserIDCol, e.Aggregate().ID),
|
||||
handler.NewCol(IDPUserLinkExternalUserIDCol, e.ExternalUserID),
|
||||
handler.NewCol(IDPUserLinkCreationDateCol, e.CreationDate()),
|
||||
handler.NewCol(IDPUserLinkChangeDateCol, e.CreationDate()),
|
||||
handler.NewCol(IDPUserLinkSequenceCol, e.Sequence()),
|
||||
handler.NewCol(IDPUserLinkResourceOwnerCol, e.Aggregate().ResourceOwner),
|
||||
handler.NewCol(IDPUserLinkDisplayNameCol, e.DisplayName),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *IDPUserLinkProjection) reduceRemoved(event eventstore.EventReader) (*handler.Statement, error) {
|
||||
e, ok := event.(*user.UserIDPLinkRemovedEvent)
|
||||
if !ok {
|
||||
logging.LogWithFields("HANDL-zX5m9", "seq", event.Sequence(), "expectedType", user.UserIDPLinkRemovedType).Error("wrong event type")
|
||||
return nil, errors.ThrowInvalidArgument(nil, "HANDL-AZmfJ", "reduce.wrong.event.type")
|
||||
}
|
||||
return crdb.NewDeleteStatement(e,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(IDPUserLinkIDPIDCol, e.IDPConfigID),
|
||||
handler.NewCond(IDPUserLinkUserIDCol, e.Aggregate().ID),
|
||||
handler.NewCond(IDPUserLinkExternalUserIDCol, e.ExternalUserID),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *IDPUserLinkProjection) reduceCascadeRemoved(event eventstore.EventReader) (*handler.Statement, error) {
|
||||
e, ok := event.(*user.UserIDPLinkCascadeRemovedEvent)
|
||||
if !ok {
|
||||
logging.LogWithFields("HANDL-I0s2H", "seq", event.Sequence(), "expectedType", user.UserIDPLinkCascadeRemovedType).Error("wrong event type")
|
||||
return nil, errors.ThrowInvalidArgument(nil, "HANDL-jQpv9", "reduce.wrong.event.type")
|
||||
}
|
||||
return crdb.NewDeleteStatement(e,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(IDPUserLinkIDPIDCol, e.IDPConfigID),
|
||||
handler.NewCond(IDPUserLinkUserIDCol, e.Aggregate().ID),
|
||||
handler.NewCond(IDPUserLinkExternalUserIDCol, e.ExternalUserID),
|
||||
},
|
||||
), nil
|
||||
}
|
139
internal/query/projection/idp_user_link_test.go
Normal file
139
internal/query/projection/idp_user_link_test.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package projection
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/handler"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
)
|
||||
|
||||
func TestIDPUserLinkProjection_reduces(t *testing.T) {
|
||||
type args struct {
|
||||
event func(t *testing.T) eventstore.EventReader
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
reduce func(event eventstore.EventReader) (*handler.Statement, error)
|
||||
want wantReduce
|
||||
}{
|
||||
{
|
||||
name: "reduceAdded",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(user.UserIDPLinkAddedType),
|
||||
user.AggregateType,
|
||||
[]byte(`{
|
||||
"idpConfigId": "idp-config-id",
|
||||
"userId": "external-user-id",
|
||||
"displayName": "gigi@caos.ch"
|
||||
}`),
|
||||
), user.UserIDPLinkAddedEventMapper),
|
||||
},
|
||||
reduce: (&IDPUserLinkProjection{}).reduceAdded,
|
||||
want: wantReduce{
|
||||
aggregateType: user.AggregateType,
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
projection: IDPUserLinkTable,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO zitadel.projections.idp_user_links (idp_id, user_id, external_user_id, creation_date, change_date, sequence, resource_owner, display_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-config-id",
|
||||
"agg-id",
|
||||
"external-user-id",
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"ro-id",
|
||||
"gigi@caos.ch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceRemoved",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(user.UserIDPLinkRemovedType),
|
||||
user.AggregateType,
|
||||
[]byte(`{
|
||||
"idpConfigId": "idp-config-id",
|
||||
"userId": "external-user-id"
|
||||
}`),
|
||||
), user.UserIDPLinkRemovedEventMapper),
|
||||
},
|
||||
reduce: (&IDPUserLinkProjection{}).reduceRemoved,
|
||||
want: wantReduce{
|
||||
aggregateType: user.AggregateType,
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
projection: IDPUserLinkTable,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM zitadel.projections.idp_user_links WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-config-id",
|
||||
"agg-id",
|
||||
"external-user-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceCascadeRemoved",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(user.UserIDPLinkCascadeRemovedType),
|
||||
user.AggregateType,
|
||||
[]byte(`{
|
||||
"idpConfigId": "idp-config-id",
|
||||
"userId": "external-user-id"
|
||||
}`),
|
||||
), user.UserIDPLinkCascadeRemovedEventMapper),
|
||||
},
|
||||
reduce: (&IDPUserLinkProjection{}).reduceCascadeRemoved,
|
||||
want: wantReduce{
|
||||
aggregateType: user.AggregateType,
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
projection: IDPUserLinkTable,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM zitadel.projections.idp_user_links WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-config-id",
|
||||
"agg-id",
|
||||
"external-user-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := baseEvent(t)
|
||||
got, err := tt.reduce(event)
|
||||
if _, ok := err.(errors.InvalidArgument); !ok {
|
||||
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
|
||||
}
|
||||
|
||||
event = tt.args.event(t)
|
||||
got, err = tt.reduce(event)
|
||||
assertReduce(t, got, err, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
@@ -49,6 +49,7 @@ func Start(ctx context.Context, sqlClient *sql.DB, es *eventstore.Eventstore, co
|
||||
NewLoginPolicyProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["login_policies"]))
|
||||
NewIDPProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idps"]))
|
||||
NewAppProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["apps"]))
|
||||
NewIDPUserLinkProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_user_links"]))
|
||||
NewMailTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["mail_templates"]))
|
||||
NewMessageTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["message_texts"]))
|
||||
NewCustomTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["custom_texts"]))
|
||||
|
Reference in New Issue
Block a user