From 70fbf47022650bdf75c071314732ef226a055722 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Wed, 7 Dec 2022 17:03:22 +0100 Subject: [PATCH] chore: remove CreateUser from sqlstore & replace with userService.CreateUserForTests (#59910) --- pkg/api/org_users_test.go | 23 +- pkg/api/team_members_test.go | 24 +- pkg/api/user_test.go | 16 +- .../commands/conflict_user_command_test.go | 42 +++- .../resourcepermissions/api_test.go | 20 +- .../resourcepermissions/service_test.go | 13 +- .../resourcepermissions/store_bench_test.go | 11 +- .../resourcepermissions/store_test.go | 6 +- pkg/services/dashboards/database/acl_test.go | 8 +- .../libraryelements/libraryelements_test.go | 9 +- .../librarypanels/librarypanels_test.go | 11 +- .../login/authinfoservice/user_auth_test.go | 47 +++- pkg/services/org/orgimpl/org.go | 15 +- pkg/services/org/orgimpl/store_test.go | 57 +++-- pkg/services/org/orgtest/fake.go | 2 +- .../queryhistory/queryhistory_test.go | 11 +- pkg/services/serviceaccounts/api/api_test.go | 74 +++--- .../serviceaccounts/api/token_test.go | 28 +-- .../serviceaccounts/database/database.go | 7 +- .../serviceaccounts/database/database_test.go | 5 +- pkg/services/serviceaccounts/tests/common.go | 11 +- pkg/services/sqlstore/health_test.go | 3 +- pkg/services/sqlstore/org.go | 70 ------ pkg/services/sqlstore/org_test.go | 211 ----------------- pkg/services/sqlstore/org_users.go | 68 ------ pkg/services/sqlstore/org_users_test.go | 66 ------ pkg/services/sqlstore/sqlbuilder_test.go | 139 +++++++++-- pkg/services/sqlstore/sqlstore.go | 5 +- pkg/services/sqlstore/store.go | 2 - pkg/services/sqlstore/user.go | 201 ++++++++-------- pkg/services/stats/statsimpl/stats_test.go | 9 +- pkg/services/team/teamimpl/store_test.go | 28 ++- pkg/services/user/user.go | 4 + pkg/services/user/userimpl/store.go | 47 +++- pkg/services/user/userimpl/store_test.go | 99 +++++--- pkg/services/user/userimpl/time.go | 16 ++ pkg/services/user/userimpl/user.go | 217 ++++++++++++++++-- pkg/services/user/userimpl/user_test.go | 6 +- pkg/services/user/usertest/fake.go | 8 + .../api/alerting/api_alertmanager_test.go | 11 +- pkg/tests/api/correlations/common_test.go | 18 +- .../api/dashboards/api_dashboards_test.go | 11 +- pkg/tests/api/plugins/api_plugins_test.go | 11 +- pkg/tests/testinfra/testinfra.go | 11 +- 44 files changed, 943 insertions(+), 758 deletions(-) delete mode 100644 pkg/services/sqlstore/org.go delete mode 100644 pkg/services/sqlstore/org_test.go delete mode 100644 pkg/services/sqlstore/org_users.go delete mode 100644 pkg/services/sqlstore/org_users_test.go create mode 100644 pkg/services/user/userimpl/time.go diff --git a/pkg/api/org_users_test.go b/pkg/api/org_users_test.go index 7a418591664..b86adfc5b29 100644 --- a/pkg/api/org_users_test.go +++ b/pkg/api/org_users_test.go @@ -22,6 +22,7 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/org/orgtest" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" @@ -37,11 +38,17 @@ func setUpGetOrgUsersDB(t *testing.T, sqlStore *sqlstore.SQLStore) { sqlStore.Cfg.AutoAssignOrg = true sqlStore.Cfg.AutoAssignOrgId = int(testOrgID) - _, err := sqlStore.CreateUser(context.Background(), user.CreateUserCommand{Email: "testUser@grafana.com", Login: testUserLogin}) + quotaService := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgService, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) require.NoError(t, err) - _, err = sqlStore.CreateUser(context.Background(), user.CreateUserCommand{Email: "user1@grafana.com", Login: "user1"}) + usrSvc, err := userimpl.ProvideService(sqlStore, orgService, sqlStore.Cfg, nil, nil, quotaService) require.NoError(t, err) - _, err = sqlStore.CreateUser(context.Background(), user.CreateUserCommand{Email: "user2@grafana.com", Login: "user2"}) + + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Email: "testUser@grafana.com", Login: testUserLogin}) + require.NoError(t, err) + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Email: "user1@grafana.com", Login: "user1"}) + require.NoError(t, err) + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Email: "user2@grafana.com", Login: "user2"}) require.NoError(t, err) } @@ -331,13 +338,15 @@ var ( func setupOrgUsersDBForAccessControlTests(t *testing.T, db *sqlstore.SQLStore, orgService org.Service) { t.Helper() - var err error + quotaService := quotaimpl.ProvideService(db, db.Cfg) + usrSvc, err := userimpl.ProvideService(db, orgService, db.Cfg, nil, nil, quotaService) + require.NoError(t, err) - _, err = db.CreateUser(context.Background(), user.CreateUserCommand{Email: testServerAdminViewer.Email, SkipOrgSetup: true, Login: testServerAdminViewer.Login}) + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Email: testServerAdminViewer.Email, SkipOrgSetup: true, Login: testServerAdminViewer.Login}) require.NoError(t, err) - _, err = db.CreateUser(context.Background(), user.CreateUserCommand{Email: testAdminOrg2.Email, SkipOrgSetup: true, Login: testAdminOrg2.Login}) + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Email: testAdminOrg2.Email, SkipOrgSetup: true, Login: testAdminOrg2.Login}) require.NoError(t, err) - _, err = db.CreateUser(context.Background(), user.CreateUserCommand{Email: testEditorOrg1.Email, SkipOrgSetup: true, Login: testEditorOrg1.Login}) + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Email: testEditorOrg1.Email, SkipOrgSetup: true, Login: testEditorOrg1.Login}) require.NoError(t, err) // Create both orgs with server admin diff --git a/pkg/api/team_members_test.go b/pkg/api/team_members_test.go index 5336cdb0768..3fb5aaff768 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/licensing" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" @@ -25,6 +26,7 @@ import ( "github.com/grafana/grafana/pkg/services/teamguardian/database" "github.com/grafana/grafana/pkg/services/teamguardian/manager" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" ) @@ -46,6 +48,12 @@ func setUpGetTeamMembersHandler(t *testing.T, sqlStore *sqlstore.SQLStore) { teamSvc := teamimpl.ProvideService(sqlStore, setting.NewCfg()) team, err := teamSvc.CreateTeam("group1 name", "test1@test.com", testOrgID) require.NoError(t, err) + quotaService := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgService, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgService, sqlStore.Cfg, nil, nil, quotaService) + require.NoError(t, err) + for i := 0; i < 3; i++ { userCmd = user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), @@ -53,7 +61,7 @@ func setUpGetTeamMembersHandler(t *testing.T, sqlStore *sqlstore.SQLStore) { Login: fmt.Sprint("loginuser", i), } // user - user, err := sqlStore.CreateUser(context.Background(), userCmd) + user, err := usrSvc.CreateUserForTests(context.Background(), &userCmd) require.NoError(t, err) err = teamSvc.AddTeamMember(user.ID, testOrgID, team.Id, false, 1) require.NoError(t, err) @@ -115,7 +123,13 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) { } func createUser(db sqlstore.Store, orgId int64, t *testing.T) int64 { - user, err := db.CreateUser(context.Background(), user.CreateUserCommand{ + quotaService := quotaimpl.ProvideService(db, setting.NewCfg()) + orgService, err := orgimpl.ProvideService(db, setting.NewCfg(), quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(db, orgService, setting.NewCfg(), nil, nil, quotaService) + require.NoError(t, err) + + user, err := usrSvc.CreateUserForTests(context.Background(), &user.CreateUserCommand{ Login: fmt.Sprintf("TestUser%d", rand.Int()), OrgID: orgId, Password: "password", @@ -127,7 +141,11 @@ func createUser(db sqlstore.Store, orgId int64, t *testing.T) int64 { func setupTeamTestScenario(userCount int, db *sqlstore.SQLStore, orgService org.Service, t *testing.T) int64 { teamService := teamimpl.ProvideService(db, setting.NewCfg()) // FIXME - user, err := db.CreateUser(context.Background(), user.CreateUserCommand{SkipOrgSetup: true, Login: testUserLogin}) + quotaService := quotaimpl.ProvideService(db, db.Cfg) + usrSvc, err := userimpl.ProvideService(db, orgService, db.Cfg, teamService, nil, quotaService) + require.NoError(t, err) + + user, err := usrSvc.CreateUserForTests(context.Background(), &user.CreateUserCommand{SkipOrgSetup: true, Login: testUserLogin}) require.NoError(t, err) cmd := &org.CreateOrgCommand{Name: "TestOrg", UserID: user.ID} testOrg, err := orgService.CreateWithMember(context.Background(), cmd) diff --git a/pkg/api/user_test.go b/pkg/api/user_test.go index e810cecc6c3..7f733b7dc9a 100644 --- a/pkg/api/user_test.go +++ b/pkg/api/user_test.go @@ -23,6 +23,7 @@ import ( "github.com/grafana/grafana/pkg/services/login/authinfoservice" authinfostore "github.com/grafana/grafana/pkg/services/login/authinfoservice/database" "github.com/grafana/grafana/pkg/services/login/logintest" + "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/searchusers" "github.com/grafana/grafana/pkg/services/searchusers/filters" @@ -63,6 +64,11 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { &usagestats.UsageStatsMock{}, ) hs.authInfoService = srv + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotatest.New(false, nil)) + require.NoError(t, err) + userSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sc.cfg, nil, nil, quotatest.New(false, nil)) + require.NoError(t, err) + hs.userService = userSvc createUserCmd := user.CreateUserCommand{ Email: fmt.Sprint("user", "@test.com"), @@ -70,9 +76,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { Login: "loginuser", IsAdmin: true, } - user, err := sqlStore.CreateUser(context.Background(), createUserCmd) - require.Nil(t, err) - hs.userService, err = userimpl.ProvideService(sqlStore, nil, sc.cfg, nil, nil, quotatest.New(false, nil)) + user, err := userSvc.CreateUserForTests(context.Background(), &createUserCmd) require.NoError(t, err) sc.handlerFunc = hs.GetUserByID @@ -128,7 +132,11 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { Login: "admin", IsAdmin: true, } - _, err := sqlStore.CreateUser(context.Background(), createUserCmd) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotatest.New(false, nil)) + require.NoError(t, err) + userSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sc.cfg, nil, nil, quotatest.New(false, nil)) + require.NoError(t, err) + _, err = userSvc.Create(context.Background(), &createUserCmd) require.Nil(t, err) sc.handlerFunc = hs.GetUserByLoginOrEmail diff --git a/pkg/cmd/grafana-cli/commands/conflict_user_command_test.go b/pkg/cmd/grafana-cli/commands/conflict_user_command_test.go index 194edfeac4b..deb397a0bf2 100644 --- a/pkg/cmd/grafana-cli/commands/conflict_user_command_test.go +++ b/pkg/cmd/grafana-cli/commands/conflict_user_command_test.go @@ -12,9 +12,13 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/accesscontrol/actest" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotatest" + "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/setting" ) @@ -102,7 +106,7 @@ func TestBuildConflictBlock(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { // Restore after destructive operation sqlStore := db.InitTestDB(t) - + usrSvc := setupTestUserService(t, sqlStore) if sqlStore.GetDialect().DriverName() != ignoredDatabase { for _, u := range tc.users { cmd := user.CreateUserCommand{ @@ -111,7 +115,7 @@ func TestBuildConflictBlock(t *testing.T) { Login: u.Login, OrgID: int64(testOrgID), } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) } m, err := GetUsersWithConflictingEmailsOrLogins(&cli.Context{Context: context.Background()}, sqlStore) @@ -207,7 +211,7 @@ conflict: test2 t.Run(tc.desc, func(t *testing.T) { // Restore after destructive operation sqlStore := db.InitTestDB(t) - + usrSvc := setupTestUserService(t, sqlStore) if sqlStore.GetDialect().DriverName() != ignoredDatabase { for _, u := range tc.users { cmd := user.CreateUserCommand{ @@ -216,7 +220,7 @@ conflict: test2 Login: u.Login, OrgID: int64(testOrgID), } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) } @@ -385,6 +389,7 @@ func TestGetConflictingUsers(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { // Restore after destructive operation sqlStore := db.InitTestDB(t) + usrSvc := setupTestUserService(t, sqlStore) if sqlStore.GetDialect().DriverName() != ignoredDatabase { for _, u := range tc.users { cmd := user.CreateUserCommand{ @@ -394,7 +399,7 @@ func TestGetConflictingUsers(t *testing.T) { OrgID: int64(testOrgID), IsServiceAccount: u.IsServiceAccount, } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) } m, err := GetUsersWithConflictingEmailsOrLogins(&cli.Context{Context: context.Background()}, sqlStore) @@ -493,6 +498,7 @@ func TestGenerateConflictingUsersFile(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { // Restore after destructive operation sqlStore := db.InitTestDB(t) + usrSvc := setupTestUserService(t, sqlStore) if sqlStore.GetDialect().DriverName() != ignoredDatabase { for _, u := range tc.users { cmd := user.CreateUserCommand{ @@ -501,7 +507,7 @@ func TestGenerateConflictingUsersFile(t *testing.T) { Login: u.Login, OrgID: int64(testOrgID), } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) } m, err := GetUsersWithConflictingEmailsOrLogins(&cli.Context{Context: context.Background()}, sqlStore) @@ -543,6 +549,8 @@ func TestRunValidateConflictUserFile(t *testing.T) { t.Run("should validate file thats gets created", func(t *testing.T) { // Restore after destructive operation sqlStore := db.InitTestDB(t) + usrSvc := setupTestUserService(t, sqlStore) + const testOrgID int64 = 1 if sqlStore.GetDialect().DriverName() != ignoredDatabase { // add additional user with conflicting login where DOMAIN is upper case @@ -551,14 +559,14 @@ func TestRunValidateConflictUserFile(t *testing.T) { Login: "user_duplicate_test_1_login", OrgID: testOrgID, } - _, err := sqlStore.CreateUser(context.Background(), dupUserLogincmd) + _, err := usrSvc.Create(context.Background(), &dupUserLogincmd) require.NoError(t, err) dupUserEmailcmd := user.CreateUserCommand{ Email: "USERDUPLICATETEST1@TEST.COM", Login: "USER_DUPLICATE_TEST_1_LOGIN", OrgID: testOrgID, } - _, err = sqlStore.CreateUser(context.Background(), dupUserEmailcmd) + _, err = usrSvc.Create(context.Background(), &dupUserEmailcmd) require.NoError(t, err) // get users @@ -589,6 +597,7 @@ func TestIntegrationMergeUser(t *testing.T) { teamSvc := teamimpl.ProvideService(sqlStore, setting.NewCfg()) team1, err := teamSvc.CreateTeam("team1 name", "", 1) require.Nil(t, err) + usrSvc := setupTestUserService(t, sqlStore) const testOrgID int64 = 1 if sqlStore.GetDialect().DriverName() != ignoredDatabase { @@ -601,7 +610,7 @@ func TestIntegrationMergeUser(t *testing.T) { Login: "user_duplicate_test_1_login", OrgID: testOrgID, } - _, err := sqlStore.CreateUser(context.Background(), dupUserLogincmd) + _, err := usrSvc.Create(context.Background(), &dupUserLogincmd) require.NoError(t, err) dupUserEmailcmd := user.CreateUserCommand{ Email: "USERDUPLICATETEST1@TEST.COM", @@ -609,7 +618,7 @@ func TestIntegrationMergeUser(t *testing.T) { Login: "USER_DUPLICATE_TEST_1_LOGIN", OrgID: testOrgID, } - userWithUpperCase, err := sqlStore.CreateUser(context.Background(), dupUserEmailcmd) + userWithUpperCase, err := usrSvc.Create(context.Background(), &dupUserEmailcmd) require.NoError(t, err) // this is the user we want to update to another team err = teamSvc.AddTeamMember(userWithUpperCase.ID, testOrgID, team1.Id, false, 0) @@ -746,6 +755,7 @@ conflict: test2 for _, tc := range testCases { // Restore after destructive operation sqlStore := db.InitTestDB(t) + usrSvc := setupTestUserService(t, sqlStore) if sqlStore.GetDialect().DriverName() != ignoredDatabase { for _, u := range tc.users { cmd := user.CreateUserCommand{ @@ -754,7 +764,7 @@ conflict: test2 Login: u.Login, OrgID: int64(testOrgID), } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) } // add additional user with conflicting login where DOMAIN is upper case @@ -840,3 +850,13 @@ func TestMarshalConflictUser(t *testing.T) { }) } } + +func setupTestUserService(t *testing.T, sqlStore *sqlstore.SQLStore) user.Service { + t.Helper() + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, "atest.FakeQuotaService{}) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, "atest.FakeQuotaService{}) + require.NoError(t, err) + + return usrSvc +} diff --git a/pkg/services/accesscontrol/resourcepermissions/api_test.go b/pkg/services/accesscontrol/resourcepermissions/api_test.go index d1d918098de..ddeee01766b 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/api_test.go @@ -18,9 +18,12 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -399,10 +402,17 @@ func TestApi_setUserPermission(t *testing.T) { for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { service, sql, _ := setupTestEnvironment(t, tt.permissions, testOptions) - server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}, service) + server := setupTestServer(t, &user.SignedInUser{ + OrgID: 1, + Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}, + }, service) // seed user - _, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "test", OrgID: 1}) + orgSvc, err := orgimpl.ProvideService(sql, sql.Cfg, quotatest.New(false, nil)) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sql, orgSvc, sql.Cfg, nil, nil, "atest.FakeQuotaService{}) + require.NoError(t, err) + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Login: "test", OrgID: 1}) require.NoError(t, err) recorder := setPermission(t, server, testOptions.Resource, tt.resourceID, tt.permission, "users", strconv.Itoa(int(tt.userID))) @@ -505,7 +515,11 @@ func seedPermissions(t *testing.T, resourceID string, sql *sqlstore.SQLStore, se _, err = service.SetTeamPermission(context.Background(), team.OrgId, team.Id, resourceID, "Edit") require.NoError(t, err) // seed user 1 with "View" permission on dashboard 1 - u, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "test", OrgID: 1}) + orgSvc, err := orgimpl.ProvideService(sql, sql.Cfg, quotatest.New(false, nil)) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sql, orgSvc, sql.Cfg, nil, nil, "atest.FakeQuotaService{}) + require.NoError(t, err) + u, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{Login: "test", OrgID: 1}) require.NoError(t, err) _, err = service.SetUserPermission(context.Background(), u.OrgID, accesscontrol.User{ID: u.ID}, resourceID, "View") require.NoError(t, err) diff --git a/pkg/services/accesscontrol/resourcepermissions/service_test.go b/pkg/services/accesscontrol/resourcepermissions/service_test.go index c1352b89f9b..605db098460 100644 --- a/pkg/services/accesscontrol/resourcepermissions/service_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/service_test.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/licensing/licensingtest" + "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/team" @@ -47,7 +48,11 @@ func TestService_SetUserPermission(t *testing.T) { }) // seed user - user, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "test", OrgID: 1}) + orgSvc, err := orgimpl.ProvideService(sql, sql.Cfg, quotatest.New(false, nil)) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sql, orgSvc, sql.Cfg, nil, nil, "atest.FakeQuotaService{}) + require.NoError(t, err) + user, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{Login: "test", OrgID: 1}) require.NoError(t, err) var hookCalled bool @@ -204,7 +209,11 @@ func TestService_SetPermissions(t *testing.T) { service, sql, teamSvc := setupTestEnvironment(t, []accesscontrol.Permission{}, tt.options) // seed user - _, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "user", OrgID: 1}) + orgSvc, err := orgimpl.ProvideService(sql, sql.Cfg, quotatest.New(false, nil)) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sql, orgSvc, sql.Cfg, nil, nil, "atest.FakeQuotaService{}) + require.NoError(t, err) + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{Login: "user", OrgID: 1}) require.NoError(t, err) _, err = teamSvc.CreateTeam("team", "", 1) require.NoError(t, err) diff --git a/pkg/services/accesscontrol/resourcepermissions/store_bench_test.go b/pkg/services/accesscontrol/resourcepermissions/store_bench_test.go index e6fff4cacb8..0e782a7cd20 100644 --- a/pkg/services/accesscontrol/resourcepermissions/store_bench_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/store_bench_test.go @@ -14,9 +14,12 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/datasources" datasourcesService "github.com/grafana/grafana/pkg/services/datasources/service" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" ) const ( @@ -137,7 +140,11 @@ func generateTeamsAndUsers(b *testing.B, db *sqlstore.SQLStore, users int) ([]in teamSvc := teamimpl.ProvideService(db, db.Cfg) numberOfTeams := int(math.Ceil(float64(users) / UsersPerTeam)) globalUserId := 0 - + qs := quotatest.New(false, nil) + orgSvc, err := orgimpl.ProvideService(db, db.Cfg, qs) + require.NoError(b, err) + usrSvc, err := userimpl.ProvideService(db, orgSvc, db.Cfg, nil, nil, qs) + require.NoError(b, err) userIds := make([]int64, 0) teamIds := make([]int64, 0) for i := 0; i < numberOfTeams; i++ { @@ -155,7 +162,7 @@ func generateTeamsAndUsers(b *testing.B, db *sqlstore.SQLStore, users int) ([]in userEmail := fmt.Sprintf("%s@example.org", userName) createUserCmd := user.CreateUserCommand{Email: userEmail, Name: userName, Login: userName, OrgID: 1} - user, err := db.CreateUser(context.Background(), createUserCmd) + user, err := usrSvc.Create(context.Background(), &createUserCmd) require.NoError(b, err) userId := user.ID globalUserId++ diff --git a/pkg/services/accesscontrol/resourcepermissions/store_test.go b/pkg/services/accesscontrol/resourcepermissions/store_test.go index 81affa327ab..0598e8c9190 100644 --- a/pkg/services/accesscontrol/resourcepermissions/store_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/store_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" ) type setUserResourcePermissionTest struct { @@ -488,6 +489,9 @@ func TestIntegrationStore_GetResourcePermissions(t *testing.T) { func seedResourcePermissions(t *testing.T, store *store, sql *sqlstore.SQLStore, orgService org.Service, actions []string, resource, resourceID, resourceAttribute string, numUsers int) { t.Helper() var orgModel *org.Org + usrSvc, err := userimpl.ProvideService(sql, orgService, sql.Cfg, nil, nil, quotatest.New(false, nil)) + require.NoError(t, err) + for i := 0; i < numUsers; i++ { if orgModel == nil { cmd := &org.CreateOrgCommand{Name: "test", UserID: int64(i)} @@ -496,7 +500,7 @@ func seedResourcePermissions(t *testing.T, store *store, sql *sqlstore.SQLStore, orgModel = addedOrg } - u, err := sql.CreateUser(context.Background(), user.CreateUserCommand{ + u, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{ Login: fmt.Sprintf("user:%s%d", resourceID, i), OrgID: orgModel.ID, }) diff --git a/pkg/services/dashboards/database/acl_test.go b/pkg/services/dashboards/database/acl_test.go index ae097469e5d..4e67fe4446b 100644 --- a/pkg/services/dashboards/database/acl_test.go +++ b/pkg/services/dashboards/database/acl_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/services/tag/tagimpl" "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" ) func TestIntegrationDashboardACLDataAccess(t *testing.T) { @@ -274,11 +275,14 @@ func createUser(t *testing.T, sqlStore *sqlstore.SQLStore, name string, role str sqlStore.Cfg.AutoAssignOrgId = 1 sqlStore.Cfg.AutoAssignOrgRole = role - orgService, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaimpl.ProvideService(sqlStore, sqlStore.Cfg)) + qs := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgService, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, qs) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgService, sqlStore.Cfg, nil, nil, qs) require.NoError(t, err) currentUserCmd := user.CreateUserCommand{Login: name, Email: name + "@test.com", Name: "a " + name, IsAdmin: isAdmin} - currentUser, err := sqlStore.CreateUser(context.Background(), currentUserCmd) + currentUser, err := usrSvc.CreateUserForTests(context.Background(), ¤tUserCmd) require.NoError(t, err) orgs, err := orgService.GetUserOrgList(context.Background(), &org.GetUserOrgListQuery{UserID: currentUser.ID}) require.NoError(t, err) diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index 49e02f71790..180188d6454 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -30,10 +30,12 @@ import ( "github.com/grafana/grafana/pkg/services/folder/folderimpl" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/tag/tagimpl" "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -456,8 +458,11 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo Name: "User In DB", Login: userInDbName, } - - _, err = sqlStore.CreateUser(context.Background(), cmd) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, quotaService) + require.NoError(t, err) + _, err = usrSvc.Create(context.Background(), &cmd) require.NoError(t, err) sc := scenarioContext{ diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index 356ea61e045..c326e415c5b 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -28,10 +28,12 @@ import ( "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/libraryelements" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/tag/tagimpl" "github.com/grafana/grafana/pkg/services/team/teamtest" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" ) @@ -856,12 +858,13 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo Name: "User In DB", Login: userInDbName, } - ctx := appcontext.WithUser(context.Background(), usr) - - _, err = sqlStore.CreateUser(ctx, cmd) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, quotaService) + require.NoError(t, err) + _, err = usrSvc.Create(context.Background(), &cmd) require.NoError(t, err) - sc := scenarioContext{ user: usr, ctx: ctx, diff --git a/pkg/services/login/authinfoservice/user_auth_test.go b/pkg/services/login/authinfoservice/user_auth_test.go index 5e8181e9528..f22814020a5 100644 --- a/pkg/services/login/authinfoservice/user_auth_test.go +++ b/pkg/services/login/authinfoservice/user_auth_test.go @@ -15,7 +15,10 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/login/authinfoservice/database" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" ) //nolint:goconst @@ -29,13 +32,19 @@ func TestUserAuth(t *testing.T) { ) t.Run("Given 5 users", func(t *testing.T) { + qs := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, qs) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, qs) + require.NoError(t, err) + for i := 0; i < 5; i++ { cmd := user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.Create(context.Background(), &cmd) require.Nil(t, err) } @@ -204,6 +213,11 @@ func TestUserAuth(t *testing.T) { t.Run("Always return the most recently used auth_module", func(t *testing.T) { // Restore after destructive operation sqlStore = db.InitTestDB(t) + qs := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, qs) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, qs) + require.NoError(t, err) for i := 0; i < 5; i++ { cmd := user.CreateUserCommand{ @@ -211,8 +225,8 @@ func TestUserAuth(t *testing.T) { Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), } - _, err := sqlStore.CreateUser(context.Background(), cmd) - require.Nil(t, err) + _, err = usrSvc.Create(context.Background(), &cmd) + require.NoError(t, err) } // Find a user to set tokens on @@ -272,6 +286,11 @@ func TestUserAuth(t *testing.T) { t.Run("Keeps track of last used auth_module when not using oauth", func(t *testing.T) { // Restore after destructive operation sqlStore = db.InitTestDB(t) + qs := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, qs) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, qs) + require.NoError(t, err) for i := 0; i < 5; i++ { cmd := user.CreateUserCommand{ @@ -279,7 +298,7 @@ func TestUserAuth(t *testing.T) { Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.Create(context.Background(), &cmd) require.Nil(t, err) } @@ -406,6 +425,11 @@ func TestUserAuth(t *testing.T) { // Restore after destructive operation sqlStore = db.InitTestDB(t) + qs := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, qs) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, qs) + require.NoError(t, err) for i := 0; i < 5; i++ { cmd := user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), @@ -413,17 +437,22 @@ func TestUserAuth(t *testing.T) { Login: fmt.Sprint("loginuser", i), OrgID: 1, } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.Create(context.Background(), &cmd) require.Nil(t, err) } - _, err := srv.authInfoStore.GetLoginStats(context.Background()) + _, err = srv.authInfoStore.GetLoginStats(context.Background()) require.Nil(t, err) }) t.Run("calculate metrics on duplicate userstats", func(t *testing.T) { // Restore after destructive operation sqlStore = db.InitTestDB(t) + qs := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, qs) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, qs) + require.NoError(t, err) for i := 0; i < 5; i++ { cmd := user.CreateUserCommand{ @@ -432,7 +461,7 @@ func TestUserAuth(t *testing.T) { Login: fmt.Sprint("loginuser", i), OrgID: 1, } - _, err := sqlStore.CreateUser(context.Background(), cmd) + _, err := usrSvc.Create(context.Background(), &cmd) require.Nil(t, err) } @@ -443,7 +472,7 @@ func TestUserAuth(t *testing.T) { Name: "user name 1", Login: "USER_DUPLICATE_TEST_1_LOGIN", } - _, err := sqlStore.CreateUser(context.Background(), dupUserEmailcmd) + _, err := usrSvc.Create(context.Background(), &dupUserEmailcmd) require.NoError(t, err) // add additional user with duplicate login where DOMAIN is upper case @@ -452,7 +481,7 @@ func TestUserAuth(t *testing.T) { Name: "user name 1", Login: "user_duplicate_test_1_login", } - _, err = sqlStore.CreateUser(context.Background(), dupUserLogincmd) + _, err = usrSvc.Create(context.Background(), &dupUserLogincmd) require.NoError(t, err) authInfoStore.ExpectedUser = &user.User{ Email: "userduplicatetest1@test.com", diff --git a/pkg/services/org/orgimpl/org.go b/pkg/services/org/orgimpl/org.go index ed6c3bc506a..030a3476d70 100644 --- a/pkg/services/org/orgimpl/org.go +++ b/pkg/services/org/orgimpl/org.go @@ -2,6 +2,7 @@ package orgimpl import ( "context" + "errors" "fmt" "time" @@ -65,10 +66,12 @@ func (s *Service) GetIDForNewUser(ctx context.Context, cmd org.GetOrgIDForNewUse return cmd.OrgID, nil } - orgName := cmd.OrgName + var orgName string + orgName = cmd.OrgName if len(orgName) == 0 { orgName = util.StringsFallback2(cmd.Email, cmd.Login) } + orga.Name = orgName if setting.AutoAssignOrg { orga, err := s.store.Get(ctx, int64(s.cfg.AutoAssignOrgId)) @@ -142,12 +145,14 @@ func (s *Service) Delete(ctx context.Context, cmd *org.DeleteOrgCommand) error { } func (s *Service) GetOrCreate(ctx context.Context, orgName string) (int64, error) { - var orga *org.Org + var orga = &org.Org{} var err error if s.cfg.AutoAssignOrg { - orga, err = s.store.Get(ctx, int64(s.cfg.AutoAssignOrgId)) - if err != nil { + got, err := s.store.Get(ctx, int64(s.cfg.AutoAssignOrgId)) + if err != nil && !errors.Is(err, org.ErrOrgNotFound) { return 0, err + } else if err == nil { + return got.ID, nil } if s.cfg.AutoAssignOrgId != 1 { @@ -156,11 +161,9 @@ func (s *Service) GetOrCreate(ctx context.Context, orgName string) (int64, error return 0, fmt.Errorf("could not create user: organization ID %d does not exist", s.cfg.AutoAssignOrgId) } - orga.Name = MainOrgName orga.ID = int64(s.cfg.AutoAssignOrgId) } else { - orga = &org.Org{} orga.Name = orgName } diff --git a/pkg/services/org/orgimpl/store_test.go b/pkg/services/org/orgimpl/store_test.go index 60461b8698c..06a75d217ef 100644 --- a/pkg/services/org/orgimpl/store_test.go +++ b/pkg/services/org/orgimpl/store_test.go @@ -14,8 +14,10 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" ) @@ -304,11 +306,12 @@ func TestIntegrationOrgUserDataAccess(t *testing.T) { }) t.Run("GetOrgUsers and UpdateOrgUsers", func(t *testing.T) { ss := db.InitTestDB(t) - ac1cmd := user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} - ac2cmd := user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true} - ac1, err := ss.CreateUser(context.Background(), ac1cmd) + _, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg) + ac1cmd := &user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} + ac2cmd := &user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true} + ac1, err := usrSvc.CreateUserForTests(context.Background(), ac1cmd) require.NoError(t, err) - ac2, err := ss.CreateUser(context.Background(), ac2cmd) + ac2, err := usrSvc.CreateUserForTests(context.Background(), ac2cmd) require.NoError(t, err) cmd := org.AddOrgUserCommand{ OrgID: ac1.OrgID, @@ -412,6 +415,8 @@ func TestIntegrationOrgUserDataAccess(t *testing.T) { t.Run("Given single org and 2 users inserted", func(t *testing.T) { ss = db.InitTestDB(t) + _, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg) + testUser := &user.SignedInUser{ Permissions: map[int64]map[string][]string{ 1: {accesscontrol.ActionOrgUsersRead: []string{accesscontrol.ScopeUsersAll}}, @@ -421,13 +426,13 @@ func TestIntegrationOrgUserDataAccess(t *testing.T) { ss.Cfg.AutoAssignOrgId = 1 ss.Cfg.AutoAssignOrgRole = "Viewer" - ac1cmd := user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} - ac2cmd := user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name"} + ac1cmd := &user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} + ac2cmd := &user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name"} - ac1, err := ss.CreateUser(context.Background(), ac1cmd) + ac1, err := usrSvc.CreateUserForTests(context.Background(), ac1cmd) testUser.OrgID = ac1.OrgID require.NoError(t, err) - _, err = ss.CreateUser(context.Background(), ac2cmd) + _, err = usrSvc.Create(context.Background(), ac2cmd) require.NoError(t, err) t.Run("Can get organization users paginated with query", func(t *testing.T) { @@ -470,20 +475,20 @@ func TestIntegrationSQLStore_AddOrgUser(t *testing.T) { dialect: store.GetDialect(), cfg: setting.NewCfg(), } + _, usrSvc := createOrgAndUserSvc(t, store, store.Cfg) // create org and admin - u, err := store.CreateUser(context.Background(), user.CreateUserCommand{ + u, err := usrSvc.CreateUserForTests(context.Background(), &user.CreateUserCommand{ Login: "admin", }) require.NoError(t, err) // create a service account with no org - sa, err := store.CreateUser(context.Background(), user.CreateUserCommand{ + sa, err := usrSvc.CreateUserForTests(context.Background(), &user.CreateUserCommand{ Login: "sa-no-org", IsServiceAccount: true, SkipOrgSetup: true, }) - require.NoError(t, err) require.Equal(t, int64(-1), sa.OrgID) @@ -599,9 +604,11 @@ func TestIntegration_SQLStore_GetOrgUsers(t *testing.T) { func seedOrgUsers(t *testing.T, orgUserStore store, store *sqlstore.SQLStore, numUsers int) { t.Helper() + _, usrSvc := createOrgAndUserSvc(t, store, store.Cfg) + // Seed users for i := 1; i <= numUsers; i++ { - user, err := store.CreateUser(context.Background(), user.CreateUserCommand{ + user, err := usrSvc.CreateUserForTests(context.Background(), &user.CreateUserCommand{ Login: fmt.Sprintf("user-%d", i), OrgID: 1, }) @@ -633,8 +640,8 @@ func TestIntegration_SQLStore_GetOrgUsers_PopulatesCorrectly(t *testing.T) { } // The millisecond part is not stored in the DB constNow := time.Date(2022, 8, 17, 20, 34, 58, 0, time.UTC) - sqlstore.MockTimeNow(constNow) - defer sqlstore.ResetTimeNow() + userimpl.MockTimeNow(constNow) + defer userimpl.ResetTimeNow() store := db.InitTestDB(t, sqlstore.InitTestDBOpt{}) orgUserStore := sqlStore{ @@ -642,6 +649,7 @@ func TestIntegration_SQLStore_GetOrgUsers_PopulatesCorrectly(t *testing.T) { dialect: store.GetDialect(), cfg: setting.NewCfg(), } + _, usrSvc := createOrgAndUserSvc(t, store, store.Cfg) id, err := orgUserStore.Insert(context.Background(), &org.Org{ @@ -651,7 +659,7 @@ func TestIntegration_SQLStore_GetOrgUsers_PopulatesCorrectly(t *testing.T) { }) require.NoError(t, err) - newUser, err := store.CreateUser(context.Background(), user.CreateUserCommand{ + newUser, err := usrSvc.CreateUserForTests(context.Background(), &user.CreateUserCommand{ Login: "Viewer", Email: "viewer@localhost", OrgID: id, @@ -752,8 +760,6 @@ func TestIntegration_SQLStore_SearchOrgUsers(t *testing.T) { for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { result, err := orgUserStore.SearchOrgUsers(context.Background(), tt.query) - fmt.Println("users:", result) - require.NoError(t, err) assert.Len(t, result.OrgUsers, tt.expectedNumUsers) @@ -776,15 +782,16 @@ func TestIntegration_SQLStore_RemoveOrgUser(t *testing.T) { dialect: store.GetDialect(), cfg: setting.NewCfg(), } + _, usrSvc := createOrgAndUserSvc(t, store, store.Cfg) // create org and admin - _, err := store.CreateUser(context.Background(), user.CreateUserCommand{ + _, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{ Login: "admin", OrgID: 1, }) require.NoError(t, err) // create a user with no org - _, err = store.CreateUser(context.Background(), user.CreateUserCommand{ + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{ Login: "user", OrgID: 1, SkipOrgSetup: true, @@ -807,3 +814,15 @@ func TestIntegration_SQLStore_RemoveOrgUser(t *testing.T) { }) require.NoError(t, err) } + +func createOrgAndUserSvc(t *testing.T, store db.DB, cfg *setting.Cfg) (org.Service, user.Service) { + t.Helper() + + quotaService := quotaimpl.ProvideService(store, cfg) + orgService, err := ProvideService(store, cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(store, orgService, cfg, nil, nil, quotaService) + require.NoError(t, err) + + return orgService, usrSvc +} diff --git a/pkg/services/org/orgtest/fake.go b/pkg/services/org/orgtest/fake.go index d359d03fb34..3ac6ac57eab 100644 --- a/pkg/services/org/orgtest/fake.go +++ b/pkg/services/org/orgtest/fake.go @@ -75,7 +75,7 @@ func (f *FakeOrgService) Delete(ctx context.Context, cmd *org.DeleteOrgCommand) } func (f *FakeOrgService) GetOrCreate(ctx context.Context, orgName string) (int64, error) { - return 0, f.ExpectedError + return f.ExpectedOrg.ID, f.ExpectedError } func (f *FakeOrgService) AddOrgUser(ctx context.Context, cmd *org.AddOrgUserCommand) error { diff --git a/pkg/services/queryhistory/queryhistory_test.go b/pkg/services/queryhistory/queryhistory_test.go index 56f71f218a1..2976281b6d8 100644 --- a/pkg/services/queryhistory/queryhistory_test.go +++ b/pkg/services/queryhistory/queryhistory_test.go @@ -17,7 +17,10 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -51,8 +54,12 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo Cfg: setting.NewCfg(), store: sqlStore, } - service.Cfg.QueryHistoryEnabled = true + quotaService := quotatest.New(false, nil) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, quotaService) + require.NoError(t, err) usr := user.SignedInUser{ UserID: testUserID, @@ -64,7 +71,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo LastSeenAt: time.Now(), } - _, err := sqlStore.CreateUser(context.Background(), user.CreateUserCommand{ + _, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{ Email: "signed.in.user@test.com", Name: "Signed In User", Login: "signed_in_user", diff --git a/pkg/services/serviceaccounts/api/api_test.go b/pkg/services/serviceaccounts/api/api_test.go index 92130e02611..54f8ac7a0ef 100644 --- a/pkg/services/serviceaccounts/api/api_test.go +++ b/pkg/services/serviceaccounts/api/api_test.go @@ -23,6 +23,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/actest" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol" + "github.com/grafana/grafana/pkg/services/apikey" "github.com/grafana/grafana/pkg/services/apikey/apikeyimpl" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" "github.com/grafana/grafana/pkg/services/licensing" @@ -32,6 +33,7 @@ import ( "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/serviceaccounts/database" "github.com/grafana/grafana/pkg/services/serviceaccounts/tests" + "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user/userimpl" @@ -46,14 +48,7 @@ var ( func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) { store := db.InitTestDB(t) - quotaService := quotatest.New(false, nil) - apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService) - require.NoError(t, err) - kvStore := kvstore.ProvideService(store) - orgService, err := orgimpl.ProvideService(store, setting.NewCfg(), quotaService) - require.NoError(t, err) - saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, orgService) - svcmock := tests.ServiceAccountMock{} + services := setupTestServices(t, store) autoAssignOrg := store.Cfg.AutoAssignOrg store.Cfg.AutoAssignOrg = true @@ -62,7 +57,7 @@ func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) { }() orgCmd := &org.CreateOrgCommand{Name: "Some Test Org"} - _, err = orgService.CreateWithMember(context.Background(), orgCmd) + _, err := services.OrgService.CreateWithMember(context.Background(), orgCmd) require.Nil(t, err) type testCreateSATestCase struct { @@ -167,7 +162,7 @@ func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { serviceAccountRequestScenario(t, http.MethodPost, serviceAccountPath, testUser, func(httpmethod string, endpoint string, usr *tests.TestUser) { - server, api := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, saStore) + server, api := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore) marshalled, err := json.Marshal(tc.body) require.NoError(t, err) @@ -216,12 +211,7 @@ func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) { // with permissions and without permissions func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) { store := db.InitTestDB(t) - kvStore := kvstore.ProvideService(store) - quotaService := quotatest.New(false, nil) - apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService) - require.NoError(t, err) - saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil) - svcmock := tests.ServiceAccountMock{} + services := setupTestServices(t, store) var requestResponse = func(server *web.Mux, httpMethod, requestpath string) *httptest.ResponseRecorder { req, err := http.NewRequest(httpMethod, requestpath, nil) @@ -249,7 +239,7 @@ func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) { } serviceAccountRequestScenario(t, http.MethodDelete, serviceAccountIDPath, &testcase.user, func(httpmethod string, endpoint string, user *tests.TestUser) { createduser := tests.SetupUserServiceAccount(t, store, testcase.user) - server, _ := setupTestServer(t, &svcmock, routing.NewRouteRegister(), testcase.acmock, store, saStore) + server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), testcase.acmock, store, services.SAStore) actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, fmt.Sprint(createduser.ID))).Code require.Equal(t, testcase.expectedCode, actual) }) @@ -273,7 +263,7 @@ func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) { } serviceAccountRequestScenario(t, http.MethodDelete, serviceAccountIDPath, &testcase.user, func(httpmethod string, endpoint string, user *tests.TestUser) { createduser := tests.SetupUserServiceAccount(t, store, testcase.user) - server, _ := setupTestServer(t, &svcmock, routing.NewRouteRegister(), testcase.acmock, store, saStore) + server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), testcase.acmock, store, services.SAStore) actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, createduser.ID)).Code require.Equal(t, testcase.expectedCode, actual) }) @@ -326,12 +316,7 @@ func setupTestServer(t *testing.T, svc *tests.ServiceAccountMock, func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) { store := db.InitTestDB(t) - quotaService := quotatest.New(false, nil) - apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService) - require.NoError(t, err) - kvStore := kvstore.ProvideService(store) - saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil) - svcmock := tests.ServiceAccountMock{} + services := setupTestServices(t, store) type testRetrieveSATestCase struct { desc string user *tests.TestUser @@ -395,7 +380,7 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) { createdUser := tests.SetupUserServiceAccount(t, store, *tc.user) scopeID = int(createdUser.ID) } - server, _ := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, saStore) + server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore) actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, scopeID)) @@ -420,12 +405,7 @@ func newString(s string) *string { func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) { store := db.InitTestDB(t) - quotaService := quotatest.New(false, nil) - apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService) - require.NoError(t, err) - kvStore := kvstore.ProvideService(store) - saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil) - svcmock := tests.ServiceAccountMock{} + services := setupTestServices(t, store) type testUpdateSATestCase struct { desc string user *tests.TestUser @@ -518,7 +498,7 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { - server, saAPI := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, saStore) + server, saAPI := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore) scopeID := tc.Id if tc.user != nil { createdUser := tests.SetupUserServiceAccount(t, store, *tc.user) @@ -556,3 +536,33 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) { }) } } + +type services struct { + OrgService org.Service + UserService user.Service + SAStore serviceaccounts.Store + SAService tests.ServiceAccountMock + APIKeyService apikey.Service +} + +func setupTestServices(t *testing.T, db *sqlstore.SQLStore) services { + kvStore := kvstore.ProvideService(db) + quotaService := quotatest.New(false, nil) + apiKeyService, err := apikeyimpl.ProvideService(db, db.Cfg, quotaService) + require.NoError(t, err) + + orgService, err := orgimpl.ProvideService(db, setting.NewCfg(), quotaService) + require.NoError(t, err) + userSvc, err := userimpl.ProvideService(db, orgService, db.Cfg, nil, nil, quotaService) + require.NoError(t, err) + saStore := database.ProvideServiceAccountsStore(db, apiKeyService, kvStore, userSvc, orgService) + svcmock := tests.ServiceAccountMock{} + + return services{ + OrgService: orgService, + UserService: userSvc, + SAStore: saStore, + SAService: svcmock, + APIKeyService: apiKeyService, + } +} diff --git a/pkg/services/serviceaccounts/api/token_test.go b/pkg/services/serviceaccounts/api/token_test.go index 90b234d24d2..ca5fda55914 100644 --- a/pkg/services/serviceaccounts/api/token_test.go +++ b/pkg/services/serviceaccounts/api/token_test.go @@ -18,14 +18,10 @@ import ( "github.com/grafana/grafana/pkg/components/apikeygen" apikeygenprefix "github.com/grafana/grafana/pkg/components/apikeygenprefixed" "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/kvstore" "github.com/grafana/grafana/pkg/services/accesscontrol" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/apikey" - "github.com/grafana/grafana/pkg/services/apikey/apikeyimpl" - "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/serviceaccounts" - "github.com/grafana/grafana/pkg/services/serviceaccounts/database" "github.com/grafana/grafana/pkg/services/serviceaccounts/tests" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/web" @@ -55,12 +51,7 @@ func createTokenforSA(t *testing.T, store serviceaccounts.Store, keyName string, func TestServiceAccountsAPI_CreateToken(t *testing.T) { store := db.InitTestDB(t) - quotaService := quotatest.New(false, nil) - apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService) - require.NoError(t, err) - kvStore := kvstore.ProvideService(store) - saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil) - svcmock := tests.ServiceAccountMock{} + services := setupTestServices(t, store) sa := tests.SetupUserServiceAccount(t, store, tests.TestUser{Login: "sa", IsServiceAccount: true}) type testCreateSAToken struct { @@ -140,7 +131,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) { bodyString = string(b) } - server, _ := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, saStore) + server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore) actual := requestResponse(server, http.MethodPost, endpoint, strings.NewReader(bodyString)) actualCode := actual.Code @@ -154,7 +145,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) { assert.Equal(t, tc.body["name"], actualBody["name"]) query := apikey.GetByNameQuery{KeyName: tc.body["name"].(string), OrgId: sa.OrgID} - err = apiKeyService.GetApiKeyByName(context.Background(), &query) + err = services.APIKeyService.GetApiKeyByName(context.Background(), &query) require.NoError(t, err) assert.Equal(t, sa.ID, *query.Result.ServiceAccountId) @@ -174,12 +165,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) { func TestServiceAccountsAPI_DeleteToken(t *testing.T) { store := db.InitTestDB(t) - quotaService := quotatest.New(false, nil) - apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService) - require.NoError(t, err) - kvStore := kvstore.ProvideService(store) - svcMock := &tests.ServiceAccountMock{} - saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil) + services := setupTestServices(t, store) sa := tests.SetupUserServiceAccount(t, store, tests.TestUser{Login: "sa", IsServiceAccount: true}) type testCreateSAToken struct { @@ -239,11 +225,11 @@ func TestServiceAccountsAPI_DeleteToken(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { - token := createTokenforSA(t, saStore, tc.keyName, sa.OrgID, sa.ID, 1) + token := createTokenforSA(t, services.SAStore, tc.keyName, sa.OrgID, sa.ID, 1) endpoint := fmt.Sprintf(serviceaccountIDTokensDetailPath, sa.ID, token.Id) bodyString := "" - server, _ := setupTestServer(t, svcMock, routing.NewRouteRegister(), tc.acmock, store, saStore) + server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore) actual := requestResponse(server, http.MethodDelete, endpoint, strings.NewReader(bodyString)) actualCode := actual.Code @@ -253,7 +239,7 @@ func TestServiceAccountsAPI_DeleteToken(t *testing.T) { require.Equal(t, tc.expectedCode, actualCode, endpoint, actualBody) query := apikey.GetByNameQuery{KeyName: tc.keyName, OrgId: sa.OrgID} - err := apiKeyService.GetApiKeyByName(context.Background(), &query) + err := services.APIKeyService.GetApiKeyByName(context.Background(), &query) if actualCode == http.StatusOK { require.Error(t, err) } else { diff --git a/pkg/services/serviceaccounts/database/database.go b/pkg/services/serviceaccounts/database/database.go index 19265645f15..20982a29f42 100644 --- a/pkg/services/serviceaccounts/database/database.go +++ b/pkg/services/serviceaccounts/database/database.go @@ -30,13 +30,14 @@ type ServiceAccountsStoreImpl struct { } func ProvideServiceAccountsStore(store *sqlstore.SQLStore, apiKeyService apikey.Service, - kvStore kvstore.KVStore, orgService org.Service) *ServiceAccountsStoreImpl { + kvStore kvstore.KVStore, userService user.Service, orgService org.Service) *ServiceAccountsStoreImpl { return &ServiceAccountsStoreImpl{ sqlStore: store, apiKeyService: apiKeyService, kvStore: kvStore, log: log.New("serviceaccounts.store"), orgService: orgService, + userService: userService, } } @@ -55,7 +56,7 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, org var newSA *user.User createErr := s.sqlStore.WithTransactionalDbSession(ctx, func(sess *db.Session) (err error) { var errUser error - newSA, errUser = s.sqlStore.CreateUser(ctx, user.CreateUserCommand{ + newSA, errUser = s.userService.CreateServiceAccount(ctx, &user.CreateUserCommand{ Login: generatedLogin, OrgID: orgId, Name: saForm.Name, @@ -461,7 +462,7 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccountFromApikey(ctx context.Co } return s.sqlStore.WithTransactionalDbSession(ctx, func(sess *db.Session) error { - newSA, errCreateSA := s.sqlStore.CreateUser(ctx, cmd) + newSA, errCreateSA := s.userService.CreateServiceAccount(ctx, &cmd) if errCreateSA != nil { return fmt.Errorf("failed to create service account: %w", errCreateSA) } diff --git a/pkg/services/serviceaccounts/database/database_test.go b/pkg/services/serviceaccounts/database/database_test.go index 268f6a678c0..41084066d4c 100644 --- a/pkg/services/serviceaccounts/database/database_test.go +++ b/pkg/services/serviceaccounts/database/database_test.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/serviceaccounts/tests" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" ) @@ -118,7 +119,9 @@ func setupTestDatabase(t *testing.T) (*sqlstore.SQLStore, *ServiceAccountsStoreI kvStore := kvstore.ProvideService(db) orgService, err := orgimpl.ProvideService(db, setting.NewCfg(), quotaService) require.NoError(t, err) - return db, ProvideServiceAccountsStore(db, apiKeyService, kvStore, orgService) + userSvc, err := userimpl.ProvideService(db, orgService, db.Cfg, nil, nil, quotaService) + require.NoError(t, err) + return db, ProvideServiceAccountsStore(db, apiKeyService, kvStore, userSvc, orgService) } func TestStore_RetrieveServiceAccount(t *testing.T) { diff --git a/pkg/services/serviceaccounts/tests/common.go b/pkg/services/serviceaccounts/tests/common.go index d8b5dea247b..232cfc8da8b 100644 --- a/pkg/services/serviceaccounts/tests/common.go +++ b/pkg/services/serviceaccounts/tests/common.go @@ -12,10 +12,13 @@ import ( "github.com/grafana/grafana/pkg/services/apikey" "github.com/grafana/grafana/pkg/services/apikey/apikeyimpl" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" ) type TestUser struct { @@ -41,7 +44,13 @@ func SetupUserServiceAccount(t *testing.T, sqlStore *sqlstore.SQLStore, testUser role = testUser.Role } - u1, err := sqlStore.CreateUser(context.Background(), user.CreateUserCommand{ + quotaService := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgService, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(sqlStore, orgService, sqlStore.Cfg, nil, nil, quotaService) + require.NoError(t, err) + + u1, err := usrSvc.CreateUserForTests(context.Background(), &user.CreateUserCommand{ Login: testUser.Login, IsServiceAccount: testUser.IsServiceAccount, DefaultOrgRole: role, diff --git a/pkg/services/sqlstore/health_test.go b/pkg/services/sqlstore/health_test.go index 4873ec37fbf..2865a4302b8 100644 --- a/pkg/services/sqlstore/health_test.go +++ b/pkg/services/sqlstore/health_test.go @@ -4,8 +4,9 @@ import ( "context" "testing" - "github.com/grafana/grafana/pkg/models" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/models" ) func TestIntegrationGetDBHealthQuery(t *testing.T) { diff --git a/pkg/services/sqlstore/org.go b/pkg/services/sqlstore/org.go deleted file mode 100644 index 52b970f9128..00000000000 --- a/pkg/services/sqlstore/org.go +++ /dev/null @@ -1,70 +0,0 @@ -// DO NOT ADD METHODS TO THIS FILES. SQLSTORE IS DEPRECATED AND WILL BE REMOVED. -package sqlstore - -import ( - "fmt" - "time" - - "github.com/grafana/grafana/pkg/events" - "github.com/grafana/grafana/pkg/models" -) - -const mainOrgName = "Main Org." - -func verifyExistingOrg(sess *DBSession, orgId int64) error { - var org models.Org - has, err := sess.Where("id=?", orgId).Get(&org) - if err != nil { - return err - } - if !has { - return models.ErrOrgNotFound - } - return nil -} - -func (ss *SQLStore) getOrCreateOrg(sess *DBSession, orgName string) (int64, error) { - var org models.Org - if ss.Cfg.AutoAssignOrg { - has, err := sess.Where("id=?", ss.Cfg.AutoAssignOrgId).Get(&org) - if err != nil { - return 0, err - } - if has { - return org.Id, nil - } - - if ss.Cfg.AutoAssignOrgId != 1 { - ss.log.Error("Could not create user: organization ID does not exist", "orgID", - ss.Cfg.AutoAssignOrgId) - return 0, fmt.Errorf("could not create user: organization ID %d does not exist", - ss.Cfg.AutoAssignOrgId) - } - - org.Name = mainOrgName - org.Id = int64(ss.Cfg.AutoAssignOrgId) - } else { - org.Name = orgName - } - - org.Created = time.Now() - org.Updated = time.Now() - - if org.Id != 0 { - if _, err := sess.InsertId(&org); err != nil { - return 0, err - } - } else { - if _, err := sess.InsertOne(&org); err != nil { - return 0, err - } - } - - sess.publishAfterCommit(&events.OrgCreated{ - Timestamp: org.Created, - Id: org.Id, - Name: org.Name, - }) - - return org.Id, nil -} diff --git a/pkg/services/sqlstore/org_test.go b/pkg/services/sqlstore/org_test.go deleted file mode 100644 index c348e404fb2..00000000000 --- a/pkg/services/sqlstore/org_test.go +++ /dev/null @@ -1,211 +0,0 @@ -package sqlstore - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/dashboards" - dashver "github.com/grafana/grafana/pkg/services/dashboardversion" - "github.com/grafana/grafana/pkg/services/org" - "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/util" -) - -func TestIntegrationAccountDataAccess(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - t.Run("Testing Account DB Access", func(t *testing.T) { - sqlStore := InitTestDB(t) - - t.Run("Given single org mode", func(t *testing.T) { - sqlStore.Cfg.AutoAssignOrg = true - sqlStore.Cfg.AutoAssignOrgId = 1 - sqlStore.Cfg.AutoAssignOrgRole = "Viewer" - - t.Run("Users should be added to default organization", func(t *testing.T) { - ac1cmd := user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} - ac2cmd := user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name"} - - ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd) - require.NoError(t, err) - ac2, err := sqlStore.CreateUser(context.Background(), ac2cmd) - require.NoError(t, err) - - q1 := models.GetUserOrgListQuery{UserId: ac1.ID} - q2 := models.GetUserOrgListQuery{UserId: ac2.ID} - err = sqlStore.getUserOrgList(context.Background(), &q1) - require.NoError(t, err) - err = sqlStore.getUserOrgList(context.Background(), &q2) - require.NoError(t, err) - - require.Equal(t, q1.Result[0].OrgId, q2.Result[0].OrgId) - require.Equal(t, string(q1.Result[0].Role), "Viewer") - }) - }) - - t.Run("Given two saved users", func(t *testing.T) { - sqlStore = InitTestDB(t) - sqlStore.Cfg.AutoAssignOrg = false - - ac1cmd := user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} - ac2cmd := user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true} - serviceaccountcmd := user.CreateUserCommand{Login: "serviceaccount", Email: "service@test.com", Name: "serviceaccount name", IsAdmin: true, IsServiceAccount: true} - - ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd) - require.NoError(t, err) - ac2, err := sqlStore.CreateUser(context.Background(), ac2cmd) - require.NoError(t, err) - // user only used for making sure we filter out the service accounts - _, err = sqlStore.CreateUser(context.Background(), serviceaccountcmd) - require.NoError(t, err) - - t.Run("Given an added org user", func(t *testing.T) { - cmd := models.AddOrgUserCommand{ - OrgId: ac1.OrgID, - UserId: ac2.ID, - Role: org.RoleViewer, - } - - err := sqlStore.addOrgUser(context.Background(), &cmd) - t.Run("Should have been saved without error", func(t *testing.T) { - require.NoError(t, err) - }) - - t.Run("Can get user organizations", func(t *testing.T) { - query := models.GetUserOrgListQuery{UserId: ac2.ID} - err := sqlStore.getUserOrgList(context.Background(), &query) - - require.NoError(t, err) - require.Equal(t, len(query.Result), 2) - }) - - t.Run("Given an org user with dashboard permissions", func(t *testing.T) { - ac3cmd := user.CreateUserCommand{Login: "ac3", Email: "ac3@test.com", Name: "ac3 name", IsAdmin: false} - ac3, err := sqlStore.CreateUser(context.Background(), ac3cmd) - require.NoError(t, err) - - orgUserCmd := models.AddOrgUserCommand{ - OrgId: ac1.OrgID, - UserId: ac3.ID, - Role: org.RoleViewer, - } - - err = sqlStore.addOrgUser(context.Background(), &orgUserCmd) - require.NoError(t, err) - - dash1 := insertTestDashboard(t, sqlStore, "1 test dash", ac1.OrgID, 0, false, "prod", "webapp") - dash2 := insertTestDashboard(t, sqlStore, "2 test dash", ac3.OrgID, 0, false, "prod", "webapp") - - err = updateDashboardACL(t, sqlStore, dash1.Id, &models.DashboardACL{ - DashboardID: dash1.Id, OrgID: ac1.OrgID, UserID: ac3.ID, Permission: models.PERMISSION_EDIT, - }) - require.NoError(t, err) - - err = updateDashboardACL(t, sqlStore, dash2.Id, &models.DashboardACL{ - DashboardID: dash2.Id, OrgID: ac3.OrgID, UserID: ac3.ID, Permission: models.PERMISSION_EDIT, - }) - require.NoError(t, err) - }) - }) - }) - }) -} - -// TODO: Use FakeDashboardStore when org has its own service -func insertTestDashboard(t *testing.T, sqlStore *SQLStore, title string, orgId int64, - folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard { - t.Helper() - cmd := models.SaveDashboardCommand{ - OrgId: orgId, - FolderId: folderId, - IsFolder: isFolder, - Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": nil, - "title": title, - "tags": tags, - }), - } - - var dash *models.Dashboard - err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { - dash = cmd.GetDashboardModel() - dash.SetVersion(1) - dash.Created = time.Now() - dash.Updated = time.Now() - dash.Uid = util.GenerateShortUID() - _, err := sess.Insert(dash) - return err - }) - - require.NoError(t, err) - require.NotNil(t, dash) - dash.Data.Set("id", dash.Id) - dash.Data.Set("uid", dash.Uid) - - err = sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { - dashVersion := &dashver.DashboardVersion{ - DashboardID: dash.Id, - ParentVersion: dash.Version, - RestoredFrom: cmd.RestoredFrom, - Version: dash.Version, - Created: time.Now(), - CreatedBy: dash.UpdatedBy, - Message: cmd.Message, - Data: dash.Data, - } - require.NoError(t, err) - - if affectedRows, err := sess.Insert(dashVersion); err != nil { - return err - } else if affectedRows == 0 { - return dashboards.ErrDashboardNotFound - } - - return nil - }) - require.NoError(t, err) - - return dash -} - -// TODO: Use FakeDashboardStore when org has its own service -func updateDashboardACL(t *testing.T, sqlStore *SQLStore, dashboardID int64, items ...*models.DashboardACL) error { - t.Helper() - - err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { - _, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", dashboardID) - if err != nil { - return fmt.Errorf("deleting from dashboard_acl failed: %w", err) - } - - for _, item := range items { - item.Created = time.Now() - item.Updated = time.Now() - if item.UserID == 0 && item.TeamID == 0 && (item.Role == nil || !item.Role.IsValid()) { - return models.ErrDashboardACLInfoMissing - } - - if item.DashboardID == 0 { - return models.ErrDashboardPermissionDashboardEmpty - } - - sess.Nullable("user_id", "team_id") - if _, err := sess.Insert(item); err != nil { - return err - } - } - - // Update dashboard HasACL flag - dashboard := models.Dashboard{HasACL: true} - _, err = sess.Cols("has_acl").Where("id=?", dashboardID).Update(&dashboard) - return err - }) - return err -} diff --git a/pkg/services/sqlstore/org_users.go b/pkg/services/sqlstore/org_users.go deleted file mode 100644 index d15870fefb8..00000000000 --- a/pkg/services/sqlstore/org_users.go +++ /dev/null @@ -1,68 +0,0 @@ -package sqlstore - -import ( - "context" - "time" - - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/user" -) - -func (ss *SQLStore) addOrgUser(ctx context.Context, cmd *models.AddOrgUserCommand) error { - return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { - // check if user exists - var usr user.User - session := sess.ID(cmd.UserId) - if !cmd.AllowAddingServiceAccount { - session = session.Where(notServiceAccountFilter(ss)) - } - - if exists, err := session.Get(&usr); err != nil { - return err - } else if !exists { - return user.ErrUserNotFound - } - - if res, err := sess.Query("SELECT 1 from org_user WHERE org_id=? and user_id=?", cmd.OrgId, usr.ID); err != nil { - return err - } else if len(res) == 1 { - return models.ErrOrgUserAlreadyAdded - } - - if res, err := sess.Query("SELECT 1 from org WHERE id=?", cmd.OrgId); err != nil { - return err - } else if len(res) != 1 { - return models.ErrOrgNotFound - } - - entity := models.OrgUser{ - OrgId: cmd.OrgId, - UserId: cmd.UserId, - Role: cmd.Role, - Created: time.Now(), - Updated: time.Now(), - } - - _, err := sess.Insert(&entity) - if err != nil { - return err - } - - var userOrgs []*models.UserOrgDTO - sess.Table("org_user") - sess.Join("INNER", "org", "org_user.org_id=org.id") - sess.Where("org_user.user_id=? AND org_user.org_id=?", usr.ID, usr.OrgID) - sess.Cols("org.name", "org_user.role", "org_user.org_id") - err = sess.Find(&userOrgs) - - if err != nil { - return err - } - - if len(userOrgs) == 0 { - return setUsingOrgInTransaction(sess, usr.ID, cmd.OrgId) - } - - return nil - }) -} diff --git a/pkg/services/sqlstore/org_users_test.go b/pkg/services/sqlstore/org_users_test.go deleted file mode 100644 index 7528e679805..00000000000 --- a/pkg/services/sqlstore/org_users_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package sqlstore - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/user" -) - -func TestSQLStore_AddOrgUser(t *testing.T) { - var orgID int64 = 1 - store := InitTestDB(t) - - // create org and admin - _, err := store.CreateUser(context.Background(), user.CreateUserCommand{ - Login: "admin", - OrgID: orgID, - }) - require.NoError(t, err) - - // create a service account with no org - sa, err := store.CreateUser(context.Background(), user.CreateUserCommand{ - Login: "sa-no-org", - IsServiceAccount: true, - SkipOrgSetup: true, - }) - - require.NoError(t, err) - require.Equal(t, int64(-1), sa.OrgID) - - // assign the sa to the org but without the override. should fail - err = store.addOrgUser(context.Background(), &models.AddOrgUserCommand{ - Role: "Viewer", - OrgId: orgID, - UserId: sa.ID, - }) - require.Error(t, err) - - // assign the sa to the org with the override. should succeed - err = store.addOrgUser(context.Background(), &models.AddOrgUserCommand{ - Role: "Viewer", - OrgId: orgID, - UserId: sa.ID, - AllowAddingServiceAccount: true, - }) - - require.NoError(t, err) - - // assert the org has been correctly set - saFound := new(user.User) - err = store.WithDbSession(context.Background(), func(sess *DBSession) error { - has, err := sess.ID(sa.ID).Get(saFound) - if err != nil { - return err - } else if !has { - return user.ErrUserNotFound - } - return nil - }) - - require.NoError(t, err) - require.Equal(t, saFound.OrgID, orgID) -} diff --git a/pkg/services/sqlstore/sqlbuilder_test.go b/pkg/services/sqlstore/sqlbuilder_test.go index d9a56aab581..8d75c369cf7 100644 --- a/pkg/services/sqlstore/sqlbuilder_test.go +++ b/pkg/services/sqlstore/sqlbuilder_test.go @@ -2,17 +2,22 @@ package sqlstore import ( "context" + "fmt" "math/rand" "strconv" "testing" "time" - "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/org" - "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/util" ) func TestIntegrationSQLBuilder(t *testing.T) { @@ -196,22 +201,28 @@ func createDummyUser(t *testing.T, sqlStore *SQLStore) *user.User { t.Helper() uid := strconv.Itoa(rand.Intn(9999999)) - createUserCmd := user.CreateUserCommand{ - Email: uid + "@example.com", - Login: uid, - Name: uid, - Company: "", - OrgName: "", - Password: uid, - EmailVerified: true, - IsAdmin: false, - SkipOrgSetup: false, - DefaultOrgRole: string(org.RoleViewer), + usr := &user.User{ + Email: uid + "@example.com", + Login: uid, + Name: uid, + Company: "", + Password: uid, + EmailVerified: true, + IsAdmin: false, + Created: time.Now(), + Updated: time.Now(), } - user, err := sqlStore.CreateUser(context.Background(), createUserCmd) - require.NoError(t, err) - return user + var id int64 + err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { + sess.UseBool("is_admin") + var err error + id, err = sess.Insert(usr) + return err + }) + require.NoError(t, err) + usr.ID = id + return usr } func createDummyDashboard(t *testing.T, sqlStore *SQLStore, dashboardProps DashboardProps) *models.Dashboard { @@ -317,3 +328,95 @@ func getDashboards(t *testing.T, sqlStore *SQLStore, search Search, aclUserID in require.NoError(t, err) return res } + +// TODO: Use FakeDashboardStore when org has its own service +func insertTestDashboard(t *testing.T, sqlStore *SQLStore, title string, orgId int64, + folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard { + t.Helper() + cmd := models.SaveDashboardCommand{ + OrgId: orgId, + FolderId: folderId, + IsFolder: isFolder, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": title, + "tags": tags, + }), + } + + var dash *models.Dashboard + err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { + dash = cmd.GetDashboardModel() + dash.SetVersion(1) + dash.Created = time.Now() + dash.Updated = time.Now() + dash.Uid = util.GenerateShortUID() + _, err := sess.Insert(dash) + return err + }) + + require.NoError(t, err) + require.NotNil(t, dash) + dash.Data.Set("id", dash.Id) + dash.Data.Set("uid", dash.Uid) + + err = sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { + dashVersion := &dashver.DashboardVersion{ + DashboardID: dash.Id, + ParentVersion: dash.Version, + RestoredFrom: cmd.RestoredFrom, + Version: dash.Version, + Created: time.Now(), + CreatedBy: dash.UpdatedBy, + Message: cmd.Message, + Data: dash.Data, + } + require.NoError(t, err) + + if affectedRows, err := sess.Insert(dashVersion); err != nil { + return err + } else if affectedRows == 0 { + return dashboards.ErrDashboardNotFound + } + + return nil + }) + require.NoError(t, err) + + return dash +} + +// TODO: Use FakeDashboardStore when org has its own service +func updateDashboardACL(t *testing.T, sqlStore *SQLStore, dashboardID int64, items ...*models.DashboardACL) error { + t.Helper() + + err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { + _, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", dashboardID) + if err != nil { + return fmt.Errorf("deleting from dashboard_acl failed: %w", err) + } + + for _, item := range items { + item.Created = time.Now() + item.Updated = time.Now() + if item.UserID == 0 && item.TeamID == 0 && (item.Role == nil || !item.Role.IsValid()) { + return models.ErrDashboardACLInfoMissing + } + + if item.DashboardID == 0 { + return models.ErrDashboardPermissionDashboardEmpty + } + + sess.Nullable("user_id", "team_id") + if _, err := sess.Insert(item); err != nil { + return err + } + } + + // Update dashboard HasACL flag + dashboard := models.Dashboard{HasACL: true} + _, err = sess.Cols("has_acl").Where("id=?", dashboardID).Update(&dashboard) + return err + }) + return err +} diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index 4dc3291164f..bbe0a39a8c7 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -198,7 +198,6 @@ func (ss *SQLStore) ensureMainOrgAndAdminUser() error { if _, err := sess.SQL(rawSQL).Get(&stats); err != nil { return fmt.Errorf("could not determine if admin user exists: %w", err) } - if stats.Count > 0 { return nil } @@ -206,6 +205,7 @@ func (ss *SQLStore) ensureMainOrgAndAdminUser() error { // ensure admin user if !ss.Cfg.DisableInitAdminCreation { ss.log.Debug("Creating default admin user") + if _, err := ss.createUser(ctx, sess, user.CreateUserCommand{ Login: ss.Cfg.AdminUser, Email: ss.Cfg.AdminEmail, @@ -216,9 +216,6 @@ func (ss *SQLStore) ensureMainOrgAndAdminUser() error { } ss.log.Info("Created default admin", "user", ss.Cfg.AdminUser) - // Why should we return and not create the default org in this case? - // Returning here breaks tests using anonymous access - // return nil } ss.log.Debug("Creating default org", "name", mainOrgName) diff --git a/pkg/services/sqlstore/store.go b/pkg/services/sqlstore/store.go index 77dfe576391..747af3a8aa7 100644 --- a/pkg/services/sqlstore/store.go +++ b/pkg/services/sqlstore/store.go @@ -8,13 +8,11 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/sqlstore/session" - "github.com/grafana/grafana/pkg/services/user" ) type Store interface { GetDialect() migrator.Dialect GetDBType() core.DbType - CreateUser(ctx context.Context, cmd user.CreateUserCommand) (*user.User, error) WithDbSession(ctx context.Context, callback DBTransactionFunc) error WithNewDbSession(ctx context.Context, callback DBTransactionFunc) error WithTransactionalDbSession(ctx context.Context, callback DBTransactionFunc) error diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go index b30766fd6c8..b11cdb37558 100644 --- a/pkg/services/sqlstore/user.go +++ b/pkg/services/sqlstore/user.go @@ -4,8 +4,8 @@ package sqlstore import ( "context" "fmt" - "sort" "strings" + "time" "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/models" @@ -14,6 +14,8 @@ import ( "github.com/grafana/grafana/pkg/util" ) +const mainOrgName = "Main Org." + func (ss *SQLStore) getOrgIDForNewUser(sess *DBSession, args user.CreateUserCommand) (int64, error) { if ss.Cfg.AutoAssignOrg && args.OrgID != 0 { if err := verifyExistingOrg(sess, args.OrgID); err != nil { @@ -30,21 +32,19 @@ func (ss *SQLStore) getOrgIDForNewUser(sess *DBSession, args user.CreateUserComm return ss.getOrCreateOrg(sess, orgName) } -// createUser creates a user in the database -// if autoAssignOrg is enabled then args.OrgID will be used -// to add to an existing Org with id=args.OrgID -// if autoAssignOrg is disabled then args.OrgName will be used -// to create a new Org with name=args.OrgName. -// If a org already exists with that name, it will error +// createUser creates a user in the database. It will also create a default +// organization, if none exists. This should only be used by the sqlstore +// Reset() function. +// +// If AutoAssignOrg is enabled then args.OrgID will be used to add to an +// existing Org with id=args.OrgID. If AutoAssignOrg is disabled then +// args.OrgName will be used to create a new Org with name=args.OrgName. If an +// org already exists with that name, it will error. func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args user.CreateUserCommand) (user.User, error) { var usr user.User - var orgID int64 = -1 - if !args.SkipOrgSetup { - var err error - orgID, err = ss.getOrgIDForNewUser(sess, args) - if err != nil { - return usr, err - } + orgID, err := ss.getOrgIDForNewUser(sess, args) + if err != nil { + return usr, err } if args.Email == "" { @@ -68,18 +68,13 @@ func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args user.C // create user usr = user.User{ - Email: args.Email, - Name: args.Name, - Login: args.Login, - Company: args.Company, - IsAdmin: args.IsAdmin, - IsDisabled: args.IsDisabled, - OrgID: orgID, - EmailVerified: args.EmailVerified, - Created: TimeNow(), - Updated: TimeNow(), - LastSeenAt: TimeNow().AddDate(-10, 0, 0), - IsServiceAccount: args.IsServiceAccount, + Email: args.Email, + Login: args.Login, + IsAdmin: args.IsAdmin, + OrgID: orgID, + Created: TimeNow(), + Updated: TimeNow(), + LastSeenAt: TimeNow().AddDate(-10, 0, 0), } salt, err := util.GetRandomString(10) @@ -115,95 +110,29 @@ func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args user.C Email: usr.Email, }) - // create org user link - if !args.SkipOrgSetup { - orgUser := models.OrgUser{ - OrgId: orgID, - UserId: usr.ID, - Role: org.RoleAdmin, - Created: TimeNow(), - Updated: TimeNow(), - } + orgUser := models.OrgUser{ + OrgId: orgID, + UserId: usr.ID, + Role: org.RoleAdmin, + Created: TimeNow(), + Updated: TimeNow(), + } - if ss.Cfg.AutoAssignOrg && !usr.IsAdmin { - if len(args.DefaultOrgRole) > 0 { - orgUser.Role = org.RoleType(args.DefaultOrgRole) - } else { - orgUser.Role = org.RoleType(ss.Cfg.AutoAssignOrgRole) - } + if ss.Cfg.AutoAssignOrg && !usr.IsAdmin { + if len(args.DefaultOrgRole) > 0 { + orgUser.Role = org.RoleType(args.DefaultOrgRole) + } else { + orgUser.Role = org.RoleType(ss.Cfg.AutoAssignOrgRole) } + } - if _, err = sess.Insert(&orgUser); err != nil { - return usr, err - } + if _, err = sess.Insert(&orgUser); err != nil { + return usr, err } return usr, nil } -// deprecated method, use only for tests -func (ss *SQLStore) CreateUser(ctx context.Context, cmd user.CreateUserCommand) (*user.User, error) { - var user user.User - createErr := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) (err error) { - user, err = ss.createUser(ctx, sess, cmd) - return - }) - return &user, createErr -} - -func notServiceAccountFilter(ss *SQLStore) string { - return fmt.Sprintf("%s.is_service_account = %s", - ss.Dialect.Quote("user"), - ss.Dialect.BooleanStr(false)) -} - -func setUsingOrgInTransaction(sess *DBSession, userID int64, orgID int64) error { - user := user.User{ - ID: userID, - OrgID: orgID, - } - - _, err := sess.ID(userID).Update(&user) - return err -} - -type byOrgName []*models.UserOrgDTO - -// Len returns the length of an array of organisations. -func (o byOrgName) Len() int { - return len(o) -} - -// Swap swaps two indices of an array of organizations. -func (o byOrgName) Swap(i, j int) { - o[i], o[j] = o[j], o[i] -} - -// Less returns whether element i of an array of organizations is less than element j. -func (o byOrgName) Less(i, j int) bool { - if strings.ToLower(o[i].Name) < strings.ToLower(o[j].Name) { - return true - } - - return o[i].Name < o[j].Name -} - -func (ss *SQLStore) getUserOrgList(ctx context.Context, query *models.GetUserOrgListQuery) error { - return ss.WithDbSession(ctx, func(dbSess *DBSession) error { - query.Result = make([]*models.UserOrgDTO, 0) - sess := dbSess.Table("org_user") - sess.Join("INNER", "org", "org_user.org_id=org.id") - sess.Join("INNER", ss.Dialect.Quote("user"), fmt.Sprintf("org_user.user_id=%s.id", ss.Dialect.Quote("user"))) - sess.Where("org_user.user_id=?", query.UserId) - sess.Where(notServiceAccountFilter(ss)) - sess.Cols("org.name", "org_user.role", "org_user.org_id") - sess.OrderBy("org.name") - err := sess.Find(&query.Result) - sort.Sort(byOrgName(query.Result)) - return err - }) -} - func UserDeletions() []string { deletes := []string{ "DELETE FROM star WHERE user_id = ?", @@ -218,3 +147,61 @@ func UserDeletions() []string { } return deletes } + +func verifyExistingOrg(sess *DBSession, orgId int64) error { + var org models.Org + has, err := sess.Where("id=?", orgId).Get(&org) + if err != nil { + return err + } + if !has { + return models.ErrOrgNotFound + } + return nil +} + +func (ss *SQLStore) getOrCreateOrg(sess *DBSession, orgName string) (int64, error) { + var org models.Org + if ss.Cfg.AutoAssignOrg { + has, err := sess.Where("id=?", ss.Cfg.AutoAssignOrgId).Get(&org) + if err != nil { + return 0, err + } + if has { + return org.Id, nil + } + + if ss.Cfg.AutoAssignOrgId != 1 { + ss.log.Error("Could not create user: organization ID does not exist", "orgID", + ss.Cfg.AutoAssignOrgId) + return 0, fmt.Errorf("could not create user: organization ID %d does not exist", + ss.Cfg.AutoAssignOrgId) + } + + org.Name = mainOrgName + org.Id = int64(ss.Cfg.AutoAssignOrgId) + } else { + org.Name = orgName + } + + org.Created = time.Now() + org.Updated = time.Now() + + if org.Id != 0 { + if _, err := sess.InsertId(&org); err != nil { + return 0, err + } + } else { + if _, err := sess.InsertOne(&org); err != nil { + return 0, err + } + } + + sess.publishAfterCommit(&events.OrgCreated{ + Timestamp: org.Created, + Id: org.Id, + Name: org.Name, + }) + + return org.Id, nil +} diff --git a/pkg/services/stats/statsimpl/stats_test.go b/pkg/services/stats/statsimpl/stats_test.go index 1017f870b35..938bf16992d 100644 --- a/pkg/services/stats/statsimpl/stats_test.go +++ b/pkg/services/stats/statsimpl/stats_test.go @@ -5,14 +5,16 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/services/user/userimpl" ) func TestIntegrationStatsDataAccess(t *testing.T) { @@ -71,6 +73,7 @@ func populateDB(t *testing.T, sqlStore *sqlstore.SQLStore) { t.Helper() orgService, _ := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotatest.New(false, nil)) + userSvc, _ := userimpl.ProvideService(sqlStore, orgService, sqlStore.Cfg, nil, nil, "atest.FakeQuotaService{}) users := make([]user.User, 3) for i := range users { @@ -80,7 +83,7 @@ func populateDB(t *testing.T, sqlStore *sqlstore.SQLStore) { Login: fmt.Sprintf("user_test_%v_login", i), OrgName: fmt.Sprintf("Org #%v", i), } - user, err := sqlStore.CreateUser(context.Background(), cmd) + user, err := userSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) users[i] = *user } diff --git a/pkg/services/team/teamimpl/store_test.go b/pkg/services/team/teamimpl/store_test.go index 17ec4f6d08b..047beacd9c9 100644 --- a/pkg/services/team/teamimpl/store_test.go +++ b/pkg/services/team/teamimpl/store_test.go @@ -13,16 +13,19 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/models" ac "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" ) func TestIntegrationTeamCommandsAndQueries(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - t.Run("Testing Team commands & queries", func(t *testing.T) { + t.Run("Testing Team commands and queries", func(t *testing.T) { sqlStore := db.InitTestDB(t) teamSvc := ProvideService(sqlStore, sqlStore.Cfg) testUser := &user.SignedInUser{ @@ -35,6 +38,11 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { }, }, } + quotaService := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) + require.NoError(t, err) + userSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, teamSvc, nil, quotaService) + require.NoError(t, err) t.Run("Given saved users and two teams", func(t *testing.T) { var userIds []int64 @@ -51,7 +59,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), } - usr, err = sqlStore.CreateUser(context.Background(), userCmd) + usr, err = userSvc.Create(context.Background(), &userCmd) require.NoError(t, err) userIds = append(userIds, usr.ID) } @@ -82,7 +90,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { q1 := &models.GetTeamMembersQuery{OrgId: testOrgID, TeamId: team1.Id, SignedInUser: testUser} err = teamSvc.GetTeamMembers(context.Background(), q1) require.NoError(t, err) - require.Equal(t, len(q1.Result), 2) + require.Equal(t, 2, len(q1.Result)) require.Equal(t, q1.Result[0].TeamId, team1.Id) require.Equal(t, q1.Result[0].Login, "loginuser0") require.Equal(t, q1.Result[0].OrgId, testOrgID) @@ -373,6 +381,11 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { t.Run("Should be able to exclude service accounts from teamembers", func(t *testing.T) { sqlStore = db.InitTestDB(t) + quotaService := quotaimpl.ProvideService(sqlStore, sqlStore.Cfg) + orgSvc, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService) + require.NoError(t, err) + userSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, teamSvc, nil, quotaService) + require.NoError(t, err) setup() userCmd = user.CreateUserCommand{ Email: fmt.Sprint("sa", 1, "@test.com"), @@ -380,7 +393,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { Login: fmt.Sprint("login-sa", 1), IsServiceAccount: true, } - serviceAccount, err := sqlStore.CreateUser(context.Background(), userCmd) + serviceAccount, err := userSvc.CreateUserForTests(context.Background(), &userCmd) require.NoError(t, err) groupId := team2.Id @@ -497,6 +510,11 @@ func TestIntegrationSQLStore_GetTeamMembers_ACFilter(t *testing.T) { require.NoError(t, errCreateTeam) team2, errCreateTeam := teamSvc.CreateTeam("group2 name", "test2@example.org", testOrgID) require.NoError(t, errCreateTeam) + quotaService := quotaimpl.ProvideService(store, store.Cfg) + orgSvc, err := orgimpl.ProvideService(store, store.Cfg, quotaService) + require.NoError(t, err) + userSvc, err := userimpl.ProvideService(store, orgSvc, store.Cfg, teamSvc, nil, quotaService) + require.NoError(t, err) for i := 0; i < 4; i++ { userCmd := user.CreateUserCommand{ @@ -504,7 +522,7 @@ func TestIntegrationSQLStore_GetTeamMembers_ACFilter(t *testing.T) { Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), } - user, errCreateUser := store.CreateUser(context.Background(), userCmd) + user, errCreateUser := userSvc.Create(context.Background(), &userCmd) require.NoError(t, errCreateUser) userIds[i] = user.ID } diff --git a/pkg/services/user/user.go b/pkg/services/user/user.go index b66962c48f9..2852ef4afd4 100644 --- a/pkg/services/user/user.go +++ b/pkg/services/user/user.go @@ -6,6 +6,7 @@ import ( type Service interface { Create(context.Context, *CreateUserCommand) (*User, error) + CreateServiceAccount(context.Context, *CreateUserCommand) (*User, error) Delete(context.Context, *DeleteUserCommand) error GetByID(context.Context, *GetUserByIDQuery) (*User, error) GetByLogin(context.Context, *GetUserByLoginQuery) (*User, error) @@ -23,4 +24,7 @@ type Service interface { UpdatePermissions(context.Context, int64, bool) error SetUserHelpFlag(context.Context, *SetUserHelpFlagCommand) error GetProfile(context.Context, *GetUserProfileQuery) (*UserProfileDTO, error) + + // TEST ONLY METHOD + CreateUserForTests(context.Context, *CreateUserCommand) (*User, error) } diff --git a/pkg/services/user/userimpl/store.go b/pkg/services/user/userimpl/store.go index 53deaf17c41..2d1710bbe92 100644 --- a/pkg/services/user/userimpl/store.go +++ b/pkg/services/user/userimpl/store.go @@ -11,7 +11,6 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" @@ -24,6 +23,7 @@ type store interface { GetByID(context.Context, int64) (*user.User, error) GetNotServiceAccount(context.Context, int64) (*user.User, error) Delete(context.Context, int64) error + LoginConflict(ctx context.Context, login, email string, caseInsensitive bool) error CaseInsensitiveLoginConflict(context.Context, string, string) error GetByLogin(context.Context, *user.GetUserByLoginQuery) (*user.User, error) GetByEmail(context.Context, *user.GetUserByEmailQuery) (*user.User, error) @@ -59,12 +59,11 @@ func ProvideStore(db db.DB, cfg *setting.Cfg) sqlStore { } func (ss *sqlStore) Insert(ctx context.Context, cmd *user.User) (int64, error) { - var userID int64 var err error err = ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error { sess.UseBool("is_admin") - if userID, err = sess.Insert(cmd); err != nil { + if _, err = sess.Insert(cmd); err != nil { return err } sess.PublishAfterCommit(&events.UserCreated{ @@ -79,7 +78,7 @@ func (ss *sqlStore) Insert(ctx context.Context, cmd *user.User) (int64, error) { if err != nil { return 0, err } - return userID, nil + return cmd.ID, nil } func (ss *sqlStore) Get(ctx context.Context, usr *user.User) (*user.User, error) { @@ -185,7 +184,6 @@ func (ss *sqlStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQu where = "LOWER(email)=LOWER(?)" } has, err = sess.Where(ss.notServiceAccountFilter()).Where(where, query.LoginOrEmail).Get(usr) - if err != nil { return err } @@ -264,6 +262,43 @@ func (ss *sqlStore) userCaseInsensitiveLoginConflict(ctx context.Context, sess * return nil } +// LoginConflict returns an error if the provided email or login are already +// associated with a user. If caseInsensitive is true the search is not case +// sensitive. +func (ss *sqlStore) LoginConflict(ctx context.Context, login, email string, caseInsensitive bool) error { + err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { + return ss.loginConflict(ctx, sess, login, email, caseInsensitive) + }) + return err +} + +func (ss *sqlStore) loginConflict(ctx context.Context, sess *db.Session, login, email string, caseInsensitive bool) error { + users := make([]user.User, 0) + where := "email=? OR login=?" + if caseInsensitive { + where = "LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)" + login = strings.ToLower(login) + email = strings.ToLower(email) + } + + exists, err := sess.Where(where, email, login).Get(&user.User{}) + if err != nil { + return err + } + if exists { + return user.ErrUserAlreadyExists + } + if err := sess.Where("LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)", + email, login).Find(&users); err != nil { + return err + } + + if len(users) > 1 { + return &user.ErrCaseInsensitiveLoginConflict{Users: users} + } + return nil +} + func (ss *sqlStore) Update(ctx context.Context, cmd *user.UpdateUserCommand) error { if ss.cfg.CaseInsensitiveLogin { cmd.Login = strings.ToLower(cmd.Login) @@ -470,7 +505,7 @@ func (ss *sqlStore) Count(ctx context.Context) (int64, error) { } r := result{} - err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s WHERE is_service_account=%s", ss.db.GetDialect().Quote("user"), ss.db.GetDialect().BooleanStr(false)) if _, err := sess.SQL(rawSQL).Get(&r); err != nil { return err diff --git a/pkg/services/user/userimpl/store_test.go b/pkg/services/user/userimpl/store_test.go index 48e2d2de23b..2a58935c035 100644 --- a/pkg/services/user/userimpl/store_test.go +++ b/pkg/services/user/userimpl/store_test.go @@ -15,7 +15,6 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotaimpl" - "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" @@ -31,6 +30,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { orgService, err := orgimpl.ProvideService(ss, ss.Cfg, quotaService) require.NoError(t, err) userStore := ProvideStore(ss, setting.NewCfg()) + usrSvc, err := ProvideService(ss, orgService, ss.Cfg, nil, nil, quotaService) + require.NoError(t, err) usr := &user.SignedInUser{ OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"global.users:*"}}}, @@ -73,12 +74,14 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - creates and loads user", func(t *testing.T) { ss := db.InitTestDB(t) + _, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg) + cmd := user.CreateUserCommand{ Email: "usertest@test.com", Name: "user name", Login: "user_test_login", } - usr, err := ss.CreateUser(context.Background(), cmd) + usr, err := usrSvc.Create(context.Background(), &cmd) require.NoError(t, err) result, err := userStore.GetByID(context.Background(), usr.ID) @@ -147,7 +150,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { Login: "user_email_conflict", } // userEmailConflict - _, err := ss.CreateUser(context.Background(), cmd) + _, err = usrSvc.Create(context.Background(), &cmd) require.NoError(t, err) cmd = user.CreateUserCommand{ @@ -155,7 +158,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { Name: "user name", Login: "user_email_conflict_two", } - _, err = ss.CreateUser(context.Background(), cmd) + _, err := usrSvc.Create(context.Background(), &cmd) require.NoError(t, err) cmd = user.CreateUserCommand{ @@ -164,7 +167,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { Login: "user_test_login_conflict", } // userLoginConflict - _, err = ss.CreateUser(context.Background(), cmd) + _, err = usrSvc.Create(context.Background(), &cmd) require.NoError(t, err) cmd = user.CreateUserCommand{ @@ -172,7 +175,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { Name: "user name", Login: "user_test_login_CONFLICT", } - _, err = ss.CreateUser(context.Background(), cmd) + _, err = usrSvc.Create(context.Background(), &cmd) require.NoError(t, err) ss.Cfg.CaseInsensitiveLogin = true @@ -262,7 +265,9 @@ func TestIntegrationUserDataAccess(t *testing.T) { }) t.Run("get signed in user", func(t *testing.T) { - users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + ss := db.InitTestDB(t) + orgService, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg) + users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -300,26 +305,24 @@ func TestIntegrationUserDataAccess(t *testing.T) { }) t.Run("Testing DB - grafana admin users", func(t *testing.T) { - ss = db.InitTestDB(t) - + ss := db.InitTestDB(t) + _, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg) createUserCmd := user.CreateUserCommand{ Email: fmt.Sprint("admin", "@test.com"), Name: "admin", Login: "admin", IsAdmin: true, } - usr, err := ss.CreateUser(context.Background(), createUserCmd) + usr, err := usrSvc.Create(context.Background(), &createUserCmd) require.Nil(t, err) // Cannot make themselves a non-admin updatePermsError := userStore.UpdatePermissions(context.Background(), usr.ID, false) - require.Equal(t, user.ErrLastGrafanaAdmin, updatePermsError) query := user.GetUserByIDQuery{ID: usr.ID} queryResult, getUserError := userStore.GetByID(context.Background(), query.ID) require.Nil(t, getUserError) - require.True(t, queryResult.IsAdmin) // One user @@ -330,7 +333,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { Name: "user", Login: username, } - _, err = ss.CreateUser(context.Background(), createUserCmd) + _, err = usrSvc.Create(context.Background(), &createUserCmd) require.Nil(t, err) // When trying to create a new user with the same email, an error is returned @@ -340,8 +343,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { Login: "user2", SkipOrgSetup: true, } - _, err = ss.CreateUser(context.Background(), createUserCmd) - require.Equal(t, err, user.ErrUserAlreadyExists) + _, err = usrSvc.Create(context.Background(), &createUserCmd) + require.Equal(t, user.ErrUserAlreadyExists, err) // When trying to create a new user with the same login, an error is returned createUserCmd = user.CreateUserCommand{ @@ -350,8 +353,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { Login: username, SkipOrgSetup: true, } - _, err = ss.CreateUser(context.Background(), createUserCmd) - require.Equal(t, err, user.ErrUserAlreadyExists) + _, err = usrSvc.Create(context.Background(), &createUserCmd) + require.Equal(t, user.ErrUserAlreadyExists, err) }) t.Run("GetProfile", func(t *testing.T) { @@ -366,7 +369,10 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - return list users based on their is_disabled flag", func(t *testing.T) { ss = db.InitTestDB(t) - createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + _, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg) + userStore := ProvideStore(ss, ss.Cfg) + + createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -379,7 +385,6 @@ func TestIntegrationUserDataAccess(t *testing.T) { query := user.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: usr} result, err := userStore.Search(context.Background(), &query) require.Nil(t, err) - require.Len(t, result.Users, 2) first, third := false, false @@ -397,8 +402,10 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.True(t, third) // Re-init DB - ss = db.InitTestDB(t) - users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + ss := db.InitTestDB(t) + orgService, usrSvc = createOrgAndUserSvc(t, ss, ss.Cfg) + + users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -432,7 +439,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { // A user is an org member and has been assigned permissions // Re-init DB ss = db.InitTestDB(t) - users = createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + orgService, usrSvc = createOrgAndUserSvc(t, ss, ss.Cfg) + users = createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -487,7 +495,12 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - return list of users that the SignedInUser has permission to read", func(t *testing.T) { ss := db.InitTestDB(t) - createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + orgService, err := orgimpl.ProvideService(ss, ss.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := ProvideService(ss, orgService, ss.Cfg, nil, nil, quotaService) + require.NoError(t, err) + + createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -508,7 +521,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { ss = db.InitTestDB(t) t.Run("Testing DB - enable all users", func(t *testing.T) { - users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -541,12 +554,12 @@ func TestIntegrationUserDataAccess(t *testing.T) { ac2cmd := user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true} serviceaccountcmd := user.CreateUserCommand{Login: "serviceaccount", Email: "service@test.com", Name: "serviceaccount name", IsAdmin: true, IsServiceAccount: true} - _, err := ss.CreateUser(context.Background(), ac1cmd) + _, err := usrSvc.Create(context.Background(), &ac1cmd) require.NoError(t, err) - _, err = ss.CreateUser(context.Background(), ac2cmd) + _, err = usrSvc.Create(context.Background(), &ac2cmd) require.NoError(t, err) // user only used for making sure we filter out the service accounts - _, err = ss.CreateUser(context.Background(), serviceaccountcmd) + _, err = usrSvc.Create(context.Background(), &serviceaccountcmd) require.NoError(t, err) query := user.SearchUsersQuery{Query: "", SignedInUser: &user.SignedInUser{ OrgID: 1, @@ -564,7 +577,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { ss = db.InitTestDB(t) t.Run("Testing DB - disable only specific users", func(t *testing.T) { - users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -594,7 +607,6 @@ func TestIntegrationUserDataAccess(t *testing.T) { // Check if user id is in the userIdsToDisable list for _, disabledUserId := range userIdsToDisable { - fmt.Println(user.ID, disabledUserId) if user.ID == disabledUserId { require.True(t, user.IsDisabled) shouldBeDisabled = true @@ -612,7 +624,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - search users", func(t *testing.T) { // Since previous tests were destructive - createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -636,7 +648,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - multiple users", func(t *testing.T) { ss = db.InitTestDB(t) - createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), @@ -729,8 +741,9 @@ func TestIntegrationUserUpdate(t *testing.T) { ss := db.InitTestDB(t) userStore := ProvideStore(ss, setting.NewCfg()) + _, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg) - users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand { return &user.CreateUserCommand{ Email: fmt.Sprint("USER", i, "@test.com"), Name: fmt.Sprint("USER", i), @@ -789,17 +802,15 @@ func TestIntegrationUserUpdate(t *testing.T) { ss.Cfg.CaseInsensitiveLogin = false } -func createFiveTestUsers(t *testing.T, sqlStore *sqlstore.SQLStore, fn func(i int) *user.CreateUserCommand) []user.User { +func createFiveTestUsers(t *testing.T, svc user.Service, fn func(i int) *user.CreateUserCommand) []user.User { t.Helper() - users := []user.User{} + users := make([]user.User, 5) for i := 0; i < 5; i++ { cmd := fn(i) - - user, err := sqlStore.CreateUser(context.Background(), *cmd) - users = append(users, *user) - + user, err := svc.CreateUserForTests(context.Background(), cmd) require.Nil(t, err) + users[i] = *user } return users @@ -924,3 +935,15 @@ func (ss *sqlStore) getDashboardACLInfoList(query *models.GetDashboardACLInfoLis return nil } + +func createOrgAndUserSvc(t *testing.T, store db.DB, cfg *setting.Cfg) (org.Service, user.Service) { + t.Helper() + + quotaService := quotaimpl.ProvideService(store, cfg) + orgService, err := orgimpl.ProvideService(store, cfg, quotaService) + require.NoError(t, err) + usrSvc, err := ProvideService(store, orgService, cfg, nil, nil, quotaService) + require.NoError(t, err) + + return orgService, usrSvc +} diff --git a/pkg/services/user/userimpl/time.go b/pkg/services/user/userimpl/time.go new file mode 100644 index 00000000000..87ded6cd9c5 --- /dev/null +++ b/pkg/services/user/userimpl/time.go @@ -0,0 +1,16 @@ +package userimpl + +import "time" + +// timeNow wraps time.Now so it can be mocked in tests. +var timeNow = time.Now + +func MockTimeNow(constTime time.Time) { + timeNow = func() time.Time { + return constTime + } +} + +func ResetTimeNow() { + timeNow = time.Now +} diff --git a/pkg/services/user/userimpl/user.go b/pkg/services/user/userimpl/user.go index 132f556a1c2..4f275baa598 100644 --- a/pkg/services/user/userimpl/user.go +++ b/pkg/services/user/userimpl/user.go @@ -82,32 +82,27 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use SkipOrgSetup: cmd.SkipOrgSetup, } orgID, err := s.orgService.GetIDForNewUser(ctx, cmdOrg) - cmd.OrgID = orgID if err != nil { return nil, err } - if cmd.Email == "" { cmd.Email = cmd.Login } - usr := &user.User{ - Login: cmd.Login, - Email: cmd.Email, - } - usr, err = s.store.Get(ctx, usr) - if err != nil && !errors.Is(err, user.ErrUserNotFound) { - return usr, err + + err = s.store.LoginConflict(ctx, cmd.Login, cmd.Email, s.cfg.CaseInsensitiveLogin) + if err != nil { + return nil, user.ErrUserAlreadyExists } // create user - usr = &user.User{ + usr := &user.User{ Email: cmd.Email, Name: cmd.Name, Login: cmd.Login, Company: cmd.Company, IsAdmin: cmd.IsAdmin, IsDisabled: cmd.IsDisabled, - OrgID: cmd.OrgID, + OrgID: orgID, EmailVerified: cmd.EmailVerified, Created: time.Now(), Updated: time.Now(), @@ -134,7 +129,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use usr.Password = encodedPassword } - userID, err := s.store.Insert(ctx, usr) + _, err = s.store.Insert(ctx, usr) if err != nil { return nil, err } @@ -158,11 +153,10 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use } _, err = s.orgService.InsertOrgUser(ctx, &orgUser) if err != nil { - err := s.store.Delete(ctx, userID) + err := s.store.Delete(ctx, usr.ID) return usr, err } } - return usr, nil } @@ -354,3 +348,198 @@ func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) { limits.Set(globalQuotaTag, cfg.Quota.Global.User) return limits, nil } + +// CreateUserForTests creates a test user and optionally an organization. Unlike +// Create, `cmd.SkipOrgSetup` toggles whether or not to create an org for the +// test user if there isn't already an existing org. This must only be used in tests. +func (s *Service) CreateUserForTests(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) { + var orgID int64 = -1 + var err error + if !cmd.SkipOrgSetup { + orgID, err = s.getOrgIDForNewUser(ctx, cmd) + if err != nil { + return nil, err + } + } + + if cmd.Email == "" { + cmd.Email = cmd.Login + } + + usr, err := s.GetByLogin(ctx, &user.GetUserByLoginQuery{LoginOrEmail: cmd.Login}) + if err != nil && !errors.Is(err, user.ErrUserNotFound) { + return usr, err + } else if err == nil { // user exists + return usr, err + } + + // create user + usr = &user.User{ + Email: cmd.Email, + Name: cmd.Name, + Login: cmd.Login, + Company: cmd.Company, + IsAdmin: cmd.IsAdmin, + IsDisabled: cmd.IsDisabled, + OrgID: orgID, + EmailVerified: cmd.EmailVerified, + Created: timeNow(), + Updated: timeNow(), + LastSeenAt: timeNow().AddDate(-10, 0, 0), + IsServiceAccount: cmd.IsServiceAccount, + } + + salt, err := util.GetRandomString(10) + if err != nil { + return usr, err + } + usr.Salt = salt + rands, err := util.GetRandomString(10) + if err != nil { + return usr, err + } + usr.Rands = rands + + if len(cmd.Password) > 0 { + encodedPassword, err := util.EncodePassword(cmd.Password, usr.Salt) + if err != nil { + return usr, err + } + usr.Password = encodedPassword + } + + _, err = s.store.Insert(ctx, usr) + if err != nil { + return usr, err + } + + // create org user link + if !cmd.SkipOrgSetup { + orgCmd := &org.AddOrgUserCommand{ + OrgID: orgID, + UserID: usr.ID, + Role: org.RoleAdmin, + AllowAddingServiceAccount: true, + } + + if s.cfg.AutoAssignOrg && !usr.IsAdmin { + if len(cmd.DefaultOrgRole) > 0 { + orgCmd.Role = org.RoleType(cmd.DefaultOrgRole) + } else { + orgCmd.Role = org.RoleType(s.cfg.AutoAssignOrgRole) + } + } + + if err = s.orgService.AddOrgUser(ctx, orgCmd); err != nil { + return nil, err + } + } + + return usr, nil +} + +func (s *Service) getOrgIDForNewUser(ctx context.Context, cmd *user.CreateUserCommand) (int64, error) { + if s.cfg.AutoAssignOrg && cmd.OrgID != 0 { + if _, err := s.orgService.GetByID(ctx, &org.GetOrgByIdQuery{ID: cmd.OrgID}); err != nil { + return -1, err + } + return cmd.OrgID, nil + } + + orgName := cmd.OrgName + if orgName == "" { + orgName = util.StringsFallback2(cmd.Email, cmd.Login) + } + + orgID, err := s.orgService.GetOrCreate(ctx, orgName) + if err != nil { + return 0, err + } + return orgID, err +} + +// CreateServiceAccount is a copy of Create with a single difference; it will create the OrgUser service account. +func (s *Service) CreateServiceAccount(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) { + cmdOrg := org.GetOrgIDForNewUserCommand{ + Email: cmd.Email, + Login: cmd.Login, + OrgID: cmd.OrgID, + OrgName: cmd.OrgName, + SkipOrgSetup: cmd.SkipOrgSetup, + } + orgID, err := s.orgService.GetIDForNewUser(ctx, cmdOrg) + if err != nil { + return nil, err + } + if cmd.Email == "" { + cmd.Email = cmd.Login + } + + err = s.store.LoginConflict(ctx, cmd.Login, cmd.Email, s.cfg.CaseInsensitiveLogin) + if err != nil { + return nil, user.ErrUserAlreadyExists + } + + // create user + usr := &user.User{ + Email: cmd.Email, + Name: cmd.Name, + Login: cmd.Login, + Company: cmd.Company, + IsAdmin: cmd.IsAdmin, + IsDisabled: cmd.IsDisabled, + OrgID: cmd.OrgID, + EmailVerified: cmd.EmailVerified, + Created: time.Now(), + Updated: time.Now(), + LastSeenAt: time.Now().AddDate(-10, 0, 0), + IsServiceAccount: cmd.IsServiceAccount, + } + + salt, err := util.GetRandomString(10) + if err != nil { + return nil, err + } + usr.Salt = salt + rands, err := util.GetRandomString(10) + if err != nil { + return nil, err + } + usr.Rands = rands + + if len(cmd.Password) > 0 { + encodedPassword, err := util.EncodePassword(cmd.Password, usr.Salt) + if err != nil { + return nil, err + } + usr.Password = encodedPassword + } + + _, err = s.store.Insert(ctx, usr) + if err != nil { + return nil, err + } + + // create org user link + if !cmd.SkipOrgSetup { + orgCmd := &org.AddOrgUserCommand{ + OrgID: orgID, + UserID: usr.ID, + Role: org.RoleAdmin, + AllowAddingServiceAccount: true, + } + + if s.cfg.AutoAssignOrg && !usr.IsAdmin { + if len(cmd.DefaultOrgRole) > 0 { + orgCmd.Role = org.RoleType(cmd.DefaultOrgRole) + } else { + orgCmd.Role = org.RoleType(s.cfg.AutoAssignOrgRole) + } + } + + if err = s.orgService.AddOrgUser(ctx, orgCmd); err != nil { + return nil, err + } + } + return usr, nil +} diff --git a/pkg/services/user/userimpl/user_test.go b/pkg/services/user/userimpl/user_test.go index d491bd4f848..53f63e72940 100644 --- a/pkg/services/user/userimpl/user_test.go +++ b/pkg/services/user/userimpl/user_test.go @@ -26,6 +26,7 @@ func TestUserService(t *testing.T) { cacheService: localcache.ProvideService(), teamService: &teamtest.FakeService{}, } + userService.cfg = setting.NewCfg() t.Run("create user", func(t *testing.T) { _, err := userService.Create(context.Background(), &user.CreateUserCommand{ @@ -44,7 +45,6 @@ func TestUserService(t *testing.T) { require.NoError(t, err) require.Equal(t, "login", u.Login) require.Equal(t, "name", u.Name) - require.Equal(t, "email", u.Email) }) @@ -229,6 +229,10 @@ func (f *FakeUserStore) CaseInsensitiveLoginConflict(context.Context, string, st return f.ExpectedError } +func (f *FakeUserStore) LoginConflict(context.Context, string, string, bool) error { + return f.ExpectedError +} + func (f *FakeUserStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQuery) (*user.User, error) { return f.ExpectedUser, f.ExpectedError } diff --git a/pkg/services/user/usertest/fake.go b/pkg/services/user/usertest/fake.go index 0041dd9e8d3..aa26ee05314 100644 --- a/pkg/services/user/usertest/fake.go +++ b/pkg/services/user/usertest/fake.go @@ -28,6 +28,14 @@ func (f *FakeUserService) Create(ctx context.Context, cmd *user.CreateUserComman return f.ExpectedUser, f.ExpectedError } +func (f *FakeUserService) CreateUserForTests(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) { + return f.ExpectedUser, f.ExpectedError +} + +func (f *FakeUserService) CreateServiceAccount(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) { + return f.ExpectedUser, f.ExpectedError +} + func (f *FakeUserService) Delete(ctx context.Context, cmd *user.DeleteUserCommand) error { return f.ExpectedError } diff --git a/pkg/tests/api/alerting/api_alertmanager_test.go b/pkg/tests/api/alerting/api_alertmanager_test.go index ca79eb54301..b6815a3278f 100644 --- a/pkg/tests/api/alerting/api_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_test.go @@ -20,8 +20,11 @@ import ( ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" ngstore "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -2534,7 +2537,13 @@ func createUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserComma store.Cfg.AutoAssignOrg = true store.Cfg.AutoAssignOrgId = 1 - u, err := store.CreateUser(context.Background(), cmd) + quotaService := quotaimpl.ProvideService(store, store.Cfg) + orgService, err := orgimpl.ProvideService(store, store.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(store, orgService, store.Cfg, nil, nil, quotaService) + require.NoError(t, err) + + u, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) return u.ID } diff --git a/pkg/tests/api/correlations/common_test.go b/pkg/tests/api/correlations/common_test.go index 1f8ee1c4736..aabdb761929 100644 --- a/pkg/tests/api/correlations/common_test.go +++ b/pkg/tests/api/correlations/common_test.go @@ -7,12 +7,16 @@ import ( "net/http" "testing" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/server" "github.com/grafana/grafana/pkg/services/correlations" "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/tests/testinfra" - "github.com/stretchr/testify/require" ) type errorResponseBody struct { @@ -130,11 +134,17 @@ func (c TestContext) getURL(url string, user User) string { func (c TestContext) createUser(cmd user.CreateUserCommand) { c.t.Helper() + store := c.env.SQLStore + store.Cfg.AutoAssignOrg = true + store.Cfg.AutoAssignOrgId = 1 - c.env.SQLStore.Cfg.AutoAssignOrg = true - c.env.SQLStore.Cfg.AutoAssignOrgId = 1 + quotaService := quotaimpl.ProvideService(store, store.Cfg) + orgService, err := orgimpl.ProvideService(store, store.Cfg, quotaService) + require.NoError(c.t, err) + usrSvc, err := userimpl.ProvideService(store, orgService, store.Cfg, nil, nil, quotaService) + require.NoError(c.t, err) - _, err := c.env.SQLStore.CreateUser(context.Background(), cmd) + _, err = usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(c.t, err) } diff --git a/pkg/tests/api/dashboards/api_dashboards_test.go b/pkg/tests/api/dashboards/api_dashboards_test.go index 7e8841dedb0..5eefc5c15f5 100644 --- a/pkg/tests/api/dashboards/api_dashboards_test.go +++ b/pkg/tests/api/dashboards/api_dashboards_test.go @@ -20,9 +20,12 @@ import ( "github.com/grafana/grafana/pkg/services/dashboardimport" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/plugindashboards" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -100,7 +103,13 @@ func createUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserComma store.Cfg.AutoAssignOrg = true store.Cfg.AutoAssignOrgId = 1 - u, err := store.CreateUser(context.Background(), cmd) + quotaService := quotaimpl.ProvideService(store, store.Cfg) + orgService, err := orgimpl.ProvideService(store, store.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(store, orgService, store.Cfg, nil, nil, quotaService) + require.NoError(t, err) + + u, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) return u.ID } diff --git a/pkg/tests/api/plugins/api_plugins_test.go b/pkg/tests/api/plugins/api_plugins_test.go index 0d62275c4b7..0ebffe901b3 100644 --- a/pkg/tests/api/plugins/api_plugins_test.go +++ b/pkg/tests/api/plugins/api_plugins_test.go @@ -11,8 +11,11 @@ import ( "path/filepath" "testing" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/stretchr/testify/assert" @@ -115,7 +118,13 @@ func createUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserComma store.Cfg.AutoAssignOrg = true store.Cfg.AutoAssignOrgId = 1 - _, err := store.CreateUser(context.Background(), cmd) + quotaService := quotaimpl.ProvideService(store, store.Cfg) + orgService, err := orgimpl.ProvideService(store, store.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(store, orgService, store.Cfg, nil, nil, quotaService) + require.NoError(t, err) + + _, err = usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) } diff --git a/pkg/tests/testinfra/testinfra.go b/pkg/tests/testinfra/testinfra.go index d5aeef74c52..eb565baa74b 100644 --- a/pkg/tests/testinfra/testinfra.go +++ b/pkg/tests/testinfra/testinfra.go @@ -22,8 +22,11 @@ import ( "github.com/grafana/grafana/pkg/infra/fs" "github.com/grafana/grafana/pkg/server" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" ) @@ -370,7 +373,13 @@ func CreateUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserComma store.Cfg.AutoAssignOrg = true store.Cfg.AutoAssignOrgId = 1 - u, err := store.CreateUser(context.Background(), cmd) + quotaService := quotaimpl.ProvideService(store, store.Cfg) + orgService, err := orgimpl.ProvideService(store, store.Cfg, quotaService) + require.NoError(t, err) + usrSvc, err := userimpl.ProvideService(store, orgService, store.Cfg, nil, nil, quotaService) + require.NoError(t, err) + + u, err := usrSvc.CreateUserForTests(context.Background(), &cmd) require.NoError(t, err) return u.ID }