mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 03:37:34 +00:00
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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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")
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -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(
|
||||
|
Reference in New Issue
Block a user