mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-05 05:42:16 +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:
@@ -7,6 +7,7 @@ import {
|
||||
GetDefaultInitMessageTextRequest as AdminGetDefaultInitMessageTextRequest,
|
||||
GetDefaultPasswordChangeMessageTextRequest as AdminGetDefaultPasswordChangeMessageTextRequest,
|
||||
GetDefaultPasswordlessRegistrationMessageTextRequest as AdminGetDefaultPasswordlessRegistrationMessageTextRequest,
|
||||
GetDefaultInviteUserMessageTextRequest as AdminGetDefaultInviteUserMessageTextRequest,
|
||||
GetDefaultPasswordResetMessageTextRequest as AdminGetDefaultPasswordResetMessageTextRequest,
|
||||
GetDefaultVerifyEmailMessageTextRequest as AdminGetDefaultVerifyEmailMessageTextRequest,
|
||||
GetDefaultVerifyEmailOTPMessageTextRequest as AdminGetDefaultVerifyEmailOTPMessageTextRequest,
|
||||
@@ -16,6 +17,7 @@ import {
|
||||
SetDefaultInitMessageTextRequest,
|
||||
SetDefaultPasswordChangeMessageTextRequest,
|
||||
SetDefaultPasswordlessRegistrationMessageTextRequest,
|
||||
SetDefaultInviteUserMessageTextRequest,
|
||||
SetDefaultPasswordResetMessageTextRequest,
|
||||
SetDefaultVerifyEmailMessageTextRequest,
|
||||
SetDefaultVerifyEmailOTPMessageTextRequest,
|
||||
@@ -27,6 +29,7 @@ import {
|
||||
GetCustomInitMessageTextRequest,
|
||||
GetCustomPasswordChangeMessageTextRequest,
|
||||
GetCustomPasswordlessRegistrationMessageTextRequest,
|
||||
GetCustomInviteUserMessageTextRequest,
|
||||
GetCustomPasswordResetMessageTextRequest,
|
||||
GetCustomVerifyEmailMessageTextRequest,
|
||||
GetCustomVerifyEmailOTPMessageTextRequest,
|
||||
@@ -36,6 +39,7 @@ import {
|
||||
GetDefaultInitMessageTextRequest,
|
||||
GetDefaultPasswordChangeMessageTextRequest,
|
||||
GetDefaultPasswordlessRegistrationMessageTextRequest,
|
||||
GetDefaultInviteUserMessageTextRequest,
|
||||
GetDefaultPasswordResetMessageTextRequest,
|
||||
GetDefaultVerifyEmailMessageTextRequest,
|
||||
GetDefaultVerifyEmailOTPMessageTextRequest,
|
||||
@@ -45,6 +49,7 @@ import {
|
||||
SetCustomInitMessageTextRequest,
|
||||
SetCustomPasswordChangeMessageTextRequest,
|
||||
SetCustomPasswordlessRegistrationMessageTextRequest,
|
||||
SetCustomInviteUserMessageTextRequest,
|
||||
SetCustomPasswordResetMessageTextRequest,
|
||||
SetCustomVerifyEmailMessageTextRequest,
|
||||
SetCustomVerifyEmailOTPMessageTextRequest,
|
||||
@@ -73,6 +78,7 @@ enum MESSAGETYPES {
|
||||
PASSWORDCHANGE = 'PC',
|
||||
VERIFYSMSOTP = 'VSO',
|
||||
VERIFYEMAILOTP = 'VEO',
|
||||
INVITEUSER = 'IU',
|
||||
}
|
||||
|
||||
const REQUESTMAP = {
|
||||
@@ -226,6 +232,23 @@ const REQUESTMAP = {
|
||||
req.setText(map.text ?? '');
|
||||
req.setTitle(map.title ?? '');
|
||||
|
||||
return req;
|
||||
},
|
||||
},
|
||||
[MESSAGETYPES.INVITEUSER]: {
|
||||
get: new GetCustomInviteUserMessageTextRequest(),
|
||||
set: new SetCustomInviteUserMessageTextRequest(),
|
||||
getDefault: new GetDefaultInviteUserMessageTextRequest(),
|
||||
setFcn: (map: Partial<SetCustomInviteUserMessageTextRequest.AsObject>): SetCustomInviteUserMessageTextRequest => {
|
||||
const req = new SetCustomInviteUserMessageTextRequest();
|
||||
req.setButtonText(map.buttonText ?? '');
|
||||
req.setFooterText(map.footerText ?? '');
|
||||
req.setGreeting(map.greeting ?? '');
|
||||
req.setPreHeader(map.preHeader ?? '');
|
||||
req.setSubject(map.subject ?? '');
|
||||
req.setText(map.text ?? '');
|
||||
req.setTitle(map.title ?? '');
|
||||
|
||||
return req;
|
||||
},
|
||||
},
|
||||
@@ -371,6 +394,22 @@ const REQUESTMAP = {
|
||||
req.setText(map.text ?? '');
|
||||
req.setTitle(map.title ?? '');
|
||||
|
||||
return req;
|
||||
},
|
||||
},
|
||||
[MESSAGETYPES.INVITEUSER]: {
|
||||
get: new AdminGetDefaultInviteUserMessageTextRequest(),
|
||||
set: new SetDefaultInviteUserMessageTextRequest(),
|
||||
setFcn: (map: Partial<SetDefaultInviteUserMessageTextRequest.AsObject>): SetDefaultInviteUserMessageTextRequest => {
|
||||
const req = new SetDefaultInviteUserMessageTextRequest();
|
||||
req.setButtonText(map.buttonText ?? '');
|
||||
req.setFooterText(map.footerText ?? '');
|
||||
req.setGreeting(map.greeting ?? '');
|
||||
req.setPreHeader(map.preHeader ?? '');
|
||||
req.setSubject(map.subject ?? '');
|
||||
req.setText(map.text ?? '');
|
||||
req.setTitle(map.title ?? '');
|
||||
|
||||
return req;
|
||||
},
|
||||
},
|
||||
@@ -540,6 +579,21 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.loginnames', value: '{{.LoginNames}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.changedate', value: '{{.ChangeDate}}' },
|
||||
],
|
||||
[MESSAGETYPES.INVITEUSER]: [
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.preferredLoginName', value: '{{.PreferredLoginName}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.username', value: '{{.UserName}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.firstname', value: '{{.FirstName}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.lastname', value: '{{.LastName}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.nickName', value: '{{.NickName}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.displayName', value: '{{.DisplayName}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.lastEmail', value: '{{.LastEmail}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.verifiedEmail', value: '{{.VerifiedEmail}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.lastPhone', value: '{{.LastPhone}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.verifiedPhone', value: '{{.VerifiedPhone}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.loginnames', value: '{{.LoginNames}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.changedate', value: '{{.ChangeDate}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.applicationName', value: '{{.ApplicationName}}' },
|
||||
],
|
||||
};
|
||||
|
||||
public language: string = 'en';
|
||||
@@ -599,6 +653,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
return this.stripEmail(this.service.getDefaultPasswordlessRegistrationMessageText(req));
|
||||
case MESSAGETYPES.PASSWORDCHANGE:
|
||||
return this.stripEmail(this.service.getDefaultPasswordChangeMessageText(req));
|
||||
case MESSAGETYPES.INVITEUSER:
|
||||
return this.stripEmail(this.service.getDefaultInviteUserMessageText(req));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,6 +678,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
return this.stripEmail(this.service.getCustomPasswordlessRegistrationMessageText(req));
|
||||
case MESSAGETYPES.PASSWORDCHANGE:
|
||||
return this.stripEmail(this.service.getCustomPasswordChangeMessageText(req));
|
||||
case MESSAGETYPES.INVITEUSER:
|
||||
return this.stripEmail(this.service.getCustomInviteUserMessageText(req));
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
@@ -690,6 +748,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
case MESSAGETYPES.PASSWORDCHANGE:
|
||||
return handler((this.service as ManagementService).setCustomPasswordChangeMessageText(this.updateRequest));
|
||||
case MESSAGETYPES.INVITEUSER:
|
||||
return handler((this.service as ManagementService).setCustomInviteUserMessageText(this.updateRequest));
|
||||
}
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
switch (this.currentType) {
|
||||
@@ -711,6 +771,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
return handler((this.service as AdminService).setDefaultPasswordlessRegistrationMessageText(this.updateRequest));
|
||||
case MESSAGETYPES.PASSWORDCHANGE:
|
||||
return handler((this.service as AdminService).setDefaultPasswordChangeMessageText(this.updateRequest));
|
||||
case MESSAGETYPES.INVITEUSER:
|
||||
return handler((this.service as AdminService).setDefaultInviteUserMessageText(this.updateRequest));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -763,6 +825,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
return handler(this.service.resetCustomPasswordlessRegistrationMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.PASSWORDCHANGE:
|
||||
return handler(this.service.resetCustomPasswordChangeMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.INVITEUSER:
|
||||
return handler(this.service.resetCustomInviteUserMessageTextToDefault(this.language));
|
||||
default:
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user