backend/services: Move GetDashboard from sqlstore to dashboard service (#48971)

* rename folder to match package name
* backend/sqlstore: move GetDashboard into DashboardService

This is a stepping-stone commit which copies the GetDashboard function - which lets us remove the sqlstore from the interfaces in dashboards - without changing any other callers.
* checkpoint: moving GetDashboard calls into dashboard service
* finish refactoring api tests for dashboardService.GetDashboard
This commit is contained in:
Kristin Laemmert 2022-05-17 14:52:22 -04:00 committed by GitHub
parent 9af30f6570
commit 1df340ff28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 376 additions and 269 deletions

View File

@ -53,7 +53,7 @@ func (hs *HTTPServer) GetAnnotations(c *models.ReqContext) response.Response {
item.DashboardUID = val item.DashboardUID = val
} else { } else {
query := models.GetDashboardQuery{Id: item.DashboardId, OrgId: c.OrgId} query := models.GetDashboardQuery{Id: item.DashboardId, OrgId: c.OrgId}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err == nil && query.Result != nil { if err == nil && query.Result != nil {
item.DashboardUID = &query.Result.Uid item.DashboardUID = &query.Result.Uid
dashboardCache[item.DashboardId] = &query.Result.Uid dashboardCache[item.DashboardId] = &query.Result.Uid
@ -82,7 +82,7 @@ func (hs *HTTPServer) PostAnnotation(c *models.ReqContext) response.Response {
// overwrite dashboardId when dashboardUID is not empty // overwrite dashboardId when dashboardUID is not empty
if cmd.DashboardUID != "" { if cmd.DashboardUID != "" {
query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID} query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err == nil { if err == nil {
cmd.DashboardId = query.Result.Id cmd.DashboardId = query.Result.Id
} }
@ -291,7 +291,7 @@ func (hs *HTTPServer) MassDeleteAnnotations(c *models.ReqContext) response.Respo
if cmd.DashboardUID != "" { if cmd.DashboardUID != "" {
query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID} query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err == nil { if err == nil {
cmd.DashboardId = query.Result.Id cmd.DashboardId = query.Result.Id
} }

View File

@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
@ -221,10 +222,6 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
role := models.ROLE_ADMIN role := models.ROLE_ADMIN
mock := mockstore.NewSQLStoreMock() mock := mockstore.NewSQLStoreMock()
mock.ExpectedDashboard = &models.Dashboard{
Id: 1,
Uid: "home",
}
t.Run("Should be able to do anything", func(t *testing.T) { t.Run("Should be able to do anything", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, func(sc *scenarioContext) { postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, func(sc *scenarioContext) {
@ -327,6 +324,7 @@ func postAnnotationScenario(t *testing.T, desc string, url string, routePattern
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
hs.SQLStore = store hs.SQLStore = store
hs.dashboardService = &dashboards.FakeDashboardService{}
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
@ -411,6 +409,7 @@ func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePatte
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
hs.SQLStore = store hs.SQLStore = store
hs.dashboardService = &dashboards.FakeDashboardService{}
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {

View File

@ -11,6 +11,8 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/fs" "github.com/grafana/grafana/pkg/infra/fs"
@ -27,7 +29,7 @@ import (
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy" "github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashboardsstore "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardsstore "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/login/loginservice"
@ -41,7 +43,6 @@ import (
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
"github.com/grafana/grafana/pkg/web/webtest" "github.com/grafana/grafana/pkg/web/webtest"
"github.com/stretchr/testify/require"
) )
func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) { func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {

View File

@ -151,7 +151,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
// lookup folder title // lookup folder title
if dash.FolderId > 0 { if dash.FolderId > 0 {
query := models.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId} query := models.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId}
if err := hs.SQLStore.GetDashboard(c.Req.Context(), &query); err != nil { if err := hs.dashboardService.GetDashboard(c.Req.Context(), &query); err != nil {
if errors.Is(err, models.ErrFolderNotFound) { if errors.Is(err, models.ErrFolderNotFound) {
return response.Error(404, "Folder not found", err) return response.Error(404, "Folder not found", err)
} }
@ -242,7 +242,7 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in
query = models.GetDashboardQuery{Id: id, OrgId: orgID} query = models.GetDashboardQuery{Id: id, OrgId: orgID}
} }
if err := hs.SQLStore.GetDashboard(ctx, &query); err != nil { if err := hs.dashboardService.GetDashboard(ctx, &query); err != nil {
return nil, response.Error(404, "Dashboard not found", err) return nil, response.Error(404, "Dashboard not found", err)
} }
@ -531,7 +531,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *models.ReqContext) response.Respon
OrgId: c.SignedInUser.OrgId, OrgId: c.SignedInUser.OrgId,
Uid: dashUID, Uid: dashUID,
} }
if err := hs.SQLStore.GetDashboard(c.Req.Context(), &q); err != nil { if err := hs.dashboardService.GetDashboard(c.Req.Context(), &q); err != nil {
return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err) return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err)
} }
dashID = q.Result.Id dashID = q.Result.Id
@ -589,7 +589,7 @@ func (hs *HTTPServer) GetDashboardVersion(c *models.ReqContext) response.Respons
OrgId: c.SignedInUser.OrgId, OrgId: c.SignedInUser.OrgId,
Uid: dashUID, Uid: dashUID,
} }
if err := hs.SQLStore.GetDashboard(c.Req.Context(), &q); err != nil { if err := hs.dashboardService.GetDashboard(c.Req.Context(), &q); err != nil {
return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err) return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err)
} }
dashID = q.Result.Id dashID = q.Result.Id

View File

@ -15,7 +15,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
@ -26,6 +26,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
t.Run("Dashboard permissions test", func(t *testing.T) { t.Run("Dashboard permissions test", func(t *testing.T) {
settings := setting.NewCfg() settings := setting.NewCfg()
dashboardStore := &dashboards.FakeDashboardStore{} dashboardStore := &dashboards.FakeDashboardStore{}
dashboardStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(nil)
defer dashboardStore.AssertExpectations(t) defer dashboardStore.AssertExpectations(t)
features := featuremgmt.WithFeatures() features := featuremgmt.WithFeatures()

View File

@ -23,7 +23,7 @@ import (
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/dashboards/database"
service "github.com/grafana/grafana/pkg/services/dashboards/manager" service "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/libraryelements" "github.com/grafana/grafana/pkg/services/libraryelements"
@ -101,7 +101,7 @@ func newTestLive(t *testing.T, store *sqlstore.SQLStore) *live.GrafanaLive {
nil, nil,
&usagestats.UsageStatsMock{T: t}, &usagestats.UsageStatsMock{T: t},
nil, nil,
features, accesscontrolmock.New()) features, accesscontrolmock.New(), &dashboards.FakeDashboardService{})
require.NoError(t, err) require.NoError(t, err)
return gLive return gLive
} }
@ -118,9 +118,13 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.Id = 1 fakeDash.Id = 1
fakeDash.FolderId = 1 fakeDash.FolderId = 1
fakeDash.HasAcl = false fakeDash.HasAcl = false
dashboardService := &dashboards.FakeDashboardService{}
dashboardService.GetDashboardFn = func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
}
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
hs := &HTTPServer{ hs := &HTTPServer{
Cfg: setting.NewCfg(), Cfg: setting.NewCfg(),
@ -128,8 +132,8 @@ func TestDashboardAPIEndpoint(t *testing.T) {
SQLStore: mockSQLStore, SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(), AccessControl: accesscontrolmock.New(),
Features: featuremgmt.WithFeatures(), Features: featuremgmt.WithFeatures(),
dashboardService: dashboardService,
} }
hs.SQLStore = mockSQLStore
setUp := func() { setUp := func() {
viewerRole := models.ROLE_VIEWER viewerRole := models.ROLE_VIEWER
@ -153,7 +157,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc) dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.False(t, dash.Meta.CanEdit) assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave) assert.False(t, dash.Meta.CanSave)
@ -185,7 +189,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc) dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave) assert.True(t, dash.Meta.CanSave)
@ -216,14 +220,16 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.Id = 1 fakeDash.Id = 1
fakeDash.FolderId = 1 fakeDash.FolderId = 1
fakeDash.HasAcl = true fakeDash.HasAcl = true
dashboardService := &dashboards.FakeDashboardService{}
dashboardService.GetDashboardFn = func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
}
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
cfg := setting.NewCfg() cfg := setting.NewCfg()
features := featuremgmt.WithFeatures()
sql := sqlstore.InitTestDB(t) sql := sqlstore.InitTestDB(t)
dashboardStore := database.ProvideDashboardStore(sql)
hs := &HTTPServer{ hs := &HTTPServer{
Cfg: cfg, Cfg: cfg,
Live: newTestLive(t, sql), Live: newTestLive(t, sql),
@ -231,12 +237,8 @@ func TestDashboardAPIEndpoint(t *testing.T) {
LibraryElementService: &mockLibraryElementService{}, LibraryElementService: &mockLibraryElementService{},
SQLStore: mockSQLStore, SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(), AccessControl: accesscontrolmock.New(),
dashboardService: service.ProvideDashboardService( dashboardService: dashboardService,
cfg, dashboardStore, nil, features,
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
),
} }
hs.SQLStore = mockSQLStore
setUp := func() { setUp := func() {
origCanEdit := setting.ViewersCanEdit origCanEdit := setting.ViewersCanEdit
@ -281,7 +283,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
hs.callDeleteDashboardByUID(t, sc, nil) hs.callDeleteDashboardByUID(t, sc, &dashboards.FakeDashboardService{})
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
@ -319,7 +321,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
hs.callDeleteDashboardByUID(t, sc, nil) hs.callDeleteDashboardByUID(t, sc, &dashboards.FakeDashboardService{})
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
@ -357,7 +359,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc) dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave) assert.True(t, dash.Meta.CanSave)
@ -420,7 +422,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
require.True(t, setting.ViewersCanEdit) require.True(t, setting.ViewersCanEdit)
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc) dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave) assert.False(t, dash.Meta.CanSave)
@ -430,7 +432,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
hs.callDeleteDashboardByUID(t, sc, nil) hs.callDeleteDashboardByUID(t, sc, dashboardService)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
}) })
@ -450,7 +452,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc) dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave) assert.True(t, dash.Meta.CanSave)
@ -495,7 +497,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
sc.sqlStore = mockSQLStore sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc) dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.False(t, dash.Meta.CanEdit) assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave) assert.False(t, dash.Meta.CanSave)
@ -503,7 +505,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
hs.callDeleteDashboardByUID(t, sc, nil) hs.callDeleteDashboardByUID(t, sc, dashboardService)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
@ -780,13 +782,19 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.FolderId = folderID fakeDash.FolderId = folderID
fakeDash.HasAcl = false fakeDash.HasAcl = false
mock := &dashboards.FakeDashboardService{ saved := &models.Dashboard{
SaveDashboardResult: &models.Dashboard{
Id: 2, Id: 2,
Uid: "uid", Uid: "uid",
Title: "Dash", Title: "Dash",
Slug: "dash", Slug: "dash",
Version: 1, Version: 1,
}
mock := &dashboards.FakeDashboardService{
SaveDashboardResult: saved,
GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
}, },
} }
@ -794,7 +802,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Version: 1, Version: 1,
} }
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{ mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{
{ {
DashboardId: 2, DashboardId: 2,
@ -818,13 +825,19 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.Id = 2 fakeDash.Id = 2
fakeDash.HasAcl = false fakeDash.HasAcl = false
mock := &dashboards.FakeDashboardService{ saved := &models.Dashboard{
SaveDashboardResult: &models.Dashboard{
Id: 2, Id: 2,
Uid: "uid", Uid: "uid",
Title: "Dash", Title: "Dash",
Slug: "dash", Slug: "dash",
Version: 1, Version: 1,
}
mock := &dashboards.FakeDashboardService{
SaveDashboardResult: saved,
GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
}, },
} }
@ -832,7 +845,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Version: 1, Version: 1,
} }
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{ mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{
{ {
DashboardId: 2, DashboardId: 2,
@ -861,7 +873,12 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dataValue, err := simplejson.NewJson([]byte(`{"id": 1, "editable": true, "style": "dark"}`)) dataValue, err := simplejson.NewJson([]byte(`{"id": 1, "editable": true, "style": "dark"}`))
require.NoError(t, err) require.NoError(t, err)
mockSQLStore.ExpectedDashboard = &models.Dashboard{Id: 1, Data: dataValue} dashboardService := &dashboards.FakeDashboardService{
GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = &models.Dashboard{Id: 1, Data: dataValue}
return nil
},
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp() setUp()
@ -875,7 +892,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dashboardStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(&models.DashboardProvisioning{ExternalId: "/dashboard1.json"}, nil).Once() dashboardStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(&models.DashboardProvisioning{ExternalId: "/dashboard1.json"}, nil).Once()
dash := getDashboardShouldReturn200WithConfig(t, sc, fakeProvisioningService, dashboardStore) dash := getDashboardShouldReturn200WithConfig(t, sc, fakeProvisioningService, dashboardStore, dashboardService)
assert.Equal(t, "../../../dashboard1.json", dash.Meta.ProvisionedExternalId, mockSQLStore) assert.Equal(t, "../../../dashboard1.json", dash.Meta.ProvisionedExternalId, mockSQLStore)
}, mockSQLStore) }, mockSQLStore)
@ -899,6 +916,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dashboardProvisioningService: mockDashboardProvisioningService{}, dashboardProvisioningService: mockDashboardProvisioningService{},
SQLStore: mockSQLStore, SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(), AccessControl: accesscontrolmock.New(),
dashboardService: dashboardService,
} }
hs.callGetDashboard(sc) hs.callGetDashboard(sc)
@ -913,7 +931,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
} }
func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, provisioningService provisioning.ProvisioningService, dashboardStore dashboards.Store) dtos.DashboardFullWithMeta { func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, provisioningService provisioning.ProvisioningService, dashboardStore dashboards.Store, dashboardService dashboards.DashboardService) dtos.DashboardFullWithMeta {
t.Helper() t.Helper()
if provisioningService == nil { if provisioningService == nil {
@ -925,6 +943,10 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
dashboardStore = database.ProvideDashboardStore(sql) dashboardStore = database.ProvideDashboardStore(sql)
} }
if dashboardService == nil {
dashboardService = &dashboards.FakeDashboardService{}
}
libraryPanelsService := mockLibraryPanelService{} libraryPanelsService := mockLibraryPanelService{}
libraryElementsService := mockLibraryElementService{} libraryElementsService := mockLibraryElementService{}
cfg := setting.NewCfg() cfg := setting.NewCfg()
@ -941,6 +963,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
cfg, dashboardStore, nil, features, cfg, dashboardStore, nil, features,
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
), ),
dashboardService: dashboardService,
} }
hs.callGetDashboard(sc) hs.callGetDashboard(sc)
@ -954,10 +977,6 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
return dash return dash
} }
func getDashboardShouldReturn200(t *testing.T, sc *scenarioContext) dtos.DashboardFullWithMeta {
return getDashboardShouldReturn200WithConfig(t, sc, nil, nil)
}
func (hs *HTTPServer) callGetDashboard(sc *scenarioContext) { func (hs *HTTPServer) callGetDashboard(sc *scenarioContext) {
sc.handlerFunc = hs.GetDashboard sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()

View File

@ -15,7 +15,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
service "github.com/grafana/grafana/pkg/services/dashboards/manager" service "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"

View File

@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"

View File

@ -7,16 +7,15 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/web/webtest" "github.com/stretchr/testify/require"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes" fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/query" "github.com/grafana/grafana/pkg/services/query"
"github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/web/webtest"
) )
var queryDatasourceInput = `{ var queryDatasourceInput = `{

View File

@ -31,7 +31,7 @@ func (hs *HTTPServer) SetHomeDashboard(c *models.ReqContext) response.Response {
dashboardID := cmd.HomeDashboardID dashboardID := cmd.HomeDashboardID
if cmd.HomeDashboardUID != nil { if cmd.HomeDashboardUID != nil {
query := models.GetDashboardQuery{Uid: *cmd.HomeDashboardUID} query := models.GetDashboardQuery{Uid: *cmd.HomeDashboardUID}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err != nil { if err != nil {
return response.Error(404, "Dashboard not found", err) return response.Error(404, "Dashboard not found", err)
} }
@ -65,7 +65,7 @@ func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, team
// when homedashboardID is 0, that means it is the default home dashboard, no UID would be returned in the response // when homedashboardID is 0, that means it is the default home dashboard, no UID would be returned in the response
if preference.HomeDashboardID != 0 { if preference.HomeDashboardID != 0 {
query := models.GetDashboardQuery{Id: preference.HomeDashboardID, OrgId: orgID} query := models.GetDashboardQuery{Id: preference.HomeDashboardID, OrgId: orgID}
err = hs.SQLStore.GetDashboard(ctx, &query) err = hs.dashboardService.GetDashboard(ctx, &query)
if err == nil { if err == nil {
dashboardUID = query.Result.Uid dashboardUID = query.Result.Uid
} }
@ -104,7 +104,7 @@ func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, t
dashboardID := dtoCmd.HomeDashboardID dashboardID := dtoCmd.HomeDashboardID
if dtoCmd.HomeDashboardUID != nil { if dtoCmd.HomeDashboardUID != nil {
query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID} query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID}
err := hs.SQLStore.GetDashboard(ctx, &query) err := hs.dashboardService.GetDashboard(ctx, &query)
if err != nil { if err != nil {
return response.Error(404, "Dashboard not found", err) return response.Error(404, "Dashboard not found", err)
} }
@ -147,7 +147,7 @@ func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, te
dashboardID := dtoCmd.HomeDashboardID dashboardID := dtoCmd.HomeDashboardID
if dtoCmd.HomeDashboardUID != nil { if dtoCmd.HomeDashboardUID != nil {
query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID} query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID}
err := hs.SQLStore.GetDashboard(ctx, &query) err := hs.dashboardService.GetDashboard(ctx, &query)
if err != nil { if err != nil {
return response.Error(404, "Dashboard not found", err) return response.Error(404, "Dashboard not found", err)
} }

View File

@ -1,19 +1,21 @@
package api package api
import ( import (
"context"
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
"testing" "testing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/preference/preftest"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/preference/preftest"
) )
var ( var (
@ -32,12 +34,13 @@ var (
func TestAPIEndpoint_GetCurrentOrgPreferences_LegacyAccessControl(t *testing.T) { func TestAPIEndpoint_GetCurrentOrgPreferences_LegacyAccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, false) sc := setupHTTPServer(t, true, false)
sqlstore := mockstore.NewSQLStoreMock() dashSvc := &dashboards.FakeDashboardService{
sqlstore.ExpectedDashboard = &models.Dashboard{ GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
Uid: "home", cmd.Result = &models.Dashboard{Uid: "home", Id: 1}
Id: 1, return nil
},
} }
sc.hs.SQLStore = sqlstore sc.hs.dashboardService = dashSvc
prefService := preftest.NewPreferenceServiceFake() prefService := preftest.NewPreferenceServiceFake()
prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"} prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"}
@ -68,13 +71,6 @@ func TestAPIEndpoint_GetCurrentOrgPreferences_AccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, true) sc := setupHTTPServer(t, true, true)
setInitCtxSignedInViewer(sc.initCtx) setInitCtxSignedInViewer(sc.initCtx)
sqlstore := mockstore.NewSQLStoreMock()
sqlstore.ExpectedDashboard = &models.Dashboard{
Uid: "home",
Id: 1,
}
sc.hs.SQLStore = sqlstore
prefService := preftest.NewPreferenceServiceFake() prefService := preftest.NewPreferenceServiceFake()
prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"} prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"}
sc.hs.preferenceService = prefService sc.hs.preferenceService = prefService
@ -168,12 +164,8 @@ func TestAPIEndpoint_PatchUserPreferences(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, response.Code) assert.Equal(t, http.StatusBadRequest, response.Code)
}) })
input = strings.NewReader(testUpdateOrgPreferencesWithHomeDashboardUIDCmd) input = strings.NewReader(testUpdateOrgPreferencesWithHomeDashboardUIDCmd)
sqlstore := mockstore.NewSQLStoreMock() dashSvc := &dashboards.FakeDashboardService{}
sqlstore.ExpectedDashboard = &models.Dashboard{ sc.hs.dashboardService = dashSvc
Uid: "home",
Id: 1,
}
sc.hs.SQLStore = sqlstore
t.Run("Returns 200 on success", func(t *testing.T) { t.Run("Returns 200 on success", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t) response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t)
assert.Equal(t, http.StatusOK, response.Code) assert.Equal(t, http.StatusOK, response.Code)

View File

@ -26,7 +26,7 @@ func (hs *HTTPServer) GetStars(c *models.ReqContext) response.Response {
Id: dashboardId, Id: dashboardId,
OrgId: c.OrgId, OrgId: c.OrgId,
} }
err := hs.SQLStore.GetDashboard(c.Req.Context(), query) err := hs.dashboardService.GetDashboard(c.Req.Context(), query)
if err != nil { if err != nil {
return response.Error(500, "Failed to get dashboard", err) return response.Error(500, "Failed to get dashboard", err)
} }

View File

@ -369,10 +369,6 @@ func TestTeamAPIEndpoint_GetTeamPreferences_RBAC(t *testing.T) {
_, err := sc.db.CreateTeam("team1", "", 1) _, err := sc.db.CreateTeam("team1", "", 1)
sqlstore := mockstore.NewSQLStoreMock() sqlstore := mockstore.NewSQLStoreMock()
sqlstore.ExpectedDashboard = &models.Dashboard{
Uid: "home",
Id: 1,
}
sc.hs.SQLStore = sqlstore sc.hs.SQLStore = sqlstore
prefService := preftest.NewPreferenceServiceFake() prefService := preftest.NewPreferenceServiceFake()

View File

@ -46,7 +46,7 @@ import (
dashboardimportservice "github.com/grafana/grafana/pkg/services/dashboardimport/service" dashboardimportservice "github.com/grafana/grafana/pkg/services/dashboardimport/service"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/dashboardsnapshots" "github.com/grafana/grafana/pkg/services/dashboardsnapshots"
"github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasourceproxy"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"

View File

@ -109,10 +109,11 @@ var DashboardAdminActions = append(DashboardEditActions, []string{dashboards.Act
func ProvideDashboardPermissions( func ProvideDashboardPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore, cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
ac accesscontrol.AccessControl, store resourcepermissions.Store, ac accesscontrol.AccessControl, store resourcepermissions.Store,
dashboardStore dashboards.Store,
) (*DashboardPermissionsService, error) { ) (*DashboardPermissionsService, error) {
getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) { getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) {
query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID} query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil { if err := dashboardStore.GetDashboard(ctx, query); err != nil {
return nil, err return nil, err
} }
return query.Result, nil return query.Result, nil
@ -141,7 +142,7 @@ func ProvideDashboardPermissions(
} }
if dashboard.FolderId > 0 { if dashboard.FolderId > 0 {
query := &models.GetDashboardQuery{Id: dashboard.FolderId, OrgId: orgID} query := &models.GetDashboardQuery{Id: dashboard.FolderId, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil { if err := dashboardStore.GetDashboard(ctx, query); err != nil {
return nil, err return nil, err
} }
return []string{dashboards.ScopeFoldersProvider.GetResourceScopeUID(query.Result.Uid)}, nil return []string{dashboards.ScopeFoldersProvider.GetResourceScopeUID(query.Result.Uid)}, nil
@ -181,13 +182,14 @@ var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFol
func ProvideFolderPermissions( func ProvideFolderPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore, cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
accesscontrol accesscontrol.AccessControl, store resourcepermissions.Store, accesscontrol accesscontrol.AccessControl, store resourcepermissions.Store,
dashboardStore dashboards.Store,
) (*FolderPermissionsService, error) { ) (*FolderPermissionsService, error) {
options := resourcepermissions.Options{ options := resourcepermissions.Options{
Resource: "folders", Resource: "folders",
ResourceAttribute: "uid", ResourceAttribute: "uid",
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error { ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID} query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil { if err := dashboardStore.GetDashboard(ctx, query); err != nil {
return err return err
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
@ -16,15 +17,18 @@ type PermissionChecker struct {
sqlStore *sqlstore.SQLStore sqlStore *sqlstore.SQLStore
features featuremgmt.FeatureToggles features featuremgmt.FeatureToggles
accessControl accesscontrol.AccessControl accessControl accesscontrol.AccessControl
dashboardService dashboards.DashboardService
} }
func NewPermissionChecker(sqlStore *sqlstore.SQLStore, features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl) *PermissionChecker { func NewPermissionChecker(sqlStore *sqlstore.SQLStore, features featuremgmt.FeatureToggles,
accessControl accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
) *PermissionChecker {
return &PermissionChecker{sqlStore: sqlStore, features: features, accessControl: accessControl} return &PermissionChecker{sqlStore: sqlStore, features: features, accessControl: accessControl}
} }
func (c *PermissionChecker) getDashboardByUid(ctx context.Context, orgID int64, uid string) (*models.Dashboard, error) { func (c *PermissionChecker) getDashboardByUid(ctx context.Context, orgID int64, uid string) (*models.Dashboard, error) {
query := models.GetDashboardQuery{Uid: uid, OrgId: orgID} query := models.GetDashboardQuery{Uid: uid, OrgId: orgID}
if err := c.sqlStore.GetDashboard(ctx, &query); err != nil { if err := c.dashboardService.GetDashboard(ctx, &query); err != nil {
return nil, err return nil, err
} }
return query.Result, nil return query.Result, nil
@ -32,7 +36,7 @@ func (c *PermissionChecker) getDashboardByUid(ctx context.Context, orgID int64,
func (c *PermissionChecker) getDashboardById(ctx context.Context, orgID int64, id int64) (*models.Dashboard, error) { func (c *PermissionChecker) getDashboardById(ctx context.Context, orgID int64, id int64) (*models.Dashboard, error) {
query := models.GetDashboardQuery{Id: id, OrgId: orgID} query := models.GetDashboardQuery{Id: id, OrgId: orgID}
if err := c.sqlStore.GetDashboard(ctx, &query); err != nil { if err := c.dashboardService.GetDashboard(ctx, &query); err != nil {
return nil, err return nil, err
} }
return query.Result, nil return query.Result, nil

View File

@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/comments/commentmodel" "github.com/grafana/grafana/pkg/services/comments/commentmodel"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/live" "github.com/grafana/grafana/pkg/services/live"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
@ -19,7 +20,9 @@ type Service struct {
permissions *commentmodel.PermissionChecker permissions *commentmodel.PermissionChecker
} }
func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.GrafanaLive, features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl) *Service { func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.GrafanaLive,
features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl,
dashboardService dashboards.DashboardService) *Service {
s := &Service{ s := &Service{
cfg: cfg, cfg: cfg,
live: live, live: live,
@ -27,7 +30,7 @@ func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.Grafa
storage: &sqlStorage{ storage: &sqlStorage{
sql: store, sql: store,
}, },
permissions: commentmodel.NewPermissionChecker(store, features, accessControl), permissions: commentmodel.NewPermissionChecker(store, features, accessControl, dashboardService),
} }
return s return s
} }

View File

@ -14,6 +14,7 @@ type DashboardService interface {
MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error
BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*models.SaveDashboardCommand, error) BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*models.SaveDashboardCommand, error)
UpdateDashboardACL(ctx context.Context, uid int64, items []*models.DashboardAcl) error UpdateDashboardACL(ctx context.Context, uid int64, items []*models.DashboardAcl) error
GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
} }
// PluginService is a service for operating on plugin dashboards. // PluginService is a service for operating on plugin dashboards.
@ -51,6 +52,7 @@ type Store interface {
UnprovisionDashboard(ctx context.Context, id int64) error UnprovisionDashboard(ctx context.Context, id int64) error
// GetDashboardsByPluginID retrieves dashboards identified by plugin. // GetDashboardsByPluginID retrieves dashboards identified by plugin.
GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error
GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error
FolderStore FolderStore
} }

View File

@ -13,6 +13,8 @@ type FakeDashboardService struct {
SaveDashboardError error SaveDashboardError error
SavedDashboards []*SaveDashboardDTO SavedDashboards []*SaveDashboardDTO
ProvisionedDashData *models.DashboardProvisioning ProvisionedDashData *models.DashboardProvisioning
GetDashboardFn func(ctx context.Context, cmd *models.GetDashboardQuery) error
} }
func (s *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) { func (s *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) {
@ -45,3 +47,15 @@ func (s *FakeDashboardService) GetProvisionedDashboardDataByDashboardID(id int64
func (s *FakeDashboardService) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error { func (s *FakeDashboardService) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error {
return nil return nil
} }
func (s *FakeDashboardService) GetDashboard(ctx context.Context, cmd *models.GetDashboardQuery) error {
if s.GetDashboardFn != nil {
return s.GetDashboardFn(ctx, cmd)
}
// A minimal result for tests that need a valid result, but don't care what's in it.
d := models.NewDashboard("mocked")
d.Id = 1
d.Uid = "1"
cmd.Result = d
return nil
}

View File

@ -21,6 +21,9 @@ type DashboardStore struct {
log log.Logger log log.Logger
} }
// DashboardStore implements the Store interface
var _ dashboards.Store = (*DashboardStore)(nil)
func ProvideDashboardStore(sqlStore *sqlstore.SQLStore) *DashboardStore { func ProvideDashboardStore(sqlStore *sqlstore.SQLStore) *DashboardStore {
return &DashboardStore{sqlStore: sqlStore, log: log.New("dashboard-store")} return &DashboardStore{sqlStore: sqlStore, log: log.New("dashboard-store")}
} }
@ -823,3 +826,25 @@ func (d *DashboardStore) deleteAlertDefinition(dashboardId int64, sess *sqlstore
return nil return nil
} }
func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
return d.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 {
return models.ErrDashboardIdentifierNotSet
}
dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
has, err := sess.Get(&dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
query.Result = &dashboard
return nil
})
}

View File

@ -61,7 +61,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1, OrgId: 1,
} }
err := sqlStore.GetDashboard(context.Background(), &query) err := dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, query.Result.Title, "test dash 23") require.Equal(t, query.Result.Title, "test dash 23")
@ -78,7 +78,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1, OrgId: 1,
} }
err := sqlStore.GetDashboard(context.Background(), &query) err := dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, query.Result.Title, "test dash 23") require.Equal(t, query.Result.Title, "test dash 23")
@ -95,7 +95,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1, OrgId: 1,
} }
err := sqlStore.GetDashboard(context.Background(), &query) err := dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, query.Result.Title, "test dash 23") require.Equal(t, query.Result.Title, "test dash 23")
@ -111,7 +111,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1, OrgId: 1,
} }
err := sqlStore.GetDashboard(context.Background(), &query) err := dashboardStore.GetDashboard(context.Background(), &query)
require.Equal(t, err, models.ErrDashboardIdentifierNotSet) require.Equal(t, err, models.ErrDashboardIdentifierNotSet)
}) })
@ -180,7 +180,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1, OrgId: 1,
} }
err = sqlStore.GetDashboard(context.Background(), &query) err = dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, query.Result.FolderId, int64(0)) require.Equal(t, query.Result.FolderId, int64(0))
require.Equal(t, query.Result.CreatedBy, savedDash.CreatedBy) require.Equal(t, query.Result.CreatedBy, savedDash.CreatedBy)

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.10.0. DO NOT EDIT. // Code generated by mockery v2.12.2. DO NOT EDIT.
package dashboards package dashboards
@ -7,6 +7,8 @@ import (
models "github.com/grafana/grafana/pkg/models" models "github.com/grafana/grafana/pkg/models"
mock "github.com/stretchr/testify/mock" mock "github.com/stretchr/testify/mock"
testing "testing"
) )
// FakeDashboardStore is an autogenerated mock type for the Store type // FakeDashboardStore is an autogenerated mock type for the Store type
@ -42,6 +44,20 @@ func (_m *FakeDashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Co
return r0 return r0
} }
// GetDashboard provides a mock function with given fields: ctx, query
func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
ret := _m.Called(ctx, query)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *models.GetDashboardQuery) error); ok {
r0 = rf(ctx, query)
} else {
r0 = ret.Error(0)
}
return r0
}
// GetDashboardsByPluginID provides a mock function with given fields: ctx, query // GetDashboardsByPluginID provides a mock function with given fields: ctx, query
func (_m *FakeDashboardStore) GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error { func (_m *FakeDashboardStore) GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error {
ret := _m.Called(ctx, query) ret := _m.Called(ctx, query)
@ -302,3 +318,13 @@ func (_m *FakeDashboardStore) ValidateDashboardBeforeSave(dashboard *models.Dash
return r0, r1 return r0, r1
} }
// NewFakeDashboardStore creates a new instance of FakeDashboardStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
func NewFakeDashboardStore(t testing.TB) *FakeDashboardStore {
mock := &FakeDashboardStore{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -481,3 +481,7 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
return nil return nil
} }
func (dr *DashboardServiceImpl) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
return dr.dashboardStore.GetDashboard(ctx, query)
}

View File

@ -7,18 +7,20 @@ import (
"context" "context"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/dashboards"
dashbboardservice "github.com/grafana/grafana/pkg/services/dashboards" dashbboardservice "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
const testOrgID int64 = 1 const testOrgID int64 = 1
@ -76,7 +78,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore) res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res) require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
OrgId: otherOrgId, OrgId: otherOrgId,
Uid: sc.savedDashInFolder.Uid, Uid: sc.savedDashInFolder.Uid,
}) })
@ -316,7 +318,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore) res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res) require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id, Id: res.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -341,7 +343,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id) assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id, Id: res.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -366,7 +368,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id) assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
assert.True(t, res.IsFolder) assert.True(t, res.IsFolder)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id, Id: res.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -388,7 +390,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Greater(t, res.Id, int64(0)) assert.Greater(t, res.Id, int64(0))
assert.NotEmpty(t, res.Uid) assert.NotEmpty(t, res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id, Id: res.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -409,7 +411,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore) res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res) require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id, Id: res.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -463,7 +465,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore) res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res) require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInGeneralFolder.Id, Id: sc.savedDashInGeneralFolder.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -503,7 +505,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore) res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res) require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInFolder.Id, Id: sc.savedDashInFolder.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -577,7 +579,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore) res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res) require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInGeneralFolder.Id, Id: sc.savedDashInGeneralFolder.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -599,7 +601,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore) res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res) require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInFolder.Id, Id: sc.savedDashInFolder.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -623,7 +625,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Equal(t, sc.savedDashInFolder.Id, res.Id) assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
assert.Equal(t, "new-uid", res.Uid) assert.Equal(t, "new-uid", res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInFolder.Id, Id: sc.savedDashInFolder.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -663,7 +665,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Equal(t, sc.savedDashInFolder.Id, res.Id) assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
assert.Equal(t, sc.savedDashInFolder.Uid, res.Uid) assert.Equal(t, sc.savedDashInFolder.Uid, res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id, Id: res.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -687,7 +689,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Equal(t, sc.savedDashInGeneralFolder.Id, res.Id) assert.Equal(t, sc.savedDashInGeneralFolder.Id, res.Id)
assert.Equal(t, sc.savedDashInGeneralFolder.Uid, res.Uid) assert.Equal(t, sc.savedDashInGeneralFolder.Uid, res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id, Id: res.Id,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
}) })
@ -795,6 +797,7 @@ func TestIntegratedDashboardService(t *testing.T) {
type permissionScenarioContext struct { type permissionScenarioContext struct {
dashboardGuardianMock *guardian.FakeDashboardGuardian dashboardGuardianMock *guardian.FakeDashboardGuardian
sqlStore *sqlstore.SQLStore sqlStore *sqlstore.SQLStore
dashboardStore dashboards.Store
savedFolder *models.Dashboard savedFolder *models.Dashboard
savedDashInFolder *models.Dashboard savedDashInFolder *models.Dashboard
otherSavedFolder *models.Dashboard otherSavedFolder *models.Dashboard
@ -813,6 +816,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
t.Run(desc, func(t *testing.T) { t.Run(desc, func(t *testing.T) {
sqlStore := sqlstore.InitTestDB(t) sqlStore := sqlstore.InitTestDB(t)
guardian.InitLegacyGuardian(sqlStore) guardian.InitLegacyGuardian(sqlStore)
dashboardStore := database.ProvideDashboardStore(sqlStore)
savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore) savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore)
savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.Id, sqlStore) savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.Id, sqlStore)
@ -847,6 +851,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
otherSavedFolder: otherSavedFolder, otherSavedFolder: otherSavedFolder,
savedDashInGeneralFolder: savedDashInGeneralFolder, savedDashInGeneralFolder: savedDashInGeneralFolder,
savedFolder: savedFolder, savedFolder: savedFolder,
dashboardStore: dashboardStore,
} }
fn(t, sc) fn(t, sc)

View File

@ -12,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -24,13 +23,12 @@ type FolderServiceImpl struct {
searchService *search.SearchService searchService *search.SearchService
features featuremgmt.FeatureToggles features featuremgmt.FeatureToggles
permissions accesscontrol.FolderPermissionsService permissions accesscontrol.FolderPermissionsService
sqlStore sqlstore.Store
} }
func ProvideFolderService( func ProvideFolderService(
cfg *setting.Cfg, dashboardService dashboards.DashboardService, dashboardStore dashboards.Store, cfg *setting.Cfg, dashboardService dashboards.DashboardService, dashboardStore dashboards.Store,
searchService *search.SearchService, features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService, searchService *search.SearchService, features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
ac accesscontrol.AccessControl, sqlStore sqlstore.Store, ac accesscontrol.AccessControl,
) *FolderServiceImpl { ) *FolderServiceImpl {
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore)) ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore))
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore)) ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore))
@ -43,7 +41,6 @@ func ProvideFolderService(
searchService: searchService, searchService: searchService,
features: features, features: features,
permissions: folderPermissionsService, permissions: folderPermissionsService,
sqlStore: sqlStore,
} }
} }
@ -190,7 +187,7 @@ func (f *FolderServiceImpl) CreateFolder(ctx context.Context, user *models.Signe
func (f *FolderServiceImpl) UpdateFolder(ctx context.Context, user *models.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error { func (f *FolderServiceImpl) UpdateFolder(ctx context.Context, user *models.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
query := models.GetDashboardQuery{OrgId: orgID, Uid: existingUid} query := models.GetDashboardQuery{OrgId: orgID, Uid: existingUid}
if err := f.sqlStore.GetDashboard(ctx, &query); err != nil { if err := f.dashboardStore.GetDashboard(ctx, &query); err != nil {
return toFolderError(err) return toFolderError(err)
} }

View File

@ -18,7 +18,6 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@ -39,7 +38,7 @@ func TestProvideFolderService(t *testing.T) {
ProvideFolderService( ProvideFolderService(
cfg, &dashboards.FakeDashboardService{DashboardService: dashboardService}, cfg, &dashboards.FakeDashboardService{DashboardService: dashboardService},
store, nil, features, folderPermissions, ac, mockstore.NewSQLStoreMock(), store, nil, features, folderPermissions, ac,
) )
require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 2) require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 2)
@ -55,7 +54,6 @@ func TestFolderService(t *testing.T) {
folderPermissions := acmock.NewMockedPermissionsService() folderPermissions := acmock.NewMockedPermissionsService()
dashboardPermissions := acmock.NewMockedPermissionsService() dashboardPermissions := acmock.NewMockedPermissionsService()
dashboardService := ProvideDashboardService(cfg, store, nil, features, folderPermissions, dashboardPermissions) dashboardService := ProvideDashboardService(cfg, store, nil, features, folderPermissions, dashboardPermissions)
mockStore := mockstore.NewSQLStoreMock()
service := FolderServiceImpl{ service := FolderServiceImpl{
cfg: cfg, cfg: cfg,
@ -65,7 +63,6 @@ func TestFolderService(t *testing.T) {
searchService: nil, searchService: nil,
features: features, features: features,
permissions: folderPermissions, permissions: folderPermissions,
sqlStore: mockStore,
} }
t.Run("Given user has no permissions", func(t *testing.T) { t.Run("Given user has no permissions", func(t *testing.T) {
@ -105,7 +102,11 @@ func TestFolderService(t *testing.T) {
}) })
t.Run("When updating folder should return access denied error", func(t *testing.T) { t.Run("When updating folder should return access denied error", func(t *testing.T) {
mockStore.ExpectedDashboard = models.NewDashboardFolder("Folder") store.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
folder := args.Get(1).(*models.GetDashboardQuery)
folder.Result = models.NewDashboard("dashboard-test")
folder.Result.IsFolder = true
}).Return(nil)
err := service.UpdateFolder(context.Background(), user, orgID, folderUID, &models.UpdateFolderCommand{ err := service.UpdateFolder(context.Background(), user, orgID, folderUID, &models.UpdateFolderCommand{
Uid: folderUID, Uid: folderUID,
Title: "Folder-TEST", Title: "Folder-TEST",
@ -156,8 +157,6 @@ func TestFolderService(t *testing.T) {
dashboardFolder.Uid = util.GenerateShortUID() dashboardFolder.Uid = util.GenerateShortUID()
f := models.DashboardToFolder(dashboardFolder) f := models.DashboardToFolder(dashboardFolder)
mockStore.ExpectedDashboard = dashboardFolder
store.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything).Return(true, nil) store.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything).Return(true, nil)
store.On("SaveDashboard", mock.Anything).Return(dashboardFolder, nil) store.On("SaveDashboard", mock.Anything).Return(dashboardFolder, nil)
store.On("GetFolderByID", mock.Anything, orgID, dashboardFolder.Id).Return(f, nil) store.On("GetFolderByID", mock.Anything, orgID, dashboardFolder.Id).Return(f, nil)

View File

@ -25,6 +25,7 @@ func NewAccessControlDashboardGuardian(
store sqlstore.Store, ac accesscontrol.AccessControl, store sqlstore.Store, ac accesscontrol.AccessControl,
folderPermissionsService accesscontrol.FolderPermissionsService, folderPermissionsService accesscontrol.FolderPermissionsService,
dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService,
dashboardService dashboards.DashboardService,
) *AccessControlDashboardGuardian { ) *AccessControlDashboardGuardian {
return &AccessControlDashboardGuardian{ return &AccessControlDashboardGuardian{
ctx: ctx, ctx: ctx,
@ -35,6 +36,7 @@ func NewAccessControlDashboardGuardian(
ac: ac, ac: ac,
folderPermissionsService: folderPermissionsService, folderPermissionsService: folderPermissionsService,
dashboardPermissionsService: dashboardPermissionsService, dashboardPermissionsService: dashboardPermissionsService,
dashboardService: dashboardService,
} }
} }
@ -49,6 +51,7 @@ type AccessControlDashboardGuardian struct {
ac accesscontrol.AccessControl ac accesscontrol.AccessControl
folderPermissionsService accesscontrol.FolderPermissionsService folderPermissionsService accesscontrol.FolderPermissionsService
dashboardPermissionsService accesscontrol.DashboardPermissionsService dashboardPermissionsService accesscontrol.DashboardPermissionsService
dashboardService dashboards.DashboardService
} }
func (a *AccessControlDashboardGuardian) CanSave() (bool, error) { func (a *AccessControlDashboardGuardian) CanSave() (bool, error) {
@ -264,7 +267,7 @@ func (a *AccessControlDashboardGuardian) GetHiddenACL(cfg *setting.Cfg) ([]*mode
func (a *AccessControlDashboardGuardian) loadDashboard() error { func (a *AccessControlDashboardGuardian) loadDashboard() error {
if a.dashboard == nil { if a.dashboard == nil {
query := &models.GetDashboardQuery{Id: a.dashboardID, OrgId: a.user.OrgId} query := &models.GetDashboardQuery{Id: a.dashboardID, OrgId: a.user.OrgId}
if err := a.store.GetDashboard(a.ctx, query); err != nil { if err := a.dashboardService.GetDashboard(a.ctx, query); err != nil {
return err return err
} }
if !query.Result.IsFolder { if !query.Result.IsFolder {
@ -284,7 +287,7 @@ func (a *AccessControlDashboardGuardian) loadParentFolder(folderID int64) (*mode
return &models.Dashboard{Uid: accesscontrol.GeneralFolderUID}, nil return &models.Dashboard{Uid: accesscontrol.GeneralFolderUID}, nil
} }
folderQuery := &models.GetDashboardQuery{Id: folderID, OrgId: a.user.OrgId} folderQuery := &models.GetDashboardQuery{Id: folderID, OrgId: a.user.OrgId}
if err := a.store.GetDashboard(a.ctx, folderQuery); err != nil { if err := a.dashboardService.GetDashboard(a.ctx, folderQuery); err != nil {
return nil, err return nil, err
} }
return folderQuery.Result, nil return folderQuery.Result, nil

View File

@ -595,10 +595,12 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []*acc
}) })
require.NoError(t, err) require.NoError(t, err)
ac := accesscontrolmock.New().WithPermissions(permissions) ac := accesscontrolmock.New().WithPermissions(permissions)
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store)) folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{})
require.NoError(t, err) require.NoError(t, err)
dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store)) dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{})
require.NoError(t, err) require.NoError(t, err)
return NewAccessControlDashboardGuardian(context.Background(), dash.Id, &models.SignedInUser{OrgId: 1}, store, ac, folderPermissions, dashboardPermissions), dash return NewAccessControlDashboardGuardian(context.Background(), dash.Id, &models.SignedInUser{OrgId: 1}, store, ac, folderPermissions, dashboardPermissions, &dashboards.FakeDashboardService{}), dash
} }

View File

@ -7,9 +7,10 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert"
) )
type scenarioContext struct { type scenarioContext struct {

View File

@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
) )
@ -13,10 +14,11 @@ type Provider struct{}
func ProvideService( func ProvideService(
store *sqlstore.SQLStore, ac accesscontrol.AccessControl, store *sqlstore.SQLStore, ac accesscontrol.AccessControl,
folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService, folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService,
dashboardService dashboards.DashboardService,
) *Provider { ) *Provider {
if !ac.IsDisabled() { if !ac.IsDisabled() {
// TODO: Fix this hack, see https://github.com/grafana/grafana-enterprise/issues/2935 // TODO: Fix this hack, see https://github.com/grafana/grafana-enterprise/issues/2935
InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService) InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
} else { } else {
InitLegacyGuardian(store) InitLegacyGuardian(store)
} }
@ -31,9 +33,9 @@ func InitLegacyGuardian(store sqlstore.Store) {
func InitAccessControlGuardian( func InitAccessControlGuardian(
store sqlstore.Store, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService, store sqlstore.Store, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService,
dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardService dashboards.DashboardService,
) { ) {
New = func(ctx context.Context, dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian { New = func(ctx context.Context, dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian {
return NewAccessControlDashboardGuardian(ctx, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService) return NewAccessControlDashboardGuardian(ctx, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
} }
} }

View File

@ -19,7 +19,7 @@ import (
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
@ -235,7 +235,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string
ac := acmock.New() ac := acmock.New()
s := dashboardservice.ProvideFolderService( s := dashboardservice.ProvideFolderService(
cfg, d, dashboardStore, nil, cfg, d, dashboardStore, nil,
features, folderPermissions, ac, nil, features, folderPermissions, ac,
) )
t.Logf("Creating folder with title and UID %q", title) t.Logf("Creating folder with title and UID %q", title)
folder, err := s.CreateFolder(context.Background(), &user, user.OrgId, title, title) folder, err := s.CreateFolder(context.Background(), &user, user.OrgId, title, title)
@ -340,7 +340,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
SQLStore: sqlStore, SQLStore: sqlStore,
folderService: dashboardservice.ProvideFolderService( folderService: dashboardservice.ProvideFolderService(
cfg, dashboardService, dashboardStore, nil, cfg, dashboardService, dashboardStore, nil,
features, folderPermissions, ac, nil, features, folderPermissions, ac,
), ),
} }

View File

@ -17,7 +17,7 @@ import (
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/libraryelements" "github.com/grafana/grafana/pkg/services/libraryelements"
@ -1392,7 +1392,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string
dashboardPermissions := acmock.NewMockedPermissionsService() dashboardPermissions := acmock.NewMockedPermissionsService()
dashboardStore := database.ProvideDashboardStore(sqlStore) dashboardStore := database.ProvideDashboardStore(sqlStore)
d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions) d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions)
s := dashboardservice.ProvideFolderService(cfg, d, dashboardStore, nil, features, folderPermissions, ac, nil) s := dashboardservice.ProvideFolderService(cfg, d, dashboardStore, nil, features, folderPermissions, ac)
t.Logf("Creating folder with title and UID %q", title) t.Logf("Creating folder with title and UID %q", title)
folder, err := s.CreateFolder(context.Background(), user, user.OrgId, title, title) folder, err := s.CreateFolder(context.Background(), user, user.OrgId, title, title)
@ -1496,7 +1496,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
folderService := dashboardservice.ProvideFolderService( folderService := dashboardservice.ProvideFolderService(
cfg, dashboardService, dashboardStore, nil, cfg, dashboardService, dashboardStore, nil,
features, folderPermissions, ac, nil, features, folderPermissions, ac,
) )
elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService) elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService)

View File

@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
) )
@ -40,6 +41,7 @@ type DashboardHandler struct {
Publisher models.ChannelPublisher Publisher models.ChannelPublisher
ClientCount models.ChannelClientCount ClientCount models.ChannelClientCount
Store sqlstore.Store Store sqlstore.Store
DashboardService dashboards.DashboardService
} }
// GetHandlerForPath called on init // GetHandlerForPath called on init
@ -63,7 +65,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *models.SignedI
// make sure can view this dashboard // make sure can view this dashboard
if len(parts) == 2 && parts[0] == "uid" { if len(parts) == 2 && parts[0] == "uid" {
query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId} query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId}
if err := h.Store.GetDashboard(ctx, &query); err != nil { if err := h.DashboardService.GetDashboard(ctx, &query); err != nil {
logger.Error("Error getting dashboard", "query", query, "error", err) logger.Error("Error getting dashboard", "query", query, "error", err)
return models.SubscribeReply{}, backend.SubscribeStreamStatusNotFound, nil return models.SubscribeReply{}, backend.SubscribeStreamStatusNotFound, nil
} }
@ -110,7 +112,7 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *models.SignedInU
return models.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???") return models.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???")
} }
query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId} query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId}
if err := h.Store.GetDashboard(ctx, &query); err != nil { if err := h.DashboardService.GetDashboard(ctx, &query); err != nil {
logger.Error("Unknown dashboard", "query", query) logger.Error("Unknown dashboard", "query", query)
return models.PublishReply{}, backend.PublishStreamStatusNotFound, nil return models.PublishReply{}, backend.PublishStreamStatusNotFound, nil
} }

View File

@ -26,6 +26,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/plugincontext" "github.com/grafana/grafana/pkg/plugins/plugincontext"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/comments/commentmodel" "github.com/grafana/grafana/pkg/services/comments/commentmodel"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/live/database" "github.com/grafana/grafana/pkg/services/live/database"
@ -71,7 +72,7 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
pluginStore plugins.Store, cacheService *localcache.CacheService, pluginStore plugins.Store, cacheService *localcache.CacheService,
dataSourceCache datasources.CacheService, sqlStore *sqlstore.SQLStore, secretsService secrets.Service, dataSourceCache datasources.CacheService, sqlStore *sqlstore.SQLStore, secretsService secrets.Service,
usageStatsService usagestats.Service, queryDataService *query.Service, toggles featuremgmt.FeatureToggles, usageStatsService usagestats.Service, queryDataService *query.Service, toggles featuremgmt.FeatureToggles,
accessControl accesscontrol.AccessControl) (*GrafanaLive, error) { accessControl accesscontrol.AccessControl, dashboardService dashboards.DashboardService) (*GrafanaLive, error) {
g := &GrafanaLive{ g := &GrafanaLive{
Cfg: cfg, Cfg: cfg,
Features: toggles, Features: toggles,
@ -237,12 +238,13 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
Publisher: g.Publish, Publisher: g.Publish,
ClientCount: g.ClientCount, ClientCount: g.ClientCount,
Store: sqlStore, Store: sqlStore,
DashboardService: dashboardService,
} }
g.storage = database.NewStorage(g.SQLStore, g.CacheService) g.storage = database.NewStorage(g.SQLStore, g.CacheService)
g.GrafanaScope.Dashboards = dash g.GrafanaScope.Dashboards = dash
g.GrafanaScope.Features["dashboard"] = dash g.GrafanaScope.Features["dashboard"] = dash
g.GrafanaScope.Features["broadcast"] = features.NewBroadcastRunner(g.storage) g.GrafanaScope.Features["broadcast"] = features.NewBroadcastRunner(g.storage)
g.GrafanaScope.Features["comment"] = features.NewCommentHandler(commentmodel.NewPermissionChecker(g.SQLStore, g.Features, accessControl)) g.GrafanaScope.Features["comment"] = features.NewCommentHandler(commentmodel.NewPermissionChecker(g.SQLStore, g.Features, accessControl, dashboardService))
g.surveyCaller = survey.NewCaller(managedStreamRunner, node) g.surveyCaller = survey.NewCaller(managedStreamRunner, node)
err = g.surveyCaller.SetupHandlers() err = g.surveyCaller.SetupHandlers()

View File

@ -33,7 +33,7 @@ import (
func ProvideService(cfg *setting.Cfg, dataSourceCache datasources.CacheService, routeRegister routing.RouteRegister, func ProvideService(cfg *setting.Cfg, dataSourceCache datasources.CacheService, routeRegister routing.RouteRegister,
sqlStore *sqlstore.SQLStore, kvStore kvstore.KVStore, expressionService *expr.Service, dataProxy *datasourceproxy.DataSourceProxyService, sqlStore *sqlstore.SQLStore, kvStore kvstore.KVStore, expressionService *expr.Service, dataProxy *datasourceproxy.DataSourceProxyService,
quotaService *quota.QuotaService, secretsService secrets.Service, notificationService notifications.Service, m *metrics.NGAlert, quotaService *quota.QuotaService, secretsService secrets.Service, notificationService notifications.Service, m *metrics.NGAlert,
folderService dashboards.FolderService, ac accesscontrol.AccessControl) (*AlertNG, error) { folderService dashboards.FolderService, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService) (*AlertNG, error) {
ng := &AlertNG{ ng := &AlertNG{
Cfg: cfg, Cfg: cfg,
DataSourceCache: dataSourceCache, DataSourceCache: dataSourceCache,
@ -79,6 +79,7 @@ type AlertNG struct {
schedule schedule.ScheduleService schedule schedule.ScheduleService
stateManager *state.Manager stateManager *state.Manager
folderService dashboards.FolderService folderService dashboards.FolderService
dashboardService dashboards.DashboardService
// Alerting notification services // Alerting notification services
MultiOrgAlertmanager *notifier.MultiOrgAlertmanager MultiOrgAlertmanager *notifier.MultiOrgAlertmanager
@ -131,7 +132,7 @@ func (ng *AlertNG) init() error {
ng.Log.Error("Failed to parse application URL. Continue without it.", "error", err) ng.Log.Error("Failed to parse application URL. Continue without it.", "error", err)
appUrl = nil appUrl = nil
} }
stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.SQLStore) stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.SQLStore, ng.dashboardService)
scheduler := schedule.NewScheduler(schedCfg, ng.ExpressionService, appUrl, stateManager) scheduler := schedule.NewScheduler(schedCfg, ng.ExpressionService, appUrl, stateManager)
ng.stateManager = stateManager ng.stateManager = stateManager

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/ngalert/metrics"
"github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/models"
@ -106,7 +107,7 @@ func TestWarmStateCache(t *testing.T) {
Metrics: testMetrics.GetSchedulerMetrics(), Metrics: testMetrics.GetSchedulerMetrics(),
AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests. AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests.
} }
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore) st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore, &dashboards.FakeDashboardService{})
st.Warm(ctx) st.Warm(ctx)
t.Run("instance cache has expected entries", func(t *testing.T) { t.Run("instance cache has expected entries", func(t *testing.T) {
@ -158,7 +159,7 @@ func TestAlertingTicker(t *testing.T) {
disabledOrgID: {}, disabledOrgID: {},
}, },
} }
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore) st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore, &dashboards.FakeDashboardService{})
appUrl := &url.URL{ appUrl := &url.URL{
Scheme: "http", Scheme: "http",
Host: "localhost", Host: "localhost",

View File

@ -21,6 +21,7 @@ import (
"github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/ngalert/metrics"
"github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/models"
@ -925,7 +926,7 @@ func setupScheduler(t *testing.T, rs store.RuleStore, is store.InstanceStore, ac
Metrics: m.GetSchedulerMetrics(), Metrics: m.GetSchedulerMetrics(),
AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests. AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests.
} }
st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, mockstore.NewSQLStoreMock()) st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, mockstore.NewSQLStoreMock(), &dashboards.FakeDashboardService{})
appUrl := &url.URL{ appUrl := &url.URL{
Scheme: "http", Scheme: "http",
Host: "localhost", Host: "localhost",

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/ngalert/metrics"
ngModels "github.com/grafana/grafana/pkg/services/ngalert/models" ngModels "github.com/grafana/grafana/pkg/services/ngalert/models"
@ -39,10 +40,12 @@ type Manager struct {
ruleStore store.RuleStore ruleStore store.RuleStore
instanceStore store.InstanceStore instanceStore store.InstanceStore
sqlStore sqlstore.Store sqlStore sqlstore.Store
dashboardService dashboards.DashboardService
} }
func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL, ruleStore store.RuleStore, func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL,
instanceStore store.InstanceStore, sqlStore sqlstore.Store) *Manager { ruleStore store.RuleStore, instanceStore store.InstanceStore, sqlStore sqlstore.Store,
dashboardService dashboards.DashboardService) *Manager {
manager := &Manager{ manager := &Manager{
cache: newCache(logger, metrics, externalURL), cache: newCache(logger, metrics, externalURL),
quit: make(chan struct{}), quit: make(chan struct{}),
@ -52,6 +55,7 @@ func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL,
ruleStore: ruleStore, ruleStore: ruleStore,
instanceStore: instanceStore, instanceStore: instanceStore,
sqlStore: sqlStore, sqlStore: sqlStore,
dashboardService: dashboardService,
} }
go manager.recordMetrics() go manager.recordMetrics()
return manager return manager
@ -274,7 +278,7 @@ func (st *Manager) annotateState(ctx context.Context, alertRule *ngModels.AlertR
OrgId: alertRule.OrgID, OrgId: alertRule.OrgID,
} }
err = st.sqlStore.GetDashboard(ctx, query) err = st.dashboardService.GetDashboard(ctx, query)
if err != nil { if err != nil {
st.log.Error("error getting dashboard for alert annotation", "dashboardUID", dashUid, "alertRuleUID", alertRule.UID, "error", err.Error()) st.log.Error("error getting dashboard for alert annotation", "dashboardUID", dashUid, "alertRuleUID", alertRule.UID, "error", err.Error())
return return

View File

@ -9,6 +9,7 @@ import (
"time" "time"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
@ -37,7 +38,7 @@ func TestDashboardAnnotations(t *testing.T) {
_, dbstore := tests.SetupTestEnv(t, 1) _, dbstore := tests.SetupTestEnv(t, 1)
sqlStore := mockstore.NewSQLStoreMock() sqlStore := mockstore.NewSQLStoreMock()
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore) st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore, &dashboards.FakeDashboardService{})
fakeAnnoRepo := store.NewFakeAnnotationsRepo() fakeAnnoRepo := store.NewFakeAnnotationsRepo()
annotations.SetRepository(fakeAnnoRepo) annotations.SetRepository(fakeAnnoRepo)
@ -1770,7 +1771,7 @@ func TestProcessEvalResults(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
ss := mockstore.NewSQLStoreMock() ss := mockstore.NewSQLStoreMock()
st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, ss) st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, ss, &dashboards.FakeDashboardService{})
t.Run(tc.desc, func(t *testing.T) { t.Run(tc.desc, func(t *testing.T) {
fakeAnnoRepo := store.NewFakeAnnotationsRepo() fakeAnnoRepo := store.NewFakeAnnotationsRepo()
annotations.SetRepository(fakeAnnoRepo) annotations.SetRepository(fakeAnnoRepo)
@ -1881,7 +1882,7 @@ func TestStaleResultsHandler(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
ctx := context.Background() ctx := context.Background()
sqlStore := mockstore.NewSQLStoreMock() sqlStore := mockstore.NewSQLStoreMock()
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore) st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore, &dashboards.FakeDashboardService{})
st.Warm(ctx) st.Warm(ctx)
existingStatesForRule := st.GetStatesForRuleUID(rule.OrgID, rule.UID) existingStatesForRule := st.GetStatesForRuleUID(rule.OrgID, rule.UID)

View File

@ -10,8 +10,9 @@ import (
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards"
databasestore "github.com/grafana/grafana/pkg/services/dashboards/database" databasestore "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ngalert" "github.com/grafana/grafana/pkg/services/ngalert"
"github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/ngalert/metrics"
@ -60,12 +61,12 @@ func SetupTestEnv(t *testing.T, baseInterval time.Duration) (*ngalert.AlertNG, *
) )
folderService := dashboardservice.ProvideFolderService( folderService := dashboardservice.ProvideFolderService(
cfg, dashboardService, dashboardStore, nil, cfg, dashboardService, dashboardStore, nil,
features, folderPermissions, ac, nil, features, folderPermissions, ac,
) )
ng, err := ngalert.ProvideService( ng, err := ngalert.ProvideService(
cfg, nil, routing.NewRouteRegister(), sqlStore, cfg, nil, routing.NewRouteRegister(), sqlStore, nil, nil, nil, nil,
nil, nil, nil, nil, secretsService, nil, m, folderService, ac, secretsService, nil, m, folderService, ac, &dashboards.FakeDashboardService{},
) )
require.NoError(t, err) require.NoError(t, err)
return ng, &store.DBstore{ return ng, &store.DBstore{

View File

@ -26,8 +26,9 @@ import (
func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore, pluginStore plugifaces.Store, func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore, pluginStore plugifaces.Store,
encryptionService encryption.Internal, notificatonService *notifications.NotificationService, encryptionService encryption.Internal, notificatonService *notifications.NotificationService,
dashboardService dashboardservice.DashboardProvisioningService, dashboardProvisioningService dashboardservice.DashboardProvisioningService,
datasourceService datasourceservice.DataSourceService, datasourceService datasourceservice.DataSourceService,
dashboardService dashboardservice.DashboardService,
alertingService *alerting.AlertNotificationService, pluginSettings pluginsettings.Service, alertingService *alerting.AlertNotificationService, pluginSettings pluginsettings.Service,
) (*ProvisioningServiceImpl, error) { ) (*ProvisioningServiceImpl, error) {
s := &ProvisioningServiceImpl{ s := &ProvisioningServiceImpl{
@ -41,6 +42,7 @@ func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore, pluginStore p
provisionNotifiers: notifiers.Provision, provisionNotifiers: notifiers.Provision,
provisionDatasources: datasources.Provision, provisionDatasources: datasources.Provision,
provisionPlugins: plugins.Provision, provisionPlugins: plugins.Provision,
dashboardProvisioningService: dashboardProvisioningService,
dashboardService: dashboardService, dashboardService: dashboardService,
datasourceService: datasourceService, datasourceService: datasourceService,
alertingService: alertingService, alertingService: alertingService,
@ -101,7 +103,8 @@ type ProvisioningServiceImpl struct {
provisionDatasources func(context.Context, string, datasources.Store, utils.OrgStore) error provisionDatasources func(context.Context, string, datasources.Store, utils.OrgStore) error
provisionPlugins func(context.Context, string, plugins.Store, plugifaces.Store, pluginsettings.Service) error provisionPlugins func(context.Context, string, plugins.Store, plugifaces.Store, pluginsettings.Service) error
mutex sync.Mutex mutex sync.Mutex
dashboardService dashboardservice.DashboardProvisioningService dashboardProvisioningService dashboardservice.DashboardProvisioningService
dashboardService dashboardservice.DashboardService
datasourceService datasourceservice.DataSourceService datasourceService datasourceservice.DataSourceService
alertingService *alerting.AlertNotificationService alertingService *alerting.AlertNotificationService
pluginsSettings pluginsettings.Service pluginsSettings pluginsettings.Service
@ -187,7 +190,7 @@ func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) e
func (ps *ProvisioningServiceImpl) ProvisionDashboards(ctx context.Context) error { func (ps *ProvisioningServiceImpl) ProvisionDashboards(ctx context.Context) error {
dashboardPath := filepath.Join(ps.Cfg.ProvisioningPath, "dashboards") dashboardPath := filepath.Join(ps.Cfg.ProvisioningPath, "dashboards")
dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardService, ps.SQLStore, ps.SQLStore) dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardProvisioningService, ps.SQLStore, ps.dashboardService)
if err != nil { if err != nil {
return errutil.Wrap("Failed to create provisioner", err) return errutil.Wrap("Failed to create provisioner", err)
} }

View File

@ -29,28 +29,6 @@ func init() {
var generateNewUid func() string = util.GenerateShortUID var generateNewUid func() string = util.GenerateShortUID
func (ss *SQLStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 {
return models.ErrDashboardIdentifierNotSet
}
dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
has, err := dbSession.Get(&dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
query.Result = &dashboard
return nil
})
}
type DashboardSearchProjection struct { type DashboardSearchProjection struct {
ID int64 `xorm:"id"` ID int64 `xorm:"id"`
UID string `xorm:"uid"` UID string `xorm:"uid"`

View File

@ -9,11 +9,12 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/require"
) )
func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) { func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) {
@ -94,14 +95,13 @@ func TestGetDashboardVersion(t *testing.T) {
require.Equal(t, query.DashboardId, savedDash.Id) require.Equal(t, query.DashboardId, savedDash.Id)
require.Equal(t, query.Version, savedDash.Version) require.Equal(t, query.Version, savedDash.Version)
dashCmd := models.GetDashboardQuery{ dashCmd := &models.Dashboard{
OrgId: savedDash.OrgId,
Uid: savedDash.Uid, Uid: savedDash.Uid,
OrgId: savedDash.OrgId,
} }
err = getDashboard(t, sqlStore, dashCmd)
err = sqlStore.GetDashboard(context.Background(), &dashCmd)
require.Nil(t, err) require.Nil(t, err)
eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data) eq := reflect.DeepEqual(dashCmd.Data, query.Result.Data)
require.Equal(t, true, eq) require.Equal(t, true, eq)
}) })
@ -222,3 +222,20 @@ func TestDeleteExpiredVersions(t *testing.T) {
require.LessOrEqual(t, versionsToWriteBigNumber-len(query.Result), perBatch*maxBatches) require.LessOrEqual(t, versionsToWriteBigNumber-len(query.Result), perBatch*maxBatches)
}) })
} }
func getDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard) error {
t.Helper()
return sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
has, err := sess.Get(dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
return nil
})
}

View File

@ -20,7 +20,6 @@ type SQLStoreMock struct {
ExpectedDatasource *models.DataSource ExpectedDatasource *models.DataSource
ExpectedAlert *models.Alert ExpectedAlert *models.Alert
ExpectedPluginSetting *models.PluginSetting ExpectedPluginSetting *models.PluginSetting
ExpectedDashboard *models.Dashboard
ExpectedDashboards []*models.Dashboard ExpectedDashboards []*models.Dashboard
ExpectedDashboardVersion *models.DashboardVersion ExpectedDashboardVersion *models.DashboardVersion
ExpectedDashboardVersions []*models.DashboardVersion ExpectedDashboardVersions []*models.DashboardVersion
@ -466,11 +465,6 @@ func (m *SQLStoreMock) SaveDashboard(cmd models.SaveDashboardCommand) (*models.D
return nil, m.ExpectedError return nil, m.ExpectedError
} }
func (m *SQLStoreMock) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
query.Result = m.ExpectedDashboard
return m.ExpectedError
}
func (m SQLStoreMock) SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error { func (m SQLStoreMock) SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error {
query.Result = m.ExpectedPersistedDashboards query.Result = m.ExpectedPersistedDashboards
return m.ExpectedError return m.ExpectedError

View File

@ -100,7 +100,6 @@ type Store interface {
GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQuery) error GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQuery) error
SearchOrgUsers(ctx context.Context, query *models.SearchOrgUsersQuery) error SearchOrgUsers(ctx context.Context, query *models.SearchOrgUsersQuery) error
RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error
GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
GetDashboardTags(ctx context.Context, query *models.GetDashboardTagsQuery) error GetDashboardTags(ctx context.Context, query *models.GetDashboardTagsQuery) error
SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error
GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error

View File

@ -9,11 +9,14 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/segmentio/encoding/json"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/serverlock" "github.com/grafana/grafana/pkg/infra/serverlock"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/registry" "github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/live" "github.com/grafana/grafana/pkg/services/live"
@ -21,7 +24,6 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
"github.com/segmentio/encoding/json"
) )
type Service interface { type Service interface {
@ -53,6 +55,7 @@ type thumbService struct {
log log.Logger log log.Logger
canRunCrawler bool canRunCrawler bool
settings setting.DashboardPreviewsSettings settings setting.DashboardPreviewsSettings
dashboardService dashboards.DashboardService
} }
type crawlerScheduleOptions struct { type crawlerScheduleOptions struct {
@ -65,7 +68,10 @@ type crawlerScheduleOptions struct {
auth CrawlerAuth auth CrawlerAuth
} }
func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockService *serverlock.ServerLockService, renderService rendering.Service, gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService) Service { func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
lockService *serverlock.ServerLockService, renderService rendering.Service,
gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService,
dashboardService dashboards.DashboardService) Service {
if !features.IsEnabled(featuremgmt.FlagDashboardPreviews) { if !features.IsEnabled(featuremgmt.FlagDashboardPreviews) {
return &dummyService{} return &dummyService{}
} }
@ -96,7 +102,6 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockS
log: logger, log: logger,
canRunCrawler: canRunCrawler, canRunCrawler: canRunCrawler,
settings: cfg.DashboardPreviews, settings: cfg.DashboardPreviews,
scheduleOptions: crawlerScheduleOptions{ scheduleOptions: crawlerScheduleOptions{
tickerInterval: 5 * time.Minute, tickerInterval: 5 * time.Minute,
crawlInterval: cfg.DashboardPreviews.SchedulerInterval, crawlInterval: cfg.DashboardPreviews.SchedulerInterval,
@ -106,6 +111,7 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockS
themes: []models.Theme{models.ThemeDark, models.ThemeLight}, themes: []models.Theme{models.ThemeDark, models.ThemeLight},
auth: crawlerAuth, auth: crawlerAuth,
}, },
dashboardService: dashboardService,
} }
return t return t
@ -400,7 +406,7 @@ func (hs *thumbService) getStatus(c *models.ReqContext, uid string, checkSave bo
func (hs *thumbService) getDashboardId(c *models.ReqContext, uid string) (int64, error) { func (hs *thumbService) getDashboardId(c *models.ReqContext, uid string) (int64, error) {
query := models.GetDashboardQuery{Uid: uid, OrgId: c.OrgId} query := models.GetDashboardQuery{Uid: uid, OrgId: c.OrgId}
if err := hs.store.GetDashboard(c.Req.Context(), &query); err != nil { if err := hs.dashboardService.GetDashboard(c.Req.Context(), &query); err != nil {
return 0, err return 0, err
} }