diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 6337eafe1fc..5b066557d21 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -23,6 +23,7 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" ) func TestAnnotationsAPIEndpoint(t *testing.T) { @@ -922,7 +923,7 @@ func setUpACL() { viewerRole := org.RoleViewer editorRole := org.RoleEditor store := mockstore.NewSQLStoreMock() - store.ExpectedTeamsByUser = []*models.TeamDTO{} + teamSvc := &teamtest.FakeService{} dashSvc := &dashboards.FakeDashboardService{} dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardACLInfoListQuery) @@ -932,7 +933,7 @@ func setUpACL() { } }).Return(nil) - guardian.InitLegacyGuardian(store, dashSvc) + guardian.InitLegacyGuardian(store, dashSvc, teamSvc) } func setUpRBACGuardian(t *testing.T) { diff --git a/pkg/api/api.go b/pkg/api/api.go index dc7b0319a07..b4acf5a1224 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -58,7 +58,7 @@ func (hs *HTTPServer) registerRoutes() { reqGrafanaAdmin := middleware.ReqGrafanaAdmin reqEditorRole := middleware.ReqEditorRole reqOrgAdmin := middleware.ReqOrgAdmin - reqOrgAdminDashOrFolderAdminOrTeamAdmin := middleware.OrgAdminDashOrFolderAdminOrTeamAdmin(hs.SQLStore, hs.DashboardService) + reqOrgAdminDashOrFolderAdminOrTeamAdmin := middleware.OrgAdminDashOrFolderAdminOrTeamAdmin(hs.SQLStore, hs.DashboardService, hs.teamService) reqCanAccessTeams := middleware.AdminOrEditorAndFeatureEnabled(hs.Cfg.EditorsCanAdmin) reqSnapshotPublicModeOrSignedIn := middleware.SnapshotPublicModeOrSignedIn(hs.Cfg) redirectFromLegacyPanelEditURL := middleware.RedirectFromLegacyPanelEditURL(hs.Cfg) diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index ba4d9dbba55..838a24b102d 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -51,6 +51,9 @@ import ( "github.com/grafana/grafana/pkg/services/searchusers/filters" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team" + "github.com/grafana/grafana/pkg/services/team/teamimpl" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/setting" @@ -297,6 +300,7 @@ type accessControlScenarioContext struct { cfg *setting.Cfg dashboardsStore dashboards.Store + teamService team.Service } func setAccessControlPermissions(acmock *accesscontrolmock.Mock, perms []accesscontrol.Permission, org int64) { @@ -366,6 +370,7 @@ func setupHTTPServerWithCfgDb( license := &licensing.OSSLicensingService{} routeRegister := routing.NewRouteRegister() + teamService := teamimpl.ProvideService(db) dashboardsStore := dashboardsstore.ProvideDashboardStore(db, featuremgmt.WithFeatures()) var acmock *accesscontrolmock.Mock @@ -412,6 +417,7 @@ func setupHTTPServerWithCfgDb( preferenceService: preftest.NewPreferenceServiceFake(), userService: userMock, orgService: orgtest.NewOrgServiceFake(), + teamService: teamService, annotationsRepo: annotationstest.NewFakeAnnotationsRepo(), } @@ -447,6 +453,7 @@ func setupHTTPServerWithCfgDb( db: db, cfg: cfg, dashboardsStore: dashboardsStore, + teamService: teamService, usermock: userMock, } } @@ -524,11 +531,12 @@ func setUp(confs ...setUpConf) *HTTPServer { } } store.ExpectedTeamsByUser = []*models.TeamDTO{} + teamSvc := &teamtest.FakeService{} dashSvc := &dashboards.FakeDashboardService{} dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardACLInfoListQuery) q.Result = aclMockResp }).Return(nil) - guardian.InitLegacyGuardian(store, dashSvc) + guardian.InitLegacyGuardian(store, dashSvc, teamSvc) return hs } diff --git a/pkg/api/dashboard_snapshot_test.go b/pkg/api/dashboard_snapshot_test.go index 720964a84c3..f0ea1ffaba5 100644 --- a/pkg/api/dashboard_snapshot_test.go +++ b/pkg/api/dashboard_snapshot_test.go @@ -20,6 +20,7 @@ import ( "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" ) func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) { @@ -70,10 +71,11 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) { hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, 0, "")} sc.handlerFunc = hs.DeleteDashboardSnapshot + teamSvc := &teamtest.FakeService{} dashSvc := dashboards.NewFakeDashboardService(t) dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Return(nil).Maybe() - guardian.InitLegacyGuardian(sc.sqlStore, dashSvc) + guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc) sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec() assert.Equal(t, 403, sc.resp.Code) @@ -107,6 +109,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) { }) t.Run("When user is editor and dashboard has default ACL", func(t *testing.T) { + teamSvc := &teamtest.FakeService{} dashSvc := &dashboards.FakeDashboardService{} dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardACLInfoListQuery) @@ -118,7 +121,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) { loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) { - guardian.InitLegacyGuardian(sc.sqlStore, dashSvc) + guardian.InitLegacyGuardian(sc.sqlStore, dashSvc, teamSvc) var externalRequest *http.Request ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(200) diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index c53fb3aca02..ffa8d59dc08 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -39,6 +39,7 @@ import ( "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" @@ -129,6 +130,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.HasACL = false fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake() fakeDashboardVersionService.ExpectedDashboardVersion = &dashver.DashboardVersion{} + teamService := &teamtest.FakeService{} dashboardService := dashboards.NewFakeDashboardService(t) dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardQuery) @@ -157,7 +159,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { {Role: &editorRole, Permission: models.PERMISSION_EDIT}, } }).Return(nil) - guardian.InitLegacyGuardian(mockSQLStore, dashboardService) + guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService) } // This tests two scenarios: @@ -235,6 +237,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.HasACL = true fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake() fakeDashboardVersionService.ExpectedDashboardVersion = &dashver.DashboardVersion{} + teamService := &teamtest.FakeService{} dashboardService := dashboards.NewFakeDashboardService(t) dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardQuery) @@ -274,7 +277,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { setting.ViewersCanEdit = origCanEdit }) setting.ViewersCanEdit = false - guardian.InitLegacyGuardian(mockSQLStore, dashboardService) + guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService) } // This tests six scenarios: @@ -378,7 +381,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { {OrgId: 1, DashboardId: 2, UserId: 1, Permission: models.PERMISSION_EDIT}, } }).Return(nil) - guardian.InitLegacyGuardian(mockSQLStore, dashboardService) + guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService) } loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", @@ -440,7 +443,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { {OrgId: 1, DashboardId: 2, UserId: 1, Permission: models.PERMISSION_VIEW}, } }).Return(nil) - guardian.InitLegacyGuardian(mockSQLStore, dashboardService) + guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService) } loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { @@ -480,7 +483,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { {OrgId: 1, DashboardId: 2, UserId: 1, Permission: models.PERMISSION_ADMIN}, } }).Return(nil) - guardian.InitLegacyGuardian(mockSQLStore, dashboardService) + guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService) } loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { @@ -533,7 +536,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { {OrgId: 1, DashboardId: 2, UserId: 1, Permission: models.PERMISSION_VIEW}, } }).Return(nil) - guardian.InitLegacyGuardian(mockSQLStore, dashboardService) + guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService) } loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { @@ -743,9 +746,10 @@ func TestDashboardAPIEndpoint(t *testing.T) { } sqlmock := mockstore.SQLStoreMock{} setUp := func() { + teamSvc := &teamtest.FakeService{} dashSvc := dashboards.NewFakeDashboardService(t) dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Return(nil) - guardian.InitLegacyGuardian(&sqlmock, dashSvc) + guardian.InitLegacyGuardian(&sqlmock, dashSvc, teamSvc) } cmd := dtos.CalculateDiffOptions{ @@ -861,6 +865,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { dashboardStore := dashboards.NewFakeDashboardStore(t) dashboardStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(&models.DashboardProvisioning{ExternalId: "/dashboard1.json"}, nil).Once() + teamService := &teamtest.FakeService{} dashboardService := dashboards.NewFakeDashboardService(t) dataValue, err := simplejson.NewJson([]byte(`{"id": 1, "editable": true, "style": "dark"}`)) @@ -873,7 +878,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { q := args.Get(1).(*models.GetDashboardACLInfoListQuery) q.Result = []*models.DashboardACLInfoDTO{{OrgId: testOrgID, DashboardId: 1, UserId: testUserID, Permission: models.PERMISSION_EDIT}} }).Return(nil) - guardian.InitLegacyGuardian(mockSQLStore, dashboardService) + guardian.InitLegacyGuardian(mockSQLStore, dashboardService, teamService) loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", org.RoleEditor, func(sc *scenarioContext) { fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background()) diff --git a/pkg/api/folder_test.go b/pkg/api/folder_test.go index 4c7612fd054..7bd1a30fec0 100644 --- a/pkg/api/folder_test.go +++ b/pkg/api/folder_test.go @@ -22,6 +22,7 @@ import ( "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web/webtest" @@ -237,13 +238,14 @@ func createFolderScenario(t *testing.T, desc string, url string, routePattern st setUpRBACGuardian(t) t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { aclMockResp := []*models.DashboardACLInfoDTO{} + teamSvc := &teamtest.FakeService{} dashSvc := &dashboards.FakeDashboardService{} dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardACLInfoListQuery) q.Result = aclMockResp }).Return(nil) store := mockstore.NewSQLStoreMock() - guardian.InitLegacyGuardian(store, dashSvc) + guardian.InitLegacyGuardian(store, dashSvc, teamSvc) hs := HTTPServer{ AccessControl: acmock.New(), folderService: folderService, diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 84f789f26e1..965addec765 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -84,6 +84,7 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/star" "github.com/grafana/grafana/pkg/services/store" + "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/teamguardian" tempUser "github.com/grafana/grafana/pkg/services/temp_user" "github.com/grafana/grafana/pkg/services/thumbs" @@ -189,6 +190,7 @@ type HTTPServer struct { dashboardThumbsService dashboardThumbs.Service loginAttemptService loginAttempt.Service orgService org.Service + teamService team.Service accesscontrolService accesscontrol.Service annotationsRepo annotations.Repository } @@ -228,7 +230,8 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi playlistService playlist.Service, apiKeyService apikey.Service, kvStore kvstore.KVStore, secretsMigrator secrets.Migrator, secretsPluginManager plugins.SecretsPluginManager, secretsService secrets.Service, secretsPluginMigrator spm.SecretMigrationProvider, secretsStore secretsKV.SecretsKVStore, - publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service, loginAttemptService loginAttempt.Service, orgService org.Service, + publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service, + loginAttemptService loginAttempt.Service, orgService org.Service, teamService team.Service, accesscontrolService accesscontrol.Service, dashboardThumbsService dashboardThumbs.Service, annotationRepo annotations.Repository, ) (*HTTPServer, error) { web.Env = cfg.Env @@ -324,6 +327,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi dashboardThumbsService: dashboardThumbsService, loginAttemptService: loginAttemptService, orgService: orgService, + teamService: teamService, accesscontrolService: accesscontrolService, annotationsRepo: annotationRepo, } diff --git a/pkg/api/org_users_test.go b/pkg/api/org_users_test.go index 41a905ae408..e2b901e41ba 100644 --- a/pkg/api/org_users_test.go +++ b/pkg/api/org_users_test.go @@ -185,9 +185,9 @@ func TestOrgUsersAPIEndpoint_LegacyAccessControl_TeamAdmin(t *testing.T) { setInitCtxSignedInViewer(sc.initCtx) // Setup store teams - team1, err := sc.db.CreateTeam("testteam1", "testteam1@example.org", testOrgID) + team1, err := sc.teamService.CreateTeam("testteam1", "testteam1@example.org", testOrgID) require.NoError(t, err) - err = sc.db.AddTeamMember(testUserID, testOrgID, team1.Id, false, models.PERMISSION_ADMIN) + err = sc.teamService.AddTeamMember(testUserID, testOrgID, team1.Id, false, models.PERMISSION_ADMIN) require.NoError(t, err) response := callAPI(sc.server, http.MethodGet, "/api/org/users/lookup", nil, t) diff --git a/pkg/api/team.go b/pkg/api/team.go index bb94d9f867a..01d33d69fa1 100644 --- a/pkg/api/team.go +++ b/pkg/api/team.go @@ -33,7 +33,7 @@ func (hs *HTTPServer) CreateTeam(c *models.ReqContext) response.Response { return response.Error(403, "Not allowed to create team.", nil) } - team, err := hs.SQLStore.CreateTeam(cmd.Name, cmd.Email, c.OrgID) + team, err := hs.teamService.CreateTeam(cmd.Name, cmd.Email, c.OrgID) if err != nil { if errors.Is(err, models.ErrTeamNameTaken) { return response.Error(409, "Team name taken", err) @@ -88,7 +88,7 @@ func (hs *HTTPServer) UpdateTeam(c *models.ReqContext) response.Response { } } - if err := hs.SQLStore.UpdateTeam(c.Req.Context(), &cmd); err != nil { + if err := hs.teamService.UpdateTeam(c.Req.Context(), &cmd); err != nil { if errors.Is(err, models.ErrTeamNameTaken) { return response.Error(400, "Team name taken", err) } @@ -122,7 +122,7 @@ func (hs *HTTPServer) DeleteTeamByID(c *models.ReqContext) response.Response { } } - if err := hs.SQLStore.DeleteTeam(c.Req.Context(), &models.DeleteTeamCommand{OrgId: orgId, Id: teamId}); err != nil { + if err := hs.teamService.DeleteTeam(c.Req.Context(), &models.DeleteTeamCommand{OrgId: orgId, Id: teamId}); err != nil { if errors.Is(err, models.ErrTeamNotFound) { return response.Error(404, "Failed to delete Team. ID not found", nil) } @@ -167,7 +167,7 @@ func (hs *HTTPServer) SearchTeams(c *models.ReqContext) response.Response { HiddenUsers: hs.Cfg.HiddenUsers, } - if err := hs.SQLStore.SearchTeams(c.Req.Context(), &query); err != nil { + if err := hs.teamService.SearchTeams(c.Req.Context(), &query); err != nil { return response.Error(500, "Failed to search Teams", err) } @@ -231,7 +231,7 @@ func (hs *HTTPServer) GetTeamByID(c *models.ReqContext) response.Response { UserIdFilter: userIdFilter, } - if err := hs.SQLStore.GetTeamById(c.Req.Context(), &query); err != nil { + if err := hs.teamService.GetTeamById(c.Req.Context(), &query); err != nil { if errors.Is(err, models.ErrTeamNotFound) { return response.Error(404, "Team not found", err) } diff --git a/pkg/api/team_members.go b/pkg/api/team_members.go index fc99a1a8bfe..b85bffc881f 100644 --- a/pkg/api/team_members.go +++ b/pkg/api/team_members.go @@ -42,7 +42,7 @@ func (hs *HTTPServer) GetTeamMembers(c *models.ReqContext) response.Response { } } - if err := hs.SQLStore.GetTeamMembers(c.Req.Context(), &query); err != nil { + if err := hs.teamService.GetTeamMembers(c.Req.Context(), &query); err != nil { return response.Error(500, "Failed to get Team Members", err) } @@ -94,7 +94,7 @@ func (hs *HTTPServer) AddTeamMember(c *models.ReqContext) response.Response { } } - isTeamMember, err := hs.SQLStore.IsTeamMember(c.OrgID, cmd.TeamId, cmd.UserId) + isTeamMember, err := hs.teamService.IsTeamMember(c.OrgID, cmd.TeamId, cmd.UserId) if err != nil { return response.Error(500, "Failed to add team member.", err) } @@ -143,7 +143,7 @@ func (hs *HTTPServer) UpdateTeamMember(c *models.ReqContext) response.Response { } } - isTeamMember, err := hs.SQLStore.IsTeamMember(orgId, teamId, userId) + isTeamMember, err := hs.teamService.IsTeamMember(orgId, teamId, userId) if err != nil { return response.Error(500, "Failed to update team member.", err) } diff --git a/pkg/api/team_members_test.go b/pkg/api/team_members_test.go index 155ee84465b..f03e2548a48 100644 --- a/pkg/api/team_members_test.go +++ b/pkg/api/team_members_test.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/teamguardian/database" "github.com/grafana/grafana/pkg/services/teamguardian/manager" "github.com/grafana/grafana/pkg/services/user" @@ -62,6 +63,7 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) { sqlStore.Cfg = settings hs.SQLStore = sqlStore + hs.teamService = teamimpl.ProvideService(sqlStore) hs.License = &licensing.OSSLicensingService{} hs.teamGuardian = &TeamGuardianMock{} mock := mockstore.NewSQLStoreMock() @@ -120,19 +122,20 @@ func createUser(db sqlstore.Store, orgId int64, t *testing.T) int64 { } func setupTeamTestScenario(userCount int, db sqlstore.Store, t *testing.T) int64 { + teamService := teamimpl.ProvideService(db.(*sqlstore.SQLStore)) // FIXME user, err := db.CreateUser(context.Background(), user.CreateUserCommand{SkipOrgSetup: true, Login: testUserLogin}) require.NoError(t, err) testOrg, err := db.CreateOrgWithMember("TestOrg", user.ID) require.NoError(t, err) - team, err := db.CreateTeam("test", "test@test.com", testOrg.Id) + team, err := teamService.CreateTeam("test", "test@test.com", testOrg.Id) require.NoError(t, err) for i := 0; i < userCount; i++ { userId := createUser(db, testOrg.Id, t) require.NoError(t, err) - err = db.AddTeamMember(userId, testOrg.Id, team.Id, false, 0) + err = teamService.AddTeamMember(userId, testOrg.Id, team.Id, false, 0) require.NoError(t, err) } @@ -153,7 +156,7 @@ func TestAddTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { cfg.RBACEnabled = false cfg.EditorsCanAdmin = true sc := setupHTTPServerWithCfg(t, true, cfg) - guardian := manager.ProvideService(database.ProvideTeamGuardianStore(sc.db)) + guardian := manager.ProvideService(database.ProvideTeamGuardianStore(sc.db, sc.teamService)) sc.hs.teamGuardian = guardian teamMemberCount := 3 @@ -176,7 +179,7 @@ func TestAddTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) }) - err := sc.db.AddTeamMember(sc.initCtx.UserID, 1, 1, false, 0) + err := sc.teamService.AddTeamMember(sc.initCtx.UserID, 1, 1, false, 0) require.NoError(t, err) input = strings.NewReader(fmt.Sprintf(createTeamMemberCmd, newUserId)) t.Run("Team members cannot add team members", func(t *testing.T) { @@ -184,7 +187,7 @@ func TestAddTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) }) - err = sc.db.UpdateTeamMember(context.Background(), &models.UpdateTeamMemberCommand{ + err = sc.teamService.UpdateTeamMember(context.Background(), &models.UpdateTeamMemberCommand{ UserId: sc.initCtx.UserID, OrgId: 1, TeamId: 1, @@ -290,7 +293,7 @@ func TestUpdateTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { cfg.RBACEnabled = false cfg.EditorsCanAdmin = true sc := setupHTTPServerWithCfg(t, true, cfg) - guardian := manager.ProvideService(database.ProvideTeamGuardianStore(sc.db)) + guardian := manager.ProvideService(database.ProvideTeamGuardianStore(sc.db, sc.teamService)) sc.hs.teamGuardian = guardian teamMemberCount := 3 @@ -311,7 +314,7 @@ func TestUpdateTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) }) - err := sc.db.AddTeamMember(sc.initCtx.UserID, 1, 1, false, 0) + err := sc.teamService.AddTeamMember(sc.initCtx.UserID, 1, 1, false, 0) require.NoError(t, err) input = strings.NewReader(fmt.Sprintf(updateTeamMemberCmd, 0)) t.Run("Team members cannot update team members", func(t *testing.T) { @@ -319,7 +322,7 @@ func TestUpdateTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) }) - err = sc.db.UpdateTeamMember(context.Background(), &models.UpdateTeamMemberCommand{ + err = sc.teamService.UpdateTeamMember(context.Background(), &models.UpdateTeamMemberCommand{ UserId: sc.initCtx.UserID, OrgId: 1, TeamId: 1, @@ -369,7 +372,7 @@ func TestDeleteTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { cfg.RBACEnabled = false cfg.EditorsCanAdmin = true sc := setupHTTPServerWithCfg(t, true, cfg) - guardian := manager.ProvideService(database.ProvideTeamGuardianStore(sc.db)) + guardian := manager.ProvideService(database.ProvideTeamGuardianStore(sc.db, sc.teamService)) sc.hs.teamGuardian = guardian teamMemberCount := 3 @@ -388,14 +391,14 @@ func TestDeleteTeamMembersAPIEndpoint_LegacyAccessControl(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) }) - err := sc.db.AddTeamMember(sc.initCtx.UserID, 1, 1, false, 0) + err := sc.teamService.AddTeamMember(sc.initCtx.UserID, 1, 1, false, 0) require.NoError(t, err) t.Run("Team members cannot remove team members", func(t *testing.T) { response := callAPI(sc.server, http.MethodDelete, fmt.Sprintf(teamMemberDeleteRoute, "1", "3"), nil, t) assert.Equal(t, http.StatusForbidden, response.Code) }) - err = sc.db.UpdateTeamMember(context.Background(), &models.UpdateTeamMemberCommand{ + err = sc.teamService.UpdateTeamMember(context.Background(), &models.UpdateTeamMemberCommand{ UserId: sc.initCtx.UserID, OrgId: 1, TeamId: 1, diff --git a/pkg/api/team_test.go b/pkg/api/team_test.go index eff5a77129e..1ee9f97a3d9 100644 --- a/pkg/api/team_test.go +++ b/pkg/api/team_test.go @@ -19,6 +19,8 @@ import ( "github.com/grafana/grafana/pkg/services/preference/preftest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamimpl" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" @@ -30,14 +32,15 @@ func TestTeamAPIEndpoint(t *testing.T) { hs.Cfg.EditorsCanAdmin = true store := sqlstore.InitTestDB(t) store.Cfg = hs.Cfg + hs.teamService = teamimpl.ProvideService(store) hs.SQLStore = store mock := &mockstore.SQLStoreMock{} loggedInUserScenarioWithRole(t, "When admin is calling GET on", "GET", "/api/teams/search", "/api/teams/search", org.RoleAdmin, func(sc *scenarioContext) { - _, err := hs.SQLStore.CreateTeam("team1", "", 1) + _, err := hs.teamService.CreateTeam("team1", "", 1) require.NoError(t, err) - _, err = hs.SQLStore.CreateTeam("team2", "", 1) + _, err = hs.teamService.CreateTeam("team2", "", 1) require.NoError(t, err) sc.handlerFunc = hs.SearchTeams @@ -53,13 +56,13 @@ func TestTeamAPIEndpoint(t *testing.T) { loggedInUserScenario(t, "When editor (with editors_can_admin) is calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) { - team1, err := hs.SQLStore.CreateTeam("team1", "", 1) + team1, err := hs.teamService.CreateTeam("team1", "", 1) require.NoError(t, err) - _, err = hs.SQLStore.CreateTeam("team2", "", 1) + _, err = hs.teamService.CreateTeam("team2", "", 1) require.NoError(t, err) // Adding the test user to the teams in order for him to list them - err = hs.SQLStore.AddTeamMember(testUserID, testOrgID, team1.Id, false, 0) + err = hs.teamService.AddTeamMember(testUserID, testOrgID, team1.Id, false, 0) require.NoError(t, err) sc.handlerFunc = hs.SearchTeams @@ -75,15 +78,15 @@ func TestTeamAPIEndpoint(t *testing.T) { loggedInUserScenario(t, "When editor (with editors_can_admin) calling GET with pagination on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) { - team1, err := hs.SQLStore.CreateTeam("team1", "", 1) + team1, err := hs.teamService.CreateTeam("team1", "", 1) require.NoError(t, err) - team2, err := hs.SQLStore.CreateTeam("team2", "", 1) + team2, err := hs.teamService.CreateTeam("team2", "", 1) require.NoError(t, err) // Adding the test user to the teams in order for him to list them - err = hs.SQLStore.AddTeamMember(testUserID, testOrgID, team1.Id, false, 0) + err = hs.teamService.AddTeamMember(testUserID, testOrgID, team1.Id, false, 0) require.NoError(t, err) - err = hs.SQLStore.AddTeamMember(testUserID, testOrgID, team2.Id, false, 0) + err = hs.teamService.AddTeamMember(testUserID, testOrgID, team2.Id, false, 0) require.NoError(t, err) sc.handlerFunc = hs.SearchTeams @@ -102,6 +105,7 @@ func TestTeamAPIEndpoint(t *testing.T) { hs := setupSimpleHTTPServer(nil) hs.Cfg.EditorsCanAdmin = true hs.SQLStore = mockstore.NewSQLStoreMock() + hs.teamService = &teamtest.FakeService{} teamName := "team foo" addTeamMemberCalled := 0 @@ -216,7 +220,7 @@ func TestTeamAPIEndpoint_SearchTeams_RBAC(t *testing.T) { sc := setupHTTPServer(t, true) // Seed three teams for i := 1; i <= 3; i++ { - _, err := sc.db.CreateTeam(fmt.Sprintf("team%d", i), fmt.Sprintf("team%d@example.org", i), 1) + _, err := sc.teamService.CreateTeam(fmt.Sprintf("team%d", i), fmt.Sprintf("team%d@example.org", i), 1) require.NoError(t, err) } @@ -260,7 +264,7 @@ func TestTeamAPIEndpoint_GetTeamByID_RBAC(t *testing.T) { sc := setupHTTPServer(t, true) sc.db = sqlstore.InitTestDB(t) - _, err := sc.db.CreateTeam("team1", "team1@example.org", 1) + _, err := sc.teamService.CreateTeam("team1", "team1@example.org", 1) require.NoError(t, err) setInitCtxSignedInViewer(sc.initCtx) @@ -289,7 +293,7 @@ func TestTeamAPIEndpoint_GetTeamByID_RBAC(t *testing.T) { func TestTeamAPIEndpoint_UpdateTeam_RBAC(t *testing.T) { sc := setupHTTPServer(t, true) sc.db = sqlstore.InitTestDB(t) - _, err := sc.db.CreateTeam("team1", "", 1) + _, err := sc.teamService.CreateTeam("team1", "", 1) require.NoError(t, err) @@ -302,7 +306,7 @@ func TestTeamAPIEndpoint_UpdateTeam_RBAC(t *testing.T) { assert.Equal(t, http.StatusOK, response.Code) teamQuery := &models.GetTeamByIdQuery{OrgId: 1, SignedInUser: sc.initCtx.SignedInUser, Id: 1, Result: &models.TeamDTO{}} - err := sc.db.GetTeamById(context.Background(), teamQuery) + err := sc.teamService.GetTeamById(context.Background(), teamQuery) require.NoError(t, err) assert.Equal(t, "MyTestTeam1", teamQuery.Result.Name) }) @@ -314,7 +318,7 @@ func TestTeamAPIEndpoint_UpdateTeam_RBAC(t *testing.T) { assert.Equal(t, http.StatusOK, response.Code) teamQuery := &models.GetTeamByIdQuery{OrgId: 1, SignedInUser: sc.initCtx.SignedInUser, Id: 1, Result: &models.TeamDTO{}} - err := sc.db.GetTeamById(context.Background(), teamQuery) + err := sc.teamService.GetTeamById(context.Background(), teamQuery) require.NoError(t, err) assert.Equal(t, "MyTestTeam2", teamQuery.Result.Name) }) @@ -326,7 +330,7 @@ func TestTeamAPIEndpoint_UpdateTeam_RBAC(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) teamQuery := &models.GetTeamByIdQuery{OrgId: 1, SignedInUser: sc.initCtx.SignedInUser, Id: 1, Result: &models.TeamDTO{}} - err := sc.db.GetTeamById(context.Background(), teamQuery) + err := sc.teamService.GetTeamById(context.Background(), teamQuery) assert.NoError(t, err) assert.Equal(t, "MyTestTeam2", teamQuery.Result.Name) }) @@ -338,7 +342,7 @@ func TestTeamAPIEndpoint_UpdateTeam_RBAC(t *testing.T) { func TestTeamAPIEndpoint_DeleteTeam_RBAC(t *testing.T) { sc := setupHTTPServer(t, true) sc.db = sqlstore.InitTestDB(t) - _, err := sc.db.CreateTeam("team1", "", 1) + _, err := sc.teamService.CreateTeam("team1", "", 1) require.NoError(t, err) setInitCtxSignedInViewer(sc.initCtx) @@ -349,7 +353,7 @@ func TestTeamAPIEndpoint_DeleteTeam_RBAC(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) teamQuery := &models.GetTeamByIdQuery{OrgId: 1, SignedInUser: sc.initCtx.SignedInUser, Id: 1, Result: &models.TeamDTO{}} - err := sc.db.GetTeamById(context.Background(), teamQuery) + err := sc.teamService.GetTeamById(context.Background(), teamQuery) require.NoError(t, err) }) @@ -359,7 +363,7 @@ func TestTeamAPIEndpoint_DeleteTeam_RBAC(t *testing.T) { assert.Equal(t, http.StatusOK, response.Code) teamQuery := &models.GetTeamByIdQuery{OrgId: 1, SignedInUser: sc.initCtx.SignedInUser, Id: 1, Result: &models.TeamDTO{}} - err := sc.db.GetTeamById(context.Background(), teamQuery) + err := sc.teamService.GetTeamById(context.Background(), teamQuery) require.ErrorIs(t, err, models.ErrTeamNotFound) }) } @@ -370,7 +374,7 @@ func TestTeamAPIEndpoint_DeleteTeam_RBAC(t *testing.T) { func TestTeamAPIEndpoint_GetTeamPreferences_RBAC(t *testing.T) { sc := setupHTTPServer(t, true) sc.db = sqlstore.InitTestDB(t) - _, err := sc.db.CreateTeam("team1", "", 1) + _, err := sc.teamService.CreateTeam("team1", "", 1) sqlstore := mockstore.NewSQLStoreMock() sc.hs.SQLStore = sqlstore @@ -409,7 +413,7 @@ func TestTeamAPIEndpoint_UpdateTeamPreferences_RBAC(t *testing.T) { prefService.ExpectedPreference = &pref.Preference{Theme: "dark"} sc.hs.preferenceService = prefService - _, err := sc.db.CreateTeam("team1", "", 1) + _, err := sc.teamService.CreateTeam("team1", "", 1) require.NoError(t, err) diff --git a/pkg/api/user.go b/pkg/api/user.go index ab915476e42..8e870eb0d57 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -254,7 +254,7 @@ func (hs *HTTPServer) GetUserTeams(c *models.ReqContext) response.Response { func (hs *HTTPServer) getUserTeamList(c *models.ReqContext, orgID int64, userID int64) response.Response { query := models.GetTeamsByUserQuery{OrgId: orgID, UserId: userID, SignedInUser: c.SignedInUser} - if err := hs.SQLStore.GetTeamsByUser(c.Req.Context(), &query); err != nil { + if err := hs.teamService.GetTeamsByUser(c.Req.Context(), &query); err != nil { return response.Error(500, "Failed to get user teams", err) } diff --git a/pkg/cmd/grafana-cli/runner/wire.go b/pkg/cmd/grafana-cli/runner/wire.go index 77b4333e903..50f067059b8 100644 --- a/pkg/cmd/grafana-cli/runner/wire.go +++ b/pkg/cmd/grafana-cli/runner/wire.go @@ -116,6 +116,7 @@ import ( "github.com/grafana/grafana/pkg/services/star/starimpl" "github.com/grafana/grafana/pkg/services/store" "github.com/grafana/grafana/pkg/services/store/sanitizer" + "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/teamguardian" teamguardianDatabase "github.com/grafana/grafana/pkg/services/teamguardian/database" teamguardianManager "github.com/grafana/grafana/pkg/services/teamguardian/manager" @@ -319,6 +320,7 @@ var wireSet = wire.NewSet( publicdashboardsApi.ProvideApi, userimpl.ProvideService, orgimpl.ProvideService, + teamimpl.ProvideService, userauthimpl.ProvideService, ngmetrics.ProvideServiceForTest, wire.Bind(new(sqlstore.TeamStore), new(*sqlstore.SQLStore)), diff --git a/pkg/middleware/auth.go b/pkg/middleware/auth.go index 85147ea083d..ea5b91597e2 100644 --- a/pkg/middleware/auth.go +++ b/pkg/middleware/auth.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -193,7 +194,7 @@ func shouldForceLogin(c *models.ReqContext) bool { return forceLogin } -func OrgAdminDashOrFolderAdminOrTeamAdmin(ss sqlstore.Store, ds dashboards.DashboardService) func(c *models.ReqContext) { +func OrgAdminDashOrFolderAdminOrTeamAdmin(ss sqlstore.Store, ds dashboards.DashboardService, ts team.Service) func(c *models.ReqContext) { return func(c *models.ReqContext) { if c.OrgRole == org.RoleAdmin { return @@ -209,7 +210,7 @@ func OrgAdminDashOrFolderAdminOrTeamAdmin(ss sqlstore.Store, ds dashboards.Dashb } isAdminOfTeamsQuery := models.IsAdminOfTeamsQuery{SignedInUser: c.SignedInUser} - if err := ss.IsAdminOfTeams(c.Req.Context(), &isAdminOfTeamsQuery); err != nil { + if err := ts.IsAdminOfTeams(c.Req.Context(), &isAdminOfTeamsQuery); err != nil { c.JsonApiErr(500, "Failed to check if user is a team admin", err) } diff --git a/pkg/services/dashboards/service/dashboard_service_integration_test.go b/pkg/services/dashboards/service/dashboard_service_integration_test.go index 96848122c1c..33ee9be9362 100644 --- a/pkg/services/dashboards/service/dashboard_service_integration_test.go +++ b/pkg/services/dashboards/service/dashboard_service_integration_test.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -826,7 +827,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.New(), ) - guardian.InitLegacyGuardian(sqlStore, service) + guardian.InitLegacyGuardian(sqlStore, service, &teamtest.FakeService{}) savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore) savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.Id, sqlStore) diff --git a/pkg/services/guardian/guardian.go b/pkg/services/guardian/guardian.go index ee841fa7229..acca3493321 100644 --- a/pkg/services/guardian/guardian.go +++ b/pkg/services/guardian/guardian.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -48,6 +49,7 @@ type dashboardGuardianImpl struct { ctx context.Context store sqlstore.Store dashboardService dashboards.DashboardService + teamService team.Service } // New factory for creating a new dashboard guardian instance @@ -56,7 +58,7 @@ var New = func(ctx context.Context, dashId int64, orgId int64, user *user.Signed panic("no guardian factory implementation provided") } -func newDashboardGuardian(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser, store sqlstore.Store, dashSvc dashboards.DashboardService) *dashboardGuardianImpl { +func newDashboardGuardian(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser, store sqlstore.Store, dashSvc dashboards.DashboardService, teamSvc team.Service) *dashboardGuardianImpl { return &dashboardGuardianImpl{ user: user, dashId: dashId, @@ -65,6 +67,7 @@ func newDashboardGuardian(ctx context.Context, dashId int64, orgId int64, user * ctx: ctx, store: store, dashboardService: dashSvc, + teamService: teamSvc, } } @@ -276,7 +279,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*models.TeamDTO, error) { } query := models.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserID, SignedInUser: g.user} - err := g.store.GetTeamsByUser(g.ctx, &query) + err := g.teamService.GetTeamsByUser(g.ctx, &query) g.teams = query.Result return query.Result, err diff --git a/pkg/services/guardian/guardian_test.go b/pkg/services/guardian/guardian_test.go index 650382b9d58..a0345a25070 100644 --- a/pkg/services/guardian/guardian_test.go +++ b/pkg/services/guardian/guardian_test.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -706,7 +707,7 @@ func TestGuardianGetHiddenACL(t *testing.T) { UserID: 1, Login: "user1", } - g := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc) + g := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{}) hiddenACL, err := g.GetHiddenACL(cfg) require.NoError(t, err) @@ -722,7 +723,7 @@ func TestGuardianGetHiddenACL(t *testing.T) { Login: "user1", IsGrafanaAdmin: true, } - g := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, &dashboards.FakeDashboardService{}) + g := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, &dashboards.FakeDashboardService{}, &teamtest.FakeService{}) hiddenACL, err := g.GetHiddenACL(cfg) require.NoError(t, err) @@ -756,7 +757,7 @@ func TestGuardianGetACLWithoutDuplicates(t *testing.T) { UserID: 1, Login: "user1", } - g := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc) + g := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, dashSvc, &teamtest.FakeService{}) acl, err := g.GetACLWithoutDuplicates() require.NoError(t, err) diff --git a/pkg/services/guardian/guardian_util_test.go b/pkg/services/guardian/guardian_util_test.go index 71b4cc4468e..359b0f2df52 100644 --- a/pkg/services/guardian/guardian_util_test.go +++ b/pkg/services/guardian/guardian_util_test.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" ) @@ -42,7 +43,7 @@ func orgRoleScenario(desc string, t *testing.T, role org.RoleType, fn scenarioFu OrgRole: role, } store := mockstore.NewSQLStoreMock() - guard := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, &dashboards.FakeDashboardService{}) + guard := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, &dashboards.FakeDashboardService{}, &teamtest.FakeService{}) sc := &scenarioContext{ t: t, @@ -64,7 +65,7 @@ func apiKeyScenario(desc string, t *testing.T, role org.RoleType, fn scenarioFun ApiKeyID: 10, } store := mockstore.NewSQLStoreMock() - guard := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, &dashboards.FakeDashboardService{}) + guard := newDashboardGuardian(context.Background(), dashboardID, orgID, user, store, &dashboards.FakeDashboardService{}, &teamtest.FakeService{}) sc := &scenarioContext{ t: t, orgRoleScenario: desc, @@ -88,7 +89,7 @@ func permissionScenario(desc string, dashboardID int64, sc *scenarioContext, teams = append(teams, &models.TeamDTO{Id: p.TeamId}) } } - store.ExpectedTeamsByUser = teams + teamSvc := &teamtest.FakeService{ExpectedTeamsByUser: teams} dashSvc := dashboards.NewFakeDashboardService(t) dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) { @@ -97,7 +98,7 @@ func permissionScenario(desc string, dashboardID int64, sc *scenarioContext, }).Return(nil) sc.permissionScenario = desc - sc.g = newDashboardGuardian(context.Background(), dashboardID, sc.givenUser.OrgID, sc.givenUser, store, dashSvc) + sc.g = newDashboardGuardian(context.Background(), dashboardID, sc.givenUser.OrgID, sc.givenUser, store, dashSvc, teamSvc) sc.givenDashboardID = dashboardID sc.givenPermissions = permissions sc.givenTeams = teams diff --git a/pkg/services/guardian/provider.go b/pkg/services/guardian/provider.go index d0a95c0f63c..689438bd7df 100644 --- a/pkg/services/guardian/provider.go +++ b/pkg/services/guardian/provider.go @@ -6,6 +6,7 @@ import ( "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/team" "github.com/grafana/grafana/pkg/services/user" ) @@ -14,20 +15,20 @@ type Provider struct{} func ProvideService( store *sqlstore.SQLStore, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService, - dashboardService dashboards.DashboardService, + dashboardService dashboards.DashboardService, teamService team.Service, ) *Provider { if !ac.IsDisabled() { // TODO: Fix this hack, see https://github.com/grafana/grafana-enterprise/issues/2935 InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService) } else { - InitLegacyGuardian(store, dashboardService) + InitLegacyGuardian(store, dashboardService, teamService) } return &Provider{} } -func InitLegacyGuardian(store sqlstore.Store, dashSvc dashboards.DashboardService) { +func InitLegacyGuardian(store sqlstore.Store, dashSvc dashboards.DashboardService, teamSvc team.Service) { New = func(ctx context.Context, dashId int64, orgId int64, user *user.SignedInUser) DashboardGuardian { - return newDashboardGuardian(ctx, dashId, orgId, user, store, dashSvc) + return newDashboardGuardian(ctx, dashId, orgId, user, store, dashSvc, teamSvc) } } diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index eb94a30a822..512ba461d33 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -26,6 +26,7 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" @@ -378,7 +379,7 @@ func validateAndUnMarshalArrayResponse(t *testing.T, resp response.Response) lib func scenarioWithPanel(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) { t.Helper() store := mockstore.NewSQLStoreMock() - guardian.InitLegacyGuardian(store, &dashboards.FakeDashboardService{}) + guardian.InitLegacyGuardian(store, &dashboards.FakeDashboardService{}, &teamtest.FakeService{}) testScenario(t, desc, func(t *testing.T, sc scenarioContext) { command := getCreatePanelCommand(sc.folder.Id, "Text - Library Panel") @@ -415,7 +416,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo sqlStore.Cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac, ) - guardian.InitLegacyGuardian(sqlStore, dashboardService) + guardian.InitLegacyGuardian(sqlStore, dashboardService, &teamtest.FakeService{}) service := LibraryElementService{ Cfg: sqlStore.Cfg, SQLStore: sqlStore, diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index 3d19e30e9f9..b343220bd72 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -24,6 +24,7 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -1441,7 +1442,7 @@ func updateFolderACL(t *testing.T, dashboardStore *database.DashboardStore, fold func scenarioWithLibraryPanel(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) { store := mockstore.NewSQLStoreMock() - guardian.InitLegacyGuardian(store, &dashboards.FakeDashboardService{}) + guardian.InitLegacyGuardian(store, &dashboards.FakeDashboardService{}, &teamtest.FakeService{}) t.Helper() testScenario(t, desc, func(t *testing.T, sc scenarioContext) { diff --git a/pkg/services/sqlstore/store.go b/pkg/services/sqlstore/store.go index 1b4893aaba5..d34508d256b 100644 --- a/pkg/services/sqlstore/store.go +++ b/pkg/services/sqlstore/store.go @@ -30,18 +30,6 @@ type Store interface { GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error UpdateUserPermissions(userID int64, isAdmin bool) error SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHelpFlagCommand) error - CreateTeam(name, email string, orgID int64) (models.Team, error) - UpdateTeam(ctx context.Context, cmd *models.UpdateTeamCommand) error - DeleteTeam(ctx context.Context, cmd *models.DeleteTeamCommand) error - SearchTeams(ctx context.Context, query *models.SearchTeamsQuery) error - GetTeamById(ctx context.Context, query *models.GetTeamByIdQuery) error - GetTeamsByUser(ctx context.Context, query *models.GetTeamsByUserQuery) error - AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission models.PermissionType) error - UpdateTeamMember(ctx context.Context, cmd *models.UpdateTeamMemberCommand) error - IsTeamMember(orgId int64, teamId int64, userId int64) (bool, error) - RemoveTeamMember(ctx context.Context, cmd *models.RemoveTeamMemberCommand) error - GetUserTeamMemberships(ctx context.Context, orgID, userID int64, external bool) ([]*models.TeamMemberDTO, error) - GetTeamMembers(ctx context.Context, query *models.GetTeamMembersQuery) error NewSession(ctx context.Context) *DBSession WithDbSession(ctx context.Context, callback DBTransactionFunc) error GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error @@ -64,6 +52,5 @@ type Store interface { Quote(value string) string GetDBHealthQuery(ctx context.Context, query *models.GetDBHealthQuery) error SearchOrgs(ctx context.Context, query *models.SearchOrgsQuery) error - IsAdminOfTeams(ctx context.Context, query *models.IsAdminOfTeamsQuery) error GetSqlxSession() *session.SessionDB } diff --git a/pkg/services/team/teamtest/team.go b/pkg/services/team/teamtest/team.go new file mode 100644 index 00000000000..0314a757333 --- /dev/null +++ b/pkg/services/team/teamtest/team.go @@ -0,0 +1,67 @@ +package teamtest + +import ( + "context" + + "github.com/grafana/grafana/pkg/models" +) + +type FakeService struct { + ExpectedTeam models.Team + ExpectedTeamsByUser []*models.TeamDTO + ExpectedMembers []*models.TeamMemberDTO + ExpectedError error +} + +func (s *FakeService) CreateTeam(name, email string, orgID int64) (models.Team, error) { + return s.ExpectedTeam, s.ExpectedError +} + +func (s *FakeService) UpdateTeam(ctx context.Context, cmd *models.UpdateTeamCommand) error { + return s.ExpectedError +} + +func (s *FakeService) DeleteTeam(ctx context.Context, cmd *models.DeleteTeamCommand) error { + return s.ExpectedError +} + +func (s *FakeService) SearchTeams(ctx context.Context, query *models.SearchTeamsQuery) error { + return s.ExpectedError +} + +func (s *FakeService) GetTeamById(ctx context.Context, query *models.GetTeamByIdQuery) error { + return s.ExpectedError +} + +func (s *FakeService) GetTeamsByUser(ctx context.Context, query *models.GetTeamsByUserQuery) error { + query.Result = s.ExpectedTeamsByUser + return s.ExpectedError +} + +func (s *FakeService) AddTeamMember(userID, orgID, teamID int64, isExternal bool, permission models.PermissionType) error { + return s.ExpectedError +} + +func (s *FakeService) UpdateTeamMember(ctx context.Context, cmd *models.UpdateTeamMemberCommand) error { + return s.ExpectedError +} + +func (s *FakeService) IsTeamMember(orgId int64, teamId int64, userId int64) (bool, error) { + return false, s.ExpectedError +} + +func (s *FakeService) RemoveTeamMember(ctx context.Context, cmd *models.RemoveTeamMemberCommand) error { + return s.ExpectedError +} + +func (s *FakeService) GetUserTeamMemberships(ctx context.Context, orgID, userID int64, external bool) ([]*models.TeamMemberDTO, error) { + return s.ExpectedMembers, s.ExpectedError +} + +func (s *FakeService) GetTeamMembers(ctx context.Context, query *models.GetTeamMembersQuery) error { + return s.ExpectedError +} + +func (s *FakeService) IsAdminOfTeams(ctx context.Context, query *models.IsAdminOfTeamsQuery) error { + return s.ExpectedError +} diff --git a/pkg/services/teamguardian/database/database.go b/pkg/services/teamguardian/database/database.go index 3a4ee687d9d..2f744e3c559 100644 --- a/pkg/services/teamguardian/database/database.go +++ b/pkg/services/teamguardian/database/database.go @@ -5,18 +5,20 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/team" ) type TeamGuardianStoreImpl struct { - sqlStore sqlstore.Store + sqlStore sqlstore.Store + teamService team.Service } -func ProvideTeamGuardianStore(sqlStore sqlstore.Store) *TeamGuardianStoreImpl { - return &TeamGuardianStoreImpl{sqlStore: sqlStore} +func ProvideTeamGuardianStore(sqlStore sqlstore.Store, teamService team.Service) *TeamGuardianStoreImpl { + return &TeamGuardianStoreImpl{sqlStore: sqlStore, teamService: teamService} } func (t *TeamGuardianStoreImpl) GetTeamMembers(ctx context.Context, query models.GetTeamMembersQuery) ([]*models.TeamMemberDTO, error) { - if err := t.sqlStore.GetTeamMembers(ctx, &query); err != nil { + if err := t.teamService.GetTeamMembers(ctx, &query); err != nil { return nil, err }