mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 07:57:32 +00:00
feat: label policy (#1708)
* feat: label policy proto extension * feat: label policy and activate event * feat: label policy asset events * feat: label policy asset commands * feat: add storage key * feat: storage key validation * feat: label policy asset tests * feat: label policy query side * feat: avatar * feat: avatar event * feat: human avatar * feat: avatar read side * feat: font on iam label policy * feat: label policy font * feat: possiblity to create bucket on put file * uplaoder * login policy logo * set bucket prefix * feat: avatar upload * feat: avatar upload * feat: use assets on command side * feat: fix human avatar removed event * feat: remove human avatar * feat: mock asset storage * feat: remove human avatar * fix(operator): add configuration of asset storage to zitadel operator * feat(console): private labeling policy (#1697) * private labeling component, routing, preview * font, colors, upload, i18n * show logo * fix: uniqueness (#1710) * fix: uniqueconstraint to lower * feat: change org * feat: org change test * feat: change org * fix: tests * fix: handle domain claims correctly * feat: update org Co-authored-by: fabi <fabienne.gerschwiler@gmail.com> * fix: handle domain claimed event correctly for service users (#1711) * fix: handle domain claimed event correctly on user view * fix: ignore domain claimed events for email notifications * fix: change org * handle org changed in read models correctly * fix: change org in user grant handler Co-authored-by: fabi <fabienne.gerschwiler@gmail.com> * fix: correct value (#1695) * docs(api): correct link (#1712) * upload service Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: fabi <fabienne.gerschwiler@gmail.com> Co-authored-by: Florian Forster <florian@caos.ch> * feat: fix tests, * feat: remove assets from label policy * fix npm, set environment * lint ts * remove stylelinting * fix(operator): add mapping for console with changed unit tests * fix(operator): add secrets as env variables to pod * feat: remove human avatar * fix(operator): add secrets as env variables to pod * feat: map label policy * feat: labelpolicy, admin, mgmt, adv settings (#1715) * fetch label policy, mgmt, admin service * feat: advanced beh, links, add, update * lint ts * feat: watermark * feat: remove human avatar * feat: remove human avatar * feat: remove human avatar * feat: remove human avatar * feat: remove human avatar * feat: remove human avatar * feat: remove human avatar * feat: custom css * css * css * css * css * css * getobject * feat: dynamic handler * feat: varibale css * content info * css overwrite * feat: variablen css * feat: generate css file * feat: dark mode * feat: dark mode * fix logo css * feat: upload logos * dark mode with cookie * feat: handle images in login * avatar css and begin font * feat: avatar * feat: user avatar * caching of static assets in login * add avatar.js to main.html * feat: header dont show logo if no url * feat: label policy colors * feat: mock asset storage * feat: mock asset storage * feat: fix tests * feat: user avatar * feat: header logo * avatar * avatar * make it compatible with go 1.15 * feat: remove unused logos * fix handler * fix: styling error handling * fonts * fix: download func * switch to mux * fix: change upload api to assets * fix build * fix: download avatar * fix: download logos * fix: my avatar * font * fix: remove error msg popup possibility * fix: docs * fix: svalidate colors * rem msg popup from frontend * fix: email with private labeling * fix: tests * fix: email templates * fix: change migration version * fix: fix duplicate imports * fix(console): assets, service url, upload, policy current and preview (#1781) * upload endpoint, layout * fetch current, preview, fix upload * cleanup private labeling * fix linting * begin generated asset handler * generate asset api in dockerfile * features for label policy * features for label policy * features * flag for asset generator * change asset generator flag * fix label policy view in grpc * fix: layout, activate policy (#1786) * theme switcher up on top * change layout * activate policy * feat(console): label policy back color, layout (#1788) * theme switcher up on top * change layout * activate policy * fix overwrite value fc * reset policy, reset service * autosave policy, preview desc, layout impv * layout, i18n * background colors, inject material styles * load images * clean, lint * fix layout * set custom hex * fix content size conversion * remove font format in generated css * fix features for assets * fix(console): label policy colors, image downloads, preview (#1804) * load images * colors, images binding * lint * refresh emitter * lint * propagate font colors * upload error handling * label policy feature check * add blob in csp for console * log * fix: feature edits for label policy, refresh state on upload (#1807) * show error on load image, stop spinner * fix merge * fix migration versions * fix assets * fix csp * fix background color * scss * fix build * lint scss * fix statik for console * fix features check for label policy * cleanup * lint * public links * fix notifications * public links * feat: merge main * feat: fix translation files * fix migration * set api domain * fix logo in email * font face in email * font face in email * validate assets on upload * cleanup * add missing translations * add missing translations Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Stefan Benz <stefan@caos.ch> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Florian Forster <florian@caos.ch>
This commit is contained in:
@@ -300,7 +300,15 @@ func (repo *IAMRepository) GetOrgIAMPolicy(ctx context.Context) (*iam_model.OrgI
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
|
||||
policy, err := repo.View.LabelPolicyByAggregateID(repo.SystemDefaults.IamID)
|
||||
policy, err := repo.View.LabelPolicyByAggregateIDAndState(repo.SystemDefaults.IamID, int32(domain.LabelPolicyStateActive))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_es_model.LabelPolicyViewToModel(policy), err
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) GetDefaultPreviewLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
|
||||
policy, err := repo.View.LabelPolicyByAggregateIDAndState(repo.SystemDefaults.IamID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
|
||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
@@ -30,8 +31,8 @@ func (h *handler) Eventstore() v1.Eventstore {
|
||||
return h.es
|
||||
}
|
||||
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, defaults systemdefaults.SystemDefaults) []query.Handler {
|
||||
return []query.Handler{
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, defaults systemdefaults.SystemDefaults, static static.Storage, localDevMode bool) []query.Handler {
|
||||
handlers := []query.Handler{
|
||||
newOrg(
|
||||
handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}),
|
||||
newIAMMember(
|
||||
@@ -66,6 +67,13 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
|
||||
newFeatures(
|
||||
handler{view, bulkLimit, configs.cycleDuration("Features"), errorCount, es}),
|
||||
}
|
||||
if static != nil {
|
||||
handlers = append(handlers, newStyling(
|
||||
handler{view, bulkLimit, configs.cycleDuration("Styling"), errorCount, es},
|
||||
static,
|
||||
localDevMode))
|
||||
}
|
||||
return handlers
|
||||
}
|
||||
|
||||
func (configs Configs) cycleDuration(viewModel string) time.Duration {
|
||||
|
@@ -2,6 +2,8 @@ package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"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"
|
||||
@@ -77,8 +79,25 @@ func (p *LabelPolicy) processLabelPolicy(event *es_models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case model.LabelPolicyAdded:
|
||||
err = policy.AppendEvent(event)
|
||||
case model.LabelPolicyChanged:
|
||||
policy, err = p.view.LabelPolicyByAggregateID(event.AggregateID)
|
||||
case model.LabelPolicyChanged,
|
||||
model.LabelPolicyLogoAdded,
|
||||
model.LabelPolicyLogoRemoved,
|
||||
model.LabelPolicyIconAdded,
|
||||
model.LabelPolicyIconRemoved,
|
||||
model.LabelPolicyLogoDarkAdded,
|
||||
model.LabelPolicyLogoDarkRemoved,
|
||||
model.LabelPolicyIconDarkAdded,
|
||||
model.LabelPolicyIconDarkRemoved,
|
||||
model.LabelPolicyFontAdded,
|
||||
model.LabelPolicyFontRemoved,
|
||||
model.LabelPolicyAssetsRemoved:
|
||||
policy, err = p.view.LabelPolicyByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = policy.AppendEvent(event)
|
||||
case model.LabelPolicyActivated:
|
||||
policy, err = p.view.LabelPolicyByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
298
internal/admin/repository/eventsourcing/handler/styling.go
Normal file
298
internal/admin/repository/eventsourcing/handler/styling.go
Normal file
@@ -0,0 +1,298 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/lucasb-eyer/go-colorful"
|
||||
"github.com/muesli/gamut"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"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"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
)
|
||||
|
||||
const (
|
||||
stylingTable = "adminapi.styling"
|
||||
)
|
||||
|
||||
type Styling struct {
|
||||
handler
|
||||
static static.Storage
|
||||
subscription *v1.Subscription
|
||||
devMode bool
|
||||
resourceUrl string
|
||||
}
|
||||
|
||||
func newStyling(handler handler, static static.Storage, localDevMode bool) *Styling {
|
||||
h := &Styling{
|
||||
handler: handler,
|
||||
static: static,
|
||||
}
|
||||
prefix := ""
|
||||
if localDevMode {
|
||||
prefix = "/login"
|
||||
}
|
||||
h.resourceUrl = prefix + "/resources/dynamic" //TODO: ?
|
||||
|
||||
h.subscribe()
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (m *Styling) subscribe() {
|
||||
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
|
||||
go func() {
|
||||
for event := range m.subscription.Events {
|
||||
query.ReduceEvent(m, event)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *Styling) ViewModel() string {
|
||||
return stylingTable
|
||||
}
|
||||
|
||||
func (_ *Styling) AggregateTypes() []es_models.AggregateType {
|
||||
return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
|
||||
}
|
||||
|
||||
func (m *Styling) CurrentSequence() (uint64, error) {
|
||||
sequence, err := m.view.GetLatestStylingSequence()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return sequence.CurrentSequence, nil
|
||||
}
|
||||
|
||||
func (m *Styling) EventQuery() (*es_models.SearchQuery, error) {
|
||||
sequence, err := m.view.GetLatestStylingSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(m.AggregateTypes()...).
|
||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
||||
}
|
||||
|
||||
func (m *Styling) Reduce(event *es_models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case model.OrgAggregate, iam_es_model.IAMAggregate:
|
||||
err = m.processLabelPolicy(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Styling) processLabelPolicy(event *es_models.Event) (err error) {
|
||||
policy := new(iam_model.LabelPolicyView)
|
||||
switch event.Type {
|
||||
case iam_es_model.LabelPolicyAdded, model.LabelPolicyAdded:
|
||||
err = policy.AppendEvent(event)
|
||||
case iam_es_model.LabelPolicyChanged, model.LabelPolicyChanged,
|
||||
iam_es_model.LabelPolicyLogoAdded, model.LabelPolicyLogoAdded,
|
||||
iam_es_model.LabelPolicyLogoRemoved, model.LabelPolicyLogoRemoved,
|
||||
iam_es_model.LabelPolicyIconAdded, model.LabelPolicyIconAdded,
|
||||
iam_es_model.LabelPolicyIconRemoved, model.LabelPolicyIconRemoved,
|
||||
iam_es_model.LabelPolicyLogoDarkAdded, model.LabelPolicyLogoDarkAdded,
|
||||
iam_es_model.LabelPolicyLogoDarkRemoved, model.LabelPolicyLogoDarkRemoved,
|
||||
iam_es_model.LabelPolicyIconDarkAdded, model.LabelPolicyIconDarkAdded,
|
||||
iam_es_model.LabelPolicyIconDarkRemoved, model.LabelPolicyIconDarkRemoved,
|
||||
iam_es_model.LabelPolicyFontAdded, model.LabelPolicyFontAdded,
|
||||
iam_es_model.LabelPolicyFontRemoved, model.LabelPolicyFontRemoved,
|
||||
iam_es_model.LabelPolicyAssetsRemoved, model.LabelPolicyAssetsRemoved:
|
||||
policy, err = m.view.StylingByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = policy.AppendEvent(event)
|
||||
|
||||
case iam_es_model.LabelPolicyActivated, model.LabelPolicyActivated:
|
||||
policy, err = m.view.StylingByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = policy.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.generateStylingFile(policy)
|
||||
default:
|
||||
return m.view.ProcessedStylingSequence(event)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.PutStyling(policy, event)
|
||||
}
|
||||
|
||||
func (m *Styling) OnError(event *es_models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-2m9fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
|
||||
return spooler.HandleError(event, err, m.view.GetLatestLabelPolicyFailedEvent, m.view.ProcessedLabelPolicyFailedEvent, m.view.ProcessedLabelPolicySequence, m.errorCountUntilSkip)
|
||||
}
|
||||
|
||||
func (m *Styling) OnSuccess() error {
|
||||
return spooler.HandleSuccess(m.view.UpdateLabelPolicySpoolerRunTimestamp)
|
||||
}
|
||||
|
||||
func (m *Styling) generateStylingFile(policy *iam_model.LabelPolicyView) error {
|
||||
reader, size, err := m.writeFile(policy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.uploadFilesToBucket(policy.AggregateID, "text/css", reader, size)
|
||||
}
|
||||
|
||||
func (m *Styling) writeFile(policy *iam_model.LabelPolicyView) (io.Reader, int64, error) {
|
||||
cssContent := ""
|
||||
cssContent += fmt.Sprint(":root {")
|
||||
if policy.PrimaryColor != "" {
|
||||
palette := m.generateColorPaletteRGBA255(policy.PrimaryColor)
|
||||
for i, color := range palette {
|
||||
cssContent += fmt.Sprintf("--zitadel-color-primary-%v: %s;", i, color)
|
||||
}
|
||||
}
|
||||
|
||||
if policy.BackgroundColor != "" {
|
||||
palette := m.generateColorPaletteRGBA255(policy.BackgroundColor)
|
||||
for i, color := range palette {
|
||||
cssContent += fmt.Sprintf("--zitadel-color-background-%v: %s;", i, color)
|
||||
}
|
||||
}
|
||||
if policy.WarnColor != "" {
|
||||
palette := m.generateColorPaletteRGBA255(policy.WarnColor)
|
||||
for i, color := range palette {
|
||||
cssContent += fmt.Sprintf("--zitadel-color-warn-%v: %s;", i, color)
|
||||
}
|
||||
}
|
||||
var fontname string
|
||||
if policy.FontURL != "" {
|
||||
split := strings.Split(policy.FontURL, "/")
|
||||
fontname = split[len(split)-1]
|
||||
cssContent += fmt.Sprintf("--zitadel-font-family: %s;", fontname)
|
||||
}
|
||||
cssContent += fmt.Sprint("}")
|
||||
if policy.FontURL != "" {
|
||||
cssContent += fmt.Sprintf(fontFaceTemplate, fontname, m.resourceUrl, policy.AggregateID, policy.FontURL)
|
||||
}
|
||||
cssContent += fmt.Sprint(".lgn-dark-theme {")
|
||||
if policy.PrimaryColorDark != "" {
|
||||
palette := m.generateColorPaletteRGBA255(policy.PrimaryColorDark)
|
||||
for i, color := range palette {
|
||||
cssContent += fmt.Sprintf("--zitadel-color-primary-%v: %s;", i, color)
|
||||
}
|
||||
}
|
||||
if policy.BackgroundColorDark != "" {
|
||||
palette := m.generateColorPaletteRGBA255(policy.BackgroundColorDark)
|
||||
for i, color := range palette {
|
||||
cssContent += fmt.Sprintf("--zitadel-color-background-%v: %s;", i, color)
|
||||
}
|
||||
}
|
||||
if policy.WarnColorDark != "" {
|
||||
palette := m.generateColorPaletteRGBA255(policy.WarnColorDark)
|
||||
for i, color := range palette {
|
||||
cssContent += fmt.Sprintf("--zitadel-color-warn-%v: %s;", i, color)
|
||||
}
|
||||
}
|
||||
if policy.FontColorDark != "" {
|
||||
palette := m.generateColorPaletteRGBA255(policy.FontColorDark)
|
||||
for i, color := range palette {
|
||||
cssContent += fmt.Sprintf("--zitadel-color-font-%v: %s;", i, color)
|
||||
}
|
||||
}
|
||||
cssContent += fmt.Sprint("}")
|
||||
|
||||
data := []byte(cssContent)
|
||||
buffer := bytes.NewBuffer(data)
|
||||
return buffer, int64(buffer.Len()), nil
|
||||
}
|
||||
|
||||
const fontFaceTemplate = `
|
||||
@font-face {
|
||||
font-family: '%s';
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url(%s?orgId=%s&filename=%s);
|
||||
}
|
||||
`
|
||||
|
||||
func (m *Styling) uploadFilesToBucket(aggregateID, contentType string, reader io.Reader, size int64) error {
|
||||
fileName := domain.CssPath + "/" + domain.CssVariablesFileName
|
||||
_, err := m.static.PutObject(context.Background(), aggregateID, fileName, contentType, reader, size, true)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Styling) generateColorPaletteRGBA255(hex string) map[string]string {
|
||||
palette := make(map[string]string)
|
||||
defaultColor := gamut.Hex(hex)
|
||||
|
||||
color50, ok := colorful.MakeColor(gamut.Lighter(defaultColor, 1.0))
|
||||
if ok {
|
||||
palette["50"] = cssRGB(color50.RGB255())
|
||||
}
|
||||
|
||||
color100, ok := colorful.MakeColor(gamut.Lighter(defaultColor, 0.8))
|
||||
if ok {
|
||||
palette["100"] = cssRGB(color100.RGB255())
|
||||
}
|
||||
|
||||
color200, ok := colorful.MakeColor(gamut.Lighter(defaultColor, 0.6))
|
||||
if ok {
|
||||
palette["200"] = cssRGB(color200.RGB255())
|
||||
}
|
||||
|
||||
color300, ok := colorful.MakeColor(gamut.Lighter(defaultColor, 0.4))
|
||||
if ok {
|
||||
palette["300"] = cssRGB(color300.RGB255())
|
||||
}
|
||||
|
||||
color400, ok := colorful.MakeColor(gamut.Lighter(defaultColor, 0.1))
|
||||
if ok {
|
||||
palette["400"] = cssRGB(color400.RGB255())
|
||||
}
|
||||
|
||||
color500, ok := colorful.MakeColor(defaultColor)
|
||||
if ok {
|
||||
palette["500"] = cssRGB(color500.RGB255())
|
||||
}
|
||||
|
||||
color600, ok := colorful.MakeColor(gamut.Darker(defaultColor, 0.1))
|
||||
if ok {
|
||||
palette["600"] = cssRGB(color600.RGB255())
|
||||
}
|
||||
|
||||
color700, ok := colorful.MakeColor(gamut.Darker(defaultColor, 0.2))
|
||||
if ok {
|
||||
palette["700"] = cssRGB(color700.RGB255())
|
||||
}
|
||||
|
||||
color800, ok := colorful.MakeColor(gamut.Darker(defaultColor, 0.3))
|
||||
if ok {
|
||||
palette["800"] = cssRGB(color800.RGB255())
|
||||
}
|
||||
|
||||
color900, ok := colorful.MakeColor(gamut.Darker(defaultColor, 0.4))
|
||||
if ok {
|
||||
palette["900"] = cssRGB(color900.RGB255())
|
||||
}
|
||||
|
||||
colorContrast, ok := colorful.MakeColor(gamut.Contrast(defaultColor))
|
||||
if ok {
|
||||
palette["contrast"] = cssRGB(colorContrast.RGB255())
|
||||
}
|
||||
|
||||
return palette
|
||||
}
|
||||
|
||||
func cssRGB(r, g, b uint8) string {
|
||||
return fmt.Sprintf("rgb(%v, %v, %v)", r, g, b)
|
||||
}
|
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
es_spol "github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -28,7 +29,7 @@ type EsRepository struct {
|
||||
eventstore.UserRepo
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRepository, error) {
|
||||
func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, static static.Storage, roles []string, localDevMode bool) (*EsRepository, error) {
|
||||
es, err := v1.Start(conf.Eventstore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -42,7 +43,7 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, r
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults)
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults, static, localDevMode)
|
||||
|
||||
return &EsRepository{
|
||||
spooler: spool,
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
|
||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/handler"
|
||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||
@@ -17,12 +18,12 @@ type SpoolerConfig struct {
|
||||
Handlers handler.Configs
|
||||
}
|
||||
|
||||
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, defaults systemdefaults.SystemDefaults) *spooler.Spooler {
|
||||
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, defaults systemdefaults.SystemDefaults, static static.Storage, localDevMode bool) *spooler.Spooler {
|
||||
spoolerConfig := spooler.Config{
|
||||
Eventstore: es,
|
||||
Locker: &locker{dbClient: sql},
|
||||
ConcurrentWorkers: c.ConcurrentWorkers,
|
||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, defaults),
|
||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, defaults, static, localDevMode),
|
||||
}
|
||||
spool := spoolerConfig.New()
|
||||
spool.Start()
|
||||
|
@@ -11,8 +11,8 @@ const (
|
||||
labelPolicyTable = "adminapi.label_policies"
|
||||
)
|
||||
|
||||
func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
|
||||
func (v *View) LabelPolicyByAggregateIDAndState(aggregateID string, state int32) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateIDAndState(v.Db, labelPolicyTable, aggregateID, state)
|
||||
}
|
||||
|
||||
func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, event *models.Event) error {
|
||||
|
44
internal/admin/repository/eventsourcing/view/styling.go
Normal file
44
internal/admin/repository/eventsourcing/view/styling.go
Normal file
@@ -0,0 +1,44 @@
|
||||
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 (
|
||||
stylingTyble = "adminapi.styling"
|
||||
)
|
||||
|
||||
func (v *View) StylingByAggregateIDAndState(aggregateID string, state int32) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateIDAndState(v.Db, stylingTyble, aggregateID, state)
|
||||
}
|
||||
|
||||
func (v *View) PutStyling(policy *model.LabelPolicyView, event *models.Event) error {
|
||||
err := view.PutLabelPolicy(v.Db, stylingTyble, policy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedStylingSequence(event)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestStylingSequence() (*global_view.CurrentSequence, error) {
|
||||
return v.latestSequence(stylingTyble)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedStylingSequence(event *models.Event) error {
|
||||
return v.saveCurrentSequence(stylingTyble, event)
|
||||
}
|
||||
|
||||
func (v *View) UpdateStylingSpoolerRunTimestamp() error {
|
||||
return v.updateSpoolerRunSequence(stylingTyble)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestStylingFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||
return v.latestFailedEvent(stylingTyble, sequence)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedStylingFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||
return v.saveFailedEvent(failedEvent)
|
||||
}
|
@@ -24,6 +24,7 @@ type IAMRepository interface {
|
||||
ExternalIDPsByIDPConfigIDFromDefaultPolicy(ctx context.Context, idpConfigID string) ([]*usr_model.ExternalIDPView, error)
|
||||
|
||||
GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
GetDefaultPreviewLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
|
||||
GetDefaultMailTemplate(ctx context.Context) (*iam_model.MailTemplateView, error)
|
||||
|
||||
|
194
internal/api/assets/asset.go
Normal file
194
internal/api/assets/asset.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
"github.com/caos/zitadel/internal/management/repository"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
errorHandler ErrorHandler
|
||||
storage static.Storage
|
||||
commands *command.Commands
|
||||
authInterceptor *http_mw.AuthInterceptor
|
||||
idGenerator id.Generator
|
||||
orgRepo repository.OrgRepository
|
||||
}
|
||||
|
||||
func (h *Handler) AuthInterceptor() *http_mw.AuthInterceptor {
|
||||
return h.authInterceptor
|
||||
}
|
||||
|
||||
func (h *Handler) Commands() *command.Commands {
|
||||
return h.commands
|
||||
}
|
||||
|
||||
func (h *Handler) ErrorHandler() ErrorHandler {
|
||||
return DefaultErrorHandler
|
||||
}
|
||||
|
||||
func (h *Handler) Storage() static.Storage {
|
||||
return h.storage
|
||||
}
|
||||
|
||||
type Uploader interface {
|
||||
Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error
|
||||
ObjectName(data authz.CtxData) (string, error)
|
||||
BucketName(data authz.CtxData) string
|
||||
ContentTypeAllowed(contentType string) bool
|
||||
MaxFileSize() int64
|
||||
}
|
||||
|
||||
type Downloader interface {
|
||||
ObjectName(ctx context.Context, path string) (string, error)
|
||||
BucketName(ctx context.Context, id string) string
|
||||
}
|
||||
|
||||
type ErrorHandler func(http.ResponseWriter, *http.Request, error)
|
||||
|
||||
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
|
||||
logging.Log("ASSET-g5ef1").WithError(err).WithField("uri", r.RequestURI).Error("error occurred on asset api")
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func NewHandler(
|
||||
commands *command.Commands,
|
||||
verifier *authz.TokenVerifier,
|
||||
authConfig authz.Config,
|
||||
idGenerator id.Generator,
|
||||
storage static.Storage,
|
||||
orgRepo repository.OrgRepository,
|
||||
) http.Handler {
|
||||
h := &Handler{
|
||||
commands: commands,
|
||||
errorHandler: DefaultErrorHandler,
|
||||
authInterceptor: http_mw.AuthorizationInterceptor(verifier, authConfig),
|
||||
idGenerator: idGenerator,
|
||||
storage: storage,
|
||||
orgRepo: orgRepo,
|
||||
}
|
||||
|
||||
verifier.RegisterServer("Management-API", "assets", AssetsService_AuthMethods) //TODO: separate api?
|
||||
router := mux.NewRouter()
|
||||
RegisterRoutes(router, h)
|
||||
router.PathPrefix("/{id}").Methods("GET").HandlerFunc(DownloadHandleFunc(h, h.GetFile()))
|
||||
return router
|
||||
}
|
||||
|
||||
func (h *Handler) GetFile() Downloader {
|
||||
return &publicFileDownloader{}
|
||||
}
|
||||
|
||||
type publicFileDownloader struct{}
|
||||
|
||||
func (l *publicFileDownloader) ObjectName(_ context.Context, path string) (string, error) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (l *publicFileDownloader) BucketName(_ context.Context, id string) string {
|
||||
return id
|
||||
}
|
||||
|
||||
const maxMemory = 2 << 20
|
||||
const paramFile = "file"
|
||||
|
||||
func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
ctxData := authz.GetCtxData(ctx)
|
||||
err := r.ParseMultipartForm(maxMemory)
|
||||
file, handler, err := r.FormFile(paramFile)
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
err = file.Close()
|
||||
logging.Log("UPLOAD-GDg34").OnError(err).Warn("could not close file")
|
||||
}()
|
||||
contentType := handler.Header.Get("content-type")
|
||||
size := handler.Size
|
||||
if !uploader.ContentTypeAllowed(contentType) {
|
||||
s.ErrorHandler()(w, r, caos_errs.ThrowInvalidArgument(nil, "UPLOAD-Dbvfs", "invalid content-type"))
|
||||
return
|
||||
}
|
||||
if size > uploader.MaxFileSize() {
|
||||
s.ErrorHandler()(w, r, caos_errs.ThrowInvalidArgumentf(nil, "UPLOAD-Bfb32", "file to big, max file size is %v", uploader.MaxFileSize()))
|
||||
return
|
||||
}
|
||||
|
||||
bucketName := uploader.BucketName(ctxData)
|
||||
objectName, err := uploader.ObjectName(ctxData)
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
info, err := s.Commands().UploadAsset(ctx, bucketName, objectName, contentType, file, size)
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
err = uploader.Callback(ctx, info, ctxData.OrgID, s.Commands())
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if s.Storage() == nil {
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
id := mux.Vars(r)["id"]
|
||||
bucketName := downloader.BucketName(ctx, id)
|
||||
path := ""
|
||||
if id != "" {
|
||||
path = strings.Split(r.RequestURI, id+"/")[1]
|
||||
}
|
||||
objectName, err := downloader.ObjectName(ctx, path)
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
if objectName == "" {
|
||||
s.ErrorHandler()(w, r, caos_errs.ThrowNotFound(nil, "UPLOAD-adf4f", "file not found"))
|
||||
return
|
||||
}
|
||||
reader, getInfo, err := s.Storage().GetObject(ctx, bucketName, objectName)
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
data, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
info, err := getInfo()
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("content-length", strconv.FormatInt(info.Size, 10))
|
||||
w.Header().Set("content-type", info.ContentType)
|
||||
w.Header().Set("ETag", info.ETag)
|
||||
w.Write(data)
|
||||
}
|
||||
}
|
119
internal/api/assets/generator/asset.yaml
Normal file
119
internal/api/assets/generator/asset.yaml
Normal file
@@ -0,0 +1,119 @@
|
||||
Services:
|
||||
IAM:
|
||||
Prefix: "/iam"
|
||||
Methods:
|
||||
DefaultLabelPolicyLogo:
|
||||
Path: "/policy/label/logo"
|
||||
HasDarkMode: true
|
||||
Handlers:
|
||||
- Name: Upload
|
||||
Comment:
|
||||
Type: upload
|
||||
Permission: iam.policy.write
|
||||
- Name: Get
|
||||
Comment:
|
||||
Type: download
|
||||
Permission: iam.policy.read
|
||||
- Name: GetPreview
|
||||
Comment:
|
||||
Type: preview
|
||||
Permission: iam.policy.read
|
||||
DefaultLabelPolicyIcon:
|
||||
Path: "/policy/label/icon"
|
||||
HasDarkMode: true
|
||||
Handlers:
|
||||
- Name: Upload
|
||||
Comment:
|
||||
Type: upload
|
||||
Permission: iam.policy.write
|
||||
- Name: Get
|
||||
Comment:
|
||||
Type: download
|
||||
Permission: iam.policy.read
|
||||
- Name: GetPreview
|
||||
Comment:
|
||||
Type: preview
|
||||
Permission: iam.policy.read
|
||||
DefaultLabelPolicyFont:
|
||||
Path: "/policy/label/font"
|
||||
Handlers:
|
||||
- Name: Upload
|
||||
Comment:
|
||||
Type: upload
|
||||
Permission: iam.policy.write
|
||||
- Name: Get
|
||||
Comment:
|
||||
Type: download
|
||||
Permission: iam.policy.read
|
||||
- Name: GetPreview
|
||||
Comment:
|
||||
Type: preview
|
||||
Permission: iam.policy.read
|
||||
Org:
|
||||
Prefix: "/org"
|
||||
Methods:
|
||||
OrgLabelPolicyLogo:
|
||||
Path: "/policy/label/logo"
|
||||
Feature: "label_policy.private_label"
|
||||
HasDarkMode: true
|
||||
Handlers:
|
||||
- Name: Upload
|
||||
Comment:
|
||||
Type: upload
|
||||
Permission: policy.write
|
||||
- Name: Get
|
||||
Comment:
|
||||
Type: download
|
||||
Permission: policy.read
|
||||
- Name: GetPreview
|
||||
Comment:
|
||||
Type: preview
|
||||
Permission: policy.read
|
||||
OrgLabelPolicyIcon:
|
||||
Path: "/policy/label/icon"
|
||||
Feature: "label_policy.private_label"
|
||||
HasDarkMode: true
|
||||
Handlers:
|
||||
- Name: Upload
|
||||
Comment:
|
||||
Type: upload
|
||||
Permission: policy.write
|
||||
- Name: Get
|
||||
Comment:
|
||||
Type: download
|
||||
Permission: policy.read
|
||||
- Name: GetPreview
|
||||
Comment:
|
||||
Type: preview
|
||||
Permission: policy.read
|
||||
OrgLabelPolicyFont:
|
||||
Path: "/policy/label/font"
|
||||
Feature: "label_policy.private_label"
|
||||
Handlers:
|
||||
- Name: Upload
|
||||
Comment:
|
||||
Type: upload
|
||||
Permission: policy.write
|
||||
- Name: Get
|
||||
Comment:
|
||||
Type: download
|
||||
Permission: policy.read
|
||||
- Name: GetPreview
|
||||
Comment:
|
||||
Type: preview
|
||||
Permission: policy.read
|
||||
Users:
|
||||
Prefix: "/users"
|
||||
Methods:
|
||||
MyUserAvatar:
|
||||
Path: "/me/avatar"
|
||||
Features: "label_policy.private_label"
|
||||
Handlers:
|
||||
- Name: Upload
|
||||
Comment:
|
||||
Type: upload
|
||||
Permission: authenticated
|
||||
- Name: Get
|
||||
Comment:
|
||||
Type: download
|
||||
Permission: authenticated
|
200
internal/api/assets/generator/asset_generator.go
Normal file
200
internal/api/assets/generator/asset_generator.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/config"
|
||||
)
|
||||
|
||||
var (
|
||||
directory = flag.String("directory", "./", "working directory: asset.yaml must be in this directory, files will be generated into parent directory")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
configFile := *directory + "asset.yaml"
|
||||
authz, err := os.OpenFile(*directory+"../authz.go", os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755)
|
||||
logging.Log("ASSETS-Gn31f").OnError(err).Fatal("cannot open authz file")
|
||||
router, err := os.OpenFile(*directory+"../router.go", os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755)
|
||||
logging.Log("ASSETS-ABen3").OnError(err).Fatal("cannot open router file")
|
||||
GenerateAssetHandler(configFile, authz, router)
|
||||
}
|
||||
|
||||
type Method struct {
|
||||
Path string
|
||||
Feature string
|
||||
HasDarkMode bool
|
||||
Handlers []Handler
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
Name string
|
||||
Comment string
|
||||
Type HandlerType
|
||||
Permission string
|
||||
}
|
||||
|
||||
func (a Handler) Method() string {
|
||||
if a.Type == MethodTypeUpload {
|
||||
return "POST"
|
||||
}
|
||||
return "GET"
|
||||
}
|
||||
|
||||
func (a Handler) PathSuffix() string {
|
||||
if a.Type == MethodTypePreview {
|
||||
return "/_preview"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a Handler) MethodReturn() string {
|
||||
if a.Type == MethodTypeUpload {
|
||||
return "Uploader"
|
||||
}
|
||||
if a.Type == MethodTypeDownload {
|
||||
return "Downloader"
|
||||
}
|
||||
if a.Type == MethodTypePreview {
|
||||
return "Downloader"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a Handler) HandlerType() string {
|
||||
if a.Type == MethodTypeUpload {
|
||||
return "UploadHandleFunc"
|
||||
}
|
||||
if a.Type == MethodTypeDownload {
|
||||
return "DownloadHandleFunc"
|
||||
}
|
||||
if a.Type == MethodTypePreview {
|
||||
return "DownloadHandleFunc"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type HandlerType string
|
||||
|
||||
const (
|
||||
MethodTypeUpload = "upload"
|
||||
MethodTypeDownload = "download"
|
||||
MethodTypePreview = "preview"
|
||||
)
|
||||
|
||||
type Services map[string]Service
|
||||
|
||||
type Service struct {
|
||||
Prefix string
|
||||
Methods map[string]Method
|
||||
}
|
||||
|
||||
func GenerateAssetHandler(configFilePath string, output io.Writer, output2 io.Writer) {
|
||||
conf := new(struct {
|
||||
Services Services
|
||||
})
|
||||
err := config.Read(conf, configFilePath)
|
||||
logging.Log("ASSETS-Dgbn4").OnError(err).Fatal("cannot read config")
|
||||
tmplAuthz, err := template.New("").Parse(authzTmpl)
|
||||
logging.Log("ASSETS-BGbbg").OnError(err).Fatal("cannot parse authz template")
|
||||
tmplRouter, err := template.New("").Parse(routerTmpl)
|
||||
logging.Log("ASSETS-gh4rq").OnError(err).Fatal("cannot parse router template")
|
||||
data := &struct {
|
||||
GoPkgName string
|
||||
Name string
|
||||
Prefix string
|
||||
Services Services
|
||||
}{
|
||||
GoPkgName: "assets",
|
||||
Name: "AssetsService",
|
||||
Prefix: "/assets/v1",
|
||||
Services: conf.Services,
|
||||
}
|
||||
err = tmplAuthz.Execute(output, data)
|
||||
logging.Log("ASSETS-BHngj").OnError(err).Fatal("cannot generate authz")
|
||||
err = tmplRouter.Execute(output2, data)
|
||||
logging.Log("ASSETS-Bfd41").OnError(err).Fatal("cannot generate router")
|
||||
}
|
||||
|
||||
const authzTmpl = `package {{.GoPkgName}}
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
)
|
||||
|
||||
/**
|
||||
* {{.Name}}
|
||||
*/
|
||||
|
||||
{{ $prefix := .Prefix }}
|
||||
var {{.Name}}_AuthMethods = authz.MethodMapping {
|
||||
{{ range $service := .Services}}
|
||||
{{ range $method := .Methods}}
|
||||
{{ range $handler := .Handlers}}
|
||||
{{ if (or $method.Feature $handler.Permission) }}
|
||||
"{{$handler.Method}}:{{$prefix}}{{$service.Prefix}}{{$method.Path}}{{$handler.PathSuffix}}": authz.Option{
|
||||
Permission: "{{$handler.Permission}}",
|
||||
Feature: "{{$method.Feature}}",
|
||||
},
|
||||
{{ if $method.HasDarkMode }}
|
||||
"{{$handler.Method}}:{{$prefix}}{{$service.Prefix}}{{$method.Path}}/dark{{$handler.PathSuffix}}": authz.Option{
|
||||
Permission: "{{$handler.Permission}}",
|
||||
Feature: "{{$method.Feature}}",
|
||||
},
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
}
|
||||
`
|
||||
|
||||
const routerTmpl = `package {{.GoPkgName}}
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
)
|
||||
|
||||
type {{.Name}} interface {
|
||||
AuthInterceptor() *http_mw.AuthInterceptor
|
||||
Commands() *command.Commands
|
||||
ErrorHandler() ErrorHandler
|
||||
Storage() static.Storage
|
||||
|
||||
{{ range $service := .Services}}
|
||||
{{ range $methodName, $method := .Methods}}
|
||||
{{ range $handler := .Handlers}}
|
||||
{{$handler.Name}}{{$methodName}}() {{if $handler.MethodReturn}}{{$handler.MethodReturn}}{{end}}
|
||||
{{ if $method.HasDarkMode }}
|
||||
{{$handler.Name}}{{$methodName}}Dark() {{if $handler.MethodReturn}}{{$handler.MethodReturn}}{{end}}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
func RegisterRoutes(router *mux.Router, s {{.Name}}) {
|
||||
|
||||
router.Use(s.AuthInterceptor().Handler)
|
||||
|
||||
{{ range $service := .Services}}
|
||||
{{ range $methodName, $method := .Methods}}
|
||||
{{ range $handler := .Handlers}}
|
||||
router.Path("{{$service.Prefix}}{{$method.Path}}{{$handler.PathSuffix}}").Methods("{{$handler.Method}}").HandlerFunc({{if $handler.HandlerType}}{{$handler.HandlerType}}(s, {{end}}s.{{$handler.Name}}{{$methodName}}(){{if $handler.HandlerType}}){{end}})
|
||||
{{ if $method.HasDarkMode }}
|
||||
router.Path("{{$service.Prefix}}{{$method.Path}}/dark{{$handler.PathSuffix}}").Methods("{{$handler.Method}}").HandlerFunc({{if $handler.HandlerType}}{{$handler.HandlerType}}(s, {{end}}s.{{$handler.Name}}{{$methodName}}Dark(){{if $handler.HandlerType}}){{end}})
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
}
|
||||
`
|
377
internal/api/assets/login_policy.go
Normal file
377
internal/api/assets/login_policy.go
Normal file
@@ -0,0 +1,377 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/iam/model"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
"github.com/caos/zitadel/internal/management/repository"
|
||||
)
|
||||
|
||||
func (h *Handler) UploadDefaultLabelPolicyLogo() Uploader {
|
||||
return &labelPolicyLogoUploader{h.idGenerator, false, true, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
func (h *Handler) UploadDefaultLabelPolicyLogoDark() Uploader {
|
||||
return &labelPolicyLogoUploader{h.idGenerator, true, true, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
func (h *Handler) UploadOrgLabelPolicyLogo() Uploader {
|
||||
return &labelPolicyLogoUploader{h.idGenerator, false, false, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
func (h *Handler) UploadOrgLabelPolicyLogoDark() Uploader {
|
||||
return &labelPolicyLogoUploader{h.idGenerator, true, false, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
type labelPolicyLogoUploader struct {
|
||||
idGenerator id.Generator
|
||||
darkMode bool
|
||||
defaultPolicy bool
|
||||
contentTypes []string
|
||||
maxSize int64
|
||||
}
|
||||
|
||||
func (l *labelPolicyLogoUploader) ContentTypeAllowed(contentType string) bool {
|
||||
for _, ct := range l.contentTypes {
|
||||
if strings.HasPrefix(contentType, ct) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *labelPolicyLogoUploader) MaxFileSize() int64 {
|
||||
return l.maxSize
|
||||
}
|
||||
|
||||
func (l *labelPolicyLogoUploader) ObjectName(_ authz.CtxData) (string, error) {
|
||||
suffixID, err := l.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
prefix := domain.LabelPolicyLogoPath
|
||||
if l.darkMode {
|
||||
return prefix + "-" + domain.Dark + "-" + suffixID, nil
|
||||
}
|
||||
return prefix + "-" + suffixID, nil
|
||||
}
|
||||
|
||||
func (l *labelPolicyLogoUploader) BucketName(ctxData authz.CtxData) string {
|
||||
if l.defaultPolicy {
|
||||
return domain.IAMID
|
||||
}
|
||||
return ctxData.OrgID
|
||||
}
|
||||
|
||||
func (l *labelPolicyLogoUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
||||
if l.defaultPolicy {
|
||||
if l.darkMode {
|
||||
_, err := commands.AddLogoDarkDefaultLabelPolicy(ctx, info.Key)
|
||||
return err
|
||||
}
|
||||
_, err := commands.AddLogoDefaultLabelPolicy(ctx, info.Key)
|
||||
return err
|
||||
}
|
||||
if l.darkMode {
|
||||
_, err := commands.AddLogoDarkLabelPolicy(ctx, orgID, info.Key)
|
||||
return err
|
||||
}
|
||||
_, err := commands.AddLogoLabelPolicy(ctx, orgID, info.Key)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *Handler) GetDefaultLabelPolicyLogo() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: true, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetDefaultLabelPolicyLogoDark() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: true, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewDefaultLabelPolicyLogo() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: true, preview: true}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewDefaultLabelPolicyLogoDark() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: true, preview: true}
|
||||
}
|
||||
|
||||
func (h *Handler) GetOrgLabelPolicyLogo() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: false, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetOrgLabelPolicyLogoDark() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: false, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewOrgLabelPolicyLogo() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: false, preview: true}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewOrgLabelPolicyLogoDark() Downloader {
|
||||
return &labelPolicyLogoDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: false, preview: true}
|
||||
}
|
||||
|
||||
type labelPolicyLogoDownloader struct {
|
||||
org repository.OrgRepository
|
||||
darkMode bool
|
||||
defaultPolicy bool
|
||||
preview bool
|
||||
}
|
||||
|
||||
func (l *labelPolicyLogoDownloader) ObjectName(ctx context.Context, path string) (string, error) {
|
||||
policy, err := getLabelPolicy(ctx, l.defaultPolicy, l.preview, l.org)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if l.darkMode {
|
||||
return policy.LogoDarkURL, nil
|
||||
}
|
||||
return policy.LogoURL, nil
|
||||
}
|
||||
|
||||
func (l *labelPolicyLogoDownloader) BucketName(ctx context.Context, id string) string {
|
||||
if l.defaultPolicy {
|
||||
return domain.IAMID
|
||||
}
|
||||
return authz.GetCtxData(ctx).OrgID
|
||||
}
|
||||
|
||||
func (h *Handler) UploadDefaultLabelPolicyIcon() Uploader {
|
||||
return &labelPolicyIconUploader{h.idGenerator, false, true, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
func (h *Handler) UploadDefaultLabelPolicyIconDark() Uploader {
|
||||
return &labelPolicyIconUploader{h.idGenerator, true, true, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
func (h *Handler) UploadOrgLabelPolicyIcon() Uploader {
|
||||
return &labelPolicyIconUploader{h.idGenerator, false, false, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
func (h *Handler) UploadOrgLabelPolicyIconDark() Uploader {
|
||||
return &labelPolicyIconUploader{h.idGenerator, true, false, []string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
type labelPolicyIconUploader struct {
|
||||
idGenerator id.Generator
|
||||
darkMode bool
|
||||
defaultPolicy bool
|
||||
contentTypes []string
|
||||
maxSize int64
|
||||
}
|
||||
|
||||
func (l *labelPolicyIconUploader) ContentTypeAllowed(contentType string) bool {
|
||||
for _, ct := range l.contentTypes {
|
||||
if strings.HasPrefix(contentType, ct) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *labelPolicyIconUploader) MaxFileSize() int64 {
|
||||
return l.maxSize
|
||||
}
|
||||
|
||||
func (l *labelPolicyIconUploader) ObjectName(_ authz.CtxData) (string, error) {
|
||||
suffixID, err := l.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
prefix := domain.LabelPolicyIconPath
|
||||
if l.darkMode {
|
||||
return prefix + "-" + domain.Dark + "-" + suffixID, nil
|
||||
}
|
||||
return prefix + "-" + suffixID, nil
|
||||
}
|
||||
|
||||
func (l *labelPolicyIconUploader) BucketName(ctxData authz.CtxData) string {
|
||||
if l.defaultPolicy {
|
||||
return domain.IAMID
|
||||
}
|
||||
return ctxData.OrgID
|
||||
}
|
||||
|
||||
func (l *labelPolicyIconUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
||||
if l.defaultPolicy {
|
||||
if l.darkMode {
|
||||
_, err := commands.AddIconDarkDefaultLabelPolicy(ctx, info.Key)
|
||||
return err
|
||||
}
|
||||
_, err := commands.AddIconDefaultLabelPolicy(ctx, info.Key)
|
||||
return err
|
||||
}
|
||||
|
||||
if l.darkMode {
|
||||
_, err := commands.AddIconDarkLabelPolicy(ctx, orgID, info.Key)
|
||||
return err
|
||||
}
|
||||
_, err := commands.AddIconLabelPolicy(ctx, orgID, info.Key)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *Handler) GetDefaultLabelPolicyIcon() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: true, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetDefaultLabelPolicyIconDark() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: true, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewDefaultLabelPolicyIcon() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: true, preview: true}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewDefaultLabelPolicyIconDark() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: true, preview: true}
|
||||
}
|
||||
|
||||
func (h *Handler) GetOrgLabelPolicyIcon() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: false, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetOrgLabelPolicyIconDark() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: false, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewOrgLabelPolicyIcon() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: false, defaultPolicy: false, preview: true}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewOrgLabelPolicyIconDark() Downloader {
|
||||
return &labelPolicyIconDownloader{org: h.orgRepo, darkMode: true, defaultPolicy: false, preview: true}
|
||||
}
|
||||
|
||||
type labelPolicyIconDownloader struct {
|
||||
org repository.OrgRepository
|
||||
darkMode bool
|
||||
defaultPolicy bool
|
||||
preview bool
|
||||
}
|
||||
|
||||
func (l *labelPolicyIconDownloader) ObjectName(ctx context.Context, path string) (string, error) {
|
||||
policy, err := getLabelPolicy(ctx, l.defaultPolicy, l.preview, l.org)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if l.darkMode {
|
||||
return policy.IconDarkURL, nil
|
||||
}
|
||||
return policy.IconURL, nil
|
||||
}
|
||||
|
||||
func (l *labelPolicyIconDownloader) BucketName(ctx context.Context, id string) string {
|
||||
if l.defaultPolicy {
|
||||
return domain.IAMID
|
||||
}
|
||||
return authz.GetCtxData(ctx).OrgID
|
||||
}
|
||||
|
||||
func (h *Handler) UploadDefaultLabelPolicyFont() Uploader {
|
||||
return &labelPolicyFontUploader{h.idGenerator, true, []string{"font/"}, 1 << 19}
|
||||
}
|
||||
|
||||
func (h *Handler) UploadOrgLabelPolicyFont() Uploader {
|
||||
return &labelPolicyFontUploader{h.idGenerator, false, []string{"font/"}, 1 << 19}
|
||||
}
|
||||
|
||||
type labelPolicyFontUploader struct {
|
||||
idGenerator id.Generator
|
||||
defaultPolicy bool
|
||||
contentTypes []string
|
||||
maxSize int64
|
||||
}
|
||||
|
||||
func (l *labelPolicyFontUploader) ContentTypeAllowed(contentType string) bool {
|
||||
for _, ct := range l.contentTypes {
|
||||
if strings.HasPrefix(contentType, ct) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *labelPolicyFontUploader) MaxFileSize() int64 {
|
||||
return l.maxSize
|
||||
}
|
||||
|
||||
func (l *labelPolicyFontUploader) ObjectName(_ authz.CtxData) (string, error) {
|
||||
suffixID, err := l.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
prefix := domain.LabelPolicyFontPath
|
||||
return prefix + "-" + suffixID, nil
|
||||
}
|
||||
|
||||
func (l *labelPolicyFontUploader) BucketName(ctxData authz.CtxData) string {
|
||||
if l.defaultPolicy {
|
||||
return domain.IAMID
|
||||
}
|
||||
return ctxData.OrgID
|
||||
}
|
||||
|
||||
func (l *labelPolicyFontUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
||||
if l.defaultPolicy {
|
||||
_, err := commands.AddFontDefaultLabelPolicy(ctx, info.Key)
|
||||
return err
|
||||
}
|
||||
_, err := commands.AddFontLabelPolicy(ctx, orgID, info.Key)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *Handler) GetDefaultLabelPolicyFont() Downloader {
|
||||
return &labelPolicyFontDownloader{org: h.orgRepo, defaultPolicy: true, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewDefaultLabelPolicyFont() Downloader {
|
||||
return &labelPolicyFontDownloader{org: h.orgRepo, defaultPolicy: true, preview: true}
|
||||
}
|
||||
|
||||
func (h *Handler) GetOrgLabelPolicyFont() Downloader {
|
||||
return &labelPolicyFontDownloader{org: h.orgRepo, defaultPolicy: false, preview: false}
|
||||
}
|
||||
|
||||
func (h *Handler) GetPreviewOrgLabelPolicyFont() Downloader {
|
||||
return &labelPolicyFontDownloader{org: h.orgRepo, defaultPolicy: true, preview: true}
|
||||
}
|
||||
|
||||
type labelPolicyFontDownloader struct {
|
||||
org repository.OrgRepository
|
||||
defaultPolicy bool
|
||||
preview bool
|
||||
}
|
||||
|
||||
func (l *labelPolicyFontDownloader) ObjectName(ctx context.Context, path string) (string, error) {
|
||||
policy, err := getLabelPolicy(ctx, l.defaultPolicy, l.preview, l.org)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return policy.FontURL, nil
|
||||
}
|
||||
|
||||
func (l *labelPolicyFontDownloader) BucketName(ctx context.Context, id string) string {
|
||||
if l.defaultPolicy {
|
||||
return domain.IAMID
|
||||
}
|
||||
return authz.GetCtxData(ctx).OrgID
|
||||
}
|
||||
|
||||
func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, orgRepo repository.OrgRepository) (*model.LabelPolicyView, error) {
|
||||
if defaultPolicy {
|
||||
if preview {
|
||||
return orgRepo.GetPreviewDefaultLabelPolicy(ctx)
|
||||
}
|
||||
return orgRepo.GetDefaultLabelPolicy(ctx)
|
||||
}
|
||||
if preview {
|
||||
return orgRepo.GetPreviewLabelPolicy(ctx)
|
||||
}
|
||||
return orgRepo.GetLabelPolicy(ctx)
|
||||
}
|
59
internal/api/assets/user_avatar.go
Normal file
59
internal/api/assets/user_avatar.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
func (h *Handler) UploadMyUserAvatar() Uploader {
|
||||
return &myHumanAvatarUploader{[]string{"image/"}, 1 << 19}
|
||||
}
|
||||
|
||||
type myHumanAvatarUploader struct {
|
||||
contentTypes []string
|
||||
maxSize int64
|
||||
}
|
||||
|
||||
func (l *myHumanAvatarUploader) ContentTypeAllowed(contentType string) bool {
|
||||
for _, ct := range l.contentTypes {
|
||||
if strings.HasPrefix(contentType, ct) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *myHumanAvatarUploader) MaxFileSize() int64 {
|
||||
return l.maxSize
|
||||
}
|
||||
|
||||
func (l *myHumanAvatarUploader) ObjectName(ctxData authz.CtxData) (string, error) {
|
||||
return domain.GetHumanAvatarAssetPath(ctxData.UserID), nil
|
||||
}
|
||||
|
||||
func (l *myHumanAvatarUploader) BucketName(ctxData authz.CtxData) string {
|
||||
return ctxData.OrgID
|
||||
}
|
||||
|
||||
func (l *myHumanAvatarUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
||||
_, err := commands.AddHumanAvatar(ctx, orgID, authz.GetCtxData(ctx).UserID, info.Key)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *Handler) GetMyUserAvatar() Downloader {
|
||||
return &myHumanAvatarDownloader{}
|
||||
}
|
||||
|
||||
type myHumanAvatarDownloader struct{}
|
||||
|
||||
func (l *myHumanAvatarDownloader) ObjectName(ctx context.Context, path string) (string, error) {
|
||||
return domain.GetHumanAvatarAssetPath(authz.GetCtxData(ctx).UserID), nil
|
||||
}
|
||||
|
||||
func (l *myHumanAvatarDownloader) BucketName(ctx context.Context, id string) string {
|
||||
return authz.GetCtxData(ctx).OrgID
|
||||
}
|
@@ -71,7 +71,8 @@ func setDefaultFeaturesRequestToDomain(req *admin_pb.SetDefaultFeaturesRequest)
|
||||
LoginPolicyUsernameLogin: req.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: req.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: req.PasswordComplexityPolicy,
|
||||
LabelPolicy: req.LabelPolicy,
|
||||
LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: req.LabelPolicyWatermark,
|
||||
CustomDomain: req.CustomDomain,
|
||||
}
|
||||
}
|
||||
@@ -90,7 +91,8 @@ func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.
|
||||
LoginPolicyUsernameLogin: req.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: req.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: req.PasswordComplexityPolicy,
|
||||
LabelPolicy: req.LabelPolicy,
|
||||
LabelPolicyPrivateLabel: req.LabelPolicy || req.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: req.LabelPolicyWatermark,
|
||||
CustomDomain: req.CustomDomain,
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,14 @@ func (s *Server) GetLabelPolicy(ctx context.Context, req *admin_pb.GetLabelPolic
|
||||
return &admin_pb.GetLabelPolicyResponse{Policy: policy_grpc.ModelLabelPolicyToPb(policy)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetPreviewLabelPolicy(ctx context.Context, req *admin_pb.GetPreviewLabelPolicyRequest) (*admin_pb.GetPreviewLabelPolicyResponse, error) {
|
||||
policy, err := s.iam.GetDefaultPreviewLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetPreviewLabelPolicyResponse{Policy: policy_grpc.ModelLabelPolicyToPb(policy)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateLabelPolicy(ctx context.Context, req *admin_pb.UpdateLabelPolicyRequest) (*admin_pb.UpdateLabelPolicyResponse, error) {
|
||||
policy, err := s.command.ChangeDefaultLabelPolicy(ctx, updateLabelPolicyToDomain(req))
|
||||
if err != nil {
|
||||
@@ -29,3 +37,87 @@ func (s *Server) UpdateLabelPolicy(ctx context.Context, req *admin_pb.UpdateLabe
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ActivateLabelPolicy(ctx context.Context, req *admin_pb.ActivateLabelPolicyRequest) (*admin_pb.ActivateLabelPolicyResponse, error) {
|
||||
policy, err := s.command.ActivateDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.ActivateLabelPolicyResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveLabelPolicyLogo(ctx context.Context, req *admin_pb.RemoveLabelPolicyLogoRequest) (*admin_pb.RemoveLabelPolicyLogoResponse, error) {
|
||||
policy, err := s.command.RemoveLogoDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.RemoveLabelPolicyLogoResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveLabelPolicyLogoDark(ctx context.Context, req *admin_pb.RemoveLabelPolicyLogoDarkRequest) (*admin_pb.RemoveLabelPolicyLogoDarkResponse, error) {
|
||||
policy, err := s.command.RemoveLogoDarkDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.RemoveLabelPolicyLogoDarkResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveLabelPolicyIcon(ctx context.Context, req *admin_pb.RemoveLabelPolicyIconRequest) (*admin_pb.RemoveLabelPolicyIconResponse, error) {
|
||||
policy, err := s.command.RemoveIconDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.RemoveLabelPolicyIconResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveLabelPolicyIconDark(ctx context.Context, req *admin_pb.RemoveLabelPolicyIconDarkRequest) (*admin_pb.RemoveLabelPolicyIconDarkResponse, error) {
|
||||
policy, err := s.command.RemoveIconDarkDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.RemoveLabelPolicyIconDarkResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveLabelPolicyFont(ctx context.Context, req *admin_pb.RemoveLabelPolicyFontRequest) (*admin_pb.RemoveLabelPolicyFontResponse, error) {
|
||||
policy, err := s.command.RemoveFontDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.RemoveLabelPolicyFontResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
@@ -8,7 +8,14 @@ import (
|
||||
func updateLabelPolicyToDomain(policy *admin_pb.UpdateLabelPolicyRequest) *domain.LabelPolicy {
|
||||
return &domain.LabelPolicy{
|
||||
PrimaryColor: policy.PrimaryColor,
|
||||
SecondaryColor: policy.SecondaryColor,
|
||||
BackgroundColor: policy.BackgroundColor,
|
||||
WarnColor: policy.WarnColor,
|
||||
FontColor: policy.FontColor,
|
||||
PrimaryColorDark: policy.PrimaryColorDark,
|
||||
BackgroundColorDark: policy.BackgroundColorDark,
|
||||
WarnColorDark: policy.WarnColorDark,
|
||||
FontColorDark: policy.FontColorDark,
|
||||
HideLoginNameSuffix: policy.HideLoginNameSuffix,
|
||||
DisableWatermark: policy.DisableWatermark,
|
||||
}
|
||||
}
|
||||
|
20
internal/api/grpc/auth/avatar.go
Normal file
20
internal/api/grpc/auth/avatar.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||
auth_pb "github.com/caos/zitadel/pkg/grpc/auth"
|
||||
)
|
||||
|
||||
func (s *Server) RemoveMyAvatar(ctx context.Context, req *auth_pb.RemoveMyAvatarRequest) (*auth_pb.RemoveMyAvatarResponse, error) {
|
||||
ctxData := authz.GetCtxData(ctx)
|
||||
objectDetails, err := s.command.RemoveHumanAvatar(ctx, ctxData.ResourceOwner, ctxData.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &auth_pb.RemoveMyAvatarResponse{
|
||||
Details: object.DomainToChangeDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/api/grpc/server"
|
||||
"github.com/caos/zitadel/internal/auth/repository"
|
||||
@@ -8,7 +10,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/pkg/grpc/auth"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var _ auth.AuthServiceServer = (*Server)(nil)
|
||||
|
@@ -23,8 +23,10 @@ func FeaturesFromModel(features *features_model.FeaturesView) *features_pb.Featu
|
||||
LoginPolicyUsernameLogin: features.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: features.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: features.PasswordComplexityPolicy,
|
||||
LabelPolicy: features.LabelPolicy,
|
||||
LabelPolicy: features.LabelPolicyPrivateLabel,
|
||||
CustomDomain: features.CustomDomain,
|
||||
LabelPolicyPrivateLabel: features.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: features.LabelPolicyWatermark,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,15 @@ func (s *Server) GetLabelPolicy(ctx context.Context, req *mgmt_pb.GetLabelPolicy
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetLabelPolicyResponse{Policy: policy_grpc.ModelLabelPolicyToPb(policy)}, nil
|
||||
return &mgmt_pb.GetLabelPolicyResponse{Policy: policy_grpc.ModelLabelPolicyToPb(policy), IsDefault: policy.Default}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetPreviewLabelPolicy(ctx context.Context, req *mgmt_pb.GetPreviewLabelPolicyRequest) (*mgmt_pb.GetPreviewLabelPolicyResponse, error) {
|
||||
policy, err := s.org.GetPreviewLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetPreviewLabelPolicyResponse{Policy: policy_grpc.ModelLabelPolicyToPb(policy)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultLabelPolicy(ctx context.Context, req *mgmt_pb.GetDefaultLabelPolicyRequest) (*mgmt_pb.GetDefaultLabelPolicyResponse, error) {
|
||||
@@ -53,6 +61,20 @@ func (s *Server) UpdateCustomLabelPolicy(ctx context.Context, req *mgmt_pb.Updat
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ActivateCustomLabelPolicy(ctx context.Context, req *mgmt_pb.ActivateCustomLabelPolicyRequest) (*mgmt_pb.ActivateCustomLabelPolicyResponse, error) {
|
||||
policy, err := s.command.ActivateLabelPolicy(ctx, authz.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.ActivateCustomLabelPolicyResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ResetLabelPolicyToDefault(ctx context.Context, req *mgmt_pb.ResetLabelPolicyToDefaultRequest) (*mgmt_pb.ResetLabelPolicyToDefaultResponse, error) {
|
||||
objectDetails, err := s.command.RemoveLabelPolicy(ctx, authz.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
@@ -62,3 +84,73 @@ func (s *Server) ResetLabelPolicyToDefault(ctx context.Context, req *mgmt_pb.Res
|
||||
Details: object.DomainToChangeDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveCustomLabelPolicyLogo(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyLogoRequest) (*mgmt_pb.RemoveCustomLabelPolicyLogoResponse, error) {
|
||||
policy, err := s.command.RemoveLogoDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.RemoveCustomLabelPolicyLogoResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveCustomLabelPolicyLogoDark(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyLogoDarkRequest) (*mgmt_pb.RemoveCustomLabelPolicyLogoDarkResponse, error) {
|
||||
policy, err := s.command.RemoveLogoDarkDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.RemoveCustomLabelPolicyLogoDarkResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveCustomLabelPolicyIcon(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyIconRequest) (*mgmt_pb.RemoveCustomLabelPolicyIconResponse, error) {
|
||||
policy, err := s.command.RemoveIconDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.RemoveCustomLabelPolicyIconResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveCustomLabelPolicyIconDark(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyIconDarkRequest) (*mgmt_pb.RemoveCustomLabelPolicyIconDarkResponse, error) {
|
||||
policy, err := s.command.RemoveIconDarkDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.RemoveCustomLabelPolicyIconDarkResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveCustomLabelPolicyFont(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyFontRequest) (*mgmt_pb.RemoveCustomLabelPolicyFontResponse, error) {
|
||||
policy, err := s.command.RemoveFontDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.RemoveCustomLabelPolicyFontResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
policy.Sequence,
|
||||
policy.EventDate,
|
||||
policy.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
@@ -8,15 +8,27 @@ import (
|
||||
func addLabelPolicyToDomain(p *mgmt_pb.AddCustomLabelPolicyRequest) *domain.LabelPolicy {
|
||||
return &domain.LabelPolicy{
|
||||
PrimaryColor: p.PrimaryColor,
|
||||
SecondaryColor: p.SecondaryColor,
|
||||
BackgroundColor: p.BackgroundColor,
|
||||
WarnColor: p.WarnColor,
|
||||
PrimaryColorDark: p.PrimaryColorDark,
|
||||
BackgroundColorDark: p.BackgroundColorDark,
|
||||
WarnColorDark: p.WarnColorDark,
|
||||
HideLoginNameSuffix: p.HideLoginNameSuffix,
|
||||
DisableWatermark: p.DisableWatermark,
|
||||
}
|
||||
}
|
||||
|
||||
func updateLabelPolicyToDomain(p *mgmt_pb.UpdateCustomLabelPolicyRequest) *domain.LabelPolicy {
|
||||
return &domain.LabelPolicy{
|
||||
PrimaryColor: p.PrimaryColor,
|
||||
SecondaryColor: p.SecondaryColor,
|
||||
BackgroundColor: p.BackgroundColor,
|
||||
WarnColor: p.WarnColor,
|
||||
FontColor: p.FontColor,
|
||||
PrimaryColorDark: p.PrimaryColorDark,
|
||||
BackgroundColorDark: p.BackgroundColorDark,
|
||||
WarnColorDark: p.WarnColorDark,
|
||||
FontColorDark: p.FontColorDark,
|
||||
HideLoginNameSuffix: p.HideLoginNameSuffix,
|
||||
DisableWatermark: p.DisableWatermark,
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ func (s *Server) GetLoginPolicy(ctx context.Context, req *mgmt_pb.GetLoginPolicy
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetLoginPolicyResponse{Policy: policy_grpc.ModelLoginPolicyToPb(policy)}, nil
|
||||
return &mgmt_pb.GetLoginPolicyResponse{Policy: policy_grpc.ModelLoginPolicyToPb(policy), IsDefault: policy.Default}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultLoginPolicy(ctx context.Context, req *mgmt_pb.GetDefaultLoginPolicyRequest) (*mgmt_pb.GetDefaultLoginPolicyResponse, error) {
|
||||
|
@@ -14,7 +14,8 @@ func (s *Server) GetPasswordAgePolicy(ctx context.Context, req *mgmt_pb.GetPassw
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetPasswordAgePolicyResponse{
|
||||
Policy: policy_grpc.ModelPasswordAgePolicyToPb(policy),
|
||||
Policy: policy_grpc.ModelPasswordAgePolicyToPb(policy),
|
||||
IsDefault: policy.Default,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,7 @@ func (s *Server) GetPasswordComplexityPolicy(ctx context.Context, req *mgmt_pb.G
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetPasswordComplexityPolicyResponse{Policy: policy_grpc.ModelPasswordComplexityPolicyToPb(policy)}, nil
|
||||
return &mgmt_pb.GetPasswordComplexityPolicyResponse{Policy: policy_grpc.ModelPasswordComplexityPolicyToPb(policy), IsDefault: policy.Default}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultPasswordComplexityPolicy(ctx context.Context, req *mgmt_pb.GetDefaultPasswordComplexityPolicyRequest) (*mgmt_pb.GetDefaultPasswordComplexityPolicyResponse, error) {
|
||||
|
@@ -13,7 +13,7 @@ func (s *Server) GetPasswordLockoutPolicy(ctx context.Context, req *mgmt_pb.GetP
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetPasswordLockoutPolicyResponse{Policy: policy_grpc.ModelPasswordLockoutPolicyToPb(policy)}, nil
|
||||
return &mgmt_pb.GetPasswordLockoutPolicyResponse{Policy: policy_grpc.ModelPasswordLockoutPolicyToPb(policy), IsDefault: policy.Default}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDefaultPasswordLockoutPolicy(ctx context.Context, req *mgmt_pb.GetDefaultPasswordLockoutPolicyRequest) (*mgmt_pb.GetDefaultPasswordLockoutPolicyResponse, error) {
|
||||
|
@@ -323,6 +323,17 @@ func (s *Server) ResendHumanPhoneVerification(ctx context.Context, req *mgmt_pb.
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveHumanAvatar(ctx context.Context, req *mgmt_pb.RemoveHumanAvatarRequest) (*mgmt_pb.RemoveHumanAvatarResponse, error) {
|
||||
ctxData := authz.GetCtxData(ctx)
|
||||
objectDetails, err := s.command.RemoveHumanAvatar(ctx, ctxData.OrgID, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.RemoveHumanAvatarResponse{
|
||||
Details: object.DomainToChangeDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetHumanInitialPassword(ctx context.Context, req *mgmt_pb.SetHumanInitialPasswordRequest) (*mgmt_pb.SetHumanInitialPasswordResponse, error) {
|
||||
objectDetails, err := s.command.SetPassword(ctx, authz.GetCtxData(ctx).OrgID, req.UserId, req.Password, true)
|
||||
if err != nil {
|
||||
|
@@ -10,7 +10,20 @@ func ModelLabelPolicyToPb(policy *model.LabelPolicyView) *policy_pb.LabelPolicy
|
||||
return &policy_pb.LabelPolicy{
|
||||
IsDefault: policy.Default,
|
||||
PrimaryColor: policy.PrimaryColor,
|
||||
SecondaryColor: policy.SecondaryColor,
|
||||
BackgroundColor: policy.BackgroundColor,
|
||||
FontColor: policy.FontColor,
|
||||
WarnColor: policy.WarnColor,
|
||||
PrimaryColorDark: policy.PrimaryColorDark,
|
||||
BackgroundColorDark: policy.BackgroundColorDark,
|
||||
WarnColorDark: policy.WarnColorDark,
|
||||
FontColorDark: policy.FontColorDark,
|
||||
FontUrl: policy.FontURL,
|
||||
LogoUrl: policy.LogoURL,
|
||||
LogoUrlDark: policy.LogoDarkURL,
|
||||
IconUrl: policy.IconURL,
|
||||
IconUrlDark: policy.IconDarkURL,
|
||||
|
||||
DisableWatermark: policy.DisableWatermark,
|
||||
HideLoginNameSuffix: policy.HideLoginNameSuffix,
|
||||
Details: object.ToViewDetailsPb(
|
||||
policy.Sequence,
|
||||
|
@@ -80,6 +80,14 @@ func RemoteIPStringFromRequest(r *http.Request) string {
|
||||
return r.RemoteAddr
|
||||
}
|
||||
|
||||
func GetAuthorization(r *http.Request) string {
|
||||
return r.Header.Get(Authorization)
|
||||
}
|
||||
|
||||
func GetOrgID(r *http.Request) string {
|
||||
return r.Header.Get(ZitadelOrgID)
|
||||
}
|
||||
|
||||
func GetForwardedFor(headers http.Header) (string, bool) {
|
||||
forwarded, ok := headers[ForwardedFor]
|
||||
if ok {
|
||||
|
71
internal/api/http/middleware/auth_interceptor.go
Normal file
71
internal/api/http/middleware/auth_interceptor.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
http_util "github.com/caos/zitadel/internal/api/http"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
)
|
||||
|
||||
type AuthInterceptor struct {
|
||||
verifier *authz.TokenVerifier
|
||||
authConfig authz.Config
|
||||
}
|
||||
|
||||
func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) *AuthInterceptor {
|
||||
return &AuthInterceptor{
|
||||
verifier: verifier,
|
||||
authConfig: authConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AuthInterceptor) Handler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, err := authorize(r, a.verifier, a.authConfig)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
r = r.WithContext(ctx)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *AuthInterceptor) HandlerFunc(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, err := authorize(r, a.verifier, a.authConfig)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
r = r.WithContext(ctx)
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
type httpReq struct{}
|
||||
|
||||
func authorize(r *http.Request, verifier *authz.TokenVerifier, authConfig authz.Config) (_ context.Context, err error) {
|
||||
ctx := r.Context()
|
||||
authOpt, needsToken := verifier.CheckAuthMethod(r.Method + ":" + r.RequestURI)
|
||||
if !needsToken {
|
||||
return ctx, nil
|
||||
}
|
||||
authCtx, span := tracing.NewServerInterceptorSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
authToken := http_util.GetAuthorization(r)
|
||||
if authToken == "" {
|
||||
return nil, errors.New("auth header missing")
|
||||
}
|
||||
|
||||
ctxSetter, err := authz.CheckUserAuthorization(authCtx, &httpReq{}, authToken, http_util.GetOrgID(r), verifier, authConfig, authOpt, r.RequestURI) //TODO: permission
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
span.End()
|
||||
return ctxSetter(ctx), nil
|
||||
}
|
@@ -248,7 +248,7 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge
|
||||
if request.RequestedOrgID == "" {
|
||||
username = user.PreferredLoginName
|
||||
}
|
||||
request.SetUserInfo(user.ID, username, user.PreferredLoginName, user.DisplayName, user.ResourceOwner)
|
||||
request.SetUserInfo(user.ID, username, user.PreferredLoginName, user.DisplayName, user.AvatarKey, user.ResourceOwner)
|
||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||
}
|
||||
|
||||
@@ -466,7 +466,7 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain
|
||||
return err
|
||||
}
|
||||
|
||||
request.SetUserInfo(user.ID, loginName, user.PreferredLoginName, "", user.ResourceOwner)
|
||||
request.SetUserInfo(user.ID, loginName, user.PreferredLoginName, "", "", user.ResourceOwner)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ func (repo *AuthRequestRepo) checkExternalUserLogin(request *domain.AuthRequest,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.SetUserInfo(externalIDP.UserID, "", "", "", externalIDP.ResourceOwner)
|
||||
request.SetUserInfo(externalIDP.UserID, "", "", "", "", externalIDP.ResourceOwner)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -614,6 +614,7 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *domain.AuthRequest)
|
||||
DisplayName: session.DisplayName,
|
||||
UserName: session.UserName,
|
||||
LoginName: session.LoginName,
|
||||
AvatarKey: session.AvatarKey,
|
||||
UserSessionState: auth_req_model.UserSessionStateToDomain(session.State),
|
||||
SelectionPossible: request.RequestedOrgID == "" || request.RequestedOrgID == session.ResourceOwner,
|
||||
}
|
||||
@@ -710,9 +711,9 @@ func (repo *AuthRequestRepo) getLoginPolicy(ctx context.Context, orgID string) (
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) getLabelPolicy(ctx context.Context, orgID string) (*domain.LabelPolicy, error) {
|
||||
policy, err := repo.View.LabelPolicyByAggregateID(orgID)
|
||||
policy, err := repo.View.LabelPolicyByAggregateIDAndState(orgID, int32(domain.LabelPolicyStateActive))
|
||||
if errors.IsNotFound(err) {
|
||||
policy, err = repo.View.LabelPolicyByAggregateID(repo.IAMID)
|
||||
policy, err = repo.View.LabelPolicyByAggregateIDAndState(repo.IAMID, int32(domain.LabelPolicyStateActive))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
@@ -103,3 +104,14 @@ func (repo *OrgRepository) GetMyPasswordComplexityPolicy(ctx context.Context) (*
|
||||
}
|
||||
return iam_view_model.PasswordComplexityViewToModel(policy), err
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetLabelPolicy(ctx context.Context, orgID string) (*iam_model.LabelPolicyView, error) {
|
||||
orgPolicy, err := repo.View.LabelPolicyByAggregateIDAndState(orgID, int32(domain.LabelPolicyStateActive))
|
||||
if errors.IsNotFound(err) {
|
||||
orgPolicy, err = repo.View.LabelPolicyByAggregateIDAndState(repo.SystemDefaults.IamID, int32(domain.LabelPolicyStateActive))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_view_model.LabelPolicyViewToModel(orgPolicy), nil
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@ package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
@@ -79,8 +81,19 @@ func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case iam_es_model.LabelPolicyAdded, model.LabelPolicyAdded:
|
||||
err = policy.AppendEvent(event)
|
||||
case iam_es_model.LabelPolicyChanged, model.LabelPolicyChanged:
|
||||
policy, err = m.view.LabelPolicyByAggregateID(event.AggregateID)
|
||||
case iam_es_model.LabelPolicyChanged, model.LabelPolicyChanged,
|
||||
iam_es_model.LabelPolicyActivated, model.LabelPolicyActivated,
|
||||
iam_es_model.LabelPolicyLogoAdded, model.LabelPolicyLogoAdded,
|
||||
iam_es_model.LabelPolicyLogoRemoved, model.LabelPolicyLogoRemoved,
|
||||
iam_es_model.LabelPolicyIconAdded, model.LabelPolicyIconAdded,
|
||||
iam_es_model.LabelPolicyIconRemoved, model.LabelPolicyIconRemoved,
|
||||
iam_es_model.LabelPolicyLogoDarkAdded, model.LabelPolicyLogoDarkAdded,
|
||||
iam_es_model.LabelPolicyLogoDarkRemoved, model.LabelPolicyLogoDarkRemoved,
|
||||
iam_es_model.LabelPolicyIconDarkAdded, model.LabelPolicyIconDarkAdded,
|
||||
iam_es_model.LabelPolicyIconDarkRemoved, model.LabelPolicyIconDarkRemoved,
|
||||
iam_es_model.LabelPolicyFontAdded, model.LabelPolicyFontAdded,
|
||||
iam_es_model.LabelPolicyFontRemoved, model.LabelPolicyFontRemoved:
|
||||
policy, err = m.view.LabelPolicyByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -122,6 +122,8 @@ func (u *User) ProcessUser(event *es_models.Event) (err error) {
|
||||
es_model.HumanProfileChanged,
|
||||
es_model.HumanEmailChanged,
|
||||
es_model.HumanEmailVerified,
|
||||
es_model.HumanAvatarAdded,
|
||||
es_model.HumanAvatarRemoved,
|
||||
es_model.HumanPhoneChanged,
|
||||
es_model.HumanPhoneVerified,
|
||||
es_model.HumanPhoneRemoved,
|
||||
|
@@ -111,6 +111,8 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
|
||||
es_model.HumanPasswordChanged,
|
||||
es_model.HumanMFAOTPRemoved,
|
||||
es_model.HumanProfileChanged,
|
||||
es_model.HumanAvatarAdded,
|
||||
es_model.HumanAvatarRemoved,
|
||||
es_model.DomainClaimed,
|
||||
es_model.UserUserNameChanged,
|
||||
es_model.HumanExternalIDPRemoved,
|
||||
@@ -167,5 +169,6 @@ func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id strin
|
||||
session.UserName = user.UserName
|
||||
session.LoginName = user.PreferredLoginName
|
||||
session.DisplayName = user.DisplayName
|
||||
session.AvatarKey = user.AvatarKey
|
||||
return nil
|
||||
}
|
||||
|
@@ -12,8 +12,8 @@ const (
|
||||
labelPolicyTable = "auth.label_policies"
|
||||
)
|
||||
|
||||
func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
|
||||
func (v *View) LabelPolicyByAggregateIDAndState(aggregateID string, state int32) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateIDAndState(v.Db, labelPolicyTable, aggregateID, state)
|
||||
}
|
||||
|
||||
func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, event *models.Event) error {
|
||||
|
@@ -12,4 +12,5 @@ type OrgRepository interface {
|
||||
GetDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicyView, error)
|
||||
GetIDPConfigByID(ctx context.Context, idpConfigID string) (*iam_model.IDPConfigView, error)
|
||||
GetMyPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error)
|
||||
GetLabelPolicy(ctx context.Context, orgID string) (*iam_model.LabelPolicyView, error)
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
@@ -130,13 +131,21 @@ func checkFeatures(features *features_view_model.FeaturesView, requiredFeatures
|
||||
if err := checkLoginPolicyFeatures(features, requiredFeature); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if requiredFeature == domain.FeaturePasswordComplexityPolicy && !features.PasswordComplexityPolicy {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
if requiredFeature == domain.FeaturePasswordComplexityPolicy {
|
||||
if !features.PasswordComplexityPolicy {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if requiredFeature == domain.FeatureLabelPolicy && !features.PasswordComplexityPolicy {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
if strings.HasPrefix(requiredFeature, domain.FeatureLabelPolicy) {
|
||||
if err := checkLabelPolicyFeatures(features, requiredFeature); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -175,6 +184,20 @@ func checkLoginPolicyFeatures(features *features_view_model.FeaturesView, requir
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkLabelPolicyFeatures(features *features_view_model.FeaturesView, requiredFeature string) error {
|
||||
switch requiredFeature {
|
||||
case domain.FeatureLabelPolicyPrivateLabel:
|
||||
if !features.LabelPolicyPrivateLabel {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
case domain.FeatureLabelPolicyWatermark:
|
||||
if !features.LabelPolicyWatermark {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func MissingFeatureErr(feature string) error {
|
||||
return caos_errs.ThrowPermissionDeniedf(nil, "AUTH-Dvgsf", "missing feature %v", feature)
|
||||
}
|
||||
|
@@ -20,12 +20,14 @@ import (
|
||||
proj_repo "github.com/caos/zitadel/internal/repository/project"
|
||||
usr_repo "github.com/caos/zitadel/internal/repository/user"
|
||||
usr_grant_repo "github.com/caos/zitadel/internal/repository/usergrant"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
webauthn_helper "github.com/caos/zitadel/internal/webauthn"
|
||||
)
|
||||
|
||||
type Commands struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
static static.Storage
|
||||
idGenerator id.Generator
|
||||
iamDomain string
|
||||
zitadelRoles []authz.RoleMapping
|
||||
@@ -58,9 +60,10 @@ type Config struct {
|
||||
Eventstore types.SQLUser
|
||||
}
|
||||
|
||||
func StartCommands(eventstore *eventstore.Eventstore, defaults sd.SystemDefaults, authZConfig authz.Config, authZRepo *authz_repo.EsRepository) (repo *Commands, err error) {
|
||||
func StartCommands(eventstore *eventstore.Eventstore, defaults sd.SystemDefaults, authZConfig authz.Config, staticStore static.Storage, authZRepo *authz_repo.EsRepository) (repo *Commands, err error) {
|
||||
repo = &Commands{
|
||||
eventstore: eventstore,
|
||||
static: staticStore,
|
||||
idGenerator: id.SonyFlakeGenerator,
|
||||
iamDomain: defaults.Domain,
|
||||
zitadelRoles: authZConfig.RolePermissionMappings,
|
||||
|
54
internal/command/existing_label_policies_model.go
Normal file
54
internal/command/existing_label_policies_model.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
type ExistingLabelPoliciesReadModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
aggregateIDs []string
|
||||
}
|
||||
|
||||
func NewExistingLabelPoliciesReadModel(ctx context.Context) *ExistingLabelPoliciesReadModel {
|
||||
return &ExistingLabelPoliciesReadModel{}
|
||||
}
|
||||
|
||||
func (rm *ExistingLabelPoliciesReadModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
rm.WriteModel.AppendEvents(events...)
|
||||
}
|
||||
|
||||
func (rm *ExistingLabelPoliciesReadModel) Reduce() error {
|
||||
for _, event := range rm.Events {
|
||||
switch e := event.(type) {
|
||||
case *iam.LabelPolicyAddedEvent,
|
||||
*org.LabelPolicyAddedEvent:
|
||||
rm.aggregateIDs = append(rm.aggregateIDs, e.Aggregate().ID)
|
||||
case *org.LabelPolicyRemovedEvent:
|
||||
for i := len(rm.aggregateIDs) - 1; i >= 0; i-- {
|
||||
if rm.aggregateIDs[i] == e.Aggregate().ID {
|
||||
copy(rm.aggregateIDs[i:], rm.aggregateIDs[i+1:])
|
||||
rm.aggregateIDs[len(rm.aggregateIDs)-1] = ""
|
||||
rm.aggregateIDs = rm.aggregateIDs[:len(rm.aggregateIDs)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rm *ExistingLabelPoliciesReadModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(
|
||||
eventstore.ColumnsEvent,
|
||||
iam.AggregateType,
|
||||
org.AggregateType).
|
||||
EventTypes(
|
||||
iam.LabelPolicyAddedEventType,
|
||||
org.LabelPolicyAddedEventType,
|
||||
org.LabelPolicyRemovedEventType,
|
||||
)
|
||||
}
|
@@ -23,7 +23,8 @@ type FeaturesWriteModel struct {
|
||||
LoginPolicyUsernameLogin bool
|
||||
LoginPolicyPasswordReset bool
|
||||
PasswordComplexityPolicy bool
|
||||
LabelPolicy bool
|
||||
LabelPolicyPrivateLabel bool
|
||||
LabelPolicyWatermark bool
|
||||
CustomDomain bool
|
||||
}
|
||||
|
||||
@@ -69,7 +70,13 @@ func (wm *FeaturesWriteModel) Reduce() error {
|
||||
wm.PasswordComplexityPolicy = *e.PasswordComplexityPolicy
|
||||
}
|
||||
if e.LabelPolicy != nil {
|
||||
wm.LabelPolicy = *e.LabelPolicy
|
||||
wm.LabelPolicyPrivateLabel = *e.LabelPolicy
|
||||
}
|
||||
if e.LabelPolicyPrivateLabel != nil {
|
||||
wm.LabelPolicyPrivateLabel = *e.LabelPolicyPrivateLabel
|
||||
}
|
||||
if e.LabelPolicyWatermark != nil {
|
||||
wm.LabelPolicyWatermark = *e.LabelPolicyWatermark
|
||||
}
|
||||
if e.CustomDomain != nil {
|
||||
wm.CustomDomain = *e.CustomDomain
|
||||
|
@@ -49,8 +49,16 @@ func writeModelToLabelPolicy(wm *LabelPolicyWriteModel) *domain.LabelPolicy {
|
||||
return &domain.LabelPolicy{
|
||||
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
|
||||
PrimaryColor: wm.PrimaryColor,
|
||||
SecondaryColor: wm.SecondaryColor,
|
||||
BackgroundColor: wm.BackgroundColor,
|
||||
WarnColor: wm.WarnColor,
|
||||
FontColor: wm.FontColor,
|
||||
PrimaryColorDark: wm.PrimaryColorDark,
|
||||
BackgroundColorDark: wm.BackgroundColorDark,
|
||||
WarnColorDark: wm.WarnColorDark,
|
||||
FontColorDark: wm.FontColorDark,
|
||||
HideLoginNameSuffix: wm.HideLoginNameSuffix,
|
||||
ErrorMsgPopup: wm.ErrorMsgPopup,
|
||||
DisableWatermark: wm.DisableWatermark,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +184,8 @@ func writeModelToFeatures(wm *FeaturesWriteModel) *domain.Features {
|
||||
LoginPolicyRegistration: wm.LoginPolicyRegistration,
|
||||
LoginPolicyUsernameLogin: wm.LoginPolicyUsernameLogin,
|
||||
PasswordComplexityPolicy: wm.PasswordComplexityPolicy,
|
||||
LabelPolicy: wm.LabelPolicy,
|
||||
LabelPolicyPrivateLabel: wm.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: wm.LabelPolicyWatermark,
|
||||
CustomDomain: wm.CustomDomain,
|
||||
}
|
||||
}
|
||||
|
@@ -46,7 +46,8 @@ func (c *Commands) setDefaultFeatures(ctx context.Context, existingFeatures *IAM
|
||||
features.LoginPolicyRegistration,
|
||||
features.LoginPolicyUsernameLogin,
|
||||
features.PasswordComplexityPolicy,
|
||||
features.LabelPolicy,
|
||||
features.LabelPolicyPrivateLabel,
|
||||
features.LabelPolicyWatermark,
|
||||
features.CustomDomain,
|
||||
)
|
||||
if !hasChanged {
|
||||
@@ -61,5 +62,7 @@ func (c *Commands) getDefaultFeatures(ctx context.Context) (*domain.Features, er
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToFeatures(&existingFeatures.FeaturesWriteModel), nil
|
||||
features := writeModelToFeatures(&existingFeatures.FeaturesWriteModel)
|
||||
features.IsDefault = true
|
||||
return features, nil
|
||||
}
|
||||
|
@@ -62,7 +62,8 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
loginPolicyRegistration,
|
||||
loginPolicyUsernameLogin,
|
||||
passwordComplexityPolicy,
|
||||
labelPolicy,
|
||||
labelPolicyPrivateLabel,
|
||||
labelPolicyWatermark,
|
||||
customDomain bool,
|
||||
) (*iam.FeaturesSetEvent, bool) {
|
||||
|
||||
@@ -101,8 +102,11 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
if wm.PasswordComplexityPolicy != passwordComplexityPolicy {
|
||||
changes = append(changes, features.ChangePasswordComplexityPolicy(passwordComplexityPolicy))
|
||||
}
|
||||
if wm.LabelPolicy != labelPolicy {
|
||||
changes = append(changes, features.ChangeLabelPolicy(labelPolicy))
|
||||
if wm.LabelPolicyPrivateLabel != labelPolicyPrivateLabel {
|
||||
changes = append(changes, features.ChangeLabelPolicyPrivateLabel(labelPolicyPrivateLabel))
|
||||
}
|
||||
if wm.LabelPolicyWatermark != labelPolicyWatermark {
|
||||
changes = append(changes, features.ChangeLabelPolicyWatermark(labelPolicyWatermark))
|
||||
}
|
||||
if wm.CustomDomain != customDomain {
|
||||
changes = append(changes, features.ChangeCustomDomain(customDomain))
|
||||
|
@@ -29,8 +29,8 @@ func (c *Commands) AddDefaultLabelPolicy(ctx context.Context, policy *domain.Lab
|
||||
}
|
||||
|
||||
func (c *Commands) addDefaultLabelPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMLabelPolicyWriteModel, policy *domain.LabelPolicy) (eventstore.EventPusher, error) {
|
||||
if !policy.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-3m9fo", "Errors.IAM.LabelPolicy.Invalid")
|
||||
if err := policy.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
|
||||
if err != nil {
|
||||
@@ -40,13 +40,26 @@ func (c *Commands) addDefaultLabelPolicy(ctx context.Context, iamAgg *eventstore
|
||||
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LabelPolicy.AlreadyExists")
|
||||
}
|
||||
|
||||
return iam_repo.NewLabelPolicyAddedEvent(ctx, iamAgg, policy.PrimaryColor, policy.SecondaryColor, policy.HideLoginNameSuffix), nil
|
||||
return iam_repo.NewLabelPolicyAddedEvent(
|
||||
ctx,
|
||||
iamAgg,
|
||||
policy.PrimaryColor,
|
||||
policy.BackgroundColor,
|
||||
policy.WarnColor,
|
||||
policy.FontColor,
|
||||
policy.PrimaryColorDark,
|
||||
policy.BackgroundColorDark,
|
||||
policy.WarnColorDark,
|
||||
policy.FontColorDark,
|
||||
policy.HideLoginNameSuffix,
|
||||
policy.ErrorMsgPopup,
|
||||
policy.DisableWatermark), nil
|
||||
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
|
||||
if !policy.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-33m8f", "Errors.IAM.LabelPolicy.Invalid")
|
||||
if err := policy.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
@@ -57,7 +70,20 @@ func (c *Commands) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-0K9dq", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.PrimaryColor, policy.SecondaryColor, policy.HideLoginNameSuffix)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(
|
||||
ctx,
|
||||
iamAgg,
|
||||
policy.PrimaryColor,
|
||||
policy.BackgroundColor,
|
||||
policy.WarnColor,
|
||||
policy.FontColor,
|
||||
policy.PrimaryColorDark,
|
||||
policy.BackgroundColorDark,
|
||||
policy.WarnColorDark,
|
||||
policy.FontColorDark,
|
||||
policy.HideLoginNameSuffix,
|
||||
policy.ErrorMsgPopup,
|
||||
policy.DisableWatermark)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
|
||||
}
|
||||
@@ -73,6 +99,275 @@ func (c *Commands) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.
|
||||
return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ActivateDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) {
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-6M23e", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyActivatedEvent(ctx, iamAgg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddLogoDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-3m20c", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-Qw0pd", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyLogoAddedEvent(ctx, iamAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveLogoDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) {
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-Xc8Kf", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
|
||||
err = c.RemoveAsset(ctx, domain.IAMID, existingPolicy.LogoKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyLogoRemovedEvent(ctx, iamAgg, existingPolicy.LogoKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddIconDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-yxE4f", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-1yMx0", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyIconAddedEvent(ctx, iamAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveIconDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) {
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-4M0qw", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, domain.IAMID, existingPolicy.IconKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyIconRemovedEvent(ctx, iamAgg, existingPolicy.IconKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddLogoDarkDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-4fMs9", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-ZR9fs", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyLogoDarkAddedEvent(ctx, iamAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveLogoDarkDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) {
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-3FGds", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, domain.IAMID, existingPolicy.LogoDarkKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyLogoDarkRemovedEvent(ctx, iamAgg, existingPolicy.LogoDarkKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddIconDarkDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-1cxM3", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-vMsf9", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyIconDarkAddedEvent(ctx, iamAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveIconDarkDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) {
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-2nc7F", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, domain.IAMID, existingPolicy.IconDarkKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyIconDarkRemovedEvent(ctx, iamAgg, existingPolicy.IconDarkKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddFontDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-1N8fs", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-1N8fE", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyFontAddedEvent(ctx, iamAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveFontDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) {
|
||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "IAM-Tk0gw", "Errors.IAM.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, domain.IAMID, existingPolicy.FontKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewLabelPolicyFontRemovedEvent(ctx, iamAgg, existingPolicy.FontKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) defaultLabelPolicyWriteModelByID(ctx context.Context) (policy *IAMLabelPolicyWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -84,3 +379,13 @@ func (c *Commands) defaultLabelPolicyWriteModelByID(ctx context.Context) (policy
|
||||
}
|
||||
return writeModel, nil
|
||||
}
|
||||
|
||||
func (c *Commands) getDefaultLabelPolicy(ctx context.Context) (*domain.LabelPolicy, error) {
|
||||
policyWriteModel, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy := writeModelToLabelPolicy(&policyWriteModel.LabelPolicyWriteModel)
|
||||
policy.Default = true
|
||||
return policy, nil
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
"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"
|
||||
)
|
||||
@@ -31,6 +31,28 @@ func (wm *IAMLabelPolicyWriteModel) AppendEvents(events ...eventstore.EventReade
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyAddedEvent)
|
||||
case *iam.LabelPolicyChangedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyChangedEvent)
|
||||
case *iam.LabelPolicyActivatedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyActivatedEvent)
|
||||
case *iam.LabelPolicyLogoAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoAddedEvent)
|
||||
case *iam.LabelPolicyLogoRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoRemovedEvent)
|
||||
case *iam.LabelPolicyLogoDarkAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoDarkAddedEvent)
|
||||
case *iam.LabelPolicyLogoDarkRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoDarkRemovedEvent)
|
||||
case *iam.LabelPolicyIconAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconAddedEvent)
|
||||
case *iam.LabelPolicyIconRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconRemovedEvent)
|
||||
case *iam.LabelPolicyIconDarkAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconDarkAddedEvent)
|
||||
case *iam.LabelPolicyIconDarkRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconDarkRemovedEvent)
|
||||
case *iam.LabelPolicyFontAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyFontAddedEvent)
|
||||
case *iam.LabelPolicyFontRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyFontRemovedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,26 +67,69 @@ func (wm *IAMLabelPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
EventTypes(
|
||||
iam.LabelPolicyAddedEventType,
|
||||
iam.LabelPolicyChangedEventType)
|
||||
iam.LabelPolicyChangedEventType,
|
||||
iam.LabelPolicyLogoAddedEventType,
|
||||
iam.LabelPolicyLogoRemovedEventType,
|
||||
iam.LabelPolicyIconAddedEventType,
|
||||
iam.LabelPolicyIconRemovedEventType,
|
||||
iam.LabelPolicyLogoDarkAddedEventType,
|
||||
iam.LabelPolicyLogoDarkRemovedEventType,
|
||||
iam.LabelPolicyIconDarkAddedEventType,
|
||||
iam.LabelPolicyIconDarkRemovedEventType,
|
||||
iam.LabelPolicyFontAddedEventType,
|
||||
iam.LabelPolicyFontRemovedEventType,
|
||||
)
|
||||
}
|
||||
|
||||
func (wm *IAMLabelPolicyWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
primaryColor,
|
||||
secondaryColor string,
|
||||
hideLoginNameSuffix bool,
|
||||
backgroundColor,
|
||||
warnColor,
|
||||
fontColor,
|
||||
primaryColorDark,
|
||||
backgroundColorDark,
|
||||
warnColorDark,
|
||||
fontColorDark string,
|
||||
hideLoginNameSuffix,
|
||||
errorMsgPopup,
|
||||
disableWatermark bool,
|
||||
) (*iam.LabelPolicyChangedEvent, bool) {
|
||||
changes := make([]policy.LabelPolicyChanges, 0)
|
||||
if wm.PrimaryColor != primaryColor {
|
||||
changes = append(changes, policy.ChangePrimaryColor(primaryColor))
|
||||
}
|
||||
if wm.SecondaryColor != secondaryColor {
|
||||
changes = append(changes, policy.ChangeSecondaryColor(secondaryColor))
|
||||
if wm.BackgroundColor != backgroundColor {
|
||||
changes = append(changes, policy.ChangeBackgroundColor(backgroundColor))
|
||||
}
|
||||
if wm.WarnColor != warnColor {
|
||||
changes = append(changes, policy.ChangeWarnColor(warnColor))
|
||||
}
|
||||
if wm.FontColor != fontColor {
|
||||
changes = append(changes, policy.ChangeFontColor(fontColor))
|
||||
}
|
||||
if wm.PrimaryColorDark != primaryColorDark {
|
||||
changes = append(changes, policy.ChangePrimaryColorDark(primaryColorDark))
|
||||
}
|
||||
if wm.BackgroundColorDark != backgroundColorDark {
|
||||
changes = append(changes, policy.ChangeBackgroundColorDark(backgroundColorDark))
|
||||
}
|
||||
if wm.WarnColorDark != warnColorDark {
|
||||
changes = append(changes, policy.ChangeWarnColorDark(warnColorDark))
|
||||
}
|
||||
if wm.FontColorDark != fontColorDark {
|
||||
changes = append(changes, policy.ChangeFontColorDark(fontColorDark))
|
||||
}
|
||||
if wm.HideLoginNameSuffix != hideLoginNameSuffix {
|
||||
changes = append(changes, policy.ChangeHideLoginNameSuffix(hideLoginNameSuffix))
|
||||
}
|
||||
if wm.ErrorMsgPopup != errorMsgPopup {
|
||||
changes = append(changes, policy.ChangeErrorMsgPopup(errorMsgPopup))
|
||||
}
|
||||
if wm.DisableWatermark != disableWatermark {
|
||||
changes = append(changes, policy.ChangeDisableWatermark(disableWatermark))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,8 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
|
||||
features.LoginPolicyUsernameLogin,
|
||||
features.LoginPolicyPasswordReset,
|
||||
features.PasswordComplexityPolicy,
|
||||
features.LabelPolicy,
|
||||
features.LabelPolicyPrivateLabel,
|
||||
features.LabelPolicyWatermark,
|
||||
features.CustomDomain,
|
||||
)
|
||||
if !hasChanged {
|
||||
@@ -106,15 +107,12 @@ func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string
|
||||
events = append(events, removePasswordComplexityEvent)
|
||||
}
|
||||
}
|
||||
if !features.LabelPolicy {
|
||||
removeLabelPolicyEvent, err := c.removeLabelPolicyIfExists(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if removeLabelPolicyEvent != nil {
|
||||
events = append(events, removeLabelPolicyEvent)
|
||||
}
|
||||
labelPolicyEvents, err := c.setAllowedLabelPolicy(ctx, orgID, features)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, labelPolicyEvents...)
|
||||
|
||||
if !features.CustomDomain {
|
||||
removeCustomDomainsEvents, err := c.removeCustomDomains(ctx, orgID)
|
||||
if err != nil {
|
||||
@@ -233,3 +231,56 @@ func (c *Commands) setDefaultAuthFactorsInCustomLoginPolicy(ctx context.Context,
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) setAllowedLabelPolicy(ctx context.Context, orgID string, features *domain.Features) ([]eventstore.EventPusher, error) {
|
||||
events := make([]eventstore.EventPusher, 0)
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, nil
|
||||
}
|
||||
if !features.LabelPolicyPrivateLabel && !features.LabelPolicyWatermark {
|
||||
removeEvent, err := c.removeLabelPolicy(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(events, removeEvent), nil
|
||||
}
|
||||
defaultPolicy, err := c.getDefaultLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy := *existingPolicy
|
||||
if !features.LabelPolicyWatermark && defaultPolicy.DisableWatermark != existingPolicy.DisableWatermark {
|
||||
policy.DisableWatermark = defaultPolicy.DisableWatermark
|
||||
}
|
||||
if !features.LabelPolicyPrivateLabel {
|
||||
if defaultPolicy.HideLoginNameSuffix != existingPolicy.HideLoginNameSuffix {
|
||||
policy.HideLoginNameSuffix = defaultPolicy.HideLoginNameSuffix
|
||||
}
|
||||
policy.PrimaryColor = ""
|
||||
policy.BackgroundColor = ""
|
||||
policy.WarnColor = ""
|
||||
policy.FontColor = ""
|
||||
policy.PrimaryColorDark = ""
|
||||
policy.BackgroundColorDark = ""
|
||||
policy.WarnColorDark = ""
|
||||
policy.FontColorDark = ""
|
||||
|
||||
assetsEvent, err := c.removeLabelPolicyAssets(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, assetsEvent)
|
||||
}
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel),
|
||||
policy.PrimaryColor, policy.BackgroundColor, policy.WarnColor, policy.FontColor,
|
||||
policy.PrimaryColorDark, policy.BackgroundColorDark, policy.WarnColorDark, policy.FontColorDark,
|
||||
policy.HideLoginNameSuffix, policy.ErrorMsgPopup, policy.HideLoginNameSuffix)
|
||||
if hasChanged {
|
||||
events = append(events, changedEvent)
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
@@ -69,7 +69,8 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
loginPolicyUsernameLogin,
|
||||
loginPolicyPasswordReset,
|
||||
passwordComplexityPolicy,
|
||||
labelPolicy,
|
||||
labelPolicyPrivateLabel,
|
||||
labelPolicyWatermark,
|
||||
customDomain bool,
|
||||
) (*org.FeaturesSetEvent, bool) {
|
||||
|
||||
@@ -111,8 +112,11 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
if wm.PasswordComplexityPolicy != passwordComplexityPolicy {
|
||||
changes = append(changes, features.ChangePasswordComplexityPolicy(passwordComplexityPolicy))
|
||||
}
|
||||
if wm.LabelPolicy != labelPolicy {
|
||||
changes = append(changes, features.ChangeLabelPolicy(labelPolicy))
|
||||
if wm.LabelPolicyPrivateLabel != labelPolicyPrivateLabel {
|
||||
changes = append(changes, features.ChangeLabelPolicyPrivateLabel(labelPolicyPrivateLabel))
|
||||
}
|
||||
if wm.LabelPolicyWatermark != labelPolicyWatermark {
|
||||
changes = append(changes, features.ChangeLabelPolicyWatermark(labelPolicyWatermark))
|
||||
}
|
||||
if wm.CustomDomain != customDomain {
|
||||
changes = append(changes, features.ChangeCustomDomain(customDomain))
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
@@ -14,12 +15,15 @@ import (
|
||||
"github.com/caos/zitadel/internal/repository/features"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
"github.com/caos/zitadel/internal/static/mock"
|
||||
)
|
||||
|
||||
func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
iamDomain string
|
||||
static static.Storage
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -56,7 +60,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
},
|
||||
},
|
||||
@@ -90,7 +95,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
},
|
||||
},
|
||||
@@ -138,6 +144,14 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
@@ -196,7 +210,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
},
|
||||
},
|
||||
@@ -246,6 +261,14 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
@@ -332,7 +355,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
},
|
||||
},
|
||||
@@ -382,6 +406,14 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
@@ -478,7 +510,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
},
|
||||
},
|
||||
@@ -528,6 +561,14 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
@@ -634,7 +675,8 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
},
|
||||
},
|
||||
@@ -740,6 +782,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
//begin setDefaultAuthFactorsInCustomLoginPolicy
|
||||
//orgLabelPolicyWriteModelByID
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
@@ -748,6 +791,14 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
@@ -757,10 +808,22 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"custom",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
//removeLabelPolicy
|
||||
expectFilter(),
|
||||
//end setDefaultAuthFactorsInCustomLoginPolicy
|
||||
//removeCustomDomains
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(
|
||||
@@ -818,6 +881,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
iamDomain: "iam-domain",
|
||||
static: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectNoError(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -832,7 +896,9 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -847,6 +913,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
iamDomain: tt.fields.iamDomain,
|
||||
static: tt.fields.static,
|
||||
}
|
||||
got, err := r.SetOrgFeatures(tt.args.ctx, tt.args.resourceOwner, tt.args.features)
|
||||
if tt.res.err == nil {
|
||||
@@ -958,6 +1025,14 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
|
@@ -12,8 +12,8 @@ func (c *Commands) AddLabelPolicy(ctx context.Context, resourceOwner string, pol
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Fn8ds", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if !policy.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Md9sf", "Errors.Org.LabelPolicy.Invalid")
|
||||
if err := policy.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedPolicy := NewOrgLabelPolicyWriteModel(resourceOwner)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
|
||||
@@ -25,7 +25,20 @@ func (c *Commands) AddLabelPolicy(ctx context.Context, resourceOwner string, pol
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyAddedEvent(ctx, orgAgg, policy.PrimaryColor, policy.SecondaryColor, policy.HideLoginNameSuffix))
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyAddedEvent(
|
||||
ctx,
|
||||
orgAgg,
|
||||
policy.PrimaryColor,
|
||||
policy.BackgroundColor,
|
||||
policy.WarnColor,
|
||||
policy.FontColor,
|
||||
policy.PrimaryColorDark,
|
||||
policy.BackgroundColorDark,
|
||||
policy.WarnColorDark,
|
||||
policy.FontColorDark,
|
||||
policy.HideLoginNameSuffix,
|
||||
policy.ErrorMsgPopup,
|
||||
policy.DisableWatermark))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -40,8 +53,8 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string,
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-3N9fs", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if !policy.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-dM9fs", "Errors.Org.LabelPolicy.Invalid")
|
||||
if err := policy.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingPolicy := NewOrgLabelPolicyWriteModel(resourceOwner)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
@@ -53,7 +66,20 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string,
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.PrimaryColor, policy.SecondaryColor, policy.HideLoginNameSuffix)
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(
|
||||
ctx,
|
||||
orgAgg,
|
||||
policy.PrimaryColor,
|
||||
policy.BackgroundColor,
|
||||
policy.WarnColor,
|
||||
policy.FontColor,
|
||||
policy.PrimaryColorDark,
|
||||
policy.BackgroundColorDark,
|
||||
policy.WarnColorDark,
|
||||
policy.FontColorDark,
|
||||
policy.HideLoginNameSuffix,
|
||||
policy.ErrorMsgPopup,
|
||||
policy.DisableWatermark)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4M9vs", "Errors.Org.LabelPolicy.NotChanged")
|
||||
}
|
||||
@@ -69,6 +95,306 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string,
|
||||
return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ActivateLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-KKd4X", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-34mSE", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyActivatedEvent(ctx, orgAgg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddLogoLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-KKd4X", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-4N3nf", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-23BMs", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyLogoAddedEvent(ctx, orgAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveLogoLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-2FN8s", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-4MVsf", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.LogoKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyLogoRemovedEvent(ctx, orgAgg, existingPolicy.LogoKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddIconLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-hMDs3", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-4BS7f", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-4nq2f", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyIconAddedEvent(ctx, orgAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveIconLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-1nd0d", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-1nd9f", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
|
||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.IconKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyIconRemovedEvent(ctx, orgAgg, existingPolicy.IconKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddLogoDarkLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-67Ms2", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-3S7fN", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-QSqcd", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyLogoDarkAddedEvent(ctx, orgAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveLogoDarkLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-4NF0d", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-0peQw", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.LogoDarkKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyLogoDarkRemovedEvent(ctx, orgAgg, existingPolicy.LogoDarkKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddIconDarkLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-tzBfs", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-4B7cs", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-4Nf8s", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyIconDarkAddedEvent(ctx, orgAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveIconDarkLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Mv9ds", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-3NFos", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.IconDarkKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyIconDarkRemovedEvent(ctx, orgAgg, existingPolicy.IconDarkKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddFontLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-1Nf9s", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-2f9fw", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-2M9fs", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyFontAddedEvent(ctx, orgAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveFontLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-2n0fW", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-4n9SD", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.FontKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyFontRemovedEvent(ctx, orgAgg, existingPolicy.FontKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingPolicy, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Mf9sf", "Errors.ResourceOwnerMissing")
|
||||
@@ -97,6 +423,10 @@ func (c *Commands) removeLabelPolicy(ctx context.Context, existingPolicy *OrgLab
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
return org.NewLabelPolicyRemovedEvent(ctx, orgAgg), nil
|
||||
}
|
||||
@@ -109,10 +439,23 @@ func (c *Commands) removeLabelPolicyIfExists(ctx context.Context, orgID string)
|
||||
if existingPolicy.State != domain.PolicyStateActive {
|
||||
return nil, nil
|
||||
}
|
||||
err = c.RemoveAsset(ctx, orgID, domain.LabelPolicyPrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
return org.NewLabelPolicyRemovedEvent(ctx, orgAgg), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeLabelPolicyAssets(ctx context.Context, existingPolicy *OrgLabelPolicyWriteModel) (*org.LabelPolicyAssetsRemovedEvent, error) {
|
||||
err := c.RemoveAsset(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
return org.NewLabelPolicyAssetsRemovedEvent(ctx, orgAgg), nil
|
||||
}
|
||||
|
||||
func (c *Commands) orgLabelPolicyWriteModelByID(ctx context.Context, orgID string) (*OrgLabelPolicyWriteModel, error) {
|
||||
policy := NewOrgLabelPolicyWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, policy)
|
||||
|
@@ -30,6 +30,26 @@ func (wm *OrgLabelPolicyWriteModel) AppendEvents(events ...eventstore.EventReade
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyAddedEvent)
|
||||
case *org.LabelPolicyChangedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyChangedEvent)
|
||||
case *org.LabelPolicyLogoAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoAddedEvent)
|
||||
case *org.LabelPolicyLogoRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoRemovedEvent)
|
||||
case *org.LabelPolicyLogoDarkAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoDarkAddedEvent)
|
||||
case *org.LabelPolicyLogoDarkRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyLogoDarkRemovedEvent)
|
||||
case *org.LabelPolicyIconAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconAddedEvent)
|
||||
case *org.LabelPolicyIconRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconRemovedEvent)
|
||||
case *org.LabelPolicyIconDarkAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconDarkAddedEvent)
|
||||
case *org.LabelPolicyIconDarkRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyIconDarkRemovedEvent)
|
||||
case *org.LabelPolicyFontAddedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyFontAddedEvent)
|
||||
case *org.LabelPolicyFontRemovedEvent:
|
||||
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyFontRemovedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,26 +64,69 @@ func (wm *OrgLabelPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
EventTypes(
|
||||
org.LabelPolicyAddedEventType,
|
||||
org.LabelPolicyChangedEventType)
|
||||
org.LabelPolicyChangedEventType,
|
||||
org.LabelPolicyLogoAddedEventType,
|
||||
org.LabelPolicyLogoRemovedEventType,
|
||||
org.LabelPolicyIconAddedEventType,
|
||||
org.LabelPolicyIconRemovedEventType,
|
||||
org.LabelPolicyLogoDarkAddedEventType,
|
||||
org.LabelPolicyLogoDarkRemovedEventType,
|
||||
org.LabelPolicyIconDarkAddedEventType,
|
||||
org.LabelPolicyIconDarkRemovedEventType,
|
||||
org.LabelPolicyFontAddedEventType,
|
||||
org.LabelPolicyFontRemovedEventType,
|
||||
)
|
||||
}
|
||||
|
||||
func (wm *OrgLabelPolicyWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
primaryColor,
|
||||
secondaryColor string,
|
||||
hideLoginNameSuffix bool,
|
||||
backgroundColor,
|
||||
warnColor,
|
||||
fontColor,
|
||||
primaryColorDark,
|
||||
backgroundColorDark,
|
||||
warnColorDark,
|
||||
fontColorDark string,
|
||||
hideLoginNameSuffix,
|
||||
errorMsgPopup,
|
||||
disableWatermark bool,
|
||||
) (*org.LabelPolicyChangedEvent, bool) {
|
||||
changes := make([]policy.LabelPolicyChanges, 0)
|
||||
if wm.PrimaryColor != primaryColor {
|
||||
changes = append(changes, policy.ChangePrimaryColor(primaryColor))
|
||||
}
|
||||
if wm.SecondaryColor != secondaryColor {
|
||||
changes = append(changes, policy.ChangeSecondaryColor(secondaryColor))
|
||||
if wm.BackgroundColor != backgroundColor {
|
||||
changes = append(changes, policy.ChangeBackgroundColor(backgroundColor))
|
||||
}
|
||||
if wm.WarnColor != warnColor {
|
||||
changes = append(changes, policy.ChangeWarnColor(warnColor))
|
||||
}
|
||||
if wm.FontColor != fontColor {
|
||||
changes = append(changes, policy.ChangeFontColor(fontColor))
|
||||
}
|
||||
if wm.PrimaryColorDark != primaryColorDark {
|
||||
changes = append(changes, policy.ChangePrimaryColorDark(primaryColorDark))
|
||||
}
|
||||
if wm.BackgroundColorDark != backgroundColorDark {
|
||||
changes = append(changes, policy.ChangeBackgroundColorDark(backgroundColorDark))
|
||||
}
|
||||
if wm.WarnColorDark != warnColorDark {
|
||||
changes = append(changes, policy.ChangeWarnColorDark(warnColorDark))
|
||||
}
|
||||
if wm.FontColorDark != fontColorDark {
|
||||
changes = append(changes, policy.ChangeFontColorDark(fontColorDark))
|
||||
}
|
||||
if wm.HideLoginNameSuffix != hideLoginNameSuffix {
|
||||
changes = append(changes, policy.ChangeHideLoginNameSuffix(hideLoginNameSuffix))
|
||||
}
|
||||
if wm.ErrorMsgPopup != errorMsgPopup {
|
||||
changes = append(changes, policy.ChangeErrorMsgPopup(errorMsgPopup))
|
||||
}
|
||||
if wm.DisableWatermark != disableWatermark {
|
||||
changes = append(changes, policy.ChangeDisableWatermark(disableWatermark))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,25 @@ import (
|
||||
type LabelPolicyWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
PrimaryColor string
|
||||
SecondaryColor string
|
||||
PrimaryColor string
|
||||
BackgroundColor string
|
||||
WarnColor string
|
||||
FontColor string
|
||||
LogoKey string
|
||||
IconKey string
|
||||
|
||||
PrimaryColorDark string
|
||||
BackgroundColorDark string
|
||||
WarnColorDark string
|
||||
FontColorDark string
|
||||
LogoDarkKey string
|
||||
IconDarkKey string
|
||||
|
||||
FontKey string
|
||||
|
||||
HideLoginNameSuffix bool
|
||||
ErrorMsgPopup bool
|
||||
DisableWatermark bool
|
||||
|
||||
State domain.PolicyState
|
||||
}
|
||||
@@ -21,19 +37,71 @@ func (wm *LabelPolicyWriteModel) Reduce() error {
|
||||
switch e := event.(type) {
|
||||
case *policy.LabelPolicyAddedEvent:
|
||||
wm.PrimaryColor = e.PrimaryColor
|
||||
wm.SecondaryColor = e.SecondaryColor
|
||||
wm.BackgroundColor = e.BackgroundColor
|
||||
wm.WarnColor = e.WarnColor
|
||||
wm.FontColor = e.FontColor
|
||||
wm.PrimaryColorDark = e.PrimaryColorDark
|
||||
wm.BackgroundColorDark = e.BackgroundColorDark
|
||||
wm.WarnColorDark = e.WarnColorDark
|
||||
wm.FontColorDark = e.FontColorDark
|
||||
wm.HideLoginNameSuffix = e.HideLoginNameSuffix
|
||||
wm.ErrorMsgPopup = e.ErrorMsgPopup
|
||||
wm.DisableWatermark = e.DisableWatermark
|
||||
wm.State = domain.PolicyStateActive
|
||||
case *policy.LabelPolicyChangedEvent:
|
||||
if e.PrimaryColor != nil {
|
||||
wm.PrimaryColor = *e.PrimaryColor
|
||||
}
|
||||
if e.SecondaryColor != nil {
|
||||
wm.SecondaryColor = *e.SecondaryColor
|
||||
if e.BackgroundColor != nil {
|
||||
wm.BackgroundColor = *e.BackgroundColor
|
||||
}
|
||||
if e.WarnColor != nil {
|
||||
wm.WarnColor = *e.WarnColor
|
||||
}
|
||||
if e.FontColor != nil {
|
||||
wm.FontColor = *e.FontColor
|
||||
}
|
||||
if e.PrimaryColorDark != nil {
|
||||
wm.PrimaryColorDark = *e.PrimaryColorDark
|
||||
}
|
||||
if e.BackgroundColorDark != nil {
|
||||
wm.BackgroundColorDark = *e.BackgroundColorDark
|
||||
}
|
||||
if e.WarnColorDark != nil {
|
||||
wm.WarnColorDark = *e.WarnColorDark
|
||||
}
|
||||
if e.FontColorDark != nil {
|
||||
wm.FontColorDark = *e.FontColorDark
|
||||
}
|
||||
if e.HideLoginNameSuffix != nil {
|
||||
wm.HideLoginNameSuffix = *e.HideLoginNameSuffix
|
||||
}
|
||||
if e.ErrorMsgPopup != nil {
|
||||
wm.ErrorMsgPopup = *e.ErrorMsgPopup
|
||||
}
|
||||
if e.DisableWatermark != nil {
|
||||
wm.DisableWatermark = *e.DisableWatermark
|
||||
}
|
||||
case *policy.LabelPolicyLogoAddedEvent:
|
||||
wm.LogoKey = e.StoreKey
|
||||
case *policy.LabelPolicyLogoRemovedEvent:
|
||||
wm.LogoKey = ""
|
||||
case *policy.LabelPolicyLogoDarkAddedEvent:
|
||||
wm.LogoDarkKey = e.StoreKey
|
||||
case *policy.LabelPolicyLogoDarkRemovedEvent:
|
||||
wm.LogoDarkKey = ""
|
||||
case *policy.LabelPolicyIconAddedEvent:
|
||||
wm.IconKey = e.StoreKey
|
||||
case *policy.LabelPolicyIconRemovedEvent:
|
||||
wm.IconKey = ""
|
||||
case *policy.LabelPolicyIconDarkAddedEvent:
|
||||
wm.IconDarkKey = e.StoreKey
|
||||
case *policy.LabelPolicyIconDarkRemovedEvent:
|
||||
wm.IconDarkKey = ""
|
||||
case *policy.LabelPolicyFontAddedEvent:
|
||||
wm.FontKey = e.StoreKey
|
||||
case *policy.LabelPolicyFontRemovedEvent:
|
||||
wm.FontKey = ""
|
||||
case *policy.LabelPolicyRemovedEvent:
|
||||
wm.State = domain.PolicyStateRemoved
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ func (c *Commands) SetupStep12(ctx context.Context, step *Step12) error {
|
||||
LoginPolicyRegistration: step.LoginPolicyRegistration,
|
||||
LoginPolicyUsernameLogin: step.LoginPolicyUsernameLogin,
|
||||
PasswordComplexityPolicy: step.PasswordComplexityPolicy,
|
||||
LabelPolicy: step.LabelPolicy,
|
||||
LabelPolicyPrivateLabel: step.LabelPolicy,
|
||||
CustomDomain: step.CustomDomain,
|
||||
})
|
||||
if err != nil {
|
||||
|
48
internal/command/setup_step14.go
Normal file
48
internal/command/setup_step14.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
iam_repo "github.com/caos/zitadel/internal/repository/iam"
|
||||
org_repo "github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
type Step14 struct {
|
||||
ActivateExistingLabelPolicies bool
|
||||
}
|
||||
|
||||
func (s *Step14) Step() domain.Step {
|
||||
return domain.Step14
|
||||
}
|
||||
|
||||
func (s *Step14) execute(ctx context.Context, commandSide *Commands) error {
|
||||
return commandSide.SetupStep14(ctx, s)
|
||||
}
|
||||
|
||||
func (c *Commands) SetupStep14(ctx context.Context, step *Step14) error {
|
||||
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
|
||||
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
|
||||
var events []eventstore.EventPusher
|
||||
if step.ActivateExistingLabelPolicies {
|
||||
existingPolicies := NewExistingLabelPoliciesReadModel(ctx)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicies)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, aggID := range existingPolicies.aggregateIDs {
|
||||
if iamAgg.ID == aggID {
|
||||
events = append(events, iam_repo.NewLabelPolicyActivatedEvent(ctx, iamAgg))
|
||||
continue
|
||||
}
|
||||
events = append(events, org_repo.NewLabelPolicyActivatedEvent(ctx, &org_repo.NewAggregate(aggID, aggID).Aggregate))
|
||||
}
|
||||
}
|
||||
logging.Log("SETUP-M9fsd").Info("activate login policies")
|
||||
return events, nil
|
||||
}
|
||||
return c.setup(ctx, step, fn)
|
||||
}
|
32
internal/command/setup_step15.go
Normal file
32
internal/command/setup_step15.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
type Step15 struct {
|
||||
DefaultMailTemplate domain.MailTemplate
|
||||
}
|
||||
|
||||
func (s *Step15) Step() domain.Step {
|
||||
return domain.Step15
|
||||
}
|
||||
|
||||
func (s *Step15) execute(ctx context.Context, commandSide *Commands) error {
|
||||
return commandSide.SetupStep15(ctx, s)
|
||||
}
|
||||
|
||||
func (c *Commands) SetupStep15(ctx context.Context, step *Step15) error {
|
||||
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
|
||||
_, mailTemplateEvent, err := c.changeDefaultMailTemplate(ctx, &step.DefaultMailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logging.Log("SETUP-2nfsd").Info("default mail template/text set up")
|
||||
return []eventstore.EventPusher{mailTemplateEvent}, nil
|
||||
}
|
||||
return c.setup(ctx, step, fn)
|
||||
}
|
@@ -2,15 +2,16 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
type Step2 struct {
|
||||
DefaultPasswordComplexityPolicy iam_model.PasswordComplexityPolicy
|
||||
DefaultPasswordComplexityPolicy domain.PasswordComplexityPolicy
|
||||
}
|
||||
|
||||
func (s *Step2) Step() domain.Step {
|
||||
|
@@ -2,15 +2,16 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
type Step3 struct {
|
||||
DefaultPasswordAgePolicy iam_model.PasswordAgePolicy
|
||||
DefaultPasswordAgePolicy domain.PasswordAgePolicy
|
||||
}
|
||||
|
||||
func (s *Step3) Step() domain.Step {
|
||||
|
@@ -2,15 +2,16 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
type Step4 struct {
|
||||
DefaultPasswordLockoutPolicy iam_model.PasswordLockoutPolicy
|
||||
DefaultPasswordLockoutPolicy domain.PasswordLockoutPolicy
|
||||
}
|
||||
|
||||
func (s *Step4) Step() domain.Step {
|
||||
|
@@ -2,15 +2,16 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
type Step5 struct {
|
||||
DefaultOrgIAMPolicy iam_model.OrgIAMPolicy
|
||||
DefaultOrgIAMPolicy domain.OrgIAMPolicy
|
||||
}
|
||||
|
||||
func (s *Step5) Step() domain.Step {
|
||||
|
@@ -2,15 +2,16 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
type Step6 struct {
|
||||
DefaultLabelPolicy iam_model.LabelPolicy
|
||||
DefaultLabelPolicy domain.LabelPolicy
|
||||
}
|
||||
|
||||
func (s *Step6) Step() domain.Step {
|
||||
@@ -24,10 +25,7 @@ func (s *Step6) execute(ctx context.Context, commandSide *Commands) error {
|
||||
func (c *Commands) SetupStep6(ctx context.Context, step *Step6) error {
|
||||
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
|
||||
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
|
||||
event, err := c.addDefaultLabelPolicy(ctx, iamAgg, NewIAMLabelPolicyWriteModel(), &domain.LabelPolicy{
|
||||
PrimaryColor: step.DefaultLabelPolicy.PrimaryColor,
|
||||
SecondaryColor: step.DefaultLabelPolicy.SecondaryColor,
|
||||
})
|
||||
event, err := c.addDefaultLabelPolicy(ctx, iamAgg, NewIAMLabelPolicyWriteModel(), &step.DefaultLabelPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
27
internal/command/statics.go
Normal file
27
internal/command/statics.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
func (c *Commands) UploadAsset(ctx context.Context, bucketName, objectName, contentType string, file io.Reader, size int64) (*domain.AssetInfo, error) {
|
||||
if c.static == nil {
|
||||
return nil, caos_errors.ThrowPreconditionFailed(nil, "STATIC-Fm92f", "Errors.Assets.Store.NotConfigured")
|
||||
}
|
||||
return c.static.PutObject(ctx,
|
||||
bucketName,
|
||||
objectName,
|
||||
contentType,
|
||||
file,
|
||||
size,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveAsset(ctx context.Context, bucketName, storeKey string) error {
|
||||
return c.static.RemoveObject(ctx, bucketName, storeKey)
|
||||
}
|
@@ -23,7 +23,7 @@ func (c *Commands) getHuman(ctx context.Context, userID, resourceowner string) (
|
||||
|
||||
func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Human) (*domain.Human, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M90d", "Errors.ResourceOwnerMissing")
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-XYFk9", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
orgIAMPolicy, err := c.getOrgIAMPolicy(ctx, orgID)
|
||||
if err != nil {
|
||||
@@ -81,7 +81,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
||||
|
||||
func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Human, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
|
||||
if orgID == "" || !human.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M90d", "Errors.User.Invalid")
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-67Ms8", "Errors.User.Invalid")
|
||||
}
|
||||
if human.Password != nil && human.SecretString != "" {
|
||||
human.ChangeRequired = true
|
||||
@@ -91,7 +91,7 @@ func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Hum
|
||||
|
||||
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
|
||||
if orgID == "" || !human.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M90d", "Errors.User.Invalid")
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.User.Invalid")
|
||||
}
|
||||
return c.createHuman(ctx, orgID, human, nil, false, orgIAMPolicy, pwPolicy)
|
||||
}
|
||||
|
63
internal/command/user_human_avatar.go
Normal file
63
internal/command/user_human_avatar.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
)
|
||||
|
||||
func (c *Commands) AddHumanAvatar(ctx context.Context, orgID, userID, storageKey string) (*domain.ObjectDetails, error) {
|
||||
if userID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "USER-Ba5Ds", "Errors.IDMissing")
|
||||
}
|
||||
if storageKey == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "USER-1Xyud", "Errors.Assets.EmptyKey")
|
||||
}
|
||||
existingUser, err := c.userWriteModelByID(ctx, userID, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "USER-vJ3fS", "Errors.Users.NotFound")
|
||||
}
|
||||
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, user.NewHumanAvatarAddedEvent(ctx, userAgg, storageKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingUser, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingUser.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveHumanAvatar(ctx context.Context, orgID, userID string) (*domain.ObjectDetails, error) {
|
||||
if userID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "USER-1B8sd", "Errors.IDMissing")
|
||||
}
|
||||
existingUser, err := c.getHumanWriteModelByID(ctx, userID, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "USER-35N8f", "Errors.Users.NotFound")
|
||||
}
|
||||
err = c.RemoveAsset(ctx, orgID, existingUser.Avatar)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, user.NewHumanAvatarRemovedEvent(ctx, userAgg, existingUser.Avatar))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingUser, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingUser.WriteModel), nil
|
||||
}
|
319
internal/command/user_human_avatar_test.go
Normal file
319
internal/command/user_human_avatar_test.go
Normal file
@@ -0,0 +1,319 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
"github.com/caos/zitadel/internal/static/mock"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddHumanAvatar(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
orgID string
|
||||
userID string
|
||||
storageKey string
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "userID empty, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
storageKey: "key",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "storage key empty, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
userID: "user1",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
userID: "user1",
|
||||
storageKey: "key",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "logo added, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Und,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAvatarAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"key",
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
userID: "user1",
|
||||
storageKey: "key",
|
||||
},
|
||||
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.AddHumanAvatar(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.storageKey)
|
||||
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_RemoveHumanAvatar(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
storage static.Storage
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
orgID string
|
||||
userID string
|
||||
storageKey string
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "userID empty, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
storageKey: "key",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
userID: "user1",
|
||||
storageKey: "key",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "file remove error, not found error",
|
||||
fields: fields{
|
||||
storage: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectError(),
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Und,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAvatarAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"key",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
userID: "user1",
|
||||
storageKey: "key",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsInternal,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "logo removed, ok",
|
||||
fields: fields{
|
||||
storage: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectNoError(),
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Und,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAvatarAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"key",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAvatarRemovedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"key",
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "org1",
|
||||
userID: "user1",
|
||||
storageKey: "key",
|
||||
},
|
||||
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,
|
||||
static: tt.fields.storage,
|
||||
}
|
||||
got, err := r.RemoveHumanAvatar(tt.args.ctx, tt.args.orgID, tt.args.userID)
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,11 +1,12 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type HumanWriteModel struct {
|
||||
@@ -19,6 +20,7 @@ type HumanWriteModel struct {
|
||||
DisplayName string
|
||||
PreferredLanguage language.Tag
|
||||
Gender domain.Gender
|
||||
Avatar string
|
||||
|
||||
Email string
|
||||
IsEmailVerified bool
|
||||
@@ -74,6 +76,10 @@ func (wm *HumanWriteModel) Reduce() error {
|
||||
wm.reduceHumanPhoneRemovedEvent()
|
||||
case *user.HumanPasswordChangedEvent:
|
||||
wm.reduceHumanPasswordChangedEvent(e)
|
||||
case *user.HumanAvatarAddedEvent:
|
||||
wm.Avatar = e.StoreKey
|
||||
case *user.HumanAvatarRemovedEvent:
|
||||
wm.Avatar = ""
|
||||
case *user.UserLockedEvent:
|
||||
if wm.UserState != domain.UserStateDeleted {
|
||||
wm.UserState = domain.UserStateLocked
|
||||
@@ -112,6 +118,8 @@ func (wm *HumanWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
user.HumanPhoneChangedType,
|
||||
user.HumanPhoneVerifiedType,
|
||||
user.HumanPhoneRemovedType,
|
||||
user.HumanAvatarAddedType,
|
||||
user.HumanAvatarRemovedType,
|
||||
user.HumanPasswordChangedType,
|
||||
user.UserLockedType,
|
||||
user.UserUnlockedType,
|
||||
|
@@ -828,70 +828,70 @@ func TestCommandSide_RemoveHumanPhone(t *testing.T) {
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "userid missing, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "user1",
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "phone not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "user1",
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
//{
|
||||
// name: "userid missing, invalid argument error",
|
||||
// fields: fields{
|
||||
// eventstore: eventstoreExpect(
|
||||
// t,
|
||||
// ),
|
||||
// },
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// resourceOwner: "org1",
|
||||
// },
|
||||
// res: res{
|
||||
// err: caos_errs.IsErrorInvalidArgument,
|
||||
// },
|
||||
//},
|
||||
//{
|
||||
// name: "user not existing, precondition error",
|
||||
// fields: fields{
|
||||
// eventstore: eventstoreExpect(
|
||||
// t,
|
||||
// expectFilter(),
|
||||
// ),
|
||||
// },
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// userID: "user1",
|
||||
// resourceOwner: "org1",
|
||||
// },
|
||||
// res: res{
|
||||
// err: caos_errs.IsPreconditionFailed,
|
||||
// },
|
||||
//},
|
||||
//{
|
||||
// name: "phone not existing, precondition error",
|
||||
// fields: fields{
|
||||
// eventstore: eventstoreExpect(
|
||||
// t,
|
||||
// expectFilter(
|
||||
// eventFromEventPusher(
|
||||
// user.NewHumanAddedEvent(context.Background(),
|
||||
// &user.NewAggregate("user1", "org1").Aggregate,
|
||||
// "username",
|
||||
// "firstname",
|
||||
// "lastname",
|
||||
// "nickname",
|
||||
// "displayname",
|
||||
// language.German,
|
||||
// domain.GenderUnspecified,
|
||||
// "email@test.ch",
|
||||
// true,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// },
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// userID: "user1",
|
||||
// resourceOwner: "org1",
|
||||
// },
|
||||
// res: res{
|
||||
// err: caos_errs.IsNotFound,
|
||||
// },
|
||||
//},
|
||||
{
|
||||
name: "remove phone, ok",
|
||||
fields: fields{
|
||||
|
@@ -2,6 +2,25 @@ package domain
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
UsersAssetPath = "users"
|
||||
AvatarAssetPath = "/avatar"
|
||||
|
||||
policyPrefix = "policy"
|
||||
LabelPolicyPrefix = policyPrefix + "/label"
|
||||
labelPolicyLogoPrefix = LabelPolicyPrefix + "/logo"
|
||||
labelPolicyIconPrefix = LabelPolicyPrefix + "/icon"
|
||||
labelPolicyFontPrefix = LabelPolicyPrefix + "/font"
|
||||
Dark = "dark"
|
||||
|
||||
CssPath = LabelPolicyPrefix + "/css"
|
||||
CssVariablesFileName = "variables.css"
|
||||
|
||||
LabelPolicyLogoPath = labelPolicyLogoPrefix
|
||||
LabelPolicyIconPath = labelPolicyIconPrefix
|
||||
LabelPolicyFontPath = labelPolicyFontPrefix
|
||||
)
|
||||
|
||||
type AssetInfo struct {
|
||||
Bucket string
|
||||
Key string
|
||||
@@ -12,4 +31,9 @@ type AssetInfo struct {
|
||||
VersionID string
|
||||
Expiration time.Time
|
||||
AutheticatedURL string
|
||||
ContentType string
|
||||
}
|
||||
|
||||
func GetHumanAvatarAssetPath(userID string) string {
|
||||
return UsersAssetPath + "/" + userID + AvatarAssetPath
|
||||
}
|
||||
|
@@ -30,6 +30,8 @@ type AuthRequest struct {
|
||||
UserName string
|
||||
LoginName string
|
||||
DisplayName string
|
||||
AvatarKey string
|
||||
PresignedAvatar string
|
||||
UserOrgID string
|
||||
RequestedOrgID string
|
||||
RequestedOrgName string
|
||||
@@ -108,11 +110,12 @@ func (a *AuthRequest) WithCurrentInfo(info *BrowserInfo) *AuthRequest {
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AuthRequest) SetUserInfo(userID, userName, loginName, displayName, userOrgID string) {
|
||||
func (a *AuthRequest) SetUserInfo(userID, userName, loginName, displayName, avatar, userOrgID string) {
|
||||
a.UserID = userID
|
||||
a.UserName = userName
|
||||
a.LoginName = loginName
|
||||
a.DisplayName = displayName
|
||||
a.AvatarKey = avatar
|
||||
a.UserOrgID = userOrgID
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,8 @@ const (
|
||||
FeatureLoginPolicyPasswordReset = FeatureLoginPolicy + ".password_reset"
|
||||
FeaturePasswordComplexityPolicy = "password_complexity_policy"
|
||||
FeatureLabelPolicy = "label_policy"
|
||||
FeatureLabelPolicyPrivateLabel = FeatureLabelPolicy + ".private_label"
|
||||
FeatureLabelPolicyWatermark = FeatureLabelPolicy + ".watermark"
|
||||
FeatureCustomDomain = "custom_domain"
|
||||
)
|
||||
|
||||
@@ -36,7 +38,8 @@ type Features struct {
|
||||
LoginPolicyUsernameLogin bool
|
||||
LoginPolicyPasswordReset bool
|
||||
PasswordComplexityPolicy bool
|
||||
LabelPolicy bool
|
||||
LabelPolicyPrivateLabel bool
|
||||
LabelPolicyWatermark bool
|
||||
CustomDomain bool
|
||||
}
|
||||
|
||||
|
@@ -47,6 +47,7 @@ type UserSelection struct {
|
||||
LoginName string
|
||||
UserSessionState UserSessionState
|
||||
SelectionPossible bool
|
||||
AvatarKey string
|
||||
}
|
||||
|
||||
type UserSessionState int32
|
||||
|
@@ -1,18 +1,84 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
|
||||
var colorRegex = regexp.MustCompile("^$|^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")
|
||||
|
||||
type LabelPolicy struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Default bool
|
||||
PrimaryColor string
|
||||
SecondaryColor string
|
||||
State LabelPolicyState
|
||||
Default bool
|
||||
|
||||
PrimaryColor string
|
||||
BackgroundColor string
|
||||
WarnColor string
|
||||
FontColor string
|
||||
LogoURL string
|
||||
IconURL string
|
||||
|
||||
PrimaryColorDark string
|
||||
BackgroundColorDark string
|
||||
WarnColorDark string
|
||||
FontColorDark string
|
||||
LogoDarkURL string
|
||||
IconDarkURL string
|
||||
|
||||
Font string
|
||||
|
||||
HideLoginNameSuffix bool
|
||||
ErrorMsgPopup bool
|
||||
DisableWatermark bool
|
||||
}
|
||||
|
||||
func (p *LabelPolicy) IsValid() bool {
|
||||
return p.PrimaryColor != "" && p.SecondaryColor != ""
|
||||
type LabelPolicyState int32
|
||||
|
||||
const (
|
||||
LabelPolicyStateUnspecified LabelPolicyState = iota
|
||||
LabelPolicyStateActive
|
||||
LabelPolicyStateRemoved
|
||||
LabelPolicyStatePreview
|
||||
|
||||
labelPolicyStateCount
|
||||
)
|
||||
|
||||
func (f LabelPolicy) IsValid() error {
|
||||
if !colorRegex.MatchString(f.PrimaryColor) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-391dG", "Errors.Policy.Label.Invalid.PrimaryColor")
|
||||
}
|
||||
if !colorRegex.MatchString(f.BackgroundColor) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-502F1", "Errors.Policy.Label.Invalid.BackgroundColor")
|
||||
}
|
||||
if !colorRegex.MatchString(f.WarnColor) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-nvw33", "Errors.Policy.Label.Invalid.WarnColor")
|
||||
}
|
||||
if !colorRegex.MatchString(f.FontColor) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-93mSf", "Errors.Policy.Label.Invalid.FontColor")
|
||||
}
|
||||
if !colorRegex.MatchString(f.PrimaryColorDark) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-391dG", "Errors.Policy.Label.Invalid.PrimaryColorDark")
|
||||
}
|
||||
if !colorRegex.MatchString(f.BackgroundColorDark) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-llsp2", "Errors.Policy.Label.Invalid.BackgroundColorDark")
|
||||
}
|
||||
if !colorRegex.MatchString(f.WarnColorDark) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-2b6sf", "Errors.Policy.Label.Invalid.WarnColorDark")
|
||||
}
|
||||
if !colorRegex.MatchString(f.FontColorDark) {
|
||||
return caos_errs.ThrowInvalidArgument(nil, "POLICY-3M0fs", "Errors.Policy.Label.Invalid.FontColorDark")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f LabelPolicyState) Valid() bool {
|
||||
return f >= 0 && f < labelPolicyStateCount
|
||||
}
|
||||
|
||||
func (s LabelPolicyState) Exists() bool {
|
||||
return s != LabelPolicyStateUnspecified && s != LabelPolicyStateRemoved
|
||||
}
|
||||
|
505
internal/domain/policy_label_test.go
Normal file
505
internal/domain/policy_label_test.go
Normal file
@@ -0,0 +1,505 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
func TestLabelPolicyPrimaryColorValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty primary, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColor: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColor: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColor: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColor: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelPolicyBackgroundColorValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty background, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColor: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColor: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColor: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColor: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelPolicyWarnColorValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty warn, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColor: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColor: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColor: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColor: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelPolicyFontColorValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty font, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColor: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColor: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColor: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColor: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColor: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelPolicyPrimaryColorDarkValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty primary dark, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColorDark: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColorDark: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColorDark: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColorDark: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{PrimaryColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelPolicyBackgroundColorDarkValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty background dark, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColorDark: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColorDark: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColorDark: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColorDark: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{BackgroundColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelPolicyWarnColorDarkValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty warn dark, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColorDark: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColorDark: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColorDark: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColorDark: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{WarnColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelPolicyFontColorDarkValid(t *testing.T) {
|
||||
type args struct {
|
||||
policy *LabelPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
err func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "empty font dark, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColorDark: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 6 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColorDark: "#ffffff"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with 3 characters, valid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColorDark: "#000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color code with wrong characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColorDark: "#0f9wfm"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with wrong count of characters, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "color code with no #, invalid",
|
||||
args: args{
|
||||
policy: &LabelPolicy{FontColorDark: "#00"},
|
||||
},
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.policy.IsValid()
|
||||
if tt.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.err != nil && !tt.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -16,6 +16,8 @@ const (
|
||||
Step11
|
||||
Step12
|
||||
Step13
|
||||
Step14
|
||||
Step15
|
||||
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
|
||||
StepCount
|
||||
)
|
||||
|
@@ -25,12 +25,13 @@ type FeaturesView struct {
|
||||
LoginPolicyUsernameLogin bool
|
||||
LoginPolicyPasswordReset bool
|
||||
PasswordComplexityPolicy bool
|
||||
LabelPolicy bool
|
||||
LabelPolicyPrivateLabel bool
|
||||
LabelPolicyWatermark bool
|
||||
CustomDomain bool
|
||||
}
|
||||
|
||||
func (f *FeaturesView) FeatureList() []string {
|
||||
list := make([]string, 0, 6)
|
||||
list := make([]string, 0)
|
||||
if f.LoginPolicyFactors {
|
||||
list = append(list, domain.FeatureLoginPolicyFactors)
|
||||
}
|
||||
@@ -52,8 +53,11 @@ func (f *FeaturesView) FeatureList() []string {
|
||||
if f.PasswordComplexityPolicy {
|
||||
list = append(list, domain.FeaturePasswordComplexityPolicy)
|
||||
}
|
||||
if f.LabelPolicy {
|
||||
list = append(list, domain.FeatureLabelPolicy)
|
||||
if f.LabelPolicyPrivateLabel {
|
||||
list = append(list, domain.FeatureLabelPolicyPrivateLabel)
|
||||
}
|
||||
if f.LabelPolicyWatermark {
|
||||
list = append(list, domain.FeatureLabelPolicyWatermark)
|
||||
}
|
||||
if f.CustomDomain {
|
||||
list = append(list, domain.FeatureCustomDomain)
|
||||
|
@@ -38,7 +38,9 @@ type FeaturesView struct {
|
||||
LoginPolicyUsernameLogin bool `json:"loginPolicyUsernameLogin" gorm:"column:login_policy_username_login"`
|
||||
LoginPolicyPasswordReset bool `json:"loginPolicyPasswordReset" gorm:"column:login_policy_password_reset"`
|
||||
PasswordComplexityPolicy bool `json:"passwordComplexityPolicy" gorm:"column:password_complexity_policy"`
|
||||
LabelPolicy bool `json:"labelPolicy" gorm:"column:label_policy"`
|
||||
LabelPolicy *bool `json:"labelPolicy" gorm:"-"`
|
||||
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"`
|
||||
}
|
||||
|
||||
@@ -61,7 +63,8 @@ func FeaturesToModel(features *FeaturesView) *features_model.FeaturesView {
|
||||
LoginPolicyUsernameLogin: features.LoginPolicyUsernameLogin,
|
||||
LoginPolicyPasswordReset: features.LoginPolicyPasswordReset,
|
||||
PasswordComplexityPolicy: features.PasswordComplexityPolicy,
|
||||
LabelPolicy: features.LabelPolicy,
|
||||
LabelPolicyPrivateLabel: features.LabelPolicyPrivateLabel,
|
||||
LabelPolicyWatermark: features.LabelPolicyWatermark,
|
||||
CustomDomain: features.CustomDomain,
|
||||
}
|
||||
}
|
||||
@@ -95,5 +98,8 @@ func (f *FeaturesView) SetData(event *models.Event) error {
|
||||
logging.Log("EVEN-DVsf2").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-Bfg31", "Could not unmarshal data")
|
||||
}
|
||||
if f.LabelPolicy != nil {
|
||||
f.LabelPolicyPrivateLabel = *f.LabelPolicy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -10,7 +10,13 @@ type LabelPolicy struct {
|
||||
State PolicyState
|
||||
Default bool
|
||||
PrimaryColor string
|
||||
SecondaryColor string
|
||||
BackgroundColor string
|
||||
FontColor string
|
||||
WarnColor string
|
||||
PrimaryColorDark string
|
||||
BackgroundColorDark string
|
||||
FontColorDark string
|
||||
WarnColorDark string
|
||||
HideLoginNameSuffix bool
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,33 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
type LabelPolicyView struct {
|
||||
AggregateID string
|
||||
PrimaryColor string
|
||||
SecondaryColor string
|
||||
AggregateID string
|
||||
PrimaryColor string
|
||||
BackgroundColor string
|
||||
WarnColor string
|
||||
FontColor string
|
||||
LogoURL string
|
||||
IconURL string
|
||||
|
||||
PrimaryColorDark string
|
||||
BackgroundColorDark string
|
||||
WarnColorDark string
|
||||
FontColorDark string
|
||||
LogoDarkURL string
|
||||
IconDarkURL string
|
||||
FontURL string
|
||||
|
||||
HideLoginNameSuffix bool
|
||||
Default bool
|
||||
ErrorMsgPopup bool
|
||||
DisableWatermark bool
|
||||
|
||||
Default bool
|
||||
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
@@ -30,6 +47,7 @@ type LabelPolicySearchKey int32
|
||||
const (
|
||||
LabelPolicySearchKeyUnspecified LabelPolicySearchKey = iota
|
||||
LabelPolicySearchKeyAggregateID
|
||||
LabelPolicySearchKeyState
|
||||
)
|
||||
|
||||
type LabelPolicySearchQuery struct {
|
||||
|
@@ -12,7 +12,13 @@ type LabelPolicy struct {
|
||||
es_models.ObjectRoot
|
||||
State int32 `json:"-"`
|
||||
PrimaryColor string `json:"primaryColor"`
|
||||
SecondaryColor string `json:"secondaryColor"`
|
||||
BackgroundColor string `json:"backgroundColor"`
|
||||
FontColor string `json:"fontColor"`
|
||||
WarnColor string `json:"warnColor"`
|
||||
PrimaryColorDark string `json:"primaryColorDark"`
|
||||
BackgroundColorDark string `json:"backgroundColorDark"`
|
||||
FontColorDark string `json:"fontColorDark"`
|
||||
WarnColorDark string `json:"warnColorDark"`
|
||||
HideLoginNameSuffix bool `json:"hideLoginNameSuffix"`
|
||||
}
|
||||
|
||||
@@ -21,7 +27,13 @@ func LabelPolicyToModel(policy *LabelPolicy) *iam_model.LabelPolicy {
|
||||
ObjectRoot: policy.ObjectRoot,
|
||||
State: iam_model.PolicyState(policy.State),
|
||||
PrimaryColor: policy.PrimaryColor,
|
||||
SecondaryColor: policy.SecondaryColor,
|
||||
BackgroundColor: policy.BackgroundColor,
|
||||
WarnColor: policy.WarnColor,
|
||||
FontColor: policy.FontColor,
|
||||
PrimaryColorDark: policy.PrimaryColorDark,
|
||||
BackgroundColorDark: policy.BackgroundColorDark,
|
||||
WarnColorDark: policy.WarnColorDark,
|
||||
FontColorDark: policy.FontColorDark,
|
||||
HideLoginNameSuffix: policy.HideLoginNameSuffix,
|
||||
}
|
||||
}
|
||||
@@ -31,24 +43,17 @@ func LabelPolicyFromModel(policy *iam_model.LabelPolicy) *LabelPolicy {
|
||||
ObjectRoot: policy.ObjectRoot,
|
||||
State: int32(policy.State),
|
||||
PrimaryColor: policy.PrimaryColor,
|
||||
SecondaryColor: policy.SecondaryColor,
|
||||
BackgroundColor: policy.BackgroundColor,
|
||||
WarnColor: policy.WarnColor,
|
||||
FontColor: policy.FontColor,
|
||||
PrimaryColorDark: policy.PrimaryColorDark,
|
||||
BackgroundColorDark: policy.BackgroundColorDark,
|
||||
WarnColorDark: policy.WarnColorDark,
|
||||
FontColorDark: policy.FontColorDark,
|
||||
HideLoginNameSuffix: policy.HideLoginNameSuffix,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *LabelPolicy) Changes(changed *LabelPolicy) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 2)
|
||||
|
||||
if changed.PrimaryColor != p.PrimaryColor {
|
||||
changes["primaryColor"] = changed.PrimaryColor
|
||||
}
|
||||
if changed.SecondaryColor != p.SecondaryColor {
|
||||
changes["secondaryColor"] = changed.SecondaryColor
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
func (i *IAM) appendAddLabelPolicyEvent(event *es_models.Event) error {
|
||||
i.DefaultLabelPolicy = new(LabelPolicy)
|
||||
err := i.DefaultLabelPolicy.SetDataLabel(event)
|
||||
|
@@ -7,50 +7,6 @@ import (
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
|
||||
func TestLabelPolicyChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *LabelPolicy
|
||||
new *LabelPolicy
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "labelpolicy all attributes change",
|
||||
args: args{
|
||||
existing: &LabelPolicy{PrimaryColor: "000001", SecondaryColor: "FFFFFA"},
|
||||
new: &LabelPolicy{PrimaryColor: "000000", SecondaryColor: "FFFFFF"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
||||
existing: &LabelPolicy{PrimaryColor: "000000", SecondaryColor: "FFFFFF"},
|
||||
new: &LabelPolicy{PrimaryColor: "000000", SecondaryColor: "FFFFFF"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendAddLabelPolicyEvent(t *testing.T) {
|
||||
type args struct {
|
||||
iam *IAM
|
||||
@@ -66,10 +22,10 @@ func TestAppendAddLabelPolicyEvent(t *testing.T) {
|
||||
name: "append add label policy event",
|
||||
args: args{
|
||||
iam: new(IAM),
|
||||
policy: &LabelPolicy{PrimaryColor: "000000", SecondaryColor: "FFFFFF"},
|
||||
policy: &LabelPolicy{PrimaryColor: "000000", BackgroundColor: "FFFFFF"},
|
||||
event: new(es_models.Event),
|
||||
},
|
||||
result: &IAM{DefaultLabelPolicy: &LabelPolicy{PrimaryColor: "000000", SecondaryColor: "FFFFFF"}},
|
||||
result: &IAM{DefaultLabelPolicy: &LabelPolicy{PrimaryColor: "000000", BackgroundColor: "FFFFFF"}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -82,8 +38,8 @@ func TestAppendAddLabelPolicyEvent(t *testing.T) {
|
||||
if tt.result.DefaultLabelPolicy.PrimaryColor != tt.args.iam.DefaultLabelPolicy.PrimaryColor {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLabelPolicy.PrimaryColor, tt.args.iam.DefaultLabelPolicy.PrimaryColor)
|
||||
}
|
||||
if tt.result.DefaultLabelPolicy.SecondaryColor != tt.args.iam.DefaultLabelPolicy.SecondaryColor {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLabelPolicy.SecondaryColor, tt.args.iam.DefaultLabelPolicy.SecondaryColor)
|
||||
if tt.result.DefaultLabelPolicy.BackgroundColor != tt.args.iam.DefaultLabelPolicy.BackgroundColor {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLabelPolicy.BackgroundColor, tt.args.iam.DefaultLabelPolicy.BackgroundColor)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -104,13 +60,13 @@ func TestAppendChangeLabelPolicyEvent(t *testing.T) {
|
||||
name: "append change label policy event",
|
||||
args: args{
|
||||
iam: &IAM{DefaultLabelPolicy: &LabelPolicy{
|
||||
PrimaryColor: "000001", SecondaryColor: "FFFFF0",
|
||||
PrimaryColor: "000001", BackgroundColor: "FFFFF0",
|
||||
}},
|
||||
policy: &LabelPolicy{PrimaryColor: "000000", SecondaryColor: "FFFFFF"},
|
||||
policy: &LabelPolicy{PrimaryColor: "000000", BackgroundColor: "FFFFFF"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &IAM{DefaultLabelPolicy: &LabelPolicy{
|
||||
PrimaryColor: "000000", SecondaryColor: "FFFFFF",
|
||||
PrimaryColor: "000000", BackgroundColor: "FFFFFF",
|
||||
}},
|
||||
},
|
||||
}
|
||||
@@ -124,8 +80,8 @@ func TestAppendChangeLabelPolicyEvent(t *testing.T) {
|
||||
if tt.result.DefaultLabelPolicy.PrimaryColor != tt.args.iam.DefaultLabelPolicy.PrimaryColor {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLabelPolicy.PrimaryColor, tt.args.iam.DefaultLabelPolicy.PrimaryColor)
|
||||
}
|
||||
if tt.result.DefaultLabelPolicy.SecondaryColor != tt.args.iam.DefaultLabelPolicy.SecondaryColor {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLabelPolicy.SecondaryColor, tt.args.iam.DefaultLabelPolicy.SecondaryColor)
|
||||
if tt.result.DefaultLabelPolicy.BackgroundColor != tt.args.iam.DefaultLabelPolicy.BackgroundColor {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.DefaultLabelPolicy.BackgroundColor, tt.args.iam.DefaultLabelPolicy.BackgroundColor)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -35,8 +35,21 @@ const (
|
||||
LoginPolicyMultiFactorAdded models.EventType = "iam.policy.login.multifactor.added"
|
||||
LoginPolicyMultiFactorRemoved models.EventType = "iam.policy.login.multifactor.removed"
|
||||
|
||||
LabelPolicyAdded models.EventType = "iam.policy.label.added"
|
||||
LabelPolicyChanged models.EventType = "iam.policy.label.changed"
|
||||
LabelPolicyAdded models.EventType = "iam.policy.label.added"
|
||||
LabelPolicyChanged models.EventType = "iam.policy.label.changed"
|
||||
LabelPolicyActivated models.EventType = "iam.policy.label.activated"
|
||||
|
||||
LabelPolicyLogoAdded models.EventType = "iam.policy.label.logo.added"
|
||||
LabelPolicyLogoRemoved models.EventType = "iam.policy.label.logo.removed"
|
||||
LabelPolicyIconAdded models.EventType = "iam.policy.label.icon.added"
|
||||
LabelPolicyIconRemoved models.EventType = "iam.policy.label.icon.removed"
|
||||
LabelPolicyLogoDarkAdded models.EventType = "iam.policy.label.logo.dark.added"
|
||||
LabelPolicyLogoDarkRemoved models.EventType = "iam.policy.label.logo.dark.removed"
|
||||
LabelPolicyIconDarkAdded models.EventType = "iam.policy.label.icon.dark.added"
|
||||
LabelPolicyIconDarkRemoved models.EventType = "iam.policy.label.icon.dark.removed"
|
||||
LabelPolicyFontAdded models.EventType = "iam.policy.label.font.added"
|
||||
LabelPolicyFontRemoved models.EventType = "iam.policy.label.font.removed"
|
||||
LabelPolicyAssetsRemoved models.EventType = "iam.policy.label.assets.removed"
|
||||
|
||||
MailTemplateAdded models.EventType = "iam.mail.template.added"
|
||||
MailTemplateChanged models.EventType = "iam.mail.template.changed"
|
||||
|
@@ -6,13 +6,15 @@ import (
|
||||
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"
|
||||
)
|
||||
|
||||
func GetLabelPolicyByAggregateID(db *gorm.DB, table, aggregateID string) (*model.LabelPolicyView, error) {
|
||||
func GetLabelPolicyByAggregateIDAndState(db *gorm.DB, table, aggregateID string, state int32) (*model.LabelPolicyView, error) {
|
||||
policy := new(model.LabelPolicyView)
|
||||
aggregateIDQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
||||
query := repository.PrepareGetByQuery(table, aggregateIDQuery)
|
||||
stateQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyState, Value: state, Method: domain.SearchMethodEquals}
|
||||
query := repository.PrepareGetByQuery(table, aggregateIDQuery, stateQuery)
|
||||
err := query(db, policy)
|
||||
if caos_errs.IsNotFound(err) {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-68G11", "Errors.IAM.LabelPolicy.NotExisting")
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
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"
|
||||
@@ -17,22 +18,40 @@ import (
|
||||
|
||||
const (
|
||||
LabelPolicyKeyAggregateID = "aggregate_id"
|
||||
LabelPolicyKeyState = "label_policy_state"
|
||||
)
|
||||
|
||||
type LabelPolicyView struct {
|
||||
AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"`
|
||||
State int32 `json:"-" gorm:"column:label_policy_state;primary_key"`
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
State int32 `json:"-" gorm:"column:label_policy_state"`
|
||||
|
||||
PrimaryColor string `json:"primaryColor" gorm:"column:primary_color"`
|
||||
SecondaryColor string `json:"secondaryColor" gorm:"column:secondary_color"`
|
||||
BackgroundColor string `json:"backgroundColor" gorm:"column:background_color"`
|
||||
WarnColor string `json:"warnColor" gorm:"column:warn_color"`
|
||||
FontColor string `json:"fontColor" gorm:"column:font_color"`
|
||||
PrimaryColorDark string `json:"primaryColorDark" gorm:"column:primary_color_dark"`
|
||||
BackgroundColorDark string `json:"backgroundColorDark" gorm:"column:background_color_dark"`
|
||||
WarnColorDark string `json:"warnColorDark" gorm:"column:warn_color_dark"`
|
||||
FontColorDark string `json:"fontColorDark" gorm:"column:font_color_dark"`
|
||||
LogoURL string `json:"-" gorm:"column:logo_url"`
|
||||
IconURL string `json:"-" gorm:"column:icon_url"`
|
||||
LogoDarkURL string `json:"-" gorm:"column:logo_dark_url"`
|
||||
IconDarkURL string `json:"-" gorm:"column:icon_dark_url"`
|
||||
FontURL string `json:"-" gorm:"column:font_url"`
|
||||
HideLoginNameSuffix bool `json:"hideLoginNameSuffix" gorm:"column:hide_login_name_suffix"`
|
||||
ErrorMsgPopup bool `json:"errorMsgPopup" gorm:"column:err_msg_popup"`
|
||||
DisableWatermark bool `json:"disableWatermark" gorm:"column:disable_watermark"`
|
||||
Default bool `json:"-" gorm:"-"`
|
||||
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
}
|
||||
|
||||
type AssetView struct {
|
||||
AssetURL string `json:"storeKey"`
|
||||
}
|
||||
|
||||
func (p *LabelPolicyView) ToDomain() *domain.LabelPolicy {
|
||||
return &domain.LabelPolicy{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
@@ -41,36 +60,129 @@ func (p *LabelPolicyView) ToDomain() *domain.LabelPolicy {
|
||||
ChangeDate: p.ChangeDate,
|
||||
Sequence: p.Sequence,
|
||||
},
|
||||
Default: p.Default,
|
||||
PrimaryColor: p.PrimaryColor,
|
||||
SecondaryColor: p.SecondaryColor,
|
||||
Default: p.Default,
|
||||
PrimaryColor: p.PrimaryColor,
|
||||
BackgroundColor: p.BackgroundColor,
|
||||
WarnColor: p.WarnColor,
|
||||
FontColor: p.FontColor,
|
||||
LogoURL: p.LogoURL,
|
||||
IconURL: p.IconURL,
|
||||
|
||||
PrimaryColorDark: p.PrimaryColorDark,
|
||||
BackgroundColorDark: p.BackgroundColorDark,
|
||||
WarnColorDark: p.WarnColorDark,
|
||||
FontColorDark: p.FontColorDark,
|
||||
LogoDarkURL: p.LogoDarkURL,
|
||||
IconDarkURL: p.IconDarkURL,
|
||||
Font: p.FontURL,
|
||||
|
||||
HideLoginNameSuffix: p.HideLoginNameSuffix,
|
||||
ErrorMsgPopup: p.ErrorMsgPopup,
|
||||
DisableWatermark: p.DisableWatermark,
|
||||
}
|
||||
}
|
||||
|
||||
func LabelPolicyViewToModel(policy *LabelPolicyView) *model.LabelPolicyView {
|
||||
return &model.LabelPolicyView{
|
||||
AggregateID: policy.AggregateID,
|
||||
Sequence: policy.Sequence,
|
||||
CreationDate: policy.CreationDate,
|
||||
ChangeDate: policy.ChangeDate,
|
||||
PrimaryColor: policy.PrimaryColor,
|
||||
SecondaryColor: policy.SecondaryColor,
|
||||
AggregateID: policy.AggregateID,
|
||||
Sequence: policy.Sequence,
|
||||
CreationDate: policy.CreationDate,
|
||||
ChangeDate: policy.ChangeDate,
|
||||
|
||||
PrimaryColor: policy.PrimaryColor,
|
||||
BackgroundColor: policy.BackgroundColor,
|
||||
WarnColor: policy.WarnColor,
|
||||
FontColor: policy.FontColor,
|
||||
LogoURL: policy.LogoURL,
|
||||
IconURL: policy.IconURL,
|
||||
|
||||
PrimaryColorDark: policy.PrimaryColorDark,
|
||||
BackgroundColorDark: policy.BackgroundColorDark,
|
||||
WarnColorDark: policy.WarnColorDark,
|
||||
FontColorDark: policy.FontColorDark,
|
||||
LogoDarkURL: policy.LogoDarkURL,
|
||||
IconDarkURL: policy.IconDarkURL,
|
||||
|
||||
FontURL: policy.FontURL,
|
||||
|
||||
HideLoginNameSuffix: policy.HideLoginNameSuffix,
|
||||
ErrorMsgPopup: policy.ErrorMsgPopup,
|
||||
DisableWatermark: policy.DisableWatermark,
|
||||
Default: policy.Default,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *LabelPolicyView) AppendEvent(event *models.Event) (err error) {
|
||||
asset := &AssetView{}
|
||||
i.Sequence = event.Sequence
|
||||
i.ChangeDate = event.CreationDate
|
||||
switch event.Type {
|
||||
case es_model.LabelPolicyAdded, org_es_model.LabelPolicyAdded:
|
||||
i.setRootData(event)
|
||||
i.CreationDate = event.CreationDate
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
err = i.SetData(event)
|
||||
case es_model.LabelPolicyChanged, org_es_model.LabelPolicyChanged:
|
||||
err = i.SetData(event)
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyLogoAdded, org_es_model.LabelPolicyLogoAdded:
|
||||
err = asset.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.LogoURL = asset.AssetURL
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyLogoRemoved, org_es_model.LabelPolicyLogoRemoved:
|
||||
i.LogoURL = ""
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyIconAdded, org_es_model.LabelPolicyIconAdded:
|
||||
err = asset.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.IconURL = asset.AssetURL
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyIconRemoved, org_es_model.LabelPolicyIconRemoved:
|
||||
i.IconURL = ""
|
||||
case es_model.LabelPolicyLogoDarkAdded, org_es_model.LabelPolicyLogoDarkAdded:
|
||||
err = asset.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.LogoDarkURL = asset.AssetURL
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyLogoDarkRemoved, org_es_model.LabelPolicyLogoDarkRemoved:
|
||||
i.LogoDarkURL = ""
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyIconDarkAdded, org_es_model.LabelPolicyIconDarkAdded:
|
||||
err = asset.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.IconDarkURL = asset.AssetURL
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyIconDarkRemoved, org_es_model.LabelPolicyIconDarkRemoved:
|
||||
i.IconDarkURL = ""
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyFontAdded, org_es_model.LabelPolicyFontAdded:
|
||||
err = asset.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.FontURL = asset.AssetURL
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyFontRemoved, org_es_model.LabelPolicyFontRemoved:
|
||||
i.FontURL = ""
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
case es_model.LabelPolicyActivated, org_es_model.LabelPolicyActivated:
|
||||
i.State = int32(domain.LabelPolicyStateActive)
|
||||
case es_model.LabelPolicyAssetsRemoved, org_es_model.LabelPolicyAssetsRemoved:
|
||||
i.LogoURL = ""
|
||||
i.IconURL = ""
|
||||
i.LogoDarkURL = ""
|
||||
i.IconDarkURL = ""
|
||||
i.FontURL = ""
|
||||
i.State = int32(domain.LabelPolicyStatePreview)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -86,3 +198,11 @@ func (r *LabelPolicyView) SetData(event *models.Event) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *AssetView) SetData(event *models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||
logging.Log("MODEL-Ms8f2").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-Hs8uf", "Could not unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -53,6 +53,8 @@ func (key LabelPolicySearchKey) ToColumnName() string {
|
||||
switch iam_model.LabelPolicySearchKey(key) {
|
||||
case iam_model.LabelPolicySearchKeyAggregateID:
|
||||
return LabelPolicyKeyAggregateID
|
||||
case iam_model.LabelPolicySearchKeyState:
|
||||
return LabelPolicyKeyState
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
@@ -195,9 +195,24 @@ func (repo *OrgRepository) SearchIDPConfigs(ctx context.Context, request *iam_mo
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
|
||||
policy, err := repo.View.LabelPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
||||
policy, err := repo.View.LabelPolicyByAggregateIDAndState(authz.GetCtxData(ctx).OrgID, int32(domain.LabelPolicyStateActive))
|
||||
if errors.IsNotFound(err) {
|
||||
policy, err = repo.View.LabelPolicyByAggregateID(repo.SystemDefaults.IamID)
|
||||
policy, err = repo.View.LabelPolicyByAggregateIDAndState(repo.SystemDefaults.IamID, int32(domain.LabelPolicyStateActive))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy.Default = true
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iam_es_model.LabelPolicyViewToModel(policy), err
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetPreviewLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
|
||||
policy, err := repo.View.LabelPolicyByAggregateIDAndState(authz.GetCtxData(ctx).OrgID, int32(domain.LabelPolicyStatePreview))
|
||||
if errors.IsNotFound(err) {
|
||||
policy, err = repo.View.LabelPolicyByAggregateIDAndState(repo.SystemDefaults.IamID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -210,7 +225,15 @@ func (repo *OrgRepository) GetLabelPolicy(ctx context.Context) (*iam_model.Label
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
|
||||
policy, viewErr := repo.View.LabelPolicyByAggregateID(repo.SystemDefaults.IamID)
|
||||
return repo.getDefaultLabelPolicy(ctx, domain.LabelPolicyStateActive)
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) GetPreviewDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
|
||||
return repo.getDefaultLabelPolicy(ctx, domain.LabelPolicyStatePreview)
|
||||
}
|
||||
|
||||
func (repo *OrgRepository) getDefaultLabelPolicy(ctx context.Context, state domain.LabelPolicyState) (*iam_model.LabelPolicyView, error) {
|
||||
policy, viewErr := repo.View.LabelPolicyByAggregateIDAndState(repo.SystemDefaults.IamID, int32(state))
|
||||
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
||||
return nil, viewErr
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
@@ -30,7 +31,7 @@ func (h *handler) Eventstore() v1.Eventstore {
|
||||
return h.es
|
||||
}
|
||||
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, defaults systemdefaults.SystemDefaults) []query.Handler {
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, defaults systemdefaults.SystemDefaults, staticStorage static.Storage) []query.Handler {
|
||||
return []query.Handler{
|
||||
newProject(
|
||||
handler{view, bulkLimit, configs.cycleDuration("Project"), errorCount, es}),
|
||||
@@ -58,7 +59,8 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
|
||||
newLoginPolicy(
|
||||
handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount, es}),
|
||||
newLabelPolicy(
|
||||
handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount, es}),
|
||||
handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount, es},
|
||||
staticStorage),
|
||||
newIDPProvider(
|
||||
handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount, es},
|
||||
defaults),
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"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"
|
||||
@@ -9,6 +12,7 @@ import (
|
||||
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"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -18,11 +22,13 @@ const (
|
||||
type LabelPolicy struct {
|
||||
handler
|
||||
subscription *v1.Subscription
|
||||
static static.Storage
|
||||
}
|
||||
|
||||
func newLabelPolicy(handler handler) *LabelPolicy {
|
||||
func newLabelPolicy(handler handler, static static.Storage) *LabelPolicy {
|
||||
h := &LabelPolicy{
|
||||
handler: handler,
|
||||
static: static,
|
||||
}
|
||||
|
||||
h.subscribe()
|
||||
@@ -78,12 +84,29 @@ func (m *LabelPolicy) processLabelPolicy(event *es_models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case iam_es_model.LabelPolicyAdded, model.LabelPolicyAdded:
|
||||
err = policy.AppendEvent(event)
|
||||
case iam_es_model.LabelPolicyChanged, model.LabelPolicyChanged:
|
||||
policy, err = m.view.LabelPolicyByAggregateID(event.AggregateID)
|
||||
case iam_es_model.LabelPolicyChanged, model.LabelPolicyChanged,
|
||||
iam_es_model.LabelPolicyLogoAdded, model.LabelPolicyLogoAdded,
|
||||
iam_es_model.LabelPolicyLogoRemoved, model.LabelPolicyLogoRemoved,
|
||||
iam_es_model.LabelPolicyIconAdded, model.LabelPolicyIconAdded,
|
||||
iam_es_model.LabelPolicyIconRemoved, model.LabelPolicyIconRemoved,
|
||||
iam_es_model.LabelPolicyLogoDarkAdded, model.LabelPolicyLogoDarkAdded,
|
||||
iam_es_model.LabelPolicyLogoDarkRemoved, model.LabelPolicyLogoDarkRemoved,
|
||||
iam_es_model.LabelPolicyIconDarkAdded, model.LabelPolicyIconDarkAdded,
|
||||
iam_es_model.LabelPolicyIconDarkRemoved, model.LabelPolicyIconDarkRemoved,
|
||||
iam_es_model.LabelPolicyFontAdded, model.LabelPolicyFontAdded,
|
||||
iam_es_model.LabelPolicyFontRemoved, model.LabelPolicyFontRemoved:
|
||||
policy, err = m.view.LabelPolicyByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = policy.AppendEvent(event)
|
||||
case iam_es_model.LabelPolicyActivated, model.LabelPolicyActivated:
|
||||
policy, err = m.view.LabelPolicyByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go m.CleanUpBucket(policy)
|
||||
err = policy.AppendEvent(event)
|
||||
default:
|
||||
return m.view.ProcessedLabelPolicySequence(event)
|
||||
}
|
||||
@@ -101,3 +124,27 @@ func (m *LabelPolicy) OnError(event *es_models.Event, err error) error {
|
||||
func (m *LabelPolicy) OnSuccess() error {
|
||||
return spooler.HandleSuccess(m.view.UpdateLabelPolicySpoolerRunTimestamp)
|
||||
}
|
||||
|
||||
func (p *LabelPolicy) CleanUpBucket(policy *iam_model.LabelPolicyView) {
|
||||
if p.static == nil {
|
||||
return
|
||||
}
|
||||
ctx := context.Background()
|
||||
objects, err := p.static.ListObjectInfos(ctx, policy.AggregateID, domain.LabelPolicyPrefix+"/", false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, object := range objects {
|
||||
if !deleteableObject(object, policy) {
|
||||
continue
|
||||
}
|
||||
p.static.RemoveObject(ctx, policy.AggregateID, object.Key)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteableObject(object *domain.AssetInfo, policy *iam_model.LabelPolicyView) bool {
|
||||
if object.Key == policy.LogoURL || object.Key == policy.LogoDarkURL || object.Key == policy.IconURL || object.Key == policy.IconDarkURL || object.Key == policy.FontURL {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@@ -120,6 +120,8 @@ func (u *User) ProcessUser(event *es_models.Event) (err error) {
|
||||
es_model.HumanProfileChanged,
|
||||
es_model.HumanEmailChanged,
|
||||
es_model.HumanEmailVerified,
|
||||
es_model.HumanAvatarAdded,
|
||||
es_model.HumanAvatarRemoved,
|
||||
es_model.HumanPhoneChanged,
|
||||
es_model.HumanPhoneVerified,
|
||||
es_model.HumanPhoneRemoved,
|
||||
|
@@ -3,6 +3,7 @@ package eventsourcing
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
@@ -31,7 +32,7 @@ type EsRepository struct {
|
||||
view *mgmt_view.View
|
||||
}
|
||||
|
||||
func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string, queries *query.Queries) (*EsRepository, error) {
|
||||
func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string, queries *query.Queries, staticStorage static.Storage) (*EsRepository, error) {
|
||||
|
||||
es, err := v1.Start(conf.Eventstore)
|
||||
if err != nil {
|
||||
@@ -47,7 +48,7 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string, querie
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults)
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults, staticStorage)
|
||||
|
||||
return &EsRepository{
|
||||
spooler: spool,
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing/handler"
|
||||
@@ -17,12 +18,12 @@ type SpoolerConfig struct {
|
||||
Handlers handler.Configs
|
||||
}
|
||||
|
||||
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, defaults systemdefaults.SystemDefaults) *spooler.Spooler {
|
||||
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, defaults systemdefaults.SystemDefaults, staticStorage static.Storage) *spooler.Spooler {
|
||||
spoolerConfig := spooler.Config{
|
||||
Eventstore: es,
|
||||
Locker: &locker{dbClient: sql},
|
||||
ConcurrentWorkers: c.ConcurrentWorkers,
|
||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, defaults),
|
||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, defaults, staticStorage),
|
||||
}
|
||||
spool := spoolerConfig.New()
|
||||
spool.Start()
|
||||
|
@@ -12,8 +12,8 @@ const (
|
||||
labelPolicyTable = "management.label_policies"
|
||||
)
|
||||
|
||||
func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
|
||||
func (v *View) LabelPolicyByAggregateIDAndState(aggregateID string, state int32) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateIDAndState(v.Db, labelPolicyTable, aggregateID, state)
|
||||
}
|
||||
|
||||
func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, event *models.Event) error {
|
||||
|
@@ -48,5 +48,7 @@ type OrgRepository interface {
|
||||
GetMailTexts(ctx context.Context) (*iam_model.MailTextsView, error)
|
||||
|
||||
GetLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
GetPreviewLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
GetPreviewDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
|
||||
}
|
||||
|
@@ -12,13 +12,18 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
APIDomain string
|
||||
Repository eventsourcing.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config, systemDefaults sd.SystemDefaults, command *command.Commands) {
|
||||
func Start(ctx context.Context, config Config, systemDefaults sd.SystemDefaults, command *command.Commands, hasStatics bool) {
|
||||
statikFS, err := fs.NewWithNamespace("notification")
|
||||
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start listener")
|
||||
|
||||
_, err = eventsourcing.Start(config.Repository, statikFS, systemDefaults, command)
|
||||
apiDomain := config.APIDomain
|
||||
if !hasStatics {
|
||||
apiDomain = ""
|
||||
}
|
||||
_, err = eventsourcing.Start(config.Repository, statikFS, systemDefaults, command, apiDomain)
|
||||
logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app")
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ func (h *handler) Eventstore() v1.Eventstore {
|
||||
return h.es
|
||||
}
|
||||
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, command *command.Commands, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) []query.Handler {
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, command *command.Commands, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem, apiDomain string) []query.Handler {
|
||||
aesCrypto, err := crypto.NewAESCrypto(systemDefaults.UserVerificationKey)
|
||||
if err != nil {
|
||||
logging.Log("HANDL-s90ew").WithError(err).Debug("error create new aes crypto")
|
||||
@@ -51,6 +51,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
|
||||
aesCrypto,
|
||||
i18n,
|
||||
dir,
|
||||
apiDomain,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@@ -7,12 +7,15 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||
@@ -23,7 +26,6 @@ import (
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
"github.com/caos/zitadel/internal/user/repository/view"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,6 +52,7 @@ type Notification struct {
|
||||
i18n *i18n.Translator
|
||||
statikDir http.FileSystem
|
||||
subscription *v1.Subscription
|
||||
apiDomain string
|
||||
}
|
||||
|
||||
func newNotification(
|
||||
@@ -59,6 +62,7 @@ func newNotification(
|
||||
aesCrypto crypto.EncryptionAlgorithm,
|
||||
translator *i18n.Translator,
|
||||
statikDir http.FileSystem,
|
||||
apiDomain string,
|
||||
) *Notification {
|
||||
h := &Notification{
|
||||
handler: handler,
|
||||
@@ -67,6 +71,7 @@ func newNotification(
|
||||
i18n: translator,
|
||||
statikDir: statikDir,
|
||||
AesCrypto: aesCrypto,
|
||||
apiDomain: apiDomain,
|
||||
}
|
||||
|
||||
h.subscribe()
|
||||
@@ -142,12 +147,13 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
colors, err := n.getLabelPolicy(context.Background())
|
||||
ctx := getSetNotifyContextData(event.ResourceOwner)
|
||||
colors, err := n.getLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template, err := n.getMailTemplate(context.Background())
|
||||
template, err := n.getMailTemplate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -157,16 +163,16 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(context.Background(), mailTextTypeInitCode, user.PreferredLanguage)
|
||||
text, err := n.getMailText(ctx, mailTextTypeInitCode, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = types.SendUserInitCode(string(template.Template), text, user, initCode, n.systemDefaults, n.AesCrypto, colors)
|
||||
err = types.SendUserInitCode(string(template.Template), text, user, initCode, n.systemDefaults, n.AesCrypto, colors, n.apiDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.command.HumanInitCodeSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID)
|
||||
return n.command.HumanInitCodeSent(ctx, event.ResourceOwner, event.AggregateID)
|
||||
}
|
||||
|
||||
func (n *Notification) handlePasswordCode(event *models.Event) (err error) {
|
||||
@@ -180,13 +186,13 @@ func (n *Notification) handlePasswordCode(event *models.Event) (err error) {
|
||||
if err != nil || alreadyHandled {
|
||||
return err
|
||||
}
|
||||
|
||||
colors, err := n.getLabelPolicy(context.Background())
|
||||
ctx := getSetNotifyContextData(event.ResourceOwner)
|
||||
colors, err := n.getLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template, err := n.getMailTemplate(context.Background())
|
||||
template, err := n.getMailTemplate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -196,15 +202,15 @@ func (n *Notification) handlePasswordCode(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(context.Background(), mailTextTypePasswordReset, user.PreferredLanguage)
|
||||
text, err := n.getMailText(ctx, mailTextTypePasswordReset, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = types.SendPasswordCode(string(template.Template), text, user, pwCode, n.systemDefaults, n.AesCrypto, colors)
|
||||
err = types.SendPasswordCode(string(template.Template), text, user, pwCode, n.systemDefaults, n.AesCrypto, colors, n.apiDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.command.PasswordCodeSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID)
|
||||
return n.command.PasswordCodeSent(ctx, event.ResourceOwner, event.AggregateID)
|
||||
}
|
||||
|
||||
func (n *Notification) handleEmailVerificationCode(event *models.Event) (err error) {
|
||||
@@ -219,12 +225,13 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err
|
||||
return nil
|
||||
}
|
||||
|
||||
colors, err := n.getLabelPolicy(context.Background())
|
||||
ctx := getSetNotifyContextData(event.ResourceOwner)
|
||||
colors, err := n.getLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template, err := n.getMailTemplate(context.Background())
|
||||
template, err := n.getMailTemplate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -234,16 +241,16 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(context.Background(), mailTextTypeVerifyEmail, user.PreferredLanguage)
|
||||
text, err := n.getMailText(ctx, mailTextTypeVerifyEmail, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = types.SendEmailVerificationCode(string(template.Template), text, user, emailCode, n.systemDefaults, n.AesCrypto, colors)
|
||||
err = types.SendEmailVerificationCode(string(template.Template), text, user, emailCode, n.systemDefaults, n.AesCrypto, colors, n.apiDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.command.HumanEmailVerificationCodeSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID)
|
||||
return n.command.HumanEmailVerificationCodeSent(ctx, event.ResourceOwner, event.AggregateID)
|
||||
}
|
||||
|
||||
func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err error) {
|
||||
@@ -285,25 +292,26 @@ func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
|
||||
if user.LastEmail == "" {
|
||||
return nil
|
||||
}
|
||||
colors, err := n.getLabelPolicy(context.Background())
|
||||
ctx := getSetNotifyContextData(event.ResourceOwner)
|
||||
colors, err := n.getLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template, err := n.getMailTemplate(context.Background())
|
||||
template, err := n.getMailTemplate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := n.getMailText(context.Background(), mailTextTypeDomainClaimed, user.PreferredLanguage)
|
||||
text, err := n.getMailText(ctx, mailTextTypeDomainClaimed, user.PreferredLanguage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = types.SendDomainClaimed(string(template.Template), text, user, data["userName"], n.systemDefaults, colors)
|
||||
err = types.SendDomainClaimed(string(template.Template), text, user, data["userName"], n.systemDefaults, colors, n.apiDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.command.UserDomainClaimedSent(getSetNotifyContextData(event.ResourceOwner), event.ResourceOwner, event.AggregateID)
|
||||
return n.command.UserDomainClaimedSent(ctx, event.ResourceOwner, event.AggregateID)
|
||||
}
|
||||
|
||||
func (n *Notification) checkIfCodeAlreadyHandledOrExpired(event *models.Event, expiry time.Duration, eventTypes ...models.EventType) (bool, error) {
|
||||
@@ -353,10 +361,10 @@ func getSetNotifyContextData(orgID string) context.Context {
|
||||
// Read organization specific colors
|
||||
func (n *Notification) getLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
|
||||
// read from Org
|
||||
policy, err := n.view.LabelPolicyByAggregateID(authz.GetCtxData(ctx).OrgID, labelPolicyTableOrg)
|
||||
policy, err := n.view.LabelPolicyByAggregateIDAndState(authz.GetCtxData(ctx).OrgID, labelPolicyTableOrg, int32(domain.LabelPolicyStateActive))
|
||||
if errors.IsNotFound(err) {
|
||||
// read from default
|
||||
policy, err = n.view.LabelPolicyByAggregateID(n.systemDefaults.IamID, labelPolicyTableDef)
|
||||
policy, err = n.view.LabelPolicyByAggregateIDAndState(n.systemDefaults.IamID, labelPolicyTableDef, int32(domain.LabelPolicyStateActive))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ type EsRepository struct {
|
||||
spooler *es_spol.Spooler
|
||||
}
|
||||
|
||||
func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, command *command.Commands) (*EsRepository, error) {
|
||||
func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, command *command.Commands, apiDomain string) (*EsRepository, error) {
|
||||
es, err := v1.Start(conf.Eventstore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -45,7 +45,7 @@ func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, c
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, command, systemDefaults, translator, dir)
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, command, systemDefaults, translator, dir, apiDomain)
|
||||
|
||||
return &EsRepository{
|
||||
spool,
|
||||
|
@@ -20,12 +20,12 @@ type SpoolerConfig struct {
|
||||
Handlers handler.Configs
|
||||
}
|
||||
|
||||
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, command *command.Commands, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) *spooler.Spooler {
|
||||
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, command *command.Commands, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem, apiDomain string) *spooler.Spooler {
|
||||
spoolerConfig := spooler.Config{
|
||||
Eventstore: es,
|
||||
Locker: &locker{dbClient: sql},
|
||||
ConcurrentWorkers: c.ConcurrentWorkers,
|
||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, command, systemDefaults, i18n, dir),
|
||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, command, systemDefaults, i18n, dir, apiDomain),
|
||||
}
|
||||
spool := spoolerConfig.New()
|
||||
spool.Start()
|
||||
|
@@ -5,6 +5,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
)
|
||||
|
||||
func (v *View) LabelPolicyByAggregateID(aggregateID string, labelPolicyTableVar string) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTableVar, aggregateID)
|
||||
func (v *View) LabelPolicyByAggregateIDAndState(aggregateID, labelPolicyTableVar string, state int32) (*model.LabelPolicyView, error) {
|
||||
return view.GetLabelPolicyByAggregateIDAndState(v.Db, labelPolicyTableVar, aggregateID, state)
|
||||
}
|
||||
|
@@ -1,8 +1,9 @@
|
||||
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<title>
|
||||
|
||||
</title>
|
||||
<!--[if !mso]><!-->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
@@ -10,241 +11,362 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style type="text/css">
|
||||
#outlook a {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
table,
|
||||
td {
|
||||
border-collapse: collapse;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
height: auto;
|
||||
line-height: 100%;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
p {
|
||||
display: block;
|
||||
margin: 13px 0;
|
||||
}
|
||||
#outlook a { padding:0; }
|
||||
body { margin:0;padding:0;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%; }
|
||||
table, td { border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt; }
|
||||
img { border:0;height:auto;line-height:100%; outline:none;text-decoration:none;-ms-interpolation-mode:bicubic; }
|
||||
p { display:block;margin:13px 0; }
|
||||
</style>
|
||||
<!--[if mso]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
<!--[if lte mso 11]>
|
||||
<style type="text/css">
|
||||
.mj-outlook-group-fix { width:100% !important; }
|
||||
</style>
|
||||
<![endif]-->
|
||||
<style type="text/css">
|
||||
.mj-outlook-group-fix { width:100% !important; }
|
||||
</style>
|
||||
<![endif]-->
|
||||
|
||||
<!--[if !mso]><!-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,500,700" rel="stylesheet" type="text/css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
@import url(https://fonts.googleapis.com/css?family=Lato:300,400,500,700);
|
||||
@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);
|
||||
</style>
|
||||
<!--<![endif]-->
|
||||
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
@media only screen and (min-width:480px) {
|
||||
.mj-column-per-100 {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.mj-column-per-60 {
|
||||
width: 60% !important;
|
||||
max-width: 60%;
|
||||
}
|
||||
.mj-column-per-100 { width:100% !important; max-width: 100%; }
|
||||
.mj-column-per-60 { width:60% !important; max-width: 60%; }
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
|
||||
|
||||
@media only screen and (max-width:480px) {
|
||||
table.mj-full-width-mobile {
|
||||
width: 100% !important;
|
||||
}
|
||||
table.mj-full-width-mobile { width: 100% !important; }
|
||||
td.mj-full-width-mobile { width: auto !important; }
|
||||
}
|
||||
|
||||
td.mj-full-width-mobile {
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
.shadow a {
|
||||
box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
|
||||
</style>
|
||||
<style type="text/css">.shadow a {
|
||||
box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
|
||||
}</style>
|
||||
|
||||
{{if .FontURL}}
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: '{{.FontFamily}}';
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url({{.FontURL}});
|
||||
}
|
||||
</style>
|
||||
{{end}}
|
||||
|
||||
</head>
|
||||
|
||||
<body style="word-spacing:normal;">
|
||||
<div style="">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#fafafa;background-color:#fafafa;width:100%;border-radius:16px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:800px;" width="800" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<div style="margin:0px auto;border-radius:16px;max-width:800px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;border-radius:16px;">
|
||||
<tbody>
|
||||
|
||||
|
||||
<div
|
||||
style=""
|
||||
>
|
||||
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:{{.BackgroundColor}};background-color:{{.BackgroundColor}};width:100%;border-radius:16px;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:800px;" width="800" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
|
||||
|
||||
<div style="margin:0px auto;border-radius:16px;max-width:800px;">
|
||||
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;border-radius:16px;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="direction:ltr;font-size:0px;padding:20px 0;padding-left:0;text-align:center;"
|
||||
>
|
||||
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" width="800px" ><![endif]-->
|
||||
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction:ltr;font-size:0px;padding:20px 0;padding-left:0;text-align:center;">
|
||||
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" width="800px" ><![endif]-->
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
<td>
|
||||
|
||||
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:800px;" width="800" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
|
||||
|
||||
<div style="margin:0px auto;max-width:800px;">
|
||||
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:800px;" width="800" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<div style="margin:0px auto;max-width:800px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
<td
|
||||
style="direction:ltr;font-size:0px;padding:0;text-align:center;"
|
||||
>
|
||||
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="width:800px;" ><![endif]-->
|
||||
|
||||
<div
|
||||
class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0;line-height:0;text-align:left;display:inline-block;width:100%;direction:ltr;"
|
||||
>
|
||||
<!--[if mso | IE]><table border="0" cellpadding="0" cellspacing="0" role="presentation" ><tr><td style="vertical-align:top;width:800px;" ><![endif]-->
|
||||
|
||||
<div
|
||||
class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"
|
||||
>
|
||||
|
||||
<table
|
||||
border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
|
||||
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="width:800px;" ><![endif]-->
|
||||
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0;line-height:0;text-align:left;display:inline-block;width:100%;direction:ltr;">
|
||||
<!--[if mso | IE]><table border="0" cellpadding="0" cellspacing="0" role="presentation" ><tr><td style="vertical-align:top;width:800px;" ><![endif]-->
|
||||
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
|
||||
<tbody>
|
||||
<td style="vertical-align:top;padding:0;">
|
||||
|
||||
<table
|
||||
border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%"
|
||||
>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
align="center" style="font-size:0px;padding:50px 0 30px 0;word-break:break-word;"
|
||||
>
|
||||
|
||||
<table
|
||||
border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align:top;padding:0;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size:0px;padding:50px 0 30px 0;word-break:break-word;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width:180px;">
|
||||
<img height="auto" src="https://static.zitadel.ch/zitadel-logo-dark@3x.png" style="border:0;border-radius:8px;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="180" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<td style="width:180px;">
|
||||
|
||||
<img
|
||||
height="auto" src="{{.LogoURL}}" style="border:0;border-radius:8px;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="180"
|
||||
/>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--[if mso | IE]></td></tr><tr><td class="" width="800px" ><![endif]-->
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:800px;" width="800" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<div style="margin:0px auto;max-width:800px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
|
||||
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:480px;" ><![endif]-->
|
||||
<div class="mj-column-per-60 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align:top;padding:0;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||
<div style="font-family:-apple-system, BlinkMacSystemFont, Segoe UI, Lato, Arial, Helvetica, sans-serif;font-size:24px;font-weight:500;line-height:1;text-align:center;color:#22292f;">{{.Greeting}}</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||
<div style="font-family:-apple-system, BlinkMacSystemFont, Segoe UI, Lato, Arial, Helvetica, sans-serif;font-size:16px;font-weight:light;line-height:1.5;text-align:center;color:#22292f;">{{.Text}}</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" vertical-align="middle" class="shadow" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">
|
||||
<tr>
|
||||
<td align="center" bgcolor="#5282C1" role="presentation" style="border:none;border-radius:6px;cursor:auto;mso-padding-alt:10px 25px;background:#5282C1;" valign="middle">
|
||||
<a href="{{.URL}}" rel="noopener noreferrer" style="display:inline-block;background:#5282C1;color:#ffffff;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:14px;font-weight:500;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:6px;" target="_blank">
|
||||
{{.ButtonText}}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="font-size:0px;padding:10px 25px;padding-top:20px;padding-right:20px;padding-bottom:20px;padding-left:20px;word-break:break-word;">
|
||||
<p style="border-top:solid 2px #dbdbdb;font-size:1px;margin:0px auto;width:100%;">
|
||||
</p>
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 2px #dbdbdb;font-size:1px;margin:0px auto;width:440px;" role="presentation" width="440px" ><tr><td style="height:0;line-height:0;">
|
||||
</td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="font-size:0px;padding:16px;word-break:break-word;">
|
||||
<div style="font-family:-apple-system, BlinkMacSystemFont, Segoe UI, Lato, Arial, Helvetica, sans-serif;font-size:13px;line-height:1;text-align:center;color:#9ca299;"><a href="http://www.caos.ch" style="color:#e91e63; text-decoration: none;" target="_blank"> CAOS AG </a> <span style="color: #000000; margin: 0 .5rem;">|</span> Teufener Strasse 19 <span style="color: #000000; margin: 0 .5rem;">|</span> CH-9000 St. Gallen</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</html>
|
||||
<!--[if mso | IE]></td></tr><tr><td class="" width="800px" ><![endif]-->
|
||||
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:800px;" width="800" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
|
||||
|
||||
<div style="margin:0px auto;max-width:800px;">
|
||||
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="direction:ltr;font-size:0px;padding:0;text-align:center;"
|
||||
>
|
||||
<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:480px;" ><![endif]-->
|
||||
|
||||
<div
|
||||
class="mj-column-per-60 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"
|
||||
>
|
||||
|
||||
<table
|
||||
border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align:top;padding:0;">
|
||||
|
||||
<table
|
||||
border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%"
|
||||
>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"
|
||||
>
|
||||
|
||||
<div
|
||||
style="font-family:{{.FontFamily}};font-size:24px;font-weight:500;line-height:1;text-align:center;color:{{.FontColor}};"
|
||||
>{{.Greeting}}</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"
|
||||
>
|
||||
|
||||
<div
|
||||
style="font-family:{{.FontFamily}};font-size:16px;font-weight:light;line-height:1.5;text-align:center;color:{{.FontColor}};"
|
||||
>{{.Text}}</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td
|
||||
align="center" vertical-align="middle" class="shadow" style="font-size:0px;padding:10px 25px;word-break:break-word;"
|
||||
>
|
||||
|
||||
<table
|
||||
border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;"
|
||||
>
|
||||
<tr>
|
||||
<td
|
||||
align="center" bgcolor="{{.PrimaryColor}}" role="presentation" style="border:none;border-radius:6px;cursor:auto;mso-padding-alt:10px 25px;background:{{.PrimaryColor}};" valign="middle"
|
||||
>
|
||||
<a
|
||||
href="{{.URL}}" rel="noopener noreferrer" style="display:inline-block;background:{{.PrimaryColor}};color:#ffffff;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:14px;font-weight:500;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:6px;" target="_blank"
|
||||
>
|
||||
{{.ButtonText}}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{{if .IncludeFooter}}
|
||||
<tr>
|
||||
<td
|
||||
align="center" style="font-size:0px;padding:10px 25px;padding-top:20px;padding-right:20px;padding-bottom:20px;padding-left:20px;word-break:break-word;"
|
||||
>
|
||||
|
||||
<p
|
||||
style="border-top:solid 2px #dbdbdb;font-size:1px;margin:0px auto;width:100%;"
|
||||
>
|
||||
</p>
|
||||
|
||||
<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 2px #dbdbdb;font-size:1px;margin:0px auto;width:440px;" role="presentation" width="440px" ><tr><td style="height:0;line-height:0;">
|
||||
</td></tr></table><![endif]-->
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
align="center" style="font-size:0px;padding:16px;word-break:break-word;"
|
||||
>
|
||||
|
||||
<div
|
||||
style="font-family:{{.FontFamily}};font-size:13px;line-height:1;text-align:center;color:{{.FontColor}};"
|
||||
>{{.FooterText}}</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user