diff --git a/agent/agent.go b/agent/agent.go index e3bbe7f07c984..c7a785f8d5da1 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -176,7 +176,7 @@ func New(options Options) Agent { ignorePorts: options.IgnorePorts, portCacheDuration: options.PortCacheDuration, reportMetadataInterval: options.ReportMetadataInterval, - notificationBannersRefreshInterval: options.ServiceBannerRefreshInterval, + announcementBannersRefreshInterval: options.ServiceBannerRefreshInterval, sshMaxTimeout: options.SSHMaxTimeout, subsystems: options.Subsystems, addresses: options.Addresses, @@ -193,7 +193,7 @@ func New(options Options) Agent { // that gets closed on disconnection. This is used to wait for graceful disconnection from the // coordinator during shut down. close(a.coordDisconnected) - a.notificationBanners.Store(new([]codersdk.BannerConfig)) + a.announcementBanners.Store(new([]codersdk.BannerConfig)) a.sessionToken.Store(new(string)) a.init() return a @@ -234,8 +234,8 @@ type agent struct { manifest atomic.Pointer[agentsdk.Manifest] // manifest is atomic because values can change after reconnection. reportMetadataInterval time.Duration scriptRunner *agentscripts.Runner - notificationBanners atomic.Pointer[[]codersdk.BannerConfig] // notificationBanners is atomic because it is periodically updated. - notificationBannersRefreshInterval time.Duration + announcementBanners atomic.Pointer[[]codersdk.BannerConfig] // announcementBanners is atomic because it is periodically updated. + announcementBannersRefreshInterval time.Duration sessionToken atomic.Pointer[string] sshServer *agentssh.Server sshMaxTimeout time.Duration @@ -274,7 +274,7 @@ func (a *agent) init() { sshSrv, err := agentssh.NewServer(a.hardCtx, a.logger.Named("ssh-server"), a.prometheusRegistry, a.filesystem, &agentssh.Config{ MaxTimeout: a.sshMaxTimeout, MOTDFile: func() string { return a.manifest.Load().MOTDFile }, - NotificationBanners: func() *[]codersdk.BannerConfig { return a.notificationBanners.Load() }, + AnnouncementBanners: func() *[]codersdk.BannerConfig { return a.announcementBanners.Load() }, UpdateEnv: a.updateCommandEnv, WorkingDirectory: func() string { return a.manifest.Load().Directory }, }) @@ -709,14 +709,14 @@ func (a *agent) setLifecycle(state codersdk.WorkspaceAgentLifecycle) { // (and must be done before the session actually starts). func (a *agent) fetchServiceBannerLoop(ctx context.Context, conn drpc.Conn) error { aAPI := proto.NewDRPCAgentClient(conn) - ticker := time.NewTicker(a.notificationBannersRefreshInterval) + ticker := time.NewTicker(a.announcementBannersRefreshInterval) defer ticker.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-ticker.C: - bannersProto, err := aAPI.GetNotificationBanners(ctx, &proto.GetNotificationBannersRequest{}) + bannersProto, err := aAPI.GetAnnouncementBanners(ctx, &proto.GetAnnouncementBannersRequest{}) if err != nil { if ctx.Err() != nil { return ctx.Err() @@ -724,11 +724,11 @@ func (a *agent) fetchServiceBannerLoop(ctx context.Context, conn drpc.Conn) erro a.logger.Error(ctx, "failed to update notification banners", slog.Error(err)) return err } - banners := make([]codersdk.BannerConfig, 0, len(bannersProto.NotificationBanners)) - for _, bannerProto := range bannersProto.NotificationBanners { + banners := make([]codersdk.BannerConfig, 0, len(bannersProto.AnnouncementBanners)) + for _, bannerProto := range bannersProto.AnnouncementBanners { banners = append(banners, agentsdk.BannerConfigFromProto(bannerProto)) } - a.notificationBanners.Store(&banners) + a.announcementBanners.Store(&banners) } } } @@ -763,15 +763,15 @@ func (a *agent) run() (retErr error) { connMan.start("init notification banners", gracefulShutdownBehaviorStop, func(ctx context.Context, conn drpc.Conn) error { aAPI := proto.NewDRPCAgentClient(conn) - bannersProto, err := aAPI.GetNotificationBanners(ctx, &proto.GetNotificationBannersRequest{}) + bannersProto, err := aAPI.GetAnnouncementBanners(ctx, &proto.GetAnnouncementBannersRequest{}) if err != nil { return xerrors.Errorf("fetch service banner: %w", err) } - banners := make([]codersdk.BannerConfig, 0, len(bannersProto.NotificationBanners)) - for _, bannerProto := range bannersProto.NotificationBanners { + banners := make([]codersdk.BannerConfig, 0, len(bannersProto.AnnouncementBanners)) + for _, bannerProto := range bannersProto.AnnouncementBanners { banners = append(banners, agentsdk.BannerConfigFromProto(bannerProto)) } - a.notificationBanners.Store(&banners) + a.announcementBanners.Store(&banners) return nil }, ) diff --git a/agent/agent_test.go b/agent/agent_test.go index c674a29ec35f6..a008a60a2362e 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -614,7 +614,7 @@ func TestAgent_Session_TTY_MOTD_Update(t *testing.T) { // Set new banner func and wait for the agent to call it to update the // banner. ready := make(chan struct{}, 2) - client.SetNotificationBannersFunc(func() ([]codersdk.BannerConfig, error) { + client.SetAnnouncementBannersFunc(func() ([]codersdk.BannerConfig, error) { select { case ready <- struct{}{}: default: @@ -2200,7 +2200,7 @@ func setupSSHSession( ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() opts = append(opts, func(c *agenttest.Client, o *agent.Options) { - c.SetNotificationBannersFunc(func() ([]codersdk.BannerConfig, error) { + c.SetAnnouncementBannersFunc(func() ([]codersdk.BannerConfig, error) { return []codersdk.BannerConfig{banner}, nil }) }) diff --git a/agent/agentssh/agentssh.go b/agent/agentssh/agentssh.go index 4fcc6ab869c5b..54e5a3f41223e 100644 --- a/agent/agentssh/agentssh.go +++ b/agent/agentssh/agentssh.go @@ -63,7 +63,7 @@ type Config struct { // file will be displayed to the user upon login. MOTDFile func() string // ServiceBanner returns the configuration for the Coder service banner. - NotificationBanners func() *[]codersdk.BannerConfig + AnnouncementBanners func() *[]codersdk.BannerConfig // UpdateEnv updates the environment variables for the command to be // executed. It can be used to add, modify or replace environment variables. UpdateEnv func(current []string) (updated []string, err error) @@ -123,8 +123,8 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom if config.MOTDFile == nil { config.MOTDFile = func() string { return "" } } - if config.NotificationBanners == nil { - config.NotificationBanners = func() *[]codersdk.BannerConfig { return &[]codersdk.BannerConfig{} } + if config.AnnouncementBanners == nil { + config.AnnouncementBanners = func() *[]codersdk.BannerConfig { return &[]codersdk.BannerConfig{} } } if config.WorkingDirectory == nil { config.WorkingDirectory = func() string { @@ -441,13 +441,13 @@ func (s *Server) startPTYSession(logger slog.Logger, session ptySession, magicTy session.DisablePTYEmulation() if isLoginShell(session.RawCommand()) { - banners := s.config.NotificationBanners() + banners := s.config.AnnouncementBanners() if banners != nil { for _, banner := range *banners { - err := showNotificationBanner(session, banner) + err := showAnnouncementBanner(session, banner) if err != nil { - logger.Error(ctx, "agent failed to show service banner", slog.Error(err)) - s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "notification_banner").Add(1) + logger.Error(ctx, "agent failed to show announcement banner", slog.Error(err)) + s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "announcement_banner").Add(1) break } } @@ -894,9 +894,9 @@ func isQuietLogin(fs afero.Fs, rawCommand string) bool { return err == nil } -// showNotificationBanner will write the service banner if enabled and not blank +// showAnnouncementBanner will write the service banner if enabled and not blank // along with a blank line for spacing. -func showNotificationBanner(session io.Writer, banner codersdk.BannerConfig) error { +func showAnnouncementBanner(session io.Writer, banner codersdk.BannerConfig) error { if banner.Enabled && banner.Message != "" { // The banner supports Markdown so we might want to parse it but Markdown is // still fairly readable in its raw form. diff --git a/agent/agenttest/client.go b/agent/agenttest/client.go index b21a7444c6084..3a4fa4de60b26 100644 --- a/agent/agenttest/client.go +++ b/agent/agenttest/client.go @@ -138,8 +138,8 @@ func (c *Client) GetStartupLogs() []agentsdk.Log { return c.logs } -func (c *Client) SetNotificationBannersFunc(f func() ([]codersdk.ServiceBannerConfig, error)) { - c.fakeAgentAPI.SetNotificationBannersFunc(f) +func (c *Client) SetAnnouncementBannersFunc(f func() ([]codersdk.BannerConfig, error)) { + c.fakeAgentAPI.SetAnnouncementBannersFunc(f) } func (c *Client) PushDERPMapUpdate(update *tailcfg.DERPMap) error { @@ -171,7 +171,7 @@ type FakeAgentAPI struct { lifecycleStates []codersdk.WorkspaceAgentLifecycle metadata map[string]agentsdk.Metadata - getNotificationBannersFunc func() ([]codersdk.BannerConfig, error) + getAnnouncementBannersFunc func() ([]codersdk.BannerConfig, error) } func (f *FakeAgentAPI) GetManifest(context.Context, *agentproto.GetManifestRequest) (*agentproto.Manifest, error) { @@ -182,20 +182,20 @@ func (*FakeAgentAPI) GetServiceBanner(context.Context, *agentproto.GetServiceBan return &agentproto.ServiceBanner{}, nil } -func (f *FakeAgentAPI) SetNotificationBannersFunc(fn func() ([]codersdk.BannerConfig, error)) { +func (f *FakeAgentAPI) SetAnnouncementBannersFunc(fn func() ([]codersdk.BannerConfig, error)) { f.Lock() defer f.Unlock() - f.getNotificationBannersFunc = fn + f.getAnnouncementBannersFunc = fn f.logger.Info(context.Background(), "updated notification banners") } -func (f *FakeAgentAPI) GetNotificationBanners(context.Context, *agentproto.GetNotificationBannersRequest) (*agentproto.GetNotificationBannersResponse, error) { +func (f *FakeAgentAPI) GetAnnouncementBanners(context.Context, *agentproto.GetAnnouncementBannersRequest) (*agentproto.GetAnnouncementBannersResponse, error) { f.Lock() defer f.Unlock() - if f.getNotificationBannersFunc == nil { - return &agentproto.GetNotificationBannersResponse{NotificationBanners: []*agentproto.BannerConfig{}}, nil + if f.getAnnouncementBannersFunc == nil { + return &agentproto.GetAnnouncementBannersResponse{AnnouncementBanners: []*agentproto.BannerConfig{}}, nil } - banners, err := f.getNotificationBannersFunc() + banners, err := f.getAnnouncementBannersFunc() if err != nil { return nil, err } @@ -203,7 +203,7 @@ func (f *FakeAgentAPI) GetNotificationBanners(context.Context, *agentproto.GetNo for _, banner := range banners { bannersProto = append(bannersProto, agentsdk.ProtoFromBannerConfig(banner)) } - return &agentproto.GetNotificationBannersResponse{NotificationBanners: bannersProto}, nil + return &agentproto.GetAnnouncementBannersResponse{AnnouncementBanners: bannersProto}, nil } func (f *FakeAgentAPI) UpdateStats(ctx context.Context, req *agentproto.UpdateStatsRequest) (*agentproto.UpdateStatsResponse, error) { diff --git a/agent/proto/agent.pb.go b/agent/proto/agent.pb.go index 41e8d061054a5..35e62ace80ce5 100644 --- a/agent/proto/agent.pb.go +++ b/agent/proto/agent.pb.go @@ -1859,14 +1859,14 @@ func (x *BatchCreateLogsResponse) GetLogLimitExceeded() bool { return false } -type GetNotificationBannersRequest struct { +type GetAnnouncementBannersRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *GetNotificationBannersRequest) Reset() { - *x = GetNotificationBannersRequest{} +func (x *GetAnnouncementBannersRequest) Reset() { + *x = GetAnnouncementBannersRequest{} if protoimpl.UnsafeEnabled { mi := &file_agent_proto_agent_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1874,13 +1874,13 @@ func (x *GetNotificationBannersRequest) Reset() { } } -func (x *GetNotificationBannersRequest) String() string { +func (x *GetAnnouncementBannersRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetNotificationBannersRequest) ProtoMessage() {} +func (*GetAnnouncementBannersRequest) ProtoMessage() {} -func (x *GetNotificationBannersRequest) ProtoReflect() protoreflect.Message { +func (x *GetAnnouncementBannersRequest) ProtoReflect() protoreflect.Message { mi := &file_agent_proto_agent_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1892,21 +1892,21 @@ func (x *GetNotificationBannersRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetNotificationBannersRequest.ProtoReflect.Descriptor instead. -func (*GetNotificationBannersRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetAnnouncementBannersRequest.ProtoReflect.Descriptor instead. +func (*GetAnnouncementBannersRequest) Descriptor() ([]byte, []int) { return file_agent_proto_agent_proto_rawDescGZIP(), []int{22} } -type GetNotificationBannersResponse struct { +type GetAnnouncementBannersResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - NotificationBanners []*BannerConfig `protobuf:"bytes,1,rep,name=notification_banners,json=notificationBanners,proto3" json:"notification_banners,omitempty"` + AnnouncementBanners []*BannerConfig `protobuf:"bytes,1,rep,name=announcement_banners,json=announcementBanners,proto3" json:"announcement_banners,omitempty"` } -func (x *GetNotificationBannersResponse) Reset() { - *x = GetNotificationBannersResponse{} +func (x *GetAnnouncementBannersResponse) Reset() { + *x = GetAnnouncementBannersResponse{} if protoimpl.UnsafeEnabled { mi := &file_agent_proto_agent_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1914,13 +1914,13 @@ func (x *GetNotificationBannersResponse) Reset() { } } -func (x *GetNotificationBannersResponse) String() string { +func (x *GetAnnouncementBannersResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetNotificationBannersResponse) ProtoMessage() {} +func (*GetAnnouncementBannersResponse) ProtoMessage() {} -func (x *GetNotificationBannersResponse) ProtoReflect() protoreflect.Message { +func (x *GetAnnouncementBannersResponse) ProtoReflect() protoreflect.Message { mi := &file_agent_proto_agent_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1932,14 +1932,14 @@ func (x *GetNotificationBannersResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetNotificationBannersResponse.ProtoReflect.Descriptor instead. -func (*GetNotificationBannersResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetAnnouncementBannersResponse.ProtoReflect.Descriptor instead. +func (*GetAnnouncementBannersResponse) Descriptor() ([]byte, []int) { return file_agent_proto_agent_proto_rawDescGZIP(), []int{23} } -func (x *GetNotificationBannersResponse) GetNotificationBanners() []*BannerConfig { +func (x *GetAnnouncementBannersResponse) GetAnnouncementBanners() []*BannerConfig { if x != nil { - return x.NotificationBanners + return x.AnnouncementBanners } return nil } @@ -2742,16 +2742,16 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6c, 0x6f, 0x67, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x63, 0x65, - 0x65, 0x64, 0x65, 0x64, 0x22, 0x1f, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x71, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x14, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x18, + 0x65, 0x64, 0x65, 0x64, 0x22, 0x1f, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, + 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x71, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, + 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x14, 0x61, 0x6e, 0x6e, 0x6f, 0x75, + 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x13, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x6d, 0x0a, 0x0c, 0x42, 0x61, 0x6e, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x13, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x6d, 0x0a, 0x0c, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, @@ -2812,13 +2812,13 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x12, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, + 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, - 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, - 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x67, 0x65, 0x6e, @@ -2869,8 +2869,8 @@ var file_agent_proto_agent_proto_goTypes = []interface{}{ (*Log)(nil), // 26: coder.agent.v2.Log (*BatchCreateLogsRequest)(nil), // 27: coder.agent.v2.BatchCreateLogsRequest (*BatchCreateLogsResponse)(nil), // 28: coder.agent.v2.BatchCreateLogsResponse - (*GetNotificationBannersRequest)(nil), // 29: coder.agent.v2.GetNotificationBannersRequest - (*GetNotificationBannersResponse)(nil), // 30: coder.agent.v2.GetNotificationBannersResponse + (*GetAnnouncementBannersRequest)(nil), // 29: coder.agent.v2.GetAnnouncementBannersRequest + (*GetAnnouncementBannersResponse)(nil), // 30: coder.agent.v2.GetAnnouncementBannersResponse (*BannerConfig)(nil), // 31: coder.agent.v2.BannerConfig (*WorkspaceApp_Healthcheck)(nil), // 32: coder.agent.v2.WorkspaceApp.Healthcheck (*WorkspaceAgentMetadata_Result)(nil), // 33: coder.agent.v2.WorkspaceAgentMetadata.Result @@ -2911,7 +2911,7 @@ var file_agent_proto_agent_proto_depIdxs = []int32{ 42, // 23: coder.agent.v2.Log.created_at:type_name -> google.protobuf.Timestamp 6, // 24: coder.agent.v2.Log.level:type_name -> coder.agent.v2.Log.Level 26, // 25: coder.agent.v2.BatchCreateLogsRequest.logs:type_name -> coder.agent.v2.Log - 31, // 26: coder.agent.v2.GetNotificationBannersResponse.notification_banners:type_name -> coder.agent.v2.BannerConfig + 31, // 26: coder.agent.v2.GetAnnouncementBannersResponse.announcement_banners:type_name -> coder.agent.v2.BannerConfig 40, // 27: coder.agent.v2.WorkspaceApp.Healthcheck.interval:type_name -> google.protobuf.Duration 42, // 28: coder.agent.v2.WorkspaceAgentMetadata.Result.collected_at:type_name -> google.protobuf.Timestamp 40, // 29: coder.agent.v2.WorkspaceAgentMetadata.Description.interval:type_name -> google.protobuf.Duration @@ -2927,7 +2927,7 @@ var file_agent_proto_agent_proto_depIdxs = []int32{ 22, // 39: coder.agent.v2.Agent.UpdateStartup:input_type -> coder.agent.v2.UpdateStartupRequest 24, // 40: coder.agent.v2.Agent.BatchUpdateMetadata:input_type -> coder.agent.v2.BatchUpdateMetadataRequest 27, // 41: coder.agent.v2.Agent.BatchCreateLogs:input_type -> coder.agent.v2.BatchCreateLogsRequest - 29, // 42: coder.agent.v2.Agent.GetNotificationBanners:input_type -> coder.agent.v2.GetNotificationBannersRequest + 29, // 42: coder.agent.v2.Agent.GetAnnouncementBanners:input_type -> coder.agent.v2.GetAnnouncementBannersRequest 10, // 43: coder.agent.v2.Agent.GetManifest:output_type -> coder.agent.v2.Manifest 12, // 44: coder.agent.v2.Agent.GetServiceBanner:output_type -> coder.agent.v2.ServiceBanner 16, // 45: coder.agent.v2.Agent.UpdateStats:output_type -> coder.agent.v2.UpdateStatsResponse @@ -2936,7 +2936,7 @@ var file_agent_proto_agent_proto_depIdxs = []int32{ 21, // 48: coder.agent.v2.Agent.UpdateStartup:output_type -> coder.agent.v2.Startup 25, // 49: coder.agent.v2.Agent.BatchUpdateMetadata:output_type -> coder.agent.v2.BatchUpdateMetadataResponse 28, // 50: coder.agent.v2.Agent.BatchCreateLogs:output_type -> coder.agent.v2.BatchCreateLogsResponse - 30, // 51: coder.agent.v2.Agent.GetNotificationBanners:output_type -> coder.agent.v2.GetNotificationBannersResponse + 30, // 51: coder.agent.v2.Agent.GetAnnouncementBanners:output_type -> coder.agent.v2.GetAnnouncementBannersResponse 43, // [43:52] is the sub-list for method output_type 34, // [34:43] is the sub-list for method input_type 34, // [34:34] is the sub-list for extension type_name @@ -3215,7 +3215,7 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetNotificationBannersRequest); i { + switch v := v.(*GetAnnouncementBannersRequest); i { case 0: return &v.state case 1: @@ -3227,7 +3227,7 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetNotificationBannersResponse); i { + switch v := v.(*GetAnnouncementBannersResponse); i { case 0: return &v.state case 1: diff --git a/agent/proto/agent.proto b/agent/proto/agent.proto index 8432fe8ef7f2b..4548ed8e7f2de 100644 --- a/agent/proto/agent.proto +++ b/agent/proto/agent.proto @@ -251,10 +251,10 @@ message BatchCreateLogsResponse { bool log_limit_exceeded = 1; } -message GetNotificationBannersRequest {} +message GetAnnouncementBannersRequest {} -message GetNotificationBannersResponse { - repeated BannerConfig notification_banners = 1; +message GetAnnouncementBannersResponse { + repeated BannerConfig announcement_banners = 1; } message BannerConfig { @@ -272,5 +272,5 @@ service Agent { rpc UpdateStartup(UpdateStartupRequest) returns (Startup); rpc BatchUpdateMetadata(BatchUpdateMetadataRequest) returns (BatchUpdateMetadataResponse); rpc BatchCreateLogs(BatchCreateLogsRequest) returns (BatchCreateLogsResponse); - rpc GetNotificationBanners(GetNotificationBannersRequest) returns (GetNotificationBannersResponse); + rpc GetAnnouncementBanners(GetAnnouncementBannersRequest) returns (GetAnnouncementBannersResponse); } diff --git a/agent/proto/agent_drpc.pb.go b/agent/proto/agent_drpc.pb.go index 0003a1fa4568a..09b3c972c2ce6 100644 --- a/agent/proto/agent_drpc.pb.go +++ b/agent/proto/agent_drpc.pb.go @@ -46,7 +46,7 @@ type DRPCAgentClient interface { UpdateStartup(ctx context.Context, in *UpdateStartupRequest) (*Startup, error) BatchUpdateMetadata(ctx context.Context, in *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) BatchCreateLogs(ctx context.Context, in *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) - GetNotificationBanners(ctx context.Context, in *GetNotificationBannersRequest) (*GetNotificationBannersResponse, error) + GetAnnouncementBanners(ctx context.Context, in *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) } type drpcAgentClient struct { @@ -131,9 +131,9 @@ func (c *drpcAgentClient) BatchCreateLogs(ctx context.Context, in *BatchCreateLo return out, nil } -func (c *drpcAgentClient) GetNotificationBanners(ctx context.Context, in *GetNotificationBannersRequest) (*GetNotificationBannersResponse, error) { - out := new(GetNotificationBannersResponse) - err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/GetNotificationBanners", drpcEncoding_File_agent_proto_agent_proto{}, in, out) +func (c *drpcAgentClient) GetAnnouncementBanners(ctx context.Context, in *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) { + out := new(GetAnnouncementBannersResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/GetAnnouncementBanners", drpcEncoding_File_agent_proto_agent_proto{}, in, out) if err != nil { return nil, err } @@ -149,7 +149,7 @@ type DRPCAgentServer interface { UpdateStartup(context.Context, *UpdateStartupRequest) (*Startup, error) BatchUpdateMetadata(context.Context, *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) BatchCreateLogs(context.Context, *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) - GetNotificationBanners(context.Context, *GetNotificationBannersRequest) (*GetNotificationBannersResponse, error) + GetAnnouncementBanners(context.Context, *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) } type DRPCAgentUnimplementedServer struct{} @@ -186,7 +186,7 @@ func (s *DRPCAgentUnimplementedServer) BatchCreateLogs(context.Context, *BatchCr return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } -func (s *DRPCAgentUnimplementedServer) GetNotificationBanners(context.Context, *GetNotificationBannersRequest) (*GetNotificationBannersResponse, error) { +func (s *DRPCAgentUnimplementedServer) GetAnnouncementBanners(context.Context, *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) { return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } @@ -269,14 +269,14 @@ func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, ) }, DRPCAgentServer.BatchCreateLogs, true case 8: - return "/coder.agent.v2.Agent/GetNotificationBanners", drpcEncoding_File_agent_proto_agent_proto{}, + return "/coder.agent.v2.Agent/GetAnnouncementBanners", drpcEncoding_File_agent_proto_agent_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return srv.(DRPCAgentServer). - GetNotificationBanners( + GetAnnouncementBanners( ctx, - in1.(*GetNotificationBannersRequest), + in1.(*GetAnnouncementBannersRequest), ) - }, DRPCAgentServer.GetNotificationBanners, true + }, DRPCAgentServer.GetAnnouncementBanners, true default: return "", nil, nil, nil, false } @@ -414,16 +414,16 @@ func (x *drpcAgent_BatchCreateLogsStream) SendAndClose(m *BatchCreateLogsRespons return x.CloseSend() } -type DRPCAgent_GetNotificationBannersStream interface { +type DRPCAgent_GetAnnouncementBannersStream interface { drpc.Stream - SendAndClose(*GetNotificationBannersResponse) error + SendAndClose(*GetAnnouncementBannersResponse) error } -type drpcAgent_GetNotificationBannersStream struct { +type drpcAgent_GetAnnouncementBannersStream struct { drpc.Stream } -func (x *drpcAgent_GetNotificationBannersStream) SendAndClose(m *GetNotificationBannersResponse) error { +func (x *drpcAgent_GetAnnouncementBannersStream) SendAndClose(m *GetAnnouncementBannersResponse) error { if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { return err } diff --git a/coderd/agentapi/notification_banners.go b/coderd/agentapi/announcement_banners.go similarity index 63% rename from coderd/agentapi/notification_banners.go rename to coderd/agentapi/announcement_banners.go index ab4e7dda96741..8eebb9ae0c9ea 100644 --- a/coderd/agentapi/notification_banners.go +++ b/coderd/agentapi/announcement_banners.go @@ -11,12 +11,12 @@ import ( "github.com/coder/coder/v2/codersdk/agentsdk" ) -type NotificationBannerAPI struct { +type AnnouncementBannerAPI struct { appearanceFetcher *atomic.Pointer[appearance.Fetcher] } -// Deprecated: GetServiceBanner has been deprecated in favor of GetNotificationBanners. -func (a *NotificationBannerAPI) GetServiceBanner(ctx context.Context, _ *proto.GetServiceBannerRequest) (*proto.ServiceBanner, error) { +// Deprecated: GetServiceBanner has been deprecated in favor of GetAnnouncementBanners. +func (a *AnnouncementBannerAPI) GetServiceBanner(ctx context.Context, _ *proto.GetServiceBannerRequest) (*proto.ServiceBanner, error) { cfg, err := (*a.appearanceFetcher.Load()).Fetch(ctx) if err != nil { return nil, xerrors.Errorf("fetch appearance: %w", err) @@ -24,16 +24,16 @@ func (a *NotificationBannerAPI) GetServiceBanner(ctx context.Context, _ *proto.G return agentsdk.ProtoFromServiceBanner(cfg.ServiceBanner), nil } -func (a *NotificationBannerAPI) GetNotificationBanners(ctx context.Context, _ *proto.GetNotificationBannersRequest) (*proto.GetNotificationBannersResponse, error) { +func (a *AnnouncementBannerAPI) GetAnnouncementBanners(ctx context.Context, _ *proto.GetAnnouncementBannersRequest) (*proto.GetAnnouncementBannersResponse, error) { cfg, err := (*a.appearanceFetcher.Load()).Fetch(ctx) if err != nil { return nil, xerrors.Errorf("fetch appearance: %w", err) } - banners := make([]*proto.BannerConfig, 0, len(cfg.NotificationBanners)) - for _, banner := range cfg.NotificationBanners { + banners := make([]*proto.BannerConfig, 0, len(cfg.AnnouncementBanners)) + for _, banner := range cfg.AnnouncementBanners { banners = append(banners, agentsdk.ProtoFromBannerConfig(banner)) } - return &proto.GetNotificationBannersResponse{ - NotificationBanners: banners, + return &proto.GetAnnouncementBannersResponse{ + AnnouncementBanners: banners, }, nil } diff --git a/coderd/agentapi/notification_banners_internal_test.go b/coderd/agentapi/announcement_banners_internal_test.go similarity index 68% rename from coderd/agentapi/notification_banners_internal_test.go rename to coderd/agentapi/announcement_banners_internal_test.go index 87f4df2d21764..145459a7c636e 100644 --- a/coderd/agentapi/notification_banners_internal_test.go +++ b/coderd/agentapi/announcement_banners_internal_test.go @@ -14,7 +14,7 @@ import ( "github.com/coder/coder/v2/codersdk/agentsdk" ) -func TestGetNotificationBanners(t *testing.T) { +func TestGetAnnouncementBanners(t *testing.T) { t.Parallel() t.Run("OK", func(t *testing.T) { @@ -26,15 +26,15 @@ func TestGetNotificationBanners(t *testing.T) { BackgroundColor: "#00FF00", }} - var ff appearance.Fetcher = fakeFetcher{cfg: codersdk.AppearanceConfig{NotificationBanners: cfg}} + var ff appearance.Fetcher = fakeFetcher{cfg: codersdk.AppearanceConfig{AnnouncementBanners: cfg}} ptr := atomic.Pointer[appearance.Fetcher]{} ptr.Store(&ff) - api := &NotificationBannerAPI{appearanceFetcher: &ptr} - resp, err := api.GetNotificationBanners(context.Background(), &agentproto.GetNotificationBannersRequest{}) + api := &AnnouncementBannerAPI{appearanceFetcher: &ptr} + resp, err := api.GetAnnouncementBanners(context.Background(), &agentproto.GetAnnouncementBannersRequest{}) require.NoError(t, err) - require.Len(t, resp.NotificationBanners, 1) - require.Equal(t, cfg[0], agentsdk.BannerConfigFromProto(resp.NotificationBanners[0])) + require.Len(t, resp.AnnouncementBanners, 1) + require.Equal(t, cfg[0], agentsdk.BannerConfigFromProto(resp.AnnouncementBanners[0])) }) t.Run("FetchError", func(t *testing.T) { @@ -45,8 +45,8 @@ func TestGetNotificationBanners(t *testing.T) { ptr := atomic.Pointer[appearance.Fetcher]{} ptr.Store(&ff) - api := &NotificationBannerAPI{appearanceFetcher: &ptr} - resp, err := api.GetNotificationBanners(context.Background(), &agentproto.GetNotificationBannersRequest{}) + api := &AnnouncementBannerAPI{appearanceFetcher: &ptr} + resp, err := api.GetAnnouncementBanners(context.Background(), &agentproto.GetAnnouncementBannersRequest{}) require.Error(t, err) require.ErrorIs(t, err, expectedErr) require.Nil(t, resp) diff --git a/coderd/agentapi/api.go b/coderd/agentapi/api.go index b8b07672d6aa2..ae0d594314e66 100644 --- a/coderd/agentapi/api.go +++ b/coderd/agentapi/api.go @@ -36,7 +36,7 @@ import ( type API struct { opts Options *ManifestAPI - *NotificationBannerAPI + *AnnouncementBannerAPI *StatsAPI *LifecycleAPI *AppsAPI @@ -108,7 +108,7 @@ func New(opts Options) *API { }, } - api.NotificationBannerAPI = &NotificationBannerAPI{ + api.AnnouncementBannerAPI = &AnnouncementBannerAPI{ appearanceFetcher: opts.AppearanceFetcher, } diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index f373e0079a780..a284e46d0a0bb 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -8378,20 +8378,20 @@ const docTemplate = `{ "codersdk.AppearanceConfig": { "type": "object", "properties": { + "announcement_banners": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.BannerConfig" + } + }, "application_name": { "type": "string" }, "logo_url": { "type": "string" }, - "notification_banners": { - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.BannerConfig" - } - }, "service_banner": { - "description": "Deprecated: ServiceBanner has been replaced by NotificationBanners.", + "description": "Deprecated: ServiceBanner has been replaced by AnnouncementBanners.", "allOf": [ { "$ref": "#/definitions/codersdk.BannerConfig" @@ -12148,20 +12148,20 @@ const docTemplate = `{ "codersdk.UpdateAppearanceConfig": { "type": "object", "properties": { + "announcement_banners": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.BannerConfig" + } + }, "application_name": { "type": "string" }, "logo_url": { "type": "string" }, - "notification_banners": { - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.BannerConfig" - } - }, "service_banner": { - "description": "Deprecated: ServiceBanner has been replaced by NotificationBanners.", + "description": "Deprecated: ServiceBanner has been replaced by AnnouncementBanners.", "allOf": [ { "$ref": "#/definitions/codersdk.BannerConfig" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 84bb41c44fcdd..28212bdaa8342 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -7433,20 +7433,20 @@ "codersdk.AppearanceConfig": { "type": "object", "properties": { + "announcement_banners": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.BannerConfig" + } + }, "application_name": { "type": "string" }, "logo_url": { "type": "string" }, - "notification_banners": { - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.BannerConfig" - } - }, "service_banner": { - "description": "Deprecated: ServiceBanner has been replaced by NotificationBanners.", + "description": "Deprecated: ServiceBanner has been replaced by AnnouncementBanners.", "allOf": [ { "$ref": "#/definitions/codersdk.BannerConfig" @@ -10997,20 +10997,20 @@ "codersdk.UpdateAppearanceConfig": { "type": "object", "properties": { + "announcement_banners": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.BannerConfig" + } + }, "application_name": { "type": "string" }, "logo_url": { "type": "string" }, - "notification_banners": { - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.BannerConfig" - } - }, "service_banner": { - "description": "Deprecated: ServiceBanner has been replaced by NotificationBanners.", + "description": "Deprecated: ServiceBanner has been replaced by AnnouncementBanners.", "allOf": [ { "$ref": "#/definitions/codersdk.BannerConfig" diff --git a/coderd/appearance/appearance.go b/coderd/appearance/appearance.go index f9809036ec84b..9b45884ce115e 100644 --- a/coderd/appearance/appearance.go +++ b/coderd/appearance/appearance.go @@ -32,7 +32,7 @@ type AGPLFetcher struct{} func (AGPLFetcher) Fetch(context.Context) (codersdk.AppearanceConfig, error) { return codersdk.AppearanceConfig{ - NotificationBanners: []codersdk.BannerConfig{}, + AnnouncementBanners: []codersdk.BannerConfig{}, SupportLinks: DefaultSupportLinks, }, nil } diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index ec9d14bb57de6..3a814cfed88d2 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1142,6 +1142,11 @@ func (q *querier) GetAllTailnetTunnels(ctx context.Context) ([]database.TailnetT return q.db.GetAllTailnetTunnels(ctx) } +func (q *querier) GetAnnouncementBanners(ctx context.Context) (string, error) { + // No authz checks + return q.db.GetAnnouncementBanners(ctx) +} + func (q *querier) GetAppSecurityKey(ctx context.Context) (string, error) { // No authz checks return q.db.GetAppSecurityKey(ctx) @@ -1359,11 +1364,6 @@ func (q *querier) GetLogoURL(ctx context.Context) (string, error) { return q.db.GetLogoURL(ctx) } -func (q *querier) GetNotificationBanners(ctx context.Context) (string, error) { - // No authz checks - return q.db.GetNotificationBanners(ctx) -} - func (q *querier) GetOAuth2ProviderAppByID(ctx context.Context, id uuid.UUID) (database.OAuth2ProviderApp, error) { if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceOauth2App); err != nil { return database.OAuth2ProviderApp{}, err @@ -3405,6 +3405,13 @@ func (q *querier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Cont return fetchAndExec(q.log, q.auth, policy.ActionUpdate, fetch, q.db.UpdateWorkspacesDormantDeletingAtByTemplateID)(ctx, arg) } +func (q *querier) UpsertAnnouncementBanners(ctx context.Context, value string) error { + if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceDeploymentConfig); err != nil { + return err + } + return q.db.UpsertAnnouncementBanners(ctx, value) +} + func (q *querier) UpsertAppSecurityKey(ctx context.Context, data string) error { // No authz checks as this is done during startup return q.db.UpsertAppSecurityKey(ctx, data) @@ -3538,13 +3545,6 @@ func (q *querier) UpsertLogoURL(ctx context.Context, value string) error { return q.db.UpsertLogoURL(ctx, value) } -func (q *querier) UpsertNotificationBanners(ctx context.Context, value string) error { - if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceDeploymentConfig); err != nil { - return err - } - return q.db.UpsertNotificationBanners(ctx, value) -} - func (q *querier) UpsertOAuthSigningKey(ctx context.Context, value string) error { if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil { return err diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 8e84f4644b91e..9507e1b83c00e 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -528,7 +528,7 @@ func (s *MethodTestSuite) TestLicense() { s.Run("UpsertLogoURL", s.Subtest(func(db database.Store, check *expects) { check.Args("value").Asserts(rbac.ResourceDeploymentConfig, policy.ActionUpdate) })) - s.Run("UpsertNotificationBanners", s.Subtest(func(db database.Store, check *expects) { + s.Run("UpsertAnnouncementBanners", s.Subtest(func(db database.Store, check *expects) { check.Args("value").Asserts(rbac.ResourceDeploymentConfig, policy.ActionUpdate) })) s.Run("GetLicenseByID", s.Subtest(func(db database.Store, check *expects) { @@ -559,8 +559,8 @@ func (s *MethodTestSuite) TestLicense() { require.NoError(s.T(), err) check.Args().Asserts().Returns("value") })) - s.Run("GetNotificationBanners", s.Subtest(func(db database.Store, check *expects) { - err := db.UpsertNotificationBanners(context.Background(), "value") + s.Run("GetAnnouncementBanners", s.Subtest(func(db database.Store, check *expects) { + err := db.UpsertAnnouncementBanners(context.Background(), "value") require.NoError(s.T(), err) check.Args().Asserts().Returns("value") })) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index e9497880b274c..fe9b56e35ebdb 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -191,7 +191,7 @@ type data struct { deploymentID string derpMeshKey string lastUpdateCheck []byte - notificationBanners []byte + announcementBanners []byte healthSettings []byte applicationName string logoURL string @@ -1857,6 +1857,17 @@ func (*FakeQuerier) GetAllTailnetTunnels(context.Context) ([]database.TailnetTun return nil, ErrUnimplemented } +func (q *FakeQuerier) GetAnnouncementBanners(_ context.Context) (string, error) { + q.mutex.RLock() + defer q.mutex.RUnlock() + + if q.announcementBanners == nil { + return "", sql.ErrNoRows + } + + return string(q.announcementBanners), nil +} + func (q *FakeQuerier) GetAppSecurityKey(_ context.Context) (string, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -2540,17 +2551,6 @@ func (q *FakeQuerier) GetLogoURL(_ context.Context) (string, error) { return q.logoURL, nil } -func (q *FakeQuerier) GetNotificationBanners(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.notificationBanners == nil { - return "", sql.ErrNoRows - } - - return string(q.notificationBanners), nil -} - func (q *FakeQuerier) GetOAuth2ProviderAppByID(_ context.Context, id uuid.UUID) (database.OAuth2ProviderApp, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -8358,6 +8358,14 @@ func (q *FakeQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(_ context.Co return nil } +func (q *FakeQuerier) UpsertAnnouncementBanners(_ context.Context, data string) error { + q.mutex.RLock() + defer q.mutex.RUnlock() + + q.announcementBanners = []byte(data) + return nil +} + func (q *FakeQuerier) UpsertAppSecurityKey(_ context.Context, data string) error { q.mutex.Lock() defer q.mutex.Unlock() @@ -8472,14 +8480,6 @@ func (q *FakeQuerier) UpsertLogoURL(_ context.Context, data string) error { return nil } -func (q *FakeQuerier) UpsertNotificationBanners(_ context.Context, data string) error { - q.mutex.RLock() - defer q.mutex.RUnlock() - - q.notificationBanners = []byte(data) - return nil -} - func (q *FakeQuerier) UpsertOAuthSigningKey(_ context.Context, value string) error { q.mutex.Lock() defer q.mutex.Unlock() diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index bb5a38ef82c61..aff562fcdb89f 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -431,6 +431,13 @@ func (m metricsStore) GetAllTailnetTunnels(ctx context.Context) ([]database.Tail return r0, r1 } +func (m metricsStore) GetAnnouncementBanners(ctx context.Context) (string, error) { + start := time.Now() + r0, r1 := m.s.GetAnnouncementBanners(ctx) + m.queryLatencies.WithLabelValues("GetAnnouncementBanners").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m metricsStore) GetAppSecurityKey(ctx context.Context) (string, error) { start := time.Now() key, err := m.s.GetAppSecurityKey(ctx) @@ -662,13 +669,6 @@ func (m metricsStore) GetLogoURL(ctx context.Context) (string, error) { return url, err } -func (m metricsStore) GetNotificationBanners(ctx context.Context) (string, error) { - start := time.Now() - r0, r1 := m.s.GetNotificationBanners(ctx) - m.queryLatencies.WithLabelValues("GetNotificationBanners").Observe(time.Since(start).Seconds()) - return r0, r1 -} - func (m metricsStore) GetOAuth2ProviderAppByID(ctx context.Context, id uuid.UUID) (database.OAuth2ProviderApp, error) { start := time.Now() r0, r1 := m.s.GetOAuth2ProviderAppByID(ctx, id) @@ -2174,6 +2174,13 @@ func (m metricsStore) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context. return r0 } +func (m metricsStore) UpsertAnnouncementBanners(ctx context.Context, value string) error { + start := time.Now() + r0 := m.s.UpsertAnnouncementBanners(ctx, value) + m.queryLatencies.WithLabelValues("UpsertAnnouncementBanners").Observe(time.Since(start).Seconds()) + return r0 +} + func (m metricsStore) UpsertAppSecurityKey(ctx context.Context, value string) error { start := time.Now() r0 := m.s.UpsertAppSecurityKey(ctx, value) @@ -2230,13 +2237,6 @@ func (m metricsStore) UpsertLogoURL(ctx context.Context, value string) error { return r0 } -func (m metricsStore) UpsertNotificationBanners(ctx context.Context, value string) error { - start := time.Now() - r0 := m.s.UpsertNotificationBanners(ctx, value) - m.queryLatencies.WithLabelValues("UpsertNotificationBanners").Observe(time.Since(start).Seconds()) - return r0 -} - func (m metricsStore) UpsertOAuthSigningKey(ctx context.Context, value string) error { start := time.Now() r0 := m.s.UpsertOAuthSigningKey(ctx, value) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 90d7a20eb6ff8..3ef96d13f8b33 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -764,6 +764,21 @@ func (mr *MockStoreMockRecorder) GetAllTailnetTunnels(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllTailnetTunnels", reflect.TypeOf((*MockStore)(nil).GetAllTailnetTunnels), arg0) } +// GetAnnouncementBanners mocks base method. +func (m *MockStore) GetAnnouncementBanners(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAnnouncementBanners", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAnnouncementBanners indicates an expected call of GetAnnouncementBanners. +func (mr *MockStoreMockRecorder) GetAnnouncementBanners(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAnnouncementBanners", reflect.TypeOf((*MockStore)(nil).GetAnnouncementBanners), arg0) +} + // GetAppSecurityKey mocks base method. func (m *MockStore) GetAppSecurityKey(arg0 context.Context) (string, error) { m.ctrl.T.Helper() @@ -1304,21 +1319,6 @@ func (mr *MockStoreMockRecorder) GetLogoURL(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogoURL", reflect.TypeOf((*MockStore)(nil).GetLogoURL), arg0) } -// GetNotificationBanners mocks base method. -func (m *MockStore) GetNotificationBanners(arg0 context.Context) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetNotificationBanners", arg0) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetNotificationBanners indicates an expected call of GetNotificationBanners. -func (mr *MockStoreMockRecorder) GetNotificationBanners(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNotificationBanners", reflect.TypeOf((*MockStore)(nil).GetNotificationBanners), arg0) -} - // GetOAuth2ProviderAppByID mocks base method. func (m *MockStore) GetOAuth2ProviderAppByID(arg0 context.Context, arg1 uuid.UUID) (database.OAuth2ProviderApp, error) { m.ctrl.T.Helper() @@ -4553,6 +4553,20 @@ func (mr *MockStoreMockRecorder) UpdateWorkspacesDormantDeletingAtByTemplateID(a return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspacesDormantDeletingAtByTemplateID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspacesDormantDeletingAtByTemplateID), arg0, arg1) } +// UpsertAnnouncementBanners mocks base method. +func (m *MockStore) UpsertAnnouncementBanners(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpsertAnnouncementBanners", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpsertAnnouncementBanners indicates an expected call of UpsertAnnouncementBanners. +func (mr *MockStoreMockRecorder) UpsertAnnouncementBanners(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertAnnouncementBanners", reflect.TypeOf((*MockStore)(nil).UpsertAnnouncementBanners), arg0, arg1) +} + // UpsertAppSecurityKey mocks base method. func (m *MockStore) UpsertAppSecurityKey(arg0 context.Context, arg1 string) error { m.ctrl.T.Helper() @@ -4666,20 +4680,6 @@ func (mr *MockStoreMockRecorder) UpsertLogoURL(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertLogoURL", reflect.TypeOf((*MockStore)(nil).UpsertLogoURL), arg0, arg1) } -// UpsertNotificationBanners mocks base method. -func (m *MockStore) UpsertNotificationBanners(arg0 context.Context, arg1 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpsertNotificationBanners", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpsertNotificationBanners indicates an expected call of UpsertNotificationBanners. -func (mr *MockStoreMockRecorder) UpsertNotificationBanners(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertNotificationBanners", reflect.TypeOf((*MockStore)(nil).UpsertNotificationBanners), arg0, arg1) -} - // UpsertOAuthSigningKey mocks base method. func (m *MockStore) UpsertOAuthSigningKey(arg0 context.Context, arg1 string) error { m.ctrl.T.Helper() diff --git a/coderd/database/migrations/000213_announcement_banners.down.sql b/coderd/database/migrations/000213_announcement_banners.down.sql new file mode 100644 index 0000000000000..0ec90c4a9e05a --- /dev/null +++ b/coderd/database/migrations/000213_announcement_banners.down.sql @@ -0,0 +1,3 @@ +update site_configs SET + key = 'notification_banners' + where key = 'announcement_banners'; diff --git a/coderd/database/migrations/000213_announcement_banners.up.sql b/coderd/database/migrations/000213_announcement_banners.up.sql new file mode 100644 index 0000000000000..a76e4b6f25629 --- /dev/null +++ b/coderd/database/migrations/000213_announcement_banners.up.sql @@ -0,0 +1,3 @@ +update site_configs SET + key = 'announcement_banners' + where key = 'notification_banners'; diff --git a/coderd/database/querier.go b/coderd/database/querier.go index a590ae87bc8fd..6e2b1ff60cfdf 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -97,6 +97,7 @@ type sqlcQuerier interface { GetAllTailnetCoordinators(ctx context.Context) ([]TailnetCoordinator, error) GetAllTailnetPeers(ctx context.Context) ([]TailnetPeer, error) GetAllTailnetTunnels(ctx context.Context) ([]TailnetTunnel, error) + GetAnnouncementBanners(ctx context.Context) (string, error) GetAppSecurityKey(ctx context.Context) (string, error) GetApplicationName(ctx context.Context) (string, error) // GetAuditLogsBefore retrieves `row_limit` number of audit logs before the provided @@ -137,7 +138,6 @@ type sqlcQuerier interface { GetLicenseByID(ctx context.Context, id int32) (License, error) GetLicenses(ctx context.Context) ([]License, error) GetLogoURL(ctx context.Context) (string, error) - GetNotificationBanners(ctx context.Context) (string, error) GetOAuth2ProviderAppByID(ctx context.Context, id uuid.UUID) (OAuth2ProviderApp, error) GetOAuth2ProviderAppCodeByID(ctx context.Context, id uuid.UUID) (OAuth2ProviderAppCode, error) GetOAuth2ProviderAppCodeByPrefix(ctx context.Context, secretPrefix []byte) (OAuth2ProviderAppCode, error) @@ -416,6 +416,7 @@ type sqlcQuerier interface { UpdateWorkspaceProxyDeleted(ctx context.Context, arg UpdateWorkspaceProxyDeletedParams) error UpdateWorkspaceTTL(ctx context.Context, arg UpdateWorkspaceTTLParams) error UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg UpdateWorkspacesDormantDeletingAtByTemplateIDParams) error + UpsertAnnouncementBanners(ctx context.Context, value string) error UpsertAppSecurityKey(ctx context.Context, value string) error UpsertApplicationName(ctx context.Context, value string) error UpsertCustomRole(ctx context.Context, arg UpsertCustomRoleParams) (CustomRole, error) @@ -427,7 +428,6 @@ type sqlcQuerier interface { UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg UpsertJFrogXrayScanByWorkspaceAndAgentIDParams) error UpsertLastUpdateCheck(ctx context.Context, value string) error UpsertLogoURL(ctx context.Context, value string) error - UpsertNotificationBanners(ctx context.Context, value string) error UpsertOAuthSigningKey(ctx context.Context, value string) error UpsertProvisionerDaemon(ctx context.Context, arg UpsertProvisionerDaemonParams) (ProvisionerDaemon, error) UpsertTailnetAgent(ctx context.Context, arg UpsertTailnetAgentParams) (TailnetAgent, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index bcc961c88e048..56fcfaf998e4f 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -5727,6 +5727,17 @@ func (q *sqlQuerier) UpsertCustomRole(ctx context.Context, arg UpsertCustomRoleP return i, err } +const getAnnouncementBanners = `-- name: GetAnnouncementBanners :one +SELECT value FROM site_configs WHERE key = 'announcement_banners' +` + +func (q *sqlQuerier) GetAnnouncementBanners(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getAnnouncementBanners) + var value string + err := row.Scan(&value) + return value, err +} + const getAppSecurityKey = `-- name: GetAppSecurityKey :one SELECT value FROM site_configs WHERE key = 'app_signing_key' ` @@ -5823,17 +5834,6 @@ func (q *sqlQuerier) GetLogoURL(ctx context.Context) (string, error) { return value, err } -const getNotificationBanners = `-- name: GetNotificationBanners :one -SELECT value FROM site_configs WHERE key = 'notification_banners' -` - -func (q *sqlQuerier) GetNotificationBanners(ctx context.Context) (string, error) { - row := q.db.QueryRowContext(ctx, getNotificationBanners) - var value string - err := row.Scan(&value) - return value, err -} - const getOAuthSigningKey = `-- name: GetOAuthSigningKey :one SELECT value FROM site_configs WHERE key = 'oauth_signing_key' ` @@ -5863,6 +5863,16 @@ func (q *sqlQuerier) InsertDeploymentID(ctx context.Context, value string) error return err } +const upsertAnnouncementBanners = `-- name: UpsertAnnouncementBanners :exec +INSERT INTO site_configs (key, value) VALUES ('announcement_banners', $1) +ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'announcement_banners' +` + +func (q *sqlQuerier) UpsertAnnouncementBanners(ctx context.Context, value string) error { + _, err := q.db.ExecContext(ctx, upsertAnnouncementBanners, value) + return err +} + const upsertAppSecurityKey = `-- name: UpsertAppSecurityKey :exec INSERT INTO site_configs (key, value) VALUES ('app_signing_key', $1) ON CONFLICT (key) DO UPDATE set value = $1 WHERE site_configs.key = 'app_signing_key' @@ -5936,16 +5946,6 @@ func (q *sqlQuerier) UpsertLogoURL(ctx context.Context, value string) error { return err } -const upsertNotificationBanners = `-- name: UpsertNotificationBanners :exec -INSERT INTO site_configs (key, value) VALUES ('notification_banners', $1) -ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'notification_banners' -` - -func (q *sqlQuerier) UpsertNotificationBanners(ctx context.Context, value string) error { - _, err := q.db.ExecContext(ctx, upsertNotificationBanners, value) - return err -} - const upsertOAuthSigningKey = `-- name: UpsertOAuthSigningKey :exec INSERT INTO site_configs (key, value) VALUES ('oauth_signing_key', $1) ON CONFLICT (key) DO UPDATE set value = $1 WHERE site_configs.key = 'oauth_signing_key' diff --git a/coderd/database/queries/siteconfig.sql b/coderd/database/queries/siteconfig.sql index b827c6e19e959..2b56a6d1455af 100644 --- a/coderd/database/queries/siteconfig.sql +++ b/coderd/database/queries/siteconfig.sql @@ -36,12 +36,12 @@ ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'last_update -- name: GetLastUpdateCheck :one SELECT value FROM site_configs WHERE key = 'last_update_check'; --- name: UpsertNotificationBanners :exec -INSERT INTO site_configs (key, value) VALUES ('notification_banners', $1) -ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'notification_banners'; +-- name: UpsertAnnouncementBanners :exec +INSERT INTO site_configs (key, value) VALUES ('announcement_banners', $1) +ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'announcement_banners'; --- name: GetNotificationBanners :one -SELECT value FROM site_configs WHERE key = 'notification_banners'; +-- name: GetAnnouncementBanners :one +SELECT value FROM site_configs WHERE key = 'announcement_banners'; -- name: UpsertLogoURL :exec INSERT INTO site_configs (key, value) VALUES ('logo_url', $1) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index dd52cae77d1b4..c89a78668637d 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -2105,18 +2105,18 @@ func (c *Client) DeploymentStats(ctx context.Context) (DeploymentStats, error) { type AppearanceConfig struct { ApplicationName string `json:"application_name"` LogoURL string `json:"logo_url"` - // Deprecated: ServiceBanner has been replaced by NotificationBanners. + // Deprecated: ServiceBanner has been replaced by AnnouncementBanners. ServiceBanner BannerConfig `json:"service_banner"` - NotificationBanners []BannerConfig `json:"notification_banners"` + AnnouncementBanners []BannerConfig `json:"announcement_banners"` SupportLinks []LinkConfig `json:"support_links,omitempty"` } type UpdateAppearanceConfig struct { ApplicationName string `json:"application_name"` LogoURL string `json:"logo_url"` - // Deprecated: ServiceBanner has been replaced by NotificationBanners. + // Deprecated: ServiceBanner has been replaced by AnnouncementBanners. ServiceBanner BannerConfig `json:"service_banner"` - NotificationBanners []BannerConfig `json:"notification_banners"` + AnnouncementBanners []BannerConfig `json:"announcement_banners"` } // Deprecated: ServiceBannerConfig has been renamed to BannerConfig. diff --git a/docs/api/enterprise.md b/docs/api/enterprise.md index 800e9e517196d..3cf43102e7c77 100644 --- a/docs/api/enterprise.md +++ b/docs/api/enterprise.md @@ -19,15 +19,15 @@ curl -X GET http://coder-server:8080/api/v2/appearance \ ```json { - "application_name": "string", - "logo_url": "string", - "notification_banners": [ + "announcement_banners": [ { "background_color": "string", "enabled": true, "message": "string" } ], + "application_name": "string", + "logo_url": "string", "service_banner": { "background_color": "string", "enabled": true, @@ -69,15 +69,15 @@ curl -X PUT http://coder-server:8080/api/v2/appearance \ ```json { - "application_name": "string", - "logo_url": "string", - "notification_banners": [ + "announcement_banners": [ { "background_color": "string", "enabled": true, "message": "string" } ], + "application_name": "string", + "logo_url": "string", "service_banner": { "background_color": "string", "enabled": true, @@ -98,15 +98,15 @@ curl -X PUT http://coder-server:8080/api/v2/appearance \ ```json { - "application_name": "string", - "logo_url": "string", - "notification_banners": [ + "announcement_banners": [ { "background_color": "string", "enabled": true, "message": "string" } ], + "application_name": "string", + "logo_url": "string", "service_banner": { "background_color": "string", "enabled": true, diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 978da35a58d02..82804508b0e96 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -749,15 +749,15 @@ ```json { - "application_name": "string", - "logo_url": "string", - "notification_banners": [ + "announcement_banners": [ { "background_color": "string", "enabled": true, "message": "string" } ], + "application_name": "string", + "logo_url": "string", "service_banner": { "background_color": "string", "enabled": true, @@ -777,10 +777,10 @@ | Name | Type | Required | Restrictions | Description | | ---------------------- | ------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------- | +| `announcement_banners` | array of [codersdk.BannerConfig](#codersdkbannerconfig) | false | | | | `application_name` | string | false | | | | `logo_url` | string | false | | | -| `notification_banners` | array of [codersdk.BannerConfig](#codersdkbannerconfig) | false | | | -| `service_banner` | [codersdk.BannerConfig](#codersdkbannerconfig) | false | | Deprecated: ServiceBanner has been replaced by NotificationBanners. | +| `service_banner` | [codersdk.BannerConfig](#codersdkbannerconfig) | false | | Deprecated: ServiceBanner has been replaced by AnnouncementBanners. | | `support_links` | array of [codersdk.LinkConfig](#codersdklinkconfig) | false | | | ## codersdk.ArchiveTemplateVersionsRequest @@ -5301,15 +5301,15 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o ```json { - "application_name": "string", - "logo_url": "string", - "notification_banners": [ + "announcement_banners": [ { "background_color": "string", "enabled": true, "message": "string" } ], + "application_name": "string", + "logo_url": "string", "service_banner": { "background_color": "string", "enabled": true, @@ -5322,10 +5322,10 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o | Name | Type | Required | Restrictions | Description | | ---------------------- | ------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------- | +| `announcement_banners` | array of [codersdk.BannerConfig](#codersdkbannerconfig) | false | | | | `application_name` | string | false | | | | `logo_url` | string | false | | | -| `notification_banners` | array of [codersdk.BannerConfig](#codersdkbannerconfig) | false | | | -| `service_banner` | [codersdk.BannerConfig](#codersdkbannerconfig) | false | | Deprecated: ServiceBanner has been replaced by NotificationBanners. | +| `service_banner` | [codersdk.BannerConfig](#codersdkbannerconfig) | false | | Deprecated: ServiceBanner has been replaced by AnnouncementBanners. | ## codersdk.UpdateCheckResponse diff --git a/enterprise/coderd/appearance.go b/enterprise/coderd/appearance.go index 8a9d51cdb9070..b53c812c3e748 100644 --- a/enterprise/coderd/appearance.go +++ b/enterprise/coderd/appearance.go @@ -58,7 +58,7 @@ func (f *appearanceFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfi var ( applicationName string logoURL string - notificationBannersJSON string + announcementBannersJSON string ) eg.Go(func() (err error) { applicationName, err = f.database.GetApplicationName(ctx) @@ -75,7 +75,7 @@ func (f *appearanceFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfi return nil }) eg.Go(func() (err error) { - notificationBannersJSON, err = f.database.GetNotificationBanners(ctx) + announcementBannersJSON, err = f.database.GetAnnouncementBanners(ctx) if err != nil && !errors.Is(err, sql.ErrNoRows) { return xerrors.Errorf("get notification banners: %w", err) } @@ -89,22 +89,22 @@ func (f *appearanceFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfi cfg := codersdk.AppearanceConfig{ ApplicationName: applicationName, LogoURL: logoURL, - NotificationBanners: []codersdk.BannerConfig{}, + AnnouncementBanners: []codersdk.BannerConfig{}, SupportLinks: agpl.DefaultSupportLinks, } - if notificationBannersJSON != "" { - err = json.Unmarshal([]byte(notificationBannersJSON), &cfg.NotificationBanners) + if announcementBannersJSON != "" { + err = json.Unmarshal([]byte(announcementBannersJSON), &cfg.AnnouncementBanners) if err != nil { return codersdk.AppearanceConfig{}, xerrors.Errorf( - "unmarshal notification banners json: %w, raw: %s", err, notificationBannersJSON, + "unmarshal announcement banners json: %w, raw: %s", err, announcementBannersJSON, ) } // Redundant, but improves compatibility with slightly mismatched agent versions. // Maybe we can remove this after a grace period? -Kayla, May 6th 2024 - if len(cfg.NotificationBanners) > 0 { - cfg.ServiceBanner = cfg.NotificationBanners[0] + if len(cfg.AnnouncementBanners) > 0 { + cfg.ServiceBanner = cfg.AnnouncementBanners[0] } } if len(f.supportLinks) > 0 { @@ -149,7 +149,7 @@ func (api *API) putAppearance(rw http.ResponseWriter, r *http.Request) { return } - for _, banner := range appearance.NotificationBanners { + for _, banner := range appearance.AnnouncementBanners { if err := validateHexColor(banner.BackgroundColor); err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: fmt.Sprintf("Invalid color format: %q", banner.BackgroundColor), @@ -159,22 +159,22 @@ func (api *API) putAppearance(rw http.ResponseWriter, r *http.Request) { } } - if appearance.NotificationBanners == nil { - appearance.NotificationBanners = []codersdk.BannerConfig{} + if appearance.AnnouncementBanners == nil { + appearance.AnnouncementBanners = []codersdk.BannerConfig{} } - notificationBannersJSON, err := json.Marshal(appearance.NotificationBanners) + announcementBannersJSON, err := json.Marshal(appearance.AnnouncementBanners) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Unable to marshal notification banners", + Message: "Unable to marshal announcement banners", Detail: err.Error(), }) return } - err = api.Database.UpsertNotificationBanners(ctx, string(notificationBannersJSON)) + err = api.Database.UpsertAnnouncementBanners(ctx, string(announcementBannersJSON)) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Unable to set notification banners", + Message: "Unable to set announcement banners", Detail: err.Error(), }) return diff --git a/enterprise/coderd/appearance_test.go b/enterprise/coderd/appearance_test.go index 745f90e00d03b..0e2358e1eef58 100644 --- a/enterprise/coderd/appearance_test.go +++ b/enterprise/coderd/appearance_test.go @@ -55,7 +55,7 @@ func TestCustomLogoAndCompanyName(t *testing.T) { require.Equal(t, uac.LogoURL, got.LogoURL) } -func TestNotificationBanners(t *testing.T) { +func TestAnnouncementBanners(t *testing.T) { t.Parallel() t.Run("User", func(t *testing.T) { @@ -70,7 +70,7 @@ func TestNotificationBanners(t *testing.T) { // Without a license, there should be no banners. sb, err := basicUserClient.Appearance(ctx) require.NoError(t, err) - require.Empty(t, sb.NotificationBanners) + require.Empty(t, sb.AnnouncementBanners) coderdenttest.AddLicense(t, adminClient, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -81,11 +81,11 @@ func TestNotificationBanners(t *testing.T) { // Default state sb, err = basicUserClient.Appearance(ctx) require.NoError(t, err) - require.Empty(t, sb.NotificationBanners) + require.Empty(t, sb.AnnouncementBanners) // Regular user should be unable to set the banner uac := codersdk.UpdateAppearanceConfig{ - NotificationBanners: []codersdk.BannerConfig{{Enabled: true}}, + AnnouncementBanners: []codersdk.BannerConfig{{Enabled: true}}, } err = basicUserClient.UpdateAppearance(ctx, uac) require.Error(t, err) @@ -96,7 +96,7 @@ func TestNotificationBanners(t *testing.T) { // But an admin can wantBanner := codersdk.UpdateAppearanceConfig{ - NotificationBanners: []codersdk.BannerConfig{{ + AnnouncementBanners: []codersdk.BannerConfig{{ Enabled: true, Message: "The beep-bop will be boop-beeped on Saturday at 12AM PST.", BackgroundColor: "#00FF00", @@ -106,10 +106,10 @@ func TestNotificationBanners(t *testing.T) { require.NoError(t, err) gotBanner, err := adminClient.Appearance(ctx) //nolint:gocritic // we should assert at least once that the owner can get the banner require.NoError(t, err) - require.Equal(t, wantBanner.NotificationBanners, gotBanner.NotificationBanners) + require.Equal(t, wantBanner.AnnouncementBanners, gotBanner.AnnouncementBanners) // But even an admin can't give a bad color - wantBanner.NotificationBanners[0].BackgroundColor = "#bad color" + wantBanner.AnnouncementBanners[0].BackgroundColor = "#bad color" err = adminClient.UpdateAppearance(ctx, wantBanner) require.Error(t, err) var sdkErr *codersdk.Error @@ -139,7 +139,7 @@ func TestNotificationBanners(t *testing.T) { }, }) cfg := codersdk.UpdateAppearanceConfig{ - NotificationBanners: []codersdk.BannerConfig{{ + AnnouncementBanners: []codersdk.BannerConfig{{ Enabled: true, Message: "The beep-bop will be boop-beeped on Saturday at 12AM PST.", BackgroundColor: "#00FF00", @@ -155,35 +155,35 @@ func TestNotificationBanners(t *testing.T) { agentClient := agentsdk.New(client.URL) agentClient.SetSessionToken(r.AgentToken) - banners := requireGetNotificationBanners(ctx, t, agentClient) - require.Equal(t, cfg.NotificationBanners, banners) + banners := requireGetAnnouncementBanners(ctx, t, agentClient) + require.Equal(t, cfg.AnnouncementBanners, banners) // Create an AGPL Coderd against the same database agplClient := coderdtest.New(t, &coderdtest.Options{Database: store, Pubsub: ps}) agplAgentClient := agentsdk.New(agplClient.URL) agplAgentClient.SetSessionToken(r.AgentToken) - banners = requireGetNotificationBanners(ctx, t, agplAgentClient) + banners = requireGetAnnouncementBanners(ctx, t, agplAgentClient) require.Equal(t, []codersdk.BannerConfig{}, banners) // No license means no banner. err = client.DeleteLicense(ctx, lic.ID) require.NoError(t, err) - banners = requireGetNotificationBanners(ctx, t, agentClient) + banners = requireGetAnnouncementBanners(ctx, t, agentClient) require.Equal(t, []codersdk.BannerConfig{}, banners) }) } -func requireGetNotificationBanners(ctx context.Context, t *testing.T, client *agentsdk.Client) []codersdk.BannerConfig { +func requireGetAnnouncementBanners(ctx context.Context, t *testing.T, client *agentsdk.Client) []codersdk.BannerConfig { cc, err := client.ConnectRPC(ctx) require.NoError(t, err) defer func() { _ = cc.Close() }() aAPI := proto.NewDRPCAgentClient(cc) - bannersProto, err := aAPI.GetNotificationBanners(ctx, &proto.GetNotificationBannersRequest{}) + bannersProto, err := aAPI.GetAnnouncementBanners(ctx, &proto.GetAnnouncementBannersRequest{}) require.NoError(t, err) - banners := make([]codersdk.BannerConfig, 0, len(bannersProto.NotificationBanners)) - for _, bannerProto := range bannersProto.NotificationBanners { + banners := make([]codersdk.BannerConfig, 0, len(bannersProto.AnnouncementBanners)) + for _, bannerProto := range bannersProto.AnnouncementBanners { banners = append(banners, agentsdk.BannerConfigFromProto(bannerProto)) } return banners diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 8baa6a5edfc1c..e2c94138a1d04 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1581,7 +1581,7 @@ class ApiMethods { return { application_name: "", logo_url: "", - notification_banners: [], + announcement_banners: [], service_banner: { enabled: false, }, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 171f6744680cb..88e5c7e508f67 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -49,7 +49,7 @@ export interface AppearanceConfig { readonly application_name: string; readonly logo_url: string; readonly service_banner: BannerConfig; - readonly notification_banners: readonly BannerConfig[]; + readonly announcement_banners: readonly BannerConfig[]; readonly support_links?: readonly LinkConfig[]; } @@ -1309,7 +1309,7 @@ export interface UpdateAppearanceConfig { readonly application_name: string; readonly logo_url: string; readonly service_banner: BannerConfig; - readonly notification_banners: readonly BannerConfig[]; + readonly announcement_banners: readonly BannerConfig[]; } // From codersdk/updatecheck.go diff --git a/site/src/modules/dashboard/NotificationBanners/NotificationBannerView.stories.tsx b/site/src/modules/dashboard/AnnouncementBanners/AnnouncementBannerView.stories.tsx similarity index 60% rename from site/src/modules/dashboard/NotificationBanners/NotificationBannerView.stories.tsx rename to site/src/modules/dashboard/AnnouncementBanners/AnnouncementBannerView.stories.tsx index ee5f8dece47ca..9515bd9f1cd46 100644 --- a/site/src/modules/dashboard/NotificationBanners/NotificationBannerView.stories.tsx +++ b/site/src/modules/dashboard/AnnouncementBanners/AnnouncementBannerView.stories.tsx @@ -1,13 +1,13 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { NotificationBannerView } from "./NotificationBannerView"; +import { AnnouncementBannerView } from "./AnnouncementBannerView"; -const meta: Meta = { - title: "modules/dashboard/NotificationBannerView", - component: NotificationBannerView, +const meta: Meta = { + title: "modules/dashboard/AnnouncementBannerView", + component: AnnouncementBannerView, }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Production: Story = { args: { diff --git a/site/src/modules/dashboard/NotificationBanners/NotificationBannerView.tsx b/site/src/modules/dashboard/AnnouncementBanners/AnnouncementBannerView.tsx similarity index 89% rename from site/src/modules/dashboard/NotificationBanners/NotificationBannerView.tsx rename to site/src/modules/dashboard/AnnouncementBanners/AnnouncementBannerView.tsx index 4832ea93f6065..91fe2276b6664 100644 --- a/site/src/modules/dashboard/NotificationBanners/NotificationBannerView.tsx +++ b/site/src/modules/dashboard/AnnouncementBanners/AnnouncementBannerView.tsx @@ -3,12 +3,12 @@ import type { FC } from "react"; import { InlineMarkdown } from "components/Markdown/Markdown"; import { readableForegroundColor } from "utils/colors"; -export interface NotificationBannerViewProps { +export interface AnnouncementBannerViewProps { message?: string; backgroundColor?: string; } -export const NotificationBannerView: FC = ({ +export const AnnouncementBannerView: FC = ({ message, backgroundColor, }) => { diff --git a/site/src/modules/dashboard/NotificationBanners/NotificationBanners.tsx b/site/src/modules/dashboard/AnnouncementBanners/AnnouncementBanners.tsx similarity index 69% rename from site/src/modules/dashboard/NotificationBanners/NotificationBanners.tsx rename to site/src/modules/dashboard/AnnouncementBanners/AnnouncementBanners.tsx index a8ab663721a46..5f1e32e3fd016 100644 --- a/site/src/modules/dashboard/NotificationBanners/NotificationBanners.tsx +++ b/site/src/modules/dashboard/AnnouncementBanners/AnnouncementBanners.tsx @@ -1,10 +1,10 @@ import type { FC } from "react"; import { useDashboard } from "modules/dashboard/useDashboard"; -import { NotificationBannerView } from "./NotificationBannerView"; +import { AnnouncementBannerView } from "./AnnouncementBannerView"; -export const NotificationBanners: FC = () => { +export const AnnouncementBanners: FC = () => { const { appearance, entitlements } = useDashboard(); - const notificationBanners = appearance.notification_banners; + const announcementBanners = appearance.announcement_banners; const isEntitled = entitlements.features.appearance.entitlement !== "not_entitled"; @@ -14,10 +14,10 @@ export const NotificationBanners: FC = () => { return ( <> - {notificationBanners + {announcementBanners .filter((banner) => banner.enabled) .map((banner) => ( - { return ( <> {canViewDeployment && } - +
= { - title: "pages/DeploySettingsPage/NotificationBannerDialog", - component: NotificationBannerDialog, +const meta: Meta = { + title: "pages/DeploySettingsPage/AnnouncementBannerDialog", + component: AnnouncementBannerDialog, args: { banner: { enabled: true, @@ -17,8 +17,8 @@ const meta: Meta = { }; export default meta; -type Story = StoryObj; +type Story = StoryObj; const Example: Story = {}; -export { Example as NotificationBannerDialog }; +export { Example as AnnouncementBannerDialog }; diff --git a/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerDialog.tsx b/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerDialog.tsx similarity index 92% rename from site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerDialog.tsx rename to site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerDialog.tsx index 6b5ffaf6fc27b..4664a5365fa44 100644 --- a/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerDialog.tsx +++ b/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerDialog.tsx @@ -7,16 +7,16 @@ import { BlockPicker } from "react-color"; import type { BannerConfig } from "api/typesGenerated"; import { Dialog, DialogActionButtons } from "components/Dialogs/Dialog"; import { Stack } from "components/Stack/Stack"; -import { NotificationBannerView } from "modules/dashboard/NotificationBanners/NotificationBannerView"; +import { AnnouncementBannerView } from "modules/dashboard/AnnouncementBanners/AnnouncementBannerView"; import { getFormHelpers } from "utils/formUtils"; -interface NotificationBannerDialogProps { +interface AnnouncementBannerDialogProps { banner: BannerConfig; onCancel: () => void; onUpdate: (banner: Partial) => Promise; } -export const NotificationBannerDialog: FC = ({ +export const AnnouncementBannerDialog: FC = ({ banner, onCancel, onUpdate, @@ -39,14 +39,14 @@ export const NotificationBannerDialog: FC = ({ {/* Banner preview */}
-
-

Notification banner

+

Announcement banner

Message

diff --git a/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerItem.tsx b/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerItem.tsx similarity index 94% rename from site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerItem.tsx rename to site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerItem.tsx index 76636a30c4492..7cd35969340b8 100644 --- a/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerItem.tsx +++ b/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerItem.tsx @@ -12,7 +12,7 @@ import { ThreeDotsButton, } from "components/MoreMenu/MoreMenu"; -interface NotificationBannerItemProps { +interface AnnouncementBannerItemProps { enabled: boolean; backgroundColor?: string; message?: string; @@ -21,7 +21,7 @@ interface NotificationBannerItemProps { onDelete: () => void; } -export const NotificationBannerItem: FC = ({ +export const AnnouncementBannerItem: FC = ({ enabled, backgroundColor = "#004852", message, diff --git a/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerSettings.tsx b/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerSettings.tsx similarity index 91% rename from site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerSettings.tsx rename to site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerSettings.tsx index d5611af119614..6d9b871ee24dd 100644 --- a/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/NotificationBannerSettings.tsx +++ b/site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AnnouncementBannerSettings.tsx @@ -13,20 +13,20 @@ import type { BannerConfig } from "api/typesGenerated"; import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog"; import { EmptyState } from "components/EmptyState/EmptyState"; import { Stack } from "components/Stack/Stack"; -import { NotificationBannerDialog } from "./NotificationBannerDialog"; -import { NotificationBannerItem } from "./NotificationBannerItem"; +import { AnnouncementBannerDialog } from "./AnnouncementBannerDialog"; +import { AnnouncementBannerItem } from "./AnnouncementBannerItem"; -interface NotificationBannerSettingsProps { +interface AnnouncementBannersettingsProps { isEntitled: boolean; - notificationBanners: readonly BannerConfig[]; + announcementBanners: readonly BannerConfig[]; onSubmit: (banners: readonly BannerConfig[]) => Promise; } -export const NotificationBannerSettings: FC< - NotificationBannerSettingsProps -> = ({ isEntitled, notificationBanners, onSubmit }) => { +export const AnnouncementBannerSettings: FC< + AnnouncementBannersettingsProps +> = ({ isEntitled, announcementBanners, onSubmit }) => { const theme = useTheme(); - const [banners, setBanners] = useState(notificationBanners); + const [banners, setBanners] = useState(announcementBanners); const [editingBannerId, setEditingBannerId] = useState(null); const [deletingBannerId, setDeletingBannerId] = useState(null); @@ -84,7 +84,7 @@ export const NotificationBannerSettings: FC< fontWeight: 600, }} > - Notification Banners + Announcement Banners