feat(notification): state the email provider on the sent events

The sent events of email notifications state the ID of the email
provider the notification was sent through. Together with the flag for
suppressed deliveries it is passed as senders.DeliveryInfo instead of a
positional bool, from the send through the sent commands to the events.

A delivered email states the provider, a suppressed one only the flag.
Events which had no payload before only carry one if either is set.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Livio SpringandClaude Fable 5.1 committed 2026-10-05 11:03:06 +02:00
1 parent d9bf2008cd
commit 46ceca6080
37 files changed
+359 -306

No files matched your search

+2 -2
View File
@@ -99,7 +99,7 @@ func (c *Commands) createOTPEmailChallenge(returnCode bool, urlTmpl string, dst
}
}
func (c *Commands) OTPEmailSent(ctx context.Context, sessionID, resourceOwner string, deliverySuppressed bool) error {
func (c *Commands) OTPEmailSent(ctx context.Context, sessionID, resourceOwner string, deliveryInfo senders.DeliveryInfo) error {
sessionWriteModel := NewSessionWriteModel(sessionID, resourceOwner)
err := c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel)
if err != nil {
@@ -109,7 +109,7 @@ func (c *Commands) OTPEmailSent(ctx context.Context, sessionID, resourceOwner st
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-SLr02", "Errors.User.Code.NotFound")
}
return c.pushAppendAndReduce(ctx, sessionWriteModel,
session.NewOTPEmailSentEvent(ctx, &session.NewAggregate(sessionID, sessionWriteModel.ResourceOwner).Aggregate, deliverySuppressed),
session.NewOTPEmailSentEvent(ctx, &session.NewAggregate(sessionID, sessionWriteModel.ResourceOwner).Aggregate, deliveryInfo),
)
}
+11 -11
View File
@@ -691,10 +691,10 @@ func TestCommands_OTPEmailSent(t *testing.T) {
eventstore func(*testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
sessionID string
resourceOwner string
deliverySuppressed bool
ctx context.Context
sessionID string
resourceOwner string
deliveryInfo senders.DeliveryInfo
}
tests := []struct {
name string
@@ -736,7 +736,7 @@ func TestCommands_OTPEmailSent(t *testing.T) {
),
),
expectPush(
session.NewOTPEmailSentEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, false),
session.NewOTPEmailSentEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, senders.DeliveryInfo{}),
),
),
},
@@ -767,15 +767,15 @@ func TestCommands_OTPEmailSent(t *testing.T) {
),
),
expectPush(
session.NewOTPEmailSentEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, true),
session.NewOTPEmailSentEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, senders.DeliveryInfo{DeliverySuppressed: true}),
),
),
},
args: args{
ctx: context.Background(),
sessionID: "sessionID",
resourceOwner: "instanceID",
deliverySuppressed: true,
ctx: context.Background(),
sessionID: "sessionID",
resourceOwner: "instanceID",
deliveryInfo: senders.DeliveryInfo{DeliverySuppressed: true},
},
wantErr: nil,
},
@@ -785,7 +785,7 @@ func TestCommands_OTPEmailSent(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
}
err := c.OTPEmailSent(tt.args.ctx, tt.args.sessionID, tt.args.resourceOwner, tt.args.deliverySuppressed)
err := c.OTPEmailSent(tt.args.ctx, tt.args.sessionID, tt.args.resourceOwner, tt.args.deliveryInfo)
assert.ErrorIs(t, err, tt.wantErr)
})
}
+3 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -353,7 +354,7 @@ func (c *Commands) prepareUserDomainClaimed(ctx context.Context, filter preparat
), nil
}
func (c *Commands) UserDomainClaimedSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) (err error) {
func (c *Commands) UserDomainClaimedSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) (err error) {
if userID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-5m0fs", "Errors.IDMissing")
}
@@ -366,7 +367,7 @@ func (c *Commands) UserDomainClaimedSent(ctx context.Context, orgID, userID stri
}
_, err = c.eventstore.Push(ctx,
user.NewDomainClaimedSentEvent(ctx, UserAggregateFromWriteModelCtx(ctx, &existingUser.WriteModel), deliverySuppressed))
user.NewDomainClaimedSentEvent(ctx, UserAggregateFromWriteModelCtx(ctx, &existingUser.WriteModel), deliveryInfo))
return err
}
+3 -2
View File
@@ -8,6 +8,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -145,7 +146,7 @@ func (c *Commands) CreateHumanEmailVerificationCode(ctx context.Context, userID,
return writeModelToObjectDetails(&existingEmail.WriteModel), nil
}
func (c *Commands) HumanEmailVerificationCodeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) (err error) {
func (c *Commands) HumanEmailVerificationCodeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) (err error) {
if userID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9fs", "Errors.IDMissing")
}
@@ -157,7 +158,7 @@ func (c *Commands) HumanEmailVerificationCodeSent(ctx context.Context, orgID, us
return zerrors.ThrowNotFound(nil, "COMMAND-6n8uH", "Errors.User.Email.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingEmail.WriteModel)
_, err = c.eventstore.Push(ctx, user.NewHumanEmailCodeSentEvent(ctx, userAgg, deliverySuppressed))
_, err = c.eventstore.Push(ctx, user.NewHumanEmailCodeSentEvent(ctx, userAgg, deliveryInfo))
return err
}
+3 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/org"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -1277,7 +1278,7 @@ func TestCommandSide_EmailVerificationCodeSent(t *testing.T) {
expectPush(
user.NewHumanEmailCodeSentEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
false,
senders.DeliveryInfo{},
),
),
),
@@ -1295,7 +1296,7 @@ func TestCommandSide_EmailVerificationCodeSent(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
}
err := r.HumanEmailVerificationCodeSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, false)
err := r.HumanEmailVerificationCodeSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, senders.DeliveryInfo{})
if tt.res.err == nil {
assert.NoError(t, err)
}
+3 -2
View File
@@ -8,6 +8,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -93,7 +94,7 @@ func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwne
return err
}
func (c *Commands) HumanInitCodeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) (err error) {
func (c *Commands) HumanInitCodeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) (err error) {
if userID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-3M9fs", "Errors.IDMissing")
}
@@ -105,7 +106,7 @@ func (c *Commands) HumanInitCodeSent(ctx context.Context, orgID, userID string,
return zerrors.ThrowNotFound(nil, "COMMAND-556zg", "Errors.User.Code.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingInitCode.WriteModel)
_, err = c.eventstore.Push(ctx, user.NewHumanInitialCodeSentEvent(ctx, userAgg, deliverySuppressed))
_, err = c.eventstore.Push(ctx, user.NewHumanInitialCodeSentEvent(ctx, userAgg, deliveryInfo))
return err
}
+3 -2
View File
@@ -11,6 +11,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/org"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -849,7 +850,7 @@ func TestCommandSide_InitCodeSent(t *testing.T) {
expectPush(
user.NewHumanInitialCodeSentEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
false,
senders.DeliveryInfo{},
),
),
),
@@ -867,7 +868,7 @@ func TestCommandSide_InitCodeSent(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
}
err := r.HumanInitCodeSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, false)
err := r.HumanInitCodeSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, senders.DeliveryInfo{})
if tt.res.err == nil {
assert.NoError(t, err)
}
+2 -2
View File
@@ -492,12 +492,12 @@ func (c *Commands) HumanSendOTPEmail(ctx context.Context, userID, resourceOwner
)
}
func (c *Commands) HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string, deliverySuppressed bool) (err error) {
func (c *Commands) HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string, deliveryInfo senders.DeliveryInfo) (err error) {
smsWriteModel := func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error) {
return c.otpEmailWriteModelByID(ctx, userID, resourceOwner)
}
codeSentEvent := func(ctx context.Context, aggregate *eventstore.Aggregate) eventstore.Command {
return user.NewHumanOTPEmailCodeSentEvent(ctx, aggregate, deliverySuppressed)
return user.NewHumanOTPEmailCodeSentEvent(ctx, aggregate, deliveryInfo)
}
return c.humanOTPSent(ctx, userID, resourceOwner, smsWriteModel, codeSentEvent)
}
+2 -2
View File
@@ -3095,7 +3095,7 @@ func TestCommandSide_HumanOTPEmailCodeSent(t *testing.T) {
expectPush(
user.NewHumanOTPEmailCodeSentEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
false,
senders.DeliveryInfo{},
),
),
),
@@ -3117,7 +3117,7 @@ func TestCommandSide_HumanOTPEmailCodeSent(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
}
err := r.HumanOTPEmailCodeSent(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, false)
err := r.HumanOTPEmailCodeSent(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, senders.DeliveryInfo{})
assert.ErrorIs(t, err, tt.res.err)
})
}
+4 -4
View File
@@ -321,7 +321,7 @@ func (c *Commands) RequestSetPassword(ctx context.Context, userID, resourceOwner
}
// PasswordCodeSent notification send with code to change password
func (c *Commands) PasswordCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool) (err error) {
func (c *Commands) PasswordCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo) (err error) {
if userID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-meEfe", "Errors.User.UserIDMissing")
}
@@ -334,12 +334,12 @@ func (c *Commands) PasswordCodeSent(ctx context.Context, orgID, userID string, g
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-3n77z", "Errors.User.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingPassword.WriteModel)
_, err = c.eventstore.Push(ctx, user.NewHumanPasswordCodeSentEvent(ctx, userAgg, generatorInfo, deliverySuppressed))
_, err = c.eventstore.Push(ctx, user.NewHumanPasswordCodeSentEvent(ctx, userAgg, generatorInfo, deliveryInfo))
return err
}
// PasswordChangeSent notification sent that user changed password
func (c *Commands) PasswordChangeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) (err error) {
func (c *Commands) PasswordChangeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) (err error) {
if userID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-pqlm2n", "Errors.User.UserIDMissing")
}
@@ -352,7 +352,7 @@ func (c *Commands) PasswordChangeSent(ctx context.Context, orgID, userID string,
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-x902b2v", "Errors.User.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingPassword.WriteModel)
_, err = c.eventstore.Push(ctx, user.NewHumanPasswordChangeSentEvent(ctx, userAgg, deliverySuppressed))
_, err = c.eventstore.Push(ctx, user.NewHumanPasswordChangeSentEvent(ctx, userAgg, deliveryInfo))
return err
}
+4 -4
View File
@@ -689,7 +689,7 @@ func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) {
ID: "id",
VerificationID: "verificationID",
},
false,
senders.DeliveryInfo{},
),
),
),
@@ -1621,7 +1621,7 @@ func TestCommandSide_PasswordCodeSent(t *testing.T) {
user.NewHumanPasswordCodeSentEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
&senders.CodeGeneratorInfo{},
false,
senders.DeliveryInfo{},
),
),
),
@@ -1667,7 +1667,7 @@ func TestCommandSide_PasswordCodeSent(t *testing.T) {
ID: "generatorID",
VerificationID: "verificationID",
},
false,
senders.DeliveryInfo{},
),
),
),
@@ -1689,7 +1689,7 @@ func TestCommandSide_PasswordCodeSent(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
}
err := r.PasswordCodeSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.generatorInfo, false)
err := r.PasswordCodeSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.generatorInfo, senders.DeliveryInfo{})
if tt.res.err == nil {
assert.NoError(t, err)
}
+3 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
"github.com/zitadel/zitadel/internal/notification/senders"
usr_repo "github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -576,7 +577,7 @@ func (c *Commands) humanAddPasswordlessInitCode(ctx context.Context, userID, res
return codeEvent, initCode, code, nil
}
func (c *Commands) HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string, deliverySuppressed bool) error {
func (c *Commands) HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string, deliveryInfo senders.DeliveryInfo) error {
if userID == "" || codeID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-ADggh", "Errors.IDMissing")
}
@@ -591,7 +592,7 @@ func (c *Commands) HumanPasswordlessInitCodeSent(ctx context.Context, userID, re
}
_, err = c.eventstore.Push(ctx,
usr_repo.NewHumanPasswordlessInitCodeSentEvent(ctx, UserAggregateFromWriteModelCtx(ctx, &initCode.WriteModel), codeID, deliverySuppressed),
usr_repo.NewHumanPasswordlessInitCodeSentEvent(ctx, UserAggregateFromWriteModelCtx(ctx, &initCode.WriteModel), codeID, deliveryInfo),
)
return err
}
+5 -4
View File
@@ -13,6 +13,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -67,7 +68,7 @@ func TestCommands_humanVerifyPasswordlessInitCode(t *testing.T) {
),
),
eventFromEventPusherWithCreationDateNow(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
),
),
expectPush(
@@ -94,7 +95,7 @@ func TestCommands_humanVerifyPasswordlessInitCode(t *testing.T) {
),
),
eventFromEventPusherWithCreationDateNow(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
),
),
),
@@ -118,7 +119,7 @@ func TestCommands_humanVerifyPasswordlessInitCode(t *testing.T) {
time.Now().Add(-2*time.Minute),
),
eventFromEventPusherWithCreationDate(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
time.Now().Add(-2*time.Minute),
),
),
@@ -148,7 +149,7 @@ func TestCommands_humanVerifyPasswordlessInitCode(t *testing.T) {
time.Now().Add(-2*time.Minute),
),
eventFromEventPusherWithCreationDate(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
time.Now().Add(-2*time.Minute),
),
eventFromEventPusherWithCreationDateNow(
+3 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/group"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/org"
@@ -1854,7 +1855,7 @@ func TestCommandSide_UserDomainClaimedSent(t *testing.T) {
expectPush(
user.NewDomainClaimedSentEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
false,
senders.DeliveryInfo{},
),
),
),
@@ -1872,7 +1873,7 @@ func TestCommandSide_UserDomainClaimedSent(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
}
err := r.UserDomainClaimedSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, false)
err := r.UserDomainClaimedSent(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, senders.DeliveryInfo{})
if tt.res.err == nil {
assert.NoError(t, err)
}
+3 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -97,7 +98,7 @@ func (c *Commands) sendInviteCode(ctx context.Context, invite *CreateUserInvite,
return writeModelToObjectDetails(&wm.WriteModel), returnCode, nil
}
func (c *Commands) InviteCodeSent(ctx context.Context, userID, orgID string, deliverySuppressed bool) (err error) {
func (c *Commands) InviteCodeSent(ctx context.Context, userID, orgID string, deliveryInfo senders.DeliveryInfo) (err error) {
if userID == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Sgf31", "Errors.User.UserIDMissing")
}
@@ -112,7 +113,7 @@ func (c *Commands) InviteCodeSent(ctx context.Context, userID, orgID string, del
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-Wr3gq", "Errors.User.Code.NotFound")
}
userAgg := UserAggregateFromWriteModelCtx(ctx, &existingCode.WriteModel)
_, err = c.eventstore.Push(ctx, user.NewHumanInviteCodeSentEvent(ctx, userAgg, deliverySuppressed))
_, err = c.eventstore.Push(ctx, user.NewHumanInviteCodeSentEvent(ctx, userAgg, deliveryInfo))
return err
}
+11 -10
View File
@@ -15,6 +15,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/org"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -1262,10 +1263,10 @@ func TestCommands_InviteCodeSent(t *testing.T) {
eventstore func(*testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
orgID string
deliverySuppressed bool
ctx context.Context
userID string
orgID string
deliveryInfo senders.DeliveryInfo
}
tests := []struct {
name string
@@ -1363,7 +1364,7 @@ func TestCommands_InviteCodeSent(t *testing.T) {
eventFromEventPusher(
user.NewHumanInviteCodeSentEvent(context.Background(),
&user.NewAggregate("userID", "org1").Aggregate,
false,
senders.DeliveryInfo{},
),
),
),
@@ -1414,16 +1415,16 @@ func TestCommands_InviteCodeSent(t *testing.T) {
eventFromEventPusher(
user.NewHumanInviteCodeSentEvent(context.Background(),
&user.NewAggregate("userID", "org1").Aggregate,
true,
senders.DeliveryInfo{DeliverySuppressed: true},
),
),
),
),
},
args{
ctx: context.Background(),
userID: "userID",
deliverySuppressed: true,
ctx: context.Background(),
userID: "userID",
deliveryInfo: senders.DeliveryInfo{DeliverySuppressed: true},
},
nil,
},
@@ -1434,7 +1435,7 @@ func TestCommands_InviteCodeSent(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
}
err := c.InviteCodeSent(tt.args.ctx, tt.args.userID, tt.args.orgID, tt.args.deliverySuppressed)
err := c.InviteCodeSent(tt.args.ctx, tt.args.userID, tt.args.orgID, tt.args.deliveryInfo)
assert.ErrorIs(t, err, tt.wantErr)
})
}
+7 -6
View File
@@ -18,6 +18,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/id"
id_mock "github.com/zitadel/zitadel/internal/id/mock"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/org"
"github.com/zitadel/zitadel/internal/repository/user"
webauthn_helper "github.com/zitadel/zitadel/internal/webauthn"
@@ -177,7 +178,7 @@ func TestCommands_RegisterUserPasskeyWithCode(t *testing.T) {
),
),
eventFromEventPusherWithCreationDateNow(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
),
),
expectPush(
@@ -205,7 +206,7 @@ func TestCommands_RegisterUserPasskeyWithCode(t *testing.T) {
),
),
eventFromEventPusherWithCreationDateNow(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
),
),
expectFilterError(io.ErrClosedPipe),
@@ -286,7 +287,7 @@ func TestCommands_verifyUserPasskeyCode(t *testing.T) {
),
),
eventFromEventPusherWithCreationDateNow(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
),
),
expectPush(
@@ -313,7 +314,7 @@ func TestCommands_verifyUserPasskeyCode(t *testing.T) {
),
),
eventFromEventPusherWithCreationDateNow(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
),
),
),
@@ -338,7 +339,7 @@ func TestCommands_verifyUserPasskeyCode(t *testing.T) {
time.Now().Add(-2*time.Minute),
),
eventFromEventPusherWithCreationDate(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
time.Now().Add(-2*time.Minute),
),
),
@@ -368,7 +369,7 @@ func TestCommands_verifyUserPasskeyCode(t *testing.T) {
time.Now().Add(-2*time.Minute),
),
eventFromEventPusherWithCreationDate(
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", false),
user.NewHumanPasswordlessInitCodeSentEvent(ctx, userAgg, "123", senders.DeliveryInfo{}),
time.Now().Add(-2*time.Minute),
),
eventFromEventPusherWithCreationDateNow(
+9 -9
View File
@@ -10,18 +10,18 @@ import (
//go:generate mockgen -typed -package mock -destination ./mock/commands.mock.go . Commands
type Commands interface {
HumanInitCodeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error
HumanEmailVerificationCodeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error
PasswordCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool) error
HumanInitCodeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error
HumanEmailVerificationCodeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error
PasswordCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo) error
HumanOTPSMSCodeSent(ctx context.Context, userID, resourceOwner string, generatorInfo *senders.CodeGeneratorInfo) error
HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string, deliverySuppressed bool) error
HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string, deliveryInfo senders.DeliveryInfo) error
OTPSMSSent(ctx context.Context, sessionID, resourceOwner string, generatorInfo *senders.CodeGeneratorInfo) error
OTPEmailSent(ctx context.Context, sessionID, resourceOwner string, deliverySuppressed bool) error
UserDomainClaimedSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error
HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string, deliverySuppressed bool) error
PasswordChangeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error
OTPEmailSent(ctx context.Context, sessionID, resourceOwner string, deliveryInfo senders.DeliveryInfo) error
UserDomainClaimedSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error
HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string, deliveryInfo senders.DeliveryInfo) error
PasswordChangeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error
HumanPhoneVerificationCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo) error
InviteCodeSent(ctx context.Context, userID, orgID string, deliverySuppressed bool) error
InviteCodeSent(ctx context.Context, userID, orgID string, deliveryInfo senders.DeliveryInfo) error
UsageNotificationSent(ctx context.Context, dueEvent *quota.NotificationDueEvent) error
MilestonePushed(ctx context.Context, instanceID string, msType milestone.Type, endpoints []string) error
BackChannelLogoutSent(ctx context.Context, id, oidcSessionID, instanceID string) (err error)
@@ -58,45 +58,45 @@ func (mr *MockCommandsMockRecorder) BackChannelLogoutSent(ctx, id, oidcSessionID
}
// HumanEmailVerificationCodeSent mocks base method.
func (m *MockCommands) HumanEmailVerificationCodeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error {
func (m *MockCommands) HumanEmailVerificationCodeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HumanEmailVerificationCodeSent", ctx, orgID, userID, deliverySuppressed)
ret := m.ctrl.Call(m, "HumanEmailVerificationCodeSent", ctx, orgID, userID, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// HumanEmailVerificationCodeSent indicates an expected call of HumanEmailVerificationCodeSent.
func (mr *MockCommandsMockRecorder) HumanEmailVerificationCodeSent(ctx, orgID, userID, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) HumanEmailVerificationCodeSent(ctx, orgID, userID, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanEmailVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanEmailVerificationCodeSent), ctx, orgID, userID, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanEmailVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanEmailVerificationCodeSent), ctx, orgID, userID, deliveryInfo)
}
// HumanInitCodeSent mocks base method.
func (m *MockCommands) HumanInitCodeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error {
func (m *MockCommands) HumanInitCodeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HumanInitCodeSent", ctx, orgID, userID, deliverySuppressed)
ret := m.ctrl.Call(m, "HumanInitCodeSent", ctx, orgID, userID, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// HumanInitCodeSent indicates an expected call of HumanInitCodeSent.
func (mr *MockCommandsMockRecorder) HumanInitCodeSent(ctx, orgID, userID, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) HumanInitCodeSent(ctx, orgID, userID, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanInitCodeSent), ctx, orgID, userID, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanInitCodeSent), ctx, orgID, userID, deliveryInfo)
}
// HumanOTPEmailCodeSent mocks base method.
func (m *MockCommands) HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string, deliverySuppressed bool) error {
func (m *MockCommands) HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HumanOTPEmailCodeSent", ctx, userID, resourceOwner, deliverySuppressed)
ret := m.ctrl.Call(m, "HumanOTPEmailCodeSent", ctx, userID, resourceOwner, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// HumanOTPEmailCodeSent indicates an expected call of HumanOTPEmailCodeSent.
func (mr *MockCommandsMockRecorder) HumanOTPEmailCodeSent(ctx, userID, resourceOwner, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) HumanOTPEmailCodeSent(ctx, userID, resourceOwner, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPEmailCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPEmailCodeSent), ctx, userID, resourceOwner, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPEmailCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPEmailCodeSent), ctx, userID, resourceOwner, deliveryInfo)
}
// HumanOTPSMSCodeSent mocks base method.
@@ -114,17 +114,17 @@ func (mr *MockCommandsMockRecorder) HumanOTPSMSCodeSent(ctx, userID, resourceOwn
}
// HumanPasswordlessInitCodeSent mocks base method.
func (m *MockCommands) HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string, deliverySuppressed bool) error {
func (m *MockCommands) HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HumanPasswordlessInitCodeSent", ctx, userID, resourceOwner, codeID, deliverySuppressed)
ret := m.ctrl.Call(m, "HumanPasswordlessInitCodeSent", ctx, userID, resourceOwner, codeID, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// HumanPasswordlessInitCodeSent indicates an expected call of HumanPasswordlessInitCodeSent.
func (mr *MockCommandsMockRecorder) HumanPasswordlessInitCodeSent(ctx, userID, resourceOwner, codeID, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) HumanPasswordlessInitCodeSent(ctx, userID, resourceOwner, codeID, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPasswordlessInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPasswordlessInitCodeSent), ctx, userID, resourceOwner, codeID, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPasswordlessInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPasswordlessInitCodeSent), ctx, userID, resourceOwner, codeID, deliveryInfo)
}
// HumanPhoneVerificationCodeSent mocks base method.
@@ -142,17 +142,17 @@ func (mr *MockCommandsMockRecorder) HumanPhoneVerificationCodeSent(ctx, orgID, u
}
// InviteCodeSent mocks base method.
func (m *MockCommands) InviteCodeSent(ctx context.Context, userID, orgID string, deliverySuppressed bool) error {
func (m *MockCommands) InviteCodeSent(ctx context.Context, userID, orgID string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InviteCodeSent", ctx, userID, orgID, deliverySuppressed)
ret := m.ctrl.Call(m, "InviteCodeSent", ctx, userID, orgID, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// InviteCodeSent indicates an expected call of InviteCodeSent.
func (mr *MockCommandsMockRecorder) InviteCodeSent(ctx, userID, orgID, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) InviteCodeSent(ctx, userID, orgID, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InviteCodeSent", reflect.TypeOf((*MockCommands)(nil).InviteCodeSent), ctx, userID, orgID, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InviteCodeSent", reflect.TypeOf((*MockCommands)(nil).InviteCodeSent), ctx, userID, orgID, deliveryInfo)
}
// MilestonePushed mocks base method.
@@ -170,17 +170,17 @@ func (mr *MockCommandsMockRecorder) MilestonePushed(ctx, instanceID, msType, end
}
// OTPEmailSent mocks base method.
func (m *MockCommands) OTPEmailSent(ctx context.Context, sessionID, resourceOwner string, deliverySuppressed bool) error {
func (m *MockCommands) OTPEmailSent(ctx context.Context, sessionID, resourceOwner string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OTPEmailSent", ctx, sessionID, resourceOwner, deliverySuppressed)
ret := m.ctrl.Call(m, "OTPEmailSent", ctx, sessionID, resourceOwner, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// OTPEmailSent indicates an expected call of OTPEmailSent.
func (mr *MockCommandsMockRecorder) OTPEmailSent(ctx, sessionID, resourceOwner, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) OTPEmailSent(ctx, sessionID, resourceOwner, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPEmailSent", reflect.TypeOf((*MockCommands)(nil).OTPEmailSent), ctx, sessionID, resourceOwner, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPEmailSent", reflect.TypeOf((*MockCommands)(nil).OTPEmailSent), ctx, sessionID, resourceOwner, deliveryInfo)
}
// OTPSMSSent mocks base method.
@@ -198,31 +198,31 @@ func (mr *MockCommandsMockRecorder) OTPSMSSent(ctx, sessionID, resourceOwner, ge
}
// PasswordChangeSent mocks base method.
func (m *MockCommands) PasswordChangeSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error {
func (m *MockCommands) PasswordChangeSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PasswordChangeSent", ctx, orgID, userID, deliverySuppressed)
ret := m.ctrl.Call(m, "PasswordChangeSent", ctx, orgID, userID, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// PasswordChangeSent indicates an expected call of PasswordChangeSent.
func (mr *MockCommandsMockRecorder) PasswordChangeSent(ctx, orgID, userID, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) PasswordChangeSent(ctx, orgID, userID, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordChangeSent", reflect.TypeOf((*MockCommands)(nil).PasswordChangeSent), ctx, orgID, userID, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordChangeSent", reflect.TypeOf((*MockCommands)(nil).PasswordChangeSent), ctx, orgID, userID, deliveryInfo)
}
// PasswordCodeSent mocks base method.
func (m *MockCommands) PasswordCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool) error {
func (m *MockCommands) PasswordCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PasswordCodeSent", ctx, orgID, userID, generatorInfo, deliverySuppressed)
ret := m.ctrl.Call(m, "PasswordCodeSent", ctx, orgID, userID, generatorInfo, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// PasswordCodeSent indicates an expected call of PasswordCodeSent.
func (mr *MockCommandsMockRecorder) PasswordCodeSent(ctx, orgID, userID, generatorInfo, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) PasswordCodeSent(ctx, orgID, userID, generatorInfo, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordCodeSent", reflect.TypeOf((*MockCommands)(nil).PasswordCodeSent), ctx, orgID, userID, generatorInfo, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordCodeSent", reflect.TypeOf((*MockCommands)(nil).PasswordCodeSent), ctx, orgID, userID, generatorInfo, deliveryInfo)
}
// UsageNotificationSent mocks base method.
@@ -240,15 +240,15 @@ func (mr *MockCommandsMockRecorder) UsageNotificationSent(ctx, dueEvent any) *go
}
// UserDomainClaimedSent mocks base method.
func (m *MockCommands) UserDomainClaimedSent(ctx context.Context, orgID, userID string, deliverySuppressed bool) error {
func (m *MockCommands) UserDomainClaimedSent(ctx context.Context, orgID, userID string, deliveryInfo senders.DeliveryInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UserDomainClaimedSent", ctx, orgID, userID, deliverySuppressed)
ret := m.ctrl.Call(m, "UserDomainClaimedSent", ctx, orgID, userID, deliveryInfo)
ret0, _ := ret[0].(error)
return ret0
}
// UserDomainClaimedSent indicates an expected call of UserDomainClaimedSent.
func (mr *MockCommandsMockRecorder) UserDomainClaimedSent(ctx, orgID, userID, deliverySuppressed any) *gomock.Call {
func (mr *MockCommandsMockRecorder) UserDomainClaimedSent(ctx, orgID, userID, deliveryInfo any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserDomainClaimedSent", reflect.TypeOf((*MockCommands)(nil).UserDomainClaimedSent), ctx, orgID, userID, deliverySuppressed)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserDomainClaimedSent", reflect.TypeOf((*MockCommands)(nil).UserDomainClaimedSent), ctx, orgID, userID, deliveryInfo)
}
@@ -92,8 +92,8 @@ type WorkerConfig struct {
type nowFunc func() time.Time
// Sent is called after a notification was sent to set the corresponding event on the aggregate.
// deliverySuppressed is true if an email was accepted, but intentionally not sent to the provider.
type Sent func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error
// deliveryInfo is true if an email was accepted, but intentionally not sent to the provider.
type Sent func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error
var sentHandlers map[eventstore.EventType]Sent
@@ -160,7 +160,7 @@ func (w *NotificationWorker) sendNotificationQueue(ctx context.Context, request
}
generatorInfo := new(senders.CodeGeneratorInfo)
deliverySuppressed := new(bool)
deliveryInfo := new(senders.DeliveryInfo)
var notify types.Notify
switch request.NotificationType {
case domain.NotificationTypeEmail:
@@ -168,7 +168,7 @@ func (w *NotificationWorker) sendNotificationQueue(ctx context.Context, request
if err != nil {
return err
}
notify = types.SendEmail(ctx, w.channels, string(template.Template), translator, notifyUser, colors, request.EventType, deliverySuppressed)
notify = types.SendEmail(ctx, w.channels, string(template.Template), translator, notifyUser, colors, request.EventType, deliveryInfo)
case domain.NotificationTypeSms:
notify = types.SendSMS(ctx, w.channels, translator, notifyUser, colors, request.EventType, request.Aggregate.InstanceID, jobID, generatorInfo)
}
@@ -184,7 +184,7 @@ func (w *NotificationWorker) sendNotificationQueue(ctx context.Context, request
return err
}
err = sentHandler(authz.WithInstanceID(ctx, request.Aggregate.InstanceID), w.commands, request.Aggregate.ID, request.Aggregate.ResourceOwner, generatorInfo, *deliverySuppressed, args)
err = sentHandler(authz.WithInstanceID(ctx, request.Aggregate.InstanceID), w.commands, request.Aggregate.ID, request.Aggregate.ResourceOwner, generatorInfo, *deliveryInfo, args)
logging.WithFields("instanceID", request.Aggregate.InstanceID, "notification", request.Aggregate.ID).
OnError(err).Error("could not set notification event on aggregate")
return nil
@@ -108,7 +108,7 @@ func Test_userNotifier_reduceNotificationRequested(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().InviteCodeSent(gomock.Any(), userID, orgID, false).Return(nil)
commands.EXPECT().InviteCodeSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fieldsWorker{
queries: queries,
commands: commands,
@@ -156,7 +156,7 @@ func Test_userNotifier_reduceNotificationRequested(t *testing.T) {
// no message is expected, but the notification is set to sent and flagged
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithReservedNotifyUserQueries(queries, "{{.LogoURL}}")
commands.EXPECT().InviteCodeSent(gomock.Any(), userID, orgID, true).Return(nil)
commands.EXPECT().InviteCodeSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{DeliverySuppressed: true}).Return(nil)
return fieldsWorker{
queries: queries,
commands: commands,
@@ -276,7 +276,7 @@ func Test_userNotifier_reduceNotificationRequested(t *testing.T) {
TriggeringEventType: user.UserDomainClaimedType,
}
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().UserDomainClaimedSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().UserDomainClaimedSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fieldsWorker{
queries: queries,
commands: commands,
+21 -21
View File
@@ -23,63 +23,63 @@ import (
func init() {
RegisterSentHandler(user.HumanInitialCodeAddedType,
func(ctx context.Context, commands Commands, id, orgID string, _ *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.HumanInitCodeSent(ctx, orgID, id, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, _ *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.HumanInitCodeSent(ctx, orgID, id, deliveryInfo)
},
)
RegisterSentHandler(user.HumanEmailCodeAddedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.HumanEmailVerificationCodeSent(ctx, orgID, id, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.HumanEmailVerificationCodeSent(ctx, orgID, id, deliveryInfo)
},
)
RegisterSentHandler(user.HumanPasswordCodeAddedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.PasswordCodeSent(ctx, orgID, id, generatorInfo, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.PasswordCodeSent(ctx, orgID, id, generatorInfo, deliveryInfo)
},
)
RegisterSentHandler(user.HumanOTPSMSCodeAddedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, _ bool, args map[string]any) error {
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, _ senders.DeliveryInfo, args map[string]any) error {
return commands.HumanOTPSMSCodeSent(ctx, id, orgID, generatorInfo)
},
)
RegisterSentHandler(session.OTPSMSChallengedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, _ bool, args map[string]any) error {
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, _ senders.DeliveryInfo, args map[string]any) error {
return commands.OTPSMSSent(ctx, id, orgID, generatorInfo)
},
)
RegisterSentHandler(user.HumanOTPEmailCodeAddedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.HumanOTPEmailCodeSent(ctx, id, orgID, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.HumanOTPEmailCodeSent(ctx, id, orgID, deliveryInfo)
},
)
RegisterSentHandler(session.OTPEmailChallengedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.OTPEmailSent(ctx, id, orgID, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.OTPEmailSent(ctx, id, orgID, deliveryInfo)
},
)
RegisterSentHandler(user.UserDomainClaimedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.UserDomainClaimedSent(ctx, orgID, id, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.UserDomainClaimedSent(ctx, orgID, id, deliveryInfo)
},
)
RegisterSentHandler(user.HumanPasswordlessInitCodeRequestedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.HumanPasswordlessInitCodeSent(ctx, id, orgID, args["CodeID"].(string), deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.HumanPasswordlessInitCodeSent(ctx, id, orgID, args["CodeID"].(string), deliveryInfo)
},
)
RegisterSentHandler(user.HumanPasswordChangedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.PasswordChangeSent(ctx, orgID, id, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.PasswordChangeSent(ctx, orgID, id, deliveryInfo)
},
)
RegisterSentHandler(user.HumanPhoneCodeAddedType,
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, _ bool, args map[string]any) error {
func(ctx context.Context, commands Commands, id, orgID string, generatorInfo *senders.CodeGeneratorInfo, _ senders.DeliveryInfo, args map[string]any) error {
return commands.HumanPhoneVerificationCodeSent(ctx, orgID, id, generatorInfo)
},
)
RegisterSentHandler(user.HumanInviteCodeAddedType,
func(ctx context.Context, commands Commands, id, orgID string, _ *senders.CodeGeneratorInfo, deliverySuppressed bool, args map[string]any) error {
return commands.InviteCodeSent(ctx, id, orgID, deliverySuppressed)
func(ctx context.Context, commands Commands, id, orgID string, _ *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo, args map[string]any) error {
return commands.InviteCodeSent(ctx, id, orgID, deliveryInfo)
},
)
}
@@ -172,8 +172,8 @@ func (u *userNotifierLegacy) reduceInitCodeAdded(event eventstore.Event) (*handl
if err != nil {
return err
}
deliverySuppressed := new(bool)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, e.Type(), deliverySuppressed).
deliveryInfo := new(senders.DeliveryInfo)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, e.Type(), deliveryInfo).
SendUserInitCode(ctx, notifyUser, code, e.AuthRequestID)
if err != nil {
if errors.Is(err, &channels.CancelError{}) {
@@ -182,7 +182,7 @@ func (u *userNotifierLegacy) reduceInitCodeAdded(event eventstore.Event) (*handl
}
return err
}
return u.commands.HumanInitCodeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliverySuppressed)
return u.commands.HumanInitCodeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliveryInfo)
}), nil
}
@@ -234,8 +234,8 @@ func (u *userNotifierLegacy) reduceEmailCodeAdded(event eventstore.Event) (*hand
if err != nil {
return err
}
deliverySuppressed := new(bool)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliverySuppressed).
deliveryInfo := new(senders.DeliveryInfo)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliveryInfo).
SendEmailVerificationCode(ctx, notifyUser, code, e.URLTemplate, e.AuthRequestID)
if err != nil {
if errors.Is(err, &channels.CancelError{}) {
@@ -244,7 +244,7 @@ func (u *userNotifierLegacy) reduceEmailCodeAdded(event eventstore.Event) (*hand
}
return err
}
return u.commands.HumanEmailVerificationCodeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliverySuppressed)
return u.commands.HumanEmailVerificationCodeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliveryInfo)
}), nil
}
@@ -299,8 +299,8 @@ func (u *userNotifierLegacy) reducePasswordCodeAdded(event eventstore.Event) (*h
return err
}
generatorInfo := new(senders.CodeGeneratorInfo)
deliverySuppressed := new(bool)
notify := types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliverySuppressed)
deliveryInfo := new(senders.DeliveryInfo)
notify := types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliveryInfo)
if e.NotificationType == domain.NotificationTypeSms {
notify = types.SendSMS(ctx, u.channels, translator, notifyUser, colors, e.Type(), e.Aggregate().InstanceID, e.ID, generatorInfo)
}
@@ -312,7 +312,7 @@ func (u *userNotifierLegacy) reducePasswordCodeAdded(event eventstore.Event) (*h
}
return err
}
return u.commands.PasswordCodeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, generatorInfo, *deliverySuppressed)
return u.commands.PasswordCodeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, generatorInfo, *deliveryInfo)
}), nil
}
@@ -485,7 +485,7 @@ func (u *userNotifierLegacy) reduceOTPEmail(
userID,
resourceOwner string,
urlTmpl func(code string, origin *url.URL, user *query.NotifyUser) (string, error),
sentCommand func(ctx context.Context, userID string, resourceOwner string, deliverySuppressed bool) (err error),
sentCommand func(ctx context.Context, userID string, resourceOwner string, deliveryInfo senders.DeliveryInfo) (err error),
eventTypes ...eventstore.EventType,
) (*handler.Statement, error) {
ctx := HandlerContext(context.Background(), event.Aggregate())
@@ -526,8 +526,8 @@ func (u *userNotifierLegacy) reduceOTPEmail(
if err != nil {
return nil, err
}
deliverySuppressed := new(bool)
notify := types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliverySuppressed)
deliveryInfo := new(senders.DeliveryInfo)
notify := types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliveryInfo)
err = notify.SendOTPEmailCode(ctx, link, plainCode, expiry)
if err != nil {
if errors.Is(err, &channels.CancelError{}) {
@@ -536,7 +536,7 @@ func (u *userNotifierLegacy) reduceOTPEmail(
}
return nil, err
}
err = sentCommand(ctx, event.Aggregate().ID, event.Aggregate().ResourceOwner, *deliverySuppressed)
err = sentCommand(ctx, event.Aggregate().ID, event.Aggregate().ResourceOwner, *deliveryInfo)
if err != nil {
return nil, err
}
@@ -581,8 +581,8 @@ func (u *userNotifierLegacy) reduceDomainClaimed(event eventstore.Event) (*handl
if err != nil {
return err
}
deliverySuppressed := new(bool)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliverySuppressed).
deliveryInfo := new(senders.DeliveryInfo)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliveryInfo).
SendDomainClaimed(ctx, notifyUser, e.UserName, e.URLTemplate)
if err != nil {
if errors.Is(err, &channels.CancelError{}) {
@@ -591,7 +591,7 @@ func (u *userNotifierLegacy) reduceDomainClaimed(event eventstore.Event) (*handl
}
return err
}
return u.commands.UserDomainClaimedSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliverySuppressed)
return u.commands.UserDomainClaimedSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliveryInfo)
}), nil
}
@@ -640,8 +640,8 @@ func (u *userNotifierLegacy) reducePasswordlessCodeRequested(event eventstore.Ev
if err != nil {
return err
}
deliverySuppressed := new(bool)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliverySuppressed).
deliveryInfo := new(senders.DeliveryInfo)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliveryInfo).
SendPasswordlessRegistrationLink(ctx, notifyUser, code, e.ID, e.URLTemplate)
if err != nil {
if errors.Is(err, &channels.CancelError{}) {
@@ -650,7 +650,7 @@ func (u *userNotifierLegacy) reducePasswordlessCodeRequested(event eventstore.Ev
}
return err
}
return u.commands.HumanPasswordlessInitCodeSent(ctx, e.Aggregate().ID, e.Aggregate().ResourceOwner, e.ID, *deliverySuppressed)
return u.commands.HumanPasswordlessInitCodeSent(ctx, e.Aggregate().ID, e.Aggregate().ResourceOwner, e.ID, *deliveryInfo)
}), nil
}
@@ -704,8 +704,8 @@ func (u *userNotifierLegacy) reducePasswordChanged(event eventstore.Event) (*han
if err != nil {
return err
}
deliverySuppressed := new(bool)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliverySuppressed).
deliveryInfo := new(senders.DeliveryInfo)
err = types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliveryInfo).
SendPasswordChange(ctx, notifyUser)
if err != nil {
if errors.Is(err, &channels.CancelError{}) {
@@ -714,7 +714,7 @@ func (u *userNotifierLegacy) reducePasswordChanged(event eventstore.Event) (*han
}
return err
}
return u.commands.PasswordChangeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliverySuppressed)
return u.commands.PasswordChangeSent(ctx, e.Aggregate().ResourceOwner, e.Aggregate().ID, *deliveryInfo)
}), nil
}
@@ -822,8 +822,8 @@ func (u *userNotifierLegacy) reduceInviteCodeAdded(event eventstore.Event) (*han
if err != nil {
return err
}
deliverySuppressed := new(bool)
notify := types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliverySuppressed)
deliveryInfo := new(senders.DeliveryInfo)
notify := types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, event.Type(), deliveryInfo)
err = notify.SendInviteCode(ctx, notifyUser, code, e.ApplicationName, e.URLTemplate, e.AuthRequestID)
if err != nil {
if errors.Is(err, &channels.CancelError{}) {
@@ -832,7 +832,7 @@ func (u *userNotifierLegacy) reduceInviteCodeAdded(event eventstore.Event) (*han
}
return err
}
return u.commands.InviteCodeSent(ctx, e.Aggregate().ID, e.Aggregate().ResourceOwner, *deliverySuppressed)
return u.commands.InviteCodeSent(ctx, e.Aggregate().ID, e.Aggregate().ResourceOwner, *deliveryInfo)
}), nil
}
@@ -48,7 +48,7 @@ func Test_userNotifierLegacy_reduceInitCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -75,7 +75,7 @@ func Test_userNotifierLegacy_reduceInitCodeAdded(t *testing.T) {
// no message is expected, but the notification is set to sent and flagged
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithReservedNotifyUserQueries(queries, "{{.LogoURL}}")
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, true).Return(nil)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{DeliverySuppressed: true}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -117,7 +117,7 @@ func Test_userNotifierLegacy_reduceInitCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -152,7 +152,7 @@ func Test_userNotifierLegacy_reduceInitCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -194,7 +194,7 @@ func Test_userNotifierLegacy_reduceInitCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -235,7 +235,7 @@ func Test_userNotifierLegacy_reduceInitCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanInitCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -341,7 +341,7 @@ func Test_userNotifierLegacy_reduceEmailCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -384,7 +384,7 @@ func Test_userNotifierLegacy_reduceEmailCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -421,7 +421,7 @@ func Test_userNotifierLegacy_reduceEmailCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -466,7 +466,7 @@ func Test_userNotifierLegacy_reduceEmailCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -509,7 +509,7 @@ func Test_userNotifierLegacy_reduceEmailCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -548,7 +548,7 @@ func Test_userNotifierLegacy_reduceEmailCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().HumanEmailVerificationCodeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -655,7 +655,7 @@ func Test_userNotifierLegacy_reducePasswordCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, false).Return(nil)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -698,7 +698,7 @@ func Test_userNotifierLegacy_reducePasswordCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, false).Return(nil)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -735,7 +735,7 @@ func Test_userNotifierLegacy_reducePasswordCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, false).Return(nil)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -780,7 +780,7 @@ func Test_userNotifierLegacy_reducePasswordCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, false).Return(nil)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -823,7 +823,7 @@ func Test_userNotifierLegacy_reducePasswordCodeAdded(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, false).Return(nil)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -862,7 +862,7 @@ func Test_userNotifierLegacy_reducePasswordCodeAdded(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, false).Return(nil)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{}, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -900,7 +900,7 @@ func Test_userNotifierLegacy_reducePasswordCodeAdded(t *testing.T) {
},
}
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{ID: smsProviderID, VerificationID: verificationID}, false).Return(nil)
commands.EXPECT().PasswordCodeSent(gomock.Any(), orgID, userID, &senders.CodeGeneratorInfo{ID: smsProviderID, VerificationID: verificationID}, senders.DeliveryInfo{}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1006,7 +1006,7 @@ func Test_userNotifierLegacy_reduceDomainClaimed(t *testing.T) {
},
}
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().UserDomainClaimedSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().UserDomainClaimedSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1043,7 +1043,7 @@ func Test_userNotifierLegacy_reduceDomainClaimed(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().UserDomainClaimedSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().UserDomainClaimedSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1138,7 +1138,7 @@ func Test_userNotifierLegacy_reducePasswordlessCodeRequested(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, false).Return(nil)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1182,7 +1182,7 @@ func Test_userNotifierLegacy_reducePasswordlessCodeRequested(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, false).Return(nil)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1220,7 +1220,7 @@ func Test_userNotifierLegacy_reducePasswordlessCodeRequested(t *testing.T) {
},
}
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, false).Return(nil)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1266,7 +1266,7 @@ func Test_userNotifierLegacy_reducePasswordlessCodeRequested(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, false).Return(nil)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1305,7 +1305,7 @@ func Test_userNotifierLegacy_reducePasswordlessCodeRequested(t *testing.T) {
}
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, false).Return(nil)
commands.EXPECT().HumanPasswordlessInitCodeSent(gomock.Any(), userID, orgID, codeID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1415,7 +1415,7 @@ func Test_userNotifierLegacy_reducePasswordChanged(t *testing.T) {
PasswordChange: true,
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordChangeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().PasswordChangeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1455,7 +1455,7 @@ func Test_userNotifierLegacy_reducePasswordChanged(t *testing.T) {
}},
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
commands.EXPECT().PasswordChangeSent(gomock.Any(), orgID, userID, false).Return(nil)
commands.EXPECT().PasswordChangeSent(gomock.Any(), orgID, userID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1554,7 +1554,7 @@ func Test_userNotifierLegacy_reduceOTPEmailChallenged(t *testing.T) {
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), userID, gomock.Any(), nil).Return(&query.Session{}, nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, false).Return(nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1584,7 +1584,7 @@ func Test_userNotifierLegacy_reduceOTPEmailChallenged(t *testing.T) {
codeAlg, code := cryptoValue(t, ctrl, "testcode")
expectTemplateWithReservedNotifyUserQueries(queries, "{{.LogoURL}}")
queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), userID, gomock.Any(), nil).Return(&query.Session{}, nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, true).Return(nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{DeliverySuppressed: true}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1629,7 +1629,7 @@ func Test_userNotifierLegacy_reduceOTPEmailChallenged(t *testing.T) {
IsPrimary: true,
}},
}, nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, false).Return(nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1667,7 +1667,7 @@ func Test_userNotifierLegacy_reduceOTPEmailChallenged(t *testing.T) {
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), userID, gomock.Any(), nil).Return(&query.Session{}, nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, false).Return(nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1713,7 +1713,7 @@ func Test_userNotifierLegacy_reduceOTPEmailChallenged(t *testing.T) {
}, nil)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), userID, gomock.Any(), nil).Return(&query.Session{}, nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, false).Return(nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -1751,7 +1751,7 @@ func Test_userNotifierLegacy_reduceOTPEmailChallenged(t *testing.T) {
codeAlg, code := cryptoValue(t, ctrl, testCode)
expectTemplateWithNotifyUserQueries(queries, givenTemplate)
queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), userID, gomock.Any(), nil).Return(&query.Session{}, nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, false).Return(nil)
commands.EXPECT().OTPEmailSent(gomock.Any(), userID, orgID, senders.DeliveryInfo{ProviderID: "emailProviderID"}).Return(nil)
return fields{
queries: queries,
commands: commands,
@@ -0,0 +1,12 @@
package senders
// DeliveryInfo describes how an email notification was handled.
// It is part of the sent events of the notification.
type DeliveryInfo struct {
// ProviderID is the ID of the email provider the notification was sent through.
// It is empty if the delivery was suppressed.
ProviderID string `json:"providerId,omitzero"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
}
+4 -3
View File
@@ -48,7 +48,8 @@ type ChannelChains interface {
const SuppressedEmailsCounter = "suppressed_deliveries_email"
// SendEmail returns a [Notify] function, which sends the notification as email.
// deliverySuppressed is optional and set to true if the email was accepted but not sent to the provider,
// deliveryInfo is optional and states the provider the email was sent through,
// or that the email was accepted but not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
func SendEmail(
ctx context.Context,
@@ -58,7 +59,7 @@ func SendEmail(
user *query.NotifyUser,
colors *query.LabelPolicy,
triggeringEventType eventstore.EventType,
deliverySuppressed *bool,
deliveryInfo *senders.DeliveryInfo,
) Notify {
return func(
urlTmpl string,
@@ -104,7 +105,7 @@ func SendEmail(
args,
allowUnverifiedNotificationChannel,
triggeringEventType,
deliverySuppressed,
deliveryInfo,
)
}
}
@@ -97,13 +97,15 @@ func TestSendEmail(t *testing.T) {
germanText = `Dieser Benutzer wurde soeben im Zitadel erstellt. Mit dem Benutzernamen <br><strong>{{.PreferredLoginName}}</strong><br> kannst du dich anmelden. (Code <strong>{{.Code}}</strong>)`
)
smtpConfig := &email.Config{
ProviderConfig: &email.Provider{ID: "smtpProvider"},
SMTPConfig: &smtp.Config{
SMTP: smtp.SMTP{Host: "smtp.example.com:587"},
From: "noreply@example.com",
},
}
webhookConfig := &email.Config{
WebhookConfig: &webhook.Config{CallURL: "https://relay.example.com"},
ProviderConfig: &email.Provider{ID: "webhookProvider"},
WebhookConfig: &webhook.Config{CallURL: "https://relay.example.com"},
}
expectMessage := func(recipient, content string, headers map[string]string) *messages.Email {
return &messages.Email{
@@ -371,11 +373,11 @@ func TestSendEmail(t *testing.T) {
PreferredLanguage: language.English,
}
var deliverySuppressed *bool
var deliveryInfo *senders.DeliveryInfo
if !tt.nilSuppressed {
deliverySuppressed = new(bool)
deliveryInfo = new(senders.DeliveryInfo)
}
notify := SendEmail(t.Context(), tt.channels, mailTemplate, translator, user, &query.LabelPolicy{}, eventType, deliverySuppressed)
notify := SendEmail(t.Context(), tt.channels, mailTemplate, translator, user, &query.LabelPolicy{}, eventType, deliveryInfo)
err = notify(
cmp.Or(tt.urlTemplate, urlTemplate),
map[string]any{"Code": "code1", "ApplicationName": "App"},
@@ -392,8 +394,16 @@ func TestSendEmail(t *testing.T) {
return
}
require.NoError(t, err)
if deliverySuppressed != nil {
assert.Equal(t, tt.wantSuppressed, *deliverySuppressed)
if deliveryInfo != nil {
// the provider is only stated if the email was sent to it
wantProviderID := tt.channels.emailConfig.ProviderConfig.ID
if tt.wantSuppressed {
wantProviderID = ""
}
assert.Equal(t, senders.DeliveryInfo{
ProviderID: wantProviderID,
DeliverySuppressed: tt.wantSuppressed,
}, *deliveryInfo)
}
if tt.wantMessage == nil && (tt.wantSuppressed || tt.nilSuppressed) {
assert.Empty(t, tt.channels.messages)
+8 -3
View File
@@ -15,6 +15,7 @@ import (
"github.com/zitadel/zitadel/internal/notification/channels/email"
"github.com/zitadel/zitadel/internal/notification/channels/smtp"
"github.com/zitadel/zitadel/internal/notification/messages"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/notification/templates"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -31,7 +32,7 @@ func generateEmail(
args map[string]interface{},
lastEmail bool,
triggeringEventType eventstore.EventType,
deliverySuppressed *bool,
deliveryInfo *senders.DeliveryInfo,
) error {
recipient := user.VerifiedEmail
if lastEmail {
@@ -41,12 +42,16 @@ func generateEmail(
// The notification is handled as sent, but the email is not sent to the provider,
// as the recipient domain can never receive it and the email would only bounce.
// This is checked before the channels are created, so no connection to the provider is made.
if deliverySuppressed != nil {
*deliverySuppressed = true
if deliveryInfo != nil {
deliveryInfo.DeliverySuppressed = true
}
countSuppressedEmail(ctx, recipient, triggeringEventType)
return nil
}
if deliveryInfo != nil && config.ProviderConfig != nil {
// The provider is stated on the sent event, which is only created if the email was handled successfully.
deliveryInfo.ProviderID = config.ProviderConfig.ID
}
// The channels connect to the provider and are closed when the message is handled.
// They are therefore only created once the email is ready to be sent.
emailChannels, err := channels.Email(ctx, config)
@@ -8,19 +8,25 @@ import (
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
)
func TestOTPEmailSentEvent_DeliverySuppressed(t *testing.T) {
func TestOTPEmailSentEvent_DeliveryInfo(t *testing.T) {
agg := &eventstore.Aggregate{ID: "session1", Type: AggregateType, ResourceOwner: "instance1", InstanceID: "instance1", Version: AggregateVersion}
for _, suppressed := range []bool{false, true} {
event := NewOTPEmailSentEvent(t.Context(), agg, suppressed)
for _, info := range []senders.DeliveryInfo{
{},
{ProviderID: "provider1"},
{DeliverySuppressed: true},
} {
event := NewOTPEmailSentEvent(t.Context(), agg, info)
payload, err := json.Marshal(event.Payload())
require.NoError(t, err)
mapped, err := eventstore.GenericEventMapper[OTPEmailSentEvent](&eventstore.BaseEvent{Agg: agg, Data: payload})
require.NoError(t, err)
assert.Equal(t, suppressed, mapped.(*OTPEmailSentEvent).DeliverySuppressed)
assert.Equal(t, info, mapped.(*OTPEmailSentEvent).DeliveryInfo)
}
// events stored before the delivery information existed carry no payload at all
mapped, err := eventstore.GenericEventMapper[OTPEmailSentEvent](&eventstore.BaseEvent{Agg: agg})
require.NoError(t, err)
assert.False(t, mapped.(*OTPEmailSentEvent).DeliverySuppressed)
assert.Zero(t, mapped.(*OTPEmailSentEvent).DeliveryInfo)
}
+4 -5
View File
@@ -484,9 +484,8 @@ func NewOTPEmailChallengedEvent(
type OTPEmailSentEvent struct {
eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
}
func (e *OTPEmailSentEvent) Payload() interface{} {
@@ -504,7 +503,7 @@ func (e *OTPEmailSentEvent) SetBaseEvent(base *eventstore.BaseEvent) {
func NewOTPEmailSentEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
deliverySuppressed bool,
deliveryInfo senders.DeliveryInfo,
) *OTPEmailSentEvent {
return &OTPEmailSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
@@ -512,7 +511,7 @@ func NewOTPEmailSentEvent(
aggregate,
OTPEmailSentType,
),
DeliverySuppressed: deliverySuppressed,
DeliveryInfo: deliveryInfo,
}
}
@@ -8,115 +8,128 @@ import (
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
)
// TestDeliverySuppressed ensures that the flag of the email sent events survives the round trip
// and that events stored before the flag existed are still mapped.
func TestDeliverySuppressed(t *testing.T) {
// TestDeliveryInfo ensures that the delivery information of the email sent events survives the round trip
// and that events stored before it existed are still mapped.
func TestDeliveryInfo(t *testing.T) {
ctx := t.Context()
agg := &eventstore.Aggregate{ID: "user1", Type: AggregateType, ResourceOwner: "org1", InstanceID: "instance1", Version: AggregateVersion}
tests := []struct {
name string
event func(suppressed bool) eventstore.Command
event func(info senders.DeliveryInfo) eventstore.Command
mapper func(eventstore.Event) (eventstore.Event, error)
flag func(eventstore.Event) bool
// payloadLessBefore marks events which had no payload before the flag was introduced
info func(eventstore.Event) senders.DeliveryInfo
// payloadLessBefore marks events which had no payload before the delivery information was introduced
payloadLessBefore bool
}{
{
name: "initial code",
payloadLessBefore: true,
event: func(suppressed bool) eventstore.Command {
return NewHumanInitialCodeSentEvent(ctx, agg, suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewHumanInitialCodeSentEvent(ctx, agg, info)
},
mapper: eventstore.GenericEventMapper[HumanInitialCodeSentEvent],
flag: func(e eventstore.Event) bool { return e.(*HumanInitialCodeSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo { return e.(*HumanInitialCodeSentEvent).DeliveryInfo },
},
{
name: "email code",
payloadLessBefore: true,
event: func(suppressed bool) eventstore.Command {
return NewHumanEmailCodeSentEvent(ctx, agg, suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewHumanEmailCodeSentEvent(ctx, agg, info)
},
mapper: eventstore.GenericEventMapper[HumanEmailCodeSentEvent],
flag: func(e eventstore.Event) bool { return e.(*HumanEmailCodeSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo { return e.(*HumanEmailCodeSentEvent).DeliveryInfo },
},
{
name: "invite code",
payloadLessBefore: true,
event: func(suppressed bool) eventstore.Command {
return NewHumanInviteCodeSentEvent(ctx, agg, suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewHumanInviteCodeSentEvent(ctx, agg, info)
},
mapper: eventstore.GenericEventMapper[HumanInviteCodeSentEvent],
flag: func(e eventstore.Event) bool { return e.(*HumanInviteCodeSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo { return e.(*HumanInviteCodeSentEvent).DeliveryInfo },
},
{
name: "password code",
event: func(suppressed bool) eventstore.Command {
return NewHumanPasswordCodeSentEvent(ctx, agg, nil, suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewHumanPasswordCodeSentEvent(ctx, agg, nil, info)
},
mapper: eventstore.GenericEventMapper[HumanPasswordCodeSentEvent],
flag: func(e eventstore.Event) bool { return e.(*HumanPasswordCodeSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo { return e.(*HumanPasswordCodeSentEvent).DeliveryInfo },
},
{
name: "otp email code",
event: func(suppressed bool) eventstore.Command {
return NewHumanOTPEmailCodeSentEvent(ctx, agg, suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewHumanOTPEmailCodeSentEvent(ctx, agg, info)
},
mapper: eventstore.GenericEventMapper[HumanOTPEmailCodeSentEvent],
flag: func(e eventstore.Event) bool { return e.(*HumanOTPEmailCodeSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo { return e.(*HumanOTPEmailCodeSentEvent).DeliveryInfo },
},
{
name: "passwordless init code",
event: func(suppressed bool) eventstore.Command {
return NewHumanPasswordlessInitCodeSentEvent(ctx, agg, "code1", suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewHumanPasswordlessInitCodeSentEvent(ctx, agg, "code1", info)
},
mapper: eventstore.GenericEventMapper[HumanPasswordlessInitCodeSentEvent],
flag: func(e eventstore.Event) bool { return e.(*HumanPasswordlessInitCodeSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo {
return e.(*HumanPasswordlessInitCodeSentEvent).DeliveryInfo
},
},
{
name: "domain claimed",
payloadLessBefore: true,
event: func(suppressed bool) eventstore.Command {
return NewDomainClaimedSentEvent(ctx, agg, suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewDomainClaimedSentEvent(ctx, agg, info)
},
mapper: eventstore.GenericEventMapper[DomainClaimedSentEvent],
flag: func(e eventstore.Event) bool { return e.(*DomainClaimedSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo { return e.(*DomainClaimedSentEvent).DeliveryInfo },
},
{
name: "password change",
payloadLessBefore: true,
event: func(suppressed bool) eventstore.Command {
return NewHumanPasswordChangeSentEvent(ctx, agg, suppressed)
event: func(info senders.DeliveryInfo) eventstore.Command {
return NewHumanPasswordChangeSentEvent(ctx, agg, info)
},
mapper: eventstore.GenericEventMapper[HumanPasswordChangeSentEvent],
flag: func(e eventstore.Event) bool { return e.(*HumanPasswordChangeSentEvent).DeliverySuppressed },
info: func(e eventstore.Event) senders.DeliveryInfo { return e.(*HumanPasswordChangeSentEvent).DeliveryInfo },
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for _, suppressed := range []bool{false, true} {
payload, err := json.Marshal(tt.event(suppressed).Payload())
for _, info := range []senders.DeliveryInfo{
{},
{ProviderID: "provider1"},
{DeliverySuppressed: true},
} {
payload, err := json.Marshal(tt.event(info).Payload())
require.NoError(t, err)
if suppressed {
switch {
case info.DeliverySuppressed:
assert.Contains(t, string(payload), `"deliverySuppressed":true`)
} else {
assert.NotContains(t, string(payload), "providerId")
case info.ProviderID != "":
assert.Contains(t, string(payload), `"providerId":"provider1"`)
assert.NotContains(t, string(payload), "deliverySuppressed")
default:
assert.NotContains(t, string(payload), "deliverySuppressed")
assert.NotContains(t, string(payload), "providerId")
if tt.payloadLessBefore {
// the stored payload must not change for events which had none before
assert.Nil(t, tt.event(false).Payload())
assert.Nil(t, tt.event(info).Payload())
}
}
mapped, err := tt.mapper(&eventstore.BaseEvent{Agg: agg, Data: payload})
require.NoError(t, err)
assert.Equal(t, suppressed, tt.flag(mapped))
assert.Equal(t, info, tt.info(mapped))
}
// events stored before the flag existed carry no payload at all
// events stored before the delivery information existed carry no payload at all
mapped, err := tt.mapper(&eventstore.BaseEvent{Agg: agg})
require.NoError(t, err)
assert.False(t, tt.flag(mapped))
assert.Zero(t, tt.info(mapped))
})
}
}
+13 -14
View File
@@ -10,6 +10,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -308,14 +309,13 @@ func HumanInitialCodeAddedEventMapper(event eventstore.Event) (eventstore.Event,
type HumanInitialCodeSentEvent struct {
eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
}
// Payload returns nil if nothing is set, as the event had no payload before the flag was introduced.
// Payload returns nil if no delivery information is set, as the event had no payload before it was introduced.
func (e *HumanInitialCodeSentEvent) Payload() interface{} {
if !e.DeliverySuppressed {
if e.DeliveryInfo == (senders.DeliveryInfo{}) {
return nil
}
return e
@@ -329,14 +329,14 @@ func (e *HumanInitialCodeSentEvent) SetBaseEvent(base *eventstore.BaseEvent) {
e.BaseEvent = *base
}
func NewHumanInitialCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliverySuppressed bool) *HumanInitialCodeSentEvent {
func NewHumanInitialCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliveryInfo senders.DeliveryInfo) *HumanInitialCodeSentEvent {
return &HumanInitialCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
HumanInitialCodeSentType,
),
DeliverySuppressed: deliverySuppressed,
DeliveryInfo: deliveryInfo,
}
}
@@ -452,18 +452,17 @@ func NewHumanInviteCodeAddedEvent(
type HumanInviteCodeSentEvent struct {
*eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
}
func (e *HumanInviteCodeSentEvent) SetBaseEvent(b *eventstore.BaseEvent) {
e.BaseEvent = b
}
// Payload returns nil if nothing is set, as the event had no payload before the flag was introduced.
// Payload returns nil if no delivery information is set, as the event had no payload before it was introduced.
func (e *HumanInviteCodeSentEvent) Payload() interface{} {
if !e.DeliverySuppressed {
if e.DeliveryInfo == (senders.DeliveryInfo{}) {
return nil
}
return e
@@ -473,14 +472,14 @@ func (e *HumanInviteCodeSentEvent) UniqueConstraints() []*eventstore.UniqueConst
return nil
}
func NewHumanInviteCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliverySuppressed bool) *HumanInviteCodeSentEvent {
func NewHumanInviteCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliveryInfo senders.DeliveryInfo) *HumanInviteCodeSentEvent {
return &HumanInviteCodeSentEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
HumanInviteCodeSentType,
),
DeliverySuppressed: deliverySuppressed,
DeliveryInfo: deliveryInfo,
}
}
+7 -7
View File
@@ -8,6 +8,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -180,14 +181,13 @@ func HumanEmailCodeAddedEventMapper(event eventstore.Event) (eventstore.Event, e
type HumanEmailCodeSentEvent struct {
eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
}
// Payload returns nil if nothing is set, as the event had no payload before the flag was introduced.
// Payload returns nil if no delivery information is set, as the event had no payload before it was introduced.
func (e *HumanEmailCodeSentEvent) Payload() interface{} {
if !e.DeliverySuppressed {
if e.DeliveryInfo == (senders.DeliveryInfo{}) {
return nil
}
return e
@@ -201,13 +201,13 @@ func (e *HumanEmailCodeSentEvent) SetBaseEvent(base *eventstore.BaseEvent) {
e.BaseEvent = *base
}
func NewHumanEmailCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliverySuppressed bool) *HumanEmailCodeSentEvent {
func NewHumanEmailCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliveryInfo senders.DeliveryInfo) *HumanEmailCodeSentEvent {
return &HumanEmailCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
HumanEmailCodeSentType,
),
DeliverySuppressed: deliverySuppressed,
DeliveryInfo: deliveryInfo,
}
}
+4 -5
View File
@@ -570,9 +570,8 @@ func NewHumanOTPEmailCodeAddedEvent(
type HumanOTPEmailCodeSentEvent struct {
eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
Code *crypto.CryptoValue `json:"code,omitempty"`
Expiry time.Duration `json:"expiry,omitempty"`
@@ -594,7 +593,7 @@ func (e *HumanOTPEmailCodeSentEvent) SetBaseEvent(event *eventstore.BaseEvent) {
func NewHumanOTPEmailCodeSentEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
deliverySuppressed bool,
deliveryInfo senders.DeliveryInfo,
) *HumanOTPEmailCodeSentEvent {
return &HumanOTPEmailCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
@@ -602,7 +601,7 @@ func NewHumanOTPEmailCodeSentEvent(
aggregate,
HumanOTPEmailCodeSentType,
),
DeliverySuppressed: deliverySuppressed,
DeliveryInfo: deliveryInfo,
}
}
@@ -8,6 +8,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -374,9 +375,8 @@ func HumanPasswordlessInitCodeRequestedEventMapper(event eventstore.Event) (even
type HumanPasswordlessInitCodeSentEvent struct {
eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
ID string `json:"id"`
}
@@ -397,7 +397,7 @@ func NewHumanPasswordlessInitCodeSentEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id string,
deliverySuppressed bool,
deliveryInfo senders.DeliveryInfo,
) *HumanPasswordlessInitCodeSentEvent {
return &HumanPasswordlessInitCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
@@ -405,8 +405,8 @@ func NewHumanPasswordlessInitCodeSentEvent(
aggregate,
HumanPasswordlessInitCodeSentType,
),
DeliverySuppressed: deliverySuppressed,
ID: id,
DeliveryInfo: deliveryInfo,
ID: id,
}
}
+11 -13
View File
@@ -170,9 +170,8 @@ func HumanPasswordCodeAddedEventMapper(event eventstore.Event) (eventstore.Event
type HumanPasswordCodeSentEvent struct {
*eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
GeneratorInfo *senders.CodeGeneratorInfo `json:"generatorInfo,omitempty"`
}
@@ -189,29 +188,28 @@ func (e *HumanPasswordCodeSentEvent) UniqueConstraints() []*eventstore.UniqueCon
return nil
}
func NewHumanPasswordCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, generatorInfo *senders.CodeGeneratorInfo, deliverySuppressed bool) *HumanPasswordCodeSentEvent {
func NewHumanPasswordCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, generatorInfo *senders.CodeGeneratorInfo, deliveryInfo senders.DeliveryInfo) *HumanPasswordCodeSentEvent {
return &HumanPasswordCodeSentEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
HumanPasswordCodeSentType,
),
DeliverySuppressed: deliverySuppressed,
GeneratorInfo: generatorInfo,
DeliveryInfo: deliveryInfo,
GeneratorInfo: generatorInfo,
}
}
type HumanPasswordChangeSentEvent struct {
eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
}
// Payload returns nil if nothing is set, as the event had no payload before the flag was introduced.
// Payload returns nil if no delivery information is set, as the event had no payload before it was introduced.
func (e *HumanPasswordChangeSentEvent) Payload() interface{} {
if !e.DeliverySuppressed {
if e.DeliveryInfo == (senders.DeliveryInfo{}) {
return nil
}
return e
@@ -225,14 +223,14 @@ func (e *HumanPasswordChangeSentEvent) SetBaseEvent(base *eventstore.BaseEvent)
e.BaseEvent = *base
}
func NewHumanPasswordChangeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliverySuppressed bool) *HumanPasswordChangeSentEvent {
func NewHumanPasswordChangeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate, deliveryInfo senders.DeliveryInfo) *HumanPasswordChangeSentEvent {
return &HumanPasswordChangeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
HumanPasswordChangeSentType,
),
DeliverySuppressed: deliverySuppressed,
DeliveryInfo: deliveryInfo,
}
}
+7 -7
View File
@@ -7,6 +7,7 @@ import (
"github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -469,14 +470,13 @@ func DomainClaimedEventMapper(event eventstore.Event) (eventstore.Event, error)
type DomainClaimedSentEvent struct {
eventstore.BaseEvent `json:"-"`
// DeliverySuppressed is true if the notification was accepted, but the email was not sent to the provider,
// because the recipient domain is reserved and the operator rule of the provider suppresses them.
DeliverySuppressed bool `json:"deliverySuppressed,omitzero"`
// DeliveryInfo states the provider the email was sent through or that the delivery was suppressed.
senders.DeliveryInfo
}
// Payload returns nil if nothing is set, as the event had no payload before the flag was introduced.
// Payload returns nil if no delivery information is set, as the event had no payload before it was introduced.
func (e *DomainClaimedSentEvent) Payload() interface{} {
if !e.DeliverySuppressed {
if e.DeliveryInfo == (senders.DeliveryInfo{}) {
return nil
}
return e
@@ -493,7 +493,7 @@ func (e *DomainClaimedSentEvent) SetBaseEvent(base *eventstore.BaseEvent) {
func NewDomainClaimedSentEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
deliverySuppressed bool,
deliveryInfo senders.DeliveryInfo,
) *DomainClaimedSentEvent {
return &DomainClaimedSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
@@ -501,7 +501,7 @@ func NewDomainClaimedSentEvent(
aggregate,
UserDomainClaimedSentType,
),
DeliverySuppressed: deliverySuppressed,
DeliveryInfo: deliveryInfo,
}
}