diff --git a/services/web/pkg/config/options.go b/services/web/pkg/config/options.go index cb47976928..bc4f4781aa 100644 --- a/services/web/pkg/config/options.go +++ b/services/web/pkg/config/options.go @@ -24,7 +24,9 @@ type Options struct { OxAppSuite *OxAppSuite `json:"oxAppSuite,omitempty" yaml:"oxAppSuite"` } -// Announcement is a banner message shown above the top bar to all users. +// Announcement is a banner message shown above the top bar to all users. It is managed at runtime +// (via the web service's store and the admin settings UI) and injected into config.json here; a +// value configured statically is ignored. type Announcement struct { // BannerText is the short line shown in the banner. BannerText string `json:"bannerText,omitempty" yaml:"bannerText"` diff --git a/services/web/pkg/service/v0/service.go b/services/web/pkg/service/v0/service.go index 9db9ac23c8..5454c15c07 100644 --- a/services/web/pkg/service/v0/service.go +++ b/services/web/pkg/service/v0/service.go @@ -158,43 +158,32 @@ func (p Web) getPayload(ctx context.Context) (payload []byte, err error) { // ensure that the server url has a trailing slash webConfig.Server = strings.TrimRight(webConfig.Server, "/") + "/" - // the runtime store is authoritative once it manages an announcement (enabled or explicitly - // disabled); only when it holds nothing do we keep a statically configured one - // (web.config.options.announcement) - if a, managed := p.managedAnnouncement(ctx); managed { - webConfig.Options.Announcement = a - } + // the runtime store is the single source of truth for the announcement banner: expose it + // when live, clear it otherwise. A statically configured value is not supported. + webConfig.Options.Announcement = p.currentAnnouncement(ctx) return json.Marshal(webConfig) } -// managedAnnouncement returns the announcement the runtime store manages for config.json. The -// bool reports whether the store manages one at all: when true, the returned value (nil for an -// explicitly disabled announcement) overrides any static config; when false, the store holds -// nothing and a statically configured announcement is kept. -func (p Web) managedAnnouncement(ctx context.Context) (*config.Announcement, bool) { +// currentAnnouncement returns the stored announcement for config.json, or nil if unset, disabled +// or unavailable. +func (p Web) currentAnnouncement(ctx context.Context) *config.Announcement { if p.announcementStore == nil { - return nil, false + return nil } a, err := p.announcementStore.Get(ctx) if err != nil { p.logger.Error().Err(err).Msg("could not read announcement from store") - return nil, false + return nil } - // an announcement without a banner line is nothing to manage (empty/removed store) - if a.BannerText == "" { - return nil, false + // only live (enabled) announcements with a banner line are exposed in the public config.json + if !a.Enabled || a.BannerText == "" { + return nil } - // managed but disabled: hide it, overriding any static config - if !a.Enabled { - return nil, true - } - - // only live (enabled) announcements are exposed in the public config.json - return &config.Announcement{BannerText: a.BannerText, InfoText: a.InfoText}, true + return &config.Announcement{BannerText: a.BannerText, InfoText: a.InfoText} } // Config implements the Service interface. diff --git a/services/web/pkg/service/v0/service_test.go b/services/web/pkg/service/v0/service_test.go index e4cc1704c2..a61b7ec648 100644 --- a/services/web/pkg/service/v0/service_test.go +++ b/services/web/pkg/service/v0/service_test.go @@ -14,7 +14,7 @@ import ( "github.com/opencloud-eu/opencloud/services/web/pkg/config" ) -func TestManagedAnnouncement(t *testing.T) { +func TestCurrentAnnouncement(t *testing.T) { newWeb := func(store *announcement.Store) Web { return Web{logger: log.NopLogger(), announcementStore: store} } @@ -33,36 +33,26 @@ func TestManagedAnnouncement(t *testing.T) { return announcement.NewStore(kv) } - t.Run("not managed when there is no store, so a static config is kept", func(t *testing.T) { - a, managed := newWeb(nil).managedAnnouncement(context.Background()) - require.Nil(t, a) - require.False(t, managed) + t.Run("nil when there is no store", func(t *testing.T) { + require.Nil(t, newWeb(nil).currentAnnouncement(context.Background())) }) - t.Run("not managed when the store is empty, so a static config is kept", func(t *testing.T) { - a, managed := newWeb(emptyStore(t)).managedAnnouncement(context.Background()) - require.Nil(t, a) - require.False(t, managed) + t.Run("nil when the store is empty", func(t *testing.T) { + require.Nil(t, newWeb(emptyStore(t)).currentAnnouncement(context.Background())) }) - t.Run("managed but nil when disabled, so a static config is cleared", func(t *testing.T) { + t.Run("nil when disabled", func(t *testing.T) { s := storeReturning(t, `{"enabled":false,"bannerText":"hi","infoText":"info"}`) - a, managed := newWeb(s).managedAnnouncement(context.Background()) - require.Nil(t, a) - require.True(t, managed) + require.Nil(t, newWeb(s).currentAnnouncement(context.Background())) }) - t.Run("not managed when enabled but the banner text is empty", func(t *testing.T) { + t.Run("nil when enabled but the banner text is empty", func(t *testing.T) { s := storeReturning(t, `{"enabled":true,"bannerText":"","infoText":"info"}`) - a, managed := newWeb(s).managedAnnouncement(context.Background()) - require.Nil(t, a) - require.False(t, managed) + require.Nil(t, newWeb(s).currentAnnouncement(context.Background())) }) - t.Run("managed with banner and info text when enabled with a banner text", func(t *testing.T) { + t.Run("returns banner and info text when enabled with a banner text", func(t *testing.T) { s := storeReturning(t, `{"enabled":true,"bannerText":"hi","infoText":"info"}`) - a, managed := newWeb(s).managedAnnouncement(context.Background()) - require.Equal(t, &config.Announcement{BannerText: "hi", InfoText: "info"}, a) - require.True(t, managed) + require.Equal(t, &config.Announcement{BannerText: "hi", InfoText: "info"}, newWeb(s).currentAnnouncement(context.Background())) }) }