chore: remove CreateUser from sqlstore & replace with userService.CreateUserForTests (#59910)

This commit is contained in:
Kristin Laemmert 2022-12-07 17:03:22 +01:00 committed by GitHub
parent d036225f7b
commit 70fbf47022
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 943 additions and 758 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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, &quotatest.FakeQuotaService{})
require.NoError(t, err)
usrSvc, err := userimpl.ProvideService(sqlStore, orgSvc, sqlStore.Cfg, nil, nil, &quotatest.FakeQuotaService{})
require.NoError(t, err)
return usrSvc
}

View File

@ -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, &quotatest.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, &quotatest.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)

View File

@ -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, &quotatest.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, &quotatest.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)

View File

@ -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++

View File

@ -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,
})

View File

@ -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(), &currentUserCmd)
require.NoError(t, err)
orgs, err := orgService.GetUserOrgList(context.Background(), &org.GetUserOrgListQuery{UserID: currentUser.ID})
require.NoError(t, err)

View File

@ -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{

View File

@ -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,

View File

@ -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",

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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",

View File

@ -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,
}
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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) {

View File

@ -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,

View File

@ -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) {

View File

@ -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
}

View File

@ -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
}

View File

@ -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
})
}

View File

@ -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)
}

View File

@ -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{
usr := &user.User{
Email: uid + "@example.com",
Login: uid,
Name: uid,
Company: "",
OrgName: "",
Password: uid,
EmailVerified: true,
IsAdmin: false,
SkipOrgSetup: false,
DefaultOrgRole: string(org.RoleViewer),
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
}

View File

@ -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)

View File

@ -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

View File

@ -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,22 +32,20 @@ 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)
orgID, err := ss.getOrgIDForNewUser(sess, args)
if err != nil {
return usr, err
}
}
if args.Email == "" {
args.Email = args.Login
@ -69,17 +69,12 @@ 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,
}
salt, err := util.GetRandomString(10)
@ -115,8 +110,6 @@ 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,
@ -136,74 +129,10 @@ func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args user.C
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
}

View File

@ -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, &quotatest.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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}