From 8520a8614cd2e84ae4c1c7002b3b8900765934f1 Mon Sep 17 00:00:00 2001 From: Ezequiel Victorero Date: Fri, 10 Feb 2023 15:01:26 -0300 Subject: [PATCH] PublicDashboards: add recipients to the public dashboards retrieval (#63149) --- pkg/server/wire.go | 1 - pkg/server/wireexts_oss.go | 4 ++ .../publicdashboards/api/query_test.go | 3 +- .../publicdashboards/models/models.go | 1 + .../public_dashboard_service_wrapper_mock.go | 53 +++++++++++++++++++ .../public_dashboard_store_mock.go | 2 +- .../publicdashboards/publicdashboard.go | 7 +++ .../publicdashboards/service/service.go | 22 +++----- .../publicdashboards/service/service_test.go | 18 ++++--- .../service/service_wapper.go | 45 ++++++++++++++++ .../SupportedPubdashDatasources.ts | 1 + 11 files changed, 134 insertions(+), 23 deletions(-) create mode 100644 pkg/services/publicdashboards/public_dashboard_service_wrapper_mock.go create mode 100644 pkg/services/publicdashboards/service/service_wapper.go diff --git a/pkg/server/wire.go b/pkg/server/wire.go index e071147f94e..f65d974bd3a 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -385,7 +385,6 @@ var wireTestSet = wire.NewSet( ProvideTestEnv, sqlstore.ProvideServiceForTests, ngmetrics.ProvideServiceForTest, - notifications.MockNotificationService, wire.Bind(new(notifications.Service), new(*notifications.NotificationServiceMock)), wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationServiceMock)), diff --git a/pkg/server/wireexts_oss.go b/pkg/server/wireexts_oss.go index 6ce8a35c7f4..98a89b73d54 100644 --- a/pkg/server/wireexts_oss.go +++ b/pkg/server/wireexts_oss.go @@ -28,6 +28,8 @@ import ( "github.com/grafana/grafana/pkg/services/login/authinfoservice" "github.com/grafana/grafana/pkg/services/pluginsintegration" "github.com/grafana/grafana/pkg/services/provisioning" + "github.com/grafana/grafana/pkg/services/publicdashboards" + publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service" "github.com/grafana/grafana/pkg/services/searchusers" "github.com/grafana/grafana/pkg/services/searchusers/filters" "github.com/grafana/grafana/pkg/services/sqlstore/migrations" @@ -80,6 +82,8 @@ var wireExtsBasicSet = wire.NewSet( ossaccesscontrol.ProvideDatasourcePermissionsService, wire.Bind(new(accesscontrol.DatasourcePermissionsService), new(*ossaccesscontrol.DatasourcePermissionsService)), pluginsintegration.WireExtensionSet, + publicdashboardsService.ProvideServiceWrapper, + wire.Bind(new(publicdashboards.ServiceWrapper), new(*publicdashboardsService.PublicDashboardServiceWrapperImpl)), ) var wireExtsSet = wire.NewSet( diff --git a/pkg/services/publicdashboards/api/query_test.go b/pkg/services/publicdashboards/api/query_test.go index cfc9a17bbe4..5db699d08c0 100644 --- a/pkg/services/publicdashboards/api/query_test.go +++ b/pkg/services/publicdashboards/api/query_test.go @@ -324,8 +324,9 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T) store := publicdashboardsStore.ProvideStore(db) cfg := setting.NewCfg() ac := acmock.New() + ws := &publicdashboards.FakePublicDashboardServiceWrapper{} cfg.RBACEnabled = false - service := publicdashboardsService.ProvideService(cfg, store, qds, annotationsService, ac) + service := publicdashboardsService.ProvideService(cfg, store, qds, annotationsService, ac, ws) pubdash, err := service.Create(context.Background(), &user.SignedInUser{}, savePubDashboardCmd) require.NoError(t, err) diff --git a/pkg/services/publicdashboards/models/models.go b/pkg/services/publicdashboards/models/models.go index 44d05ee9b3c..3615fdddb5a 100644 --- a/pkg/services/publicdashboards/models/models.go +++ b/pkg/services/publicdashboards/models/models.go @@ -49,6 +49,7 @@ type PublicDashboard struct { AnnotationsEnabled bool `json:"annotationsEnabled" xorm:"annotations_enabled"` TimeSelectionEnabled bool `json:"timeSelectionEnabled" xorm:"time_selection_enabled"` Share ShareType `json:"share" xorm:"share"` + Recipients []string `json:"recipients,omitempty" xorm:"-"` CreatedBy int64 `json:"createdBy" xorm:"created_by"` UpdatedBy int64 `json:"updatedBy" xorm:"updated_by"` CreatedAt time.Time `json:"createdAt" xorm:"created_at"` diff --git a/pkg/services/publicdashboards/public_dashboard_service_wrapper_mock.go b/pkg/services/publicdashboards/public_dashboard_service_wrapper_mock.go new file mode 100644 index 00000000000..fa33d059e6a --- /dev/null +++ b/pkg/services/publicdashboards/public_dashboard_service_wrapper_mock.go @@ -0,0 +1,53 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package publicdashboards + +import ( + context "context" + + models "github.com/grafana/grafana/pkg/services/publicdashboards/models" + mock "github.com/stretchr/testify/mock" +) + +// FakePublicDashboardServiceWrapper is an autogenerated mock type for the ServiceWrapper type +type FakePublicDashboardServiceWrapper struct { + mock.Mock +} + +// FindByDashboardUid provides a mock function with given fields: ctx, orgId, dashboardUid +func (_m *FakePublicDashboardServiceWrapper) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) { + ret := _m.Called(ctx, orgId, dashboardUid) + + var r0 *models.PublicDashboard + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *models.PublicDashboard); ok { + r0 = rf(ctx, orgId, dashboardUid) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.PublicDashboard) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, orgId, dashboardUid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewFakePublicDashboardServiceWrapper interface { + mock.TestingT + Cleanup(func()) +} + +// NewFakePublicDashboardServiceWrapper creates a new instance of FakePublicDashboardServiceWrapper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewFakePublicDashboardServiceWrapper(t mockConstructorTestingTNewFakePublicDashboardServiceWrapper) *FakePublicDashboardServiceWrapper { + mock := &FakePublicDashboardServiceWrapper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/services/publicdashboards/public_dashboard_store_mock.go b/pkg/services/publicdashboards/public_dashboard_store_mock.go index 16a79872fea..7e0bcdf3ae5 100644 --- a/pkg/services/publicdashboards/public_dashboard_store_mock.go +++ b/pkg/services/publicdashboards/public_dashboard_store_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.16.0. DO NOT EDIT. +// Code generated by mockery v2.14.0. DO NOT EDIT. package publicdashboards diff --git a/pkg/services/publicdashboards/publicdashboard.go b/pkg/services/publicdashboards/publicdashboard.go index 017c37f4152..404dc5501cf 100644 --- a/pkg/services/publicdashboards/publicdashboard.go +++ b/pkg/services/publicdashboards/publicdashboard.go @@ -36,6 +36,13 @@ type Service interface { ExistsEnabledByDashboardUid(ctx context.Context, dashboardUid string) (bool, error) } +// ServiceWrapper these methods have different behavior between OSS and Enterprise. The latter would call the OSS service first +// +//go:generate mockery --name ServiceWrapper --structname FakePublicDashboardServiceWrapper --inpackage --filename public_dashboard_service_wrapper_mock.go +type ServiceWrapper interface { + FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error) +} + //go:generate mockery --name Store --structname FakePublicDashboardStore --inpackage --filename public_dashboard_store_mock.go type Store interface { Find(ctx context.Context, uid string) (*PublicDashboard, error) diff --git a/pkg/services/publicdashboards/service/service.go b/pkg/services/publicdashboards/service/service.go index 79bca16642c..23fd5417843 100644 --- a/pkg/services/publicdashboards/service/service.go +++ b/pkg/services/publicdashboards/service/service.go @@ -33,6 +33,7 @@ type PublicDashboardServiceImpl struct { QueryDataService *query.Service AnnotationsRepo annotations.Repository ac accesscontrol.AccessControl + serviceWrapper publicdashboards.ServiceWrapper } var LogPrefix = "publicdashboards.service" @@ -49,6 +50,7 @@ func ProvideService( qds *query.Service, anno annotations.Repository, ac accesscontrol.AccessControl, + serviceWrapper publicdashboards.ServiceWrapper, ) *PublicDashboardServiceImpl { return &PublicDashboardServiceImpl{ log: log.New(LogPrefix), @@ -58,9 +60,15 @@ func ProvideService( QueryDataService: qds, AnnotationsRepo: anno, ac: ac, + serviceWrapper: serviceWrapper, } } +// FindByDashboardUid this method would be replaced by another implementation for Enterprise version +func (pd *PublicDashboardServiceImpl) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error) { + return pd.serviceWrapper.FindByDashboardUid(ctx, orgId, dashboardUid) +} + func (pd *PublicDashboardServiceImpl) Find(ctx context.Context, uid string) (*PublicDashboard, error) { pubdash, err := pd.store.Find(ctx, uid) if err != nil { @@ -120,20 +128,6 @@ func (pd *PublicDashboardServiceImpl) FindPublicDashboardAndDashboardByAccessTok return pubdash, dash, nil } -// FindByDashboardUid is a helper method to retrieve the public dashboard configuration for a given dashboard from the database -func (pd *PublicDashboardServiceImpl) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error) { - pubdash, err := pd.store.FindByDashboardUid(ctx, orgId, dashboardUid) - if err != nil { - return nil, ErrInternalServerError.Errorf("FindByDashboardUid: failed to find a public dashboard by orgId: %d and dashboardUid: %s: %w", orgId, dashboardUid, err) - } - - if pubdash == nil { - return nil, ErrPublicDashboardNotFound.Errorf("FindByDashboardUid: Public dashboard not found by orgId: %d and dashboardUid: %s", orgId, dashboardUid) - } - - return pubdash, nil -} - // Creates and validates the public dashboard and saves it to the database func (pd *PublicDashboardServiceImpl) Create(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error) { // ensure dashboard exists diff --git a/pkg/services/publicdashboards/service/service_test.go b/pkg/services/publicdashboards/service/service_test.go index fd8e26971ae..41f74436fc5 100644 --- a/pkg/services/publicdashboards/service/service_test.go +++ b/pkg/services/publicdashboards/service/service_test.go @@ -131,10 +131,12 @@ func TestCreatePublicDashboard(t *testing.T) { require.NoError(t, err) publicdashboardStore := database.ProvideStore(sqlStore) dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil) + serviceWrapper := ProvideServiceWrapper(publicdashboardStore) service := &PublicDashboardServiceImpl{ - log: log.New("test.logger"), - store: publicdashboardStore, + log: log.New("test.logger"), + store: publicdashboardStore, + serviceWrapper: serviceWrapper, } dto := &SavePublicDashboardDTO{ @@ -183,10 +185,12 @@ func TestCreatePublicDashboard(t *testing.T) { require.NoError(t, err) publicdashboardStore := database.ProvideStore(sqlStore) dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil) + serviceWrapper := ProvideServiceWrapper(publicdashboardStore) service := &PublicDashboardServiceImpl{ - log: log.New("test.logger"), - store: publicdashboardStore, + log: log.New("test.logger"), + store: publicdashboardStore, + serviceWrapper: serviceWrapper, } dto := &SavePublicDashboardDTO{ @@ -331,10 +335,12 @@ func TestCreatePublicDashboard(t *testing.T) { require.NoError(t, err) publicdashboardStore := database.ProvideStore(sqlStore) dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil) + serviceWrapper := ProvideServiceWrapper(publicdashboardStore) service := &PublicDashboardServiceImpl{ - log: log.New("test.logger"), - store: publicdashboardStore, + log: log.New("test.logger"), + store: publicdashboardStore, + serviceWrapper: serviceWrapper, } dto := &SavePublicDashboardDTO{ diff --git a/pkg/services/publicdashboards/service/service_wapper.go b/pkg/services/publicdashboards/service/service_wapper.go new file mode 100644 index 00000000000..c29919072c7 --- /dev/null +++ b/pkg/services/publicdashboards/service/service_wapper.go @@ -0,0 +1,45 @@ +package service + +import ( + "context" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/publicdashboards" + . "github.com/grafana/grafana/pkg/services/publicdashboards/models" +) + +// PublicDashboardServiceWrapperImpl Define the Service Implementation. We're generating mock implementation +// automatically +type PublicDashboardServiceWrapperImpl struct { + log log.Logger + store publicdashboards.Store +} + +// Gives us compile time error if the service does not adhere to the contract of +// the interface +var _ publicdashboards.ServiceWrapper = (*PublicDashboardServiceWrapperImpl)(nil) + +// ProvideServiceWrapper Factory for method used by wire to inject dependencies. +// builds the service, and api, and configures routes +func ProvideServiceWrapper( + store publicdashboards.Store, +) *PublicDashboardServiceWrapperImpl { + return &PublicDashboardServiceWrapperImpl{ + log: log.New(LogPrefix), + store: store, + } +} + +// FindByDashboardUid is a helper method to retrieve the public dashboard configuration for a given dashboard from the database +func (pd *PublicDashboardServiceWrapperImpl) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error) { + pubdash, err := pd.store.FindByDashboardUid(ctx, orgId, dashboardUid) + if err != nil { + return nil, ErrInternalServerError.Errorf("FindByDashboardUid: failed to find a public dashboard by orgId: %d and dashboardUid: %s: %w", orgId, dashboardUid, err) + } + + if pubdash == nil { + return nil, ErrPublicDashboardNotFound.Errorf("FindByDashboardUid: Public dashboard not found by orgId: %d and dashboardUid: %s", orgId, dashboardUid) + } + + return pubdash, nil +} diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SupportedPubdashDatasources.ts b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SupportedPubdashDatasources.ts index 63b05bf2347..11afee3e72f 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SupportedPubdashDatasources.ts +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SupportedPubdashDatasources.ts @@ -51,6 +51,7 @@ export const supportedDatasources = new Set([ 'marcusolsson-ynab-datasource', 'mssql', 'mysql', + 'nagasudhirpulla-api-datasource', 'opentsdb', 'postgres', 'prometheus',