mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 18:07:31 +00:00
feat: invite user link (#8578)
# Which Problems Are Solved As an administrator I want to be able to invite users to my application with the API V2, some user data I will already prefil, the user should add the authentication method themself (password, passkey, sso). # How the Problems Are Solved - A user can now be created with a email explicitly set to false. - If a user has no verified email and no authentication method, an `InviteCode` can be created through the User V2 API. - the code can be returned or sent through email - additionally `URLTemplate` and an `ApplicatioName` can provided for the email - The code can be resent and verified through the User V2 API - The V1 login allows users to verify and resend the code and set a password (analog user initialization) - The message text for the user invitation can be customized # Additional Changes - `verifyUserPasskeyCode` directly uses `crypto.VerifyCode` (instead of `verifyEncryptedCode`) - `verifyEncryptedCode` is removed (unnecessarily queried for the code generator) # Additional Context - closes #8310 - TODO: login V2 will have to implement invite flow: https://github.com/zitadel/typescript/issues/166
This commit is contained in:
@@ -19,6 +19,7 @@ type Commands interface {
|
||||
HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string) error
|
||||
PasswordChangeSent(ctx context.Context, orgID, userID string) error
|
||||
HumanPhoneVerificationCodeSent(ctx context.Context, orgID, userID string) error
|
||||
InviteCodeSent(ctx context.Context, orgID, userID string) error
|
||||
UsageNotificationSent(ctx context.Context, dueEvent *quota.NotificationDueEvent) error
|
||||
MilestonePushed(ctx context.Context, msType milestone.Type, endpoints []string, primaryDomain string) error
|
||||
}
|
||||
|
@@ -18,30 +18,30 @@ import (
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockCommands is a mock of Commands interface.
|
||||
// MockCommands is a mock of Commands interface
|
||||
type MockCommands struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCommandsMockRecorder
|
||||
}
|
||||
|
||||
// MockCommandsMockRecorder is the mock recorder for MockCommands.
|
||||
// MockCommandsMockRecorder is the mock recorder for MockCommands
|
||||
type MockCommandsMockRecorder struct {
|
||||
mock *MockCommands
|
||||
}
|
||||
|
||||
// NewMockCommands creates a new mock instance.
|
||||
// NewMockCommands creates a new mock instance
|
||||
func NewMockCommands(ctrl *gomock.Controller) *MockCommands {
|
||||
mock := &MockCommands{ctrl: ctrl}
|
||||
mock.recorder = &MockCommandsMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockCommands) EXPECT() *MockCommandsMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// HumanEmailVerificationCodeSent mocks base method.
|
||||
// HumanEmailVerificationCodeSent mocks base method
|
||||
func (m *MockCommands) HumanEmailVerificationCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanEmailVerificationCodeSent", arg0, arg1, arg2)
|
||||
@@ -49,13 +49,13 @@ func (m *MockCommands) HumanEmailVerificationCodeSent(arg0 context.Context, arg1
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanEmailVerificationCodeSent indicates an expected call of HumanEmailVerificationCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanEmailVerificationCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// HumanEmailVerificationCodeSent indicates an expected call of HumanEmailVerificationCodeSent
|
||||
func (mr *MockCommandsMockRecorder) HumanEmailVerificationCodeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanEmailVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanEmailVerificationCodeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// HumanInitCodeSent mocks base method.
|
||||
// HumanInitCodeSent mocks base method
|
||||
func (m *MockCommands) HumanInitCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanInitCodeSent", arg0, arg1, arg2)
|
||||
@@ -63,13 +63,13 @@ func (m *MockCommands) HumanInitCodeSent(arg0 context.Context, arg1, arg2 string
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanInitCodeSent indicates an expected call of HumanInitCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanInitCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// HumanInitCodeSent indicates an expected call of HumanInitCodeSent
|
||||
func (mr *MockCommandsMockRecorder) HumanInitCodeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanInitCodeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// HumanOTPEmailCodeSent mocks base method.
|
||||
// HumanOTPEmailCodeSent mocks base method
|
||||
func (m *MockCommands) HumanOTPEmailCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanOTPEmailCodeSent", arg0, arg1, arg2)
|
||||
@@ -77,13 +77,13 @@ func (m *MockCommands) HumanOTPEmailCodeSent(arg0 context.Context, arg1, arg2 st
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanOTPEmailCodeSent indicates an expected call of HumanOTPEmailCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPEmailCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// HumanOTPEmailCodeSent indicates an expected call of HumanOTPEmailCodeSent
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPEmailCodeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPEmailCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPEmailCodeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// HumanOTPSMSCodeSent mocks base method.
|
||||
// HumanOTPSMSCodeSent mocks base method
|
||||
func (m *MockCommands) HumanOTPSMSCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanOTPSMSCodeSent", arg0, arg1, arg2)
|
||||
@@ -91,13 +91,13 @@ func (m *MockCommands) HumanOTPSMSCodeSent(arg0 context.Context, arg1, arg2 stri
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanOTPSMSCodeSent indicates an expected call of HumanOTPSMSCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPSMSCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// HumanOTPSMSCodeSent indicates an expected call of HumanOTPSMSCodeSent
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPSMSCodeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPSMSCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPSMSCodeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// HumanPasswordlessInitCodeSent mocks base method.
|
||||
// HumanPasswordlessInitCodeSent mocks base method
|
||||
func (m *MockCommands) HumanPasswordlessInitCodeSent(arg0 context.Context, arg1, arg2, arg3 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanPasswordlessInitCodeSent", arg0, arg1, arg2, arg3)
|
||||
@@ -105,13 +105,13 @@ func (m *MockCommands) HumanPasswordlessInitCodeSent(arg0 context.Context, arg1,
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanPasswordlessInitCodeSent indicates an expected call of HumanPasswordlessInitCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanPasswordlessInitCodeSent(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
// HumanPasswordlessInitCodeSent indicates an expected call of HumanPasswordlessInitCodeSent
|
||||
func (mr *MockCommandsMockRecorder) HumanPasswordlessInitCodeSent(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPasswordlessInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPasswordlessInitCodeSent), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// HumanPhoneVerificationCodeSent mocks base method.
|
||||
// HumanPhoneVerificationCodeSent mocks base method
|
||||
func (m *MockCommands) HumanPhoneVerificationCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanPhoneVerificationCodeSent", arg0, arg1, arg2)
|
||||
@@ -119,13 +119,27 @@ func (m *MockCommands) HumanPhoneVerificationCodeSent(arg0 context.Context, arg1
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanPhoneVerificationCodeSent indicates an expected call of HumanPhoneVerificationCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanPhoneVerificationCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// HumanPhoneVerificationCodeSent indicates an expected call of HumanPhoneVerificationCodeSent
|
||||
func (mr *MockCommandsMockRecorder) HumanPhoneVerificationCodeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPhoneVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPhoneVerificationCodeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// MilestonePushed mocks base method.
|
||||
// InviteCodeSent mocks base method
|
||||
func (m *MockCommands) InviteCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InviteCodeSent", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InviteCodeSent indicates an expected call of InviteCodeSent
|
||||
func (mr *MockCommandsMockRecorder) InviteCodeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InviteCodeSent", reflect.TypeOf((*MockCommands)(nil).InviteCodeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// MilestonePushed mocks base method
|
||||
func (m *MockCommands) MilestonePushed(arg0 context.Context, arg1 milestone.Type, arg2 []string, arg3 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MilestonePushed", arg0, arg1, arg2, arg3)
|
||||
@@ -133,13 +147,13 @@ func (m *MockCommands) MilestonePushed(arg0 context.Context, arg1 milestone.Type
|
||||
return ret0
|
||||
}
|
||||
|
||||
// MilestonePushed indicates an expected call of MilestonePushed.
|
||||
func (mr *MockCommandsMockRecorder) MilestonePushed(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
// MilestonePushed indicates an expected call of MilestonePushed
|
||||
func (mr *MockCommandsMockRecorder) MilestonePushed(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MilestonePushed", reflect.TypeOf((*MockCommands)(nil).MilestonePushed), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// OTPEmailSent mocks base method.
|
||||
// OTPEmailSent mocks base method
|
||||
func (m *MockCommands) OTPEmailSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "OTPEmailSent", arg0, arg1, arg2)
|
||||
@@ -147,13 +161,13 @@ func (m *MockCommands) OTPEmailSent(arg0 context.Context, arg1, arg2 string) err
|
||||
return ret0
|
||||
}
|
||||
|
||||
// OTPEmailSent indicates an expected call of OTPEmailSent.
|
||||
func (mr *MockCommandsMockRecorder) OTPEmailSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// OTPEmailSent indicates an expected call of OTPEmailSent
|
||||
func (mr *MockCommandsMockRecorder) OTPEmailSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPEmailSent", reflect.TypeOf((*MockCommands)(nil).OTPEmailSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// OTPSMSSent mocks base method.
|
||||
// OTPSMSSent mocks base method
|
||||
func (m *MockCommands) OTPSMSSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "OTPSMSSent", arg0, arg1, arg2)
|
||||
@@ -161,13 +175,13 @@ func (m *MockCommands) OTPSMSSent(arg0 context.Context, arg1, arg2 string) error
|
||||
return ret0
|
||||
}
|
||||
|
||||
// OTPSMSSent indicates an expected call of OTPSMSSent.
|
||||
func (mr *MockCommandsMockRecorder) OTPSMSSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// OTPSMSSent indicates an expected call of OTPSMSSent
|
||||
func (mr *MockCommandsMockRecorder) OTPSMSSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPSMSSent", reflect.TypeOf((*MockCommands)(nil).OTPSMSSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// PasswordChangeSent mocks base method.
|
||||
// PasswordChangeSent mocks base method
|
||||
func (m *MockCommands) PasswordChangeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PasswordChangeSent", arg0, arg1, arg2)
|
||||
@@ -175,13 +189,13 @@ func (m *MockCommands) PasswordChangeSent(arg0 context.Context, arg1, arg2 strin
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PasswordChangeSent indicates an expected call of PasswordChangeSent.
|
||||
func (mr *MockCommandsMockRecorder) PasswordChangeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// PasswordChangeSent indicates an expected call of PasswordChangeSent
|
||||
func (mr *MockCommandsMockRecorder) PasswordChangeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordChangeSent", reflect.TypeOf((*MockCommands)(nil).PasswordChangeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// PasswordCodeSent mocks base method.
|
||||
// PasswordCodeSent mocks base method
|
||||
func (m *MockCommands) PasswordCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PasswordCodeSent", arg0, arg1, arg2)
|
||||
@@ -189,13 +203,13 @@ func (m *MockCommands) PasswordCodeSent(arg0 context.Context, arg1, arg2 string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PasswordCodeSent indicates an expected call of PasswordCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) PasswordCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// PasswordCodeSent indicates an expected call of PasswordCodeSent
|
||||
func (mr *MockCommandsMockRecorder) PasswordCodeSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordCodeSent", reflect.TypeOf((*MockCommands)(nil).PasswordCodeSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// UsageNotificationSent mocks base method.
|
||||
// UsageNotificationSent mocks base method
|
||||
func (m *MockCommands) UsageNotificationSent(arg0 context.Context, arg1 *quota.NotificationDueEvent) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UsageNotificationSent", arg0, arg1)
|
||||
@@ -203,13 +217,13 @@ func (m *MockCommands) UsageNotificationSent(arg0 context.Context, arg1 *quota.N
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UsageNotificationSent indicates an expected call of UsageNotificationSent.
|
||||
func (mr *MockCommandsMockRecorder) UsageNotificationSent(arg0, arg1 any) *gomock.Call {
|
||||
// UsageNotificationSent indicates an expected call of UsageNotificationSent
|
||||
func (mr *MockCommandsMockRecorder) UsageNotificationSent(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UsageNotificationSent", reflect.TypeOf((*MockCommands)(nil).UsageNotificationSent), arg0, arg1)
|
||||
}
|
||||
|
||||
// UserDomainClaimedSent mocks base method.
|
||||
// UserDomainClaimedSent mocks base method
|
||||
func (m *MockCommands) UserDomainClaimedSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UserDomainClaimedSent", arg0, arg1, arg2)
|
||||
@@ -217,8 +231,8 @@ func (m *MockCommands) UserDomainClaimedSent(arg0 context.Context, arg1, arg2 st
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UserDomainClaimedSent indicates an expected call of UserDomainClaimedSent.
|
||||
func (mr *MockCommandsMockRecorder) UserDomainClaimedSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
// UserDomainClaimedSent indicates an expected call of UserDomainClaimedSent
|
||||
func (mr *MockCommandsMockRecorder) UserDomainClaimedSent(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserDomainClaimedSent", reflect.TypeOf((*MockCommands)(nil).UserDomainClaimedSent), arg0, arg1, arg2)
|
||||
}
|
||||
|
@@ -106,6 +106,10 @@ func (u *userNotifier) Reducers() []handler.AggregateReducer {
|
||||
Event: user.HumanOTPEmailCodeAddedType,
|
||||
Reduce: u.reduceOTPEmailCodeAdded,
|
||||
},
|
||||
{
|
||||
Event: user.HumanInviteCodeAddedType,
|
||||
Reduce: u.reduceInviteCodeAdded,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -718,6 +722,61 @@ func (u *userNotifier) reducePhoneCodeAdded(event eventstore.Event) (*handler.St
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (u *userNotifier) reduceInviteCodeAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, ok := event.(*user.HumanInviteCodeAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Eeg3s", "reduce.wrong.event.type %s", user.HumanInviteCodeAddedType)
|
||||
}
|
||||
if e.CodeReturned {
|
||||
return handler.NewNoOpStatement(e), nil
|
||||
}
|
||||
|
||||
return handler.NewStatement(event, func(ex handler.Executer, projectionName string) error {
|
||||
ctx := HandlerContext(event.Aggregate())
|
||||
alreadyHandled, err := u.checkIfCodeAlreadyHandledOrExpired(ctx, event, e.Expiry, nil,
|
||||
user.HumanInviteCodeAddedType, user.HumanInviteCodeSentType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if alreadyHandled {
|
||||
return nil
|
||||
}
|
||||
code, err := crypto.DecryptString(e.Code, u.queries.UserDataCrypto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
colors, err := u.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template, err := u.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
notifyUser, err := u.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
translator, err := u.queries.GetTranslatorWithOrgTexts(ctx, notifyUser.ResourceOwner, domain.InviteUserMessageType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, err = u.queries.Origin(ctx, e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notify := types.SendEmail(ctx, u.channels, string(template.Template), translator, notifyUser, colors, e)
|
||||
err = notify.SendInviteCode(ctx, notifyUser, code, e.ApplicationName, e.URLTemplate, e.AuthRequestID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return u.commands.InviteCodeSent(ctx, e.Aggregate().ID, e.Aggregate().ResourceOwner)
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (u *userNotifier) checkIfCodeAlreadyHandledOrExpired(ctx context.Context, event eventstore.Event, expiry time.Duration, data map[string]interface{}, eventTypes ...eventstore.EventType) (bool, error) {
|
||||
if event.CreatedAt().Add(expiry).Before(time.Now().UTC()) {
|
||||
return true, nil
|
||||
|
@@ -69,3 +69,10 @@ PasswordChange:
|
||||
Паролата на вашия потребител е променена, ако тази промяна не е направена от
|
||||
вас, моля, незабавно нулирайте паролата си.
|
||||
ButtonText: Влизам
|
||||
InviteUser:
|
||||
Title: Покана за {{.ApplicationName}}
|
||||
PreHeader: Покана за {{.ApplicationName}}
|
||||
Subject: Покана за {{.ApplicationName}}
|
||||
Greeting: 'Здравейте {{.DisplayName}},'
|
||||
Text: Вашият потребител е бил поканен за {{.ApplicationName}}. Моля, кликнете върху бутона по-долу, за да завършите процеса на покана. Ако не сте поискали този имейл, моля, игнорирайте го.
|
||||
ButtonText: Приеми поканата
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Dobrý den, {{.DisplayName}},
|
||||
Text: Heslo vašeho uživatele bylo změněno. Pokud tato změna nebyla provedena Vámi pak doporučujeme okamžitě resetovat/změnit vaše heslo.
|
||||
ButtonText: Přihlásit se
|
||||
InviteUser:
|
||||
Title: Pozvánka do {{.ApplicationName}}
|
||||
PreHeader: Pozvánka do {{.ApplicationName}}
|
||||
Subject: Pozvánka do {{.ApplicationName}}
|
||||
Greeting: Dobrý den, {{.DisplayName}},
|
||||
Text: Váš uživatel byl pozván do {{.ApplicationName}}. Klikněte prosím na tlačítko níže, abyste dokončili proces pozvání. Pokud jste o tento e-mail nepožádali, prosím, ignorujte ho.
|
||||
ButtonText: Přijmout pozvání
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Hallo {{.DisplayName}},
|
||||
Text: Dein Passwort wurde geändert. Wenn diese Änderung nicht von dir gemacht wurde, empfehlen wir das sofortige Zurücksetzen deines Passworts.
|
||||
ButtonText: Login
|
||||
InviteUser:
|
||||
Title: Einladung zu {{.ApplicationName}}
|
||||
PreHeader: Einladung zu {{.ApplicationName}}
|
||||
Subject: Einladung zu {{.ApplicationName}}
|
||||
Greeting: Hallo {{.DisplayName}},
|
||||
Text: Ihr Benutzer wurde zu {{.ApplicationName}} eingeladen. Bitte klicken Sie auf die Schaltfläche unten, um den Einladungsprozess abzuschließen. Wenn Sie diese E-Mail nicht angefordert haben, ignorieren Sie sie bitte.
|
||||
ButtonText: Einladung annehmen
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Hello {{.DisplayName}},
|
||||
Text: The password of your user has changed. If this change was not done by you, please be advised to immediately reset your password.
|
||||
ButtonText: Login
|
||||
InviteUser:
|
||||
Title: Invitation to {{.ApplicationName}}
|
||||
PreHeader: Invitation to {{.ApplicationName}}
|
||||
Subject: Invitation to {{.ApplicationName}}
|
||||
Greeting: Hello {{.DisplayName}},
|
||||
Text: Your user has been invited to {{.ApplicationName}}. Please click the button below to finish the invite process. If you didn't ask for this mail, please ignore it.
|
||||
ButtonText: Accept invite
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Hola {{.DisplayName}},
|
||||
Text: La contraseña de tu usuario ha sido cambiada, si este cambio no fue hecho por ti, por favor proceder a restablecer inmediatamente tu contraseña.
|
||||
ButtonText: Iniciar sesión
|
||||
InviteUser:
|
||||
Title: Invitación a {{.ApplicationName}}
|
||||
PreHeader: Invitación a {{.ApplicationName}}
|
||||
Subject: Invitación a {{.ApplicationName}}
|
||||
Greeting: Hola {{.DisplayName}},
|
||||
Text: Tu usuario ha sido invitado a {{.ApplicationName}}. Haz clic en el botón de abajo para finalizar el proceso de invitación. Si no solicitaste este correo electrónico, por favor ignóralo.
|
||||
ButtonText: Aceptar invitación
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Bonjour {{.DisplayName}},
|
||||
Text: Le mot de passe de votre utilisateur a changé, si ce changement n'a pas été fait par vous, nous vous conseillons de réinitialiser immédiatement votre mot de passe.
|
||||
ButtonText: Login
|
||||
InviteUser:
|
||||
Title: Invitation à {{.ApplicationName}}
|
||||
PreHeader: Invitation à {{.ApplicationName}}
|
||||
Subject: Invitation à {{.ApplicationName}}
|
||||
Greeting: Bonjour {{.DisplayName}},
|
||||
Text: Votre utilisateur a été invité à {{.ApplicationName}}. Veuillez cliquer sur le bouton ci-dessous pour terminer le processus d'invitation. Si vous n'avez pas demandé cet e-mail, veuillez l'ignorer.
|
||||
ButtonText: Accepter l'invitation
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: 'Halo {{.DisplayName}},'
|
||||
Text: 'Kata sandi pengguna Anda telah berubah. '
|
||||
ButtonText: Login
|
||||
InviteUser:
|
||||
Title: Undangan ke {{.ApplicationName}}
|
||||
PreHeader: Undangan ke {{.ApplicationName}}
|
||||
Subject: Undangan ke {{.ApplicationName}}
|
||||
Greeting: 'Halo {{.DisplayName}},'
|
||||
Text: Pengguna Anda telah diundang ke {{.ApplicationName}}. Silakan klik tombol di bawah ini untuk menyelesaikan proses undangan. Jika Anda tidak meminta email ini, harap abaikan.
|
||||
ButtonText: Terima undangan
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Ciao {{.DisplayName}},
|
||||
Text: La password del vostro utente è cambiata; se questa modifica non è stata fatta da voi, vi consigliamo di reimpostare immediatamente la vostra password.
|
||||
ButtonText: Login
|
||||
InviteUser:
|
||||
Title: Invito a {{.ApplicationName}}
|
||||
PreHeader: Invito a {{.ApplicationName}}
|
||||
Subject: Invito a {{.ApplicationName}}
|
||||
Greeting: 'Ciao {{.DisplayName}},'
|
||||
Text: Il tuo utente è stato invitato a {{.ApplicationName}}. Clicca sul pulsante qui sotto per completare il processo di invito. Se non hai richiesto questa email, ignorala.
|
||||
ButtonText: Accetta invito
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: こんにちは {{.DisplayName}} さん、
|
||||
Text: ユーザーのパスワードが変更されました。この変更があなたによって行われなかった場合は、すぐにパスワードをリセットすることをお勧めします。
|
||||
ButtonText: ログイン
|
||||
InviteUser:
|
||||
Title: '{{.ApplicationName}}への招待'
|
||||
PreHeader: '{{.ApplicationName}}への招待'
|
||||
Subject: '{{.ApplicationName}}への招待'
|
||||
Greeting: こんにちは {{.DisplayName}} さん、
|
||||
Text: あなたのユーザーは{{.ApplicationName}}に招待されました。下のボタンをクリックして、招待プロセスを完了してください。このメールをリクエストしていない場合は、無視してください。
|
||||
ButtonText: 招待を受け入れる
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Здраво {{.DisplayName}},
|
||||
Text: Лозинката на вашиот корисник е променета. Ако оваа промена не е извршена од вас, ве молиме веднаш ресетирајте ја вашата лозинка.
|
||||
ButtonText: Најава
|
||||
InviteUser:
|
||||
Title: Покана за {{.ApplicationName}}
|
||||
PreHeader: Покана за {{.ApplicationName}}
|
||||
Subject: Покана за {{.ApplicationName}}
|
||||
Greeting: Здраво {{.DisplayName}},
|
||||
Text: Вашиот корисник е бил поканет за {{.ApplicationName}}. Ве молиме кликнете на копчето подолу за да го завршите процесот на покана. Ако не сте побарале овој мејл, ве молиме игнорирајте го.
|
||||
ButtonText: Прифати покана
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Hallo {{.DisplayName}},
|
||||
Text: Het wachtwoord van uw gebruiker is veranderd. Als deze wijziging niet door u is gedaan, wordt u geadviseerd om direct uw wachtwoord te resetten.
|
||||
ButtonText: Inloggen
|
||||
InviteUser:
|
||||
Title: Uitnodiging voor {{.ApplicationName}}
|
||||
PreHeader: Uitnodiging voor {{.ApplicationName}}
|
||||
Subject: Uitnodiging voor {{.ApplicationName}}
|
||||
Greeting: Hallo {{.DisplayName}},
|
||||
Text: Uw gebruiker is uitgenodigd voor {{.ApplicationName}}. Klik op de onderstaande knop om het uitnodigingsproces te voltooien. Als u deze e-mail niet hebt aangevraagd, negeer deze dan.
|
||||
ButtonText: Uitnodiging accepteren
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Witaj {{.DisplayName}},
|
||||
Text: Hasło Twojego użytkownika zostało zmienione, jeśli ta zmiana nie została dokonana przez Ciebie, zalecamy natychmiastowe zresetowanie hasła.
|
||||
ButtonText: Zaloguj się
|
||||
InviteUser:
|
||||
Title: Zaproszenie do {{.ApplicationName}}
|
||||
PreHeader: Zaproszenie do {{.ApplicationName}}
|
||||
Subject: Zaproszenie do {{.ApplicationName}}
|
||||
Greeting: Witaj {{.DisplayName}},
|
||||
Text: Twój użytkownik został zaproszony do {{.ApplicationName}}. Kliknij poniższy przycisk, aby zakończyć proces zaproszenia. Jeśli nie zażądałeś tego e-maila, zignoruj go.
|
||||
ButtonText: Akceptuj zaproszenie
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Olá {{.DisplayName}},
|
||||
Text: A senha do seu usuário foi alterada. Se esta alteração não foi feita por você, recomendamos que você redefina sua senha imediatamente.
|
||||
ButtonText: Fazer login
|
||||
InviteUser:
|
||||
Title: Convite para {{.ApplicationName}}
|
||||
PreHeader: Convite para {{.ApplicationName}}
|
||||
Subject: Convite para {{.ApplicationName}}
|
||||
Greeting: Olá {{.DisplayName}},
|
||||
Text: Seu usuário foi convidado para {{.ApplicationName}}. Clique no botão abaixo para concluir o processo de convite. Se você não solicitou este e-mail, por favor, ignore-o.
|
||||
ButtonText: Aceitar convite
|
@@ -2,28 +2,28 @@ InitCode:
|
||||
Title: Регистрация пользователя
|
||||
PreHeader: Регистрация пользователя
|
||||
Subject: Регистрация пользователя
|
||||
Greeting: Здравствуйте {{.FirstName}} {{.LastName}},
|
||||
Greeting: Здравствуйте {{.DisplayName}},
|
||||
Text: Используйте логин {{.PreferredLoginName}} для входа. Пожалуйста, нажмите кнопку ниже для завершения процесса регистрации. (Код {{.Code}}) Если вы не запрашивали это письмо, пожалуйста, проигнорируйте его.
|
||||
ButtonText: Завершить регистрацию
|
||||
PasswordReset:
|
||||
Title: Сброс пароля
|
||||
PreHeader: Сброс пароля
|
||||
Subject: Сброс пароля
|
||||
Greeting: Здравствуйте {{.FirstName}} {{.LastName}},
|
||||
Greeting: Здравствуйте {{.DisplayName}},
|
||||
Text: Мы получили запрос на сброс пароля. Пожалуйста, нажмите кнопку ниже для сброса вашего пароля. (Код {{.Code}}) Если вы не запрашивали это письмо, пожалуйста, проигнорируйте его.
|
||||
ButtonText: Сбросить пароль
|
||||
VerifyEmail:
|
||||
Title: Подтверждение email
|
||||
PreHeader: Подтверждение email
|
||||
Subject: Подтверждение email
|
||||
Greeting: Здравствуйте {{.FirstName}} {{.LastName}},
|
||||
Greeting: Здравствуйте {{.DisplayName}},
|
||||
Text: Добавлен новый email. Пожалуйста, нажмите кнопку ниже для подтверждения вашего email. (Код {{.Code}}) Если вы не запрашивали это письмо, пожалуйста, проигнорируйте его.
|
||||
ButtonText: Подтвердить email
|
||||
VerifyPhone:
|
||||
Title: Подтверждение телефона
|
||||
PreHeader: Подтверждение телефона
|
||||
Subject: Подтверждение телефона
|
||||
Greeting: Здравствуйте {{.FirstName}} {{.LastName}},
|
||||
Greeting: Здравствуйте {{.DisplayName}},
|
||||
Text: Добавлен новый номер телефона. Пожалуйста, используйте следующий код, чтобы подтвердить его. Код {{.Code}}
|
||||
ButtonText: Подтвердить телефон
|
||||
VerifyEmailOTP:
|
||||
@@ -42,20 +42,27 @@ DomainClaimed:
|
||||
Title: Утверждение домена
|
||||
PreHeader: Изменение email / логина
|
||||
Subject: Домен был утвержден
|
||||
Greeting: Здравствуйте {{.FirstName}} {{.LastName}},
|
||||
Greeting: Здравствуйте {{.DisplayName}},
|
||||
Text: Домен {{.Domain}} был утвержден организацией. Ваш текущий пользователь {{.Username}} не является частью этой организации. Вам необходимо изменить свой email при входе в систему. Мы создали временный логин ({{.TempUsername}}) для входа.
|
||||
ButtonText: Вход
|
||||
PasswordlessRegistration:
|
||||
Title: Добавление входа без пароля
|
||||
PreHeader: Добавление входа без пароля
|
||||
Subject: Добавление входа без пароля
|
||||
Greeting: Здравствуйте {{.FirstName}} {{.LastName}},
|
||||
Greeting: Здравствуйте {{.DisplayName}},
|
||||
Text: Мы получили запрос на добавление токена для входа без пароля. Пожалуйста, используйте кнопку ниже, чтобы добавить свой токен или устройство для входа без пароля.
|
||||
ButtonText: Добавить вход без пароля
|
||||
PasswordChange:
|
||||
Title: Смена пароля пользователя
|
||||
PreHeader: Смена пароля
|
||||
Subject: Пароль пользователя изменен
|
||||
Greeting: Здравствуйте {{.FirstName}} {{.LastName}},
|
||||
Greeting: Здравствуйте {{.DisplayName}},
|
||||
Text: Пароль пользователя был изменен. Если это изменение сделано не вами, советуем немедленно сбросить пароль.
|
||||
ButtonText: Вход
|
||||
InviteUser:
|
||||
Title: Приглашение в {{.ApplicationName}}
|
||||
PreHeader: Приглашение в {{.ApplicationName}}
|
||||
Subject: Приглашение в {{.ApplicationName}}
|
||||
Greeting: Здравствуйте, {{.DisplayName}},
|
||||
Text: Ваш пользователь был приглашен в {{.ApplicationName}}. Пожалуйста, нажмите кнопку ниже, чтобы завершить процесс приглашения. Если вы не запрашивали это письмо, пожалуйста, игнорируйте его.
|
||||
ButtonText: Принять приглашение
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: Hej {{.DisplayName}},
|
||||
Text: Lösenordet för din användare har ändrats. Om denna ändring inte gjordes av dig, vänligen återställ ditt lösenord omedelbart.
|
||||
ButtonText: Logga in
|
||||
InviteUser:
|
||||
Title: Inbjudan till {{.ApplicationName}}
|
||||
PreHeader: Inbjudan till {{.ApplicationName}}
|
||||
Subject: Inbjudan till {{.ApplicationName}}
|
||||
Greeting: Hej {{.DisplayName}},
|
||||
Text: Din användare har blivit inbjuden till {{.ApplicationName}}. Klicka på knappen nedan för att slutföra inbjudansprocessen. Om du inte har begärt detta e-postmeddelande, ignorera det.
|
||||
ButtonText: Acceptera inbjudan
|
@@ -59,3 +59,10 @@ PasswordChange:
|
||||
Greeting: 你好 {{.DisplayName}},
|
||||
Text: 您的用户的密码已经改变,如果这个改变不是由您做的,请注意立即重新设置您的密码。
|
||||
ButtonText: 登录
|
||||
InviteUser:
|
||||
Title: '{{.ApplicationName}}邀请'
|
||||
PreHeader: '{{.ApplicationName}}邀请'
|
||||
Subject: '{{.ApplicationName}}邀请'
|
||||
Greeting: 您好,{{.DisplayName}},
|
||||
Text: 您的用户已被邀请加入{{.ApplicationName}}。请点击下面的按钮完成邀请过程。如果您没有请求此邮件,请忽略它。
|
||||
ButtonText: 接受邀请
|
31
internal/notification/types/invite_code.go
Normal file
31
internal/notification/types/invite_code.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
http_utils "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/api/ui/login"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
)
|
||||
|
||||
func (notify Notify) SendInviteCode(ctx context.Context, user *query.NotifyUser, code, applicationName, urlTmpl, authRequestID string) error {
|
||||
var url string
|
||||
if applicationName == "" {
|
||||
applicationName = "ZITADEL"
|
||||
}
|
||||
if urlTmpl == "" {
|
||||
url = login.InviteUserLink(http_utils.DomainContext(ctx).Origin(), user.ID, user.PreferredLoginName, code, user.ResourceOwner, authRequestID)
|
||||
} else {
|
||||
var buf strings.Builder
|
||||
if err := domain.RenderConfirmURLTemplate(&buf, urlTmpl, user.ID, code, user.ResourceOwner); err != nil {
|
||||
return err
|
||||
}
|
||||
url = buf.String()
|
||||
}
|
||||
args := make(map[string]interface{})
|
||||
args["Code"] = code
|
||||
args["ApplicationName"] = applicationName
|
||||
return notify(url, args, domain.InviteUserMessageType, true)
|
||||
}
|
Reference in New Issue
Block a user