mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:17:23 +00:00
feat: custom message text (#1801)
* feat: default custom message text * feat: org custom message text * feat: org custom message text * feat: custom messages query side * feat: default messages * feat: message text user fields * feat: check for inactive user * feat: fix send password reset * feat: fix custom org text * feat: add variables to docs * feat: custom text tests * feat: fix notifications * feat: add custom text feature * feat: add custom text feature * feat: feature in custom message texts * feat: add custom text feature in frontend * feat: merge main * feat: feature tests * feat: change phone message in setup * fix: remove unused code, add event translation * fix: merge main and fix problems * fix: english translation file * fix: migration versions * fix: setup * feat: fix pr requests * feat: fix phone code message * feat: migration * feat: setup * fix: remove unused tests Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
parent
67462eefe0
commit
bdf3887f9e
File diff suppressed because one or more lines are too long
@ -141,7 +141,15 @@
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="features.customDomain"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'FEATURES.DATA.CUSTOMTEXT' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="features.customText"
|
||||
[disabled]="(['iam.features.write'] | hasRole | async) == false">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
|
@ -161,6 +161,7 @@ export class FeaturesComponent implements OnDestroy {
|
||||
req.setLabelPolicyPrivateLabel(this.features.labelPolicyPrivateLabel);
|
||||
req.setLabelPolicyWatermark(this.features.labelPolicyWatermark);
|
||||
req.setCustomDomain(this.features.customDomain);
|
||||
req.setCustomText(this.features.customText);
|
||||
|
||||
this.adminService.setOrgFeatures(req).then(() => {
|
||||
this.toast.showInfo('POLICY.TOAST.SET', true);
|
||||
@ -181,6 +182,7 @@ export class FeaturesComponent implements OnDestroy {
|
||||
dreq.setLabelPolicyPrivateLabel(this.features.labelPolicyPrivateLabel);
|
||||
dreq.setLabelPolicyWatermark(this.features.labelPolicyWatermark);
|
||||
dreq.setCustomDomain(this.features.customDomain);
|
||||
dreq.setCustomText(this.features.customText);
|
||||
|
||||
this.adminService.setDefaultFeatures(dreq).then(() => {
|
||||
this.toast.showInfo('POLICY.TOAST.SET', true);
|
||||
|
@ -611,12 +611,13 @@
|
||||
"LOGINPOLICYPASSWORDRESET": "Login Richtlinie: Passwort vergessen Link nicht anzeigen - benutzerdefiniert",
|
||||
"LOGINPOLICYREGISTRATION": "Login Richtlinie: Registration erlauben - benutzerdefiniert",
|
||||
"LOGINPOLICYIDP": "Login Richtlinie: Identity Providers - benutzerdefiniert",
|
||||
"LOGINPOLICYFACTORS": "Login Richtlinie: Mltifaktoren - benutzerdefiniert",
|
||||
"LOGINPOLICYFACTORS": "Login Richtlinie: Multifaktoren - benutzerdefiniert",
|
||||
"LOGINPOLICYPASSWORDLESS": "Login Richtlinie: Passwortlose Authentifizierung - benutzerdefiniert",
|
||||
"LOGINPOLICYCOMPLEXITYPOLICY": "Passwortkomplexitäts Richtlinie - benutzerdefiniert",
|
||||
"LABELPOLICYPRIVATELABEL": "Label Richtlinie - benutzerdefiniert",
|
||||
"LABELPOLICYWATERMARK": "Label Richtlinie - Wasserzeichen",
|
||||
"CUSTOMDOMAIN": "Domänen Verifikation - verfügbar"
|
||||
"CUSTOMDOMAIN": "Domänen Verifikation - verfügbar",
|
||||
"CUSTOMTEXT": "Benutzerdefinierte Texte"
|
||||
},
|
||||
"TIERSTATES": {
|
||||
"0": "Aktiv",
|
||||
|
@ -616,7 +616,8 @@
|
||||
"LOGINPOLICYCOMPLEXITYPOLICY": "Password Complexity Policy - custom",
|
||||
"LABELPOLICYPRIVATELABEL": "Label Richtlinie - benutzerdefiniert",
|
||||
"LABELPOLICYWATERMARK": "Label Richtlinie - Wasserzeichen",
|
||||
"CUSTOMDOMAIN": "Domain Verification - available"
|
||||
"CUSTOMDOMAIN": "Domain Verification - available",
|
||||
"CUSTOMTEXT": "Custom texts"
|
||||
},
|
||||
"TIERSTATES": {
|
||||
"0": "Active",
|
||||
|
@ -528,6 +528,121 @@ it impacts all organisations without a customised policy
|
||||
|
||||
|
||||
|
||||
### GetDefaultInitMessageText
|
||||
|
||||
> **rpc** GetDefaultInitMessageText([GetDefaultInitMessageTextRequest](#getdefaultinitmessagetextrequest))
|
||||
[GetDefaultInitMessageTextResponse](#getdefaultinitmessagetextresponse)
|
||||
|
||||
Returns the custom text for initial message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultInitMessageText
|
||||
|
||||
> **rpc** SetDefaultInitMessageText([SetDefaultInitMessageTextRequest](#setdefaultinitmessagetextrequest))
|
||||
[SetDefaultInitMessageTextResponse](#setdefaultinitmessagetextresponse)
|
||||
|
||||
Sets the default custom text for initial message
|
||||
it impacts all organisations without customized initial message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultPasswordResetMessageText
|
||||
|
||||
> **rpc** GetDefaultPasswordResetMessageText([GetDefaultPasswordResetMessageTextRequest](#getdefaultpasswordresetmessagetextrequest))
|
||||
[GetDefaultPasswordResetMessageTextResponse](#getdefaultpasswordresetmessagetextresponse)
|
||||
|
||||
Returns the custom text for password reset message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultPasswordResetMessageText
|
||||
|
||||
> **rpc** SetDefaultPasswordResetMessageText([SetDefaultPasswordResetMessageTextRequest](#setdefaultpasswordresetmessagetextrequest))
|
||||
[SetDefaultPasswordResetMessageTextResponse](#setdefaultpasswordresetmessagetextresponse)
|
||||
|
||||
Sets the default custom text for password reset message
|
||||
it impacts all organisations without customized password reset message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultVerifyEmailMessageText
|
||||
|
||||
> **rpc** GetDefaultVerifyEmailMessageText([GetDefaultVerifyEmailMessageTextRequest](#getdefaultverifyemailmessagetextrequest))
|
||||
[GetDefaultVerifyEmailMessageTextResponse](#getdefaultverifyemailmessagetextresponse)
|
||||
|
||||
Returns the custom text for verify email message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultVerifyEmailMessageText
|
||||
|
||||
> **rpc** SetDefaultVerifyEmailMessageText([SetDefaultVerifyEmailMessageTextRequest](#setdefaultverifyemailmessagetextrequest))
|
||||
[SetDefaultVerifyEmailMessageTextResponse](#setdefaultverifyemailmessagetextresponse)
|
||||
|
||||
Sets the default custom text for verify email message
|
||||
it impacts all organisations without customized verify email message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultVerifyPhoneMessageText
|
||||
|
||||
> **rpc** GetDefaultVerifyPhoneMessageText([GetDefaultVerifyPhoneMessageTextRequest](#getdefaultverifyphonemessagetextrequest))
|
||||
[GetDefaultVerifyPhoneMessageTextResponse](#getdefaultverifyphonemessagetextresponse)
|
||||
|
||||
Returns the custom text for verify phone message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultVerifyPhoneMessageText
|
||||
|
||||
> **rpc** SetDefaultVerifyPhoneMessageText([SetDefaultVerifyPhoneMessageTextRequest](#setdefaultverifyphonemessagetextrequest))
|
||||
[SetDefaultVerifyPhoneMessageTextResponse](#setdefaultverifyphonemessagetextresponse)
|
||||
|
||||
Sets the default custom text for verify phone message
|
||||
it impacts all organisations without customized verify phone message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultDomainClaimedMessageText
|
||||
|
||||
> **rpc** GetDefaultDomainClaimedMessageText([GetDefaultDomainClaimedMessageTextRequest](#getdefaultdomainclaimedmessagetextrequest))
|
||||
[GetDefaultDomainClaimedMessageTextResponse](#getdefaultdomainclaimedmessagetextresponse)
|
||||
|
||||
Returns the custom text for domain claimed message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultDomainClaimedMessageText
|
||||
|
||||
> **rpc** SetDefaultDomainClaimedMessageText([SetDefaultDomainClaimedMessageTextRequest](#setdefaultdomainclaimedmessagetextrequest))
|
||||
[SetDefaultDomainClaimedMessageTextResponse](#setdefaultdomainclaimedmessagetextresponse)
|
||||
|
||||
Sets the default custom text for domain claimed phone message
|
||||
it impacts all organisations without customized verify phone message text
|
||||
The Following Variables can be used:
|
||||
{{.Domain}} {{.TempUsername}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### ListIAMMemberRoles
|
||||
|
||||
> **rpc** ListIAMMemberRoles([ListIAMMemberRolesRequest](#listiammemberrolesrequest))
|
||||
@ -877,6 +992,28 @@ This is an empty response
|
||||
|
||||
|
||||
|
||||
### GetDefaultDomainClaimedMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultDomainClaimedMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultFeaturesRequest
|
||||
|
||||
|
||||
@ -894,6 +1031,94 @@ This is an empty response
|
||||
|
||||
|
||||
|
||||
### GetDefaultInitMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultInitMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultPasswordResetMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultPasswordResetMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultVerifyEmailMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultVerifyEmailMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultVerifyPhoneMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultVerifyPhoneMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetIDPByIDRequest
|
||||
|
||||
|
||||
@ -1593,6 +1818,35 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### SetDefaultDomainClaimedMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultDomainClaimedMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultFeaturesRequest
|
||||
|
||||
|
||||
@ -1613,6 +1867,7 @@ This is an empty request
|
||||
| login_policy_password_reset | bool | - | |
|
||||
| label_policy_private_label | bool | - | |
|
||||
| label_policy_watermark | bool | - | |
|
||||
| custom_text | bool | - | |
|
||||
|
||||
|
||||
|
||||
@ -1628,6 +1883,122 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### SetDefaultInitMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 1000<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultInitMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultPasswordResetMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultPasswordResetMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultVerifyEmailMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultVerifyEmailMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultVerifyPhoneMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetDefaultVerifyPhoneMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetOrgFeaturesRequest
|
||||
|
||||
|
||||
@ -1651,6 +2022,7 @@ This is an empty request
|
||||
| login_policy_password_reset | bool | - | |
|
||||
| label_policy_private_label | bool | - | |
|
||||
| label_policy_watermark | bool | - | |
|
||||
| custom_text | bool | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -1712,6 +1712,176 @@ The default policy of the IAM will trigger after
|
||||
|
||||
|
||||
|
||||
### GetCustomInitMessageText
|
||||
|
||||
> **rpc** GetCustomInitMessageText([GetCustomInitMessageTextRequest](#getcustominitmessagetextrequest))
|
||||
[GetCustomInitMessageTextResponse](#getcustominitmessagetextresponse)
|
||||
|
||||
Returns the custom text for initial message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomInitMessageText
|
||||
|
||||
> **rpc** SetCustomInitMessageText([SetCustomInitMessageTextRequest](#setcustominitmessagetextrequest))
|
||||
[SetCustomInitMessageTextResponse](#setcustominitmessagetextresponse)
|
||||
|
||||
Sets the default custom text for initial message
|
||||
it impacts all organisations without customized initial message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomInitMessageTextToDefault
|
||||
|
||||
> **rpc** ResetCustomInitMessageTextToDefault([ResetCustomInitMessageTextToDefaultRequest](#resetcustominitmessagetexttodefaultrequest))
|
||||
[ResetCustomInitMessageTextToDefaultResponse](#resetcustominitmessagetexttodefaultresponse)
|
||||
|
||||
Removes the custom init message text of the organisation
|
||||
The default text of the IAM will trigger after
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomPasswordResetMessageText
|
||||
|
||||
> **rpc** GetCustomPasswordResetMessageText([GetCustomPasswordResetMessageTextRequest](#getcustompasswordresetmessagetextrequest))
|
||||
[GetCustomPasswordResetMessageTextResponse](#getcustompasswordresetmessagetextresponse)
|
||||
|
||||
Returns the custom text for password reset message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomPasswordResetMessageText
|
||||
|
||||
> **rpc** SetCustomPasswordResetMessageText([SetCustomPasswordResetMessageTextRequest](#setcustompasswordresetmessagetextrequest))
|
||||
[SetCustomPasswordResetMessageTextResponse](#setcustompasswordresetmessagetextresponse)
|
||||
|
||||
Sets the default custom text for password reset message
|
||||
it impacts all organisations without customized password reset message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomPasswordResetMessageTextToDefault
|
||||
|
||||
> **rpc** ResetCustomPasswordResetMessageTextToDefault([ResetCustomPasswordResetMessageTextToDefaultRequest](#resetcustompasswordresetmessagetexttodefaultrequest))
|
||||
[ResetCustomPasswordResetMessageTextToDefaultResponse](#resetcustompasswordresetmessagetexttodefaultresponse)
|
||||
|
||||
Removes the custom init message text of the organisation
|
||||
The default text of the IAM will trigger after
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomVerifyEmailMessageText
|
||||
|
||||
> **rpc** GetCustomVerifyEmailMessageText([GetCustomVerifyEmailMessageTextRequest](#getcustomverifyemailmessagetextrequest))
|
||||
[GetCustomVerifyEmailMessageTextResponse](#getcustomverifyemailmessagetextresponse)
|
||||
|
||||
Returns the custom text for verify email message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomVerifyEmailMessageText
|
||||
|
||||
> **rpc** SetCustomVerifyEmailMessageText([SetCustomVerifyEmailMessageTextRequest](#setcustomverifyemailmessagetextrequest))
|
||||
[SetCustomVerifyEmailMessageTextResponse](#setcustomverifyemailmessagetextresponse)
|
||||
|
||||
Sets the default custom text for verify email message
|
||||
it impacts all organisations without customized verify email message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomVerifyEmailMessageTextToDefault
|
||||
|
||||
> **rpc** ResetCustomVerifyEmailMessageTextToDefault([ResetCustomVerifyEmailMessageTextToDefaultRequest](#resetcustomverifyemailmessagetexttodefaultrequest))
|
||||
[ResetCustomVerifyEmailMessageTextToDefaultResponse](#resetcustomverifyemailmessagetexttodefaultresponse)
|
||||
|
||||
Removes the custom init message text of the organisation
|
||||
The default text of the IAM will trigger after
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomVerifyPhoneMessageText
|
||||
|
||||
> **rpc** GetCustomVerifyPhoneMessageText([GetCustomVerifyPhoneMessageTextRequest](#getcustomverifyphonemessagetextrequest))
|
||||
[GetCustomVerifyPhoneMessageTextResponse](#getcustomverifyphonemessagetextresponse)
|
||||
|
||||
Returns the custom text for verify email message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomVerifyPhoneMessageText
|
||||
|
||||
> **rpc** SetCustomVerifyPhoneMessageText([SetCustomVerifyPhoneMessageTextRequest](#setcustomverifyphonemessagetextrequest))
|
||||
[SetCustomVerifyPhoneMessageTextResponse](#setcustomverifyphonemessagetextresponse)
|
||||
|
||||
Sets the default custom text for verify email message
|
||||
it impacts all organisations without customized verify email message text
|
||||
The Following Variables can be used:
|
||||
{{.Code}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomVerifyPhoneMessageTextToDefault
|
||||
|
||||
> **rpc** ResetCustomVerifyPhoneMessageTextToDefault([ResetCustomVerifyPhoneMessageTextToDefaultRequest](#resetcustomverifyphonemessagetexttodefaultrequest))
|
||||
[ResetCustomVerifyPhoneMessageTextToDefaultResponse](#resetcustomverifyphonemessagetexttodefaultresponse)
|
||||
|
||||
Removes the custom init message text of the organisation
|
||||
The default text of the IAM will trigger after
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomDomainClaimedMessageText
|
||||
|
||||
> **rpc** GetCustomDomainClaimedMessageText([GetCustomDomainClaimedMessageTextRequest](#getcustomdomainclaimedmessagetextrequest))
|
||||
[GetCustomDomainClaimedMessageTextResponse](#getcustomdomainclaimedmessagetextresponse)
|
||||
|
||||
Returns the custom text for domain claimed message
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomDomainClaimedMessageCustomText
|
||||
|
||||
> **rpc** SetCustomDomainClaimedMessageCustomText([SetCustomDomainClaimedMessageTextRequest](#setcustomdomainclaimedmessagetextrequest))
|
||||
[SetCustomDomainClaimedMessageTextResponse](#setcustomdomainclaimedmessagetextresponse)
|
||||
|
||||
Sets the default custom text for domain claimed message
|
||||
it impacts all organisations without customized domain claimed message text
|
||||
The Following Variables can be used:
|
||||
{{.Domain}} {{.TempUsername}} {{.UserName}} {{.FirstName}} {{.LastName}} {{.NickName}} {{.DisplayName}} {{.LastEmail}} {{.VerifiedEmail}} {{.LastPhone}} {{.VerifiedPhone}} {{.PreferredLoginName}} {{.LoginNames}} {{.ChangeDate}}
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomDomainClaimedMessageTextToDefault
|
||||
|
||||
> **rpc** ResetCustomDomainClaimedMessageTextToDefault([ResetCustomDomainClaimedMessageTextToDefaultRequest](#resetcustomdomainclaimedmessagetexttodefaultrequest))
|
||||
[ResetCustomDomainClaimedMessageTextToDefaultResponse](#resetcustomdomainclaimedmessagetexttodefaultresponse)
|
||||
|
||||
Removes the custom init message text of the organisation
|
||||
The default text of the IAM will trigger after
|
||||
|
||||
|
||||
|
||||
|
||||
### GetOrgIDPByID
|
||||
|
||||
> **rpc** GetOrgIDPByID([GetOrgIDPByIDRequest](#getorgidpbyidrequest))
|
||||
@ -2758,6 +2928,116 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### GetCustomDomainClaimedMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomDomainClaimedMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomInitMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomInitMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomPasswordResetMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomPasswordResetMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomVerifyEmailMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomVerifyEmailMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomVerifyPhoneMessageTextRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetCustomVerifyPhoneMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| custom_text | zitadel.text.v1.MessageCustomText | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetDefaultLabelPolicyRequest
|
||||
This is an empty request
|
||||
|
||||
@ -4972,6 +5252,116 @@ This is an empty response
|
||||
|
||||
|
||||
|
||||
### ResetCustomDomainClaimedMessageTextToDefaultRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomDomainClaimedMessageTextToDefaultResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomInitMessageTextToDefaultRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomInitMessageTextToDefaultResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomPasswordResetMessageTextToDefaultRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomPasswordResetMessageTextToDefaultResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomVerifyEmailMessageTextToDefaultRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomVerifyEmailMessageTextToDefaultResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomVerifyPhoneMessageTextToDefaultRequest
|
||||
This is an empty request
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetCustomVerifyPhoneMessageTextToDefaultResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ResetLabelPolicyToDefaultRequest
|
||||
This is an empty request
|
||||
|
||||
@ -5080,6 +5470,151 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### SetCustomDomainClaimedMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomDomainClaimedMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomInitMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomInitMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomPasswordResetMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomPasswordResetMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomVerifyEmailMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomVerifyEmailMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomVerifyPhoneMessageTextRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| title | string | - | string.max_len: 200<br /> |
|
||||
| pre_header | string | - | string.max_len: 200<br /> |
|
||||
| subject | string | - | string.max_len: 200<br /> |
|
||||
| greeting | string | - | string.max_len: 200<br /> |
|
||||
| text | string | - | string.max_len: 800<br /> |
|
||||
| button_text | string | - | string.max_len: 200<br /> |
|
||||
| footer_text | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetCustomVerifyPhoneMessageTextResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### SetHumanInitialPasswordRequest
|
||||
|
||||
|
||||
|
@ -2,16 +2,18 @@ package eventstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
"strings"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
@ -347,21 +349,21 @@ func (repo *IAMRepository) SearchIAMMembersx(ctx context.Context, request *iam_m
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) GetDefaultMailTexts(ctx context.Context) (*iam_model.MailTextsView, error) {
|
||||
text, err := repo.View.MailTexts(repo.SystemDefaults.IamID)
|
||||
func (repo *IAMRepository) GetDefaultMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error) {
|
||||
text, err := repo.View.MessageTexts(repo.SystemDefaults.IamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_es_model.MailTextsViewToModel(text, true), err
|
||||
return iam_es_model.MessageTextsViewToModel(text, true), err
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) GetDefaultMailText(ctx context.Context, textType string, language string) (*iam_model.MailTextView, error) {
|
||||
text, err := repo.View.MailTextByIDs(repo.SystemDefaults.IamID, textType, language)
|
||||
func (repo *IAMRepository) GetDefaultMessageText(ctx context.Context, textType, lang string) (*iam_model.MessageTextView, error) {
|
||||
text, err := repo.View.MessageTextByIDs(repo.SystemDefaults.IamID, textType, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
text.Default = true
|
||||
return iam_es_model.MailTextViewToModel(text), err
|
||||
return iam_es_model.MessageTextViewToModel(text), err
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) getIAMEvents(ctx context.Context, sequence uint64) ([]*models.Event, error) {
|
||||
|
@ -62,8 +62,8 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
|
||||
defaults),
|
||||
newMailTemplate(
|
||||
handler{view, bulkLimit, configs.cycleDuration("MailTemplate"), errorCount, es}),
|
||||
newMailText(
|
||||
handler{view, bulkLimit, configs.cycleDuration("MailText"), errorCount, es}),
|
||||
newMessageText(
|
||||
handler{view, bulkLimit, configs.cycleDuration("MessageText"), errorCount, es}),
|
||||
newFeatures(
|
||||
handler{view, bulkLimit, configs.cycleDuration("Features"), errorCount, es}),
|
||||
}
|
||||
|
@ -1,108 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
)
|
||||
|
||||
type MailText struct {
|
||||
handler
|
||||
subscription *v1.Subscription
|
||||
}
|
||||
|
||||
func newMailText(handler handler) *MailText {
|
||||
h := &MailText{
|
||||
handler: handler,
|
||||
}
|
||||
|
||||
h.subscribe()
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (m *MailText) subscribe() {
|
||||
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
|
||||
go func() {
|
||||
for event := range m.subscription.Events {
|
||||
query.ReduceEvent(m, event)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
const (
|
||||
mailTextTable = "adminapi.mail_texts"
|
||||
)
|
||||
|
||||
func (m *MailText) ViewModel() string {
|
||||
return mailTextTable
|
||||
}
|
||||
|
||||
func (_ *MailText) AggregateTypes() []es_models.AggregateType {
|
||||
return []es_models.AggregateType{iam_es_model.IAMAggregate}
|
||||
}
|
||||
|
||||
func (p *MailText) CurrentSequence() (uint64, error) {
|
||||
sequence, err := p.view.GetLatestMailTextSequence()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return sequence.CurrentSequence, nil
|
||||
}
|
||||
|
||||
func (m *MailText) EventQuery() (*es_models.SearchQuery, error) {
|
||||
sequence, err := m.view.GetLatestMailTextSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(m.AggregateTypes()...).
|
||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
||||
}
|
||||
|
||||
func (m *MailText) Reduce(event *es_models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case model.IAMAggregate:
|
||||
err = m.processMailText(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *MailText) processMailText(event *es_models.Event) (err error) {
|
||||
mailText := new(iam_model.MailTextView)
|
||||
switch event.Type {
|
||||
case model.MailTextAdded:
|
||||
err = mailText.AppendEvent(event)
|
||||
case model.MailTextChanged:
|
||||
err = mailText.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mailText, err = m.view.MailTextByIDs(event.AggregateID, mailText.MailTextType, mailText.Language)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = mailText.AppendEvent(event)
|
||||
default:
|
||||
return m.view.ProcessedMailTextSequence(event)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.PutMailText(mailText, event)
|
||||
}
|
||||
|
||||
func (m *MailText) OnError(event *es_models.Event, err error) error {
|
||||
logging.LogWithFields("HANDL-5jk84", "id", event.AggregateID).WithError(err).Warn("something went wrong in label mailText handler")
|
||||
return spooler.HandleError(event, err, m.view.GetLatestMailTextFailedEvent, m.view.ProcessedMailTextFailedEvent, m.view.ProcessedMailTextSequence, m.errorCountUntilSkip)
|
||||
}
|
||||
|
||||
func (o *MailText) OnSuccess() error {
|
||||
return spooler.HandleSuccess(o.view.UpdateMailTextSpoolerRunTimestamp)
|
||||
}
|
116
internal/admin/repository/eventsourcing/handler/message_text.go
Normal file
116
internal/admin/repository/eventsourcing/handler/message_text.go
Normal file
@ -0,0 +1,116 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
)
|
||||
|
||||
type MessageText struct {
|
||||
handler
|
||||
subscription *v1.Subscription
|
||||
}
|
||||
|
||||
func newMessageText(handler handler) *MessageText {
|
||||
h := &MessageText{
|
||||
handler: handler,
|
||||
}
|
||||
|
||||
h.subscribe()
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (m *MessageText) subscribe() {
|
||||
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
|
||||
go func() {
|
||||
for event := range m.subscription.Events {
|
||||
query.ReduceEvent(m, event)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
const (
|
||||
mailTextTable = "adminapi.message_texts"
|
||||
)
|
||||
|
||||
func (m *MessageText) ViewModel() string {
|
||||
return mailTextTable
|
||||
}
|
||||
|
||||
func (_ *MessageText) AggregateTypes() []es_models.AggregateType {
|
||||
return []es_models.AggregateType{iam_es_model.IAMAggregate}
|
||||
}
|
||||
|
||||
func (p *MessageText) CurrentSequence() (uint64, error) {
|
||||
sequence, err := p.view.GetLatestMessageTextSequence()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return sequence.CurrentSequence, nil
|
||||
}
|
||||
|
||||
func (m *MessageText) EventQuery() (*es_models.SearchQuery, error) {
|
||||
sequence, err := m.view.GetLatestMessageTextSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(m.AggregateTypes()...).
|
||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
||||
}
|
||||
|
||||
func (m *MessageText) Reduce(event *es_models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case model.IAMAggregate:
|
||||
err = m.processMessageText(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *MessageText) processMessageText(event *es_models.Event) (err error) {
|
||||
message := new(iam_model.MessageTextView)
|
||||
switch event.Type {
|
||||
case model.CustomTextSet,
|
||||
model.CustomTextRemoved:
|
||||
text := new(iam_model.CustomText)
|
||||
err = text.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
message, err = m.view.MessageTextByIDs(event.AggregateID, text.Template, text.Language.String())
|
||||
if err != nil && !caos_errs.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
if caos_errs.IsNotFound(err) {
|
||||
err = nil
|
||||
message = new(iam_model.MessageTextView)
|
||||
message.Language = text.Language.String()
|
||||
message.MessageTextType = text.Template
|
||||
message.CreationDate = event.CreationDate
|
||||
}
|
||||
err = message.AppendEvent(event)
|
||||
default:
|
||||
return m.view.ProcessedMessageTextSequence(event)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.PutMessageText(message, event)
|
||||
}
|
||||
|
||||
func (m *MessageText) OnError(event *es_models.Event, err error) error {
|
||||
logging.LogWithFields("HANDL-5jk84", "id", event.AggregateID).WithError(err).Warn("something went wrong in label mailText handler")
|
||||
return spooler.HandleError(event, err, m.view.GetLatestMessageTextFailedEvent, m.view.ProcessedMessageTextFailedEvent, m.view.ProcessedMessageTextSequence, m.errorCountUntilSkip)
|
||||
}
|
||||
|
||||
func (o *MessageText) OnSuccess() error {
|
||||
return spooler.HandleSuccess(o.view.UpdateMessageTextSpoolerRunTimestamp)
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
global_view "github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
mailTextTable = "adminapi.mail_texts"
|
||||
)
|
||||
|
||||
func (v *View) MailTexts(aggregateID string) ([]*model.MailTextView, error) {
|
||||
return view.GetMailTexts(v.Db, mailTextTable, aggregateID)
|
||||
}
|
||||
|
||||
func (v *View) MailTextByIDs(aggregateID string, textType string, language string) (*model.MailTextView, error) {
|
||||
return view.GetMailTextByIDs(v.Db, mailTextTable, aggregateID, textType, language)
|
||||
}
|
||||
|
||||
func (v *View) PutMailText(template *model.MailTextView, event *models.Event) error {
|
||||
err := view.PutMailText(v.Db, mailTextTable, template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedMailTextSequence(event)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMailTextSequence() (*global_view.CurrentSequence, error) {
|
||||
return v.latestSequence(mailTextTable)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMailTextSequence(event *models.Event) error {
|
||||
return v.saveCurrentSequence(mailTextTable, event)
|
||||
}
|
||||
|
||||
func (v *View) UpdateMailTextSpoolerRunTimestamp() error {
|
||||
return v.updateSpoolerRunSequence(mailTextTable)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMailTextFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||
return v.latestFailedEvent(mailTextTable, sequence)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMailTextFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||
return v.saveFailedEvent(failedEvent)
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
global_view "github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
messageTextTable = "adminapi.message_texts"
|
||||
)
|
||||
|
||||
func (v *View) MessageTexts(aggregateID string) ([]*model.MessageTextView, error) {
|
||||
return view.GetMessageTexts(v.Db, messageTextTable, aggregateID)
|
||||
}
|
||||
|
||||
func (v *View) MessageTextByIDs(aggregateID, textType, lang string) (*model.MessageTextView, error) {
|
||||
return view.GetMessageTextByIDs(v.Db, messageTextTable, aggregateID, textType, lang)
|
||||
}
|
||||
|
||||
func (v *View) PutMessageText(template *model.MessageTextView, event *models.Event) error {
|
||||
err := view.PutMessageText(v.Db, messageTextTable, template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedMessageTextSequence(event)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMessageTextSequence() (*global_view.CurrentSequence, error) {
|
||||
return v.latestSequence(messageTextTable)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMessageTextSequence(event *models.Event) error {
|
||||
return v.saveCurrentSequence(messageTextTable, event)
|
||||
}
|
||||
|
||||
func (v *View) UpdateMessageTextSpoolerRunTimestamp() error {
|
||||
return v.updateSpoolerRunSequence(messageTextTable)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMessageTextFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||
return v.latestFailedEvent(messageTextTable, sequence)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMessageTextFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||
return v.saveFailedEvent(failedEvent)
|
||||
}
|
@ -28,8 +28,8 @@ type IAMRepository interface {
|
||||
|
||||
GetDefaultMailTemplate(ctx context.Context) (*iam_model.MailTemplateView, error)
|
||||
|
||||
GetDefaultMailTexts(ctx context.Context) (*iam_model.MailTextsView, error)
|
||||
GetDefaultMailText(ctx context.Context, textType string, language string) (*iam_model.MailTextView, error)
|
||||
GetDefaultMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error)
|
||||
GetDefaultMessageText(ctx context.Context, textType string, language string) (*iam_model.MessageTextView, error)
|
||||
|
||||
GetDefaultPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error)
|
||||
|
||||
|
130
internal/api/grpc/admin/custom_text.go
Normal file
130
internal/api/grpc/admin/custom_text.go
Normal file
@ -0,0 +1,130 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||
text_grpc "github.com/caos/zitadel/internal/api/grpc/text"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
admin_pb "github.com/caos/zitadel/pkg/grpc/admin"
|
||||
)
|
||||
|
||||
func (s *Server) GetDefaultInitMessageText(ctx context.Context, req *admin_pb.GetDefaultInitMessageTextRequest) (*admin_pb.GetDefaultInitMessageTextResponse, error) {
|
||||
msg, err := s.iam.GetDefaultMessageText(ctx, domain.InitCodeMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetDefaultInitMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetDefaultInitMessageText(ctx context.Context, req *admin_pb.SetDefaultInitMessageTextRequest) (*admin_pb.SetDefaultInitMessageTextResponse, error) {
|
||||
result, err := s.command.SetDefaultMessageText(ctx, SetInitCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.SetDefaultInitMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultPasswordResetMessageText(ctx context.Context, req *admin_pb.GetDefaultPasswordResetMessageTextRequest) (*admin_pb.GetDefaultPasswordResetMessageTextResponse, error) {
|
||||
msg, err := s.iam.GetDefaultMessageText(ctx, domain.PasswordResetMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetDefaultPasswordResetMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetDefaultPasswordResetMessageText(ctx context.Context, req *admin_pb.SetDefaultPasswordResetMessageTextRequest) (*admin_pb.SetDefaultPasswordResetMessageTextResponse, error) {
|
||||
result, err := s.command.SetDefaultMessageText(ctx, SetPasswordResetCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.SetDefaultPasswordResetMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultVerifyEmailMessageText(ctx context.Context, req *admin_pb.GetDefaultVerifyEmailMessageTextRequest) (*admin_pb.GetDefaultVerifyEmailMessageTextResponse, error) {
|
||||
msg, err := s.iam.GetDefaultMessageText(ctx, domain.VerifyEmailMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetDefaultVerifyEmailMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetVerifyEmailMessageCustomText(ctx context.Context, req *admin_pb.SetDefaultVerifyEmailMessageTextRequest) (*admin_pb.SetDefaultVerifyEmailMessageTextResponse, error) {
|
||||
result, err := s.command.SetDefaultMessageText(ctx, SetVerifyEmailCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.SetDefaultVerifyEmailMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultVerifyPhoneMessageText(ctx context.Context, req *admin_pb.GetDefaultVerifyPhoneMessageTextRequest) (*admin_pb.GetDefaultVerifyPhoneMessageTextResponse, error) {
|
||||
msg, err := s.iam.GetDefaultMessageText(ctx, domain.VerifyPhoneMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetDefaultVerifyPhoneMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetDefaultVerifyPhoneMessageText(ctx context.Context, req *admin_pb.SetDefaultVerifyPhoneMessageTextRequest) (*admin_pb.SetDefaultVerifyPhoneMessageTextResponse, error) {
|
||||
result, err := s.command.SetDefaultMessageText(ctx, SetVerifyPhoneCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.SetDefaultVerifyPhoneMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultDomainClaimedMessageText(ctx context.Context, req *admin_pb.GetDefaultDomainClaimedMessageTextRequest) (*admin_pb.GetDefaultDomainClaimedMessageTextResponse, error) {
|
||||
msg, err := s.iam.GetDefaultMessageText(ctx, domain.DomainClaimedMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetDefaultDomainClaimedMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetDefaultDomainClaimedMessageText(ctx context.Context, req *admin_pb.SetDefaultDomainClaimedMessageTextRequest) (*admin_pb.SetDefaultDomainClaimedMessageTextResponse, error) {
|
||||
result, err := s.command.SetDefaultMessageText(ctx, SetDomainClaimedCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.SetDefaultDomainClaimedMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
83
internal/api/grpc/admin/custom_text_converter.go
Normal file
83
internal/api/grpc/admin/custom_text_converter.go
Normal file
@ -0,0 +1,83 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
admin_pb "github.com/caos/zitadel/pkg/grpc/admin"
|
||||
)
|
||||
|
||||
func SetInitCustomTextToDomain(msg *admin_pb.SetDefaultInitMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.InitCodeMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetPasswordResetCustomTextToDomain(msg *admin_pb.SetDefaultPasswordResetMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.PasswordResetMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetVerifyEmailCustomTextToDomain(msg *admin_pb.SetDefaultVerifyEmailMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.VerifyEmailMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetVerifyPhoneCustomTextToDomain(msg *admin_pb.SetDefaultVerifyPhoneMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.VerifyPhoneMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetDomainClaimedCustomTextToDomain(msg *admin_pb.SetDefaultDomainClaimedMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.DomainClaimedMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
@ -74,6 +74,7 @@ func setDefaultFeaturesRequestToDomain(req *admin_pb.SetDefaultFeaturesRequest)
|
||||
LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: req.LabelPolicyWatermark,
|
||||
CustomDomain: req.CustomDomain,
|
||||
CustomText: req.CustomText,
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,5 +95,6 @@ func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.
|
||||
LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: req.LabelPolicyWatermark,
|
||||
CustomDomain: req.CustomDomain,
|
||||
CustomText: req.CustomText,
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ func FeaturesFromModel(features *features_model.FeaturesView) *features_pb.Featu
|
||||
CustomDomain: features.CustomDomain,
|
||||
LabelPolicyPrivateLabel: features.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: features.LabelPolicyWatermark,
|
||||
CustomText: features.CustomText,
|
||||
}
|
||||
}
|
||||
|
||||
|
131
internal/api/grpc/management/custom_text.go
Normal file
131
internal/api/grpc/management/custom_text.go
Normal file
@ -0,0 +1,131 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||
text_grpc "github.com/caos/zitadel/internal/api/grpc/text"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
mgmt_pb "github.com/caos/zitadel/pkg/grpc/management"
|
||||
)
|
||||
|
||||
func (s *Server) GetCustomInitMessageText(ctx context.Context, req *mgmt_pb.GetCustomInitMessageTextRequest) (*mgmt_pb.GetCustomInitMessageTextResponse, error) {
|
||||
msg, err := s.org.GetMessageText(ctx, authz.GetCtxData(ctx).OrgID, domain.InitCodeMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetCustomInitMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetCustomInitMessageText(ctx context.Context, req *mgmt_pb.SetCustomInitMessageTextRequest) (*mgmt_pb.SetCustomInitMessageTextResponse, error) {
|
||||
result, err := s.command.SetOrgMessageText(ctx, authz.GetCtxData(ctx).OrgID, SetInitCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.SetCustomInitMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetCustomPasswordResetMessageText(ctx context.Context, req *mgmt_pb.GetCustomPasswordResetMessageTextRequest) (*mgmt_pb.GetCustomPasswordResetMessageTextResponse, error) {
|
||||
msg, err := s.org.GetMessageText(ctx, authz.GetCtxData(ctx).OrgID, domain.PasswordResetMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetCustomPasswordResetMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetCustomPasswordResetMessageText(ctx context.Context, req *mgmt_pb.SetCustomPasswordResetMessageTextRequest) (*mgmt_pb.SetCustomPasswordResetMessageTextResponse, error) {
|
||||
result, err := s.command.SetOrgMessageText(ctx, authz.GetCtxData(ctx).OrgID, SetPasswordResetCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.SetCustomPasswordResetMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetCustomVerifyEmailMessageText(ctx context.Context, req *mgmt_pb.GetCustomVerifyEmailMessageTextRequest) (*mgmt_pb.GetCustomVerifyEmailMessageTextResponse, error) {
|
||||
msg, err := s.org.GetMessageText(ctx, authz.GetCtxData(ctx).OrgID, domain.VerifyEmailMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetCustomVerifyEmailMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetCustomVerifyEmailMessageText(ctx context.Context, req *mgmt_pb.SetCustomVerifyEmailMessageTextRequest) (*mgmt_pb.SetCustomVerifyEmailMessageTextResponse, error) {
|
||||
result, err := s.command.SetOrgMessageText(ctx, authz.GetCtxData(ctx).OrgID, SetVerifyEmailCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.SetCustomVerifyEmailMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetCustomVerifyPhoneMessageText(ctx context.Context, req *mgmt_pb.GetCustomVerifyPhoneMessageTextRequest) (*mgmt_pb.GetCustomVerifyPhoneMessageTextResponse, error) {
|
||||
msg, err := s.org.GetMessageText(ctx, authz.GetCtxData(ctx).OrgID, domain.VerifyPhoneMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetCustomVerifyPhoneMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetCustomVerifyPhoneMessageText(ctx context.Context, req *mgmt_pb.SetCustomVerifyPhoneMessageTextRequest) (*mgmt_pb.SetCustomVerifyPhoneMessageTextResponse, error) {
|
||||
result, err := s.command.SetOrgMessageText(ctx, authz.GetCtxData(ctx).OrgID, SetVerifyPhoneCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.SetCustomVerifyPhoneMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetCustomDomainClaimedMessageText(ctx context.Context, req *mgmt_pb.GetCustomDomainClaimedMessageTextRequest) (*mgmt_pb.GetCustomDomainClaimedMessageTextResponse, error) {
|
||||
msg, err := s.org.GetMessageText(ctx, authz.GetCtxData(ctx).OrgID, domain.DomainClaimedMessageType, req.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetCustomDomainClaimedMessageTextResponse{
|
||||
CustomText: text_grpc.ModelCustomMsgTextToPb(msg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetCustomDomainClaimedMessageText(ctx context.Context, req *mgmt_pb.SetCustomDomainClaimedMessageTextRequest) (*mgmt_pb.SetCustomDomainClaimedMessageTextResponse, error) {
|
||||
result, err := s.command.SetOrgMessageText(ctx, authz.GetCtxData(ctx).OrgID, SetDomainClaimedCustomTextToDomain(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.SetCustomDomainClaimedMessageTextResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
result.Sequence,
|
||||
result.EventDate,
|
||||
result.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
83
internal/api/grpc/management/custom_text_converter.go
Normal file
83
internal/api/grpc/management/custom_text_converter.go
Normal file
@ -0,0 +1,83 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
mgmt_pb "github.com/caos/zitadel/pkg/grpc/management"
|
||||
)
|
||||
|
||||
func SetInitCustomTextToDomain(msg *mgmt_pb.SetCustomInitMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.InitCodeMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetPasswordResetCustomTextToDomain(msg *mgmt_pb.SetCustomPasswordResetMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.PasswordResetMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetVerifyEmailCustomTextToDomain(msg *mgmt_pb.SetCustomVerifyEmailMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.VerifyEmailMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetVerifyPhoneCustomTextToDomain(msg *mgmt_pb.SetCustomVerifyPhoneMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.VerifyPhoneMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
||||
|
||||
func SetDomainClaimedCustomTextToDomain(msg *mgmt_pb.SetCustomDomainClaimedMessageTextRequest) *domain.CustomMessageText {
|
||||
langTag := language.Make(msg.Language)
|
||||
return &domain.CustomMessageText{
|
||||
MessageTextType: domain.DomainClaimedMessageType,
|
||||
Language: langTag,
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
}
|
||||
}
|
25
internal/api/grpc/text/custom_text.go
Normal file
25
internal/api/grpc/text/custom_text.go
Normal file
@ -0,0 +1,25 @@
|
||||
package text
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||
"github.com/caos/zitadel/internal/iam/model"
|
||||
text_pb "github.com/caos/zitadel/pkg/grpc/text"
|
||||
)
|
||||
|
||||
func ModelCustomMsgTextToPb(msg *model.MessageTextView) *text_pb.MessageCustomText {
|
||||
return &text_pb.MessageCustomText{
|
||||
Title: msg.Title,
|
||||
PreHeader: msg.PreHeader,
|
||||
Subject: msg.Subject,
|
||||
Greeting: msg.Greeting,
|
||||
Text: msg.Text,
|
||||
ButtonText: msg.ButtonText,
|
||||
FooterText: msg.FooterText,
|
||||
Details: object.ToViewDetailsPb(
|
||||
msg.Sequence,
|
||||
msg.CreationDate,
|
||||
msg.ChangeDate,
|
||||
"", //TODO: resourceowner
|
||||
),
|
||||
}
|
||||
}
|
@ -465,7 +465,9 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if user.State == int32(domain.UserStateInactive) {
|
||||
return errors.ThrowPreconditionFailed(nil, "AUTH-2n8fs", "Errors.User.Inactive")
|
||||
}
|
||||
request.SetUserInfo(user.ID, loginName, user.PreferredLoginName, "", "", user.ResourceOwner)
|
||||
return nil
|
||||
}
|
||||
|
@ -145,6 +145,18 @@ func checkFeatures(features *features_view_model.FeaturesView, requiredFeatures
|
||||
}
|
||||
continue
|
||||
}
|
||||
if requiredFeature == domain.FeatureCustomDomain {
|
||||
if !features.CustomDomain {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if requiredFeature == domain.FeatureCustomText {
|
||||
if !features.CustomText {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
continue
|
||||
}
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
return nil
|
||||
|
167
internal/command/custom_message_text_model.go
Normal file
167
internal/command/custom_message_text_model.go
Normal file
@ -0,0 +1,167 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
type CustomMessageTextReadModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
MessageTextType string
|
||||
Language language.Tag
|
||||
Title string
|
||||
PreHeader string
|
||||
Subject string
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
FooterText string
|
||||
|
||||
State domain.PolicyState
|
||||
}
|
||||
|
||||
func (wm *CustomMessageTextReadModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *policy.CustomTextSetEvent:
|
||||
if e.Template != wm.MessageTextType || wm.Language != e.Language {
|
||||
continue
|
||||
}
|
||||
if e.Key == domain.MessageSubject {
|
||||
wm.Subject = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageTitle {
|
||||
wm.Title = e.Text
|
||||
}
|
||||
if e.Key == domain.MessagePreHeader {
|
||||
wm.PreHeader = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageText {
|
||||
wm.Text = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageGreeting {
|
||||
wm.Greeting = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageButtonText {
|
||||
wm.ButtonText = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageFooterText {
|
||||
wm.FooterText = e.Text
|
||||
}
|
||||
wm.State = domain.PolicyStateActive
|
||||
case *policy.CustomTextRemovedEvent:
|
||||
if e.Key != wm.MessageTextType || wm.Language != e.Language {
|
||||
continue
|
||||
}
|
||||
if e.Key == domain.MessageSubject {
|
||||
wm.Subject = ""
|
||||
}
|
||||
if e.Key == domain.MessageTitle {
|
||||
wm.Title = ""
|
||||
}
|
||||
if e.Key == domain.MessagePreHeader {
|
||||
wm.PreHeader = ""
|
||||
}
|
||||
if e.Key == domain.MessageText {
|
||||
wm.Text = ""
|
||||
}
|
||||
if e.Key == domain.MessageGreeting {
|
||||
wm.Greeting = ""
|
||||
}
|
||||
if e.Key == domain.MessageButtonText {
|
||||
wm.ButtonText = ""
|
||||
}
|
||||
if e.Key == domain.MessageFooterText {
|
||||
wm.FooterText = ""
|
||||
}
|
||||
case *policy.CustomTextTemplateRemovedEvent:
|
||||
wm.State = domain.PolicyStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
type CustomMessageTemplatesReadModel struct {
|
||||
eventstore.WriteModel
|
||||
CustomMessageTemplate map[string]*CustomText
|
||||
}
|
||||
|
||||
type CustomText struct {
|
||||
Template string
|
||||
Language language.Tag
|
||||
Title string
|
||||
PreHeader string
|
||||
Subject string
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
FooterText string
|
||||
State domain.PolicyState
|
||||
}
|
||||
|
||||
func (wm *CustomMessageTemplatesReadModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *policy.CustomTextSetEvent:
|
||||
if _, ok := wm.CustomMessageTemplate[e.Template+e.Language.String()]; !ok {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()] = &CustomText{Language: e.Language, Template: e.Template}
|
||||
}
|
||||
if e.Key == domain.MessageSubject {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Subject = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageTitle {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Title = e.Text
|
||||
}
|
||||
if e.Key == domain.MessagePreHeader {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].PreHeader = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageText {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Text = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageGreeting {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Greeting = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageButtonText {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].ButtonText = e.Text
|
||||
}
|
||||
if e.Key == domain.MessageFooterText {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].FooterText = e.Text
|
||||
}
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].State = domain.PolicyStateActive
|
||||
case *policy.CustomTextRemovedEvent:
|
||||
if _, ok := wm.CustomMessageTemplate[e.Template+e.Language.String()]; !ok {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()] = new(CustomText)
|
||||
}
|
||||
if e.Key == domain.MessageSubject {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Subject = ""
|
||||
}
|
||||
if e.Key == domain.MessageTitle {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Title = ""
|
||||
}
|
||||
if e.Key == domain.MessagePreHeader {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].PreHeader = ""
|
||||
}
|
||||
if e.Key == domain.MessageText {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Text = ""
|
||||
}
|
||||
if e.Key == domain.MessageGreeting {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].Greeting = ""
|
||||
}
|
||||
if e.Key == domain.MessageButtonText {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].ButtonText = ""
|
||||
}
|
||||
if e.Key == domain.MessageFooterText {
|
||||
wm.CustomMessageTemplate[e.Template+e.Language.String()].FooterText = ""
|
||||
}
|
||||
case *policy.CustomTextTemplateRemovedEvent:
|
||||
if _, ok := wm.CustomMessageTemplate[e.Template+e.Language.String()]; ok {
|
||||
delete(wm.CustomMessageTemplate, e.Template)
|
||||
}
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
34
internal/command/custom_text_model.go
Normal file
34
internal/command/custom_text_model.go
Normal file
@ -0,0 +1,34 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
type CustomTextWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
Key string
|
||||
Language language.Tag
|
||||
Text string
|
||||
State domain.CustomTextState
|
||||
}
|
||||
|
||||
func (wm *CustomTextWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *policy.CustomTextSetEvent:
|
||||
if wm.Key != e.Key || wm.Language != e.Language {
|
||||
continue
|
||||
}
|
||||
wm.Text = e.Text
|
||||
wm.State = domain.CustomTextStateActive
|
||||
case *policy.CustomTextRemovedEvent:
|
||||
wm.State = domain.CustomTextStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
@ -26,6 +26,7 @@ type FeaturesWriteModel struct {
|
||||
LabelPolicyPrivateLabel bool
|
||||
LabelPolicyWatermark bool
|
||||
CustomDomain bool
|
||||
CustomText bool
|
||||
}
|
||||
|
||||
func (wm *FeaturesWriteModel) Reduce() error {
|
||||
@ -81,6 +82,9 @@ func (wm *FeaturesWriteModel) Reduce() error {
|
||||
if e.CustomDomain != nil {
|
||||
wm.CustomDomain = *e.CustomDomain
|
||||
}
|
||||
if e.CustomText != nil {
|
||||
wm.CustomText = *e.CustomText
|
||||
}
|
||||
case *features.FeaturesRemovedEvent:
|
||||
wm.State = domain.FeaturesStateRemoved
|
||||
}
|
||||
|
@ -69,21 +69,6 @@ func writeModelToMailTemplate(wm *MailTemplateWriteModel) *domain.MailTemplate {
|
||||
}
|
||||
}
|
||||
|
||||
func writeModelToMailText(wm *MailTextWriteModel) *domain.MailText {
|
||||
return &domain.MailText{
|
||||
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
|
||||
MailTextType: wm.MailTextType,
|
||||
Language: wm.Language,
|
||||
Title: wm.Title,
|
||||
PreHeader: wm.PreHeader,
|
||||
Subject: wm.Subject,
|
||||
Greeting: wm.Greeting,
|
||||
Text: wm.Text,
|
||||
ButtonText: wm.ButtonText,
|
||||
State: wm.State,
|
||||
}
|
||||
}
|
||||
|
||||
func writeModelToOrgIAMPolicy(wm *IAMOrgIAMPolicyWriteModel) *domain.OrgIAMPolicy {
|
||||
return &domain.OrgIAMPolicy{
|
||||
ObjectRoot: writeModelToObjectRoot(wm.PolicyOrgIAMWriteModel.WriteModel),
|
||||
@ -98,18 +83,13 @@ func writeModelToMailTemplatePolicy(wm *MailTemplateWriteModel) *domain.MailTemp
|
||||
}
|
||||
}
|
||||
|
||||
func writeModelToMailTextPolicy(wm *MailTextWriteModel) *domain.MailText {
|
||||
return &domain.MailText{
|
||||
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
|
||||
State: wm.State,
|
||||
MailTextType: wm.MailTextType,
|
||||
Language: wm.Language,
|
||||
Title: wm.Title,
|
||||
PreHeader: wm.PreHeader,
|
||||
Subject: wm.Subject,
|
||||
Greeting: wm.Greeting,
|
||||
Text: wm.Text,
|
||||
ButtonText: wm.ButtonText,
|
||||
func writeModelToCustomText(wm *CustomTextWriteModel) *domain.CustomText {
|
||||
return &domain.CustomText{
|
||||
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
|
||||
State: wm.State,
|
||||
Key: wm.Key,
|
||||
Language: wm.Language,
|
||||
Text: wm.Text,
|
||||
}
|
||||
}
|
||||
|
||||
|
72
internal/command/iam_custom_message_text.go
Normal file
72
internal/command/iam_custom_message_text.go
Normal file
@ -0,0 +1,72 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
)
|
||||
|
||||
func (c *Commands) SetDefaultMessageText(ctx context.Context, messageText *domain.CustomMessageText) (*domain.ObjectDetails, error) {
|
||||
iamAgg := iam.NewAggregate()
|
||||
events, existingMessageText, err := c.setDefaultMessageText(ctx, &iamAgg.Aggregate, messageText)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingMessageText, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingMessageText.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) setDefaultMessageText(ctx context.Context, iamAgg *eventstore.Aggregate, msg *domain.CustomMessageText) ([]eventstore.EventPusher, *IAMCustomMessageTextReadModel, error) {
|
||||
if !msg.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "IAM-kd9fs", "Errors.CustomMessageText.Invalid")
|
||||
}
|
||||
|
||||
existingMessageText, err := c.defaultCustomMessageTextWriteModelByID(ctx, msg.MessageTextType, msg.Language)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
events := make([]eventstore.EventPusher, 0)
|
||||
if existingMessageText.Greeting != msg.Greeting {
|
||||
events = append(events, iam.NewCustomTextSetEvent(ctx, iamAgg, msg.MessageTextType, domain.MessageGreeting, msg.Greeting, msg.Language))
|
||||
}
|
||||
if existingMessageText.Subject != msg.Subject {
|
||||
events = append(events, iam.NewCustomTextSetEvent(ctx, iamAgg, msg.MessageTextType, domain.MessageSubject, msg.Subject, msg.Language))
|
||||
}
|
||||
if existingMessageText.Title != msg.Title {
|
||||
events = append(events, iam.NewCustomTextSetEvent(ctx, iamAgg, msg.MessageTextType, domain.MessageTitle, msg.Title, msg.Language))
|
||||
}
|
||||
if existingMessageText.PreHeader != msg.PreHeader {
|
||||
events = append(events, iam.NewCustomTextSetEvent(ctx, iamAgg, msg.MessageTextType, domain.MessagePreHeader, msg.PreHeader, msg.Language))
|
||||
}
|
||||
if existingMessageText.Text != msg.Text {
|
||||
events = append(events, iam.NewCustomTextSetEvent(ctx, iamAgg, msg.MessageTextType, domain.MessageText, msg.Text, msg.Language))
|
||||
}
|
||||
if existingMessageText.ButtonText != msg.ButtonText {
|
||||
events = append(events, iam.NewCustomTextSetEvent(ctx, iamAgg, msg.MessageTextType, domain.MessageButtonText, msg.ButtonText, msg.Language))
|
||||
}
|
||||
if existingMessageText.FooterText != msg.FooterText {
|
||||
events = append(events, iam.NewCustomTextSetEvent(ctx, iamAgg, msg.MessageTextType, domain.MessageFooterText, msg.FooterText, msg.Language))
|
||||
}
|
||||
return events, existingMessageText, nil
|
||||
}
|
||||
|
||||
func (c *Commands) defaultCustomMessageTextWriteModelByID(ctx context.Context, messageType string, lang language.Tag) (*IAMCustomMessageTextReadModel, error) {
|
||||
writeModel := NewIAMCustomMessageTextWriteModel(messageType, lang)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModel, nil
|
||||
}
|
47
internal/command/iam_custom_message_text_model.go
Normal file
47
internal/command/iam_custom_message_text_model.go
Normal file
@ -0,0 +1,47 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
)
|
||||
|
||||
type IAMCustomMessageTextReadModel struct {
|
||||
CustomMessageTextReadModel
|
||||
}
|
||||
|
||||
func NewIAMCustomMessageTextWriteModel(messageTextType string, lang language.Tag) *IAMCustomMessageTextReadModel {
|
||||
return &IAMCustomMessageTextReadModel{
|
||||
CustomMessageTextReadModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: domain.IAMID,
|
||||
ResourceOwner: domain.IAMID,
|
||||
},
|
||||
MessageTextType: messageTextType,
|
||||
Language: lang,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *IAMCustomMessageTextReadModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *iam.CustomTextSetEvent:
|
||||
wm.CustomMessageTextReadModel.AppendEvents(&e.CustomTextSetEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *IAMCustomMessageTextReadModel) Reduce() error {
|
||||
return wm.CustomMessageTextReadModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *IAMCustomMessageTextReadModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
|
||||
AggregateIDs(wm.CustomMessageTextReadModel.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
EventTypes(
|
||||
iam.CustomTextSetEventType)
|
||||
}
|
163
internal/command/iam_custom_message_text_test.go
Normal file
163
internal/command/iam_custom_message_text_test.go
Normal file
@ -0,0 +1,163 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
)
|
||||
|
||||
func TestCommandSide_SetDefaultMessageText(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
config *domain.CustomMessageText
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "invalid custom text, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
config: &domain.CustomMessageText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom text set all fields, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"Template",
|
||||
domain.MessageGreeting,
|
||||
"Greeting",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"Template",
|
||||
domain.MessageSubject,
|
||||
"Subject",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"Template",
|
||||
domain.MessageTitle,
|
||||
"Title",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"Template",
|
||||
domain.MessagePreHeader,
|
||||
"PreHeader",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"Template",
|
||||
domain.MessageText,
|
||||
"Text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"Template",
|
||||
domain.MessageButtonText,
|
||||
"ButtonText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"Template",
|
||||
domain.MessageFooterText,
|
||||
"FooterText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
config: &domain.CustomMessageText{
|
||||
MessageTextType: "Template",
|
||||
Language: language.English,
|
||||
Greeting: "Greeting",
|
||||
Subject: "Subject",
|
||||
Title: "Title",
|
||||
PreHeader: "PreHeader",
|
||||
Text: "Text",
|
||||
ButtonText: "ButtonText",
|
||||
FooterText: "FooterText",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "IAM",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.SetDefaultMessageText(tt.args.ctx, tt.args.config)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ func (c *Commands) setDefaultFeatures(ctx context.Context, existingFeatures *IAM
|
||||
features.LabelPolicyPrivateLabel,
|
||||
features.LabelPolicyWatermark,
|
||||
features.CustomDomain,
|
||||
features.CustomText,
|
||||
)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
|
||||
|
@ -64,7 +64,8 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
passwordComplexityPolicy,
|
||||
labelPolicyPrivateLabel,
|
||||
labelPolicyWatermark,
|
||||
customDomain bool,
|
||||
customDomain,
|
||||
customText bool,
|
||||
) (*iam.FeaturesSetEvent, bool) {
|
||||
|
||||
changes := make([]features.FeaturesChanges, 0)
|
||||
@ -111,6 +112,9 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
if wm.CustomDomain != customDomain {
|
||||
changes = append(changes, features.ChangeCustomDomain(customDomain))
|
||||
}
|
||||
if wm.CustomText != customText {
|
||||
changes = append(changes, features.ChangeCustomText(customText))
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
|
@ -1,106 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
iam_repo "github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
)
|
||||
|
||||
func (c *Commands) AddDefaultMailText(ctx context.Context, policy *domain.MailText) (*domain.MailText, error) {
|
||||
addedPolicy := NewIAMMailTextWriteModel(policy.MailTextType, policy.Language)
|
||||
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.MailTextWriteModel.WriteModel)
|
||||
event, err := c.addDefaultMailText(ctx, iamAgg, addedPolicy, policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(addedPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToMailTextPolicy(&addedPolicy.MailTextWriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) addDefaultMailText(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMMailTextWriteModel, mailText *domain.MailText) (eventstore.EventPusher, error) {
|
||||
if !mailText.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-3n8fs", "Errors.IAM.MailText.Invalid")
|
||||
}
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if addedPolicy.State == domain.PolicyStateActive {
|
||||
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-9o0pM", "Errors.IAM.MailText.AlreadyExists")
|
||||
}
|
||||
|
||||
return iam_repo.NewMailTextAddedEvent(
|
||||
ctx,
|
||||
iamAgg,
|
||||
mailText.MailTextType,
|
||||
mailText.Language,
|
||||
mailText.Title,
|
||||
mailText.PreHeader,
|
||||
mailText.Subject,
|
||||
mailText.Greeting,
|
||||
mailText.Text,
|
||||
mailText.ButtonText), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeDefaultMailText(ctx context.Context, mailText *domain.MailText) (*domain.MailText, error) {
|
||||
if !mailText.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-kd9fs", "Errors.IAM.MailText.Invalid")
|
||||
}
|
||||
existingPolicy, err := c.defaultMailTextWriteModelByID(ctx, mailText.MailTextType, mailText.Language)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-2N8fs", "Errors.IAM.MailText.NotFound")
|
||||
}
|
||||
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.MailTextWriteModel.WriteModel)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(
|
||||
ctx,
|
||||
iamAgg,
|
||||
mailText.MailTextType,
|
||||
mailText.Language,
|
||||
mailText.Title,
|
||||
mailText.PreHeader,
|
||||
mailText.Subject,
|
||||
mailText.Greeting,
|
||||
mailText.Text,
|
||||
mailText.ButtonText)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-m9L0s", "Errors.IAM.MailText.NotChanged")
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, changedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToMailTextPolicy(&existingPolicy.MailTextWriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) defaultMailTextWriteModelByID(ctx context.Context, mailTextType, language string) (policy *IAMMailTextWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel := NewIAMMailTextWriteModel(mailTextType, language)
|
||||
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModel, nil
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
type IAMMailTextWriteModel struct {
|
||||
MailTextWriteModel
|
||||
}
|
||||
|
||||
func NewIAMMailTextWriteModel(mailTextType, language string) *IAMMailTextWriteModel {
|
||||
return &IAMMailTextWriteModel{
|
||||
MailTextWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: domain.IAMID,
|
||||
ResourceOwner: domain.IAMID,
|
||||
},
|
||||
MailTextType: mailTextType,
|
||||
Language: language,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *IAMMailTextWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *iam.MailTextAddedEvent:
|
||||
wm.MailTextWriteModel.AppendEvents(&e.MailTextAddedEvent)
|
||||
case *iam.MailTextChangedEvent:
|
||||
wm.MailTextWriteModel.AppendEvents(&e.MailTextChangedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *IAMMailTextWriteModel) Reduce() error {
|
||||
return wm.MailTextWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *IAMMailTextWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
|
||||
AggregateIDs(wm.MailTextWriteModel.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
EventTypes(
|
||||
iam.MailTextAddedEventType,
|
||||
iam.MailTextChangedEventType)
|
||||
}
|
||||
|
||||
func (wm *IAMMailTextWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
mailTextType,
|
||||
language,
|
||||
title,
|
||||
preHeader,
|
||||
subject,
|
||||
greeting,
|
||||
text,
|
||||
buttonText string,
|
||||
) (*iam.MailTextChangedEvent, bool) {
|
||||
changes := make([]policy.MailTextChanges, 0)
|
||||
if wm.Title != title {
|
||||
changes = append(changes, policy.ChangeTitle(title))
|
||||
}
|
||||
if wm.PreHeader != preHeader {
|
||||
changes = append(changes, policy.ChangePreHeader(preHeader))
|
||||
}
|
||||
if wm.Subject != subject {
|
||||
changes = append(changes, policy.ChangeSubject(subject))
|
||||
}
|
||||
if wm.Greeting != greeting {
|
||||
changes = append(changes, policy.ChangeGreeting(greeting))
|
||||
}
|
||||
if wm.Text != text {
|
||||
changes = append(changes, policy.ChangeText(text))
|
||||
}
|
||||
if wm.ButtonText != buttonText {
|
||||
changes = append(changes, policy.ChangeButtonText(buttonText))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
changedEvent, err := iam.NewMailTextChangedEvent(ctx, aggregate, mailTextType, language, changes)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return changedEvent, true
|
||||
}
|
@ -1,366 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddDefaultMailTextPolicy(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
policy *domain.MailText
|
||||
}
|
||||
type res struct {
|
||||
want *domain.MailText
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "mail text invalid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mail text already existing, already exists error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewMailTextAddedEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorAlreadyExists,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add mail template,ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
iam.NewMailTextAddedEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraint(policy.NewAddMailTextUniqueConstraint("IAM", "mail-text-type", "de")),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.MailText{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "IAM",
|
||||
ResourceOwner: "IAM",
|
||||
},
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
State: domain.PolicyStateActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.AddDefaultMailText(tt.args.ctx, tt.args.policy)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_ChangeDefaultMailTextPolicy(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
policy *domain.MailText
|
||||
}
|
||||
type res struct {
|
||||
want *domain.MailText
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "mailtext invalid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mail text not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewMailTextAddedEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewMailTextAddedEvent(context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
newDefaultMailTextPolicyChangedEvent(
|
||||
context.Background(),
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title-change",
|
||||
"pre-header-change",
|
||||
"subject-change",
|
||||
"greeting-change",
|
||||
"text-change",
|
||||
"button-text-change"),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title-change",
|
||||
PreHeader: "pre-header-change",
|
||||
Subject: "subject-change",
|
||||
Greeting: "greeting-change",
|
||||
Text: "text-change",
|
||||
ButtonText: "button-text-change",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.MailText{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "IAM",
|
||||
ResourceOwner: "IAM",
|
||||
},
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title-change",
|
||||
PreHeader: "pre-header-change",
|
||||
Subject: "subject-change",
|
||||
Greeting: "greeting-change",
|
||||
Text: "text-change",
|
||||
ButtonText: "button-text-change",
|
||||
State: domain.PolicyStateActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.ChangeDefaultMailText(tt.args.ctx, tt.args.policy)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newDefaultMailTextPolicyChangedEvent(ctx context.Context, mailTextType, language, title, preHeader, subject, greeting, text, buttonText string) *iam.MailTextChangedEvent {
|
||||
event, _ := iam.NewMailTextChangedEvent(ctx,
|
||||
&iam.NewAggregate().Aggregate,
|
||||
mailTextType,
|
||||
language,
|
||||
[]policy.MailTextChanges{
|
||||
policy.ChangeTitle(title),
|
||||
policy.ChangePreHeader(preHeader),
|
||||
policy.ChangeSubject(subject),
|
||||
policy.ChangeGreeting(greeting),
|
||||
policy.ChangeText(text),
|
||||
policy.ChangeButtonText(buttonText),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}
|
95
internal/command/org_custom_message_model.go
Normal file
95
internal/command/org_custom_message_model.go
Normal file
@ -0,0 +1,95 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
type OrgCustomMessageTextReadModel struct {
|
||||
CustomMessageTextReadModel
|
||||
}
|
||||
|
||||
func NewOrgCustomMessageTextWriteModel(orgID, messageTextType string, lang language.Tag) *OrgCustomMessageTextReadModel {
|
||||
return &OrgCustomMessageTextReadModel{
|
||||
CustomMessageTextReadModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
MessageTextType: messageTextType,
|
||||
Language: lang,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgCustomMessageTextReadModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.CustomTextSetEvent:
|
||||
wm.CustomMessageTextReadModel.AppendEvents(&e.CustomTextSetEvent)
|
||||
case *org.CustomTextRemovedEvent:
|
||||
wm.CustomMessageTextReadModel.AppendEvents(&e.CustomTextRemovedEvent)
|
||||
case *org.CustomTextTemplateRemovedEvent:
|
||||
wm.CustomMessageTextReadModel.AppendEvents(&e.CustomTextTemplateRemovedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgCustomMessageTextReadModel) Reduce() error {
|
||||
return wm.CustomMessageTextReadModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgCustomMessageTextReadModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
|
||||
AggregateIDs(wm.CustomMessageTextReadModel.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
EventTypes(
|
||||
org.CustomTextSetEventType,
|
||||
org.CustomTextRemovedEventType,
|
||||
org.CustomTextTemplateRemovedEventType)
|
||||
}
|
||||
|
||||
type OrgCustomMessageTemplatesReadModel struct {
|
||||
CustomMessageTemplatesReadModel
|
||||
}
|
||||
|
||||
func NewOrgCustomMessageTextsWriteModel(orgID string) *OrgCustomMessageTemplatesReadModel {
|
||||
return &OrgCustomMessageTemplatesReadModel{
|
||||
CustomMessageTemplatesReadModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
CustomMessageTemplate: make(map[string]*CustomText),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgCustomMessageTemplatesReadModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.CustomTextSetEvent:
|
||||
wm.CustomMessageTemplatesReadModel.AppendEvents(&e.CustomTextSetEvent)
|
||||
case *org.CustomTextRemovedEvent:
|
||||
wm.CustomMessageTemplatesReadModel.AppendEvents(&e.CustomTextRemovedEvent)
|
||||
case *org.CustomTextTemplateRemovedEvent:
|
||||
wm.CustomMessageTemplatesReadModel.AppendEvents(&e.CustomTextTemplateRemovedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgCustomMessageTemplatesReadModel) Reduce() error {
|
||||
return wm.CustomMessageTemplatesReadModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgCustomMessageTemplatesReadModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
|
||||
AggregateIDs(wm.CustomMessageTemplatesReadModel.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
EventTypes(
|
||||
org.CustomTextSetEventType,
|
||||
org.CustomTextRemovedEventType,
|
||||
org.CustomTextTemplateRemovedEventType)
|
||||
}
|
137
internal/command/org_custom_message_text.go
Normal file
137
internal/command/org_custom_message_text.go
Normal file
@ -0,0 +1,137 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func (c *Commands) SetOrgMessageText(ctx context.Context, resourceOwner string, messageText *domain.CustomMessageText) (*domain.ObjectDetails, error) {
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-2biiR", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
orgAgg := org.NewAggregate(resourceOwner, resourceOwner)
|
||||
events, existingMessageText, err := c.setOrgMessageText(ctx, &orgAgg.Aggregate, messageText)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingMessageText, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingMessageText.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) setOrgMessageText(ctx context.Context, orgAgg *eventstore.Aggregate, message *domain.CustomMessageText) ([]eventstore.EventPusher, *OrgCustomMessageTextReadModel, error) {
|
||||
if !message.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "ORG-2jfsf", "Errors.CustomText.Invalid")
|
||||
}
|
||||
|
||||
existingMessageText, err := c.orgCustomMessageTextWriteModelByID(ctx, orgAgg.ID, message.MessageTextType, message.Language)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
events := make([]eventstore.EventPusher, 0)
|
||||
if existingMessageText.Greeting != message.Greeting {
|
||||
if message.Greeting != "" {
|
||||
events = append(events, org.NewCustomTextSetEvent(ctx, orgAgg, message.MessageTextType, domain.MessageGreeting, message.Greeting, message.Language))
|
||||
} else {
|
||||
events = append(events, org.NewCustomTextRemovedEvent(ctx, orgAgg, message.MessageTextType, domain.MessageGreeting, message.Language))
|
||||
}
|
||||
}
|
||||
if existingMessageText.Subject != message.Subject {
|
||||
if message.Subject != "" {
|
||||
events = append(events, org.NewCustomTextSetEvent(ctx, orgAgg, message.MessageTextType, domain.MessageSubject, message.Subject, message.Language))
|
||||
} else {
|
||||
events = append(events, org.NewCustomTextRemovedEvent(ctx, orgAgg, message.MessageTextType, domain.MessageSubject, message.Language))
|
||||
}
|
||||
}
|
||||
if existingMessageText.Title != message.Title {
|
||||
if message.Title != "" {
|
||||
events = append(events, org.NewCustomTextSetEvent(ctx, orgAgg, message.MessageTextType, domain.MessageTitle, message.Title, message.Language))
|
||||
} else {
|
||||
events = append(events, org.NewCustomTextRemovedEvent(ctx, orgAgg, message.MessageTextType, domain.MessageTitle, message.Language))
|
||||
}
|
||||
}
|
||||
if existingMessageText.PreHeader != message.PreHeader {
|
||||
if message.PreHeader != "" {
|
||||
events = append(events, org.NewCustomTextSetEvent(ctx, orgAgg, message.MessageTextType, domain.MessagePreHeader, message.PreHeader, message.Language))
|
||||
} else {
|
||||
events = append(events, org.NewCustomTextRemovedEvent(ctx, orgAgg, message.MessageTextType, domain.MessagePreHeader, message.Language))
|
||||
}
|
||||
}
|
||||
if existingMessageText.Text != message.Text {
|
||||
if message.Text != "" {
|
||||
events = append(events, org.NewCustomTextSetEvent(ctx, orgAgg, message.MessageTextType, domain.MessageText, message.Text, message.Language))
|
||||
} else {
|
||||
events = append(events, org.NewCustomTextRemovedEvent(ctx, orgAgg, message.MessageTextType, domain.MessageText, message.Language))
|
||||
}
|
||||
}
|
||||
if existingMessageText.ButtonText != message.ButtonText {
|
||||
if message.ButtonText != "" {
|
||||
events = append(events, org.NewCustomTextSetEvent(ctx, orgAgg, message.MessageTextType, domain.MessageButtonText, message.ButtonText, message.Language))
|
||||
} else {
|
||||
events = append(events, org.NewCustomTextRemovedEvent(ctx, orgAgg, message.MessageTextType, domain.MessageButtonText, message.Language))
|
||||
}
|
||||
}
|
||||
if existingMessageText.FooterText != message.FooterText {
|
||||
if message.FooterText != "" {
|
||||
events = append(events, org.NewCustomTextSetEvent(ctx, orgAgg, message.MessageTextType, domain.MessageFooterText, message.FooterText, message.Language))
|
||||
} else {
|
||||
events = append(events, org.NewCustomTextRemovedEvent(ctx, orgAgg, message.MessageTextType, domain.MessageFooterText, message.Language))
|
||||
}
|
||||
}
|
||||
return events, existingMessageText, nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveOrgMessageTexts(ctx context.Context, resourceOwner, messageTextType string, lang language.Tag) error {
|
||||
if resourceOwner == "" {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "Org-3mfsf", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if messageTextType == "" || lang == language.Und {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "Org-j59f", "Errors.CustomMessageText.Invalid")
|
||||
}
|
||||
customText, err := c.orgCustomMessageTextWriteModelByID(ctx, resourceOwner, messageTextType, lang)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if customText.State == domain.PolicyStateUnspecified || customText.State == domain.PolicyStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "Org-3b8Jf", "Errors.CustomMessageText.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&customText.WriteModel)
|
||||
_, err = c.eventstore.PushEvents(ctx, org.NewCustomTextTemplateRemovedEvent(ctx, orgAgg, messageTextType, lang))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Commands) removeOrgMessageTextsIfExists(ctx context.Context, orgID string) ([]eventstore.EventPusher, error) {
|
||||
msgTemplates := NewOrgCustomMessageTextsWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, msgTemplates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&msgTemplates.WriteModel)
|
||||
events := make([]eventstore.EventPusher, 0, len(msgTemplates.CustomMessageTemplate))
|
||||
for _, tmpl := range msgTemplates.CustomMessageTemplate {
|
||||
events = append(events, org.NewCustomTextTemplateRemovedEvent(ctx, orgAgg, tmpl.Template, tmpl.Language))
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) orgCustomMessageTextWriteModelByID(ctx context.Context, orgID, messageType string, lang language.Tag) (*OrgCustomMessageTextReadModel, error) {
|
||||
writeModel := NewOrgCustomMessageTextWriteModel(orgID, messageType, lang)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModel, nil
|
||||
}
|
514
internal/command/org_custom_message_text_test.go
Normal file
514
internal/command/org_custom_message_text_test.go
Normal file
@ -0,0 +1,514 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func TestCommandSide_SetCustomMessageText(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
config *domain.CustomMessageText
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no resource owner, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
config: &domain.CustomMessageText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid custom text, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomMessageText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom text set all fields, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageGreeting,
|
||||
"Greeting",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageSubject,
|
||||
"Subject",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageTitle,
|
||||
"Title",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessagePreHeader,
|
||||
"PreHeader",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageText,
|
||||
"Text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageButtonText,
|
||||
"ButtonText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageFooterText,
|
||||
"FooterText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomMessageText{
|
||||
MessageTextType: "Template",
|
||||
Language: language.English,
|
||||
Greeting: "Greeting",
|
||||
Subject: "Subject",
|
||||
Title: "Title",
|
||||
PreHeader: "PreHeader",
|
||||
Text: "Text",
|
||||
ButtonText: "ButtonText",
|
||||
FooterText: "FooterText",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom text remove all fields, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageGreeting,
|
||||
"Greeting",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageSubject,
|
||||
"Subject",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageTitle,
|
||||
"Title",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessagePreHeader,
|
||||
"PreHeader",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageText,
|
||||
"Text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageButtonText,
|
||||
"ButtonText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageFooterText,
|
||||
"FooterText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageGreeting,
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageSubject,
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageTitle,
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessagePreHeader,
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageText,
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageButtonText,
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageFooterText,
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomMessageText{
|
||||
MessageTextType: "Template",
|
||||
Language: language.English,
|
||||
Greeting: "",
|
||||
Subject: "",
|
||||
Title: "",
|
||||
PreHeader: "",
|
||||
Text: "",
|
||||
ButtonText: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.SetOrgMessageText(tt.args.ctx, tt.args.resourceOwner, tt.args.config)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_RemoveCustomMessageText(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
mailTextType string
|
||||
lang language.Tag
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no resource owner, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
mailTextType: "Template",
|
||||
lang: language.English,
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no mail text type owner, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
lang: language.English,
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no mail text type owner, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
mailTextType: "Template",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom text remove all fields, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageGreeting,
|
||||
"Greeting",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageSubject,
|
||||
"Subject",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageTitle,
|
||||
"Title",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessagePreHeader,
|
||||
"PreHeader",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageText,
|
||||
"Text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageButtonText,
|
||||
"ButtonText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageFooterText,
|
||||
"FooterText",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextTemplateRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"Template",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
mailTextType: "Template",
|
||||
lang: language.English,
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
err := r.RemoveOrgMessageTexts(tt.args.ctx, tt.args.resourceOwner, tt.args.mailTextType, tt.args.lang)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
|
||||
features.LabelPolicyPrivateLabel,
|
||||
features.LabelPolicyWatermark,
|
||||
features.CustomDomain,
|
||||
features.CustomText,
|
||||
)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
|
||||
@ -126,6 +127,15 @@ func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string
|
||||
events = append(events, removeCustomDomainsEvents...)
|
||||
}
|
||||
}
|
||||
if !features.CustomText {
|
||||
removeCustomTextEvents, err := c.removeOrgMessageTextsIfExists(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if removeCustomTextEvents != nil {
|
||||
events = append(events, removeCustomTextEvents...)
|
||||
}
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,8 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
passwordComplexityPolicy,
|
||||
labelPolicyPrivateLabel,
|
||||
labelPolicyWatermark,
|
||||
customDomain bool,
|
||||
customDomain,
|
||||
customText bool,
|
||||
) (*org.FeaturesSetEvent, bool) {
|
||||
|
||||
changes := make([]features.FeaturesChanges, 0)
|
||||
@ -121,6 +122,9 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
if wm.CustomDomain != customDomain {
|
||||
changes = append(changes, features.ChangeCustomDomain(customDomain))
|
||||
}
|
||||
if wm.CustomText != customText {
|
||||
changes = append(changes, features.ChangeCustomText(customText))
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
@ -226,6 +227,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
domain.InitCodeMessageType,
|
||||
domain.MessageSubject,
|
||||
"text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@ -253,6 +266,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
CustomText: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -373,6 +387,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
domain.InitCodeMessageType,
|
||||
domain.MessageSubject,
|
||||
"text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@ -534,6 +560,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
domain.InitCodeMessageType,
|
||||
domain.MessageSubject,
|
||||
"text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@ -705,6 +743,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
domain.InitCodeMessageType,
|
||||
domain.MessageSubject,
|
||||
"text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@ -931,6 +981,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
domain.InitCodeMessageType,
|
||||
domain.MessageSubject,
|
||||
"text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@ -951,6 +1013,9 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
eventFromEventPusher(
|
||||
org.NewLabelPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextTemplateRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.InitCodeMessageType, language.English),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour),
|
||||
),
|
||||
@ -1144,6 +1209,18 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
domain.InitCodeMessageType,
|
||||
domain.MessageSubject,
|
||||
"text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
|
@ -1,114 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func (c *Commands) AddMailText(ctx context.Context, resourceOwner string, mailText *domain.MailText) (*domain.MailText, error) {
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-MFiig", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if !mailText.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-4778u", "Errors.Org.MailText.Invalid")
|
||||
}
|
||||
addedPolicy := NewOrgMailTextWriteModel(resourceOwner, mailText.MailTextType, mailText.Language)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if addedPolicy.State == domain.PolicyStateActive {
|
||||
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-9kufs", "Errors.Org.MailText.AlreadyExists")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.MailTextWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(
|
||||
ctx,
|
||||
org.NewMailTextAddedEvent(
|
||||
ctx,
|
||||
orgAgg,
|
||||
mailText.MailTextType,
|
||||
mailText.Language,
|
||||
mailText.Title,
|
||||
mailText.PreHeader,
|
||||
mailText.Subject,
|
||||
mailText.Greeting,
|
||||
mailText.Text,
|
||||
mailText.ButtonText))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(addedPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return writeModelToMailText(&addedPolicy.MailTextWriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeMailText(ctx context.Context, resourceOwner string, mailText *domain.MailText) (*domain.MailText, error) {
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-NFus3", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if !mailText.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-3m9fs", "Errors.Org.MailText.Invalid")
|
||||
}
|
||||
existingPolicy := NewOrgMailTextWriteModel(resourceOwner, mailText.MailTextType, mailText.Language)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3n8fM", "Errors.Org.MailText.NotFound")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.MailTextWriteModel.WriteModel)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(
|
||||
ctx,
|
||||
orgAgg,
|
||||
mailText.MailTextType,
|
||||
mailText.Language,
|
||||
mailText.Title,
|
||||
mailText.PreHeader,
|
||||
mailText.Subject,
|
||||
mailText.Greeting,
|
||||
mailText.Text,
|
||||
mailText.ButtonText)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-2n9fs", "Errors.Org.MailText.NotChanged")
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, changedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return writeModelToMailText(&existingPolicy.MailTextWriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveMailText(ctx context.Context, resourceOwner, mailTextType, language string) error {
|
||||
if resourceOwner == "" {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "Org-2N7fd", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if mailTextType == "" || language == "" {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "Org-N8fsf", "Errors.Org.MailText.Invalid")
|
||||
}
|
||||
existingPolicy := NewOrgMailTextWriteModel(resourceOwner, mailTextType, language)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "Org-3b8Jf", "Errors.Org.MailText.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
_, err = c.eventstore.PushEvents(ctx, org.NewMailTextRemovedEvent(ctx, orgAgg, mailTextType, language))
|
||||
return err
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
type OrgMailTextWriteModel struct {
|
||||
MailTextWriteModel
|
||||
}
|
||||
|
||||
func NewOrgMailTextWriteModel(orgID, mailTextType, language string) *OrgMailTextWriteModel {
|
||||
return &OrgMailTextWriteModel{
|
||||
MailTextWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
MailTextType: mailTextType,
|
||||
Language: language,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgMailTextWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.MailTextAddedEvent:
|
||||
wm.MailTextWriteModel.AppendEvents(&e.MailTextAddedEvent)
|
||||
case *org.MailTextChangedEvent:
|
||||
wm.MailTextWriteModel.AppendEvents(&e.MailTextChangedEvent)
|
||||
case *org.MailTextRemovedEvent:
|
||||
wm.MailTextWriteModel.AppendEvents(&e.MailTextRemovedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgMailTextWriteModel) Reduce() error {
|
||||
return wm.MailTextWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgMailTextWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
|
||||
AggregateIDs(wm.MailTextWriteModel.AggregateID).
|
||||
EventTypes(org.MailTextAddedEventType,
|
||||
org.MailTextChangedEventType,
|
||||
org.MailTextRemovedEventType)
|
||||
if wm.ResourceOwner != "" {
|
||||
query.ResourceOwner(wm.ResourceOwner)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func (wm *OrgMailTextWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
mailTextType,
|
||||
language,
|
||||
title,
|
||||
preHeader,
|
||||
subject,
|
||||
greeting,
|
||||
text,
|
||||
buttonText string,
|
||||
) (*org.MailTextChangedEvent, bool) {
|
||||
changes := make([]policy.MailTextChanges, 0)
|
||||
if wm.Title != title {
|
||||
changes = append(changes, policy.ChangeTitle(title))
|
||||
}
|
||||
if wm.PreHeader != preHeader {
|
||||
changes = append(changes, policy.ChangePreHeader(preHeader))
|
||||
}
|
||||
if wm.Subject != subject {
|
||||
changes = append(changes, policy.ChangeSubject(subject))
|
||||
}
|
||||
if wm.Greeting != greeting {
|
||||
changes = append(changes, policy.ChangeGreeting(greeting))
|
||||
}
|
||||
if wm.Text != text {
|
||||
changes = append(changes, policy.ChangeText(text))
|
||||
}
|
||||
if wm.ButtonText != buttonText {
|
||||
changes = append(changes, policy.ChangeButtonText(buttonText))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
changedEvent, err := org.NewMailTextChangedEvent(ctx, aggregate, mailTextType, language, changes)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return changedEvent, true
|
||||
}
|
@ -1,563 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddMailText(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
orgID string
|
||||
policy *domain.MailText
|
||||
}
|
||||
type res struct {
|
||||
want *domain.MailText
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "org id missing, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mail text already existing, already exists error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewMailTextAddedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorAlreadyExists,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mail text already existing, already exists error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewMailTextAddedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorAlreadyExists,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add policy,ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
org.NewMailTextAddedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraint(policy.NewAddMailTextUniqueConstraint("org1", "mail-text-type", "de")),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.MailText{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "org1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
State: domain.PolicyStateActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.AddMailText(tt.args.ctx, tt.args.orgID, tt.args.policy)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_ChangeMailText(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
orgID string
|
||||
policy *domain.MailText
|
||||
}
|
||||
type res struct {
|
||||
want *domain.MailText
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "org id missing, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mailtext invalid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
policy: &domain.MailText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mail template not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewMailTextAddedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title",
|
||||
PreHeader: "pre-header",
|
||||
Subject: "subject",
|
||||
Greeting: "greeting",
|
||||
Text: "text",
|
||||
ButtonText: "button-text",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewMailTextAddedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
newMailTextChangedEvent(
|
||||
context.Background(),
|
||||
"org1",
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title-change",
|
||||
"pre-header-change",
|
||||
"subject-change",
|
||||
"greeting-change",
|
||||
"text-change",
|
||||
"button-text-change"),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
policy: &domain.MailText{
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title-change",
|
||||
PreHeader: "pre-header-change",
|
||||
Subject: "subject-change",
|
||||
Greeting: "greeting-change",
|
||||
Text: "text-change",
|
||||
ButtonText: "button-text-change",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.MailText{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "org1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
MailTextType: "mail-text-type",
|
||||
Language: "de",
|
||||
Title: "title-change",
|
||||
PreHeader: "pre-header-change",
|
||||
Subject: "subject-change",
|
||||
Greeting: "greeting-change",
|
||||
Text: "text-change",
|
||||
ButtonText: "button-text-change",
|
||||
State: domain.PolicyStateActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.ChangeMailText(tt.args.ctx, tt.args.orgID, tt.args.policy)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_RemoveMailText(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
orgID string
|
||||
mailTextType string
|
||||
language string
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "org id missing, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "policy not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
mailTextType: "mail-text-type",
|
||||
language: "de",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewMailTextAddedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"mail-text-type",
|
||||
"de",
|
||||
"title",
|
||||
"pre-header",
|
||||
"subject",
|
||||
"greeting",
|
||||
"text",
|
||||
"button-text",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
org.NewMailTextRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"mail-text-type",
|
||||
"de"),
|
||||
),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraint(policy.NewRemoveMailTextUniqueConstraint("org1", "mail-text-type", "de")),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
mailTextType: "mail-text-type",
|
||||
language: "de",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
err := r.RemoveMailText(tt.args.ctx, tt.args.orgID, tt.args.mailTextType, tt.args.language)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newMailTextChangedEvent(ctx context.Context, orgID, mailTextType, language, title, preHeader, subject, greeting, text, buttonText string) *org.MailTextChangedEvent {
|
||||
event, _ := org.NewMailTextChangedEvent(ctx,
|
||||
&org.NewAggregate(orgID, orgID).Aggregate,
|
||||
mailTextType,
|
||||
language,
|
||||
[]policy.MailTextChanges{
|
||||
policy.ChangeTitle(title),
|
||||
policy.ChangePreHeader(preHeader),
|
||||
policy.ChangeSubject(subject),
|
||||
policy.ChangeGreeting(greeting),
|
||||
policy.ChangeText(text),
|
||||
policy.ChangeButtonText(buttonText),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}
|
@ -65,7 +65,7 @@ func (c *Commands) ChangePasswordAgePolicy(ctx context.Context, resourceOwner st
|
||||
|
||||
func (c *Commands) RemovePasswordAgePolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-2N8fs", "Errors.ResourceOwnerMissing")
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-M58wd", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy := NewOrgPasswordAgePolicyWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
|
@ -1,65 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
type MailTextWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
MailTextType string
|
||||
Language string
|
||||
Title string
|
||||
PreHeader string
|
||||
Subject string
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
|
||||
State domain.PolicyState
|
||||
}
|
||||
|
||||
func (wm *MailTextWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *policy.MailTextAddedEvent:
|
||||
if wm.MailTextType != e.MailTextType || wm.Language != e.Language {
|
||||
continue
|
||||
}
|
||||
wm.Title = e.Title
|
||||
wm.PreHeader = e.PreHeader
|
||||
wm.Subject = e.Subject
|
||||
wm.Greeting = e.Greeting
|
||||
wm.Text = e.Text
|
||||
wm.ButtonText = e.ButtonText
|
||||
wm.State = domain.PolicyStateActive
|
||||
case *policy.MailTextChangedEvent:
|
||||
if wm.MailTextType != e.MailTextType || wm.Language != e.Language {
|
||||
continue
|
||||
}
|
||||
if e.Title != nil {
|
||||
wm.Title = *e.Title
|
||||
}
|
||||
if e.PreHeader != nil {
|
||||
wm.PreHeader = *e.PreHeader
|
||||
}
|
||||
if e.Subject != nil {
|
||||
wm.Subject = *e.Subject
|
||||
}
|
||||
if e.Greeting != nil {
|
||||
wm.Greeting = *e.Greeting
|
||||
}
|
||||
if e.Text != nil {
|
||||
wm.Text = *e.Text
|
||||
}
|
||||
if e.ButtonText != nil {
|
||||
wm.ButtonText = *e.ButtonText
|
||||
}
|
||||
case *policy.MailTextRemovedEvent:
|
||||
wm.State = domain.PolicyStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
@ -2,14 +2,15 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
type Step10 struct {
|
||||
DefaultMailTemplate domain.MailTemplate
|
||||
DefaultMailTexts []domain.MailText
|
||||
}
|
||||
|
||||
func (s *Step10) Step() domain.Step {
|
||||
@ -30,13 +31,6 @@ func (c *Commands) SetupStep10(ctx context.Context, step *Step10) error {
|
||||
events := []eventstore.EventPusher{
|
||||
mailTemplateEvent,
|
||||
}
|
||||
for _, text := range step.DefaultMailTexts {
|
||||
defaultTextEvent, err := c.addDefaultMailText(ctx, iamAgg, NewIAMMailTextWriteModel(text.MailTextType, text.Language), &text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, defaultTextEvent)
|
||||
}
|
||||
logging.Log("SETUP-3N9fs").Info("default mail template/text set up")
|
||||
return events, nil
|
||||
}
|
||||
|
39
internal/command/setup_step16.go
Normal file
39
internal/command/setup_step16.go
Normal file
@ -0,0 +1,39 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
type Step16 struct {
|
||||
DefaultMessageTexts []domain.CustomMessageText
|
||||
}
|
||||
|
||||
func (s *Step16) Step() domain.Step {
|
||||
return domain.Step16
|
||||
}
|
||||
|
||||
func (s *Step16) execute(ctx context.Context, commandSide *Commands) error {
|
||||
return commandSide.SetupStep16(ctx, s)
|
||||
}
|
||||
|
||||
func (c *Commands) SetupStep16(ctx context.Context, step *Step16) error {
|
||||
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
|
||||
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
|
||||
events := make([]eventstore.EventPusher, 0)
|
||||
|
||||
for _, text := range step.DefaultMessageTexts {
|
||||
mailEvents, _, err := c.setDefaultMessageText(ctx, iamAgg, &text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, mailEvents...)
|
||||
}
|
||||
|
||||
logging.Log("SETUP-4k0LL").Info("default message text set up")
|
||||
return events, nil
|
||||
}
|
||||
return c.setup(ctx, step, fn)
|
||||
}
|
42
internal/domain/custom_messge_text.go
Normal file
42
internal/domain/custom_messge_text.go
Normal file
@ -0,0 +1,42 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
|
||||
const (
|
||||
InitCodeMessageType = "InitCode"
|
||||
PasswordResetMessageType = "PasswordReset"
|
||||
VerifyEmailMessageType = "VerifyEmail"
|
||||
VerifyPhoneMessageType = "VerifyPhone"
|
||||
DomainClaimedMessageType = "DomainClaimed"
|
||||
MessageTitle = "Title"
|
||||
MessagePreHeader = "PreHeader"
|
||||
MessageSubject = "Subject"
|
||||
MessageGreeting = "Greeting"
|
||||
MessageText = "Text"
|
||||
MessageButtonText = "ButtonText"
|
||||
MessageFooterText = "FooterText"
|
||||
)
|
||||
|
||||
type CustomMessageText struct {
|
||||
models.ObjectRoot
|
||||
|
||||
State PolicyState
|
||||
Default bool
|
||||
MessageTextType string
|
||||
Language language.Tag
|
||||
Title string
|
||||
PreHeader string
|
||||
Subject string
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
FooterText string
|
||||
}
|
||||
|
||||
func (m *CustomMessageText) IsValid() bool {
|
||||
return m.MessageTextType != "" && m.Language != language.Und
|
||||
}
|
32
internal/domain/custom_text.go
Normal file
32
internal/domain/custom_text.go
Normal file
@ -0,0 +1,32 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
|
||||
type CustomText struct {
|
||||
models.ObjectRoot
|
||||
|
||||
State CustomTextState
|
||||
Default bool
|
||||
Template string
|
||||
Key string
|
||||
Language language.Tag
|
||||
Text string
|
||||
}
|
||||
|
||||
type CustomTextState int32
|
||||
|
||||
const (
|
||||
CustomTextStateUnspecified CustomTextState = iota
|
||||
CustomTextStateActive
|
||||
CustomTextStateRemoved
|
||||
|
||||
customTextStateCount
|
||||
)
|
||||
|
||||
func (m *CustomText) IsValid() bool {
|
||||
return m.Key != "" && m.Language != language.Und && m.Text != ""
|
||||
}
|
@ -18,6 +18,7 @@ const (
|
||||
FeatureLabelPolicy = "label_policy"
|
||||
FeatureLabelPolicyPrivateLabel = FeatureLabelPolicy + ".private_label"
|
||||
FeatureLabelPolicyWatermark = FeatureLabelPolicy + ".watermark"
|
||||
FeatureCustomText = "custom_text"
|
||||
FeatureCustomDomain = "custom_domain"
|
||||
)
|
||||
|
||||
@ -41,6 +42,7 @@ type Features struct {
|
||||
LabelPolicyPrivateLabel bool
|
||||
LabelPolicyWatermark bool
|
||||
CustomDomain bool
|
||||
CustomText bool
|
||||
}
|
||||
|
||||
type FeaturesState int32
|
||||
|
@ -1,22 +0,0 @@
|
||||
package domain
|
||||
|
||||
import "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
|
||||
type MailText struct {
|
||||
models.ObjectRoot
|
||||
|
||||
State PolicyState
|
||||
Default bool
|
||||
MailTextType string
|
||||
Language string
|
||||
Title string
|
||||
PreHeader string
|
||||
Subject string
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
}
|
||||
|
||||
func (m *MailText) IsValid() bool {
|
||||
return m.MailTextType != "" && m.Language != "" && m.Title != "" && m.PreHeader != "" && m.Subject != "" && m.Greeting != "" && m.Text != "" && m.ButtonText != ""
|
||||
}
|
@ -18,6 +18,7 @@ const (
|
||||
Step13
|
||||
Step14
|
||||
Step15
|
||||
Step16
|
||||
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
|
||||
StepCount
|
||||
)
|
||||
|
@ -28,6 +28,7 @@ type FeaturesView struct {
|
||||
LabelPolicyPrivateLabel bool
|
||||
LabelPolicyWatermark bool
|
||||
CustomDomain bool
|
||||
CustomText bool
|
||||
}
|
||||
|
||||
func (f *FeaturesView) FeatureList() []string {
|
||||
@ -62,6 +63,9 @@ func (f *FeaturesView) FeatureList() []string {
|
||||
if f.CustomDomain {
|
||||
list = append(list, domain.FeatureCustomDomain)
|
||||
}
|
||||
if f.CustomText {
|
||||
list = append(list, domain.FeatureCustomText)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ type FeaturesView struct {
|
||||
LabelPolicyPrivateLabel bool `json:"labelPolicyPrivateLabel" gorm:"column:label_policy_private_label"`
|
||||
LabelPolicyWatermark bool `json:"labelPolicyWatermark" gorm:"column:label_policy_watermark"`
|
||||
CustomDomain bool `json:"customDomain" gorm:"column:custom_domain"`
|
||||
CustomText bool `json:"customText" gorm:"column:custom_text"`
|
||||
}
|
||||
|
||||
func FeaturesToModel(features *FeaturesView) *features_model.FeaturesView {
|
||||
@ -66,6 +67,7 @@ func FeaturesToModel(features *FeaturesView) *features_model.FeaturesView {
|
||||
LabelPolicyPrivateLabel: features.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: features.LabelPolicyWatermark,
|
||||
CustomDomain: features.CustomDomain,
|
||||
CustomText: features.CustomText,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ type MailText struct {
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
FooterText string
|
||||
}
|
||||
|
||||
func (p *MailText) IsValid() bool {
|
||||
|
@ -1,59 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MailTextsView struct {
|
||||
Texts []*MailTextView
|
||||
Default bool
|
||||
}
|
||||
type MailTextView struct {
|
||||
AggregateID string
|
||||
MailTextType string
|
||||
Language string
|
||||
Title string
|
||||
PreHeader string
|
||||
Subject string
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
Default bool
|
||||
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
type MailTextSearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn MailTextSearchKey
|
||||
Asc bool
|
||||
Queries []*MailTextSearchQuery
|
||||
}
|
||||
|
||||
type MailTextSearchKey int32
|
||||
|
||||
const (
|
||||
MailTextSearchKeyUnspecified MailTextSearchKey = iota
|
||||
MailTextSearchKeyAggregateID
|
||||
MailTextSearchKeyMailTextType
|
||||
MailTextSearchKeyLanguage
|
||||
)
|
||||
|
||||
type MailTextSearchQuery struct {
|
||||
Key MailTextSearchKey
|
||||
Method domain.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type MailTextSearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*MailTextView
|
||||
Sequence uint64
|
||||
Timestamp time.Time
|
||||
}
|
63
internal/iam/model/message_text_view.go
Normal file
63
internal/iam/model/message_text_view.go
Normal file
@ -0,0 +1,63 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
type MessageTextsView struct {
|
||||
Texts []*MessageTextView
|
||||
Default bool
|
||||
}
|
||||
type MessageTextView struct {
|
||||
AggregateID string
|
||||
MessageTextType string
|
||||
Language language.Tag
|
||||
Title string
|
||||
PreHeader string
|
||||
Subject string
|
||||
Greeting string
|
||||
Text string
|
||||
ButtonText string
|
||||
FooterText string
|
||||
Default bool
|
||||
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
type MessageTextSearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn MessageTextSearchKey
|
||||
Asc bool
|
||||
Queries []*MessageTextSearchQuery
|
||||
}
|
||||
|
||||
type MessageTextSearchKey int32
|
||||
|
||||
const (
|
||||
MessageTextSearchKeyUnspecified MessageTextSearchKey = iota
|
||||
MessageTextSearchKeyAggregateID
|
||||
MessageTextSearchKeyMessageTextType
|
||||
MessageTextSearchKeyLanguage
|
||||
)
|
||||
|
||||
type MessageTextSearchQuery struct {
|
||||
Key MessageTextSearchKey
|
||||
Method domain.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type MessageTextSearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*MessageTextView
|
||||
Sequence uint64
|
||||
Timestamp time.Time
|
||||
}
|
@ -33,64 +33,23 @@ type IAM struct {
|
||||
DefaultLoginPolicy *LoginPolicy `json:"-"`
|
||||
DefaultLabelPolicy *LabelPolicy `json:"-"`
|
||||
DefaultMailTemplate *MailTemplate `json:"-"`
|
||||
DefaultMailTexts []*MailText `json:"-"`
|
||||
DefaultOrgIAMPolicy *OrgIAMPolicy `json:"-"`
|
||||
DefaultPasswordComplexityPolicy *PasswordComplexityPolicy `json:"-"`
|
||||
DefaultPasswordAgePolicy *PasswordAgePolicy `json:"-"`
|
||||
DefaultPasswordLockoutPolicy *PasswordLockoutPolicy `json:"-"`
|
||||
}
|
||||
|
||||
func IAMFromModel(iam *model.IAM) *IAM {
|
||||
members := IAMMembersFromModel(iam.Members)
|
||||
idps := IDPConfigsFromModel(iam.IDPs)
|
||||
mailTexts := MailTextsFromModel(iam.DefaultMailTexts)
|
||||
converted := &IAM{
|
||||
ObjectRoot: iam.ObjectRoot,
|
||||
SetUpStarted: Step(iam.SetUpStarted),
|
||||
SetUpDone: Step(iam.SetUpDone),
|
||||
GlobalOrgID: iam.GlobalOrgID,
|
||||
IAMProjectID: iam.IAMProjectID,
|
||||
Members: members,
|
||||
IDPs: idps,
|
||||
DefaultMailTexts: mailTexts,
|
||||
}
|
||||
if iam.DefaultLoginPolicy != nil {
|
||||
converted.DefaultLoginPolicy = LoginPolicyFromModel(iam.DefaultLoginPolicy)
|
||||
}
|
||||
if iam.DefaultLabelPolicy != nil {
|
||||
converted.DefaultLabelPolicy = LabelPolicyFromModel(iam.DefaultLabelPolicy)
|
||||
}
|
||||
if iam.DefaultMailTemplate != nil {
|
||||
converted.DefaultMailTemplate = MailTemplateFromModel(iam.DefaultMailTemplate)
|
||||
}
|
||||
if iam.DefaultPasswordComplexityPolicy != nil {
|
||||
converted.DefaultPasswordComplexityPolicy = PasswordComplexityPolicyFromModel(iam.DefaultPasswordComplexityPolicy)
|
||||
}
|
||||
if iam.DefaultPasswordAgePolicy != nil {
|
||||
converted.DefaultPasswordAgePolicy = PasswordAgePolicyFromModel(iam.DefaultPasswordAgePolicy)
|
||||
}
|
||||
if iam.DefaultPasswordLockoutPolicy != nil {
|
||||
converted.DefaultPasswordLockoutPolicy = PasswordLockoutPolicyFromModel(iam.DefaultPasswordLockoutPolicy)
|
||||
}
|
||||
if iam.DefaultOrgIAMPolicy != nil {
|
||||
converted.DefaultOrgIAMPolicy = OrgIAMPolicyFromModel(iam.DefaultOrgIAMPolicy)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func IAMToModel(iam *IAM) *model.IAM {
|
||||
members := IAMMembersToModel(iam.Members)
|
||||
idps := IDPConfigsToModel(iam.IDPs)
|
||||
mailTexts := MailTextsToModel(iam.DefaultMailTexts)
|
||||
converted := &model.IAM{
|
||||
ObjectRoot: iam.ObjectRoot,
|
||||
SetUpStarted: domain.Step(iam.SetUpStarted),
|
||||
SetUpDone: domain.Step(iam.SetUpDone),
|
||||
GlobalOrgID: iam.GlobalOrgID,
|
||||
IAMProjectID: iam.IAMProjectID,
|
||||
Members: members,
|
||||
IDPs: idps,
|
||||
DefaultMailTexts: mailTexts,
|
||||
ObjectRoot: iam.ObjectRoot,
|
||||
SetUpStarted: domain.Step(iam.SetUpStarted),
|
||||
SetUpDone: domain.Step(iam.SetUpDone),
|
||||
GlobalOrgID: iam.GlobalOrgID,
|
||||
IAMProjectID: iam.IAMProjectID,
|
||||
Members: members,
|
||||
IDPs: idps,
|
||||
}
|
||||
if iam.DefaultLoginPolicy != nil {
|
||||
converted.DefaultLoginPolicy = LoginPolicyToModel(iam.DefaultLoginPolicy)
|
||||
@ -199,10 +158,6 @@ func (i *IAM) AppendEvent(event *es_models.Event) (err error) {
|
||||
return i.appendAddMailTemplateEvent(event)
|
||||
case MailTemplateChanged:
|
||||
return i.appendChangeMailTemplateEvent(event)
|
||||
case MailTextAdded:
|
||||
return i.appendAddMailTextEvent(event)
|
||||
case MailTextChanged:
|
||||
return i.appendChangeMailTextEvent(event)
|
||||
case PasswordComplexityPolicyAdded:
|
||||
return i.appendAddPasswordComplexityPolicyEvent(event)
|
||||
case PasswordComplexityPolicyChanged:
|
||||
|
@ -110,43 +110,6 @@ func (p *MailText) Changes(changed *MailText) map[string]interface{} {
|
||||
return changes
|
||||
}
|
||||
|
||||
func (i *IAM) appendAddMailTextEvent(event *es_models.Event) error {
|
||||
mailText := &MailText{}
|
||||
err := mailText.SetDataLabel(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mailText.ObjectRoot.CreationDate = event.CreationDate
|
||||
i.DefaultMailTexts = append(i.DefaultMailTexts, mailText)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IAM) appendChangeMailTextEvent(event *es_models.Event) error {
|
||||
mailText := &MailText{}
|
||||
err := mailText.SetDataLabel(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n, m := GetMailText(i.DefaultMailTexts, mailText.MailTextType, mailText.Language); m != nil {
|
||||
i.DefaultMailTexts[n] = mailText
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IAM) appendRemoveMailTextEvent(event *es_models.Event) error {
|
||||
mailText := &MailText{}
|
||||
err := mailText.SetDataLabel(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n, m := GetMailText(i.DefaultMailTexts, mailText.MailTextType, mailText.Language); m != nil {
|
||||
i.DefaultMailTexts[n] = i.DefaultMailTexts[len(i.DefaultMailTexts)-1]
|
||||
i.DefaultMailTexts[len(i.DefaultMailTexts)-1] = nil
|
||||
i.DefaultMailTexts = i.DefaultMailTexts[:len(i.DefaultMailTexts)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *MailText) SetDataLabel(event *es_models.Event) error {
|
||||
err := json.Unmarshal(event.Data, p)
|
||||
if err != nil {
|
||||
|
@ -1,134 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
|
||||
func TestAppendAddMailTextEvent(t *testing.T) {
|
||||
type args struct {
|
||||
iam *IAM
|
||||
mailText *MailText
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *IAM
|
||||
}{
|
||||
{
|
||||
name: "append add mailText event",
|
||||
args: args{
|
||||
iam: &IAM{},
|
||||
mailText: &MailText{
|
||||
MailTextType: "PasswordReset",
|
||||
Language: "DE"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &IAM{DefaultMailTexts: []*MailText{&MailText{
|
||||
MailTextType: "PasswordReset",
|
||||
Language: "DE"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.mailText != nil {
|
||||
data, _ := json.Marshal(tt.args.mailText)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.iam.appendAddMailTextEvent(tt.args.event)
|
||||
if len(tt.args.iam.DefaultMailTexts) != 1 {
|
||||
t.Errorf("got wrong result should have one mailText actual: %v ", len(tt.args.iam.DefaultMailTexts))
|
||||
}
|
||||
if tt.args.iam.DefaultMailTexts[0] == tt.result.DefaultMailTexts[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultMailTexts[0], tt.args.iam.DefaultMailTexts[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeMailTextEvent(t *testing.T) {
|
||||
type args struct {
|
||||
iam *IAM
|
||||
mailText *MailText
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *IAM
|
||||
}{
|
||||
{
|
||||
name: "append change mailText event",
|
||||
args: args{
|
||||
iam: &IAM{DefaultMailTexts: []*MailText{&MailText{
|
||||
MailTextType: "PasswordReset",
|
||||
Language: "DE"}}},
|
||||
mailText: &MailText{
|
||||
MailTextType: "ChangedPasswordReset",
|
||||
Language: "DE"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &IAM{DefaultMailTexts: []*MailText{&MailText{
|
||||
MailTextType: "PasswordReset",
|
||||
Language: "ChangedDE"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.mailText != nil {
|
||||
data, _ := json.Marshal(tt.args.mailText)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.iam.appendChangeMailTextEvent(tt.args.event)
|
||||
if len(tt.args.iam.DefaultMailTexts) != 1 {
|
||||
t.Errorf("got wrong result should have one mailText actual: %v ", len(tt.args.iam.DefaultMailTexts))
|
||||
}
|
||||
if tt.args.iam.DefaultMailTexts[0] == tt.result.DefaultMailTexts[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultMailTexts[0], tt.args.iam.DefaultMailTexts[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemoveMailTextEvent(t *testing.T) {
|
||||
type args struct {
|
||||
iam *IAM
|
||||
mailText *MailText
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *IAM
|
||||
}{
|
||||
{
|
||||
name: "append remove mailText event",
|
||||
args: args{
|
||||
iam: &IAM{DefaultMailTexts: []*MailText{&MailText{
|
||||
MailTextType: "PasswordReset",
|
||||
Language: "DE",
|
||||
Subject: "Subject"}}},
|
||||
mailText: &MailText{
|
||||
MailTextType: "PasswordReset",
|
||||
Language: "DE"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &IAM{DefaultMailTexts: []*MailText{}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.mailText != nil {
|
||||
data, _ := json.Marshal(tt.args.mailText)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.iam.appendRemoveMailTextEvent(tt.args.event)
|
||||
if len(tt.args.iam.DefaultMailTexts) != 0 {
|
||||
t.Errorf("got wrong result should have no mailText actual: %v ", len(tt.args.iam.DefaultMailTexts))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -54,8 +54,9 @@ const (
|
||||
|
||||
MailTemplateAdded models.EventType = "iam.mail.template.added"
|
||||
MailTemplateChanged models.EventType = "iam.mail.template.changed"
|
||||
MailTextAdded models.EventType = "iam.mail.text.added"
|
||||
MailTextChanged models.EventType = "iam.mail.text.changed"
|
||||
|
||||
CustomTextSet models.EventType = "iam.customtext.set"
|
||||
CustomTextRemoved models.EventType = "iam.customtext.removed"
|
||||
|
||||
PasswordComplexityPolicyAdded models.EventType = "iam.policy.password.complexity.added"
|
||||
PasswordComplexityPolicyChanged models.EventType = "iam.policy.password.complexity.changed"
|
||||
|
@ -1,54 +0,0 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
"github.com/jinzhu/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetMailTexts(db *gorm.DB, table string, aggregateID string) ([]*model.MailTextView, error) {
|
||||
texts := make([]*model.MailTextView, 0)
|
||||
queries := []*iam_model.MailTextSearchQuery{
|
||||
{
|
||||
Key: iam_model.MailTextSearchKeyAggregateID,
|
||||
Value: aggregateID,
|
||||
Method: domain.SearchMethodEquals,
|
||||
},
|
||||
}
|
||||
query := repository.PrepareSearchQuery(table, model.MailTextSearchRequest{Queries: queries})
|
||||
_, err := query(db, &texts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return texts, nil
|
||||
}
|
||||
|
||||
func GetMailTextByIDs(db *gorm.DB, table, aggregateID string, textType string, language string) (*model.MailTextView, error) {
|
||||
mailText := new(model.MailTextView)
|
||||
aggregateIDQuery := &model.MailTextSearchQuery{Key: iam_model.MailTextSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
||||
textTypeQuery := &model.MailTextSearchQuery{Key: iam_model.MailTextSearchKeyMailTextType, Value: textType, Method: domain.SearchMethodEquals}
|
||||
languageQuery := &model.MailTextSearchQuery{Key: iam_model.MailTextSearchKeyLanguage, Value: strings.ToUpper(language), Method: domain.SearchMethodEquals}
|
||||
query := repository.PrepareGetByQuery(table, aggregateIDQuery, textTypeQuery, languageQuery)
|
||||
err := query(db, mailText)
|
||||
if caos_errs.IsNotFound(err) {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-IiJjm", "Errors.IAM.MailText.NotExisting")
|
||||
}
|
||||
return mailText, err
|
||||
}
|
||||
|
||||
func PutMailText(db *gorm.DB, table string, mailText *model.MailTextView) error {
|
||||
save := repository.PrepareSave(table)
|
||||
return save(db, mailText)
|
||||
}
|
||||
|
||||
func DeleteMailText(db *gorm.DB, table, aggregateID string, textType string, language string) error {
|
||||
aggregateIDSearch := repository.Key{Key: model.MailTextSearchKey(iam_model.MailTextSearchKeyAggregateID), Value: aggregateID}
|
||||
textTypeSearch := repository.Key{Key: model.MailTextSearchKey(iam_model.MailTextSearchKeyMailTextType), Value: textType}
|
||||
languageSearch := repository.Key{Key: model.MailTextSearchKey(iam_model.MailTextSearchKeyLanguage), Value: language}
|
||||
delete := repository.PrepareDeleteByKeys(table, aggregateIDSearch, textTypeSearch, languageSearch)
|
||||
return delete(db)
|
||||
}
|
54
internal/iam/repository/view/message_text_view.go
Normal file
54
internal/iam/repository/view/message_text_view.go
Normal file
@ -0,0 +1,54 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
func GetMessageTexts(db *gorm.DB, table string, aggregateID string) ([]*model.MessageTextView, error) {
|
||||
texts := make([]*model.MessageTextView, 0)
|
||||
queries := []*iam_model.MessageTextSearchQuery{
|
||||
{
|
||||
Key: iam_model.MessageTextSearchKeyAggregateID,
|
||||
Value: aggregateID,
|
||||
Method: domain.SearchMethodEquals,
|
||||
},
|
||||
}
|
||||
query := repository.PrepareSearchQuery(table, model.MessageTextSearchRequest{Queries: queries})
|
||||
_, err := query(db, &texts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return texts, nil
|
||||
}
|
||||
|
||||
func GetMessageTextByIDs(db *gorm.DB, table, aggregateID, textType, lang string) (*model.MessageTextView, error) {
|
||||
mailText := new(model.MessageTextView)
|
||||
aggregateIDQuery := &model.MessageTextSearchQuery{Key: iam_model.MessageTextSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
||||
textTypeQuery := &model.MessageTextSearchQuery{Key: iam_model.MessageTextSearchKeyMessageTextType, Value: textType, Method: domain.SearchMethodEquals}
|
||||
languageQuery := &model.MessageTextSearchQuery{Key: iam_model.MessageTextSearchKeyLanguage, Value: lang, Method: domain.SearchMethodEquals}
|
||||
query := repository.PrepareGetByQuery(table, aggregateIDQuery, textTypeQuery, languageQuery)
|
||||
err := query(db, mailText)
|
||||
if caos_errs.IsNotFound(err) {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-IiJjm", "Errors.IAM.CustomMessageText.NotExisting")
|
||||
}
|
||||
return mailText, err
|
||||
}
|
||||
|
||||
func PutMessageText(db *gorm.DB, table string, mailText *model.MessageTextView) error {
|
||||
save := repository.PrepareSave(table)
|
||||
return save(db, mailText)
|
||||
}
|
||||
|
||||
func DeleteMessageText(db *gorm.DB, table, aggregateID, textType, lang string) error {
|
||||
aggregateIDSearch := repository.Key{Key: model.MessageTextSearchKey(iam_model.MessageTextSearchKeyAggregateID), Value: aggregateID}
|
||||
textTypeSearch := repository.Key{Key: model.MessageTextSearchKey(iam_model.MessageTextSearchKeyMessageTextType), Value: textType}
|
||||
languageSearch := repository.Key{Key: model.MessageTextSearchKey(iam_model.MessageTextSearchKeyLanguage), Value: lang}
|
||||
delete := repository.PrepareDeleteByKeys(table, aggregateIDSearch, textTypeSearch, languageSearch)
|
||||
return delete(db)
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
|
||||
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
const (
|
||||
MailTextKeyAggregateID = "aggregate_id"
|
||||
MailTextKeyMailTextType = "mail_text_type"
|
||||
MailTextKeyLanguage = "language"
|
||||
)
|
||||
|
||||
type MailTextView struct {
|
||||
AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"`
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
State int32 `json:"-" gorm:"column:mail_text_state"`
|
||||
|
||||
MailTextType string `json:"mailTextType" gorm:"column:mail_text_type;primary_key"`
|
||||
Language string `json:"language" gorm:"column:language;primary_key"`
|
||||
Title string `json:"title" gorm:"column:title"`
|
||||
PreHeader string `json:"preHeader" gorm:"column:pre_header"`
|
||||
Subject string `json:"subject" gorm:"column:subject"`
|
||||
Greeting string `json:"greeting" gorm:"column:greeting"`
|
||||
Text string `json:"text" gorm:"column:text"`
|
||||
ButtonText string `json:"buttonText" gorm:"column:button_text"`
|
||||
Default bool `json:"-" gorm:"-"`
|
||||
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
}
|
||||
|
||||
func MailTextViewFromModel(template *model.MailTextView) *MailTextView {
|
||||
return &MailTextView{
|
||||
AggregateID: template.AggregateID,
|
||||
Sequence: template.Sequence,
|
||||
CreationDate: template.CreationDate,
|
||||
ChangeDate: template.ChangeDate,
|
||||
MailTextType: template.MailTextType,
|
||||
Language: template.Language,
|
||||
Title: template.Title,
|
||||
PreHeader: template.PreHeader,
|
||||
Subject: template.Subject,
|
||||
Greeting: template.Greeting,
|
||||
Text: template.Text,
|
||||
ButtonText: template.ButtonText,
|
||||
Default: template.Default,
|
||||
}
|
||||
}
|
||||
|
||||
func MailTextsViewToModel(textsIn []*MailTextView, defaultIn bool) *model.MailTextsView {
|
||||
return &model.MailTextsView{
|
||||
Texts: mailTextsViewToModelArr(textsIn, defaultIn),
|
||||
}
|
||||
}
|
||||
|
||||
func mailTextsViewToModelArr(texts []*MailTextView, defaultIn bool) []*model.MailTextView {
|
||||
result := make([]*model.MailTextView, len(texts))
|
||||
for i, r := range texts {
|
||||
r.Default = defaultIn
|
||||
result[i] = MailTextViewToModel(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func MailTextViewToModel(template *MailTextView) *model.MailTextView {
|
||||
return &model.MailTextView{
|
||||
AggregateID: template.AggregateID,
|
||||
Sequence: template.Sequence,
|
||||
CreationDate: template.CreationDate,
|
||||
ChangeDate: template.ChangeDate,
|
||||
MailTextType: template.MailTextType,
|
||||
Language: template.Language,
|
||||
Title: template.Title,
|
||||
PreHeader: template.PreHeader,
|
||||
Subject: template.Subject,
|
||||
Greeting: template.Greeting,
|
||||
Text: template.Text,
|
||||
ButtonText: template.ButtonText,
|
||||
Default: template.Default,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *MailTextView) AppendEvent(event *models.Event) (err error) {
|
||||
i.Sequence = event.Sequence
|
||||
switch event.Type {
|
||||
case es_model.MailTextAdded, org_es_model.MailTextAdded:
|
||||
i.setRootData(event)
|
||||
i.CreationDate = event.CreationDate
|
||||
err = i.SetData(event)
|
||||
case es_model.MailTextChanged, org_es_model.MailTextChanged:
|
||||
i.ChangeDate = event.CreationDate
|
||||
err = i.SetData(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *MailTextView) setRootData(event *models.Event) {
|
||||
r.AggregateID = event.AggregateID
|
||||
}
|
||||
|
||||
func (r *MailTextView) SetData(event *models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||
logging.Log("MODEL-UFqAG").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-5CVaR", "Could not unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
type MailTextSearchRequest iam_model.MailTextSearchRequest
|
||||
type MailTextSearchQuery iam_model.MailTextSearchQuery
|
||||
type MailTextSearchKey iam_model.MailTextSearchKey
|
||||
|
||||
func (req MailTextSearchRequest) GetLimit() uint64 {
|
||||
return req.Limit
|
||||
}
|
||||
|
||||
func (req MailTextSearchRequest) GetOffset() uint64 {
|
||||
return req.Offset
|
||||
}
|
||||
|
||||
func (req MailTextSearchRequest) GetSortingColumn() repository.ColumnKey {
|
||||
if req.SortingColumn == iam_model.MailTextSearchKeyUnspecified {
|
||||
return nil
|
||||
}
|
||||
return MailTextSearchKey(req.SortingColumn)
|
||||
}
|
||||
|
||||
func (req MailTextSearchRequest) GetAsc() bool {
|
||||
return req.Asc
|
||||
}
|
||||
|
||||
func (req MailTextSearchRequest) GetQueries() []repository.SearchQuery {
|
||||
result := make([]repository.SearchQuery, len(req.Queries))
|
||||
for i, q := range req.Queries {
|
||||
result[i] = MailTextSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (req MailTextSearchQuery) GetKey() repository.ColumnKey {
|
||||
return MailTextSearchKey(req.Key)
|
||||
}
|
||||
|
||||
func (req MailTextSearchQuery) GetMethod() domain.SearchMethod {
|
||||
return req.Method
|
||||
}
|
||||
|
||||
func (req MailTextSearchQuery) GetValue() interface{} {
|
||||
return req.Value
|
||||
}
|
||||
|
||||
func (key MailTextSearchKey) ToColumnName() string {
|
||||
switch iam_model.MailTextSearchKey(key) {
|
||||
case iam_model.MailTextSearchKeyAggregateID:
|
||||
return MailTextKeyAggregateID
|
||||
case iam_model.MailTextSearchKeyMailTextType:
|
||||
return MailTextKeyMailTextType
|
||||
case iam_model.MailTextSearchKeyLanguage:
|
||||
return MailTextKeyLanguage
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
184
internal/iam/repository/view/model/message_text.go
Normal file
184
internal/iam/repository/view/model/message_text.go
Normal file
@ -0,0 +1,184 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
|
||||
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
const (
|
||||
MessageTextKeyAggregateID = "aggregate_id"
|
||||
MessageTextKeyMessageTextType = "message_text_type"
|
||||
MessageTextKeyLanguage = "language"
|
||||
)
|
||||
|
||||
type MessageTextView struct {
|
||||
AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"`
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
State int32 `json:"-" gorm:"column:message_text_state"`
|
||||
|
||||
MessageTextType string `json:"-" gorm:"column:message_text_type;primary_key"`
|
||||
Language string `json:"-" gorm:"column:language;primary_key"`
|
||||
Title string `json:"-" gorm:"column:title"`
|
||||
PreHeader string `json:"-" gorm:"column:pre_header"`
|
||||
Subject string `json:"-" gorm:"column:subject"`
|
||||
Greeting string `json:"-" gorm:"column:greeting"`
|
||||
Text string `json:"-" gorm:"column:text"`
|
||||
ButtonText string `json:"-" gorm:"column:button_text"`
|
||||
FooterText string `json:"-" gorm:"column:footer_text"`
|
||||
Default bool `json:"-" gorm:"-"`
|
||||
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
}
|
||||
|
||||
func MessageTextViewFromModel(template *model.MessageTextView) *MessageTextView {
|
||||
return &MessageTextView{
|
||||
AggregateID: template.AggregateID,
|
||||
Sequence: template.Sequence,
|
||||
CreationDate: template.CreationDate,
|
||||
ChangeDate: template.ChangeDate,
|
||||
MessageTextType: template.MessageTextType,
|
||||
Language: template.Language.String(),
|
||||
Title: template.Title,
|
||||
PreHeader: template.PreHeader,
|
||||
Subject: template.Subject,
|
||||
Greeting: template.Greeting,
|
||||
Text: template.Text,
|
||||
ButtonText: template.ButtonText,
|
||||
FooterText: template.FooterText,
|
||||
Default: template.Default,
|
||||
}
|
||||
}
|
||||
|
||||
func MessageTextsViewToModel(textsIn []*MessageTextView, defaultIn bool) *model.MessageTextsView {
|
||||
return &model.MessageTextsView{
|
||||
Texts: messageTextsViewToModelArr(textsIn, defaultIn),
|
||||
}
|
||||
}
|
||||
|
||||
func messageTextsViewToModelArr(texts []*MessageTextView, defaultIn bool) []*model.MessageTextView {
|
||||
result := make([]*model.MessageTextView, len(texts))
|
||||
for i, r := range texts {
|
||||
r.Default = defaultIn
|
||||
result[i] = MessageTextViewToModel(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func MessageTextViewToModel(template *MessageTextView) *model.MessageTextView {
|
||||
lang := language.Make(template.Language)
|
||||
return &model.MessageTextView{
|
||||
AggregateID: template.AggregateID,
|
||||
Sequence: template.Sequence,
|
||||
CreationDate: template.CreationDate,
|
||||
ChangeDate: template.ChangeDate,
|
||||
MessageTextType: template.MessageTextType,
|
||||
Language: lang,
|
||||
Title: template.Title,
|
||||
PreHeader: template.PreHeader,
|
||||
Subject: template.Subject,
|
||||
Greeting: template.Greeting,
|
||||
Text: template.Text,
|
||||
ButtonText: template.ButtonText,
|
||||
FooterText: template.FooterText,
|
||||
Default: template.Default,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *MessageTextView) AppendEvent(event *models.Event) (err error) {
|
||||
i.Sequence = event.Sequence
|
||||
switch event.Type {
|
||||
case es_model.CustomTextSet, org_es_model.CustomTextSet:
|
||||
i.setRootData(event)
|
||||
customText := new(CustomText)
|
||||
err = customText.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if customText.Key == domain.MessageTitle {
|
||||
i.Title = customText.Text
|
||||
}
|
||||
if customText.Key == domain.MessagePreHeader {
|
||||
i.PreHeader = customText.Text
|
||||
}
|
||||
if customText.Key == domain.MessageSubject {
|
||||
i.Subject = customText.Text
|
||||
}
|
||||
if customText.Key == domain.MessageGreeting {
|
||||
i.Greeting = customText.Text
|
||||
}
|
||||
if customText.Key == domain.MessageText {
|
||||
i.Text = customText.Text
|
||||
}
|
||||
if customText.Key == domain.MessageButtonText {
|
||||
i.ButtonText = customText.Text
|
||||
}
|
||||
if customText.Key == domain.MessageFooterText {
|
||||
i.FooterText = customText.Text
|
||||
}
|
||||
i.ChangeDate = event.CreationDate
|
||||
case es_model.CustomTextRemoved, org_es_model.CustomTextRemoved:
|
||||
customText := new(CustomText)
|
||||
err = customText.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if customText.Key == domain.MessageTitle {
|
||||
i.Title = ""
|
||||
}
|
||||
if customText.Key == domain.MessagePreHeader {
|
||||
i.PreHeader = ""
|
||||
}
|
||||
if customText.Key == domain.MessageSubject {
|
||||
i.Subject = ""
|
||||
}
|
||||
if customText.Key == domain.MessageGreeting {
|
||||
i.Greeting = ""
|
||||
}
|
||||
if customText.Key == domain.MessageText {
|
||||
i.Text = ""
|
||||
}
|
||||
if customText.Key == domain.MessageButtonText {
|
||||
i.ButtonText = ""
|
||||
}
|
||||
if customText.Key == domain.MessageFooterText {
|
||||
i.FooterText = ""
|
||||
}
|
||||
i.ChangeDate = event.CreationDate
|
||||
case org_es_model.CustomTextMessageRemoved:
|
||||
i.State = int32(model.PolicyStateRemoved)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *MessageTextView) setRootData(event *models.Event) {
|
||||
r.AggregateID = event.AggregateID
|
||||
}
|
||||
|
||||
type CustomText struct {
|
||||
Template string `json:"template"`
|
||||
Key string `json:"key"`
|
||||
Language language.Tag `json:"language"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
func (r *CustomText) SetData(event *models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||
logging.Log("MODEL-3n9fs").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-5CVaR", "Could not unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
63
internal/iam/repository/view/model/message_text_query.go
Normal file
63
internal/iam/repository/view/model/message_text_query.go
Normal file
@ -0,0 +1,63 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
type MessageTextSearchRequest iam_model.MessageTextSearchRequest
|
||||
type MessageTextSearchQuery iam_model.MessageTextSearchQuery
|
||||
type MessageTextSearchKey iam_model.MessageTextSearchKey
|
||||
|
||||
func (req MessageTextSearchRequest) GetLimit() uint64 {
|
||||
return req.Limit
|
||||
}
|
||||
|
||||
func (req MessageTextSearchRequest) GetOffset() uint64 {
|
||||
return req.Offset
|
||||
}
|
||||
|
||||
func (req MessageTextSearchRequest) GetSortingColumn() repository.ColumnKey {
|
||||
if req.SortingColumn == iam_model.MessageTextSearchKeyUnspecified {
|
||||
return nil
|
||||
}
|
||||
return MessageTextSearchKey(req.SortingColumn)
|
||||
}
|
||||
|
||||
func (req MessageTextSearchRequest) GetAsc() bool {
|
||||
return req.Asc
|
||||
}
|
||||
|
||||
func (req MessageTextSearchRequest) GetQueries() []repository.SearchQuery {
|
||||
result := make([]repository.SearchQuery, len(req.Queries))
|
||||
for i, q := range req.Queries {
|
||||
result[i] = MessageTextSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (req MessageTextSearchQuery) GetKey() repository.ColumnKey {
|
||||
return MessageTextSearchKey(req.Key)
|
||||
}
|
||||
|
||||
func (req MessageTextSearchQuery) GetMethod() domain.SearchMethod {
|
||||
return req.Method
|
||||
}
|
||||
|
||||
func (req MessageTextSearchQuery) GetValue() interface{} {
|
||||
return req.Value
|
||||
}
|
||||
|
||||
func (key MessageTextSearchKey) ToColumnName() string {
|
||||
switch iam_model.MessageTextSearchKey(key) {
|
||||
case iam_model.MessageTextSearchKeyAggregateID:
|
||||
return MessageTextKeyAggregateID
|
||||
case iam_model.MessageTextSearchKeyMessageTextType:
|
||||
return MessageTextKeyMessageTextType
|
||||
case iam_model.MessageTextSearchKeyLanguage:
|
||||
return MessageTextKeyLanguage
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
@ -548,19 +548,19 @@ func (repo *OrgRepository) GetMailTemplate(ctx context.Context) (*iam_model.Mail
|
||||
return iam_es_model.MailTemplateViewToModel(template), err
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetDefaultMailTexts(ctx context.Context) (*iam_model.MailTextsView, error) {
|
||||
texts, err := repo.View.MailTextsByAggregateID(repo.SystemDefaults.IamID)
|
||||
func (repo *OrgRepository) GetDefaultMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error) {
|
||||
texts, err := repo.View.MessageTextsByAggregateID(repo.SystemDefaults.IamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_es_model.MailTextsViewToModel(texts, true), err
|
||||
return iam_es_model.MessageTextsViewToModel(texts, true), err
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetMailTexts(ctx context.Context) (*iam_model.MailTextsView, error) {
|
||||
func (repo *OrgRepository) GetMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error) {
|
||||
defaultIn := false
|
||||
texts, err := repo.View.MailTextsByAggregateID(authz.GetCtxData(ctx).OrgID)
|
||||
texts, err := repo.View.MessageTextsByAggregateID(authz.GetCtxData(ctx).OrgID)
|
||||
if errors.IsNotFound(err) || len(texts) == 0 {
|
||||
texts, err = repo.View.MailTextsByAggregateID(repo.SystemDefaults.IamID)
|
||||
texts, err = repo.View.MessageTextsByAggregateID(repo.SystemDefaults.IamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -569,7 +569,31 @@ func (repo *OrgRepository) GetMailTexts(ctx context.Context) (*iam_model.MailTex
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_es_model.MailTextsViewToModel(texts, defaultIn), err
|
||||
return iam_es_model.MessageTextsViewToModel(texts, defaultIn), err
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetDefaultMessageText(ctx context.Context, textType, lang string) (*iam_model.MessageTextView, error) {
|
||||
text, err := repo.View.MessageTextByIDs(repo.SystemDefaults.IamID, textType, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
text.Default = true
|
||||
return iam_es_model.MessageTextViewToModel(text), err
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetMessageText(ctx context.Context, orgID, textType, lang string) (*iam_model.MessageTextView, error) {
|
||||
text, err := repo.View.MessageTextByIDs(orgID, textType, lang)
|
||||
if errors.IsNotFound(err) {
|
||||
result, err := repo.GetDefaultMessageText(ctx, textType, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_es_model.MessageTextViewToModel(text), err
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) getOrgChanges(ctx context.Context, orgID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*org_model.OrgChanges, error) {
|
||||
|
@ -77,8 +77,8 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
|
||||
handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount, es}),
|
||||
newMailTemplate(
|
||||
handler{view, bulkLimit, configs.cycleDuration("MailTemplate"), errorCount, es}),
|
||||
newMailText(
|
||||
handler{view, bulkLimit, configs.cycleDuration("MailText"), errorCount, es}),
|
||||
newMessageText(
|
||||
handler{view, bulkLimit, configs.cycleDuration("MessageText"), errorCount, es}),
|
||||
newFeatures(
|
||||
handler{view, bulkLimit, configs.cycleDuration("Features"), errorCount, es}),
|
||||
}
|
||||
|
@ -1,111 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
type MailText struct {
|
||||
handler
|
||||
subscription *v1.Subscription
|
||||
}
|
||||
|
||||
func newMailText(handler handler) *MailText {
|
||||
h := &MailText{
|
||||
handler: handler,
|
||||
}
|
||||
|
||||
h.subscribe()
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (m *MailText) subscribe() {
|
||||
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
|
||||
go func() {
|
||||
for event := range m.subscription.Events {
|
||||
query.ReduceEvent(m, event)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
const (
|
||||
mailTextTable = "management.mail_texts"
|
||||
)
|
||||
|
||||
func (m *MailText) ViewModel() string {
|
||||
return mailTextTable
|
||||
}
|
||||
|
||||
func (_ *MailText) AggregateTypes() []es_models.AggregateType {
|
||||
return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
|
||||
}
|
||||
|
||||
func (p *MailText) CurrentSequence() (uint64, error) {
|
||||
sequence, err := p.view.GetLatestMailTextSequence()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return sequence.CurrentSequence, nil
|
||||
}
|
||||
|
||||
func (m *MailText) EventQuery() (*es_models.SearchQuery, error) {
|
||||
sequence, err := m.view.GetLatestMailTextSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(m.AggregateTypes()...).
|
||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
||||
}
|
||||
|
||||
func (m *MailText) Reduce(event *es_models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case model.OrgAggregate, iam_es_model.IAMAggregate:
|
||||
err = m.processMailText(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *MailText) processMailText(event *es_models.Event) (err error) {
|
||||
text := new(iam_model.MailTextView)
|
||||
switch event.Type {
|
||||
case iam_es_model.MailTextAdded, model.MailTextAdded:
|
||||
err = text.AppendEvent(event)
|
||||
case iam_es_model.MailTextChanged, model.MailTextChanged:
|
||||
err = text.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
text, err = m.view.MailTextByIDs(event.AggregateID, text.MailTextType, text.Language)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
text.ChangeDate = event.CreationDate
|
||||
err = text.AppendEvent(event)
|
||||
case model.MailTextRemoved:
|
||||
err = text.SetData(event)
|
||||
return m.view.DeleteMailText(event.AggregateID, text.MailTextType, text.Language, event)
|
||||
default:
|
||||
return m.view.ProcessedMailTextSequence(event)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.PutMailText(text, event)
|
||||
}
|
||||
|
||||
func (m *MailText) OnError(event *es_models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label text handler")
|
||||
return spooler.HandleError(event, err, m.view.GetLatestMailTextFailedEvent, m.view.ProcessedMailTextFailedEvent, m.view.ProcessedMailTextSequence, m.errorCountUntilSkip)
|
||||
}
|
||||
|
||||
func (o *MailText) OnSuccess() error {
|
||||
return spooler.HandleSuccess(o.view.UpdateMailTextSpoolerRunTimestamp)
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
type MessageText struct {
|
||||
handler
|
||||
subscription *v1.Subscription
|
||||
}
|
||||
|
||||
func newMessageText(handler handler) *MessageText {
|
||||
h := &MessageText{
|
||||
handler: handler,
|
||||
}
|
||||
|
||||
h.subscribe()
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (m *MessageText) subscribe() {
|
||||
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
|
||||
go func() {
|
||||
for event := range m.subscription.Events {
|
||||
query.ReduceEvent(m, event)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
const (
|
||||
messageTextTable = "management.message_texts"
|
||||
)
|
||||
|
||||
func (m *MessageText) ViewModel() string {
|
||||
return messageTextTable
|
||||
}
|
||||
|
||||
func (_ *MessageText) AggregateTypes() []es_models.AggregateType {
|
||||
return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
|
||||
}
|
||||
|
||||
func (p *MessageText) CurrentSequence() (uint64, error) {
|
||||
sequence, err := p.view.GetLatestMessageTextSequence()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return sequence.CurrentSequence, nil
|
||||
}
|
||||
|
||||
func (m *MessageText) EventQuery() (*es_models.SearchQuery, error) {
|
||||
sequence, err := m.view.GetLatestMessageTextSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(m.AggregateTypes()...).
|
||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
||||
}
|
||||
|
||||
func (m *MessageText) Reduce(event *es_models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case model.OrgAggregate, iam_es_model.IAMAggregate:
|
||||
err = m.processMessageText(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *MessageText) processMessageText(event *es_models.Event) (err error) {
|
||||
message := new(iam_model.MessageTextView)
|
||||
switch event.Type {
|
||||
case iam_es_model.CustomTextSet, model.CustomTextSet,
|
||||
iam_es_model.CustomTextRemoved, model.CustomTextRemoved:
|
||||
text := new(iam_model.CustomText)
|
||||
err = text.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
message, err = m.view.MessageTextByIDs(event.AggregateID, text.Template, text.Language.String())
|
||||
if err != nil && !caos_errs.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
if caos_errs.IsNotFound(err) {
|
||||
err = nil
|
||||
message = new(iam_model.MessageTextView)
|
||||
message.Language = text.Language.String()
|
||||
message.MessageTextType = text.Template
|
||||
message.CreationDate = event.CreationDate
|
||||
}
|
||||
err = message.AppendEvent(event)
|
||||
case model.CustomTextMessageRemoved:
|
||||
text := new(iam_model.CustomText)
|
||||
err = text.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.DeleteMessageText(event.AggregateID, text.Template, text.Language.String(), event)
|
||||
default:
|
||||
return m.view.ProcessedMessageTextSequence(event)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.PutMessageText(message, event)
|
||||
}
|
||||
|
||||
func (m *MessageText) OnError(event *es_models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label text handler")
|
||||
return spooler.HandleError(event, err, m.view.GetLatestMessageTextFailedEvent, m.view.ProcessedMessageTextFailedEvent, m.view.ProcessedMessageTextSequence, m.errorCountUntilSkip)
|
||||
}
|
||||
|
||||
func (o *MessageText) OnSuccess() error {
|
||||
return spooler.HandleSuccess(o.view.UpdateMessageTextSpoolerRunTimestamp)
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
global_view "github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
mailTextTable = "management.mail_texts"
|
||||
)
|
||||
|
||||
func (v *View) MailTextsByAggregateID(aggregateID string) ([]*model.MailTextView, error) {
|
||||
return view.GetMailTexts(v.Db, mailTextTable, aggregateID)
|
||||
}
|
||||
|
||||
func (v *View) MailTextByIDs(aggregateID string, textType string, language string) (*model.MailTextView, error) {
|
||||
return view.GetMailTextByIDs(v.Db, mailTextTable, aggregateID, textType, language)
|
||||
}
|
||||
|
||||
func (v *View) PutMailText(template *model.MailTextView, event *models.Event) error {
|
||||
err := view.PutMailText(v.Db, mailTextTable, template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedMailTextSequence(event)
|
||||
}
|
||||
|
||||
func (v *View) DeleteMailText(aggregateID string, textType string, language string, event *models.Event) error {
|
||||
err := view.DeleteMailText(v.Db, mailTextTable, aggregateID, textType, language)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedMailTextSequence(event)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMailTextSequence() (*global_view.CurrentSequence, error) {
|
||||
return v.latestSequence(mailTextTable)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMailTextSequence(event *models.Event) error {
|
||||
return v.saveCurrentSequence(mailTextTable, event)
|
||||
}
|
||||
|
||||
func (v *View) UpdateMailTextSpoolerRunTimestamp() error {
|
||||
return v.updateSpoolerRunSequence(mailTextTable)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMailTextFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||
return v.latestFailedEvent(mailTextTable, sequence)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMailTextFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||
return v.saveFailedEvent(failedEvent)
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
global_view "github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
messageTextTable = "management.message_texts"
|
||||
)
|
||||
|
||||
func (v *View) MessageTextsByAggregateID(aggregateID string) ([]*model.MessageTextView, error) {
|
||||
return view.GetMessageTexts(v.Db, messageTextTable, aggregateID)
|
||||
}
|
||||
|
||||
func (v *View) MessageTextByIDs(aggregateID, textType, lang string) (*model.MessageTextView, error) {
|
||||
return view.GetMessageTextByIDs(v.Db, messageTextTable, aggregateID, textType, lang)
|
||||
}
|
||||
|
||||
func (v *View) PutMessageText(template *model.MessageTextView, event *models.Event) error {
|
||||
err := view.PutMessageText(v.Db, messageTextTable, template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedMessageTextSequence(event)
|
||||
}
|
||||
|
||||
func (v *View) DeleteMessageText(aggregateID, textType, lang string, event *models.Event) error {
|
||||
err := view.DeleteMessageText(v.Db, messageTextTable, aggregateID, textType, lang)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedMessageTextSequence(event)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMessageTextSequence() (*global_view.CurrentSequence, error) {
|
||||
return v.latestSequence(messageTextTable)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMessageTextSequence(event *models.Event) error {
|
||||
return v.saveCurrentSequence(messageTextTable, event)
|
||||
}
|
||||
|
||||
func (v *View) UpdateMessageTextSpoolerRunTimestamp() error {
|
||||
return v.updateSpoolerRunSequence(messageTextTable)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestMessageTextFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||
return v.latestFailedEvent(messageTextTable, sequence)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedMessageTextFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||
return v.saveFailedEvent(failedEvent)
|
||||
}
|
@ -44,8 +44,10 @@ type OrgRepository interface {
|
||||
GetDefaultMailTemplate(ctx context.Context) (*iam_model.MailTemplateView, error)
|
||||
GetMailTemplate(ctx context.Context) (*iam_model.MailTemplateView, error)
|
||||
|
||||
GetDefaultMailTexts(ctx context.Context) (*iam_model.MailTextsView, error)
|
||||
GetMailTexts(ctx context.Context) (*iam_model.MailTextsView, error)
|
||||
GetDefaultMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error)
|
||||
GetMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error)
|
||||
GetDefaultMessageText(ctx context.Context, textType string, language string) (*iam_model.MessageTextView, error)
|
||||
GetMessageText(ctx context.Context, orgID, textType, language string) (*iam_model.MessageTextView, error)
|
||||
|
||||
GetLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
GetPreviewLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
|
@ -29,19 +29,19 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
notificationTable = "notification.notifications"
|
||||
NotifyUserID = "NOTIFICATION"
|
||||
labelPolicyTableOrg = "management.label_policies"
|
||||
labelPolicyTableDef = "adminapi.label_policies"
|
||||
mailTemplateTableOrg = "management.mail_templates"
|
||||
mailTemplateTableDef = "adminapi.mail_templates"
|
||||
mailTextTableOrg = "management.mail_texts"
|
||||
mailTextTableDef = "adminapi.mail_texts"
|
||||
mailTextTypeDomainClaimed = "DomainClaimed"
|
||||
mailTextTypeInitCode = "InitCode"
|
||||
mailTextTypePasswordReset = "PasswordReset"
|
||||
mailTextTypeVerifyEmail = "VerifyEmail"
|
||||
mailTextTypeVerifyPhone = "VerifyPhone"
|
||||
notificationTable = "notification.notifications"
|
||||
NotifyUserID = "NOTIFICATION"
|
||||
labelPolicyTableOrg = "management.label_policies"
|
||||
labelPolicyTableDef = "adminapi.label_policies"
|
||||
mailTemplateTableOrg = "management.mail_templates"
|
||||
mailTemplateTableDef = "adminapi.mail_templates"
|
||||
messageTextTableOrg = "management.message_texts"
|
||||
messageTextTableDef = "adminapi.message_texts"
|
||||
messageTextTypeDomainClaimed = "DomainClaimed"
|
||||
messageTextTypeInitCode = "InitCode"
|
||||
messageTextTypePasswordReset = "PasswordReset"
|
||||
messageTextTypeVerifyEmail = "VerifyEmail"
|
||||
messageTextTypeVerifyPhone = "VerifyPhone"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
@ -146,7 +146,6 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
|
||||
if err != nil || alreadyHandled {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := getSetNotifyContextData(event.ResourceOwner)
|
||||
colors, err := n.getLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
@ -163,7 +162,7 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(ctx, mailTextTypeInitCode, user.PreferredLanguage)
|
||||
text, err := n.getMessageText(user, messageTextTypeInitCode, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -202,7 +201,7 @@ func (n *Notification) handlePasswordCode(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(ctx, mailTextTypePasswordReset, user.PreferredLanguage)
|
||||
text, err := n.getMessageText(user, messageTextTypePasswordReset, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -224,7 +223,6 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err
|
||||
if err != nil || alreadyHandled {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := getSetNotifyContextData(event.ResourceOwner)
|
||||
colors, err := n.getLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
@ -241,7 +239,7 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(ctx, mailTextTypeVerifyEmail, user.PreferredLanguage)
|
||||
text, err := n.getMessageText(user, messageTextTypeVerifyEmail, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -268,7 +266,11 @@ func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = types.SendPhoneVerificationCode(n.i18n, user, phoneCode, n.systemDefaults, n.AesCrypto)
|
||||
text, err := n.getMessageText(user, messageTextTypeVerifyPhone, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = types.SendPhoneVerificationCode(text, user, phoneCode, n.systemDefaults, n.AesCrypto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -303,7 +305,7 @@ func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(ctx, mailTextTypeDomainClaimed, user.PreferredLanguage)
|
||||
text, err := n.getMessageText(user, messageTextTypeDomainClaimed, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -395,26 +397,29 @@ func (n *Notification) getMailTemplate(ctx context.Context) (*iam_model.MailTemp
|
||||
}
|
||||
|
||||
// Read organization specific texts
|
||||
func (n *Notification) getMailText(ctx context.Context, textType string, lang string) (*iam_model.MailTextView, error) {
|
||||
func (n *Notification) getMessageText(user *model.NotifyUser, textType, lang string) (*iam_model.MessageTextView, error) {
|
||||
langTag := language.Make(lang)
|
||||
if langTag == language.Und {
|
||||
langTag = n.systemDefaults.DefaultLanguage
|
||||
langTag = language.English
|
||||
}
|
||||
base, _ := langTag.Base()
|
||||
langBase, _ := langTag.Base()
|
||||
|
||||
defaultMessageText, err := n.view.MessageTextByIDs(n.systemDefaults.IamID, textType, langBase.String(), messageTextTableDef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defaultMessageText.Default = true
|
||||
|
||||
// read from Org
|
||||
mailText, err := n.view.MailTextByIDs(authz.GetCtxData(ctx).OrgID, textType, base.String(), mailTextTableOrg)
|
||||
orgMessageText, err := n.view.MessageTextByIDs(user.ResourceOwner, textType, langBase.String(), messageTextTableOrg)
|
||||
if errors.IsNotFound(err) {
|
||||
// read from default
|
||||
mailText, err = n.view.MailTextByIDs(n.systemDefaults.IamID, textType, base.String(), mailTextTableDef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mailText.Default = true
|
||||
return iam_es_model.MessageTextViewToModel(defaultMessageText), nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_es_model.MailTextViewToModel(mailText), err
|
||||
mergedText := mergeMessageTexts(defaultMessageText, orgMessageText)
|
||||
return iam_es_model.MessageTextViewToModel(mergedText), err
|
||||
}
|
||||
|
||||
func (n *Notification) getUserByID(userID string) (*model.NotifyUser, error) {
|
||||
@ -440,3 +445,28 @@ func (n *Notification) getUserByID(userID string) (*model.NotifyUser, error) {
|
||||
}
|
||||
return &userCopy, nil
|
||||
}
|
||||
|
||||
func mergeMessageTexts(defaultText *iam_es_model.MessageTextView, orgText *iam_es_model.MessageTextView) *iam_es_model.MessageTextView {
|
||||
if orgText.Subject == "" {
|
||||
orgText.Subject = defaultText.Subject
|
||||
}
|
||||
if orgText.Title == "" {
|
||||
orgText.Title = defaultText.Title
|
||||
}
|
||||
if orgText.PreHeader == "" {
|
||||
orgText.PreHeader = defaultText.PreHeader
|
||||
}
|
||||
if orgText.Text == "" {
|
||||
orgText.Text = defaultText.Text
|
||||
}
|
||||
if orgText.Greeting == "" {
|
||||
orgText.Greeting = defaultText.Greeting
|
||||
}
|
||||
if orgText.ButtonText == "" {
|
||||
orgText.ButtonText = defaultText.ButtonText
|
||||
}
|
||||
if orgText.FooterText == "" {
|
||||
orgText.FooterText = defaultText.FooterText
|
||||
}
|
||||
return orgText
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
)
|
||||
|
||||
func (v *View) MailTextByIDs(aggregateID string, textType string, language string, mailTextTableVar string) (*model.MailTextView, error) {
|
||||
return view.GetMailTextByIDs(v.Db, mailTextTableVar, aggregateID, textType, language)
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
)
|
||||
|
||||
func (v *View) MessageTextByIDs(aggregateID, textType, lang, messageTextTableVar string) (*model.MessageTextView, error) {
|
||||
return view.GetMessageTextByIDs(v.Db, messageTextTableVar, aggregateID, textType, lang)
|
||||
}
|
@ -53,7 +53,7 @@ func (data *TemplateData) Translate(i18n *i18n.Translator, args map[string]inter
|
||||
data.ButtonText = i18n.Localize(data.ButtonText, nil, langs...)
|
||||
}
|
||||
|
||||
func GetTemplateData(apiDomain, href string, text *iam_model.MailTextView, policy *iam_model.LabelPolicyView) TemplateData {
|
||||
func GetTemplateData(apiDomain, href string, text *iam_model.MessageTextView, policy *iam_model.LabelPolicyView) TemplateData {
|
||||
templateData := TemplateData{
|
||||
Title: text.Title,
|
||||
PreHeader: text.PreHeader,
|
||||
@ -62,6 +62,7 @@ func GetTemplateData(apiDomain, href string, text *iam_model.MailTextView, polic
|
||||
Text: html.UnescapeString(text.Text),
|
||||
Href: href,
|
||||
ButtonText: text.ButtonText,
|
||||
FooterText: text.FooterText,
|
||||
PrimaryColor: defaultPrimaryColor,
|
||||
BackgroundColor: defaultBackgroundColor,
|
||||
FontColor: defaultFontColor,
|
||||
|
@ -15,18 +15,14 @@ type DomainClaimedData struct {
|
||||
URL string
|
||||
}
|
||||
|
||||
func SendDomainClaimed(mailhtml string, text *iam_model.MailTextView, user *view_model.NotifyUser, username string, systemDefaults systemdefaults.SystemDefaults, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
func SendDomainClaimed(mailhtml string, text *iam_model.MessageTextView, user *view_model.NotifyUser, username string, systemDefaults systemdefaults.SystemDefaults, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
url, err := templates.ParseTemplateText(systemDefaults.Notifications.Endpoints.DomainClaimed, &UrlData{UserID: user.ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var args = map[string]interface{}{
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"Username": user.LastEmail,
|
||||
"TempUsername": username,
|
||||
"Domain": strings.Split(user.LastEmail, "@")[1],
|
||||
}
|
||||
var args = mapNotifyUserToArgs(user)
|
||||
args["TempUsername"] = username
|
||||
args["Domain"] = strings.Split(user.LastEmail, "@")[1]
|
||||
|
||||
text.Greeting, err = templates.ParseTemplateText(text.Greeting, args)
|
||||
text.Text, err = templates.ParseTemplateText(text.Text, args)
|
||||
|
@ -16,7 +16,7 @@ type EmailVerificationCodeData struct {
|
||||
URL string
|
||||
}
|
||||
|
||||
func SendEmailVerificationCode(mailhtml string, text *iam_model.MailTextView, user *view_model.NotifyUser, code *es_model.EmailCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
func SendEmailVerificationCode(mailhtml string, text *iam_model.MessageTextView, user *view_model.NotifyUser, code *es_model.EmailCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
codeString, err := crypto.DecryptString(code.Code, alg)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -25,11 +25,9 @@ func SendEmailVerificationCode(mailhtml string, text *iam_model.MailTextView, us
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var args = map[string]interface{}{
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"Code": codeString,
|
||||
}
|
||||
|
||||
var args = mapNotifyUserToArgs(user)
|
||||
args["Code"] = codeString
|
||||
|
||||
text.Greeting, err = templates.ParseTemplateText(text.Greeting, args)
|
||||
text.Text, err = templates.ParseTemplateText(text.Text, args)
|
||||
|
@ -22,7 +22,7 @@ type UrlData struct {
|
||||
PasswordSet bool
|
||||
}
|
||||
|
||||
func SendUserInitCode(mailhtml string, text *iam_model.MailTextView, user *view_model.NotifyUser, code *es_model.InitUserCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
func SendUserInitCode(mailhtml string, text *iam_model.MessageTextView, user *view_model.NotifyUser, code *es_model.InitUserCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
codeString, err := crypto.DecryptString(code.Code, alg)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -31,12 +31,8 @@ func SendUserInitCode(mailhtml string, text *iam_model.MailTextView, user *view_
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var args = map[string]interface{}{
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"Code": codeString,
|
||||
"PreferredLoginName": user.PreferredLoginName,
|
||||
}
|
||||
var args = mapNotifyUserToArgs(user)
|
||||
args["Code"] = codeString
|
||||
|
||||
text.Greeting, err = templates.ParseTemplateText(text.Greeting, args)
|
||||
text.Text, err = templates.ParseTemplateText(text.Text, args)
|
||||
|
@ -18,7 +18,7 @@ type PasswordCodeData struct {
|
||||
URL string
|
||||
}
|
||||
|
||||
func SendPasswordCode(mailhtml string, text *iam_model.MailTextView, user *view_model.NotifyUser, code *es_model.PasswordCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
func SendPasswordCode(mailhtml string, text *iam_model.MessageTextView, user *view_model.NotifyUser, code *es_model.PasswordCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
codeString, err := crypto.DecryptString(code.Code, alg)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -27,11 +27,8 @@ func SendPasswordCode(mailhtml string, text *iam_model.MailTextView, user *view_
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var args = map[string]interface{}{
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"Code": codeString,
|
||||
}
|
||||
var args = mapNotifyUserToArgs(user)
|
||||
args["Code"] = codeString
|
||||
|
||||
text.Greeting, err = templates.ParseTemplateText(text.Greeting, args)
|
||||
text.Text, err = templates.ParseTemplateText(text.Text, args)
|
||||
|
@ -3,7 +3,7 @@ package types
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/i18n"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
"github.com/caos/zitadel/internal/notification/templates"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
@ -13,19 +13,18 @@ type PhoneVerificationCodeData struct {
|
||||
UserID string
|
||||
}
|
||||
|
||||
func SendPhoneVerificationCode(i18n *i18n.Translator, user *view_model.NotifyUser, code *es_model.PhoneCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm) error {
|
||||
func SendPhoneVerificationCode(text *iam_model.MessageTextView, user *view_model.NotifyUser, code *es_model.PhoneCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm) error {
|
||||
codeString, err := crypto.DecryptString(code.Code, alg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var args = map[string]interface{}{
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"Code": codeString,
|
||||
}
|
||||
systemDefaults.Notifications.TemplateData.VerifyPhone.Translate(i18n, args, user.PreferredLanguage)
|
||||
var args = mapNotifyUserToArgs(user)
|
||||
args["Code"] = codeString
|
||||
|
||||
text.Text, err = templates.ParseTemplateText(text.Text, args)
|
||||
|
||||
codeData := &PhoneVerificationCodeData{UserID: user.ID}
|
||||
template, err := templates.ParseTemplateText(systemDefaults.Notifications.TemplateData.VerifyPhone.Text, codeData)
|
||||
template, err := templates.ParseTemplateText(text.Text, codeData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -42,3 +42,21 @@ func sendDebugEmail(message providers.Message, config systemdefaults.Notificatio
|
||||
}
|
||||
return provider.HandleMessage(message)
|
||||
}
|
||||
|
||||
func mapNotifyUserToArgs(user *view_model.NotifyUser) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"UserName": user.UserName,
|
||||
"FirstName": user.FirstName,
|
||||
"LastName": user.LastName,
|
||||
"NickName": user.NickName,
|
||||
"DisplayName": user.DisplayName,
|
||||
"LastEmail": user.LastEmail,
|
||||
"VerifiedEmail": user.VerifiedEmail,
|
||||
"LastPhone": user.LastPhone,
|
||||
"VerifiedPhone": user.VerifiedPhone,
|
||||
"PreferredLoginName": user.PreferredLoginName,
|
||||
"LoginNames": user.LoginNames,
|
||||
"ChangeDate": user.ChangeDate,
|
||||
"CreationDate": user.CreationDate,
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
func (o *Org) appendAddMailTextEvent(event *es_models.Event) error {
|
||||
mailText := &iam_es_model.MailText{}
|
||||
err := mailText.SetDataLabel(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mailText.ObjectRoot.CreationDate = event.CreationDate
|
||||
o.MailTexts = append(o.MailTexts, mailText)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendChangeMailTextEvent(event *es_models.Event) error {
|
||||
mailText := &iam_es_model.MailText{}
|
||||
err := mailText.SetDataLabel(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mailText.ObjectRoot.ChangeDate = event.CreationDate
|
||||
if n, m := iam_es_model.GetMailText(o.MailTexts, mailText.MailTextType, mailText.Language); m != nil {
|
||||
o.MailTexts[n] = mailText
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendRemoveMailTextEvent(event *es_models.Event) error {
|
||||
mailText := &iam_es_model.MailText{}
|
||||
err := mailText.SetDataLabel(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n, m := iam_es_model.GetMailText(o.MailTexts, mailText.MailTextType, mailText.Language); m != nil {
|
||||
o.MailTexts[n] = o.MailTexts[len(o.MailTexts)-1]
|
||||
o.MailTexts[len(o.MailTexts)-1] = nil
|
||||
o.MailTexts = o.MailTexts[:len(o.MailTexts)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
func TestAppendAddMailTextEvent(t *testing.T) {
|
||||
type args struct {
|
||||
org *Org
|
||||
mailText *iam_es_model.MailText
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Org
|
||||
}{
|
||||
{
|
||||
name: "append add mail text event",
|
||||
args: args{
|
||||
org: &Org{},
|
||||
mailText: &iam_es_model.MailText{MailTextType: "Type", Language: "DE"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Org{MailTexts: []*iam_es_model.MailText{&iam_es_model.MailText{MailTextType: "Type", Language: "DE"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.mailText != nil {
|
||||
data, _ := json.Marshal(tt.args.mailText)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.org.appendAddMailTextEvent(tt.args.event)
|
||||
if len(tt.args.org.MailTexts) != 1 {
|
||||
t.Errorf("got wrong result should have one mailtext actual: %v ", len(tt.args.org.MailTexts))
|
||||
}
|
||||
if tt.result.MailTexts[0].Language != tt.args.org.MailTexts[0].Language {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.MailTexts[0].Language, tt.args.org.MailTexts[0].Language)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeMailTextEvent(t *testing.T) {
|
||||
type args struct {
|
||||
org *Org
|
||||
mailText *iam_es_model.MailText
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Org
|
||||
}{
|
||||
{
|
||||
name: "append change mail text event",
|
||||
args: args{
|
||||
org: &Org{MailTexts: []*iam_es_model.MailText{&iam_es_model.MailText{
|
||||
Language: "DE",
|
||||
MailTextType: "TypeX",
|
||||
}}},
|
||||
mailText: &iam_es_model.MailText{MailTextType: "Type", Language: "DE"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Org{MailTexts: []*iam_es_model.MailText{&iam_es_model.MailText{
|
||||
Language: "DE",
|
||||
MailTextType: "Type",
|
||||
}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.mailText != nil {
|
||||
data, _ := json.Marshal(tt.args.mailText)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.org.appendChangeMailTextEvent(tt.args.event)
|
||||
if len(tt.args.org.MailTexts) != 1 {
|
||||
t.Errorf("got wrong result should have one mailtext actual: %v ", len(tt.args.org.MailTexts))
|
||||
}
|
||||
if tt.result.MailTexts[0].Language != tt.args.org.MailTexts[0].Language {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.MailTexts[0].Language, tt.args.org.MailTexts[0].Language)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -26,7 +26,6 @@ type Org struct {
|
||||
OrgIAMPolicy *iam_es_model.OrgIAMPolicy `json:"-"`
|
||||
LabelPolicy *iam_es_model.LabelPolicy `json:"-"`
|
||||
MailTemplate *iam_es_model.MailTemplate `json:"-"`
|
||||
MailTexts []*iam_es_model.MailText `json:"-"`
|
||||
IDPs []*iam_es_model.IDPConfig `json:"-"`
|
||||
LoginPolicy *iam_es_model.LoginPolicy `json:"-"`
|
||||
PasswordComplexityPolicy *iam_es_model.PasswordComplexityPolicy `json:"-"`
|
||||
@ -34,44 +33,6 @@ type Org struct {
|
||||
PasswordLockoutPolicy *iam_es_model.PasswordLockoutPolicy `json:"-"`
|
||||
}
|
||||
|
||||
func OrgFromModel(org *org_model.Org) *Org {
|
||||
members := OrgMembersFromModel(org.Members)
|
||||
domains := OrgDomainsFromModel(org.Domains)
|
||||
idps := iam_es_model.IDPConfigsFromModel(org.IDPs)
|
||||
mailTexts := iam_es_model.MailTextsFromModel(org.MailTexts)
|
||||
converted := &Org{
|
||||
ObjectRoot: org.ObjectRoot,
|
||||
Name: org.Name,
|
||||
State: int32(org.State),
|
||||
Domains: domains,
|
||||
MailTexts: mailTexts,
|
||||
Members: members,
|
||||
IDPs: idps,
|
||||
}
|
||||
if org.OrgIamPolicy != nil {
|
||||
converted.OrgIAMPolicy = iam_es_model.OrgIAMPolicyFromModel(org.OrgIamPolicy)
|
||||
}
|
||||
if org.LoginPolicy != nil {
|
||||
converted.LoginPolicy = iam_es_model.LoginPolicyFromModel(org.LoginPolicy)
|
||||
}
|
||||
if org.LabelPolicy != nil {
|
||||
converted.LabelPolicy = iam_es_model.LabelPolicyFromModel(org.LabelPolicy)
|
||||
}
|
||||
if org.MailTemplate != nil {
|
||||
converted.MailTemplate = iam_es_model.MailTemplateFromModel(org.MailTemplate)
|
||||
}
|
||||
if org.PasswordComplexityPolicy != nil {
|
||||
converted.PasswordComplexityPolicy = iam_es_model.PasswordComplexityPolicyFromModel(org.PasswordComplexityPolicy)
|
||||
}
|
||||
if org.PasswordAgePolicy != nil {
|
||||
converted.PasswordAgePolicy = iam_es_model.PasswordAgePolicyFromModel(org.PasswordAgePolicy)
|
||||
}
|
||||
if org.PasswordLockoutPolicy != nil {
|
||||
converted.PasswordLockoutPolicy = iam_es_model.PasswordLockoutPolicyFromModel(org.PasswordLockoutPolicy)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func OrgToModel(org *Org) *org_model.Org {
|
||||
converted := &org_model.Org{
|
||||
ObjectRoot: org.ObjectRoot,
|
||||
@ -79,7 +40,6 @@ func OrgToModel(org *Org) *org_model.Org {
|
||||
State: org_model.OrgState(org.State),
|
||||
Domains: OrgDomainsToModel(org.Domains),
|
||||
Members: OrgMembersToModel(org.Members),
|
||||
MailTexts: iam_es_model.MailTextsToModel(org.MailTexts),
|
||||
IDPs: iam_es_model.IDPConfigsToModel(org.IDPs),
|
||||
}
|
||||
if org.OrgIAMPolicy != nil {
|
||||
@ -216,12 +176,6 @@ func (o *Org) AppendEvent(event *es_models.Event) (err error) {
|
||||
err = o.appendChangeMailTemplateEvent(event)
|
||||
case MailTemplateRemoved:
|
||||
o.appendRemoveMailTemplateEvent(event)
|
||||
case MailTextAdded:
|
||||
err = o.appendAddMailTextEvent(event)
|
||||
case MailTextChanged:
|
||||
err = o.appendChangeMailTextEvent(event)
|
||||
case MailTextRemoved:
|
||||
o.appendRemoveMailTextEvent(event)
|
||||
case LoginPolicySecondFactorAdded:
|
||||
err = o.appendAddSecondFactorToLoginPolicyEvent(event)
|
||||
case LoginPolicySecondFactorRemoved:
|
||||
|
@ -76,9 +76,10 @@ const (
|
||||
MailTemplateAdded models.EventType = "org.mail.template.added"
|
||||
MailTemplateChanged models.EventType = "org.mail.template.changed"
|
||||
MailTemplateRemoved models.EventType = "org.mail.template.removed"
|
||||
MailTextAdded models.EventType = "org.mail.text.added"
|
||||
MailTextChanged models.EventType = "org.mail.text.changed"
|
||||
MailTextRemoved models.EventType = "org.mail.text.removed"
|
||||
|
||||
CustomTextSet models.EventType = "org.customtext.set"
|
||||
CustomTextRemoved models.EventType = "org.customtext.removed"
|
||||
CustomTextMessageRemoved models.EventType = "org.customtext.template.removed"
|
||||
|
||||
PasswordComplexityPolicyAdded models.EventType = "org.policy.password.complexity.added"
|
||||
PasswordComplexityPolicyChanged models.EventType = "org.policy.password.complexity.changed"
|
||||
|
@ -81,7 +81,7 @@ func (r *ProjectGrantViewSearchRequest) AppendMyResourceOwnerQuery(orgID string)
|
||||
|
||||
func (r *ProjectGrantViewSearchRequest) EnsureLimit(limit uint64) error {
|
||||
if r.Limit > limit {
|
||||
return caos_errors.ThrowInvalidArgument(nil, "SEARCH-2n8fS", "Errors.Limit.ExceedsDefault")
|
||||
return caos_errors.ThrowInvalidArgument(nil, "SEARCH-0fj3s", "Errors.Limit.ExceedsDefault")
|
||||
}
|
||||
if r.Limit == 0 {
|
||||
r.Limit = limit
|
||||
|
@ -35,6 +35,7 @@ type FeaturesSetEvent struct {
|
||||
LabelPolicyPrivateLabel *bool `json:"labelPolicyPrivateLabel,omitempty"`
|
||||
LabelPolicyWatermark *bool `json:"labelPolicyWatermark,omitempty"`
|
||||
CustomDomain *bool `json:"customDomain,omitempty"`
|
||||
CustomText *bool `json:"customText,omitempty"`
|
||||
}
|
||||
|
||||
func (e *FeaturesSetEvent) Data() interface{} {
|
||||
@ -153,6 +154,11 @@ func ChangeCustomDomain(customDomain bool) func(event *FeaturesSetEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeCustomText(customText bool) func(event *FeaturesSetEvent) {
|
||||
return func(e *FeaturesSetEvent) {
|
||||
e.CustomText = &customText
|
||||
}
|
||||
}
|
||||
func FeaturesSetEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &FeaturesSetEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
|
46
internal/repository/iam/custom_text.go
Normal file
46
internal/repository/iam/custom_text.go
Normal file
@ -0,0 +1,46 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
var (
|
||||
CustomTextSetEventType = iamEventTypePrefix + policy.CustomTextSetEventType
|
||||
)
|
||||
|
||||
type CustomTextSetEvent struct {
|
||||
policy.CustomTextSetEvent
|
||||
}
|
||||
|
||||
func NewCustomTextSetEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
template,
|
||||
key,
|
||||
text string,
|
||||
language language.Tag,
|
||||
) *CustomTextSetEvent {
|
||||
return &CustomTextSetEvent{
|
||||
CustomTextSetEvent: *policy.NewCustomTextSetEvent(
|
||||
eventstore.NewBaseEventForPush(ctx, aggregate, CustomTextSetEventType),
|
||||
template,
|
||||
key,
|
||||
text,
|
||||
language),
|
||||
}
|
||||
}
|
||||
|
||||
func CustomTextSetEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e, err := policy.CustomTextSetEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CustomTextSetEvent{CustomTextSetEvent: *e.(*policy.CustomTextSetEvent)}, nil
|
||||
}
|
@ -56,5 +56,6 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
RegisterFilterEventMapper(MailTemplateChangedEventType, MailTemplateChangedEventMapper).
|
||||
RegisterFilterEventMapper(MailTextAddedEventType, MailTextAddedEventMapper).
|
||||
RegisterFilterEventMapper(MailTextChangedEventType, MailTextChangedEventMapper).
|
||||
RegisterFilterEventMapper(CustomTextSetEventType, CustomTextSetEventMapper).
|
||||
RegisterFilterEventMapper(FeaturesSetEventType, FeaturesSetEventMapper)
|
||||
}
|
||||
|
107
internal/repository/org/custom_text.go
Normal file
107
internal/repository/org/custom_text.go
Normal file
@ -0,0 +1,107 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/repository/policy"
|
||||
)
|
||||
|
||||
var (
|
||||
CustomTextSetEventType = orgEventTypePrefix + policy.CustomTextSetEventType
|
||||
CustomTextRemovedEventType = orgEventTypePrefix + policy.CustomTextRemovedEventType
|
||||
CustomTextTemplateRemovedEventType = orgEventTypePrefix + policy.CustomTextTemplateRemovedEventType
|
||||
)
|
||||
|
||||
type CustomTextSetEvent struct {
|
||||
policy.CustomTextSetEvent
|
||||
}
|
||||
|
||||
func NewCustomTextSetEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
template,
|
||||
key,
|
||||
text string,
|
||||
language language.Tag,
|
||||
) *CustomTextSetEvent {
|
||||
return &CustomTextSetEvent{
|
||||
CustomTextSetEvent: *policy.NewCustomTextSetEvent(
|
||||
eventstore.NewBaseEventForPush(ctx, aggregate, CustomTextSetEventType),
|
||||
template,
|
||||
key,
|
||||
text,
|
||||
language),
|
||||
}
|
||||
}
|
||||
|
||||
func CustomTextSetEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e, err := policy.CustomTextSetEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CustomTextSetEvent{CustomTextSetEvent: *e.(*policy.CustomTextSetEvent)}, nil
|
||||
}
|
||||
|
||||
type CustomTextRemovedEvent struct {
|
||||
policy.CustomTextRemovedEvent
|
||||
}
|
||||
|
||||
func NewCustomTextRemovedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
template,
|
||||
key string,
|
||||
language language.Tag,
|
||||
) *CustomTextRemovedEvent {
|
||||
return &CustomTextRemovedEvent{
|
||||
CustomTextRemovedEvent: *policy.NewCustomTextRemovedEvent(
|
||||
eventstore.NewBaseEventForPush(ctx, aggregate, CustomTextRemovedEventType),
|
||||
template,
|
||||
key,
|
||||
language,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func CustomTextRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e, err := policy.CustomTextRemovedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CustomTextRemovedEvent{CustomTextRemovedEvent: *e.(*policy.CustomTextRemovedEvent)}, nil
|
||||
}
|
||||
|
||||
type CustomTextTemplateRemovedEvent struct {
|
||||
policy.CustomTextTemplateRemovedEvent
|
||||
}
|
||||
|
||||
func NewCustomTextTemplateRemovedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
template string,
|
||||
language language.Tag,
|
||||
) *CustomTextTemplateRemovedEvent {
|
||||
return &CustomTextTemplateRemovedEvent{
|
||||
CustomTextTemplateRemovedEvent: *policy.NewCustomTextTemplateRemovedEvent(
|
||||
eventstore.NewBaseEventForPush(ctx, aggregate, CustomTextTemplateRemovedEventType),
|
||||
template,
|
||||
language,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func CustomTextTemplateRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e, err := policy.CustomTextTemplateRemovedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CustomTextTemplateRemovedEvent{CustomTextTemplateRemovedEvent: *e.(*policy.CustomTextTemplateRemovedEvent)}, nil
|
||||
}
|
@ -62,6 +62,9 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
RegisterFilterEventMapper(MailTextAddedEventType, MailTextAddedEventMapper).
|
||||
RegisterFilterEventMapper(MailTextChangedEventType, MailTextChangedEventMapper).
|
||||
RegisterFilterEventMapper(MailTextRemovedEventType, MailTextRemovedEventMapper).
|
||||
RegisterFilterEventMapper(CustomTextSetEventType, CustomTextSetEventMapper).
|
||||
RegisterFilterEventMapper(CustomTextRemovedEventType, CustomTextRemovedEventMapper).
|
||||
RegisterFilterEventMapper(CustomTextTemplateRemovedEventType, CustomTextTemplateRemovedEventMapper).
|
||||
RegisterFilterEventMapper(IDPConfigAddedEventType, IDPConfigAddedEventMapper).
|
||||
RegisterFilterEventMapper(IDPConfigChangedEventType, IDPConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(IDPConfigRemovedEventType, IDPConfigRemovedEventMapper).
|
||||
|
138
internal/repository/policy/custom_text.go
Normal file
138
internal/repository/policy/custom_text.go
Normal file
@ -0,0 +1,138 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
customTextPrefix = "customtext."
|
||||
CustomTextSetEventType = customTextPrefix + "set"
|
||||
CustomTextRemovedEventType = customTextPrefix + "removed"
|
||||
CustomTextTemplateRemovedEventType = customTextPrefix + "template.removed"
|
||||
)
|
||||
|
||||
type CustomTextSetEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Template string `json:"template,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Language language.Tag `json:"language,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
func (e *CustomTextSetEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *CustomTextSetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCustomTextSetEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
template,
|
||||
key,
|
||||
text string,
|
||||
language language.Tag,
|
||||
) *CustomTextSetEvent {
|
||||
return &CustomTextSetEvent{
|
||||
BaseEvent: *base,
|
||||
Template: template,
|
||||
Key: key,
|
||||
Language: language,
|
||||
Text: text,
|
||||
}
|
||||
}
|
||||
|
||||
func CustomTextSetEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &CustomTextSetEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "TEXT-28dwe", "unable to unmarshal custom text")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type CustomTextRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Template string `json:"template,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Language language.Tag `json:"language,omitempty"`
|
||||
}
|
||||
|
||||
func (e *CustomTextRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *CustomTextRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCustomTextRemovedEvent(base *eventstore.BaseEvent, template, key string, language language.Tag) *CustomTextRemovedEvent {
|
||||
return &CustomTextRemovedEvent{
|
||||
BaseEvent: *base,
|
||||
Template: template,
|
||||
Key: key,
|
||||
Language: language,
|
||||
}
|
||||
}
|
||||
|
||||
func CustomTextRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &CustomTextRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "TEXT-28sMf", "unable to unmarshal custom text removed")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type CustomTextTemplateRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Template string `json:"template,omitempty"`
|
||||
Language language.Tag `json:"language,omitempty"`
|
||||
}
|
||||
|
||||
func (e *CustomTextTemplateRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *CustomTextTemplateRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCustomTextTemplateRemovedEvent(base *eventstore.BaseEvent, template string, language language.Tag) *CustomTextTemplateRemovedEvent {
|
||||
return &CustomTextTemplateRemovedEvent{
|
||||
BaseEvent: *base,
|
||||
Template: template,
|
||||
Language: language,
|
||||
}
|
||||
}
|
||||
|
||||
func CustomTextTemplateRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &CustomTextTemplateRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "TEXT-mKKRs", "unable to unmarshal custom text message removed")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
@ -21,6 +21,7 @@ type IAMSetUp struct {
|
||||
Step13 *command.Step13
|
||||
Step14 *command.Step14
|
||||
Step15 *command.Step15
|
||||
Step16 *command.Step16
|
||||
}
|
||||
|
||||
func (setup *IAMSetUp) Steps(currentDone domain.Step) ([]command.Step, error) {
|
||||
@ -42,6 +43,7 @@ func (setup *IAMSetUp) Steps(currentDone domain.Step) ([]command.Step, error) {
|
||||
setup.Step13,
|
||||
setup.Step14,
|
||||
setup.Step15,
|
||||
setup.Step16,
|
||||
} {
|
||||
if step.Step() <= currentDone {
|
||||
continue
|
||||
|
@ -162,11 +162,11 @@ Errors:
|
||||
NotChanged: Default Mail Template wurde nicht verändert
|
||||
AlreadyExists: Default Mail Template existiert bereits
|
||||
Invalid: Default Mail Template ist ungültig
|
||||
MailText:
|
||||
NotFound: Default Mail Text konnte nicht gefunden werden
|
||||
NotChanged: Default Mail Text wurde nicht verändert
|
||||
AlreadyExists: Default Mail Text existiert bereits
|
||||
Invalid: Default Mail Text ist ungültig
|
||||
CustomMessageText:
|
||||
NotFound: Default Message Text konnte nicht gefunden werden
|
||||
NotChanged: Default Message Text wurde nicht verändert
|
||||
AlreadyExists: Default Message Text existiert bereits
|
||||
Invalid: Default Message Text ist ungültig
|
||||
PasswordComplexity:
|
||||
NotFound: Password Komplexitäts Policy konnte nicht gefunden werden
|
||||
Empty: Passwort Komplexitäts Policy ist leer
|
||||
@ -276,11 +276,11 @@ Errors:
|
||||
NotChanged: Default Mail Template wurde nicht verändert
|
||||
AlreadyExists: Default Mail Template existiert bereits
|
||||
Invalid: Default Mail Template ist ungültig
|
||||
MailText:
|
||||
NotFound: Default Mail Text konnte nicht gefunden werden
|
||||
NotChanged: Default Mail Text wurde nicht verändert
|
||||
AlreadyExists: Default Mail Text existiert bereits
|
||||
Invalid: Default Mail Text ist ungültig
|
||||
CustomMessageText:
|
||||
NotFound: Default Message Text konnte nicht gefunden werden
|
||||
NotChanged: Default Message Text wurde nicht verändert
|
||||
AlreadyExists: Default Message Text existiert bereits
|
||||
Invalid: Default Message Text ist ungültig
|
||||
PasswordComplexityPolicy:
|
||||
NotFound: Default Password Complexity Policy konnte nicht gefunden werden
|
||||
NotExisting: Default Password Complexity Policy existiert nicht
|
||||
@ -351,6 +351,10 @@ Errors:
|
||||
AlreadyExists: Schritt ausgeführt existiert bereits
|
||||
Features:
|
||||
NotChanged: Feature hat nicht geändert
|
||||
CustomText:
|
||||
AlreadyExists: Kundenspezifischer Text existiert bereits
|
||||
Invalid: Kundenspezifischer Text ist ungültig
|
||||
NotFound: Kundenspezifischer Text nicht gefunden
|
||||
EventTypes:
|
||||
user:
|
||||
added: Benutzer hinzugefügt
|
||||
@ -569,6 +573,11 @@ EventTypes:
|
||||
config:
|
||||
added: SAML IDP Konfiguration hinzugefügt
|
||||
changed: SAML IDP Konfiguration geändert
|
||||
customtext:
|
||||
set: Kundenspezifischer Text wurde gesetzt
|
||||
removed: Kundenspezifischer Text wurde entfernt
|
||||
template:
|
||||
removed: Kundenspezifisches Text Template wurde entfernt
|
||||
policy:
|
||||
login:
|
||||
added: Login Richtlinie hinzugefügt
|
||||
@ -715,6 +724,9 @@ EventTypes:
|
||||
config:
|
||||
added: SAML IDP Konfiguration hinzugefügt
|
||||
changed: SAML IDP Konfiguration geändert
|
||||
customtext:
|
||||
set: Text wurde gesetzt
|
||||
removed: Text wurde entfernt
|
||||
policy:
|
||||
login:
|
||||
added: Default Login Policy hinzugefügt
|
||||
|
@ -162,11 +162,11 @@ Errors:
|
||||
NotChanged: Default Mail Template has not been changed
|
||||
AlreadyExists: Default Mail Template already exists
|
||||
Invalid: Default Mail Template is invalid
|
||||
MailText:
|
||||
NotFound: Default Mail Text not found
|
||||
NotChanged: Default Mail Text has not been changed
|
||||
AlreadyExists: Default Mail Text already exists
|
||||
Invalid: Default Mail Text is invalid
|
||||
CustomMessageText:
|
||||
NotFound: Default Message Text not found
|
||||
NotChanged: Default Message Text has not been changed
|
||||
AlreadyExists: Default Message Text already exists
|
||||
Invalid: Default Message Text is invalid
|
||||
PasswordComplexity:
|
||||
NotFound: Password Complexity Policy not found
|
||||
Empty: Password Complexity Policy is empty
|
||||
@ -276,11 +276,11 @@ Errors:
|
||||
NotChanged: Default Mail Template has not been changed
|
||||
AlreadyExists: Default Mail Template already exists
|
||||
Invalid: Default Mail Template is invalid
|
||||
MailText:
|
||||
NotFound: Default Mail Text not found
|
||||
NotChanged: Default Mail Text has not been changed
|
||||
AlreadyExists: Default Mail Text already exists
|
||||
Invalid: Default Mail Text is invalid
|
||||
CustomMessageText:
|
||||
NotFound: Default Message Text not found
|
||||
NotChanged: Default Message Text has not been changed
|
||||
AlreadyExists: Default Message Text already exists
|
||||
Invalid: Default Message Text is invalid
|
||||
PasswordComplexityPolicy:
|
||||
NotFound: Default Private Label Policy not found
|
||||
NotExisting: Default Password Complexity Policy not existing
|
||||
@ -351,6 +351,10 @@ Errors:
|
||||
AlreadyExists: Step done already exists
|
||||
Features:
|
||||
NotChanged: Feature hat nicht geändert
|
||||
CustomText:
|
||||
AlreadyExists: Custom text already exists
|
||||
Invalid: Custom text invalid
|
||||
NotFound: Custom text not found
|
||||
EventTypes:
|
||||
user:
|
||||
added: User added
|
||||
|
@ -42,7 +42,7 @@ func (l *Login) handleLoginNameCheck(w http.ResponseWriter, r *http.Request) {
|
||||
data := new(loginData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
if data.Register {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user