package query import ( "context" "database/sql" errs "errors" "time" sq "github.com/Masterminds/squirrel" "github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/query/projection" ) type Features struct { AggregateID string ChangeDate time.Time Sequence uint64 IsDefault bool TierName string TierDescription string State domain.FeaturesState StateDescription string AuditLogRetention time.Duration LoginPolicyFactors bool LoginPolicyIDP bool LoginPolicyPasswordless bool LoginPolicyRegistration bool LoginPolicyUsernameLogin bool LoginPolicyPasswordReset bool PasswordComplexityPolicy bool LabelPolicyPrivateLabel bool LabelPolicyWatermark bool CustomDomain bool PrivacyPolicy bool MetadataUser bool CustomTextMessage bool CustomTextLogin bool LockoutPolicy bool ActionsAllowed domain.ActionsAllowed MaxActions int32 } var ( featureTable = table{ name: projection.FeatureTable, } FeatureColumnAggregateID = Column{ name: projection.FeatureAggregateIDCol, table: featureTable, } FeatureColumnChangeDate = Column{ name: projection.FeatureChangeDateCol, table: featureTable, } FeatureColumnSequence = Column{ name: projection.FeatureSequenceCol, table: featureTable, } FeatureColumnIsDefault = Column{ name: projection.FeatureIsDefaultCol, table: featureTable, } FeatureTierName = Column{ name: projection.FeatureTierNameCol, table: featureTable, } FeatureTierDescription = Column{ name: projection.FeatureTierDescriptionCol, table: featureTable, } FeatureState = Column{ name: projection.FeatureStateCol, table: featureTable, } FeatureStateDescription = Column{ name: projection.FeatureStateDescriptionCol, table: featureTable, } FeatureAuditLogRetention = Column{ name: projection.FeatureAuditLogRetentionCol, table: featureTable, } FeatureLoginPolicyFactors = Column{ name: projection.FeatureLoginPolicyFactorsCol, table: featureTable, } FeatureLoginPolicyIDP = Column{ name: projection.FeatureLoginPolicyIDPCol, table: featureTable, } FeatureLoginPolicyPasswordless = Column{ name: projection.FeatureLoginPolicyPasswordlessCol, table: featureTable, } FeatureLoginPolicyRegistration = Column{ name: projection.FeatureLoginPolicyRegistrationCol, table: featureTable, } FeatureLoginPolicyUsernameLogin = Column{ name: projection.FeatureLoginPolicyUsernameLoginCol, table: featureTable, } FeatureLoginPolicyPasswordReset = Column{ name: projection.FeatureLoginPolicyPasswordResetCol, table: featureTable, } FeaturePasswordComplexityPolicy = Column{ name: projection.FeaturePasswordComplexityPolicyCol, table: featureTable, } FeatureLabelPolicyPrivateLabel = Column{ name: projection.FeatureLabelPolicyPrivateLabelCol, table: featureTable, } FeatureLabelPolicyWatermark = Column{ name: projection.FeatureLabelPolicyWatermarkCol, table: featureTable, } FeatureCustomDomain = Column{ name: projection.FeatureCustomDomainCol, table: featureTable, } FeaturePrivacyPolicy = Column{ name: projection.FeaturePrivacyPolicyCol, table: featureTable, } FeatureMetadataUser = Column{ name: projection.FeatureMetadataUserCol, table: featureTable, } FeatureCustomTextMessage = Column{ name: projection.FeatureCustomTextMessageCol, table: featureTable, } FeatureCustomTextLogin = Column{ name: projection.FeatureCustomTextLoginCol, table: featureTable, } FeatureLockoutPolicy = Column{ name: projection.FeatureLockoutPolicyCol, table: featureTable, } FeatureActionsAllowed = Column{ name: projection.FeatureActionsAllowedCol, table: featureTable, } FeatureMaxActions = Column{ name: projection.FeatureMaxActionsCol, table: featureTable, } ) func (q *Queries) FeaturesByOrgID(ctx context.Context, orgID string) (*Features, error) { query, scan := prepareFeaturesQuery() stmt, args, err := query.Where( sq.Or{ sq.Eq{ FeatureColumnAggregateID.identifier(): orgID, }, sq.Eq{ FeatureColumnAggregateID.identifier(): domain.IAMID, }, }). OrderBy(FeatureColumnIsDefault.identifier()). Limit(1).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-P9gwg", "Errors.Query.SQLStatement") } row := q.client.QueryRowContext(ctx, stmt, args...) return scan(row) } func (q *Queries) DefaultFeatures(ctx context.Context) (*Features, error) { query, scan := prepareFeaturesQuery() stmt, args, err := query.Where(sq.Eq{ FeatureColumnAggregateID.identifier(): domain.IAMID, }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-1Ndlg", "Errors.Query.SQLStatement") } row := q.client.QueryRowContext(ctx, stmt, args...) return scan(row) } func prepareFeaturesQuery() (sq.SelectBuilder, func(*sql.Row) (*Features, error)) { return sq.Select( FeatureColumnAggregateID.identifier(), FeatureColumnChangeDate.identifier(), FeatureColumnSequence.identifier(), FeatureColumnIsDefault.identifier(), FeatureTierName.identifier(), FeatureTierDescription.identifier(), FeatureState.identifier(), FeatureStateDescription.identifier(), FeatureAuditLogRetention.identifier(), FeatureLoginPolicyFactors.identifier(), FeatureLoginPolicyIDP.identifier(), FeatureLoginPolicyPasswordless.identifier(), FeatureLoginPolicyRegistration.identifier(), FeatureLoginPolicyUsernameLogin.identifier(), FeatureLoginPolicyPasswordReset.identifier(), FeaturePasswordComplexityPolicy.identifier(), FeatureLabelPolicyPrivateLabel.identifier(), FeatureLabelPolicyWatermark.identifier(), FeatureCustomDomain.identifier(), FeaturePrivacyPolicy.identifier(), FeatureMetadataUser.identifier(), FeatureCustomTextMessage.identifier(), FeatureCustomTextLogin.identifier(), FeatureLockoutPolicy.identifier(), FeatureActionsAllowed.identifier(), FeatureMaxActions.identifier(), ).From(featureTable.identifier()).PlaceholderFormat(sq.Dollar), func(row *sql.Row) (*Features, error) { p := new(Features) tierName := sql.NullString{} tierDescription := sql.NullString{} stateDescription := sql.NullString{} err := row.Scan( &p.AggregateID, &p.ChangeDate, &p.Sequence, &p.IsDefault, &tierName, &tierDescription, &p.State, &stateDescription, &p.AuditLogRetention, &p.LoginPolicyFactors, &p.LoginPolicyIDP, &p.LoginPolicyPasswordless, &p.LoginPolicyRegistration, &p.LoginPolicyUsernameLogin, &p.LoginPolicyPasswordReset, &p.PasswordComplexityPolicy, &p.LabelPolicyPrivateLabel, &p.LabelPolicyWatermark, &p.CustomDomain, &p.PrivacyPolicy, &p.MetadataUser, &p.CustomTextMessage, &p.CustomTextLogin, &p.LockoutPolicy, &p.ActionsAllowed, &p.MaxActions, ) if err != nil { if errs.Is(err, sql.ErrNoRows) { return nil, errors.ThrowNotFound(err, "QUERY-M9fse", "Errors.Features.NotFound") } return nil, errors.ThrowInternal(err, "QUERY-3o9gd", "Errors.Internal") } p.TierName = tierName.String p.TierDescription = tierDescription.String p.StateDescription = stateDescription.String return p, nil } } func (f *Features) EnabledFeatureTypes() []string { list := make([]string, 0) if f.LoginPolicyFactors { list = append(list, domain.FeatureLoginPolicyFactors) } if f.LoginPolicyIDP { list = append(list, domain.FeatureLoginPolicyIDP) } if f.LoginPolicyPasswordless { list = append(list, domain.FeatureLoginPolicyPasswordless) } if f.LoginPolicyRegistration { list = append(list, domain.FeatureLoginPolicyRegistration) } if f.LoginPolicyUsernameLogin { list = append(list, domain.FeatureLoginPolicyUsernameLogin) } if f.LoginPolicyPasswordReset { list = append(list, domain.FeatureLoginPolicyPasswordReset) } if f.PasswordComplexityPolicy { list = append(list, domain.FeaturePasswordComplexityPolicy) } if f.LabelPolicyPrivateLabel { list = append(list, domain.FeatureLabelPolicyPrivateLabel) } if f.LabelPolicyWatermark { list = append(list, domain.FeatureLabelPolicyWatermark) } if f.CustomDomain { list = append(list, domain.FeatureCustomDomain) } 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) } if f.LockoutPolicy { list = append(list, domain.FeatureLockoutPolicy) } if f.ActionsAllowed != domain.ActionsNotAllowed { list = append(list, domain.FeatureActions) } return list }