fix: Custom text split features (#2225)

* fix: separate tier of custom text (message and login)

* fix: add migration

* fix: build problems

* fix: tests

* Update internal/api/grpc/admin/features.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update internal/api/grpc/admin/features.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* fix: rename sql file

* fix: change sql files

* fix: console

* fix: console

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi 2021-08-18 12:58:57 +02:00 committed by GitHub
parent 0ab973b967
commit f4fa3ecef3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 339 additions and 60 deletions

View File

@ -36,23 +36,23 @@
</form>
<cnsl-info-section class="warn"
*ngIf="serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false"
*ngIf="serviceType == PolicyComponentServiceType.MGMT && (['custom_text.login'] | hasFeature | async) == false"
type="WARN">
{{'FEATURES.NOTAVAILABLE' | translate: ({value:
'custom_text'})}}
'custom_text.login'})}}
</cnsl-info-section>
<div class="divider"></div>
<div class="content" >
<cnsl-edit-text label="one" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false" [default$]="getDefaultInitMessageTextMap$" [current$]="getCustomInitMessageTextMap$" (changedValues)="updateCurrentValues(
<cnsl-edit-text label="one" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text.login'] | hasFeature | async) == false" [default$]="getDefaultInitMessageTextMap$" [current$]="getCustomInitMessageTextMap$" (changedValues)="updateCurrentValues(
$event)"></cnsl-edit-text>
</div>
<div class="actions">
<button class="reset-button" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false" (click)="resetDefault()" color="warn" type="submit"
<button class="reset-button" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text.login'] | hasFeature | async) == false" (click)="resetDefault()" color="warn" type="submit"
mat-stroked-button><i class="las la-history"></i> {{ 'ACTIONS.RESETDEFAULT' | translate }}</button>
<button class="save-button" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false" (click)="saveCurrentMessage()" color="primary" type="submit"
<button class="save-button" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text.login'] | hasFeature | async) == false" (click)="saveCurrentMessage()" color="primary" type="submit"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
</div>

View File

@ -20,21 +20,21 @@
</div>
<cnsl-info-section class="warn"
*ngIf="serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false"
*ngIf="serviceType == PolicyComponentServiceType.MGMT && (['custom_text.message'] | hasFeature | async) == false"
type="WARN">
{{'FEATURES.NOTAVAILABLE' | translate: ({value:
'custom_text'})}}
'custom_text.message'})}}
</cnsl-info-section>
<div class="content" >
<cnsl-edit-text [chips]="chips[currentType]" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false" label="one" [default$]="getDefaultInitMessageTextMap$" [current$]="getCustomInitMessageTextMap$" (changedValues)="updateCurrentValues(
<cnsl-edit-text [chips]="chips[currentType]" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text.message'] | hasFeature | async) == false" label="one" [default$]="getDefaultInitMessageTextMap$" [current$]="getCustomInitMessageTextMap$" (changedValues)="updateCurrentValues(
$event)"></cnsl-edit-text>
</div>
<div class="actions">
<button class="reset-button" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false" (click)="resetDefault()" color="warn" type="submit"
<button class="reset-button" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['custom_text.message'] | hasFeature | async) == false" (click)="resetDefault()" color="warn" type="submit"
mat-stroked-button><i class="las la-history"></i> {{ 'ACTIONS.RESETDEFAULT' | translate }}</button>
<button class="save-button" [disabled]="!updateRequest || serviceType == PolicyComponentServiceType.MGMT && (['custom_text'] | hasFeature | async) == false" (click)="saveCurrentMessage()" color="primary" type="submit"
<button class="save-button" [disabled]="!updateRequest || serviceType == PolicyComponentServiceType.MGMT && (['custom_text.message'] | hasFeature | async) == false" (click)="saveCurrentMessage()" color="primary" type="submit"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
</div>

View File

@ -660,7 +660,7 @@
"2": "Annuliert",
"3": "Durch IAM Owner gesetzt"
},
"NOTAVAILABLE": "Feature {{value}} ist auf Ihrer organisation nicht freigeschaltet!",
"NOTAVAILABLE": "Feature {{value}} ist auf Ihrer Organisation nicht freigeschaltet!",
"RETENTIONDAYS": "Tage"
},
"POLICY": {

View File

@ -2505,6 +2505,8 @@ This is an empty request
| custom_text | bool | - | |
| privacy_policy | bool | - | |
| metadata_user | bool | - | |
| custom_text_message | bool | - | |
| custom_text_login | bool | - | |
@ -2691,6 +2693,8 @@ This is an empty request
| custom_text | bool | - | |
| privacy_policy | bool | - | |
| metadata_user | bool | - | |
| custom_text_message | bool | - | |
| custom_text_login | bool | - | |

View File

@ -74,9 +74,10 @@ func setDefaultFeaturesRequestToDomain(req *admin_pb.SetDefaultFeaturesRequest)
LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel,
LabelPolicyWatermark: req.LabelPolicyWatermark,
CustomDomain: req.CustomDomain,
CustomText: req.CustomText,
PrivacyPolicy: req.PrivacyPolicy,
MetadataUser: req.MetadataUser,
CustomTextLogin: req.CustomTextLogin || req.CustomText,
CustomTextMessage: req.CustomTextMessage,
}
}
@ -97,8 +98,9 @@ func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.
LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel,
LabelPolicyWatermark: req.LabelPolicyWatermark,
CustomDomain: req.CustomDomain,
CustomText: req.CustomText,
PrivacyPolicy: req.PrivacyPolicy,
MetadataUser: req.MetadataUser,
CustomTextLogin: req.CustomTextLogin || req.CustomText,
CustomTextMessage: req.CustomTextMessage,
}
}

View File

@ -27,8 +27,10 @@ func FeaturesFromModel(features *features_model.FeaturesView) *features_pb.Featu
CustomDomain: features.CustomDomain,
LabelPolicyPrivateLabel: features.LabelPolicyPrivateLabel,
LabelPolicyWatermark: features.LabelPolicyWatermark,
CustomText: features.CustomText,
PrivacyPolicy: features.PrivacyPolicy,
CustomText: features.CustomTextMessage,
CustomTextMessage: features.CustomTextMessage,
CustomTextLogin: features.CustomTextLogin,
}
}

View File

@ -151,8 +151,14 @@ func checkFeatures(features *features_view_model.FeaturesView, requiredFeatures
}
continue
}
if requiredFeature == domain.FeatureCustomText {
if !features.CustomText {
if requiredFeature == domain.FeatureCustomTextMessage {
if !features.CustomTextMessage {
return MissingFeatureErr(requiredFeature)
}
continue
}
if requiredFeature == domain.FeatureCustomTextLogin {
if !features.CustomTextLogin {
return MissingFeatureErr(requiredFeature)
}
continue

View File

@ -10,6 +10,25 @@ import (
"github.com/caos/zitadel/internal/repository/policy"
)
type CustomLoginTextsReadModel struct {
eventstore.WriteModel
CustomLoginTexts map[string]*CustomText
}
func (wm *CustomLoginTextsReadModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *policy.CustomTextSetEvent:
wm.CustomLoginTexts[e.Template+e.Language.String()] = &CustomText{Language: e.Language, Template: e.Template}
case *policy.CustomTextTemplateRemovedEvent:
if _, ok := wm.CustomLoginTexts[e.Template+e.Language.String()]; ok {
delete(wm.CustomLoginTexts, e.Template)
}
}
}
return wm.WriteModel.Reduce()
}
type CustomLoginTextReadModel struct {
eventstore.WriteModel
@ -558,6 +577,9 @@ func (wm *CustomLoginTextReadModel) Reduce() error {
continue
}
case *policy.CustomTextTemplateRemovedEvent:
if e.Template != domain.LoginCustomText {
continue
}
wm.State = domain.PolicyStateRemoved
}
}

View File

@ -26,9 +26,10 @@ type FeaturesWriteModel struct {
LabelPolicyPrivateLabel bool
LabelPolicyWatermark bool
CustomDomain bool
CustomText bool
PrivacyPolicy bool
MetadataUser bool
CustomTextMessage bool
CustomTextLogin bool
}
func (wm *FeaturesWriteModel) Reduce() error {
@ -84,12 +85,15 @@ func (wm *FeaturesWriteModel) Reduce() error {
if e.CustomDomain != nil {
wm.CustomDomain = *e.CustomDomain
}
if e.CustomText != nil {
wm.CustomText = *e.CustomText
}
if e.MetadataUser != nil {
wm.MetadataUser = *e.MetadataUser
}
if e.CustomTextMessage != nil {
wm.CustomTextMessage = *e.CustomTextMessage
}
if e.CustomTextLogin != nil {
wm.CustomTextLogin = *e.CustomTextLogin
}
case *features.FeaturesRemovedEvent:
wm.State = domain.FeaturesStateRemoved
}

View File

@ -49,9 +49,10 @@ func (c *Commands) setDefaultFeatures(ctx context.Context, existingFeatures *IAM
features.LabelPolicyPrivateLabel,
features.LabelPolicyWatermark,
features.CustomDomain,
features.CustomText,
features.PrivacyPolicy,
features.MetadataUser,
features.CustomTextMessage,
features.CustomTextLogin,
)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")

View File

@ -67,9 +67,10 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
labelPolicyPrivateLabel,
labelPolicyWatermark,
customDomain,
customText,
privacyPolicy,
metadataUser bool,
metadataUser,
customTextMessage,
customTextLogin bool,
) (*iam.FeaturesSetEvent, bool) {
changes := make([]features.FeaturesChanges, 0)
@ -116,15 +117,18 @@ 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 wm.PrivacyPolicy != privacyPolicy {
changes = append(changes, features.ChangePrivacyPolicy(privacyPolicy))
}
if wm.MetadataUser != metadataUser {
changes = append(changes, features.ChangeMetadataUser(metadataUser))
}
if wm.CustomTextMessage != customTextMessage {
changes = append(changes, features.ChangeCustomTextMessage(customTextMessage))
}
if wm.CustomTextLogin != customTextLogin {
changes = append(changes, features.ChangeCustomTextLogin(customTextLogin))
}
if len(changes) == 0 {
return nil, false
}

View File

@ -67,6 +67,21 @@ func (c *Commands) RemoveOrgLoginTexts(ctx context.Context, resourceOwner string
return writeModelToObjectDetails(&customText.WriteModel), nil
}
func (c *Commands) removeOrgLoginTextsIfExists(ctx context.Context, orgID string) ([]eventstore.EventPusher, error) {
msgTemplates := NewOrgCustomLoginTextsReadModel(orgID)
err := c.eventstore.FilterToQueryReducer(ctx, msgTemplates)
if err != nil {
return nil, err
}
orgAgg := OrgAggregateFromWriteModel(&msgTemplates.WriteModel)
events := make([]eventstore.EventPusher, 0, len(msgTemplates.CustomLoginTexts))
for _, tmpl := range msgTemplates.CustomLoginTexts {
events = append(events, org.NewCustomTextTemplateRemovedEvent(ctx, orgAgg, tmpl.Template, tmpl.Language))
}
return events, nil
}
func (c *Commands) orgCustomLoginTextWriteModelByID(ctx context.Context, orgID string, lang language.Tag) (*OrgCustomLoginTextReadModel, error) {
writeModel := NewOrgCustomLoginTextReadModel(orgID, lang)
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)

View File

@ -3,6 +3,7 @@ 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/org"
)
@ -27,10 +28,19 @@ func (wm *OrgCustomLoginTextReadModel) AppendEvents(events ...eventstore.EventRe
for _, event := range events {
switch e := event.(type) {
case *org.CustomTextSetEvent:
if e.Template != domain.LoginCustomText {
continue
}
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextSetEvent)
case *org.CustomTextRemovedEvent:
if e.Template != domain.LoginCustomText {
continue
}
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextRemovedEvent)
case *org.CustomTextTemplateRemovedEvent:
if e.Template != domain.LoginCustomText {
continue
}
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextTemplateRemovedEvent)
}
}
@ -52,3 +62,58 @@ func (wm *OrgCustomLoginTextReadModel) Query() *eventstore.SearchQueryBuilder {
org.CustomTextTemplateRemovedEventType).
Builder()
}
type OrgCustomLoginTextsReadModel struct {
CustomLoginTextsReadModel
}
func NewOrgCustomLoginTextsReadModel(orgID string) *OrgCustomLoginTextsReadModel {
return &OrgCustomLoginTextsReadModel{
CustomLoginTextsReadModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
CustomLoginTexts: make(map[string]*CustomText),
},
}
}
func (wm *OrgCustomLoginTextsReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.CustomTextSetEvent:
if e.Template != domain.LoginCustomText {
continue
}
wm.CustomLoginTextsReadModel.AppendEvents(&e.CustomTextSetEvent)
case *org.CustomTextRemovedEvent:
if e.Template != domain.LoginCustomText {
continue
}
wm.CustomLoginTextsReadModel.AppendEvents(&e.CustomTextRemovedEvent)
case *org.CustomTextTemplateRemovedEvent:
if e.Template != domain.LoginCustomText {
continue
}
wm.CustomLoginTextsReadModel.AppendEvents(&e.CustomTextTemplateRemovedEvent)
}
}
}
func (wm *OrgCustomLoginTextsReadModel) Reduce() error {
return wm.CustomLoginTextsReadModel.Reduce()
}
func (wm *OrgCustomLoginTextsReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateIDs(wm.CustomLoginTextsReadModel.AggregateID).
AggregateTypes(org.AggregateType).
EventTypes(
org.CustomTextSetEventType,
org.CustomTextRemovedEventType,
org.CustomTextTemplateRemovedEventType).
Builder()
}

View File

@ -3,6 +3,7 @@ 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/org"
)
@ -74,10 +75,19 @@ func (wm *OrgCustomMessageTemplatesReadModel) AppendEvents(events ...eventstore.
for _, event := range events {
switch e := event.(type) {
case *org.CustomTextSetEvent:
if !domain.IsMessageTextType(e.Template) {
continue
}
wm.CustomMessageTemplatesReadModel.AppendEvents(&e.CustomTextSetEvent)
case *org.CustomTextRemovedEvent:
if !domain.IsMessageTextType(e.Template) {
continue
}
wm.CustomMessageTemplatesReadModel.AppendEvents(&e.CustomTextRemovedEvent)
case *org.CustomTextTemplateRemovedEvent:
if !domain.IsMessageTextType(e.Template) {
continue
}
wm.CustomMessageTemplatesReadModel.AppendEvents(&e.CustomTextTemplateRemovedEvent)
}
}

View File

@ -40,9 +40,10 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
features.LabelPolicyPrivateLabel,
features.LabelPolicyWatermark,
features.CustomDomain,
features.CustomText,
features.PrivacyPolicy,
features.MetadataUser,
features.CustomTextMessage,
features.CustomTextLogin,
)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
@ -129,13 +130,22 @@ func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string
events = append(events, removeCustomDomainsEvents...)
}
}
if !features.CustomText {
removeCustomTextEvents, err := c.removeOrgMessageTextsIfExists(ctx, orgID)
if !features.CustomTextMessage {
removeCustomMessageTextEvents, err := c.removeOrgMessageTextsIfExists(ctx, orgID)
if err != nil {
return nil, err
}
if removeCustomTextEvents != nil {
events = append(events, removeCustomTextEvents...)
if removeCustomMessageTextEvents != nil {
events = append(events, removeCustomMessageTextEvents...)
}
}
if !features.CustomTextLogin {
removeCustomLoginTextEvents, err := c.removeOrgLoginTextsIfExists(ctx, orgID)
if err != nil {
return nil, err
}
if removeCustomLoginTextEvents != nil {
events = append(events, removeCustomLoginTextEvents...)
}
}
if !features.PrivacyPolicy {

View File

@ -74,9 +74,10 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
labelPolicyPrivateLabel,
labelPolicyWatermark,
customDomain,
customText,
privacyPolicy,
metadataUser bool,
metadataUser,
customTextMessage,
customTextLogin bool,
) (*org.FeaturesSetEvent, bool) {
changes := make([]features.FeaturesChanges, 0)
@ -126,15 +127,18 @@ 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 wm.PrivacyPolicy != privacyPolicy {
changes = append(changes, features.ChangePrivacyPolicy(privacyPolicy))
}
if wm.MetadataUser != metadataUser {
changes = append(changes, features.ChangeMetadataUser(metadataUser))
}
if wm.CustomTextMessage != customTextMessage {
changes = append(changes, features.ChangeCustomTextMessage(customTextMessage))
}
if wm.CustomTextLogin != customTextLogin {
changes = append(changes, features.ChangeCustomTextLogin(customTextLogin))
}
if len(changes) == 0 {
return nil, false

View File

@ -242,6 +242,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewCustomTextSetEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.LoginCustomText,
domain.LoginKeyExternalRegistrationUserOverviewTitle,
"text",
language.English,
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewPrivacyPolicyAddedEvent(
@ -280,7 +292,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
LabelPolicyPrivateLabel: false,
LabelPolicyWatermark: false,
CustomDomain: false,
CustomText: false,
CustomTextMessage: false,
CustomTextLogin: false,
PrivacyPolicy: false,
MetadataUser: false,
},
@ -415,6 +428,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewCustomTextSetEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.LoginCustomText,
domain.LoginKeyExternalRegistrationUserOverviewTitle,
"text",
language.English,
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewPrivacyPolicyAddedEvent(
@ -600,6 +625,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewCustomTextSetEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.LoginCustomText,
domain.LoginKeyExternalRegistrationUserOverviewTitle,
"text",
language.English,
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewPrivacyPolicyAddedEvent(
@ -795,6 +832,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewCustomTextSetEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.LoginCustomText,
domain.LoginKeyExternalRegistrationUserOverviewTitle,
"text",
language.English,
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewPrivacyPolicyAddedEvent(
@ -1045,6 +1094,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
org.NewCustomTextSetEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.LoginCustomText,
domain.LoginKeyExternalRegistrationUserOverviewTitle,
"text",
language.English,
),
),
),
expectFilter(
eventFromEventPusher(
org.NewPrivacyPolicyAddedEvent(
@ -1079,6 +1140,9 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
eventFromEventPusher(
org.NewCustomTextTemplateRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.InitCodeMessageType, language.English),
),
eventFromEventPusher(
org.NewCustomTextTemplateRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, language.English),
),
eventFromEventPusher(
org.NewPrivacyPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
),
@ -1219,6 +1283,18 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewCustomTextSetEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.LoginCustomText,
domain.LoginKeyExternalRegistrationUserOverviewTitle,
"text",
language.English,
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewPrivacyPolicyAddedEvent(
@ -1269,7 +1345,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
LabelPolicyPrivateLabel: false,
LabelPolicyWatermark: false,
CustomDomain: false,
CustomText: false,
CustomTextMessage: false,
CustomTextLogin: false,
PrivacyPolicy: false,
MetadataUser: false,
},
@ -1452,6 +1529,18 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewCustomTextSetEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.LoginCustomText,
domain.LoginKeyExternalRegistrationUserOverviewTitle,
"text",
language.English,
),
),
),
expectFilter(
eventFromEventPusher(
iam.NewPrivacyPolicyAddedEvent(

View File

@ -68,3 +68,12 @@ func (m *MessageTexts) GetMessageTextByType(msgType string) *CustomMessageText {
}
return nil
}
func IsMessageTextType(textType string) bool {
return textType == InitCodeMessageType ||
textType == PasswordResetMessageType ||
textType == VerifyEmailMessageType ||
textType == VerifyPhoneMessageType ||
textType == DomainClaimedMessageType ||
textType == PasswordlessRegistrationMessageType
}

View File

@ -18,10 +18,12 @@ const (
FeatureLabelPolicy = "label_policy"
FeatureLabelPolicyPrivateLabel = FeatureLabelPolicy + ".private_label"
FeatureLabelPolicyWatermark = FeatureLabelPolicy + ".watermark"
FeatureCustomText = "custom_text"
FeatureCustomDomain = "custom_domain"
FeaturePrivacyPolicy = "privacy_policy"
FeatureMetadata = "metadata"
FeatureCustomText = "custom_text"
FeatureCustomTextMessage = FeatureCustomText + ".message"
FeatureCustomTextLogin = FeatureCustomText + ".login"
FeatureMetadataUser = FeatureMetadata + ".user"
)
@ -45,7 +47,8 @@ type Features struct {
LabelPolicyPrivateLabel bool
LabelPolicyWatermark bool
CustomDomain bool
CustomText bool
CustomTextMessage bool
CustomTextLogin bool
PrivacyPolicy bool
MetadataUser bool
}

View File

@ -28,9 +28,10 @@ type FeaturesView struct {
LabelPolicyPrivateLabel bool
LabelPolicyWatermark bool
CustomDomain bool
CustomText bool
PrivacyPolicy bool
MetadataUser bool
CustomTextMessage bool
CustomTextLogin bool
}
func (f *FeaturesView) FeatureList() []string {
@ -65,15 +66,18 @@ func (f *FeaturesView) FeatureList() []string {
if f.CustomDomain {
list = append(list, domain.FeatureCustomDomain)
}
if f.CustomText {
list = append(list, domain.FeatureCustomText)
}
if f.PrivacyPolicy {
list = append(list, domain.FeaturePrivacyPolicy)
}
if f.MetadataUser {
list = append(list, domain.FeatureMetadataUser)
}
if f.CustomTextMessage {
list = append(list, domain.FeatureCustomTextMessage)
}
if f.CustomTextLogin {
list = append(list, domain.FeatureCustomTextLogin)
}
return list
}

View File

@ -42,9 +42,10 @@ 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"`
PrivacyPolicy bool `json:"privacyPolicy" gorm:"column:privacy_policy"`
MetadataUser bool `json:"metadataUser" gorm:"column:metadata_user"`
CustomTextMessage bool `json:"customTextMessage" gorm:"column:custom_text_message"`
CustomTextLogin bool `json:"customTextLogin" gorm:"column:custom_text_login"`
}
func FeaturesToModel(features *FeaturesView) *features_model.FeaturesView {
@ -69,9 +70,10 @@ func FeaturesToModel(features *FeaturesView) *features_model.FeaturesView {
LabelPolicyPrivateLabel: features.LabelPolicyPrivateLabel,
LabelPolicyWatermark: features.LabelPolicyWatermark,
CustomDomain: features.CustomDomain,
CustomText: features.CustomText,
PrivacyPolicy: features.PrivacyPolicy,
MetadataUser: features.MetadataUser,
CustomTextMessage: features.CustomTextMessage,
CustomTextLogin: features.CustomTextLogin,
}
}

View File

@ -35,9 +35,10 @@ type FeaturesSetEvent struct {
LabelPolicyPrivateLabel *bool `json:"labelPolicyPrivateLabel,omitempty"`
LabelPolicyWatermark *bool `json:"labelPolicyWatermark,omitempty"`
CustomDomain *bool `json:"customDomain,omitempty"`
CustomText *bool `json:"customText,omitempty"`
PrivacyPolicy *bool `json:"privacyPolicy,omitempty"`
MetadataUser *bool `json:"metadataUser,omitempty"`
CustomTextMessage *bool `json:"customTextMessage,omitempty"`
CustomTextLogin *bool `json:"customTextLogin,omitempty"`
}
func (e *FeaturesSetEvent) Data() interface{} {
@ -156,12 +157,6 @@ func ChangeCustomDomain(customDomain bool) func(event *FeaturesSetEvent) {
}
}
func ChangeCustomText(customText bool) func(event *FeaturesSetEvent) {
return func(e *FeaturesSetEvent) {
e.CustomText = &customText
}
}
func ChangePrivacyPolicy(privacyPolicy bool) func(event *FeaturesSetEvent) {
return func(e *FeaturesSetEvent) {
e.PrivacyPolicy = &privacyPolicy
@ -173,6 +168,19 @@ func ChangeMetadataUser(metadataUser bool) func(event *FeaturesSetEvent) {
e.MetadataUser = &metadataUser
}
}
func ChangeCustomTextMessage(customTextMessage bool) func(event *FeaturesSetEvent) {
return func(e *FeaturesSetEvent) {
e.CustomTextMessage = &customTextMessage
}
}
func ChangeCustomTextLogin(customTextLogin bool) func(event *FeaturesSetEvent) {
return func(e *FeaturesSetEvent) {
e.CustomTextLogin = &customTextLogin
}
}
func FeaturesSetEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e := &FeaturesSetEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),

View File

@ -0,0 +1,9 @@
ALTER TABLE adminapi.features RENAME COLUMN custom_text TO custom_text_message;
ALTER TABLE auth.features RENAME COLUMN custom_text TO custom_text_message;
ALTER TABLE authz.features RENAME COLUMN custom_text TO custom_text_message;
ALTER TABLE management.features RENAME COLUMN custom_text TO custom_text_message;
ALTER TABLE adminapi.features ADD COLUMN custom_text_login BOOLEAN;
ALTER TABLE auth.features ADD COLUMN custom_text_login BOOLEAN;
ALTER TABLE authz.features ADD COLUMN custom_text_login BOOLEAN;
ALTER TABLE management.features ADD COLUMN custom_text_login BOOLEAN;

View File

@ -2613,6 +2613,8 @@ message SetDefaultFeaturesRequest {
bool custom_text = 17;
bool privacy_policy = 18;
bool metadata_user = 19;
bool custom_text_message = 20;
bool custom_text_login = 21;
}
message SetDefaultFeaturesResponse {
@ -2649,6 +2651,8 @@ message SetOrgFeaturesRequest {
bool custom_text = 18;
bool privacy_policy = 19;
bool metadata_user = 20;
bool custom_text_message = 21;
bool custom_text_login = 22;
}
message SetOrgFeaturesResponse {

View File

@ -27,6 +27,8 @@ message Features {
bool custom_text = 16;
bool privacy_policy = 17;
bool metadata_user = 18;
bool custom_text_message = 19;
bool custom_text_login = 20;
}
message FeatureTier {

View File

@ -2271,7 +2271,7 @@ service ManagementService {
option (zitadel.v1.auth_option) = {
permission: "policy.write";
feature: "custom_text"
feature: "custom_text.message"
};
}
@ -2319,7 +2319,7 @@ service ManagementService {
option (zitadel.v1.auth_option) = {
permission: "policy.write";
feature: "custom_text"
feature: "custom_text.message"
};
}
@ -2368,7 +2368,7 @@ service ManagementService {
option (zitadel.v1.auth_option) = {
permission: "policy.write";
feature: "custom_text"
feature: "custom_text.message"
};
}
@ -2417,7 +2417,7 @@ service ManagementService {
option (zitadel.v1.auth_option) = {
permission: "policy.write";
feature: "custom_text"
feature: "custom_text.message"
};
}
@ -2466,7 +2466,7 @@ service ManagementService {
option (zitadel.v1.auth_option) = {
permission: "policy.write";
feature: "custom_text"
feature: "custom_text.message"
};
}
@ -2515,7 +2515,7 @@ service ManagementService {
option (zitadel.v1.auth_option) = {
permission: "policy.write";
feature: "custom_text"
feature: "custom_text.message"
};
}
@ -2563,7 +2563,7 @@ service ManagementService {
option (zitadel.v1.auth_option) = {
permission: "policy.write";
feature: "custom_text"
feature: "custom_text.login"
};
}