From 6c43eb0b4dc876d2cda7d95ec229e66b4f0ceaec Mon Sep 17 00:00:00 2001 From: idafurjes <36131195+idafurjes@users.noreply.github.com> Date: Tue, 28 Jun 2022 14:32:25 +0200 Subject: [PATCH] Split Create User (#50502) * Split Create User * Use new create user and User from package user * Add service to wire * Making create user work * Replace user from user pkg * One more * Move Insert to orguser Service/Store * Remove unnecessary conversion * Cleaunp * Fix Get User and add fakes * Fixing get org id for user logic, adding fakes and other adjustments * Add some tests for ourguser service and store * Fix insert org logic * Add comment about deprecation * Fix after merge with main * Move orguser service/store to org service/store * Remove orguser from wire * Unimplement new Create user and use User from pkg user * Fix wire generation * Fix lint * Fix lint - use only User and CrateUserCommand from user pkg * Remove User and CreateUserCommand from models * Fix lint 2 --- pkg/api/admin_users.go | 7 +- pkg/api/ldap_debug.go | 2 +- pkg/api/ldap_debug_test.go | 9 +- pkg/api/login.go | 7 +- pkg/api/login_oauth.go | 3 +- pkg/api/login_test.go | 15 +- pkg/api/org_invite.go | 27 +-- pkg/api/org_test.go | 7 +- pkg/api/org_users.go | 2 +- pkg/api/org_users_test.go | 13 +- pkg/api/password.go | 5 +- pkg/api/signup.go | 13 +- pkg/api/team_members_test.go | 17 +- pkg/api/user.go | 4 +- pkg/api/user_test.go | 9 +- pkg/api/user_token_test.go | 7 +- pkg/login/grafana_login_test.go | 11 +- pkg/middleware/middleware_basic_auth_test.go | 3 +- pkg/middleware/middleware_test.go | 23 +-- pkg/models/notifications.go | 10 +- pkg/models/team_member.go | 2 +- pkg/models/temp_user.go | 2 +- pkg/models/user.go | 63 +------ pkg/models/user_auth.go | 8 +- pkg/models/user_token.go | 3 +- pkg/server/wire.go | 4 + .../accesscontrol/database/database_test.go | 13 +- .../resource_permissions_bench_test.go | 5 +- .../database/resource_permissions_test.go | 7 +- .../resourcepermissions/api_test.go | 7 +- .../resourcepermissions/service_test.go | 8 +- pkg/services/auth/auth_token.go | 5 +- pkg/services/auth/auth_token_test.go | 15 +- pkg/services/auth/testing.go | 7 +- .../contexthandler/auth_proxy_test.go | 3 +- .../contexthandler/authproxy/authproxy.go | 4 +- .../authproxy/authproxy_test.go | 9 +- pkg/services/contexthandler/contexthandler.go | 4 +- pkg/services/dashboards/database/acl_test.go | 19 +- .../database/database_folder_test.go | 63 +++---- .../dashboards/database/database_test.go | 7 +- .../libraryelements/libraryelements_test.go | 9 +- .../librarypanels/librarypanels_test.go | 7 +- pkg/services/login/authinfo.go | 3 +- .../authinfoservice/database/database.go | 11 +- pkg/services/login/authinfoservice/service.go | 13 +- .../login/authinfoservice/user_auth_test.go | 39 +++-- .../login/authinfoservice/userprotection.go | 6 +- pkg/services/login/login.go | 5 +- .../login/loginservice/loginservice.go | 81 ++++++--- .../login/loginservice/loginservice_mock.go | 13 +- .../login/loginservice/loginservice_test.go | 17 +- pkg/services/login/logintest/logintest.go | 9 +- pkg/services/login/userprotection.go | 9 +- pkg/services/multildap/multidap_mock.go | 3 +- pkg/services/notifications/codes.go | 10 +- pkg/services/notifications/codes_test.go | 4 +- pkg/services/notifications/email.go | 4 +- pkg/services/notifications/notifications.go | 3 +- .../notifications/notifications_test.go | 3 +- pkg/services/org/model.go | 60 +++++++ pkg/services/org/org.go | 10 ++ pkg/services/org/orgimpl/org.go | 78 +++++++++ pkg/services/org/orgimpl/org_test.go | 72 ++++++++ pkg/services/org/orgimpl/store.go | 83 +++++++++ pkg/services/org/orgimpl/store_test.go | 73 ++++++++ pkg/services/org/orgtest/fake.go | 28 +++ .../queryhistory/queryhistory_test.go | 7 +- pkg/services/serviceaccounts/api/api_test.go | 8 +- .../serviceaccounts/api/token_test.go | 16 +- .../serviceaccounts/database/database.go | 25 +-- .../serviceaccounts/database/database_test.go | 4 +- .../serviceaccounts/database/stats_test.go | 6 +- .../database/token_store_test.go | 28 +-- pkg/services/serviceaccounts/tests/common.go | 5 +- .../migrations/accesscontrol/test/ac_test.go | 30 ++-- pkg/services/sqlstore/mockstore/mockstore.go | 5 +- pkg/services/sqlstore/org_test.go | 115 ++++++------ pkg/services/sqlstore/org_users.go | 21 +-- pkg/services/sqlstore/org_users_test.go | 19 +- pkg/services/sqlstore/session.go | 4 + pkg/services/sqlstore/sqlbuilder_test.go | 15 +- pkg/services/sqlstore/sqlstore.go | 3 +- pkg/services/sqlstore/stats_test.go | 17 +- pkg/services/sqlstore/store.go | 3 +- pkg/services/sqlstore/team_test.go | 19 +- pkg/services/sqlstore/user.go | 135 ++++++++------- pkg/services/sqlstore/user_test.go | 163 +++++++++--------- pkg/services/user/model.go | 55 ++++++ pkg/services/user/user.go | 9 + pkg/services/user/userimpl/store.go | 62 +++++++ pkg/services/user/userimpl/store_test.go | 57 ++++++ pkg/services/user/userimpl/user.go | 121 +++++++++++++ pkg/services/user/userimpl/user_test.go | 41 +++++ pkg/services/user/usertest/fake.go | 20 +++ .../alerting/api_admin_configuration_test.go | 7 +- .../api_alertmanager_configuration_test.go | 9 +- .../api/alerting/api_alertmanager_test.go | 29 ++-- .../alerting/api_available_channel_test.go | 3 +- .../alerting/api_notification_channel_test.go | 19 +- pkg/tests/api/alerting/api_prometheus_test.go | 7 +- .../api/alerting/api_provisioning_test.go | 7 +- pkg/tests/api/alerting/api_ruler_test.go | 9 +- .../api/dashboards/api_dashboards_test.go | 9 +- pkg/tests/api/plugins/api_plugins_test.go | 8 +- 105 files changed, 1524 insertions(+), 701 deletions(-) create mode 100644 pkg/services/org/model.go create mode 100644 pkg/services/org/org.go create mode 100644 pkg/services/org/orgimpl/org.go create mode 100644 pkg/services/org/orgimpl/org_test.go create mode 100644 pkg/services/org/orgimpl/store.go create mode 100644 pkg/services/org/orgimpl/store_test.go create mode 100644 pkg/services/org/orgtest/fake.go create mode 100644 pkg/services/user/model.go create mode 100644 pkg/services/user/user.go create mode 100644 pkg/services/user/userimpl/store.go create mode 100644 pkg/services/user/userimpl/store_test.go create mode 100644 pkg/services/user/userimpl/user.go create mode 100644 pkg/services/user/userimpl/user_test.go create mode 100644 pkg/services/user/usertest/fake.go diff --git a/pkg/api/admin_users.go b/pkg/api/admin_users.go index 78393beb864..e5febcb0fe5 100644 --- a/pkg/api/admin_users.go +++ b/pkg/api/admin_users.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" ) @@ -19,12 +20,12 @@ func (hs *HTTPServer) AdminCreateUser(c *models.ReqContext) response.Response { if err := web.Bind(c.Req, &form); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Login: form.Login, Email: form.Email, Password: form.Password, Name: form.Name, - OrgId: form.OrgId, + OrgID: form.OrgId, } if len(cmd.Login) == 0 { @@ -55,7 +56,7 @@ func (hs *HTTPServer) AdminCreateUser(c *models.ReqContext) response.Response { result := models.UserIdDTO{ Message: "User created", - Id: user.Id, + Id: user.ID, } return response.JSON(http.StatusOK, result) diff --git a/pkg/api/ldap_debug.go b/pkg/api/ldap_debug.go index f62daaa0407..cc4ef546405 100644 --- a/pkg/api/ldap_debug.go +++ b/pkg/api/ldap_debug.go @@ -179,7 +179,7 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) response.Respon return response.Error(500, "Failed to get user", err) } - authModuleQuery := &models.GetAuthInfoQuery{UserId: query.Result.Id, AuthModule: models.AuthModuleLDAP} + authModuleQuery := &models.GetAuthInfoQuery{UserId: query.Result.ID, AuthModule: models.AuthModuleLDAP} if err := hs.authInfoService.GetAuthInfo(c.Req.Context(), authModuleQuery); err != nil { // validate the userId comes from LDAP if errors.Is(err, models.ErrUserNotFound) { return response.Error(404, models.ErrUserNotFound.Error(), nil) diff --git a/pkg/api/ldap_debug_test.go b/pkg/api/ldap_debug_test.go index 9f68496b86e..074ee98f695 100644 --- a/pkg/api/ldap_debug_test.go +++ b/pkg/api/ldap_debug_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" @@ -403,7 +404,7 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(* func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) { sqlstoremock := mockstore.SQLStoreMock{} - sqlstoremock.ExpectedUser = &models.User{Login: "ldap-daniel", Id: 34} + sqlstoremock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34} sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) { getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) { return &ldap.Config{}, nil @@ -453,7 +454,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) { } func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) { - sqlstoremock := mockstore.SQLStoreMock{ExpectedUser: &models.User{Login: "ldap-daniel", Id: 34}} + sqlstoremock := mockstore.SQLStoreMock{ExpectedUser: &user.User{Login: "ldap-daniel", ID: 34}} sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) { getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) { return &ldap.Config{}, nil @@ -477,7 +478,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) { } func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) { - sqlstoremock := mockstore.SQLStoreMock{ExpectedUser: &models.User{Login: "ldap-daniel", Id: 34}} + sqlstoremock := mockstore.SQLStoreMock{ExpectedUser: &user.User{Login: "ldap-daniel", ID: 34}} sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) { sc.authInfoService.ExpectedExternalUser = &models.ExternalUserInfo{IsDisabled: true, UserId: 34} getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) { @@ -601,7 +602,7 @@ func TestLDAP_AccessControl(t *testing.T) { cfg := setting.NewCfg() cfg.LDAPEnabled = true sc, hs := setupAccessControlScenarioContext(t, cfg, test.url, test.permissions) - hs.SQLStore = &mockstore.SQLStoreMock{ExpectedUser: &models.User{}} + hs.SQLStore = &mockstore.SQLStoreMock{ExpectedUser: &user.User{}} hs.authInfoService = &logintest.AuthInfoServiceFake{} hs.Login = &loginservice.LoginServiceMock{} sc.resp = httptest.NewRecorder() diff --git a/pkg/api/login.go b/pkg/api/login.go index 1b2bad988f0..54abf8ae683 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/middleware/cookies" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/secrets" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -120,7 +121,7 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) { if c.IsSignedIn { // Assign login token to auth proxy users if enable_login_token = true if hs.Cfg.AuthProxyEnabled && hs.Cfg.AuthProxyEnableLoginToken { - user := &models.User{Id: c.SignedInUser.UserId, Email: c.SignedInUser.Email, Login: c.SignedInUser.Login} + user := &user.User{ID: c.SignedInUser.UserId, Email: c.SignedInUser.Email, Login: c.SignedInUser.Login} err := hs.loginUserWithUser(user, c) if err != nil { c.Handle(hs.Cfg, 500, "Failed to sign in user", err) @@ -179,7 +180,7 @@ func (hs *HTTPServer) LoginPost(c *models.ReqContext) response.Response { return response.Error(http.StatusBadRequest, "bad login data", err) } authModule := "" - var user *models.User + var user *user.User var resp *response.NormalResponse defer func() { @@ -260,7 +261,7 @@ func (hs *HTTPServer) LoginPost(c *models.ReqContext) response.Response { return resp } -func (hs *HTTPServer) loginUserWithUser(user *models.User, c *models.ReqContext) error { +func (hs *HTTPServer) loginUserWithUser(user *user.User, c *models.ReqContext) error { if user == nil { return errors.New("could not login user") } diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 4a586c77b6b..7beff805990 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/grafana/pkg/login/social" "github.com/grafana/grafana/pkg/middleware/cookies" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -297,7 +298,7 @@ func (hs *HTTPServer) SyncUser( ctx *models.ReqContext, extUser *models.ExternalUserInfo, connect social.SocialConnector, -) (*models.User, error) { +) (*user.User, error) { oauthLogger.Debug("Syncing Grafana user with corresponding OAuth profile") // add/update user in Grafana cmd := &models.UpsertUserCommand{ diff --git a/pkg/api/login_test.go b/pkg/api/login_test.go index eb151eca511..beab71227ef 100644 --- a/pkg/api/login_test.go +++ b/pkg/api/login_test.go @@ -30,6 +30,7 @@ import ( "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets/fakes" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -331,8 +332,8 @@ func TestLoginPostRedirect(t *testing.T) { return hs.LoginPost(c) }) - user := &models.User{ - Id: 42, + user := &user.User{ + ID: 42, Email: "", } @@ -614,14 +615,14 @@ func TestLoginPostRunLokingHook(t *testing.T) { testHook := loginHookTest{} hookService.AddLoginHook(testHook.LoginHook) - testUser := &models.User{ - Id: 42, + testUser := &user.User{ + ID: 42, Email: "", } testCases := []struct { desc string - authUser *models.User + authUser *user.User authModule string authErr error info models.LoginInfo @@ -680,7 +681,7 @@ func TestLoginPostRunLokingHook(t *testing.T) { if c.info.User != nil { require.NotEmpty(t, info.User) - assert.Equal(t, c.info.User.Id, info.User.Id) + assert.Equal(t, c.info.User.ID, info.User.ID) } }) } @@ -716,7 +717,7 @@ func (m *mockSocialService) GetConnector(string) (social.SocialConnector, error) } type fakeAuthenticator struct { - ExpectedUser *models.User + ExpectedUser *user.User ExpectedAuthModule string ExpectedError error } diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index 44d6359e7f7..2cd52088f16 100644 --- a/pkg/api/org_invite.go +++ b/pkg/api/org_invite.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" @@ -107,9 +108,9 @@ func (hs *HTTPServer) AddOrgInvite(c *models.ReqContext) response.Response { return response.Success(fmt.Sprintf("Created invite for %s", inviteDto.LoginOrEmail)) } -func (hs *HTTPServer) inviteExistingUserToOrg(c *models.ReqContext, user *models.User, inviteDto *dtos.AddInviteForm) response.Response { +func (hs *HTTPServer) inviteExistingUserToOrg(c *models.ReqContext, user *user.User, inviteDto *dtos.AddInviteForm) response.Response { // user exists, add org role - createOrgUserCmd := models.AddOrgUserCommand{OrgId: c.OrgId, UserId: user.Id, Role: inviteDto.Role} + createOrgUserCmd := models.AddOrgUserCommand{OrgId: c.OrgId, UserId: user.ID, Role: inviteDto.Role} if err := hs.SQLStore.AddOrgUser(c.Req.Context(), &createOrgUserCmd); err != nil { if errors.Is(err, models.ErrOrgUserAlreadyAdded) { return response.Error(412, fmt.Sprintf("User %s is already added to organization", inviteDto.LoginOrEmail), err) @@ -135,7 +136,7 @@ func (hs *HTTPServer) inviteExistingUserToOrg(c *models.ReqContext, user *models return response.JSON(http.StatusOK, util.DynMap{ "message": fmt.Sprintf("Existing Grafana user %s added to org %s", user.NameOrFallback(), c.OrgName), - "userId": user.Id, + "userId": user.ID, }) } @@ -191,7 +192,7 @@ func (hs *HTTPServer) CompleteInvite(c *models.ReqContext) response.Response { return response.Error(412, fmt.Sprintf("Invite cannot be used in status %s", invite.Status), nil) } - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: completeInvite.Email, Name: completeInvite.Name, Login: completeInvite.Username, @@ -199,7 +200,7 @@ func (hs *HTTPServer) CompleteInvite(c *models.ReqContext) response.Response { SkipOrgSetup: true, } - user, err := hs.Login.CreateUser(cmd) + usr, err := hs.Login.CreateUser(cmd) if err != nil { if errors.Is(err, models.ErrUserAlreadyExists) { return response.Error(412, fmt.Sprintf("User with email '%s' or username '%s' already exists", completeInvite.Email, completeInvite.Username), err) @@ -209,17 +210,17 @@ func (hs *HTTPServer) CompleteInvite(c *models.ReqContext) response.Response { } if err := hs.bus.Publish(c.Req.Context(), &events.SignUpCompleted{ - Name: user.NameOrFallback(), - Email: user.Email, + Name: usr.NameOrFallback(), + Email: usr.Email, }); err != nil { return response.Error(500, "failed to publish event", err) } - if ok, rsp := hs.applyUserInvite(c.Req.Context(), user, invite, true); !ok { + if ok, rsp := hs.applyUserInvite(c.Req.Context(), usr, invite, true); !ok { return rsp } - err = hs.loginUserWithUser(user, c) + err = hs.loginUserWithUser(usr, c) if err != nil { return response.Error(500, "failed to accept invite", err) } @@ -229,7 +230,7 @@ func (hs *HTTPServer) CompleteInvite(c *models.ReqContext) response.Response { return response.JSON(http.StatusOK, util.DynMap{ "message": "User created and logged in", - "id": user.Id, + "id": usr.ID, }) } @@ -243,9 +244,9 @@ func (hs *HTTPServer) updateTempUserStatus(ctx context.Context, code string, sta return true, nil } -func (hs *HTTPServer) applyUserInvite(ctx context.Context, user *models.User, invite *models.TempUserDTO, setActive bool) (bool, response.Response) { +func (hs *HTTPServer) applyUserInvite(ctx context.Context, user *user.User, invite *models.TempUserDTO, setActive bool) (bool, response.Response) { // add to org - addOrgUserCmd := models.AddOrgUserCommand{OrgId: invite.OrgId, UserId: user.Id, Role: invite.Role} + addOrgUserCmd := models.AddOrgUserCommand{OrgId: invite.OrgId, UserId: user.ID, Role: invite.Role} if err := hs.SQLStore.AddOrgUser(ctx, &addOrgUserCmd); err != nil { if !errors.Is(err, models.ErrOrgUserAlreadyAdded) { return false, response.Error(500, "Error while trying to create org user", err) @@ -259,7 +260,7 @@ func (hs *HTTPServer) applyUserInvite(ctx context.Context, user *models.User, in if setActive { // set org to active - if err := hs.SQLStore.SetUsingOrg(ctx, &models.SetUsingOrgCommand{OrgId: invite.OrgId, UserId: user.Id}); err != nil { + if err := hs.SQLStore.SetUsingOrg(ctx, &models.SetUsingOrgCommand{OrgId: invite.OrgId, UserId: user.ID}); err != nil { return false, response.Error(500, "Failed to set org as active", err) } } diff --git a/pkg/api/org_test.go b/pkg/api/org_test.go index 12d36e7bb08..3c44b823644 100644 --- a/pkg/api/org_test.go +++ b/pkg/api/org_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -185,17 +186,17 @@ func TestAPIEndpoint_PutCurrentOrgAddress_AccessControl(t *testing.T) { // `/api/orgs/` endpoints test // setupOrgsDBForAccessControlTests stores users and create specified number of orgs -func setupOrgsDBForAccessControlTests(t *testing.T, db sqlstore.Store, user models.SignedInUser, orgsCount int) { +func setupOrgsDBForAccessControlTests(t *testing.T, db sqlstore.Store, usr models.SignedInUser, orgsCount int) { t.Helper() - _, err := db.CreateUser(context.Background(), models.CreateUserCommand{Email: user.Email, SkipOrgSetup: true, Login: user.Login}) + _, err := db.CreateUser(context.Background(), user.CreateUserCommand{Email: usr.Email, SkipOrgSetup: true, Login: usr.Login}) require.NoError(t, err) // Create `orgsCount` orgs for i := 1; i <= orgsCount; i++ { _, err = db.CreateOrgWithMember(fmt.Sprintf("TestOrg%v", i), 0) require.NoError(t, err) - err = db.AddOrgUser(context.Background(), &models.AddOrgUserCommand{LoginOrEmail: user.Login, Role: user.OrgRole, OrgId: int64(i), UserId: user.UserId}) + err = db.AddOrgUser(context.Background(), &models.AddOrgUserCommand{LoginOrEmail: usr.Login, Role: usr.OrgRole, OrgId: int64(i), UserId: usr.UserId}) require.NoError(t, err) } } diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index aa10fe8b354..47ecd1156bc 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -55,7 +55,7 @@ func (hs *HTTPServer) addOrgUserHelper(c *models.ReqContext, cmd models.AddOrgUs userToAdd := userQuery.Result - cmd.UserId = userToAdd.Id + cmd.UserId = userToAdd.ID if err := hs.SQLStore.AddOrgUser(c.Req.Context(), &cmd); err != nil { if errors.Is(err, models.ErrOrgUserAlreadyAdded) { diff --git a/pkg/api/org_users_test.go b/pkg/api/org_users_test.go index 1a11c61cbd5..3443b4b6d75 100644 --- a/pkg/api/org_users_test.go +++ b/pkg/api/org_users_test.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" ) @@ -26,11 +27,11 @@ func setUpGetOrgUsersDB(t *testing.T, sqlStore *sqlstore.SQLStore) { sqlStore.Cfg.AutoAssignOrg = true sqlStore.Cfg.AutoAssignOrgId = int(testOrgID) - _, err := sqlStore.CreateUser(context.Background(), models.CreateUserCommand{Email: "testUser@grafana.com", Login: testUserLogin}) + _, err := sqlStore.CreateUser(context.Background(), user.CreateUserCommand{Email: "testUser@grafana.com", Login: testUserLogin}) require.NoError(t, err) - _, err = sqlStore.CreateUser(context.Background(), models.CreateUserCommand{Email: "user1@grafana.com", Login: "user1"}) + _, err = sqlStore.CreateUser(context.Background(), user.CreateUserCommand{Email: "user1@grafana.com", Login: "user1"}) require.NoError(t, err) - _, err = sqlStore.CreateUser(context.Background(), models.CreateUserCommand{Email: "user2@grafana.com", Login: "user2"}) + _, err = sqlStore.CreateUser(context.Background(), user.CreateUserCommand{Email: "user2@grafana.com", Login: "user2"}) require.NoError(t, err) } @@ -280,11 +281,11 @@ func setupOrgUsersDBForAccessControlTests(t *testing.T, db sqlstore.Store) { var err error - _, err = db.CreateUser(context.Background(), models.CreateUserCommand{Email: testServerAdminViewer.Email, SkipOrgSetup: true, Login: testServerAdminViewer.Login}) + _, err = db.CreateUser(context.Background(), user.CreateUserCommand{Email: testServerAdminViewer.Email, SkipOrgSetup: true, Login: testServerAdminViewer.Login}) require.NoError(t, err) - _, err = db.CreateUser(context.Background(), models.CreateUserCommand{Email: testAdminOrg2.Email, SkipOrgSetup: true, Login: testAdminOrg2.Login}) + _, err = db.CreateUser(context.Background(), user.CreateUserCommand{Email: testAdminOrg2.Email, SkipOrgSetup: true, Login: testAdminOrg2.Login}) require.NoError(t, err) - _, err = db.CreateUser(context.Background(), models.CreateUserCommand{Email: testEditorOrg1.Email, SkipOrgSetup: true, Login: testEditorOrg1.Login}) + _, err = db.CreateUser(context.Background(), user.CreateUserCommand{Email: testEditorOrg1.Email, SkipOrgSetup: true, Login: testEditorOrg1.Login}) require.NoError(t, err) // Create both orgs with server admin diff --git a/pkg/api/password.go b/pkg/api/password.go index 42f7fa722ae..4f41a25ca23 100644 --- a/pkg/api/password.go +++ b/pkg/api/password.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" @@ -47,7 +48,7 @@ func (hs *HTTPServer) ResetPassword(c *models.ReqContext) response.Response { } query := models.ValidateResetPasswordCodeQuery{Code: form.Code} - getUserByLogin := func(ctx context.Context, login string) (*models.User, error) { + getUserByLogin := func(ctx context.Context, login string) (*user.User, error) { userQuery := models.GetUserByLoginQuery{LoginOrEmail: login} err := hs.SQLStore.GetUserByLogin(ctx, &userQuery) return userQuery.Result, err @@ -70,7 +71,7 @@ func (hs *HTTPServer) ResetPassword(c *models.ReqContext) response.Response { } cmd := models.ChangeUserPasswordCommand{} - cmd.UserId = query.Result.Id + cmd.UserId = query.Result.ID var err error cmd.NewPassword, err = util.EncodePassword(form.NewPassword, query.Result.Salt) if err != nil { diff --git a/pkg/api/signup.go b/pkg/api/signup.go index 1808a223331..323dada1d49 100644 --- a/pkg/api/signup.go +++ b/pkg/api/signup.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" @@ -75,7 +76,7 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext) response.Response { return response.Error(401, "User signup is disabled", nil) } - createUserCmd := models.CreateUserCommand{ + createUserCmd := user.CreateUserCommand{ Email: form.Email, Login: form.Username, Name: form.Name, @@ -91,7 +92,7 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext) response.Response { createUserCmd.EmailVerified = true } - user, err := hs.Login.CreateUser(createUserCmd) + usr, err := hs.Login.CreateUser(createUserCmd) if err != nil { if errors.Is(err, models.ErrUserAlreadyExists) { return response.Error(401, "User with same email address already exists", nil) @@ -102,8 +103,8 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext) response.Response { // publish signup event if err := hs.bus.Publish(c.Req.Context(), &events.SignUpCompleted{ - Email: user.Email, - Name: user.NameOrFallback(), + Email: usr.Email, + Name: usr.NameOrFallback(), }); err != nil { return response.Error(500, "Failed to publish event", err) } @@ -121,13 +122,13 @@ func (hs *HTTPServer) SignUpStep2(c *models.ReqContext) response.Response { apiResponse := util.DynMap{"message": "User sign up completed successfully", "code": "redirect-to-landing-page"} for _, invite := range invitesQuery.Result { - if ok, rsp := hs.applyUserInvite(c.Req.Context(), user, invite, false); !ok { + if ok, rsp := hs.applyUserInvite(c.Req.Context(), usr, invite, false); !ok { return rsp } apiResponse["code"] = "redirect-to-select-org" } - err = hs.loginUserWithUser(user, c) + err = hs.loginUserWithUser(usr, c) if err != nil { return response.Error(500, "failed to login user", err) } diff --git a/pkg/api/team_members_test.go b/pkg/api/team_members_test.go index cae9003cc0d..b06d0c233a9 100644 --- a/pkg/api/team_members_test.go +++ b/pkg/api/team_members_test.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "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/setting" ) @@ -32,11 +33,11 @@ func (t *TeamGuardianMock) CanAdmin(ctx context.Context, orgId int64, teamId int func setUpGetTeamMembersHandler(t *testing.T, sqlStore *sqlstore.SQLStore) { const testOrgID int64 = 1 - var userCmd models.CreateUserCommand + var userCmd user.CreateUserCommand team, err := sqlStore.CreateTeam("group1 name", "test1@test.com", testOrgID) require.NoError(t, err) for i := 0; i < 3; i++ { - userCmd = models.CreateUserCommand{ + userCmd = user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -44,7 +45,7 @@ func setUpGetTeamMembersHandler(t *testing.T, sqlStore *sqlstore.SQLStore) { // user user, err := sqlStore.CreateUser(context.Background(), userCmd) require.NoError(t, err) - err = sqlStore.AddTeamMember(user.Id, testOrgID, team.Id, false, 1) + err = sqlStore.AddTeamMember(user.ID, testOrgID, team.Id, false, 1) require.NoError(t, err) } } @@ -103,20 +104,20 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) { } func createUser(db sqlstore.Store, orgId int64, t *testing.T) int64 { - user, err := db.CreateUser(context.Background(), models.CreateUserCommand{ + user, err := db.CreateUser(context.Background(), user.CreateUserCommand{ Login: fmt.Sprintf("TestUser%d", rand.Int()), - OrgId: orgId, + OrgID: orgId, Password: "password", }) require.NoError(t, err) - return user.Id + return user.ID } func setupTeamTestScenario(userCount int, db sqlstore.Store, t *testing.T) int64 { - user, err := db.CreateUser(context.Background(), models.CreateUserCommand{SkipOrgSetup: true, Login: testUserLogin}) + user, err := db.CreateUser(context.Background(), user.CreateUserCommand{SkipOrgSetup: true, Login: testUserLogin}) require.NoError(t, err) - testOrg, err := db.CreateOrgWithMember("TestOrg", user.Id) + testOrg, err := db.CreateOrgWithMember("TestOrg", user.ID) require.NoError(t, err) team, err := db.CreateTeam("test", "test@test.com", testOrg.Id) diff --git a/pkg/api/user.go b/pkg/api/user.go index d3a6d19ca97..4cde69bb04b 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -63,13 +63,13 @@ func (hs *HTTPServer) GetUserByLoginOrEmail(c *models.ReqContext) response.Respo } user := query.Result result := models.UserProfileDTO{ - Id: user.Id, + Id: user.ID, Name: user.Name, Email: user.Email, Login: user.Login, Theme: user.Theme, IsGrafanaAdmin: user.IsAdmin, - OrgId: user.OrgId, + OrgId: user.OrgID, UpdatedAt: user.Updated, CreatedAt: user.Created, } diff --git a/pkg/api/user_test.go b/pkg/api/user_test.go index 0879f79dd54..bdd5cd6e071 100644 --- a/pkg/api/user_test.go +++ b/pkg/api/user_test.go @@ -25,6 +25,7 @@ import ( secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -56,7 +57,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { ) hs.authInfoService = srv - createUserCmd := models.CreateUserCommand{ + createUserCmd := user.CreateUserCommand{ Email: fmt.Sprint("user", "@test.com"), Name: "user", Login: "loginuser", @@ -77,7 +78,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { token = token.WithExtra(map[string]interface{}{"id_token": idToken}) query := &models.GetUserByAuthInfoQuery{Login: "loginuser", AuthModule: "test", AuthId: "test"} cmd := &models.UpdateAuthInfoCommand{ - UserId: user.Id, + UserId: user.ID, AuthId: query.AuthId, AuthModule: query.AuthModule, OAuthToken: token, @@ -85,7 +86,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { err = srv.UpdateAuthInfo(context.Background(), cmd) require.NoError(t, err) avatarUrl := dtos.GetGravatarUrl("@test.com") - sc.fakeReqWithParams("GET", sc.url, map[string]string{"id": fmt.Sprintf("%v", user.Id)}).exec() + sc.fakeReqWithParams("GET", sc.url, map[string]string{"id": fmt.Sprintf("%v", user.ID)}).exec() expected := models.UserProfileDTO{ Id: 1, @@ -111,7 +112,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { }, mock) loggedInUserScenario(t, "When calling GET on", "/api/users/lookup", "/api/users/lookup", func(sc *scenarioContext) { - createUserCmd := models.CreateUserCommand{ + createUserCmd := user.CreateUserCommand{ Email: fmt.Sprint("admin", "@test.com"), Name: "admin", Login: "admin", diff --git a/pkg/api/user_token_test.go b/pkg/api/user_token_test.go index 8131f9f28a5..d44f362d870 100644 --- a/pkg/api/user_token_test.go +++ b/pkg/api/user_token_test.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/assert" ) @@ -29,7 +30,7 @@ func TestUserTokenAPIEndpoint(t *testing.T) { t.Run("When current user gets auth tokens for a non-existing user", func(t *testing.T) { mock := &mockstore.SQLStoreMock{ - ExpectedUser: &models.User{Id: 200}, + ExpectedUser: &user.User{ID: 200}, ExpectedError: models.ErrUserNotFound, } getUserAuthTokensScenario(t, "Should return not found when calling GET on", "/api/user/auth-tokens", "/api/user/auth-tokens", 200, func(sc *scenarioContext) { @@ -40,7 +41,7 @@ func TestUserTokenAPIEndpoint(t *testing.T) { t.Run("When logging out an existing user from all devices", func(t *testing.T) { mock := &mockstore.SQLStoreMock{ - ExpectedUser: &models.User{Id: 200}, + ExpectedUser: &user.User{ID: 200}, } logoutUserFromAllDevicesInternalScenario(t, "Should be successful", 1, func(sc *scenarioContext) { sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() @@ -61,7 +62,7 @@ func TestUserTokenAPIEndpoint(t *testing.T) { cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2} token := &models.UserToken{Id: 1} mock := &mockstore.SQLStoreMock{ - ExpectedUser: &models.User{Id: 200}, + ExpectedUser: &user.User{ID: 200}, } revokeUserAuthTokenInternalScenario(t, "Should be successful", cmd, 200, token, func(sc *scenarioContext) { diff --git a/pkg/login/grafana_login_test.go b/pkg/login/grafana_login_test.go index fb9b1b1cd16..175e0b0f3af 100644 --- a/pkg/login/grafana_login_test.go +++ b/pkg/login/grafana_login_test.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -96,7 +97,7 @@ func mockPasswordValidation(valid bool, sc *grafanaLoginScenarioContext) { } } -func (sc *grafanaLoginScenarioContext) getUserByLoginQueryReturns(user *models.User) { +func (sc *grafanaLoginScenarioContext) getUserByLoginQueryReturns(user *user.User) { sc.store.ExpectedUser = user if user == nil { sc.store.ExpectedError = models.ErrUserNotFound @@ -104,8 +105,8 @@ func (sc *grafanaLoginScenarioContext) getUserByLoginQueryReturns(user *models.U } func (sc *grafanaLoginScenarioContext) withValidCredentials() { - sc.getUserByLoginQueryReturns(&models.User{ - Id: 1, + sc.getUserByLoginQueryReturns(&user.User{ + ID: 1, Login: sc.loginUserQuery.Username, Password: sc.loginUserQuery.Password, Salt: "salt", @@ -118,7 +119,7 @@ func (sc *grafanaLoginScenarioContext) withNonExistingUser() { } func (sc *grafanaLoginScenarioContext) withInvalidPassword() { - sc.getUserByLoginQueryReturns(&models.User{ + sc.getUserByLoginQueryReturns(&user.User{ Password: sc.loginUserQuery.Password, Salt: "salt", }) @@ -126,7 +127,7 @@ func (sc *grafanaLoginScenarioContext) withInvalidPassword() { } func (sc *grafanaLoginScenarioContext) withDisabledUser() { - sc.getUserByLoginQueryReturns(&models.User{ + sc.getUserByLoginQueryReturns(&user.User{ IsDisabled: true, }) } diff --git a/pkg/middleware/middleware_basic_auth_test.go b/pkg/middleware/middleware_basic_auth_test.go index 5836a0d315b..442df59b11b 100644 --- a/pkg/middleware/middleware_basic_auth_test.go +++ b/pkg/middleware/middleware_basic_auth_test.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/login/logintest" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/stretchr/testify/assert" @@ -59,7 +60,7 @@ func TestMiddlewareBasicAuth(t *testing.T) { encoded, err := util.EncodePassword(password, salt) require.NoError(t, err) - sc.mockSQLStore.ExpectedUser = &models.User{Password: encoded, Id: id, Salt: salt} + sc.mockSQLStore.ExpectedUser = &user.User{Password: encoded, ID: id, Salt: salt} sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{UserId: id} login.ProvideService(sc.mockSQLStore, &logintest.LoginServiceFake{}) diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index 16665518acf..a89af3a89d2 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -27,6 +27,7 @@ import ( "github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" @@ -365,7 +366,7 @@ func TestMiddlewareContext(t *testing.T) { middlewareScenario(t, "Should respect auto signup option", func(t *testing.T, sc *scenarioContext) { var actualAuthProxyAutoSignUp *bool = nil - sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *models.User { + sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *user.User { actualAuthProxyAutoSignUp = &cmd.SignupAllowed return nil } @@ -386,7 +387,7 @@ func TestMiddlewareContext(t *testing.T) { middlewareScenario(t, "Should create an user from a header", func(t *testing.T, sc *scenarioContext) { sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID} - sc.loginService.ExpectedUser = &models.User{Id: userID} + sc.loginService.ExpectedUser = &user.User{ID: userID} sc.fakeReq("GET", "/") sc.req.Header.Set(sc.cfg.AuthProxyHeaderName, hdrName) @@ -403,10 +404,10 @@ func TestMiddlewareContext(t *testing.T) { middlewareScenario(t, "Should assign role from header to default org", func(t *testing.T, sc *scenarioContext) { var storedRoleInfo map[int64]models.RoleType = nil - sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *models.User { + sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *user.User { storedRoleInfo = cmd.ExternalUser.OrgRoles sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: defaultOrgId, UserId: userID, OrgRole: storedRoleInfo[defaultOrgId]} - return &models.User{Id: userID} + return &user.User{ID: userID} } sc.fakeReq("GET", "/") @@ -426,10 +427,10 @@ func TestMiddlewareContext(t *testing.T) { middlewareScenario(t, "Should NOT assign role from header to non-default org", func(t *testing.T, sc *scenarioContext) { var storedRoleInfo map[int64]models.RoleType = nil - sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *models.User { + sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *user.User { storedRoleInfo = cmd.ExternalUser.OrgRoles sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID, OrgRole: storedRoleInfo[orgID]} - return &models.User{Id: userID} + return &user.User{ID: userID} } sc.fakeReq("GET", "/") @@ -453,7 +454,7 @@ func TestMiddlewareContext(t *testing.T) { middlewareScenario(t, "Should use organisation specified by targetOrgId parameter", func(t *testing.T, sc *scenarioContext) { var targetOrgID int64 = 123 sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: targetOrgID, UserId: userID} - sc.loginService.ExpectedUser = &models.User{Id: userID} + sc.loginService.ExpectedUser = &user.User{ID: userID} sc.fakeReq("GET", fmt.Sprintf("/?targetOrgId=%d", targetOrgID)) sc.req.Header.Set(sc.cfg.AuthProxyHeaderName, hdrName) @@ -497,7 +498,7 @@ func TestMiddlewareContext(t *testing.T) { const orgID int64 = 2 sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID} - sc.loginService.ExpectedUser = &models.User{Id: userID} + sc.loginService.ExpectedUser = &user.User{ID: userID} sc.fakeReq("GET", "/") sc.req.Header.Set(sc.cfg.AuthProxyHeaderName, hdrName) @@ -513,7 +514,7 @@ func TestMiddlewareContext(t *testing.T) { middlewareScenario(t, "Should allow the request from whitelist IP", func(t *testing.T, sc *scenarioContext) { sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID} - sc.loginService.ExpectedUser = &models.User{Id: userID} + sc.loginService.ExpectedUser = &user.User{ID: userID} sc.fakeReq("GET", "/") sc.req.Header.Set(sc.cfg.AuthProxyHeaderName, hdrName) @@ -530,7 +531,7 @@ func TestMiddlewareContext(t *testing.T) { }) middlewareScenario(t, "Should not allow the request from whitelisted IP", func(t *testing.T, sc *scenarioContext) { - sc.loginService.ExpectedUser = &models.User{Id: userID} + sc.loginService.ExpectedUser = &user.User{ID: userID} sc.fakeReq("GET", "/") sc.req.Header.Set(sc.cfg.AuthProxyHeaderName, hdrName) @@ -642,7 +643,7 @@ func getContextHandler(t *testing.T, cfg *setting.Cfg, mockSQLStore *mockstore.S authJWTSvc := models.NewFakeJWTService() tracer := tracing.InitializeTracerForTest() authProxy := authproxy.ProvideAuthProxy(cfg, remoteCacheSvc, loginService, mockSQLStore) - authenticator := &logintest.AuthenticatorFake{ExpectedUser: &models.User{}} + authenticator := &logintest.AuthenticatorFake{ExpectedUser: &user.User{}} return contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, mockSQLStore, tracer, authProxy, loginService, authenticator) } diff --git a/pkg/models/notifications.go b/pkg/models/notifications.go index 41dafa15614..c4e4289a68b 100644 --- a/pkg/models/notifications.go +++ b/pkg/models/notifications.go @@ -1,6 +1,10 @@ package models -import "errors" +import ( + "errors" + + "github.com/grafana/grafana/pkg/services/user" +) var ErrInvalidEmailCode = errors.New("invalid or expired email code") var ErrSmtpNotEnabled = errors.New("SMTP not configured, check your grafana.ini config file's [smtp] section") @@ -40,10 +44,10 @@ type SendWebhookSync struct { } type SendResetPasswordEmailCommand struct { - User *User + User *user.User } type ValidateResetPasswordCodeQuery struct { Code string - Result *User + Result *user.User } diff --git a/pkg/models/team_member.go b/pkg/models/team_member.go index 216e4a6c253..aee5d343414 100644 --- a/pkg/models/team_member.go +++ b/pkg/models/team_member.go @@ -7,7 +7,7 @@ import ( // Typed errors var ( - ErrTeamMemberAlreadyAdded = errors.New("User is already added to this team") + ErrTeamMemberAlreadyAdded = errors.New("user is already added to this team") ) // TeamMember model diff --git a/pkg/models/temp_user.go b/pkg/models/temp_user.go index 13ac06f5fe7..35ace952539 100644 --- a/pkg/models/temp_user.go +++ b/pkg/models/temp_user.go @@ -7,7 +7,7 @@ import ( // Typed errors var ( - ErrTempUserNotFound = errors.New("User not found") + ErrTempUserNotFound = errors.New("user not found") ) type TempUserStatus string diff --git a/pkg/models/user.go b/pkg/models/user.go index b29f11a7324..14d075e65ff 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -3,6 +3,8 @@ package models import ( "errors" "time" + + "github.com/grafana/grafana/pkg/services/user" ) // Typed errors @@ -20,61 +22,6 @@ func (p Password) IsWeak() bool { return len(p) <= 4 } -type User struct { - Id int64 - Version int - Email string - Name string - Login string - Password string - Salt string - Rands string - Company string - EmailVerified bool - Theme string - HelpFlags1 HelpFlags1 - IsDisabled bool - - IsAdmin bool - IsServiceAccount bool - OrgId int64 - - Created time.Time - Updated time.Time - LastSeenAt time.Time -} - -func (u *User) NameOrFallback() string { - if u.Name != "" { - return u.Name - } - if u.Login != "" { - return u.Login - } - return u.Email -} - -// --------------------- -// COMMANDS - -type CreateUserCommand struct { - Email string - Login string - Name string - Company string - OrgId int64 - OrgName string - Password string - EmailVerified bool - IsAdmin bool - IsDisabled bool - SkipOrgSetup bool - DefaultOrgRole string - IsServiceAccount bool - - Result User -} - type UpdateUserCommand struct { Name string `json:"name"` Email string `json:"email"` @@ -115,17 +62,17 @@ type SetUsingOrgCommand struct { type GetUserByLoginQuery struct { LoginOrEmail string - Result *User + Result *user.User } type GetUserByEmailQuery struct { Email string - Result *User + Result *user.User } type GetUserByIdQuery struct { Id int64 - Result *User + Result *user.User } type GetSignedInUserQuery struct { diff --git a/pkg/models/user_auth.go b/pkg/models/user_auth.go index 221b899c0e1..c9bd9ab0859 100644 --- a/pkg/models/user_auth.go +++ b/pkg/models/user_auth.go @@ -3,7 +3,9 @@ package models import ( "time" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" + "golang.org/x/oauth2" ) @@ -40,7 +42,7 @@ type ExternalUserInfo struct { type LoginInfo struct { AuthModule string - User *User + User *user.User ExternalUser ExternalUserInfo LoginUsername string HTTPStatus int @@ -59,7 +61,7 @@ type UpsertUserCommand struct { ExternalUser *ExternalUserInfo SignupAllowed bool - Result *User + Result *user.User } type SetAuthInfoCommand struct { @@ -87,7 +89,7 @@ type LoginUserQuery struct { ReqContext *ReqContext Username string Password string - User *User + User *user.User IpAddress string AuthModule string Cfg *setting.Cfg diff --git a/pkg/models/user_token.go b/pkg/models/user_token.go index c27b669575c..f1220542fef 100644 --- a/pkg/models/user_token.go +++ b/pkg/models/user_token.go @@ -6,6 +6,7 @@ import ( "net" "github.com/grafana/grafana/pkg/registry" + "github.com/grafana/grafana/pkg/services/user" ) // Typed errors @@ -65,7 +66,7 @@ type RevokeAuthTokenCmd struct { // UserTokenService are used for generating and validating user tokens type UserTokenService interface { - CreateToken(ctx context.Context, user *User, clientIP net.IP, userAgent string) (*UserToken, error) + CreateToken(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*UserToken, error) LookupToken(ctx context.Context, unhashedToken string) (*UserToken, error) TryRotateToken(ctx context.Context, token *UserToken, clientIP net.IP, userAgent string) (bool, error) RevokeToken(ctx context.Context, token *UserToken, soft bool) error diff --git a/pkg/server/wire.go b/pkg/server/wire.go index 5f04140571f..6da86c06297 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -71,6 +71,7 @@ import ( ngmetrics "github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/oauthtoken" + "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/plugindashboards" plugindashboardsservice "github.com/grafana/grafana/pkg/services/plugindashboards/service" "github.com/grafana/grafana/pkg/services/pluginsettings" @@ -99,6 +100,7 @@ import ( teamguardianManager "github.com/grafana/grafana/pkg/services/teamguardian/manager" "github.com/grafana/grafana/pkg/services/thumbs" "github.com/grafana/grafana/pkg/services/updatechecker" + "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb/azuremonitor" "github.com/grafana/grafana/pkg/tsdb/cloudmonitoring" @@ -270,6 +272,8 @@ var wireBasicSet = wire.NewSet( wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)), starimpl.ProvideService, dashverimpl.ProvideService, + userimpl.ProvideService, + orgimpl.ProvideService, ) var wireSet = wire.NewSet( diff --git a/pkg/services/accesscontrol/database/database_test.go b/pkg/services/accesscontrol/database/database_test.go index ba0bd22f041..094f27fd01c 100644 --- a/pkg/services/accesscontrol/database/database_test.go +++ b/pkg/services/accesscontrol/database/database_test.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" ) type getUserPermissionsTestCase struct { @@ -81,7 +82,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) { user, team := createUserAndTeam(t, sql, tt.orgID) for _, id := range tt.userPermissions { - _, err := store.SetUserResourcePermission(context.Background(), tt.orgID, accesscontrol.User{ID: user.Id}, types.SetResourcePermissionCommand{ + _, err := store.SetUserResourcePermission(context.Background(), tt.orgID, accesscontrol.User{ID: user.ID}, types.SetResourcePermissionCommand{ Actions: []string{"dashboards:write"}, Resource: "dashboards", ResourceID: id, @@ -119,7 +120,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) { permissions, err := store.GetUserPermissions(context.Background(), accesscontrol.GetUserPermissionsQuery{ OrgID: tt.orgID, - UserID: user.Id, + UserID: user.ID, Roles: roles, Actions: tt.actions, }) @@ -130,19 +131,19 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) { } } -func createUserAndTeam(t *testing.T, sql *sqlstore.SQLStore, orgID int64) (*models.User, models.Team) { +func createUserAndTeam(t *testing.T, sql *sqlstore.SQLStore, orgID int64) (*user.User, models.Team) { t.Helper() - user, err := sql.CreateUser(context.Background(), models.CreateUserCommand{ + user, err := sql.CreateUser(context.Background(), user.CreateUserCommand{ Login: "user", - OrgId: orgID, + OrgID: orgID, }) require.NoError(t, err) team, err := sql.CreateTeam("team", "", orgID) require.NoError(t, err) - err = sql.AddTeamMember(user.Id, orgID, team.Id, false, models.PERMISSION_VIEW) + err = sql.AddTeamMember(user.ID, orgID, team.Id, false, models.PERMISSION_VIEW) require.NoError(t, err) return user, team diff --git a/pkg/services/accesscontrol/database/resource_permissions_bench_test.go b/pkg/services/accesscontrol/database/resource_permissions_bench_test.go index 00e15325d21..56ddb86d51d 100644 --- a/pkg/services/accesscontrol/database/resource_permissions_bench_test.go +++ b/pkg/services/accesscontrol/database/resource_permissions_bench_test.go @@ -15,6 +15,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" ) const ( @@ -150,11 +151,11 @@ func generateTeamsAndUsers(b *testing.B, db *sqlstore.SQLStore, users int) ([]in for u := 0; u < UsersPerTeam; u++ { userName := fmt.Sprintf("%s%v", "user", globalUserId) userEmail := fmt.Sprintf("%s@example.org", userName) - createUserCmd := models.CreateUserCommand{Email: userEmail, Name: userName, Login: userName, OrgId: 1} + createUserCmd := user.CreateUserCommand{Email: userEmail, Name: userName, Login: userName, OrgID: 1} user, err := db.CreateUser(context.Background(), createUserCmd) require.NoError(b, err) - userId := user.Id + userId := user.ID globalUserId++ userIds = append(userIds, userId) diff --git a/pkg/services/accesscontrol/database/resource_permissions_test.go b/pkg/services/accesscontrol/database/resource_permissions_test.go index 6d6d06bb21f..fd7fc73a4cf 100644 --- a/pkg/services/accesscontrol/database/resource_permissions_test.go +++ b/pkg/services/accesscontrol/database/resource_permissions_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" ) type setUserResourcePermissionTest struct { @@ -448,13 +449,13 @@ func seedResourcePermissions(t *testing.T, store *AccessControlStore, sql *sqlst org = &addedOrg } - u, err := sql.CreateUser(context.Background(), models.CreateUserCommand{ + u, err := sql.CreateUser(context.Background(), user.CreateUserCommand{ Login: fmt.Sprintf("user:%s%d", resourceID, i), - OrgId: org.Id, + OrgID: org.Id, }) require.NoError(t, err) - _, err = store.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: u.Id}, types.SetResourcePermissionCommand{ + _, err = store.SetUserResourcePermission(context.Background(), 1, accesscontrol.User{ID: u.ID}, types.SetResourcePermissionCommand{ Actions: actions, Resource: resource, ResourceID: resourceID, diff --git a/pkg/services/accesscontrol/resourcepermissions/api_test.go b/pkg/services/accesscontrol/resourcepermissions/api_test.go index 1facd1fb666..2f32ae41b81 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/api_test.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -400,7 +401,7 @@ func TestApi_setUserPermission(t *testing.T) { server := setupTestServer(t, &models.SignedInUser{OrgId: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}, service) // seed user - _, err := sql.CreateUser(context.Background(), models.CreateUserCommand{Login: "test", OrgId: 1}) + _, err := sql.CreateUser(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))) @@ -502,9 +503,9 @@ 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(), models.CreateUserCommand{Login: "test", OrgId: 1}) + u, err := sql.CreateUser(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") + _, err = service.SetUserPermission(context.Background(), u.OrgID, accesscontrol.User{ID: u.ID}, resourceID, "View") require.NoError(t, err) // seed built in role Admin with "Edit" permission on dashboard 1 _, err = service.SetBuiltInRolePermission(context.Background(), 1, "Admin", resourceID, "Edit") diff --git a/pkg/services/accesscontrol/resourcepermissions/service_test.go b/pkg/services/accesscontrol/resourcepermissions/service_test.go index ffbe2fbcc41..8775502ab99 100644 --- a/pkg/services/accesscontrol/resourcepermissions/service_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/service_test.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/api/routing" - "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/database" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/licensing/licensingtest" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -43,7 +43,7 @@ func TestService_SetUserPermission(t *testing.T) { }) // seed user - user, err := sql.CreateUser(context.Background(), models.CreateUserCommand{Login: "test", OrgId: 1}) + user, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "test", OrgID: 1}) require.NoError(t, err) var hookCalled bool @@ -54,7 +54,7 @@ func TestService_SetUserPermission(t *testing.T) { } } - _, err = service.SetUserPermission(context.Background(), user.OrgId, accesscontrol.User{ID: user.Id}, "1", "") + _, err = service.SetUserPermission(context.Background(), user.OrgID, accesscontrol.User{ID: user.ID}, "1", "") require.NoError(t, err) assert.Equal(t, tt.callHook, hookCalled) }) @@ -200,7 +200,7 @@ func TestService_SetPermissions(t *testing.T) { service, sql := setupTestEnvironment(t, []accesscontrol.Permission{}, tt.options) // seed user - _, err := sql.CreateUser(context.Background(), models.CreateUserCommand{Login: "user", OrgId: 1}) + _, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "user", OrgID: 1}) require.NoError(t, err) _, err = sql.CreateTeam("team", "", 1) require.NoError(t, err) diff --git a/pkg/services/auth/auth_token.go b/pkg/services/auth/auth_token.go index d1de62d43fd..b277b30d081 100644 --- a/pkg/services/auth/auth_token.go +++ b/pkg/services/auth/auth_token.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -57,7 +58,7 @@ func (s *UserAuthTokenService) ActiveTokenCount(ctx context.Context) (int64, err return count, err } -func (s *UserAuthTokenService) CreateToken(ctx context.Context, user *models.User, clientIP net.IP, userAgent string) (*models.UserToken, error) { +func (s *UserAuthTokenService) CreateToken(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*models.UserToken, error) { token, err := util.RandomHex(16) if err != nil { return nil, err @@ -72,7 +73,7 @@ func (s *UserAuthTokenService) CreateToken(ctx context.Context, user *models.Use } userAuthToken := userAuthToken{ - UserId: user.Id, + UserId: user.ID, AuthToken: hashedToken, PrevAuthToken: hashedToken, ClientIp: clientIPStr, diff --git a/pkg/services/auth/auth_token_test.go b/pkg/services/auth/auth_token_test.go index af86988a2a2..6a062647b2d 100644 --- a/pkg/services/auth/auth_token_test.go +++ b/pkg/services/auth/auth_token_test.go @@ -14,13 +14,14 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/require" ) func TestUserAuthToken(t *testing.T) { ctx := createTestContext(t) - user := &models.User{Id: int64(10)} + user := &user.User{ID: int64(10)} // userID := user.Id now := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC) @@ -49,7 +50,7 @@ func TestUserAuthToken(t *testing.T) { userToken, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken) require.Nil(t, err) require.NotNil(t, userToken) - require.Equal(t, user.Id, userToken.UserId) + require.Equal(t, user.ID, userToken.UserId) require.True(t, userToken.AuthTokenSeen) storedAuthToken, err := ctx.getAuthTokenByID(userToken.Id) @@ -104,21 +105,21 @@ func TestUserAuthToken(t *testing.T) { require.NotNil(t, userToken2) t.Run("Can get first user token", func(t *testing.T) { - token, err := ctx.tokenService.GetUserToken(context.Background(), user.Id, userToken.Id) + token, err := ctx.tokenService.GetUserToken(context.Background(), user.ID, userToken.Id) require.Nil(t, err) require.NotNil(t, token) require.Equal(t, userToken.Id, token.Id) }) t.Run("Can get second user token", func(t *testing.T) { - token, err := ctx.tokenService.GetUserToken(context.Background(), user.Id, userToken2.Id) + token, err := ctx.tokenService.GetUserToken(context.Background(), user.ID, userToken2.Id) require.Nil(t, err) require.NotNil(t, token) require.Equal(t, userToken2.Id, token.Id) }) t.Run("Can get user tokens", func(t *testing.T) { - tokens, err := ctx.tokenService.GetUserTokens(context.Background(), user.Id) + tokens, err := ctx.tokenService.GetUserTokens(context.Background(), user.ID) require.Nil(t, err) require.Equal(t, 2, len(tokens)) require.Equal(t, userToken.Id, tokens[0].Id) @@ -126,7 +127,7 @@ func TestUserAuthToken(t *testing.T) { }) t.Run("Can revoke all user tokens", func(t *testing.T) { - err := ctx.tokenService.RevokeAllUserTokens(context.Background(), user.Id) + err := ctx.tokenService.RevokeAllUserTokens(context.Background(), user.ID) require.Nil(t, err) model, err := ctx.getAuthTokenByID(userToken.Id) @@ -143,7 +144,7 @@ func TestUserAuthToken(t *testing.T) { t.Run("Can revoke all users tokens", func(t *testing.T) { userIds := []int64{} for i := 0; i < 3; i++ { - userId := user.Id + int64(i+1) + userId := user.ID + int64(i+1) userIds = append(userIds, userId) _, err := ctx.tokenService.CreateToken(context.Background(), user, net.ParseIP("192.168.10.11"), "some user agent") diff --git a/pkg/services/auth/testing.go b/pkg/services/auth/testing.go index 3985646a5ec..4993c843432 100644 --- a/pkg/services/auth/testing.go +++ b/pkg/services/auth/testing.go @@ -5,10 +5,11 @@ import ( "net" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" ) type FakeUserAuthTokenService struct { - CreateTokenProvider func(ctx context.Context, user *models.User, clientIP net.IP, userAgent string) (*models.UserToken, error) + CreateTokenProvider func(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*models.UserToken, error) TryRotateTokenProvider func(ctx context.Context, token *models.UserToken, clientIP net.IP, userAgent string) (bool, error) LookupTokenProvider func(ctx context.Context, unhashedToken string) (*models.UserToken, error) RevokeTokenProvider func(ctx context.Context, token *models.UserToken, soft bool) error @@ -22,7 +23,7 @@ type FakeUserAuthTokenService struct { func NewFakeUserAuthTokenService() *FakeUserAuthTokenService { return &FakeUserAuthTokenService{ - CreateTokenProvider: func(ctx context.Context, user *models.User, clientIP net.IP, userAgent string) (*models.UserToken, error) { + CreateTokenProvider: func(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*models.UserToken, error) { return &models.UserToken{ UserId: 0, UnhashedToken: "", @@ -64,7 +65,7 @@ func (s *FakeUserAuthTokenService) Init() error { return nil } -func (s *FakeUserAuthTokenService) CreateToken(ctx context.Context, user *models.User, clientIP net.IP, userAgent string) (*models.UserToken, error) { +func (s *FakeUserAuthTokenService) CreateToken(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*models.UserToken, error) { return s.CreateTokenProvider(context.Background(), user, clientIP, userAgent) } diff --git a/pkg/services/contexthandler/auth_proxy_test.go b/pkg/services/contexthandler/auth_proxy_test.go index aead803d720..d7fddc239c1 100644 --- a/pkg/services/contexthandler/auth_proxy_test.go +++ b/pkg/services/contexthandler/auth_proxy_test.go @@ -15,6 +15,7 @@ import ( "github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" "github.com/stretchr/testify/require" @@ -81,7 +82,7 @@ func getContextHandler(t *testing.T) *ContextHandler { authJWTSvc := models.NewFakeJWTService() tracer := tracing.InitializeTracerForTest() - loginService := loginservice.LoginServiceMock{ExpectedUser: &models.User{Id: userID}} + loginService := loginservice.LoginServiceMock{ExpectedUser: &user.User{ID: userID}} authProxy := authproxy.ProvideAuthProxy(cfg, remoteCacheSvc, loginService, &FakeGetSignUserStore{}) authenticator := &fakeAuthenticator{} diff --git a/pkg/services/contexthandler/authproxy/authproxy.go b/pkg/services/contexthandler/authproxy/authproxy.go index ba4a68f3ad6..79eb395b004 100644 --- a/pkg/services/contexthandler/authproxy/authproxy.go +++ b/pkg/services/contexthandler/authproxy/authproxy.go @@ -246,7 +246,7 @@ func (auth *AuthProxy) LoginViaLDAP(reqCtx *models.ReqContext) (int64, error) { return 0, err } - return upsert.Result.Id, nil + return upsert.Result.ID, nil } // loginViaHeader logs in user from the header only @@ -305,7 +305,7 @@ func (auth *AuthProxy) loginViaHeader(reqCtx *models.ReqContext) (int64, error) return 0, err } - return upsert.Result.Id, nil + return upsert.Result.ID, nil } // getDecodedHeader gets decoded value of a header with given headerName diff --git a/pkg/services/contexthandler/authproxy/authproxy_test.go b/pkg/services/contexthandler/authproxy/authproxy_test.go index caa4dc46f71..8f49041aa88 100644 --- a/pkg/services/contexthandler/authproxy/authproxy_test.go +++ b/pkg/services/contexthandler/authproxy/authproxy_test.go @@ -7,14 +7,15 @@ import ( "net/http" "testing" - "github.com/grafana/grafana/pkg/services/login/loginservice" - "github.com/grafana/grafana/pkg/infra/remotecache" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/ldap" + "github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/multildap" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -42,8 +43,8 @@ func prepareMiddleware(t *testing.T, remoteCache *remotecache.RemoteCache, confi } loginService := loginservice.LoginServiceMock{ - ExpectedUser: &models.User{ - Id: id, + ExpectedUser: &user.User{ + ID: id, }, } diff --git a/pkg/services/contexthandler/contexthandler.go b/pkg/services/contexthandler/contexthandler.go index d01a4158dbd..35aed0664ba 100644 --- a/pkg/services/contexthandler/contexthandler.go +++ b/pkg/services/contexthandler/contexthandler.go @@ -348,11 +348,11 @@ func (h *ContextHandler) initContextWithBasicAuth(reqContext *models.ReqContext, user := authQuery.User - query := models.GetSignedInUserQuery{UserId: user.Id, OrgId: orgID} + query := models.GetSignedInUserQuery{UserId: user.ID, OrgId: orgID} if err := h.SQLStore.GetSignedInUserWithCacheCtx(ctx, &query); err != nil { reqContext.Logger.Error( "Failed at user signed in", - "id", user.Id, + "id", user.ID, "org", orgID, ) reqContext.JsonApiErr(401, InvalidUsernamePassword, err) diff --git a/pkg/services/dashboards/database/acl_test.go b/pkg/services/dashboards/database/acl_test.go index 800fcdd9d81..e6ab395ccf4 100644 --- a/pkg/services/dashboards/database/acl_test.go +++ b/pkg/services/dashboards/database/acl_test.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/require" ) @@ -14,7 +15,7 @@ func TestIntegrationDashboardAclDataAccess(t *testing.T) { t.Skip("skipping integration test") } var sqlStore *sqlstore.SQLStore - var currentUser models.User + var currentUser user.User var savedFolder, childDash *models.Dashboard var dashboardStore *DashboardStore @@ -87,7 +88,7 @@ func TestIntegrationDashboardAclDataAccess(t *testing.T) { setup(t) err := updateDashboardAcl(t, dashboardStore, savedFolder.Id, models.DashboardAcl{ OrgID: 1, - UserID: currentUser.Id, + UserID: currentUser.ID, DashboardID: savedFolder.Id, Permission: models.PERMISSION_EDIT, }) @@ -106,7 +107,7 @@ func TestIntegrationDashboardAclDataAccess(t *testing.T) { t.Run("Given child dashboard permission", func(t *testing.T) { err := updateDashboardAcl(t, dashboardStore, childDash.Id, models.DashboardAcl{ OrgID: 1, - UserID: currentUser.Id, + UserID: currentUser.ID, DashboardID: childDash.Id, Permission: models.PERMISSION_EDIT, }) @@ -131,7 +132,7 @@ func TestIntegrationDashboardAclDataAccess(t *testing.T) { setup(t) err := updateDashboardAcl(t, dashboardStore, childDash.Id, models.DashboardAcl{ OrgID: 1, - UserID: currentUser.Id, + UserID: currentUser.ID, DashboardID: childDash.Id, Permission: models.PERMISSION_EDIT, }) @@ -158,7 +159,7 @@ func TestIntegrationDashboardAclDataAccess(t *testing.T) { setup(t) err := updateDashboardAcl(t, dashboardStore, savedFolder.Id, models.DashboardAcl{ OrgID: 1, - UserID: currentUser.Id, + UserID: currentUser.ID, DashboardID: savedFolder.Id, Permission: models.PERMISSION_EDIT, }) @@ -171,7 +172,7 @@ func TestIntegrationDashboardAclDataAccess(t *testing.T) { require.Equal(t, savedFolder.Id, q1.Result[0].DashboardId) require.Equal(t, models.PERMISSION_EDIT, q1.Result[0].Permission) require.Equal(t, "Edit", q1.Result[0].PermissionName) - require.Equal(t, currentUser.Id, q1.Result[0].UserId) + require.Equal(t, currentUser.ID, q1.Result[0].UserId) require.Equal(t, currentUser.Login, q1.Result[0].UserLogin) require.Equal(t, currentUser.Email, q1.Result[0].UserEmail) @@ -248,15 +249,15 @@ func TestIntegrationDashboardAclDataAccess(t *testing.T) { }) } -func createUser(t *testing.T, sqlStore *sqlstore.SQLStore, name string, role string, isAdmin bool) models.User { +func createUser(t *testing.T, sqlStore *sqlstore.SQLStore, name string, role string, isAdmin bool) user.User { t.Helper() sqlStore.Cfg.AutoAssignOrg = true sqlStore.Cfg.AutoAssignOrgId = 1 sqlStore.Cfg.AutoAssignOrgRole = role - currentUserCmd := models.CreateUserCommand{Login: name, Email: name + "@test.com", Name: "a " + name, IsAdmin: isAdmin} + currentUserCmd := user.CreateUserCommand{Login: name, Email: name + "@test.com", Name: "a " + name, IsAdmin: isAdmin} currentUser, err := sqlStore.CreateUser(context.Background(), currentUserCmd) require.NoError(t, err) - q1 := models.GetUserOrgListQuery{UserId: currentUser.Id} + q1 := models.GetUserOrgListQuery{UserId: currentUser.ID} err = sqlStore.GetUserOrgList(context.Background(), &q1) require.NoError(t, err) require.Equal(t, models.RoleType(role), q1.Result[0].Role) diff --git a/pkg/services/dashboards/database/database_folder_test.go b/pkg/services/dashboards/database/database_folder_test.go index ebf06887b0d..5d1378d65f1 100644 --- a/pkg/services/dashboards/database/database_folder_test.go +++ b/pkg/services/dashboards/database/database_folder_test.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" ) func TestIntegrationDashboardFolderDataAccess(t *testing.T) { @@ -18,7 +19,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Testing DB", func(t *testing.T) { var sqlStore *sqlstore.SQLStore var folder, dashInRoot, childDash *models.Dashboard - var currentUser models.User + var currentUser user.User var dashboardStore *DashboardStore setup := func() { @@ -38,7 +39,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("and no acls are set", func(t *testing.T) { t.Run("should return all dashboards", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ - SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id}, } @@ -62,7 +63,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should not return folder", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ - SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id}, } err := testSearchDashboards(dashboardStore, query) @@ -74,13 +75,13 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("when the user is given permission", func(t *testing.T) { err := updateDashboardAcl(t, dashboardStore, folder.Id, models.DashboardAcl{ - DashboardID: folder.Id, OrgID: 1, UserID: currentUser.Id, Permission: models.PERMISSION_EDIT, + DashboardID: folder.Id, OrgID: 1, UserID: currentUser.ID, Permission: models.PERMISSION_EDIT, }) require.NoError(t, err) t.Run("should be able to access folder", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ - SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id}, } @@ -96,7 +97,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should be able to access folder", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ SignedInUser: &models.SignedInUser{ - UserId: currentUser.Id, + UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_ADMIN, }, @@ -123,7 +124,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should not return folder or child", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ - SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}, + SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}, } err := testSearchDashboards(dashboardStore, query) require.NoError(t, err) @@ -133,12 +134,12 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("when the user is given permission to child", func(t *testing.T) { err := updateDashboardAcl(t, dashboardStore, childDash.Id, models.DashboardAcl{ - DashboardID: childDash.Id, OrgID: 1, UserID: currentUser.Id, Permission: models.PERMISSION_EDIT, + DashboardID: childDash.Id, OrgID: 1, UserID: currentUser.ID, Permission: models.PERMISSION_EDIT, }) require.NoError(t, err) t.Run("should be able to search for child dashboard but not folder", func(t *testing.T) { - query := &models.FindPersistedDashboardsQuery{SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}} + query := &models.FindPersistedDashboardsQuery{SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}} err := testSearchDashboards(dashboardStore, query) require.NoError(t, err) require.Equal(t, len(query.Result), 2) @@ -151,7 +152,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should be able to search for child dash and folder", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ SignedInUser: &models.SignedInUser{ - UserId: currentUser.Id, + UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_ADMIN, }, @@ -172,7 +173,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Given two dashboard folders with one dashboard each and one dashboard in the root folder", func(t *testing.T) { var sqlStore *sqlstore.SQLStore var folder1, folder2, dashInRoot, childDash1, childDash2 *models.Dashboard - var currentUser models.User + var currentUser user.User var rootFolderId int64 = 0 setup2 := func() { @@ -192,7 +193,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should return dashboards in root and expanded folder", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ FolderIds: []int64{ - rootFolderId, folder1.Id}, SignedInUser: &models.SignedInUser{UserId: currentUser.Id, + rootFolderId, folder1.Id}, SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER, }, OrgId: 1, @@ -219,7 +220,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should not return folder with acl or its children", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ - SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder1.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, } @@ -235,7 +236,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should return folder without acl and its children", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ - SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, } @@ -259,7 +260,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should return folder without acl but not the dashboard with acl", func(t *testing.T) { query := &models.FindPersistedDashboardsQuery{ - SignedInUser: &models.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: currentUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, } @@ -278,7 +279,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Given two dashboard folders", func(t *testing.T) { var sqlStore *sqlstore.SQLStore var folder1, folder2 *models.Dashboard - var adminUser, editorUser, viewerUser models.User + var adminUser, editorUser, viewerUser user.User setup3 := func() { sqlStore = sqlstore.InitTestDB(t) @@ -297,7 +298,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Should have write access to all dashboard folders in their org", func(t *testing.T) { query := models.FindPersistedDashboardsQuery{ OrgId: 1, - SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgRole: models.ROLE_ADMIN, OrgId: 1}, + SignedInUser: &models.SignedInUser{UserId: adminUser.ID, OrgRole: models.ROLE_ADMIN, OrgId: 1}, Permission: models.PERMISSION_VIEW, Type: "dash-folder", } @@ -312,7 +313,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should have edit permission in folders", func(t *testing.T) { query := &models.HasEditPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_ADMIN}, + SignedInUser: &models.SignedInUser{UserId: adminUser.ID, OrgId: 1, OrgRole: models.ROLE_ADMIN}, } err := dashboardStore.HasEditPermissionInFolders(context.Background(), query) require.NoError(t, err) @@ -321,7 +322,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should have admin permission in folders", func(t *testing.T) { query := &models.HasAdminPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_ADMIN}, + SignedInUser: &models.SignedInUser{UserId: adminUser.ID, OrgId: 1, OrgRole: models.ROLE_ADMIN}, } err := dashboardStore.HasAdminPermissionInFolders(context.Background(), query) require.NoError(t, err) @@ -332,7 +333,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Editor users", func(t *testing.T) { query := models.FindPersistedDashboardsQuery{ OrgId: 1, - SignedInUser: &models.SignedInUser{UserId: editorUser.Id, OrgRole: models.ROLE_EDITOR, OrgId: 1}, + SignedInUser: &models.SignedInUser{UserId: editorUser.ID, OrgRole: models.ROLE_EDITOR, OrgId: 1}, Permission: models.PERMISSION_EDIT, } @@ -347,7 +348,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Should have write access to one dashboard folder if default role changed to view for one folder", func(t *testing.T) { err := updateDashboardAcl(t, dashboardStore, folder1.Id, models.DashboardAcl{ - DashboardID: folder1.Id, OrgID: 1, UserID: editorUser.Id, Permission: models.PERMISSION_VIEW, + DashboardID: folder1.Id, OrgID: 1, UserID: editorUser.ID, Permission: models.PERMISSION_VIEW, }) require.NoError(t, err) @@ -360,7 +361,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should have edit permission in folders", func(t *testing.T) { query := &models.HasEditPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: editorUser.Id, OrgId: 1, OrgRole: models.ROLE_EDITOR}, + SignedInUser: &models.SignedInUser{UserId: editorUser.ID, OrgId: 1, OrgRole: models.ROLE_EDITOR}, } err := dashboardStore.HasEditPermissionInFolders(context.Background(), query) go require.NoError(t, err) @@ -369,7 +370,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should not have admin permission in folders", func(t *testing.T) { query := &models.HasAdminPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_EDITOR}, + SignedInUser: &models.SignedInUser{UserId: adminUser.ID, OrgId: 1, OrgRole: models.ROLE_EDITOR}, } err := dashboardStore.HasAdminPermissionInFolders(context.Background(), query) require.NoError(t, err) @@ -380,7 +381,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Viewer users", func(t *testing.T) { query := models.FindPersistedDashboardsQuery{ OrgId: 1, - SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgRole: models.ROLE_VIEWER, OrgId: 1}, + SignedInUser: &models.SignedInUser{UserId: viewerUser.ID, OrgRole: models.ROLE_VIEWER, OrgId: 1}, Permission: models.PERMISSION_EDIT, } @@ -393,7 +394,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("Should be able to get one dashboard folder if default role changed to edit for one folder", func(t *testing.T) { err := updateDashboardAcl(t, dashboardStore, folder1.Id, models.DashboardAcl{ - DashboardID: folder1.Id, OrgID: 1, UserID: viewerUser.Id, Permission: models.PERMISSION_EDIT, + DashboardID: folder1.Id, OrgID: 1, UserID: viewerUser.ID, Permission: models.PERMISSION_EDIT, }) require.NoError(t, err) @@ -408,7 +409,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { setup3() query := &models.HasEditPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: viewerUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, } err := dashboardStore.HasEditPermissionInFolders(context.Background(), query) go require.NoError(t, err) @@ -417,7 +418,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("should not have admin permission in folders", func(t *testing.T) { query := &models.HasAdminPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: adminUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: adminUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, } err := dashboardStore.HasAdminPermissionInFolders(context.Background(), query) require.NoError(t, err) @@ -426,13 +427,13 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("and admin permission is given for user with org role viewer in one dashboard folder", func(t *testing.T) { err := updateDashboardAcl(t, dashboardStore, folder1.Id, models.DashboardAcl{ - DashboardID: folder1.Id, OrgID: 1, UserID: viewerUser.Id, Permission: models.PERMISSION_ADMIN, + DashboardID: folder1.Id, OrgID: 1, UserID: viewerUser.ID, Permission: models.PERMISSION_ADMIN, }) require.NoError(t, err) t.Run("should have edit permission in folders", func(t *testing.T) { query := &models.HasEditPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: viewerUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, } err := dashboardStore.HasEditPermissionInFolders(context.Background(), query) go require.NoError(t, err) @@ -442,13 +443,13 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { t.Run("and edit permission is given for user with org role viewer in one dashboard folder", func(t *testing.T) { err := updateDashboardAcl(t, dashboardStore, folder1.Id, models.DashboardAcl{ - DashboardID: folder1.Id, OrgID: 1, UserID: viewerUser.Id, Permission: models.PERMISSION_EDIT, + DashboardID: folder1.Id, OrgID: 1, UserID: viewerUser.ID, Permission: models.PERMISSION_EDIT, }) require.NoError(t, err) t.Run("should have edit permission in folders", func(t *testing.T) { query := &models.HasEditPermissionInFoldersQuery{ - SignedInUser: &models.SignedInUser{UserId: viewerUser.Id, OrgId: 1, OrgRole: models.ROLE_VIEWER}, + SignedInUser: &models.SignedInUser{UserId: viewerUser.ID, OrgId: 1, OrgRole: models.ROLE_VIEWER}, } err := dashboardStore.HasEditPermissionInFolders(context.Background(), query) go require.NoError(t, err) diff --git a/pkg/services/dashboards/database/database_test.go b/pkg/services/dashboards/database/database_test.go index ecb8e1aeaf4..3f692f26f45 100644 --- a/pkg/services/dashboards/database/database_test.go +++ b/pkg/services/dashboards/database/database_test.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore/searchstore" "github.com/grafana/grafana/pkg/services/star" "github.com/grafana/grafana/pkg/services/star/starimpl" + "github.com/grafana/grafana/pkg/services/user" ) func TestIntegrationDashboardDataAccess(t *testing.T) { @@ -666,15 +667,15 @@ func insertTestRule(t *testing.T, sqlStore *sqlstore.SQLStore, foderOrgID int64, require.NoError(t, err) } -func CreateUser(t *testing.T, sqlStore *sqlstore.SQLStore, name string, role string, isAdmin bool) models.User { +func CreateUser(t *testing.T, sqlStore *sqlstore.SQLStore, name string, role string, isAdmin bool) user.User { t.Helper() sqlStore.Cfg.AutoAssignOrg = true sqlStore.Cfg.AutoAssignOrgId = 1 sqlStore.Cfg.AutoAssignOrgRole = role - currentUserCmd := models.CreateUserCommand{Login: name, Email: name + "@test.com", Name: "a " + name, IsAdmin: isAdmin} + currentUserCmd := user.CreateUserCommand{Login: name, Email: name + "@test.com", Name: "a " + name, IsAdmin: isAdmin} currentUser, err := sqlStore.CreateUser(context.Background(), currentUserCmd) require.NoError(t, err) - q1 := models.GetUserOrgListQuery{UserId: currentUser.Id} + q1 := models.GetUserOrgListQuery{UserId: currentUser.ID} err = sqlStore.GetUserOrgList(context.Background(), &q1) require.NoError(t, err) require.Equal(t, models.RoleType(role), q1.Result[0].Role) diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index b4f70e53442..d0463b59da7 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -25,6 +25,7 @@ import ( "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -345,7 +346,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo ), } - user := models.SignedInUser{ + usr := models.SignedInUser{ UserId: 1, Name: "Signed In User", Login: "signed_in_user", @@ -358,7 +359,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo // deliberate difference between signed in user and user in db to make it crystal clear // what to expect in the tests // In the real world these are identical - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: "user.in.db@test.com", Name: "User In DB", Login: userInDbName, @@ -368,13 +369,13 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo require.NoError(t, err) sc := scenarioContext{ - user: user, + user: usr, ctx: &ctx, service: &service, sqlStore: sqlStore, reqContext: &models.ReqContext{ Context: &ctx, - SignedInUser: &user, + SignedInUser: &usr, }, } diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index af28610b4ce..4bee022b189 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -24,6 +24,7 @@ import ( "github.com/grafana/grafana/pkg/services/libraryelements" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -1507,7 +1508,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo LibraryElementService: elementService, } - user := &models.SignedInUser{ + usr := &models.SignedInUser{ UserId: 1, Name: "Signed In User", Login: "signed_in_user", @@ -1520,7 +1521,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo // deliberate difference between signed in user and user in db to make it crystal clear // what to expect in the tests // In the real world these are identical - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: "user.in.db@test.com", Name: "User In DB", Login: userInDbName, @@ -1530,7 +1531,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo require.NoError(t, err) sc := scenarioContext{ - user: user, + user: usr, ctx: context.Background(), service: &service, elementService: elementService, diff --git a/pkg/services/login/authinfo.go b/pkg/services/login/authinfo.go index 4db77aa6046..8257d10ec22 100644 --- a/pkg/services/login/authinfo.go +++ b/pkg/services/login/authinfo.go @@ -4,10 +4,11 @@ import ( "context" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" ) type AuthInfoService interface { - LookupAndUpdate(ctx context.Context, query *models.GetUserByAuthInfoQuery) (*models.User, error) + LookupAndUpdate(ctx context.Context, query *models.GetUserByAuthInfoQuery) (*user.User, error) GetAuthInfo(ctx context.Context, query *models.GetAuthInfoQuery) error GetExternalUserInfoByLogin(ctx context.Context, query *models.GetExternalUserInfoByLoginQuery) error SetAuthInfo(ctx context.Context, cmd *models.SetAuthInfoCommand) error diff --git a/pkg/services/login/authinfoservice/database/database.go b/pkg/services/login/authinfoservice/database/database.go index 434479d70a3..e4bc09e7cbd 100644 --- a/pkg/services/login/authinfoservice/database/database.go +++ b/pkg/services/login/authinfoservice/database/database.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" ) var GetTime = time.Now @@ -35,13 +36,13 @@ func (s *AuthInfoStore) GetExternalUserInfoByLogin(ctx context.Context, query *m return err } - authInfoQuery := &models.GetAuthInfoQuery{UserId: userQuery.Result.Id} + authInfoQuery := &models.GetAuthInfoQuery{UserId: userQuery.Result.ID} if err := s.GetAuthInfo(ctx, authInfoQuery); err != nil { return err } query.Result = &models.ExternalUserInfo{ - UserId: userQuery.Result.Id, + UserId: userQuery.Result.ID, Login: userQuery.Result.Login, Email: userQuery.Result.Email, Name: userQuery.Result.Name, @@ -218,7 +219,7 @@ func (s *AuthInfoStore) DeleteAuthInfo(ctx context.Context, cmd *models.DeleteAu }) } -func (s *AuthInfoStore) GetUserById(ctx context.Context, id int64) (*models.User, error) { +func (s *AuthInfoStore) GetUserById(ctx context.Context, id int64) (*user.User, error) { query := models.GetUserByIdQuery{Id: id} if err := s.sqlStore.GetUserById(ctx, &query); err != nil { return nil, err @@ -227,7 +228,7 @@ func (s *AuthInfoStore) GetUserById(ctx context.Context, id int64) (*models.User return query.Result, nil } -func (s *AuthInfoStore) GetUserByLogin(ctx context.Context, login string) (*models.User, error) { +func (s *AuthInfoStore) GetUserByLogin(ctx context.Context, login string) (*user.User, error) { query := models.GetUserByLoginQuery{LoginOrEmail: login} if err := s.sqlStore.GetUserByLogin(ctx, &query); err != nil { return nil, err @@ -236,7 +237,7 @@ func (s *AuthInfoStore) GetUserByLogin(ctx context.Context, login string) (*mode return query.Result, nil } -func (s *AuthInfoStore) GetUserByEmail(ctx context.Context, email string) (*models.User, error) { +func (s *AuthInfoStore) GetUserByEmail(ctx context.Context, email string) (*user.User, error) { query := models.GetUserByEmailQuery{Email: email} if err := s.sqlStore.GetUserByEmail(ctx, &query); err != nil { return nil, err diff --git a/pkg/services/login/authinfoservice/service.go b/pkg/services/login/authinfoservice/service.go index b14b9dfd965..1e8c79bc39a 100644 --- a/pkg/services/login/authinfoservice/service.go +++ b/pkg/services/login/authinfoservice/service.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/infra/usagestats" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/login" + "github.com/grafana/grafana/pkg/services/user" ) const genericOAuthModule = "oauth_generic_oauth" @@ -28,7 +29,7 @@ func ProvideAuthInfoService(userProtectionService login.UserProtectionService, a return s } -func (s *Implementation) LookupAndFix(ctx context.Context, query *models.GetUserByAuthInfoQuery) (bool, *models.User, *models.UserAuth, error) { +func (s *Implementation) LookupAndFix(ctx context.Context, query *models.GetUserByAuthInfoQuery) (bool, *user.User, *models.UserAuth, error) { authQuery := &models.GetAuthInfoQuery{} // Try to find the user by auth module and id first @@ -77,8 +78,8 @@ func (s *Implementation) LookupAndFix(ctx context.Context, query *models.GetUser return false, nil, nil, models.ErrUserNotFound } -func (s *Implementation) LookupByOneOf(ctx context.Context, userId int64, email string, login string) (*models.User, error) { - var user *models.User +func (s *Implementation) LookupByOneOf(ctx context.Context, userId int64, email string, login string) (*user.User, error) { + var user *user.User var err error // If not found, try to find the user by id @@ -128,7 +129,7 @@ func (s *Implementation) GenericOAuthLookup(ctx context.Context, authModule stri return nil, nil } -func (s *Implementation) LookupAndUpdate(ctx context.Context, query *models.GetUserByAuthInfoQuery) (*models.User, error) { +func (s *Implementation) LookupAndUpdate(ctx context.Context, query *models.GetUserByAuthInfoQuery) (*user.User, error) { // 1. LookupAndFix = auth info, user, error // TODO: Not a big fan of the fact that we are deleting auth info here, might want to move that foundUser, user, authInfo, err := s.LookupAndFix(ctx, query) @@ -149,7 +150,7 @@ func (s *Implementation) LookupAndUpdate(ctx context.Context, query *models.GetU } // Special case for generic oauth duplicates - ai, err := s.GenericOAuthLookup(ctx, query.AuthModule, query.AuthId, user.Id) + ai, err := s.GenericOAuthLookup(ctx, query.AuthModule, query.AuthId, user.ID) if !errors.Is(err, models.ErrUserNotFound) { if err != nil { return nil, err @@ -162,7 +163,7 @@ func (s *Implementation) LookupAndUpdate(ctx context.Context, query *models.GetU if query.AuthModule != "" { if authInfo == nil { cmd := &models.SetAuthInfoCommand{ - UserId: user.Id, + UserId: user.ID, AuthModule: query.AuthModule, AuthId: query.AuthId, } diff --git a/pkg/services/login/authinfoservice/user_auth_test.go b/pkg/services/login/authinfoservice/user_auth_test.go index 5189a7d415e..0c96d819e7b 100644 --- a/pkg/services/login/authinfoservice/user_auth_test.go +++ b/pkg/services/login/authinfoservice/user_auth_test.go @@ -12,6 +12,7 @@ import ( secretstore "github.com/grafana/grafana/pkg/services/secrets/database" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/require" "golang.org/x/oauth2" ) @@ -29,7 +30,7 @@ func TestUserAuth(t *testing.T) { t.Run("Given 5 users", func(t *testing.T) { for i := 0; i < 5; i++ { - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -49,12 +50,12 @@ func TestUserAuth(t *testing.T) { require.Equal(t, user.Login, login) // By ID - id := user.Id + id := user.ID user, err = srv.LookupByOneOf(context.Background(), id, "", "") require.Nil(t, err) - require.Equal(t, user.Id, id) + require.Equal(t, user.ID, id) // By Email email := "user1@test.com" @@ -98,7 +99,7 @@ func TestUserAuth(t *testing.T) { require.Equal(t, user.Login, login) // get with non-matching id - id := user.Id + id := user.ID query.UserId = id + 1 user, err = srv.LookupAndUpdate(context.Background(), query) @@ -115,7 +116,7 @@ func TestUserAuth(t *testing.T) { // remove user err = sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { - _, err := sess.Exec("DELETE FROM "+sqlStore.Dialect.Quote("user")+" WHERE id=?", user.Id) + _, err := sess.Exec("DELETE FROM "+sqlStore.Dialect.Quote("user")+" WHERE id=?", user.ID) return err }) require.NoError(t, err) @@ -149,7 +150,7 @@ func TestUserAuth(t *testing.T) { require.Equal(t, user.Login, login) cmd := &models.UpdateAuthInfoCommand{ - UserId: user.Id, + UserId: user.ID, AuthId: query.AuthId, AuthModule: query.AuthModule, OAuthToken: token, @@ -159,7 +160,7 @@ func TestUserAuth(t *testing.T) { require.Nil(t, err) getAuthQuery := &models.GetAuthInfoQuery{ - UserId: user.Id, + UserId: user.ID, } err = srv.authInfoStore.GetAuthInfo(context.Background(), getAuthQuery) @@ -176,7 +177,7 @@ func TestUserAuth(t *testing.T) { sqlStore = sqlstore.InitTestDB(t) for i := 0; i < 5; i++ { - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -210,7 +211,7 @@ func TestUserAuth(t *testing.T) { // Get the latest entry by not supply an authmodule or authid getAuthQuery := &models.GetAuthInfoQuery{ - UserId: user.Id, + UserId: user.ID, } err = authInfoStore.GetAuthInfo(context.Background(), getAuthQuery) @@ -219,14 +220,14 @@ func TestUserAuth(t *testing.T) { require.Equal(t, getAuthQuery.Result.AuthModule, "test2") // "log in" again with the first auth module - updateAuthCmd := &models.UpdateAuthInfoCommand{UserId: user.Id, AuthModule: "test1", AuthId: "test1"} + updateAuthCmd := &models.UpdateAuthInfoCommand{UserId: user.ID, AuthModule: "test1", AuthId: "test1"} err = authInfoStore.UpdateAuthInfo(context.Background(), updateAuthCmd) require.Nil(t, err) // Get the latest entry by not supply an authmodule or authid getAuthQuery = &models.GetAuthInfoQuery{ - UserId: user.Id, + UserId: user.ID, } err = authInfoStore.GetAuthInfo(context.Background(), getAuthQuery) @@ -240,7 +241,7 @@ func TestUserAuth(t *testing.T) { sqlStore = sqlstore.InitTestDB(t) for i := 0; i < 5; i++ { - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -273,7 +274,7 @@ func TestUserAuth(t *testing.T) { // Get the latest entry by not supply an authmodule or authid getAuthQuery := &models.GetAuthInfoQuery{ - UserId: user.Id, + UserId: user.ID, } err = authInfoStore.GetAuthInfo(context.Background(), getAuthQuery) @@ -285,7 +286,7 @@ func TestUserAuth(t *testing.T) { database.GetTime = func() time.Time { return fixedTime } // add oauth info to auth_info to make sure update date does not overwrite it - updateAuthCmd := &models.UpdateAuthInfoCommand{UserId: user.Id, AuthModule: "test1", AuthId: "test1", OAuthToken: &oauth2.Token{ + updateAuthCmd := &models.UpdateAuthInfoCommand{UserId: user.ID, AuthModule: "test1", AuthId: "test1", OAuthToken: &oauth2.Token{ AccessToken: "access_token", TokenType: "token_type", RefreshToken: "refresh_token", @@ -317,7 +318,7 @@ func TestUserAuth(t *testing.T) { // Ensure test 1 did not have its entry modified getAuthQueryUnchanged := &models.GetAuthInfoQuery{ - UserId: user.Id, + UserId: user.ID, AuthModule: "test1", } err = authInfoStore.GetAuthInfo(context.Background(), getAuthQueryUnchanged) @@ -354,11 +355,11 @@ func TestUserAuth(t *testing.T) { sqlStore = sqlstore.InitTestDB(t) for i := 0; i < 5; i++ { - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), - OrgId: 1, + OrgID: 1, } _, err := sqlStore.CreateUser(context.Background(), cmd) require.Nil(t, err) @@ -366,7 +367,7 @@ func TestUserAuth(t *testing.T) { // "Skipping duplicate users test for mysql as it does make unique constraint case insensitive by default if sqlStore.GetDialect().DriverName() != "mysql" { - dupUserEmailcmd := models.CreateUserCommand{ + dupUserEmailcmd := user.CreateUserCommand{ Email: "USERDUPLICATETEST1@TEST.COM", Name: "user name 1", Login: "USER_DUPLICATE_TEST_1_LOGIN", @@ -375,7 +376,7 @@ func TestUserAuth(t *testing.T) { require.NoError(t, err) // add additional user with duplicate login where DOMAIN is upper case - dupUserLogincmd := models.CreateUserCommand{ + dupUserLogincmd := user.CreateUserCommand{ Email: "userduplicatetest1@test.com", Name: "user name 1", Login: "user_duplicate_test_1_login", diff --git a/pkg/services/login/authinfoservice/userprotection.go b/pkg/services/login/authinfoservice/userprotection.go index 242ac85cb35..4c95d411f87 100644 --- a/pkg/services/login/authinfoservice/userprotection.go +++ b/pkg/services/login/authinfoservice/userprotection.go @@ -1,8 +1,6 @@ package authinfoservice -import ( - "github.com/grafana/grafana/pkg/models" -) +import "github.com/grafana/grafana/pkg/services/user" type OSSUserProtectionImpl struct { } @@ -11,6 +9,6 @@ func ProvideOSSUserProtectionService() *OSSUserProtectionImpl { return &OSSUserProtectionImpl{} } -func (*OSSUserProtectionImpl) AllowUserMapping(_ *models.User, _ string) error { +func (*OSSUserProtectionImpl) AllowUserMapping(_ *user.User, _ string) error { return nil } diff --git a/pkg/services/login/login.go b/pkg/services/login/login.go index 18b5381e552..c2ee63df7c3 100644 --- a/pkg/services/login/login.go +++ b/pkg/services/login/login.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" ) var ( @@ -14,10 +15,10 @@ var ( ErrSignupNotAllowed = errors.New("system administrator has disabled signup") ) -type TeamSyncFunc func(user *models.User, externalUser *models.ExternalUserInfo) error +type TeamSyncFunc func(user *user.User, externalUser *models.ExternalUserInfo) error type Service interface { - CreateUser(cmd models.CreateUserCommand) (*models.User, error) + CreateUser(cmd user.CreateUserCommand) (*user.User, error) UpsertUser(ctx context.Context, cmd *models.UpsertUserCommand) error DisableExternalUser(ctx context.Context, username string) error SetTeamSyncFunc(TeamSyncFunc) diff --git a/pkg/services/login/loginservice/loginservice.go b/pkg/services/login/loginservice/loginservice.go index 3879b50c257..f49532c64d0 100644 --- a/pkg/services/login/loginservice/loginservice.go +++ b/pkg/services/login/loginservice/loginservice.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" ) var ( @@ -17,11 +18,13 @@ var ( func ProvideService( sqlStore sqlstore.Store, + userService user.Service, quotaService *quota.QuotaService, authInfoService login.AuthInfoService, ) *Implementation { s := &Implementation{ SQLStore: sqlStore, + userService: userService, QuotaService: quotaService, AuthInfoService: authInfoService, } @@ -30,13 +33,14 @@ func ProvideService( type Implementation struct { SQLStore sqlstore.Store + userService user.Service AuthInfoService login.AuthInfoService QuotaService *quota.QuotaService TeamSync login.TeamSyncFunc } // CreateUser creates inserts a new one. -func (ls *Implementation) CreateUser(cmd models.CreateUserCommand) (*models.User, error) { +func (ls *Implementation) CreateUser(cmd user.CreateUserCommand) (*user.User, error) { return ls.SQLStore.CreateUser(context.Background(), cmd) } @@ -44,7 +48,7 @@ func (ls *Implementation) CreateUser(cmd models.CreateUserCommand) (*models.User func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUserCommand) error { extUser := cmd.ExternalUser - user, err := ls.AuthInfoService.LookupAndUpdate(ctx, &models.GetUserByAuthInfoQuery{ + usr, err := ls.AuthInfoService.LookupAndUpdate(ctx, &models.GetUserByAuthInfoQuery{ AuthModule: extUser.AuthModule, AuthId: extUser.AuthId, UserId: extUser.UserId, @@ -69,14 +73,36 @@ func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUser return login.ErrUsersQuotaReached } - cmd.Result, err = ls.createUser(extUser) + result, err := ls.createUser(extUser) if err != nil { return err } + cmd.Result = &user.User{ + ID: result.ID, + Version: result.Version, + Email: result.Email, + Name: result.Name, + Login: result.Login, + Password: result.Password, + Salt: result.Salt, + Rands: result.Rands, + Company: result.Company, + EmailVerified: result.EmailVerified, + Theme: result.Theme, + HelpFlags1: result.HelpFlags1, + IsDisabled: result.IsDisabled, + IsAdmin: result.IsAdmin, + IsServiceAccount: result.IsServiceAccount, + OrgID: result.OrgID, + Created: result.Created, + Updated: result.Updated, + LastSeenAt: result.LastSeenAt, + } + if extUser.AuthModule != "" { cmd2 := &models.SetAuthInfoCommand{ - UserId: cmd.Result.Id, + UserId: cmd.Result.ID, AuthModule: extUser.AuthModule, AuthId: extUser.AuthId, OAuthToken: extUser.OAuthToken, @@ -86,7 +112,7 @@ func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUser } } } else { - cmd.Result = user + cmd.Result = usr err = ls.updateUser(ctx, cmd.Result, extUser) if err != nil { @@ -101,9 +127,9 @@ func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUser } } - if extUser.AuthModule == models.AuthModuleLDAP && user.IsDisabled { + if extUser.AuthModule == models.AuthModuleLDAP && usr.IsDisabled { // Re-enable user when it found in LDAP - if err := ls.SQLStore.DisableUser(ctx, &models.DisableUserCommand{UserId: cmd.Result.Id, IsDisabled: false}); err != nil { + if err := ls.SQLStore.DisableUser(ctx, &models.DisableUserCommand{UserId: cmd.Result.ID, IsDisabled: false}); err != nil { return err } } @@ -115,7 +141,7 @@ func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUser // Sync isGrafanaAdmin permission if extUser.IsGrafanaAdmin != nil && *extUser.IsGrafanaAdmin != cmd.Result.IsAdmin { - if err := ls.SQLStore.UpdateUserPermissions(cmd.Result.Id, *extUser.IsGrafanaAdmin); err != nil { + if err := ls.SQLStore.UpdateUserPermissions(cmd.Result.ID, *extUser.IsGrafanaAdmin); err != nil { return err } } @@ -175,21 +201,20 @@ func (ls *Implementation) SetTeamSyncFunc(teamSyncFunc login.TeamSyncFunc) { ls.TeamSync = teamSyncFunc } -func (ls *Implementation) createUser(extUser *models.ExternalUserInfo) (*models.User, error) { - cmd := models.CreateUserCommand{ +func (ls *Implementation) createUser(extUser *models.ExternalUserInfo) (*user.User, error) { + cmd := user.CreateUserCommand{ Login: extUser.Login, Email: extUser.Email, Name: extUser.Name, SkipOrgSetup: len(extUser.OrgRoles) > 0, } - return ls.CreateUser(cmd) } -func (ls *Implementation) updateUser(ctx context.Context, user *models.User, extUser *models.ExternalUserInfo) error { +func (ls *Implementation) updateUser(ctx context.Context, user *user.User, extUser *models.ExternalUserInfo) error { // sync user info updateCmd := &models.UpdateUserCommand{ - UserId: user.Id, + UserId: user.ID, } needsUpdate := false @@ -215,24 +240,24 @@ func (ls *Implementation) updateUser(ctx context.Context, user *models.User, ext return nil } - logger.Debug("Syncing user info", "id", user.Id, "update", updateCmd) + logger.Debug("Syncing user info", "id", user.ID, "update", updateCmd) return ls.SQLStore.UpdateUser(ctx, updateCmd) } -func (ls *Implementation) updateUserAuth(ctx context.Context, user *models.User, extUser *models.ExternalUserInfo) error { +func (ls *Implementation) updateUserAuth(ctx context.Context, user *user.User, extUser *models.ExternalUserInfo) error { updateCmd := &models.UpdateAuthInfoCommand{ AuthModule: extUser.AuthModule, AuthId: extUser.AuthId, - UserId: user.Id, + UserId: user.ID, OAuthToken: extUser.OAuthToken, } - logger.Debug("Updating user_auth info", "user_id", user.Id) + logger.Debug("Updating user_auth info", "user_id", user.ID) return ls.AuthInfoService.UpdateAuthInfo(ctx, updateCmd) } -func (ls *Implementation) syncOrgRoles(ctx context.Context, user *models.User, extUser *models.ExternalUserInfo) error { - logger.Debug("Syncing organization roles", "id", user.Id, "extOrgRoles", extUser.OrgRoles) +func (ls *Implementation) syncOrgRoles(ctx context.Context, user *user.User, extUser *models.ExternalUserInfo) error { + logger.Debug("Syncing organization roles", "id", user.ID, "extOrgRoles", extUser.OrgRoles) // don't sync org roles if none is specified if len(extUser.OrgRoles) == 0 { @@ -240,7 +265,7 @@ func (ls *Implementation) syncOrgRoles(ctx context.Context, user *models.User, e return nil } - orgsQuery := &models.GetUserOrgListQuery{UserId: user.Id} + orgsQuery := &models.GetUserOrgListQuery{UserId: user.ID} if err := ls.SQLStore.GetUserOrgList(ctx, orgsQuery); err != nil { return err } @@ -257,7 +282,7 @@ func (ls *Implementation) syncOrgRoles(ctx context.Context, user *models.User, e deleteOrgIds = append(deleteOrgIds, org.OrgId) } else if extRole != org.Role { // update role - cmd := &models.UpdateOrgUserCommand{OrgId: org.OrgId, UserId: user.Id, Role: extRole} + cmd := &models.UpdateOrgUserCommand{OrgId: org.OrgId, UserId: user.ID, Role: extRole} if err := ls.SQLStore.UpdateOrgUser(ctx, cmd); err != nil { return err } @@ -271,7 +296,7 @@ func (ls *Implementation) syncOrgRoles(ctx context.Context, user *models.User, e } // add role - cmd := &models.AddOrgUserCommand{UserId: user.Id, Role: orgRole, OrgId: orgId} + cmd := &models.AddOrgUserCommand{UserId: user.ID, Role: orgRole, OrgId: orgId} err := ls.SQLStore.AddOrgUser(ctx, cmd) if err != nil && !errors.Is(err, models.ErrOrgNotFound) { return err @@ -281,8 +306,8 @@ func (ls *Implementation) syncOrgRoles(ctx context.Context, user *models.User, e // delete any removed org roles for _, orgId := range deleteOrgIds { logger.Debug("Removing user's organization membership as part of syncing with OAuth login", - "userId", user.Id, "orgId", orgId) - cmd := &models.RemoveOrgUserCommand{OrgId: orgId, UserId: user.Id} + "userId", user.ID, "orgId", orgId) + cmd := &models.RemoveOrgUserCommand{OrgId: orgId, UserId: user.ID} if err := ls.SQLStore.RemoveOrgUser(ctx, cmd); err != nil { if errors.Is(err, models.ErrLastOrgAdmin) { logger.Error(err.Error(), "userId", cmd.UserId, "orgId", cmd.OrgId) @@ -294,15 +319,15 @@ func (ls *Implementation) syncOrgRoles(ctx context.Context, user *models.User, e } // update user's default org if needed - if _, ok := extUser.OrgRoles[user.OrgId]; !ok { + if _, ok := extUser.OrgRoles[user.OrgID]; !ok { for orgId := range extUser.OrgRoles { - user.OrgId = orgId + user.OrgID = orgId break } return ls.SQLStore.SetUsingOrg(ctx, &models.SetUsingOrgCommand{ - UserId: user.Id, - OrgId: user.OrgId, + UserId: user.ID, + OrgId: user.OrgID, }) } diff --git a/pkg/services/login/loginservice/loginservice_mock.go b/pkg/services/login/loginservice/loginservice_mock.go index 0090653bdc2..077f2738733 100644 --- a/pkg/services/login/loginservice/loginservice_mock.go +++ b/pkg/services/login/loginservice/loginservice_mock.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/login" + "github.com/grafana/grafana/pkg/services/user" ) type LoginServiceMock struct { @@ -15,13 +16,13 @@ type LoginServiceMock struct { NoExistingOrgId int64 AlreadyExitingLogin string GeneratedUserId int64 - ExpectedUser *models.User - ExpectedUserFunc func(cmd *models.UpsertUserCommand) *models.User + ExpectedUser *user.User + ExpectedUserFunc func(cmd *models.UpsertUserCommand) *user.User ExpectedError error } -func (s LoginServiceMock) CreateUser(cmd models.CreateUserCommand) (*models.User, error) { - if cmd.OrgId == s.NoExistingOrgId { +func (s LoginServiceMock) CreateUser(cmd user.CreateUserCommand) (*user.User, error) { + if cmd.OrgID == s.NoExistingOrgId { return nil, models.ErrOrgNotFound } @@ -30,8 +31,8 @@ func (s LoginServiceMock) CreateUser(cmd models.CreateUserCommand) (*models.User } if s.ExpectedUserForm.Login == cmd.Login && s.ExpectedUserForm.Email == cmd.Email && - s.ExpectedUserForm.Password == cmd.Password && s.ExpectedUserForm.Name == cmd.Name && s.ExpectedUserForm.OrgId == cmd.OrgId { - return &models.User{Id: s.GeneratedUserId}, nil + s.ExpectedUserForm.Password == cmd.Password && s.ExpectedUserForm.Name == cmd.Name && s.ExpectedUserForm.OrgId == cmd.OrgID { + return &user.User{ID: s.GeneratedUserId}, nil } return nil, errors.New("unexpected cmd") diff --git a/pkg/services/login/loginservice/loginservice_test.go b/pkg/services/login/loginservice/loginservice_test.go index 1e687de9e00..7e5c06b665b 100644 --- a/pkg/services/login/loginservice/loginservice_test.go +++ b/pkg/services/login/loginservice/loginservice_test.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -69,15 +70,15 @@ func Test_teamSync(t *testing.T) { } upserCmd := &models.UpsertUserCommand{ExternalUser: &models.ExternalUserInfo{Email: "test_user@example.org"}} - expectedUser := &models.User{ - Id: 1, + expectedUser := &user.User{ + ID: 1, Email: "test_user@example.org", Name: "test_user", Login: "test_user", } authInfoMock.ExpectedUser = expectedUser - var actualUser *models.User + var actualUser *user.User var actualExternalUser *models.ExternalUserInfo t.Run("login.TeamSync should not be called when nil", func(t *testing.T) { @@ -87,7 +88,7 @@ func Test_teamSync(t *testing.T) { assert.Nil(t, actualExternalUser) t.Run("login.TeamSync should be called when not nil", func(t *testing.T) { - teamSyncFunc := func(user *models.User, externalUser *models.ExternalUserInfo) error { + teamSyncFunc := func(user *user.User, externalUser *models.ExternalUserInfo) error { actualUser = user actualExternalUser = externalUser return nil @@ -100,7 +101,7 @@ func Test_teamSync(t *testing.T) { }) t.Run("login.TeamSync should propagate its errors to the caller", func(t *testing.T) { - teamSyncFunc := func(user *models.User, externalUser *models.ExternalUserInfo) error { + teamSyncFunc := func(user *user.User, externalUser *models.ExternalUserInfo) error { return errors.New("teamsync test error") } login.TeamSync = teamSyncFunc @@ -110,9 +111,9 @@ func Test_teamSync(t *testing.T) { }) } -func createSimpleUser() models.User { - user := models.User{ - Id: 1, +func createSimpleUser() user.User { + user := user.User{ + ID: 1, } return user diff --git a/pkg/services/login/logintest/logintest.go b/pkg/services/login/logintest/logintest.go index 020714632e8..16691823323 100644 --- a/pkg/services/login/logintest/logintest.go +++ b/pkg/services/login/logintest/logintest.go @@ -5,11 +5,12 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/login" + "github.com/grafana/grafana/pkg/services/user" ) type LoginServiceFake struct{} -func (l *LoginServiceFake) CreateUser(cmd models.CreateUserCommand) (*models.User, error) { +func (l *LoginServiceFake) CreateUser(cmd user.CreateUserCommand) (*user.User, error) { return nil, nil } func (l *LoginServiceFake) UpsertUser(ctx context.Context, cmd *models.UpsertUserCommand) error { @@ -22,12 +23,12 @@ func (l *LoginServiceFake) SetTeamSyncFunc(login.TeamSyncFunc) {} type AuthInfoServiceFake struct { LatestUserID int64 - ExpectedUser *models.User + ExpectedUser *user.User ExpectedExternalUser *models.ExternalUserInfo ExpectedError error } -func (a *AuthInfoServiceFake) LookupAndUpdate(ctx context.Context, query *models.GetUserByAuthInfoQuery) (*models.User, error) { +func (a *AuthInfoServiceFake) LookupAndUpdate(ctx context.Context, query *models.GetUserByAuthInfoQuery) (*user.User, error) { a.LatestUserID = query.UserId return a.ExpectedUser, a.ExpectedError } @@ -51,7 +52,7 @@ func (a *AuthInfoServiceFake) GetExternalUserInfoByLogin(ctx context.Context, qu } type AuthenticatorFake struct { - ExpectedUser *models.User + ExpectedUser *user.User ExpectedError error } diff --git a/pkg/services/login/userprotection.go b/pkg/services/login/userprotection.go index 0a36fd3b900..3f2f0c8ef1f 100644 --- a/pkg/services/login/userprotection.go +++ b/pkg/services/login/userprotection.go @@ -4,10 +4,11 @@ import ( "context" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" ) type UserProtectionService interface { - AllowUserMapping(user *models.User, authModule string) error + AllowUserMapping(user *user.User, authModule string) error } type Store interface { @@ -17,8 +18,8 @@ type Store interface { UpdateAuthInfo(ctx context.Context, cmd *models.UpdateAuthInfoCommand) error UpdateAuthInfoDate(ctx context.Context, authInfo *models.UserAuth) error DeleteAuthInfo(ctx context.Context, cmd *models.DeleteAuthInfoCommand) error - GetUserById(ctx context.Context, id int64) (*models.User, error) - GetUserByLogin(ctx context.Context, login string) (*models.User, error) - GetUserByEmail(ctx context.Context, email string) (*models.User, error) + GetUserById(ctx context.Context, id int64) (*user.User, error) + GetUserByLogin(ctx context.Context, login string) (*user.User, error) + GetUserByEmail(ctx context.Context, email string) (*user.User, error) CollectLoginStats(ctx context.Context) (map[string]interface{}, error) } diff --git a/pkg/services/multildap/multidap_mock.go b/pkg/services/multildap/multidap_mock.go index 0c7748a9369..d59ca876f00 100644 --- a/pkg/services/multildap/multidap_mock.go +++ b/pkg/services/multildap/multidap_mock.go @@ -3,6 +3,7 @@ package multildap import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/ldap" + "github.com/grafana/grafana/pkg/services/user" ) type MultiLDAPmock struct { @@ -10,7 +11,7 @@ type MultiLDAPmock struct { ID int64 UserCalled bool LoginCalled bool - UserInfo *models.User + UserInfo *user.User AuthModule string ExpectedErr error } diff --git a/pkg/services/notifications/codes.go b/pkg/services/notifications/codes.go index 32cd5dd7cd1..22064c696d8 100644 --- a/pkg/services/notifications/codes.go +++ b/pkg/services/notifications/codes.go @@ -8,7 +8,7 @@ import ( "github.com/unknwon/com" - "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -49,7 +49,7 @@ func createTimeLimitCode(data string, minutes int, startInf interface{}) (string } // verify time limit code -func validateUserEmailCode(cfg *setting.Cfg, user *models.User, code string) (bool, error) { +func validateUserEmailCode(cfg *setting.Cfg, user *user.User, code string) (bool, error) { if len(code) <= 18 { return false, nil } @@ -65,7 +65,7 @@ func validateUserEmailCode(cfg *setting.Cfg, user *models.User, code string) (bo } // right active code - data := com.ToStr(user.Id) + user.Email + user.Login + user.Password + user.Rands + data := com.ToStr(user.ID) + user.Email + user.Login + user.Password + user.Rands retCode, err := createTimeLimitCode(data, minutes, start) if err != nil { return false, err @@ -93,9 +93,9 @@ func getLoginForEmailCode(code string) string { return string(b) } -func createUserEmailCode(cfg *setting.Cfg, u *models.User, startInf interface{}) (string, error) { +func createUserEmailCode(cfg *setting.Cfg, u *user.User, startInf interface{}) (string, error) { minutes := cfg.EmailCodeValidMinutes - data := com.ToStr(u.Id) + u.Email + u.Login + u.Password + u.Rands + data := com.ToStr(u.ID) + u.Email + u.Login + u.Password + u.Rands code, err := createTimeLimitCode(data, minutes, startInf) if err != nil { return "", err diff --git a/pkg/services/notifications/codes_test.go b/pkg/services/notifications/codes_test.go index a314c8decab..d9030f29de1 100644 --- a/pkg/services/notifications/codes_test.go +++ b/pkg/services/notifications/codes_test.go @@ -3,7 +3,7 @@ package notifications import ( "testing" - "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/require" @@ -14,7 +14,7 @@ func TestEmailCodes(t *testing.T) { cfg := setting.NewCfg() cfg.EmailCodeValidMinutes = 120 - user := &models.User{Id: 10, Email: "t@a.com", Login: "asd", Password: "1", Rands: "2"} + user := &user.User{ID: 10, Email: "t@a.com", Login: "asd", Password: "1", Rands: "2"} code, err := createUserEmailCode(cfg, user, nil) require.NoError(t, err) diff --git a/pkg/services/notifications/email.go b/pkg/services/notifications/email.go index 4241425ad02..120ca0d729a 100644 --- a/pkg/services/notifications/email.go +++ b/pkg/services/notifications/email.go @@ -1,7 +1,7 @@ package notifications import ( - "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -24,7 +24,7 @@ type Message struct { AttachedFiles []*AttachedFile } -func setDefaultTemplateData(cfg *setting.Cfg, data map[string]interface{}, u *models.User) { +func setDefaultTemplateData(cfg *setting.Cfg, data map[string]interface{}, u *user.User) { data["AppUrl"] = setting.AppUrl data["BuildVersion"] = setting.BuildVersion data["BuildStamp"] = setting.BuildStamp diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index 7c86ebb8348..261fa13a5f0 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -181,7 +182,7 @@ func (ns *NotificationService) SendResetPasswordEmail(ctx context.Context, cmd * }) } -type GetUserByLoginFunc = func(c context.Context, login string) (*models.User, error) +type GetUserByLoginFunc = func(c context.Context, login string) (*user.User, error) func (ns *NotificationService) ValidateResetPasswordCode(ctx context.Context, query *models.ValidateResetPasswordCodeQuery, userByLogin GetUserByLoginFunc) error { login := getLoginForEmailCode(query.Code) diff --git a/pkg/services/notifications/notifications_test.go b/pkg/services/notifications/notifications_test.go index 7517d2de44c..47e0647039b 100644 --- a/pkg/services/notifications/notifications_test.go +++ b/pkg/services/notifications/notifications_test.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -184,7 +185,7 @@ func TestSendEmailAsync(t *testing.T) { t.Run("When sending reset email password", func(t *testing.T) { sut, _ := createSut(t, bus) - err := sut.SendResetPasswordEmail(context.Background(), &models.SendResetPasswordEmailCommand{User: &models.User{Email: "asd@asd.com"}}) + err := sut.SendResetPasswordEmail(context.Background(), &models.SendResetPasswordEmailCommand{User: &user.User{Email: "asd@asd.com"}}) require.NoError(t, err) sentMsg := <-sut.mailQueue diff --git a/pkg/services/org/model.go b/pkg/services/org/model.go new file mode 100644 index 00000000000..503cae62f17 --- /dev/null +++ b/pkg/services/org/model.go @@ -0,0 +1,60 @@ +package org + +import ( + "errors" + "time" +) + +// Typed errors +var ( + ErrOrgNotFound = errors.New("organization not found") + ErrOrgNameTaken = errors.New("organization name is taken") +) + +type Org struct { + ID int64 `xorm:"pk autoincr 'id'"` + Version int + Name string + + Address1 string + Address2 string + City string + ZipCode string + State string + Country string + + Created time.Time + Updated time.Time +} +type OrgUser struct { + ID int64 `xorm:"pk autoincr 'id'"` + OrgID int64 `xorm:"org_id"` + UserID int64 `xorm:"user_id"` + Role RoleType + Created time.Time + Updated time.Time +} + +// swagger:enum RoleType +type RoleType string + +const ( + ROLE_VIEWER RoleType = "Viewer" + ROLE_EDITOR RoleType = "Editor" + ROLE_ADMIN RoleType = "Admin" +) + +type CreateOrgCommand struct { + Name string `json:"name" binding:"Required"` + + // initial admin user for account + UserID int64 `json:"-"` +} + +type GetOrgIDForNewUserCommand struct { + Email string + Login string + OrgID int64 + OrgName string + SkipOrgSetup bool +} diff --git a/pkg/services/org/org.go b/pkg/services/org/org.go new file mode 100644 index 00000000000..4f71bca6385 --- /dev/null +++ b/pkg/services/org/org.go @@ -0,0 +1,10 @@ +package org + +import ( + "context" +) + +type Service interface { + GetIDForNewUser(context.Context, GetOrgIDForNewUserCommand) (int64, error) + InsertUser(context.Context, *OrgUser) (int64, error) +} diff --git a/pkg/services/org/orgimpl/org.go b/pkg/services/org/orgimpl/org.go new file mode 100644 index 00000000000..4df55edc55e --- /dev/null +++ b/pkg/services/org/orgimpl/org.go @@ -0,0 +1,78 @@ +package orgimpl + +import ( + "context" + "fmt" + "time" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/sqlstore/db" + "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util" +) + +type Service struct { + store store + cfg *setting.Cfg + log log.Logger +} + +func ProvideService(db db.DB, cfg *setting.Cfg) org.Service { + return &Service{ + store: &sqlStore{ + db: db, + dialect: db.GetDialect(), + }, + cfg: cfg, + log: log.New("org service"), + } +} + +func (s *Service) GetIDForNewUser(ctx context.Context, cmd org.GetOrgIDForNewUserCommand) (int64, error) { + var orga org.Org + if cmd.SkipOrgSetup { + return -1, nil + } + + if setting.AutoAssignOrg && cmd.OrgID != 0 { + _, err := s.store.Get(ctx, cmd.OrgID) + if err != nil { + return -1, err + } + return cmd.OrgID, nil + } + + orgName := cmd.OrgName + if len(orgName) == 0 { + orgName = util.StringsFallback2(cmd.Email, cmd.Login) + } + + if setting.AutoAssignOrg { + orga, err := s.store.Get(ctx, int64(s.cfg.AutoAssignOrgId)) + if err != nil { + return 0, err + } + if orga.ID != 0 { + return orga.ID, nil + } + if setting.AutoAssignOrgId != 1 { + s.log.Error("Could not create user: organization ID does not exist", "orgID", + setting.AutoAssignOrgId) + return 0, fmt.Errorf("could not create user: organization ID %d does not exist", + setting.AutoAssignOrgId) + } + orga.Name = MainOrgName + orga.ID = int64(setting.AutoAssignOrgId) + } else { + orga.Name = orgName + } + orga.Created = time.Now() + orga.Updated = time.Now() + + return s.store.Insert(ctx, &orga) +} + +func (s *Service) InsertUser(ctx context.Context, orguser *org.OrgUser) (int64, error) { + return s.store.InsertUser(ctx, orguser) +} diff --git a/pkg/services/org/orgimpl/org_test.go b/pkg/services/org/orgimpl/org_test.go new file mode 100644 index 00000000000..decbf576645 --- /dev/null +++ b/pkg/services/org/orgimpl/org_test.go @@ -0,0 +1,72 @@ +package orgimpl + +import ( + "context" + "testing" + + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/setting" + "github.com/stretchr/testify/require" +) + +func TestOrgService(t *testing.T) { + orgStore := newOrgStoreFake() + orgService := Service{ + store: orgStore, + cfg: setting.NewCfg(), + } + + t.Run("create org", func(t *testing.T) { + _, err := orgService.GetIDForNewUser(context.Background(), org.GetOrgIDForNewUserCommand{}) + require.NoError(t, err) + }) + + t.Run("create org", func(t *testing.T) { + _, err := orgService.GetIDForNewUser(context.Background(), org.GetOrgIDForNewUserCommand{}) + require.NoError(t, err) + }) + + t.Run("create org with auto assign org ID", func(t *testing.T) { + setting.AutoAssignOrg = true + setting.AutoAssignOrgId = 1 + orgStore.ExpectedOrgID = 1 + orgStore.ExpectedOrg = &org.Org{} + _, err := orgService.GetIDForNewUser(context.Background(), org.GetOrgIDForNewUserCommand{}) + require.NoError(t, err) + }) + + t.Run("create org with auto assign org ID and orgID", func(t *testing.T) { + setting.AutoAssignOrg = true + setting.AutoAssignOrgId = 1 + orgStore.ExpectedOrgID = 1 + orgStore.ExpectedOrg = &org.Org{} + _, err := orgService.GetIDForNewUser(context.Background(), org.GetOrgIDForNewUserCommand{OrgID: 1}) + require.NoError(t, err) + }) + + setting.AutoAssignOrg = false + setting.AutoAssignOrgId = 0 +} + +type FakeOrgStore struct { + ExpectedOrg *org.Org + ExpectedOrgID int64 + ExpectedUserID int64 + ExpectedError error +} + +func newOrgStoreFake() *FakeOrgStore { + return &FakeOrgStore{} +} + +func (f *FakeOrgStore) Get(ctx context.Context, orgID int64) (*org.Org, error) { + return f.ExpectedOrg, f.ExpectedError +} + +func (f *FakeOrgStore) Insert(ctx context.Context, org *org.Org) (int64, error) { + return f.ExpectedOrgID, f.ExpectedError +} + +func (f *FakeOrgStore) InsertUser(ctx context.Context, org *org.OrgUser) (int64, error) { + return f.ExpectedUserID, f.ExpectedError +} diff --git a/pkg/services/org/orgimpl/store.go b/pkg/services/org/orgimpl/store.go new file mode 100644 index 00000000000..9c166cb527c --- /dev/null +++ b/pkg/services/org/orgimpl/store.go @@ -0,0 +1,83 @@ +package orgimpl + +import ( + "context" + + "github.com/grafana/grafana/pkg/events" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/sqlstore/db" + "github.com/grafana/grafana/pkg/services/sqlstore/migrator" +) + +const MainOrgName = "Main Org." + +type store interface { + Get(context.Context, int64) (*org.Org, error) + Insert(context.Context, *org.Org) (int64, error) + InsertUser(context.Context, *org.OrgUser) (int64, error) +} + +type sqlStore struct { + db db.DB + dialect migrator.Dialect +} + +func (ss *sqlStore) Get(ctx context.Context, orgID int64) (*org.Org, error) { + var orga org.Org + err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + has, err := sess.Where("id=?", orgID).Get(&orga) + if err != nil { + return err + } + if !has { + return org.ErrOrgNotFound + } + return nil + }) + if err != nil { + return nil, err + } + return &orga, nil +} + +func (ss *sqlStore) Insert(ctx context.Context, org *org.Org) (int64, error) { + var orgID int64 + var err error + err = ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + if orgID, err = sess.InsertOne(org); err != nil { + return err + } + if org.ID != 0 { + // it sets the setval in the sequence + if err := ss.dialect.PostInsertId("org", sess.Session); err != nil { + return err + } + } + sess.PublishAfterCommit(&events.OrgCreated{ + Timestamp: org.Created, + Id: org.ID, + Name: org.Name, + }) + return nil + }) + if err != nil { + return 0, err + } + return orgID, nil +} + +func (ss *sqlStore) InsertUser(ctx context.Context, cmd *org.OrgUser) (int64, error) { + var orgID int64 + var err error + err = ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + if orgID, err = sess.Insert(cmd); err != nil { + return err + } + return nil + }) + if err != nil { + return 0, err + } + return orgID, nil +} diff --git a/pkg/services/org/orgimpl/store_test.go b/pkg/services/org/orgimpl/store_test.go new file mode 100644 index 00000000000..fb85c03fe7c --- /dev/null +++ b/pkg/services/org/orgimpl/store_test.go @@ -0,0 +1,73 @@ +package orgimpl + +import ( + "context" + "testing" + "time" + + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/stretchr/testify/require" +) + +func TestIntegrationOrgDataAccess(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + ss := sqlstore.InitTestDB(t) + orgStore := sqlStore{ + db: ss, + dialect: ss.GetDialect(), + } + + t.Run("org not found", func(t *testing.T) { + _, err := orgStore.Get(context.Background(), 1) + require.Error(t, err, org.ErrOrgNotFound) + }) + + t.Run("org inserted", func(t *testing.T) { + _, err := orgStore.Insert(context.Background(), &org.Org{ + Version: 1, + Name: "test1", + Created: time.Now(), + Updated: time.Now(), + }) + require.NoError(t, err) + }) + + t.Run("org inserted with next available org ID", func(t *testing.T) { + orgID, err := orgStore.Insert(context.Background(), &org.Org{ + ID: 55, + Version: 1, + Name: "test2", + Created: time.Now(), + Updated: time.Now(), + }) + require.NoError(t, err) + _, err = orgStore.Get(context.Background(), orgID) + require.NoError(t, err) + }) +} + +func TestIntegrationOrgUserDataAccess(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + ss := sqlstore.InitTestDB(t) + orgUserStore := sqlStore{ + db: ss, + } + + t.Run("org user inserted", func(t *testing.T) { + _, err := orgUserStore.InsertUser(context.Background(), &org.OrgUser{ + ID: 1, + OrgID: 1, + UserID: 1, + Created: time.Now(), + Updated: time.Now(), + }) + require.NoError(t, err) + }) +} diff --git a/pkg/services/org/orgtest/fake.go b/pkg/services/org/orgtest/fake.go new file mode 100644 index 00000000000..2e4a8bd7568 --- /dev/null +++ b/pkg/services/org/orgtest/fake.go @@ -0,0 +1,28 @@ +package orgtest + +import ( + "context" + + "github.com/grafana/grafana/pkg/services/org" +) + +type FakeOrgService struct { + ExpectedOrgUserID int64 + ExpectedError error +} + +func NewOrgServiceFake() *FakeOrgService { + return &FakeOrgService{} +} + +func (f *FakeOrgService) GetIDForNewUser(ctx context.Context, cmd org.GetOrgIDForNewUserCommand) (int64, error) { + return f.ExpectedOrgUserID, f.ExpectedError +} + +func (f *FakeOrgService) Insert(ctx context.Context, cmd *org.OrgUser) (int64, error) { + return f.ExpectedOrgUserID, f.ExpectedError +} + +func (f *FakeOrgService) InsertUser(ctx context.Context, cmd *org.OrgUser) (int64, error) { + return f.ExpectedOrgUserID, f.ExpectedError +} diff --git a/pkg/services/queryhistory/queryhistory_test.go b/pkg/services/queryhistory/queryhistory_test.go index 395be6b0489..d1f8a354336 100644 --- a/pkg/services/queryhistory/queryhistory_test.go +++ b/pkg/services/queryhistory/queryhistory_test.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" "github.com/stretchr/testify/require" @@ -51,7 +52,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo service.Cfg.QueryHistoryEnabled = true - user := models.SignedInUser{ + usr := models.SignedInUser{ UserId: testUserID, Name: "Signed In User", Login: "signed_in_user", @@ -61,7 +62,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo LastSeenAt: time.Now(), } - _, err := sqlStore.CreateUser(context.Background(), models.CreateUserCommand{ + _, err := sqlStore.CreateUser(context.Background(), user.CreateUserCommand{ Email: "signed.in.user@test.com", Name: "Signed In User", Login: "signed_in_user", @@ -74,7 +75,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo sqlStore: sqlStore, reqContext: &models.ReqContext{ Context: &ctx, - SignedInUser: &user, + SignedInUser: &usr, }, } fn(t, sc) diff --git a/pkg/services/serviceaccounts/api/api_test.go b/pkg/services/serviceaccounts/api/api_test.go index 60d45ad36e7..2f63ea3aa74 100644 --- a/pkg/services/serviceaccounts/api/api_test.go +++ b/pkg/services/serviceaccounts/api/api_test.go @@ -185,7 +185,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) - actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, fmt.Sprint(createduser.Id))).Code + actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, fmt.Sprint(createduser.ID))).Code require.Equal(t, testcase.expectedCode, actual) }) }) @@ -209,7 +209,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) - actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, createduser.Id)).Code + actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, createduser.ID)).Code require.Equal(t, testcase.expectedCode, actual) }) }) @@ -314,7 +314,7 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) { scopeID := tc.Id if tc.user != nil { createdUser := tests.SetupUserServiceAccount(t, store, *tc.user) - scopeID = int(createdUser.Id) + scopeID = int(createdUser.ID) } server, _ := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, saStore) @@ -440,7 +440,7 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) { scopeID := tc.Id if tc.user != nil { createdUser := tests.SetupUserServiceAccount(t, store, *tc.user) - scopeID = int(createdUser.Id) + scopeID = int(createdUser.ID) } var rawBody io.Reader = http.NoBody diff --git a/pkg/services/serviceaccounts/api/token_test.go b/pkg/services/serviceaccounts/api/token_test.go index 9f4e925b7a4..93f46680378 100644 --- a/pkg/services/serviceaccounts/api/token_test.go +++ b/pkg/services/serviceaccounts/api/token_test.go @@ -125,7 +125,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { - endpoint := fmt.Sprintf(serviceaccountIDTokensPath, sa.Id) + endpoint := fmt.Sprintf(serviceaccountIDTokensPath, sa.ID) bodyString := "" if tc.body != nil { b, err := json.Marshal(tc.body) @@ -146,12 +146,12 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) { if actualCode == http.StatusOK { assert.Equal(t, tc.body["name"], actualBody["name"]) - query := models.GetApiKeyByNameQuery{KeyName: tc.body["name"].(string), OrgId: sa.OrgId} + query := models.GetApiKeyByNameQuery{KeyName: tc.body["name"].(string), OrgId: sa.OrgID} err = store.GetApiKeyByName(context.Background(), &query) require.NoError(t, err) - assert.Equal(t, sa.Id, *query.Result.ServiceAccountId) - assert.Equal(t, sa.OrgId, query.Result.OrgId) + assert.Equal(t, sa.ID, *query.Result.ServiceAccountId) + assert.Equal(t, sa.OrgID, query.Result.OrgId) assert.True(t, strings.HasPrefix(actualBody["key"].(string), "glsa")) keyInfo, err := apikeygenprefix.Decode(actualBody["key"].(string)) @@ -229,9 +229,9 @@ 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, saStore, tc.keyName, sa.OrgID, sa.ID, 1) - endpoint := fmt.Sprintf(serviceaccountIDTokensDetailPath, sa.Id, token.Id) + endpoint := fmt.Sprintf(serviceaccountIDTokensDetailPath, sa.ID, token.Id) bodyString := "" server, _ := setupTestServer(t, svcMock, routing.NewRouteRegister(), tc.acmock, store, saStore) actual := requestResponse(server, http.MethodDelete, endpoint, strings.NewReader(bodyString)) @@ -242,7 +242,7 @@ func TestServiceAccountsAPI_DeleteToken(t *testing.T) { _ = json.Unmarshal(actual.Body.Bytes(), &actualBody) require.Equal(t, tc.expectedCode, actualCode, endpoint, actualBody) - query := models.GetApiKeyByNameQuery{KeyName: tc.keyName, OrgId: sa.OrgId} + query := models.GetApiKeyByNameQuery{KeyName: tc.keyName, OrgId: sa.OrgID} err := store.GetApiKeyByName(context.Background(), &query) if actualCode == http.StatusOK { require.Error(t, err) @@ -354,7 +354,7 @@ func TestServiceAccountsAPI_ListTokens(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { - endpoint := fmt.Sprintf(serviceAccountIDPath+"/tokens", sa.Id) + endpoint := fmt.Sprintf(serviceAccountIDPath+"/tokens", sa.ID) server, _ := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, &saStoreMockTokens{saAPIKeys: tc.tokens}) actual := requestResponse(server, http.MethodGet, endpoint, http.NoBody) diff --git a/pkg/services/serviceaccounts/database/database.go b/pkg/services/serviceaccounts/database/database.go index 7a29ca0ebb1..00d09b208fc 100644 --- a/pkg/services/serviceaccounts/database/database.go +++ b/pkg/services/serviceaccounts/database/database.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" ) type ServiceAccountsStoreImpl struct { @@ -34,9 +35,9 @@ func NewServiceAccountsStore(store *sqlstore.SQLStore, kvStore kvstore.KVStore) func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, orgId int64, name string) (saDTO *serviceaccounts.ServiceAccountDTO, err error) { generatedLogin := "sa-" + strings.ToLower(name) generatedLogin = strings.ReplaceAll(generatedLogin, " ", "-") - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Login: generatedLogin, - OrgId: orgId, + OrgID: orgId, Name: name, IsServiceAccount: true, } @@ -50,10 +51,10 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, org } return &serviceaccounts.ServiceAccountDTO{ - Id: newuser.Id, + Id: newuser.ID, Name: newuser.Name, Login: newuser.Login, - OrgId: newuser.OrgId, + OrgId: newuser.OrgID, Tokens: 0, }, nil } @@ -89,7 +90,7 @@ func (s *ServiceAccountsStoreImpl) UpdateServiceAccount(ctx context.Context, } if saForm.Name != nil || saForm.IsDisabled != nil { - user := models.User{ + user := user.User{ Updated: updateTime, } @@ -131,7 +132,7 @@ func (s *ServiceAccountsStoreImpl) DeleteServiceAccount(ctx context.Context, org } func (s *ServiceAccountsStoreImpl) deleteServiceAccount(sess *sqlstore.DBSession, orgId, serviceAccountId int64) error { - user := models.User{} + user := user.User{} has, err := sess.Where(`org_id = ? and id = ? and is_service_account = ?`, orgId, serviceAccountId, s.sqlStore.Dialect.BooleanStr(true)).Get(&user) if err != nil { @@ -141,7 +142,7 @@ func (s *ServiceAccountsStoreImpl) deleteServiceAccount(sess *sqlstore.DBSession return serviceaccounts.ErrServiceAccountNotFound } for _, sql := range ServiceAccountDeletions() { - _, err := sess.Exec(sql, user.Id) + _, err := sess.Exec(sql, user.ID) if err != nil { return err } @@ -405,10 +406,10 @@ func (s *ServiceAccountsStoreImpl) MigrateApiKey(ctx context.Context, orgId int6 func (s *ServiceAccountsStoreImpl) CreateServiceAccountFromApikey(ctx context.Context, key *models.ApiKey) error { prefix := "sa-autogen" - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Login: fmt.Sprintf("%v-%v-%v", prefix, key.OrgId, key.Name), Name: fmt.Sprintf("%v-%v", prefix, key.Name), - OrgId: key.OrgId, + OrgID: key.OrgId, DefaultOrgRole: string(key.Role), IsServiceAccount: true, } @@ -419,8 +420,8 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccountFromApikey(ctx context.Co return fmt.Errorf("failed to create service account: %w", errCreateSA) } - if err := s.assignApiKeyToServiceAccount(sess, key.Id, newSA.Id); err != nil { - if err := s.sqlStore.DeleteUser(ctx, &models.DeleteUserCommand{UserId: newSA.Id}); err != nil { + if err := s.assignApiKeyToServiceAccount(sess, key.Id, newSA.ID); err != nil { + if err := s.sqlStore.DeleteUser(ctx, &models.DeleteUserCommand{UserId: newSA.ID}); err != nil { s.log.Error("Error deleting service account", "error", err) } return fmt.Errorf("failed to migrate API key to service account token: %w", err) @@ -451,7 +452,7 @@ func (s *ServiceAccountsStoreImpl) RevertApiKey(ctx context.Context, keyId int64 } err = s.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error { - user := models.User{} + user := user.User{} has, err := sess.Where(`org_id = ? and id = ? and is_service_account = ?`, key.OrgId, *key.ServiceAccountId, s.sqlStore.Dialect.BooleanStr(true)).Get(&user) if err != nil { diff --git a/pkg/services/serviceaccounts/database/database_test.go b/pkg/services/serviceaccounts/database/database_test.go index 0742f0fd3a2..cb50a593196 100644 --- a/pkg/services/serviceaccounts/database/database_test.go +++ b/pkg/services/serviceaccounts/database/database_test.go @@ -59,7 +59,7 @@ func TestStore_DeleteServiceAccount(t *testing.T) { t.Run(c.desc, func(t *testing.T) { db, store := setupTestDatabase(t) user := tests.SetupUserServiceAccount(t, db, c.user) - err := store.DeleteServiceAccount(context.Background(), user.OrgId, user.Id) + err := store.DeleteServiceAccount(context.Background(), user.OrgID, user.ID) if c.expectedErr != nil { require.ErrorIs(t, err, c.expectedErr) } else { @@ -98,7 +98,7 @@ func TestStore_RetrieveServiceAccount(t *testing.T) { t.Run(c.desc, func(t *testing.T) { db, store := setupTestDatabase(t) user := tests.SetupUserServiceAccount(t, db, c.user) - dto, err := store.RetrieveServiceAccount(context.Background(), user.OrgId, user.Id) + dto, err := store.RetrieveServiceAccount(context.Background(), user.OrgID, user.ID) if c.expectedErr != nil { require.ErrorIs(t, err, c.expectedErr) } else { diff --git a/pkg/services/serviceaccounts/database/stats_test.go b/pkg/services/serviceaccounts/database/stats_test.go index 55405509c4b..5c658b4354a 100644 --- a/pkg/services/serviceaccounts/database/stats_test.go +++ b/pkg/services/serviceaccounts/database/stats_test.go @@ -18,18 +18,18 @@ func TestStore_UsageStats(t *testing.T) { sa := tests.SetupUserServiceAccount(t, db, saToCreate) keyName := t.Name() - key, err := apikeygen.New(sa.OrgId, keyName) + key, err := apikeygen.New(sa.OrgID, keyName) require.NoError(t, err) cmd := serviceaccounts.AddServiceAccountTokenCommand{ Name: keyName, - OrgId: sa.OrgId, + OrgId: sa.OrgID, Key: key.HashedKey, SecondsToLive: 0, Result: &models.ApiKey{}, } - err = store.AddServiceAccountToken(context.Background(), sa.Id, &cmd) + err = store.AddServiceAccountToken(context.Background(), sa.ID, &cmd) require.NoError(t, err) stats, err := store.GetUsageMetrics(context.Background()) diff --git a/pkg/services/serviceaccounts/database/token_store_test.go b/pkg/services/serviceaccounts/database/token_store_test.go index 85f9a316f6c..0976b7b658d 100644 --- a/pkg/services/serviceaccounts/database/token_store_test.go +++ b/pkg/services/serviceaccounts/database/token_store_test.go @@ -26,18 +26,18 @@ func TestStore_AddServiceAccountToken(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { keyName := t.Name() - key, err := apikeygen.New(user.OrgId, keyName) + key, err := apikeygen.New(user.OrgID, keyName) require.NoError(t, err) cmd := serviceaccounts.AddServiceAccountTokenCommand{ Name: keyName, - OrgId: user.OrgId, + OrgId: user.OrgID, Key: key.HashedKey, SecondsToLive: tc.secondsToLive, Result: &models.ApiKey{}, } - err = store.AddServiceAccountToken(context.Background(), user.Id, &cmd) + err = store.AddServiceAccountToken(context.Background(), user.ID, &cmd) if tc.secondsToLive < 0 { require.Error(t, err) return @@ -48,7 +48,7 @@ func TestStore_AddServiceAccountToken(t *testing.T) { require.Equal(t, t.Name(), newKey.Name) // Verify against DB - keys, errT := store.ListTokens(context.Background(), user.OrgId, user.Id) + keys, errT := store.ListTokens(context.Background(), user.OrgID, user.ID) require.NoError(t, errT) @@ -76,18 +76,18 @@ func TestStore_AddServiceAccountToken_WrongServiceAccount(t *testing.T) { sa := tests.SetupUserServiceAccount(t, db, saToCreate) keyName := t.Name() - key, err := apikeygen.New(sa.OrgId, keyName) + key, err := apikeygen.New(sa.OrgID, keyName) require.NoError(t, err) cmd := serviceaccounts.AddServiceAccountTokenCommand{ Name: keyName, - OrgId: sa.OrgId, + OrgId: sa.OrgID, Key: key.HashedKey, SecondsToLive: 0, Result: &models.ApiKey{}, } - err = store.AddServiceAccountToken(context.Background(), sa.Id+1, &cmd) + err = store.AddServiceAccountToken(context.Background(), sa.ID+1, &cmd) require.Error(t, err, "It should not be possible to add token to non-existing service account") } @@ -97,34 +97,34 @@ func TestStore_DeleteServiceAccountToken(t *testing.T) { sa := tests.SetupUserServiceAccount(t, db, userToCreate) keyName := t.Name() - key, err := apikeygen.New(sa.OrgId, keyName) + key, err := apikeygen.New(sa.OrgID, keyName) require.NoError(t, err) cmd := serviceaccounts.AddServiceAccountTokenCommand{ Name: keyName, - OrgId: sa.OrgId, + OrgId: sa.OrgID, Key: key.HashedKey, SecondsToLive: 0, Result: &models.ApiKey{}, } - err = store.AddServiceAccountToken(context.Background(), sa.Id, &cmd) + err = store.AddServiceAccountToken(context.Background(), sa.ID, &cmd) require.NoError(t, err) newKey := cmd.Result // Delete key from wrong service account - err = store.DeleteServiceAccountToken(context.Background(), sa.OrgId, sa.Id+2, newKey.Id) + err = store.DeleteServiceAccountToken(context.Background(), sa.OrgID, sa.ID+2, newKey.Id) require.Error(t, err) // Delete key from wrong org - err = store.DeleteServiceAccountToken(context.Background(), sa.OrgId+2, sa.Id, newKey.Id) + err = store.DeleteServiceAccountToken(context.Background(), sa.OrgID+2, sa.ID, newKey.Id) require.Error(t, err) - err = store.DeleteServiceAccountToken(context.Background(), sa.OrgId, sa.Id, newKey.Id) + err = store.DeleteServiceAccountToken(context.Background(), sa.OrgID, sa.ID, newKey.Id) require.NoError(t, err) // Verify against DB - keys, errT := store.ListTokens(context.Background(), sa.OrgId, sa.Id) + keys, errT := store.ListTokens(context.Background(), sa.OrgID, sa.ID) require.NoError(t, errT) for _, k := range keys { diff --git a/pkg/services/serviceaccounts/tests/common.go b/pkg/services/serviceaccounts/tests/common.go index 11e8b27cf54..a697d64fbe5 100644 --- a/pkg/services/serviceaccounts/tests/common.go +++ b/pkg/services/serviceaccounts/tests/common.go @@ -9,6 +9,7 @@ import ( accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/require" ) @@ -27,13 +28,13 @@ type TestApiKey struct { IsExpired bool } -func SetupUserServiceAccount(t *testing.T, sqlStore *sqlstore.SQLStore, testUser TestUser) *models.User { +func SetupUserServiceAccount(t *testing.T, sqlStore *sqlstore.SQLStore, testUser TestUser) *user.User { role := string(models.ROLE_VIEWER) if testUser.Role != "" { role = testUser.Role } - u1, err := sqlStore.CreateUser(context.Background(), models.CreateUserCommand{ + u1, err := sqlStore.CreateUser(context.Background(), user.CreateUserCommand{ Login: testUser.Login, IsServiceAccount: testUser.IsServiceAccount, DefaultOrgRole: role, diff --git a/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go b/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go index 389a63216a1..0afc150d334 100644 --- a/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go +++ b/pkg/services/sqlstore/migrations/accesscontrol/test/ac_test.go @@ -15,7 +15,9 @@ import ( acmig "github.com/grafana/grafana/pkg/services/sqlstore/migrations/accesscontrol" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -38,49 +40,49 @@ func (rp *rawPermission) toPermission(roleID int64, ts time.Time) accesscontrol. var ( now = time.Now() - users = []models.User{ + users = []user.User{ { - Id: 1, + ID: 1, Email: "viewer1@example.org", Name: "viewer1", Login: "viewer1", - OrgId: 1, + OrgID: 1, Created: now, Updated: now, }, { - Id: 2, + ID: 2, Email: "viewer2@example.org", Name: "viewer2", Login: "viewer2", - OrgId: 1, + OrgID: 1, Created: now, Updated: now, }, { - Id: 3, + ID: 3, Email: "editor1@example.org", Name: "editor1", Login: "editor1", - OrgId: 1, + OrgID: 1, Created: now, Updated: now, }, { - Id: 4, + ID: 4, Email: "admin1@example.org", Name: "admin1", Login: "admin1", - OrgId: 1, + OrgID: 1, Created: now, Updated: now, }, { - Id: 5, + ID: 5, Email: "editor2@example.org", Name: "editor2", Login: "editor2", - OrgId: 2, + OrgID: 2, Created: now, Updated: now, }, @@ -213,9 +215,9 @@ func TestMigrations(t *testing.T) { for _, user := range users { // Check managed roles exist - roleName := fmt.Sprintf("managed:users:%d:permissions", user.Id) + roleName := fmt.Sprintf("managed:users:%d:permissions", user.ID) role := accesscontrol.Role{} - hasRole, errManagedRoleSearch := x.Table("role").Where("org_id = ? AND name = ?", user.OrgId, roleName).Get(&role) + hasRole, errManagedRoleSearch := x.Table("role").Where("org_id = ? AND name = ?", user.OrgID, roleName).Get(&role) require.NoError(t, errManagedRoleSearch) assert.True(t, hasRole, "expected role to be granted to user", user, roleName) @@ -234,7 +236,7 @@ func TestMigrations(t *testing.T) { // Check assignment of the roles assign := accesscontrol.UserRole{} - has, errAssignmentSearch := x.Table("user_role").Where("role_id = ? AND user_id = ?", role.ID, user.Id).Get(&assign) + has, errAssignmentSearch := x.Table("user_role").Where("role_id = ? AND user_id = ?", role.ID, user.ID).Get(&assign) require.NoError(t, errAssignmentSearch) assert.True(t, has, "expected assignment of role to user", role, user) } diff --git a/pkg/services/sqlstore/mockstore/mockstore.go b/pkg/services/sqlstore/mockstore/mockstore.go index 745a25a12db..55f8b1e7668 100644 --- a/pkg/services/sqlstore/mockstore/mockstore.go +++ b/pkg/services/sqlstore/mockstore/mockstore.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "github.com/grafana/grafana/pkg/services/user" ) type OrgListResponse []struct { @@ -18,7 +19,7 @@ type SQLStoreMock struct { LastLoginAttemptCommand *models.CreateLoginAttemptCommand LatestUserId int64 - ExpectedUser *models.User + ExpectedUser *user.User ExpectedDatasource *datasources.DataSource ExpectedAlert *models.Alert ExpectedPluginSetting *models.PluginSetting @@ -132,7 +133,7 @@ func (m *SQLStoreMock) DeleteOldLoginAttempts(ctx context.Context, cmd *models.D return m.ExpectedError } -func (m *SQLStoreMock) CreateUser(ctx context.Context, cmd models.CreateUserCommand) (*models.User, error) { +func (m *SQLStoreMock) CreateUser(ctx context.Context, cmd user.CreateUserCommand) (*user.User, error) { return nil, m.ExpectedError } diff --git a/pkg/services/sqlstore/org_test.go b/pkg/services/sqlstore/org_test.go index f4360d06bbc..93986114e7b 100644 --- a/pkg/services/sqlstore/org_test.go +++ b/pkg/services/sqlstore/org_test.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" ) @@ -86,16 +87,16 @@ func TestIntegrationAccountDataAccess(t *testing.T) { sqlStore.Cfg.AutoAssignOrgRole = "Viewer" t.Run("Users should be added to default organization", func(t *testing.T) { - ac1cmd := models.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} - ac2cmd := models.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 := 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} + 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) @@ -112,18 +113,18 @@ func TestIntegrationAccountDataAccess(t *testing.T) { sqlStore.Cfg.AutoAssignOrgId = 1 sqlStore.Cfg.AutoAssignOrgRole = "Viewer" - ac1cmd := models.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} - ac2cmd := models.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 := sqlStore.CreateUser(context.Background(), ac1cmd) - testUser.OrgId = ac1.OrgId + testUser.OrgId = ac1.OrgID require.NoError(t, err) _, err = sqlStore.CreateUser(context.Background(), ac2cmd) require.NoError(t, err) t.Run("Can get organization users paginated with query", func(t *testing.T) { query := models.SearchOrgUsersQuery{ - OrgID: ac1.OrgId, + OrgID: ac1.OrgID, Page: 1, User: testUser, } @@ -135,7 +136,7 @@ func TestIntegrationAccountDataAccess(t *testing.T) { t.Run("Can get organization users paginated and limited", func(t *testing.T) { query := models.SearchOrgUsersQuery{ - OrgID: ac1.OrgId, + OrgID: ac1.OrgID, Limit: 1, Page: 1, User: testUser, @@ -151,9 +152,9 @@ func TestIntegrationAccountDataAccess(t *testing.T) { sqlStore = InitTestDB(t) sqlStore.Cfg.AutoAssignOrg = false - ac1cmd := models.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"} - ac2cmd := models.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true} - serviceaccountcmd := models.CreateUserCommand{Login: "serviceaccount", Email: "service@test.com", Name: "serviceaccount name", IsAdmin: true, IsServiceAccount: true} + 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) @@ -164,7 +165,7 @@ func TestIntegrationAccountDataAccess(t *testing.T) { require.NoError(t, err) t.Run("Should be able to read user info projection", func(t *testing.T) { - query := models.GetUserProfileQuery{UserId: ac1.Id} + query := models.GetUserProfileQuery{UserId: ac1.ID} err = sqlStore.GetUserProfile(context.Background(), &query) require.NoError(t, err) @@ -189,8 +190,8 @@ func TestIntegrationAccountDataAccess(t *testing.T) { t.Run("Given an added org user", func(t *testing.T) { cmd := models.AddOrgUserCommand{ - OrgId: ac1.OrgId, - UserId: ac2.Id, + OrgId: ac1.OrgID, + UserId: ac2.ID, Role: models.ROLE_VIEWER, } @@ -200,15 +201,15 @@ func TestIntegrationAccountDataAccess(t *testing.T) { }) t.Run("Can update org user role", func(t *testing.T) { - updateCmd := models.UpdateOrgUserCommand{OrgId: ac1.OrgId, UserId: ac2.Id, Role: models.ROLE_ADMIN} + updateCmd := models.UpdateOrgUserCommand{OrgId: ac1.OrgID, UserId: ac2.ID, Role: models.ROLE_ADMIN} err = sqlStore.UpdateOrgUser(context.Background(), &updateCmd) require.NoError(t, err) orgUsersQuery := models.GetOrgUsersQuery{ - OrgId: ac1.OrgId, + OrgId: ac1.OrgID, User: &models.SignedInUser{ - OrgId: ac1.OrgId, - Permissions: map[int64]map[string][]string{ac1.OrgId: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, + OrgId: ac1.OrgID, + Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, }, } err = sqlStore.GetOrgUsers(context.Background(), &orgUsersQuery) @@ -218,12 +219,12 @@ func TestIntegrationAccountDataAccess(t *testing.T) { }) t.Run("Can get logged in user projection", func(t *testing.T) { - query := models.GetSignedInUserQuery{UserId: ac2.Id} + query := models.GetSignedInUserQuery{UserId: ac2.ID} err := sqlStore.GetSignedInUser(context.Background(), &query) require.NoError(t, err) require.Equal(t, query.Result.Email, "ac2@test.com") - require.Equal(t, query.Result.OrgId, ac2.OrgId) + require.Equal(t, query.Result.OrgId, ac2.OrgID) require.Equal(t, query.Result.Name, "ac2 name") require.Equal(t, query.Result.Login, "ac2") require.EqualValues(t, query.Result.OrgRole, "Admin") @@ -232,7 +233,7 @@ func TestIntegrationAccountDataAccess(t *testing.T) { }) t.Run("Can get user organizations", func(t *testing.T) { - query := models.GetUserOrgListQuery{UserId: ac2.Id} + query := models.GetUserOrgListQuery{UserId: ac2.ID} err := sqlStore.GetUserOrgList(context.Background(), &query) require.NoError(t, err) @@ -241,10 +242,10 @@ func TestIntegrationAccountDataAccess(t *testing.T) { t.Run("Can get organization users", func(t *testing.T) { query := models.GetOrgUsersQuery{ - OrgId: ac1.OrgId, + OrgId: ac1.OrgID, User: &models.SignedInUser{ - OrgId: ac1.OrgId, - Permissions: map[int64]map[string][]string{ac1.OrgId: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, + OrgId: ac1.OrgID, + Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, }, } err := sqlStore.GetOrgUsers(context.Background(), &query) @@ -256,11 +257,11 @@ func TestIntegrationAccountDataAccess(t *testing.T) { t.Run("Can get organization users with query", func(t *testing.T) { query := models.GetOrgUsersQuery{ - OrgId: ac1.OrgId, + OrgId: ac1.OrgID, Query: "ac1", User: &models.SignedInUser{ - OrgId: ac1.OrgId, - Permissions: map[int64]map[string][]string{ac1.OrgId: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, + OrgId: ac1.OrgID, + Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, }, } err := sqlStore.GetOrgUsers(context.Background(), &query) @@ -272,12 +273,12 @@ func TestIntegrationAccountDataAccess(t *testing.T) { t.Run("Can get organization users with query and limit", func(t *testing.T) { query := models.GetOrgUsersQuery{ - OrgId: ac1.OrgId, + OrgId: ac1.OrgID, Query: "ac", Limit: 1, User: &models.SignedInUser{ - OrgId: ac1.OrgId, - Permissions: map[int64]map[string][]string{ac1.OrgId: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, + OrgId: ac1.OrgID, + Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, }, } err := sqlStore.GetOrgUsers(context.Background(), &query) @@ -288,16 +289,16 @@ func TestIntegrationAccountDataAccess(t *testing.T) { }) t.Run("Can set using org", func(t *testing.T) { - cmd := models.SetUsingOrgCommand{UserId: ac2.Id, OrgId: ac1.OrgId} + cmd := models.SetUsingOrgCommand{UserId: ac2.ID, OrgId: ac1.OrgID} err := sqlStore.SetUsingOrg(context.Background(), &cmd) require.NoError(t, err) t.Run("SignedInUserQuery with a different org", func(t *testing.T) { - query := models.GetSignedInUserQuery{UserId: ac2.Id} + query := models.GetSignedInUserQuery{UserId: ac2.ID} err := sqlStore.GetSignedInUser(context.Background(), &query) require.NoError(t, err) - require.Equal(t, query.Result.OrgId, ac1.OrgId) + require.Equal(t, query.Result.OrgId, ac1.OrgID) require.Equal(t, query.Result.Email, "ac2@test.com") require.Equal(t, query.Result.Name, "ac2 name") require.Equal(t, query.Result.Login, "ac2") @@ -305,53 +306,53 @@ func TestIntegrationAccountDataAccess(t *testing.T) { }) t.Run("Should set last org as current when removing user from current", func(t *testing.T) { - remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac2.Id} + remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgID, UserId: ac2.ID} err := sqlStore.RemoveOrgUser(context.Background(), &remCmd) require.NoError(t, err) - query := models.GetSignedInUserQuery{UserId: ac2.Id} + query := models.GetSignedInUserQuery{UserId: ac2.ID} err = sqlStore.GetSignedInUser(context.Background(), &query) require.NoError(t, err) - require.Equal(t, query.Result.OrgId, ac2.OrgId) + require.Equal(t, query.Result.OrgId, ac2.OrgID) }) }) t.Run("Removing user from org should delete user completely if in no other org", func(t *testing.T) { // make sure ac2 has no org - err := sqlStore.DeleteOrg(context.Background(), &models.DeleteOrgCommand{Id: ac2.OrgId}) + err := sqlStore.DeleteOrg(context.Background(), &models.DeleteOrgCommand{Id: ac2.OrgID}) require.NoError(t, err) // remove ac2 user from ac1 org - remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac2.Id, ShouldDeleteOrphanedUser: true} + remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgID, UserId: ac2.ID, ShouldDeleteOrphanedUser: true} err = sqlStore.RemoveOrgUser(context.Background(), &remCmd) require.NoError(t, err) require.True(t, remCmd.UserWasDeleted) - err = sqlStore.GetSignedInUser(context.Background(), &models.GetSignedInUserQuery{UserId: ac2.Id}) + err = sqlStore.GetSignedInUser(context.Background(), &models.GetSignedInUserQuery{UserId: ac2.ID}) require.Equal(t, err, models.ErrUserNotFound) }) t.Run("Cannot delete last admin org user", func(t *testing.T) { - cmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac1.Id} + cmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgID, UserId: ac1.ID} err := sqlStore.RemoveOrgUser(context.Background(), &cmd) require.Equal(t, err, models.ErrLastOrgAdmin) }) t.Run("Cannot update role so no one is admin user", func(t *testing.T) { - cmd := models.UpdateOrgUserCommand{OrgId: ac1.OrgId, UserId: ac1.Id, Role: models.ROLE_VIEWER} + cmd := models.UpdateOrgUserCommand{OrgId: ac1.OrgID, UserId: ac1.ID, Role: models.ROLE_VIEWER} err := sqlStore.UpdateOrgUser(context.Background(), &cmd) require.Equal(t, err, models.ErrLastOrgAdmin) }) t.Run("Given an org user with dashboard permissions", func(t *testing.T) { - ac3cmd := models.CreateUserCommand{Login: "ac3", Email: "ac3@test.com", Name: "ac3 name", IsAdmin: false} + 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, + OrgId: ac1.OrgID, + UserId: ac3.ID, Role: models.ROLE_VIEWER, } @@ -359,36 +360,36 @@ func TestIntegrationAccountDataAccess(t *testing.T) { require.NoError(t, err) query := models.GetOrgUsersQuery{ - OrgId: ac1.OrgId, + OrgId: ac1.OrgID, User: &models.SignedInUser{ - OrgId: ac1.OrgId, - Permissions: map[int64]map[string][]string{ac1.OrgId: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, + OrgId: ac1.OrgID, + Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, }, } err = sqlStore.GetOrgUsers(context.Background(), &query) require.NoError(t, err) // require.Equal(t, len(query.Result), 3) - 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") + 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, + 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, + DashboardID: dash2.Id, OrgID: ac3.OrgID, UserID: ac3.ID, Permission: models.PERMISSION_EDIT, }) require.NoError(t, err) t.Run("When org user is deleted", func(t *testing.T) { - cmdRemove := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac3.Id} + cmdRemove := models.RemoveOrgUserCommand{OrgId: ac1.OrgID, UserId: ac3.ID} err := sqlStore.RemoveOrgUser(context.Background(), &cmdRemove) require.NoError(t, err) t.Run("Should remove dependent permissions for deleted org user", func(t *testing.T) { - permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash1.Id, OrgID: ac1.OrgId} + permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash1.Id, OrgID: ac1.OrgID} err = getDashboardAclInfoList(sqlStore, permQuery) require.NoError(t, err) @@ -397,14 +398,14 @@ func TestIntegrationAccountDataAccess(t *testing.T) { }) t.Run("Should not remove dashboard permissions for same user in another org", func(t *testing.T) { - permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash2.Id, OrgID: ac3.OrgId} + permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash2.Id, OrgID: ac3.OrgID} err = getDashboardAclInfoList(sqlStore, permQuery) require.NoError(t, err) require.Equal(t, len(permQuery.Result), 1) - require.Equal(t, permQuery.Result[0].OrgId, ac3.OrgId) - require.Equal(t, permQuery.Result[0].UserId, ac3.Id) + require.Equal(t, permQuery.Result[0].OrgId, ac3.OrgID) + require.Equal(t, permQuery.Result[0].UserId, ac3.ID) }) }) }) diff --git a/pkg/services/sqlstore/org_users.go b/pkg/services/sqlstore/org_users.go index 1afea95b156..c7d2c0df7a3 100644 --- a/pkg/services/sqlstore/org_users.go +++ b/pkg/services/sqlstore/org_users.go @@ -8,20 +8,21 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" ) func (ss *SQLStore) AddOrgUser(ctx context.Context, cmd *models.AddOrgUserCommand) error { return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { // check if user exists - var user models.User + var user user.User if exists, err := sess.ID(cmd.UserId).Where(notServiceAccountFilter(ss)).Get(&user); err != nil { return err } else if !exists { return models.ErrUserNotFound } - if res, err := sess.Query("SELECT 1 from org_user WHERE org_id=? and user_id=?", cmd.OrgId, user.Id); err != nil { + if res, err := sess.Query("SELECT 1 from org_user WHERE org_id=? and user_id=?", cmd.OrgId, user.ID); err != nil { return err } else if len(res) == 1 { return models.ErrOrgUserAlreadyAdded @@ -49,7 +50,7 @@ func (ss *SQLStore) AddOrgUser(ctx context.Context, cmd *models.AddOrgUserComman 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=?", user.Id, user.OrgId) + sess.Where("org_user.user_id=? AND org_user.org_id=?", user.ID, user.OrgID) sess.Cols("org.name", "org_user.role", "org_user.org_id") err = sess.Find(&userOrgs) @@ -58,7 +59,7 @@ func (ss *SQLStore) AddOrgUser(ctx context.Context, cmd *models.AddOrgUserComman } if len(userOrgs) == 0 { - return setUsingOrgInTransaction(sess, user.Id, cmd.OrgId) + return setUsingOrgInTransaction(sess, user.ID, cmd.OrgId) } return nil @@ -243,7 +244,7 @@ func (ss *SQLStore) SearchOrgUsers(ctx context.Context, query *models.SearchOrgU func (ss *SQLStore) RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error { return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { // check if user exists - var user models.User + var user user.User if exists, err := sess.ID(cmd.UserId).Where(notServiceAccountFilter(ss)).Get(&user); err != nil { return err } else if !exists { @@ -273,7 +274,7 @@ func (ss *SQLStore) RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUser var userOrgs []*models.UserOrgDTO sess.Table("org_user") sess.Join("INNER", "org", "org_user.org_id=org.id") - sess.Where("org_user.user_id=?", user.Id) + sess.Where("org_user.user_id=?", user.ID) sess.Cols("org.name", "org_user.role", "org_user.org_id") err := sess.Find(&userOrgs) @@ -284,28 +285,28 @@ func (ss *SQLStore) RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUser if len(userOrgs) > 0 { hasCurrentOrgSet := false for _, userOrg := range userOrgs { - if user.OrgId == userOrg.OrgId { + if user.OrgID == userOrg.OrgId { hasCurrentOrgSet = true break } } if !hasCurrentOrgSet { - err = setUsingOrgInTransaction(sess, user.Id, userOrgs[0].OrgId) + err = setUsingOrgInTransaction(sess, user.ID, userOrgs[0].OrgId) if err != nil { return err } } } else if cmd.ShouldDeleteOrphanedUser { // no other orgs, delete the full user - if err := deleteUserInTransaction(ss, sess, &models.DeleteUserCommand{UserId: user.Id}); err != nil { + if err := deleteUserInTransaction(ss, sess, &models.DeleteUserCommand{UserId: user.ID}); err != nil { return err } cmd.UserWasDeleted = true } else { // no orgs, but keep the user -> clean up orgId - err = removeUserOrg(sess, user.Id) + err = removeUserOrg(sess, user.ID) if err != nil { return err } diff --git a/pkg/services/sqlstore/org_users_test.go b/pkg/services/sqlstore/org_users_test.go index 07544990f04..c18a42eaa48 100644 --- a/pkg/services/sqlstore/org_users_test.go +++ b/pkg/services/sqlstore/org_users_test.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/models" ac "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/user" ) type getOrgUsersTestCase struct { @@ -151,16 +152,16 @@ func TestSQLStore_RemoveOrgUser(t *testing.T) { store := InitTestDB(t) // create org and admin - _, err := store.CreateUser(context.Background(), models.CreateUserCommand{ + _, err := store.CreateUser(context.Background(), user.CreateUserCommand{ Login: "admin", - OrgId: 1, + OrgID: 1, }) require.NoError(t, err) // create a user with no org - _, err = store.CreateUser(context.Background(), models.CreateUserCommand{ + _, err = store.CreateUser(context.Background(), user.CreateUserCommand{ Login: "user", - OrgId: 1, + OrgID: 1, SkipOrgSetup: true, }) require.NoError(t, err) @@ -177,7 +178,7 @@ func TestSQLStore_RemoveOrgUser(t *testing.T) { user := &models.GetUserByIdQuery{Id: 2} err = store.GetUserById(context.Background(), user) require.NoError(t, err) - require.Equal(t, user.Result.OrgId, int64(1)) + require.Equal(t, user.Result.OrgID, int64(1)) // remove the user org err = store.RemoveOrgUser(context.Background(), &models.RemoveOrgUserCommand{ @@ -191,16 +192,16 @@ func TestSQLStore_RemoveOrgUser(t *testing.T) { user = &models.GetUserByIdQuery{Id: 2} err = store.GetUserById(context.Background(), user) require.NoError(t, err) - require.Equal(t, user.Result.OrgId, int64(0)) + require.Equal(t, user.Result.OrgID, int64(0)) } func seedOrgUsers(t *testing.T, store *SQLStore, numUsers int) { t.Helper() // Seed users for i := 1; i <= numUsers; i++ { - user, err := store.CreateUser(context.Background(), models.CreateUserCommand{ + user, err := store.CreateUser(context.Background(), user.CreateUserCommand{ Login: fmt.Sprintf("user-%d", i), - OrgId: 1, + OrgID: 1, }) require.NoError(t, err) @@ -208,7 +209,7 @@ func seedOrgUsers(t *testing.T, store *SQLStore, numUsers int) { err = store.AddOrgUser(context.Background(), &models.AddOrgUserCommand{ Role: "Viewer", OrgId: 1, - UserId: user.Id, + UserId: user.ID, }) require.NoError(t, err) } diff --git a/pkg/services/sqlstore/session.go b/pkg/services/sqlstore/session.go index 556b936d4d1..4a8d27367eb 100644 --- a/pkg/services/sqlstore/session.go +++ b/pkg/services/sqlstore/session.go @@ -23,6 +23,10 @@ func (sess *DBSession) publishAfterCommit(msg interface{}) { sess.events = append(sess.events, msg) } +func (sess *DBSession) PublishAfterCommit(msg interface{}) { + sess.events = append(sess.events, msg) +} + // NewSession returns a new DBSession func (ss *SQLStore) NewSession(ctx context.Context) *DBSession { sess := &DBSession{Session: ss.engine.NewSession()} diff --git a/pkg/services/sqlstore/sqlbuilder_test.go b/pkg/services/sqlstore/sqlbuilder_test.go index 0da337cea16..926f275a8c1 100644 --- a/pkg/services/sqlstore/sqlbuilder_test.go +++ b/pkg/services/sqlstore/sqlbuilder_test.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -190,11 +191,11 @@ func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *Dash }) } -func createDummyUser(t *testing.T, sqlStore *SQLStore) *models.User { +func createDummyUser(t *testing.T, sqlStore *SQLStore) *user.User { t.Helper() uid := strconv.Itoa(rand.Intn(9999999)) - createUserCmd := models.CreateUserCommand{ + createUserCmd := user.CreateUserCommand{ Email: uid + "@example.com", Login: uid, Name: uid, @@ -262,12 +263,12 @@ func createDummyACL(t *testing.T, sqlStore *SQLStore, dashboardPermission *Dashb DashboardID: dashboardID, } - var user *models.User + var user *user.User if dashboardPermission.User { t.Logf("Creating user") user = createDummyUser(t, sqlStore) - acl.UserID = user.Id + acl.UserID = user.ID } if dashboardPermission.Team { @@ -275,9 +276,9 @@ func createDummyACL(t *testing.T, sqlStore *SQLStore, dashboardPermission *Dashb team := createDummyTeam(t, sqlStore) if search.UserFromACL { user = createDummyUser(t, sqlStore) - err := sqlStore.AddTeamMember(user.Id, 1, team.Id, false, 0) + err := sqlStore.AddTeamMember(user.ID, 1, team.Id, false, 0) require.NoError(t, err) - t.Logf("Created team member with ID %d", user.Id) + t.Logf("Created team member with ID %d", user.ID) } acl.TeamID = team.Id @@ -290,7 +291,7 @@ func createDummyACL(t *testing.T, sqlStore *SQLStore, dashboardPermission *Dashb err := updateDashboardAcl(t, sqlStore, dashboardID, acl) require.NoError(t, err) if user != nil { - return user.Id + return user.ID } return 0 } diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index 5ace2089398..ee6c4a24c5f 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -27,6 +27,7 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore/migrations" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -180,7 +181,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, models.CreateUserCommand{ + if _, err := ss.createUser(ctx, sess, user.CreateUserCommand{ Login: ss.Cfg.AdminUser, Email: ss.Cfg.AdminUser + "@localhost", Password: ss.Cfg.AdminPassword, diff --git a/pkg/services/sqlstore/stats_test.go b/pkg/services/sqlstore/stats_test.go index 0fa194e01bc..36a161bdf7d 100644 --- a/pkg/services/sqlstore/stats_test.go +++ b/pkg/services/sqlstore/stats_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -64,9 +65,9 @@ func TestIntegrationStatsDataAccess(t *testing.T) { func populateDB(t *testing.T, sqlStore *SQLStore) { t.Helper() - users := make([]models.User, 3) + users := make([]user.User, 3) for i := range users { - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: fmt.Sprintf("usertest%v@test.com", i), Name: fmt.Sprintf("user name %v", i), Login: fmt.Sprintf("user_test_%v_login", i), @@ -78,7 +79,7 @@ func populateDB(t *testing.T, sqlStore *SQLStore) { } // get 1st user's organisation - getOrgByIdQuery := &models.GetOrgByIdQuery{Id: users[0].OrgId} + getOrgByIdQuery := &models.GetOrgByIdQuery{Id: users[0].OrgID} err := sqlStore.GetOrgById(context.Background(), getOrgByIdQuery) require.NoError(t, err) org := getOrgByIdQuery.Result @@ -86,7 +87,7 @@ func populateDB(t *testing.T, sqlStore *SQLStore) { // add 2nd user as editor cmd := &models.AddOrgUserCommand{ OrgId: org.Id, - UserId: users[1].Id, + UserId: users[1].ID, Role: models.ROLE_EDITOR, } err = sqlStore.AddOrgUser(context.Background(), cmd) @@ -95,14 +96,14 @@ func populateDB(t *testing.T, sqlStore *SQLStore) { // add 3rd user as viewer cmd = &models.AddOrgUserCommand{ OrgId: org.Id, - UserId: users[2].Id, + UserId: users[2].ID, Role: models.ROLE_VIEWER, } err = sqlStore.AddOrgUser(context.Background(), cmd) require.NoError(t, err) // get 2nd user's organisation - getOrgByIdQuery = &models.GetOrgByIdQuery{Id: users[1].OrgId} + getOrgByIdQuery = &models.GetOrgByIdQuery{Id: users[1].OrgID} err = sqlStore.GetOrgById(context.Background(), getOrgByIdQuery) require.NoError(t, err) org = getOrgByIdQuery.Result @@ -110,7 +111,7 @@ func populateDB(t *testing.T, sqlStore *SQLStore) { // add 1st user as admin cmd = &models.AddOrgUserCommand{ OrgId: org.Id, - UserId: users[0].Id, + UserId: users[0].ID, Role: models.ROLE_ADMIN, } err = sqlStore.AddOrgUser(context.Background(), cmd) @@ -118,7 +119,7 @@ func populateDB(t *testing.T, sqlStore *SQLStore) { // update 1st user last seen at updateUserLastSeenAtCmd := &models.UpdateUserLastSeenAtCommand{ - UserId: users[0].Id, + UserId: users[0].ID, } err = sqlStore.UpdateUserLastSeenAt(context.Background(), updateUserLastSeenAtCmd) require.NoError(t, err) diff --git a/pkg/services/sqlstore/store.go b/pkg/services/sqlstore/store.go index f39cfe4d33a..1dedae4f695 100644 --- a/pkg/services/sqlstore/store.go +++ b/pkg/services/sqlstore/store.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "github.com/grafana/grafana/pkg/services/user" ) type Store interface { @@ -26,7 +27,7 @@ type Store interface { CreateLoginAttempt(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error GetUserLoginAttemptCount(ctx context.Context, query *models.GetUserLoginAttemptCountQuery) error DeleteOldLoginAttempts(ctx context.Context, cmd *models.DeleteOldLoginAttemptsCommand) error - CreateUser(ctx context.Context, cmd models.CreateUserCommand) (*models.User, error) + CreateUser(ctx context.Context, cmd user.CreateUserCommand) (*user.User, error) GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error GetUserByLogin(ctx context.Context, query *models.GetUserByLoginQuery) error GetUserByEmail(ctx context.Context, query *models.GetUserByEmailQuery) error diff --git a/pkg/services/sqlstore/team_test.go b/pkg/services/sqlstore/team_test.go index aff06437b73..845b0fddf3d 100644 --- a/pkg/services/sqlstore/team_test.go +++ b/pkg/services/sqlstore/team_test.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/models" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/serviceaccounts" + "github.com/grafana/grafana/pkg/services/user" ) func TestIntegrationTeamCommandsAndQueries(t *testing.T) { @@ -34,20 +35,20 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { var userIds []int64 const testOrgID int64 = 1 var team1, team2 models.Team - var user *models.User - var userCmd models.CreateUserCommand + var usr *user.User + var userCmd user.CreateUserCommand var err error setup := func() { for i := 0; i < 5; i++ { - userCmd = models.CreateUserCommand{ + userCmd = user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), } - user, err = sqlStore.CreateUser(context.Background(), userCmd) + usr, err = sqlStore.CreateUser(context.Background(), userCmd) require.NoError(t, err) - userIds = append(userIds, user.Id) + userIds = append(userIds, usr.ID) } team1, err = sqlStore.CreateTeam("group1 name", "test1@test.com", testOrgID) require.NoError(t, err) @@ -375,7 +376,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { t.Run("Should be able to exclude service accounts from teamembers", func(t *testing.T) { sqlStore = InitTestDB(t) setup() - userCmd = models.CreateUserCommand{ + userCmd = user.CreateUserCommand{ Email: fmt.Sprint("sa", 1, "@test.com"), Name: fmt.Sprint("sa", 1), Login: fmt.Sprint("login-sa", 1), @@ -386,7 +387,7 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) { groupId := team2.Id // add service account to team - err = sqlStore.AddTeamMember(serviceAccount.Id, testOrgID, groupId, false, 0) + err = sqlStore.AddTeamMember(serviceAccount.ID, testOrgID, groupId, false, 0) require.NoError(t, err) // add user to team @@ -498,14 +499,14 @@ func TestIntegrationSQLStore_GetTeamMembers_ACFilter(t *testing.T) { require.NoError(t, errCreateTeam) for i := 0; i < 4; i++ { - userCmd := models.CreateUserCommand{ + userCmd := user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@example.org"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), } user, errCreateUser := store.CreateUser(context.Background(), userCmd) require.NoError(t, errCreateUser) - userIds[i] = user.Id + userIds[i] = user.ID } errAddMember := store.AddTeamMember(userIds[0], testOrgID, team1.Id, false, 0) diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go index e0071f12d23..ecca42cffaf 100644 --- a/pkg/services/sqlstore/user.go +++ b/pkg/services/sqlstore/user.go @@ -11,11 +11,12 @@ import ( "github.com/grafana/grafana/pkg/events" "github.com/grafana/grafana/pkg/models" ac "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" ) type ErrCaseInsensitiveLoginConflict struct { - users []models.User + users []user.User } func (e *ErrCaseInsensitiveLoginConflict) Unwrap() error { @@ -27,7 +28,7 @@ func (e *ErrCaseInsensitiveLoginConflict) Error() string { userStrings := make([]string, 0, n) for _, v := range e.users { - userStrings = append(userStrings, fmt.Sprintf("%s (email:%s, id:%d)", v.Login, v.Email, v.Id)) + userStrings = append(userStrings, fmt.Sprintf("%s (email:%s, id:%d)", v.Login, v.Email, v.ID)) } return fmt.Sprintf( @@ -35,12 +36,12 @@ func (e *ErrCaseInsensitiveLoginConflict) Error() string { n, strings.Join(userStrings, ", ")) } -func (ss *SQLStore) getOrgIDForNewUser(sess *DBSession, args models.CreateUserCommand) (int64, error) { - if ss.Cfg.AutoAssignOrg && args.OrgId != 0 { - if err := verifyExistingOrg(sess, args.OrgId); err != nil { +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 { return -1, err } - return args.OrgId, nil + return args.OrgID, nil } orgName := args.OrgName @@ -52,7 +53,7 @@ func (ss *SQLStore) getOrgIDForNewUser(sess *DBSession, args models.CreateUserCo } func (ss *SQLStore) userCaseInsensitiveLoginConflict(ctx context.Context, sess *DBSession, login, email string) error { - users := make([]models.User, 0) + users := make([]user.User, 0) if err := sess.Where("LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)", email, login).Find(&users); err != nil { @@ -67,14 +68,14 @@ func (ss *SQLStore) userCaseInsensitiveLoginConflict(ctx context.Context, sess * } // createUser creates a user in the database -func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args models.CreateUserCommand) (models.User, error) { - var user models.User +func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args user.CreateUserCommand) (user.User, error) { + var usr user.User var orgID int64 = -1 if !args.SkipOrgSetup { var err error orgID, err = ss.getOrgIDForNewUser(sess, args) if err != nil { - return user, err + return usr, err } } @@ -89,23 +90,23 @@ func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args models args.Email = strings.ToLower(args.Email) } - exists, err := sess.Where(where, args.Email, args.Login).Get(&models.User{}) + exists, err := sess.Where(where, args.Email, args.Login).Get(&user.User{}) if err != nil { - return user, err + return usr, err } if exists { - return user, models.ErrUserAlreadyExists + return usr, models.ErrUserAlreadyExists } // create user - user = models.User{ + usr = user.User{ Email: args.Email, Name: args.Name, Login: args.Login, Company: args.Company, IsAdmin: args.IsAdmin, IsDisabled: args.IsDisabled, - OrgId: orgID, + OrgID: orgID, EmailVerified: args.EmailVerified, Created: time.Now(), Updated: time.Now(), @@ -115,48 +116,48 @@ func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args models salt, err := util.GetRandomString(10) if err != nil { - return user, err + return usr, err } - user.Salt = salt + usr.Salt = salt rands, err := util.GetRandomString(10) if err != nil { - return user, err + return usr, err } - user.Rands = rands + usr.Rands = rands if len(args.Password) > 0 { - encodedPassword, err := util.EncodePassword(args.Password, user.Salt) + encodedPassword, err := util.EncodePassword(args.Password, usr.Salt) if err != nil { - return user, err + return usr, err } - user.Password = encodedPassword + usr.Password = encodedPassword } sess.UseBool("is_admin") - if _, err := sess.Insert(&user); err != nil { - return user, err + if _, err := sess.Insert(&usr); err != nil { + return usr, err } sess.publishAfterCommit(&events.UserCreated{ - Timestamp: user.Created, - Id: user.Id, - Name: user.Name, - Login: user.Login, - Email: user.Email, + Timestamp: usr.Created, + Id: usr.ID, + Name: usr.Name, + Login: usr.Login, + Email: usr.Email, }) // create org user link if !args.SkipOrgSetup { orgUser := models.OrgUser{ OrgId: orgID, - UserId: user.Id, + UserId: usr.ID, Role: models.ROLE_ADMIN, Created: time.Now(), Updated: time.Now(), } - if ss.Cfg.AutoAssignOrg && !user.IsAdmin { + if ss.Cfg.AutoAssignOrg && !usr.IsAdmin { if len(args.DefaultOrgRole) > 0 { orgUser.Role = models.RoleType(args.DefaultOrgRole) } else { @@ -165,15 +166,16 @@ func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args models } if _, err = sess.Insert(&orgUser); err != nil { - return user, err + return usr, err } } - return user, nil + return usr, nil } -func (ss *SQLStore) CreateUser(ctx context.Context, cmd models.CreateUserCommand) (*models.User, error) { - var user models.User +// 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 @@ -189,7 +191,7 @@ func notServiceAccountFilter(ss *SQLStore) string { func (ss *SQLStore) GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error { return ss.WithDbSession(ctx, func(sess *DBSession) error { - user := new(models.User) + user := new(user.User) has, err := sess.ID(query.Id). Where(notServiceAccountFilter(ss)). @@ -221,13 +223,13 @@ func (ss *SQLStore) GetUserByLogin(ctx context.Context, query *models.GetUserByL // Try and find the user by login first. // It's not sufficient to assume that a LoginOrEmail with an "@" is an email. - user := &models.User{} + usr := &user.User{} where := "login=?" if ss.Cfg.CaseInsensitiveLogin { where = "LOWER(login)=LOWER(?)" } - has, err := sess.Where(notServiceAccountFilter(ss)).Where(where, query.LoginOrEmail).Get(user) + has, err := sess.Where(notServiceAccountFilter(ss)).Where(where, query.LoginOrEmail).Get(usr) if err != nil { return err } @@ -235,12 +237,13 @@ func (ss *SQLStore) GetUserByLogin(ctx context.Context, query *models.GetUserByL if !has && strings.Contains(query.LoginOrEmail, "@") { // If the user wasn't found, and it contains an "@" fallback to finding the // user by email. + where = "email=?" if ss.Cfg.CaseInsensitiveLogin { where = "LOWER(email)=LOWER(?)" } - user = &models.User{} - has, err = sess.Where(notServiceAccountFilter(ss)).Where(where, query.LoginOrEmail).Get(user) + usr = &user.User{} + has, err = sess.Where(notServiceAccountFilter(ss)).Where(where, query.LoginOrEmail).Get(usr) } if err != nil { @@ -250,12 +253,12 @@ func (ss *SQLStore) GetUserByLogin(ctx context.Context, query *models.GetUserByL } if ss.Cfg.CaseInsensitiveLogin { - if err := ss.userCaseInsensitiveLoginConflict(ctx, sess, user.Login, user.Email); err != nil { + if err := ss.userCaseInsensitiveLoginConflict(ctx, sess, usr.Login, usr.Email); err != nil { return err } } - query.Result = user + query.Result = usr return nil }) @@ -267,7 +270,7 @@ func (ss *SQLStore) GetUserByEmail(ctx context.Context, query *models.GetUserByE return models.ErrUserNotFound } - user := &models.User{} + user := &user.User{} where := "email=?" if ss.Cfg.CaseInsensitiveLogin { where = "LOWER(email)=LOWER(?)" @@ -300,7 +303,7 @@ func (ss *SQLStore) UpdateUser(ctx context.Context, cmd *models.UpdateUserComman } return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { - user := models.User{ + user := user.User{ Name: cmd.Name, Email: cmd.Email, Login: cmd.Login, @@ -320,7 +323,7 @@ func (ss *SQLStore) UpdateUser(ctx context.Context, cmd *models.UpdateUserComman sess.publishAfterCommit(&events.UserUpdated{ Timestamp: user.Created, - Id: user.Id, + Id: user.ID, Name: user.Name, Login: user.Login, Email: user.Email, @@ -332,7 +335,7 @@ func (ss *SQLStore) UpdateUser(ctx context.Context, cmd *models.UpdateUserComman func (ss *SQLStore) ChangeUserPassword(ctx context.Context, cmd *models.ChangeUserPasswordCommand) error { return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { - user := models.User{ + user := user.User{ Password: cmd.NewPassword, Updated: time.Now(), } @@ -344,8 +347,8 @@ func (ss *SQLStore) ChangeUserPassword(ctx context.Context, cmd *models.ChangeUs func (ss *SQLStore) UpdateUserLastSeenAt(ctx context.Context, cmd *models.UpdateUserLastSeenAtCommand) error { return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { - user := models.User{ - Id: cmd.UserId, + user := user.User{ + ID: cmd.UserId, LastSeenAt: time.Now(), } @@ -376,9 +379,9 @@ func (ss *SQLStore) SetUsingOrg(ctx context.Context, cmd *models.SetUsingOrgComm } func setUsingOrgInTransaction(sess *DBSession, userID int64, orgID int64) error { - user := models.User{ - Id: userID, - OrgId: orgID, + user := user.User{ + ID: userID, + OrgID: orgID, } _, err := sess.ID(userID).Update(&user) @@ -386,9 +389,9 @@ func setUsingOrgInTransaction(sess *DBSession, userID int64, orgID int64) error } func removeUserOrg(sess *DBSession, userID int64) error { - user := models.User{ - Id: userID, - OrgId: 0, + user := user.User{ + ID: userID, + OrgID: 0, } _, err := sess.ID(userID).MustCols("org_id").Update(&user) @@ -397,7 +400,7 @@ func removeUserOrg(sess *DBSession, userID int64) error { func (ss *SQLStore) GetUserProfile(ctx context.Context, query *models.GetUserProfileQuery) error { return ss.WithDbSession(ctx, func(sess *DBSession) error { - var user models.User + var user user.User has, err := sess.ID(query.UserId).Where(notServiceAccountFilter(ss)).Get(&user) if err != nil { @@ -407,14 +410,14 @@ func (ss *SQLStore) GetUserProfile(ctx context.Context, query *models.GetUserPro } query.Result = models.UserProfileDTO{ - Id: user.Id, + Id: user.ID, Name: user.Name, Email: user.Email, Login: user.Login, Theme: user.Theme, IsGrafanaAdmin: user.IsAdmin, IsDisabled: user.IsDisabled, - OrgId: user.OrgId, + OrgId: user.OrgID, UpdatedAt: user.Updated, CreatedAt: user.Created, } @@ -654,7 +657,7 @@ func (ss *SQLStore) SearchUsers(ctx context.Context, query *models.SearchUsersQu } // get total - user := models.User{} + user := user.User{} countSess := dbSess.Table("user").Alias("u") // Join with user_auth table if users filtered by auth_module @@ -691,7 +694,7 @@ func (ss *SQLStore) SearchUsers(ctx context.Context, query *models.SearchUsersQu func (ss *SQLStore) DisableUser(ctx context.Context, cmd *models.DisableUserCommand) error { return ss.WithDbSession(ctx, func(dbSess *DBSession) error { - user := models.User{} + user := user.User{} sess := dbSess.Table("user") if has, err := sess.ID(cmd.UserId).Where(notServiceAccountFilter(ss)).Get(&user); err != nil { @@ -737,7 +740,7 @@ func (ss *SQLStore) DeleteUser(ctx context.Context, cmd *models.DeleteUserComman func deleteUserInTransaction(ss *SQLStore, sess *DBSession, cmd *models.DeleteUserCommand) error { // Check if user exists - user := models.User{Id: cmd.UserId} + user := user.User{ID: cmd.UserId} has, err := sess.Where(notServiceAccountFilter(ss)).Get(&user) if err != nil { return err @@ -813,7 +816,7 @@ func UserDeletions() []string { // UpdateUserPermissions sets the user Server Admin flag func (ss *SQLStore) UpdateUserPermissions(userID int64, isAdmin bool) error { return ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error { - var user models.User + var user user.User if _, err := sess.ID(userID).Where(notServiceAccountFilter(ss)).Get(&user); err != nil { return err } @@ -821,7 +824,7 @@ func (ss *SQLStore) UpdateUserPermissions(userID int64, isAdmin bool) error { user.IsAdmin = isAdmin sess.UseBool("is_admin") - _, err := sess.ID(user.Id).Update(&user) + _, err := sess.ID(user.ID).Update(&user) if err != nil { return err } @@ -837,9 +840,9 @@ func (ss *SQLStore) UpdateUserPermissions(userID int64, isAdmin bool) error { func (ss *SQLStore) SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHelpFlagCommand) error { return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { - user := models.User{ - Id: cmd.UserId, - HelpFlags1: cmd.HelpFlags1, + user := user.User{ + ID: cmd.UserId, + HelpFlags1: user.HelpFlags1(cmd.HelpFlags1), Updated: time.Now(), } @@ -850,7 +853,7 @@ func (ss *SQLStore) SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHelp // validateOneAdminLeft validate that there is an admin user left func validateOneAdminLeft(sess *DBSession) error { - count, err := sess.Where("is_admin=?", true).Count(&models.User{}) + count, err := sess.Where("is_admin=?", true).Count(&user.User{}) if err != nil { return err } diff --git a/pkg/services/sqlstore/user_test.go b/pkg/services/sqlstore/user_test.go index e6277d5b310..ca419fa583d 100644 --- a/pkg/services/sqlstore/user_test.go +++ b/pkg/services/sqlstore/user_test.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "github.com/grafana/grafana/pkg/services/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -18,8 +19,8 @@ func TestIntegrationUserUpdate(t *testing.T) { ss := InitTestDB(t) - users := createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("USER", i, "@test.com"), Name: fmt.Sprint("USER", i), Login: fmt.Sprint("loginUSER", i), @@ -32,7 +33,7 @@ func TestIntegrationUserUpdate(t *testing.T) { t.Run("Testing DB - update generates duplicate user", func(t *testing.T) { err := ss.UpdateUser(context.Background(), &models.UpdateUserCommand{ Login: "loginuser2", - UserId: users[0].Id, + UserId: users[0].ID, }) require.Error(t, err) @@ -42,11 +43,11 @@ func TestIntegrationUserUpdate(t *testing.T) { err := ss.UpdateUser(context.Background(), &models.UpdateUserCommand{ Login: "loginUSER0", Email: "USER0@test.com", - UserId: users[0].Id, + UserId: users[0].ID, }) require.NoError(t, err) - query := models.GetUserByIdQuery{Id: users[0].Id} + query := models.GetUserByIdQuery{Id: users[0].ID} err = ss.GetUserById(context.Background(), &query) require.NoError(t, err) @@ -59,11 +60,11 @@ func TestIntegrationUserUpdate(t *testing.T) { Login: "", Email: "", Name: "Change Name", - UserId: users[3].Id, + UserId: users[3].ID, }) require.NoError(t, err) - query := models.GetUserByIdQuery{Id: users[3].Id} + query := models.GetUserByIdQuery{Id: users[3].ID} err = ss.GetUserById(context.Background(), &query) require.NoError(t, err) @@ -83,13 +84,13 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Skip("skipping integration test") } ss := InitTestDB(t) - user := &models.SignedInUser{ + usr := &models.SignedInUser{ OrgId: 1, Permissions: map[int64]map[string][]string{1: {"users:read": {"global.users:*"}}}, } t.Run("Testing DB - creates and loads user", func(t *testing.T) { - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: "usertest@test.com", Name: "user name", Login: "user_test_login", @@ -97,7 +98,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { user, err := ss.CreateUser(context.Background(), cmd) require.NoError(t, err) - query := models.GetUserByIdQuery{Id: user.Id} + query := models.GetUserByIdQuery{Id: user.ID} err = ss.GetUserById(context.Background(), &query) require.Nil(t, err) @@ -107,7 +108,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.Len(t, query.Result.Salt, 10) require.False(t, query.Result.IsDisabled) - query = models.GetUserByIdQuery{Id: user.Id} + query = models.GetUserByIdQuery{Id: user.ID} err = ss.GetUserById(context.Background(), &query) require.Nil(t, err) @@ -166,7 +167,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - creates and loads disabled user", func(t *testing.T) { ss = InitTestDB(t) - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: "usertest@test.com", Name: "user name", Login: "user_test_login", @@ -176,7 +177,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { user, err := ss.CreateUser(context.Background(), cmd) require.Nil(t, err) - query := models.GetUserByIdQuery{Id: user.Id} + query := models.GetUserByIdQuery{Id: user.ID} err = ss.GetUserById(context.Background(), &query) require.Nil(t, err) @@ -200,17 +201,17 @@ func TestIntegrationUserDataAccess(t *testing.T) { err := ss.CreateOrg(context.Background(), orgCmd) require.Nil(t, err) - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: "usertest@test.com", Name: "user name", Login: "user_test_login", - OrgId: orgCmd.Result.Id, + OrgID: orgCmd.Result.Id, } - user, err := ss.CreateUser(context.Background(), cmd) + usr, err := ss.CreateUser(context.Background(), cmd) require.Nil(t, err) - query := models.GetUserByIdQuery{Id: user.Id} + query := models.GetUserByIdQuery{Id: usr.ID} err = ss.GetUserById(context.Background(), &query) require.Nil(t, err) @@ -219,14 +220,14 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.Len(t, query.Result.Rands, 10) require.Len(t, query.Result.Salt, 10) require.False(t, query.Result.IsDisabled) - require.Equal(t, query.Result.OrgId, orgCmd.Result.Id) + require.Equal(t, query.Result.OrgID, orgCmd.Result.Id) const nonExistingOrgID = 10000 - cmd = models.CreateUserCommand{ + cmd = user.CreateUserCommand{ Email: "usertest@test.com", Name: "user name", Login: "user_test_login", - OrgId: nonExistingOrgID, + OrgID: nonExistingOrgID, } _, err = ss.CreateUser(context.Background(), cmd) @@ -236,8 +237,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - multiple users", func(t *testing.T) { ss = InitTestDB(t) - createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -246,7 +247,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { }) // Return the first page of users and a total count - query := models.SearchUsersQuery{Query: "", Page: 1, Limit: 3, SignedInUser: user} + query := models.SearchUsersQuery{Query: "", Page: 1, Limit: 3, SignedInUser: usr} err := ss.SearchUsers(context.Background(), &query) require.Nil(t, err) @@ -254,7 +255,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.EqualValues(t, query.Result.TotalCount, 5) // Return the second page of users and a total count - query = models.SearchUsersQuery{Query: "", Page: 2, Limit: 3, SignedInUser: user} + query = models.SearchUsersQuery{Query: "", Page: 2, Limit: 3, SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) @@ -262,28 +263,28 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.EqualValues(t, query.Result.TotalCount, 5) // Return list of users matching query on user name - query = models.SearchUsersQuery{Query: "use", Page: 1, Limit: 3, SignedInUser: user} + query = models.SearchUsersQuery{Query: "use", Page: 1, Limit: 3, SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) require.Len(t, query.Result.Users, 3) require.EqualValues(t, query.Result.TotalCount, 5) - query = models.SearchUsersQuery{Query: "ser1", Page: 1, Limit: 3, SignedInUser: user} + query = models.SearchUsersQuery{Query: "ser1", Page: 1, Limit: 3, SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) require.Len(t, query.Result.Users, 1) require.EqualValues(t, query.Result.TotalCount, 1) - query = models.SearchUsersQuery{Query: "USER1", Page: 1, Limit: 3, SignedInUser: user} + query = models.SearchUsersQuery{Query: "USER1", Page: 1, Limit: 3, SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) require.Len(t, query.Result.Users, 1) require.EqualValues(t, query.Result.TotalCount, 1) - query = models.SearchUsersQuery{Query: "idontexist", Page: 1, Limit: 3, SignedInUser: user} + query = models.SearchUsersQuery{Query: "idontexist", Page: 1, Limit: 3, SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) @@ -291,7 +292,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.EqualValues(t, query.Result.TotalCount, 0) // Return list of users matching query on email - query = models.SearchUsersQuery{Query: "ser1@test.com", Page: 1, Limit: 3, SignedInUser: user} + query = models.SearchUsersQuery{Query: "ser1@test.com", Page: 1, Limit: 3, SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) @@ -299,7 +300,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.EqualValues(t, query.Result.TotalCount, 1) // Return list of users matching query on login name - query = models.SearchUsersQuery{Query: "loginuser1", Page: 1, Limit: 3, SignedInUser: user} + query = models.SearchUsersQuery{Query: "loginuser1", Page: 1, Limit: 3, SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) @@ -309,8 +310,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - return list users based on their is_disabled flag", func(t *testing.T) { ss = InitTestDB(t) - createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -319,7 +320,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { }) isDisabled := false - query := models.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: user} + query := models.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: usr} err := ss.SearchUsers(context.Background(), &query) require.Nil(t, err) @@ -341,8 +342,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { // Re-init DB ss = InitTestDB(t) - users := createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -352,27 +353,27 @@ func TestIntegrationUserDataAccess(t *testing.T) { err = ss.AddOrgUser(context.Background(), &models.AddOrgUserCommand{ LoginOrEmail: users[1].Login, Role: models.ROLE_VIEWER, - OrgId: users[0].OrgId, UserId: users[1].Id, + OrgId: users[0].OrgID, UserId: users[1].ID, }) require.Nil(t, err) err = updateDashboardAcl(t, ss, 1, &models.DashboardAcl{ - DashboardID: 1, OrgID: users[0].OrgId, UserID: users[1].Id, + DashboardID: 1, OrgID: users[0].OrgID, UserID: users[1].ID, Permission: models.PERMISSION_EDIT, }) require.Nil(t, err) // When the user is deleted - err = ss.DeleteUser(context.Background(), &models.DeleteUserCommand{UserId: users[1].Id}) + err = ss.DeleteUser(context.Background(), &models.DeleteUserCommand{UserId: users[1].ID}) require.Nil(t, err) - query1 := &models.GetOrgUsersQuery{OrgId: users[0].OrgId, User: user} + query1 := &models.GetOrgUsersQuery{OrgId: users[0].OrgID, User: usr} err = ss.GetOrgUsersForTest(context.Background(), query1) require.Nil(t, err) require.Len(t, query1.Result, 1) - permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgId} + permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgID} err = getDashboardAclInfoList(ss, permQuery) require.Nil(t, err) @@ -381,8 +382,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { // A user is an org member and has been assigned permissions // Re-init DB ss = InitTestDB(t) - users = createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + users = createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -391,37 +392,37 @@ func TestIntegrationUserDataAccess(t *testing.T) { }) err = ss.AddOrgUser(context.Background(), &models.AddOrgUserCommand{ LoginOrEmail: users[1].Login, Role: models.ROLE_VIEWER, - OrgId: users[0].OrgId, UserId: users[1].Id, + OrgId: users[0].OrgID, UserId: users[1].ID, }) require.Nil(t, err) err = updateDashboardAcl(t, ss, 1, &models.DashboardAcl{ - DashboardID: 1, OrgID: users[0].OrgId, UserID: users[1].Id, + DashboardID: 1, OrgID: users[0].OrgID, UserID: users[1].ID, Permission: models.PERMISSION_EDIT, }) require.Nil(t, err) ss.CacheService.Flush() - query3 := &models.GetSignedInUserQuery{OrgId: users[1].OrgId, UserId: users[1].Id} + query3 := &models.GetSignedInUserQuery{OrgId: users[1].OrgID, UserId: users[1].ID} err = ss.GetSignedInUserWithCacheCtx(context.Background(), query3) require.Nil(t, err) require.NotNil(t, query3.Result) - require.Equal(t, query3.OrgId, users[1].OrgId) - err = ss.SetUsingOrg(context.Background(), &models.SetUsingOrgCommand{UserId: users[1].Id, OrgId: users[0].OrgId}) + require.Equal(t, query3.OrgId, users[1].OrgID) + err = ss.SetUsingOrg(context.Background(), &models.SetUsingOrgCommand{UserId: users[1].ID, OrgId: users[0].OrgID}) require.Nil(t, err) - query4 := &models.GetSignedInUserQuery{OrgId: 0, UserId: users[1].Id} + query4 := &models.GetSignedInUserQuery{OrgId: 0, UserId: users[1].ID} err = ss.GetSignedInUserWithCacheCtx(context.Background(), query4) require.Nil(t, err) require.NotNil(t, query4.Result) - require.Equal(t, query4.Result.OrgId, users[0].OrgId) + require.Equal(t, query4.Result.OrgId, users[0].OrgID) cacheKey := newSignedInUserCacheKey(query4.Result.OrgId, query4.UserId) _, found := ss.CacheService.Get(cacheKey) require.True(t, found) disableCmd := models.BatchDisableUsersCommand{ - UserIds: []int64{users[0].Id, users[1].Id, users[2].Id, users[3].Id, users[4].Id}, + UserIds: []int64{users[0].ID, users[1].ID, users[2].ID, users[3].ID, users[4].ID}, IsDisabled: true, } @@ -429,24 +430,24 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.Nil(t, err) isDisabled = true - query5 := &models.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: user} + query5 := &models.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: usr} err = ss.SearchUsers(context.Background(), query5) require.Nil(t, err) require.EqualValues(t, query5.Result.TotalCount, 5) // the user is deleted - err = ss.DeleteUser(context.Background(), &models.DeleteUserCommand{UserId: users[1].Id}) + err = ss.DeleteUser(context.Background(), &models.DeleteUserCommand{UserId: users[1].ID}) require.Nil(t, err) // delete connected org users and permissions - query2 := &models.GetOrgUsersQuery{OrgId: users[0].OrgId} + query2 := &models.GetOrgUsersQuery{OrgId: users[0].OrgID} err = ss.GetOrgUsersForTest(context.Background(), query2) require.Nil(t, err) require.Len(t, query2.Result, 1) - permQuery = &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgId} + permQuery = &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgID} err = getDashboardAclInfoList(ss, permQuery) require.Nil(t, err) @@ -455,8 +456,8 @@ 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 := InitTestDB(t) - createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -478,7 +479,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Skip("Skipping on MySQL due to case insensitive indexes") } - cmd := models.CreateUserCommand{ + cmd := user.CreateUserCommand{ Email: "confusertest@test.com", Name: "user name", Login: "user_email_conflict", @@ -486,7 +487,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { userEmailConflict, err := ss.CreateUser(context.Background(), cmd) require.NoError(t, err) - cmd = models.CreateUserCommand{ + cmd = user.CreateUserCommand{ Email: "confusertest@TEST.COM", Name: "user name", Login: "user_email_conflict_two", @@ -494,7 +495,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { _, err = ss.CreateUser(context.Background(), cmd) require.NoError(t, err) - cmd = models.CreateUserCommand{ + cmd = user.CreateUserCommand{ Email: "user_test_login_conflict@test.com", Name: "user name", Login: "user_test_login_conflict", @@ -502,7 +503,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { userLoginConflict, err := ss.CreateUser(context.Background(), cmd) require.NoError(t, err) - cmd = models.CreateUserCommand{ + cmd = user.CreateUserCommand{ Email: "user_test_login_conflict_two@test.com", Name: "user name", Login: "user_test_login_CONFLICT", @@ -525,13 +526,13 @@ func TestIntegrationUserDataAccess(t *testing.T) { }) t.Run("GetUserByID - email conflict", func(t *testing.T) { - query := models.GetUserByIdQuery{Id: userEmailConflict.Id} + query := models.GetUserByIdQuery{Id: userEmailConflict.ID} err = ss.GetUserById(context.Background(), &query) require.Error(t, err) }) t.Run("GetUserByID - login conflict", func(t *testing.T) { - query := models.GetUserByIdQuery{Id: userLoginConflict.Id} + query := models.GetUserByIdQuery{Id: userLoginConflict.ID} err = ss.GetUserById(context.Background(), &query) require.Error(t, err) }) @@ -560,8 +561,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { ss = InitTestDB(t) t.Run("Testing DB - enable all users", func(t *testing.T) { - users := createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -570,7 +571,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { }) disableCmd := models.BatchDisableUsersCommand{ - UserIds: []int64{users[0].Id, users[1].Id, users[2].Id, users[3].Id, users[4].Id}, + UserIds: []int64{users[0].ID, users[1].ID, users[2].ID, users[3].ID, users[4].ID}, IsDisabled: false, } @@ -578,7 +579,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.Nil(t, err) isDisabled := false - query := &models.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: user} + query := &models.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: usr} err = ss.SearchUsers(context.Background(), query) require.Nil(t, err) @@ -588,8 +589,8 @@ func TestIntegrationUserDataAccess(t *testing.T) { ss = InitTestDB(t) t.Run("Testing DB - disable only specific users", func(t *testing.T) { - users := createFiveTestUsers(t, ss, func(i int) *models.CreateUserCommand { - return &models.CreateUserCommand{ + users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -599,7 +600,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { userIdsToDisable := []int64{} for i := 0; i < 3; i++ { - userIdsToDisable = append(userIdsToDisable, users[i].Id) + userIdsToDisable = append(userIdsToDisable, users[i].ID) } disableCmd := models.BatchDisableUsersCommand{ UserIds: userIdsToDisable, @@ -609,7 +610,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { err := ss.BatchDisableUsers(context.Background(), &disableCmd) require.Nil(t, err) - query := models.SearchUsersQuery{SignedInUser: user} + query := models.SearchUsersQuery{SignedInUser: usr} err = ss.SearchUsers(context.Background(), &query) require.Nil(t, err) @@ -636,8 +637,8 @@ 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) *models.CreateUserCommand { - return &models.CreateUserCommand{ + createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand { + return &user.CreateUserCommand{ Email: fmt.Sprint("user", i, "@test.com"), Name: fmt.Sprint("user", i), Login: fmt.Sprint("loginuser", i), @@ -649,21 +650,21 @@ func TestIntegrationUserDataAccess(t *testing.T) { t.Run("Testing DB - grafana admin users", func(t *testing.T) { ss = InitTestDB(t) - createUserCmd := models.CreateUserCommand{ + createUserCmd := user.CreateUserCommand{ Email: fmt.Sprint("admin", "@test.com"), Name: "admin", Login: "admin", IsAdmin: true, } - user, err := ss.CreateUser(context.Background(), createUserCmd) + usr, err := ss.CreateUser(context.Background(), createUserCmd) require.Nil(t, err) // Cannot make themselves a non-admin - updatePermsError := ss.UpdateUserPermissions(user.Id, false) + updatePermsError := ss.UpdateUserPermissions(usr.ID, false) require.Equal(t, updatePermsError, models.ErrLastGrafanaAdmin) - query := models.GetUserByIdQuery{Id: user.Id} + query := models.GetUserByIdQuery{Id: usr.ID} getUserError := ss.GetUserById(context.Background(), &query) require.Nil(t, getUserError) @@ -672,7 +673,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { // One user const email = "user@test.com" const username = "user" - createUserCmd = models.CreateUserCommand{ + createUserCmd = user.CreateUserCommand{ Email: email, Name: "user", Login: username, @@ -681,7 +682,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.Nil(t, err) // When trying to create a new user with the same email, an error is returned - createUserCmd = models.CreateUserCommand{ + createUserCmd = user.CreateUserCommand{ Email: email, Name: "user2", Login: "user2", @@ -691,7 +692,7 @@ func TestIntegrationUserDataAccess(t *testing.T) { require.Equal(t, err, models.ErrUserAlreadyExists) // When trying to create a new user with the same login, an error is returned - createUserCmd = models.CreateUserCommand{ + createUserCmd = user.CreateUserCommand{ Email: "user2@test.com", Name: "user2", Login: username, @@ -715,10 +716,10 @@ func (ss *SQLStore) GetOrgUsersForTest(ctx context.Context, query *models.GetOrg }) } -func createFiveTestUsers(t *testing.T, sqlStore *SQLStore, fn func(i int) *models.CreateUserCommand) []models.User { +func createFiveTestUsers(t *testing.T, sqlStore *SQLStore, fn func(i int) *user.CreateUserCommand) []user.User { t.Helper() - users := []models.User{} + users := []user.User{} for i := 0; i < 5; i++ { cmd := fn(i) diff --git a/pkg/services/user/model.go b/pkg/services/user/model.go new file mode 100644 index 00000000000..beb22502ec7 --- /dev/null +++ b/pkg/services/user/model.go @@ -0,0 +1,55 @@ +package user + +import "time" + +type HelpFlags1 uint64 + +type User struct { + ID int64 `xorm:"pk autoincr 'id'"` + Version int + Email string + Name string + Login string + Password string + Salt string + Rands string + Company string + EmailVerified bool + Theme string + HelpFlags1 HelpFlags1 + IsDisabled bool + + IsAdmin bool + IsServiceAccount bool + OrgID int64 `xorm:"org_id"` + + Created time.Time + Updated time.Time + LastSeenAt time.Time +} + +type CreateUserCommand struct { + Email string + Login string + Name string + Company string + OrgID int64 + OrgName string + Password string + EmailVerified bool + IsAdmin bool + IsDisabled bool + SkipOrgSetup bool + DefaultOrgRole string + IsServiceAccount bool +} + +func (u *User) NameOrFallback() string { + if u.Name != "" { + return u.Name + } + if u.Login != "" { + return u.Login + } + return u.Email +} diff --git a/pkg/services/user/user.go b/pkg/services/user/user.go new file mode 100644 index 00000000000..dc04e6c3e4d --- /dev/null +++ b/pkg/services/user/user.go @@ -0,0 +1,9 @@ +package user + +import ( + "context" +) + +type Service interface { + Create(context.Context, *CreateUserCommand) (*User, error) +} diff --git a/pkg/services/user/userimpl/store.go b/pkg/services/user/userimpl/store.go new file mode 100644 index 00000000000..33afdf891b3 --- /dev/null +++ b/pkg/services/user/userimpl/store.go @@ -0,0 +1,62 @@ +package userimpl + +import ( + "context" + + "github.com/grafana/grafana/pkg/events" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/sqlstore/db" + "github.com/grafana/grafana/pkg/services/user" +) + +type store interface { + Insert(context.Context, *user.User) (int64, error) + Get(context.Context, *user.User) (*user.User, error) +} + +type sqlStore struct { + db db.DB +} + +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 *sqlstore.DBSession) error { + sess.UseBool("is_admin") + + if userID, err = sess.Insert(cmd); err != nil { + return err + } + sess.PublishAfterCommit(&events.UserCreated{ + Timestamp: cmd.Created, + Id: cmd.ID, + Name: cmd.Name, + Login: cmd.Login, + Email: cmd.Email, + }) + return nil + }) + if err != nil { + return 0, err + } + return userID, nil +} + +func (ss *sqlStore) Get(ctx context.Context, cmd *user.User) (*user.User, error) { + var usr *user.User + err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + exists, err := sess.Where("email=? OR login=?", cmd.Email, cmd.Login).Get(&user.User{}) + if !exists { + return models.ErrUserNotFound + } + if err != nil { + return err + } + return nil + }) + if err != nil { + return nil, err + } + return usr, nil +} diff --git a/pkg/services/user/userimpl/store_test.go b/pkg/services/user/userimpl/store_test.go new file mode 100644 index 00000000000..c158f6fd38b --- /dev/null +++ b/pkg/services/user/userimpl/store_test.go @@ -0,0 +1,57 @@ +package userimpl + +import ( + "context" + "testing" + "time" + + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" + + "github.com/stretchr/testify/require" +) + +func TestIntegrationUserDataAccess(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + ss := sqlstore.InitTestDB(t) + userStore := sqlStore{db: ss} + + t.Run("user not found", func(t *testing.T) { + _, err := userStore.Get(context.Background(), + &user.User{ + Email: "test@email.com", + Name: "test1", + Login: "test1", + }, + ) + require.Error(t, err, models.ErrUserNotFound) + }) + + t.Run("insert user", func(t *testing.T) { + _, err := userStore.Insert(context.Background(), + &user.User{ + Email: "test@email.com", + Name: "test1", + Login: "test1", + Created: time.Now(), + Updated: time.Now(), + }, + ) + require.NoError(t, err) + }) + + t.Run("get user", func(t *testing.T) { + _, err := userStore.Get(context.Background(), + &user.User{ + Email: "test@email.com", + Name: "test1", + Login: "test1", + }, + ) + require.NoError(t, err) + }) +} diff --git a/pkg/services/user/userimpl/user.go b/pkg/services/user/userimpl/user.go new file mode 100644 index 00000000000..28653a4edd6 --- /dev/null +++ b/pkg/services/user/userimpl/user.go @@ -0,0 +1,121 @@ +package userimpl + +import ( + "context" + "errors" + "time" + + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/sqlstore/db" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util" +) + +type Service struct { + store store + orgService org.Service +} + +func ProvideService(db db.DB, orgService org.Service) user.Service { + return &Service{ + store: &sqlStore{ + db: db, + }, + orgService: orgService, + } +} + +func (s *Service) Create(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) + 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, models.ErrUserNotFound) { + 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: 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 { + orgUser := org.OrgUser{ + OrgID: orgID, + UserID: usr.ID, + Role: org.ROLE_ADMIN, + Created: time.Now(), + Updated: time.Now(), + } + + if setting.AutoAssignOrg && !usr.IsAdmin { + if len(cmd.DefaultOrgRole) > 0 { + orgUser.Role = org.RoleType(cmd.DefaultOrgRole) + } else { + orgUser.Role = org.RoleType(setting.AutoAssignOrgRole) + } + } + _, err = s.orgService.InsertUser(ctx, &orgUser) + if err != nil { + // HERE ADD DELETE USER + return usr, err + } + } + + return usr, nil +} diff --git a/pkg/services/user/userimpl/user_test.go b/pkg/services/user/userimpl/user_test.go new file mode 100644 index 00000000000..4c75a8e6b0e --- /dev/null +++ b/pkg/services/user/userimpl/user_test.go @@ -0,0 +1,41 @@ +package userimpl + +import ( + "context" + "testing" + + "github.com/grafana/grafana/pkg/services/org/orgtest" + "github.com/grafana/grafana/pkg/services/user" + "github.com/stretchr/testify/require" +) + +func TestUserService(t *testing.T) { + userStore := newUserStoreFake() + orgService := orgtest.NewOrgServiceFake() + userService := Service{ + store: userStore, + orgService: orgService, + } + + t.Run("create user", func(t *testing.T) { + _, err := userService.Create(context.Background(), &user.CreateUserCommand{}) + require.NoError(t, err) + }) +} + +type FakeUserStore struct { + ExpectedUser *user.User + ExpectedError error +} + +func newUserStoreFake() *FakeUserStore { + return &FakeUserStore{} +} + +func (f *FakeUserStore) Get(ctx context.Context, query *user.User) (*user.User, error) { + return f.ExpectedUser, f.ExpectedError +} + +func (f *FakeUserStore) Insert(ctx context.Context, query *user.User) (int64, error) { + return 0, f.ExpectedError +} diff --git a/pkg/services/user/usertest/fake.go b/pkg/services/user/usertest/fake.go new file mode 100644 index 00000000000..5863b592fab --- /dev/null +++ b/pkg/services/user/usertest/fake.go @@ -0,0 +1,20 @@ +package usertest + +import ( + "context" + + "github.com/grafana/grafana/pkg/services/user" +) + +type FakeUserService struct { + ExpectedUser *user.User + ExpectedError error +} + +func NewUserServiceFake() *FakeUserService { + return &FakeUserService{} +} + +func (f *FakeUserService) Create(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) { + return f.ExpectedUser, f.ExpectedError +} diff --git a/pkg/tests/api/alerting/api_admin_configuration_test.go b/pkg/tests/api/alerting/api_admin_configuration_test.go index 0671b3b23b3..8a893ce34c7 100644 --- a/pkg/tests/api/alerting/api_admin_configuration_test.go +++ b/pkg/tests/api/alerting/api_admin_configuration_test.go @@ -16,6 +16,7 @@ import ( apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/store" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -33,7 +34,7 @@ func TestAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) { grafanaListedAddr, s := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - userID := createUser(t, s, models.CreateUserCommand{ + userID := createUser(t, s, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Login: "grafana", Password: "password", @@ -45,11 +46,11 @@ func TestAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) { require.Equal(t, disableOrgID, orgID) // create user under different organisation - createUser(t, s, models.CreateUserCommand{ + createUser(t, s, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Password: "admin-42", Login: "admin-42", - OrgId: orgID, + OrgID: orgID, }) // Create a couple of "fake" Alertmanagers diff --git a/pkg/tests/api/alerting/api_alertmanager_configuration_test.go b/pkg/tests/api/alerting/api_alertmanager_configuration_test.go index ddf191a2e30..9250bd1320e 100644 --- a/pkg/tests/api/alerting/api_alertmanager_configuration_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_configuration_test.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -31,7 +32,7 @@ func TestAlertmanagerConfigurationIsTransactional(t *testing.T) { alertConfigURL := fmt.Sprintf("http://editor:editor@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr) // create user under main organisation - userID := createUser(t, store, models.CreateUserCommand{ + userID := createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "editor", Login: "editor", @@ -41,11 +42,11 @@ func TestAlertmanagerConfigurationIsTransactional(t *testing.T) { orgID := createOrg(t, store, "another org", userID) // create user under different organisation - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "editor-42", Login: "editor-42", - OrgId: orgID, + OrgID: orgID, }) // On a blank start with no configuration, it saves and delivers the default configuration. @@ -139,7 +140,7 @@ func TestAlertmanagerConfigurationPersistSecrets(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) alertConfigURL := fmt.Sprintf("http://editor:editor@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "editor", Login: "editor", diff --git a/pkg/tests/api/alerting/api_alertmanager_test.go b/pkg/tests/api/alerting/api_alertmanager_test.go index 029c95ca171..329666c13db 100644 --- a/pkg/tests/api/alerting/api_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_test.go @@ -21,6 +21,7 @@ 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/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -41,17 +42,17 @@ func TestAMConfigAccess(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a users to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_VIEWER), Password: "viewer", Login: "viewer", }) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "editor", Login: "editor", }) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Password: "admin", Login: "admin", @@ -415,7 +416,7 @@ func TestAlertAndGroupsQuery(t *testing.T) { } // Create a user to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -559,17 +560,17 @@ func TestRulerAccess(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a users to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_VIEWER), Password: "viewer", Login: "viewer", }) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "editor", Login: "editor", }) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Password: "admin", Login: "admin", @@ -673,12 +674,12 @@ func TestDeleteFolderWithRules(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_VIEWER), Password: "viewer", Login: "viewer", }) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "editor", Login: "editor", @@ -833,7 +834,7 @@ func TestAlertRuleCRUD(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -1874,7 +1875,7 @@ func TestQuota(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -2090,7 +2091,7 @@ func TestEval(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -2545,7 +2546,7 @@ func rulesNamespaceWithoutVariableValues(t *testing.T, b []byte) (string, map[st return string(json), m } -func createUser(t *testing.T, store *sqlstore.SQLStore, cmd models.CreateUserCommand) int64 { +func createUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserCommand) int64 { t.Helper() store.Cfg.AutoAssignOrg = true @@ -2553,7 +2554,7 @@ func createUser(t *testing.T, store *sqlstore.SQLStore, cmd models.CreateUserCom u, err := store.CreateUser(context.Background(), cmd) require.NoError(t, err) - return u.Id + return u.ID } func createOrg(t *testing.T, store *sqlstore.SQLStore, name string, userID int64) int64 { diff --git a/pkg/tests/api/alerting/api_available_channel_test.go b/pkg/tests/api/alerting/api_available_channel_test.go index 4abefafd1b7..1002f4fc390 100644 --- a/pkg/tests/api/alerting/api_available_channel_test.go +++ b/pkg/tests/api/alerting/api_available_channel_test.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/ngalert/notifier" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -25,7 +26,7 @@ func TestAvailableChannels(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", diff --git a/pkg/tests/api/alerting/api_notification_channel_test.go b/pkg/tests/api/alerting/api_notification_channel_test.go index f24da0e76fd..28fea96dc93 100644 --- a/pkg/tests/api/alerting/api_notification_channel_test.go +++ b/pkg/tests/api/alerting/api_notification_channel_test.go @@ -27,6 +27,7 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/notifier/channels" "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -41,7 +42,7 @@ func TestTestReceivers(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -75,7 +76,7 @@ func TestTestReceivers(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -157,7 +158,7 @@ func TestTestReceivers(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -234,7 +235,7 @@ func TestTestReceivers(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -321,7 +322,7 @@ func TestTestReceivers(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -434,7 +435,7 @@ func TestTestReceiversAlertCustomization(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -527,7 +528,7 @@ func TestTestReceiversAlertCustomization(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -615,7 +616,7 @@ func TestTestReceiversAlertCustomization(t *testing.T) { grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Login: "grafana", Password: "password", @@ -738,7 +739,7 @@ func TestNotificationChannels(t *testing.T) { } // Create a user to make authenticated requests - createUser(t, env.SQLStore, models.CreateUserCommand{ + createUser(t, env.SQLStore, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", diff --git a/pkg/tests/api/alerting/api_prometheus_test.go b/pkg/tests/api/alerting/api_prometheus_test.go index d8019c0d032..42440159a98 100644 --- a/pkg/tests/api/alerting/api_prometheus_test.go +++ b/pkg/tests/api/alerting/api_prometheus_test.go @@ -21,6 +21,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -35,7 +36,7 @@ func TestPrometheusRules(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -329,7 +330,7 @@ func TestPrometheusRulesFilterByDashboard(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -623,7 +624,7 @@ func TestPrometheusRulesPermissions(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - userID := createUser(t, store, models.CreateUserCommand{ + userID := createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", diff --git a/pkg/tests/api/alerting/api_provisioning_test.go b/pkg/tests/api/alerting/api_provisioning_test.go index c3ea3a108e6..fb1a02df474 100644 --- a/pkg/tests/api/alerting/api_provisioning_test.go +++ b/pkg/tests/api/alerting/api_provisioning_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/stretchr/testify/require" ) @@ -23,17 +24,17 @@ func TestProvisioning(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a users to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_VIEWER), Password: "viewer", Login: "viewer", }) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "editor", Login: "editor", }) - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Password: "admin", Login: "admin", diff --git a/pkg/tests/api/alerting/api_ruler_test.go b/pkg/tests/api/alerting/api_ruler_test.go index 46abe65a5e8..8257d51e1b0 100644 --- a/pkg/tests/api/alerting/api_ruler_test.go +++ b/pkg/tests/api/alerting/api_ruler_test.go @@ -17,6 +17,7 @@ import ( acdb "github.com/grafana/grafana/pkg/services/accesscontrol/database" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/grafana/grafana/pkg/util" ) @@ -34,7 +35,7 @@ func TestAlertRulePermissions(t *testing.T) { permissionsStore := acdb.ProvideService(store) // Create a user to make authenticated requests - userID := createUser(t, store, models.CreateUserCommand{ + userID := createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -324,7 +325,7 @@ func TestAlertRuleConflictingTitle(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create user - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Password: "admin", Login: "admin", @@ -391,7 +392,7 @@ func TestRulerRulesFilterByDashboard(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", @@ -728,7 +729,7 @@ func TestRuleGroupSequence(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create a user to make authenticated requests - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_EDITOR), Password: "password", Login: "grafana", diff --git a/pkg/tests/api/dashboards/api_dashboards_test.go b/pkg/tests/api/dashboards/api_dashboards_test.go index 421a1023e76..711d42b6abd 100644 --- a/pkg/tests/api/dashboards/api_dashboards_test.go +++ b/pkg/tests/api/dashboards/api_dashboards_test.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboardimport" "github.com/grafana/grafana/pkg/services/plugindashboards" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -34,7 +35,7 @@ func TestDashboardQuota(t *testing.T) { grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create user - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Password: "admin", Login: "admin", @@ -90,7 +91,7 @@ func TestDashboardQuota(t *testing.T) { }) } -func createUser(t *testing.T, store *sqlstore.SQLStore, cmd models.CreateUserCommand) int64 { +func createUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserCommand) int64 { t.Helper() store.Cfg.AutoAssignOrg = true @@ -98,7 +99,7 @@ func createUser(t *testing.T, store *sqlstore.SQLStore, cmd models.CreateUserCom u, err := store.CreateUser(context.Background(), cmd) require.NoError(t, err) - return u.Id + return u.ID } func TestUpdatingProvisionionedDashboards(t *testing.T) { @@ -127,7 +128,7 @@ providers: require.NoError(t, err) grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path) // Create user - createUser(t, store, models.CreateUserCommand{ + createUser(t, store, user.CreateUserCommand{ DefaultOrgRole: string(models.ROLE_ADMIN), Password: "admin", Login: "admin", diff --git a/pkg/tests/api/plugins/api_plugins_test.go b/pkg/tests/api/plugins/api_plugins_test.go index e86ce508309..db58b42b5e5 100644 --- a/pkg/tests/api/plugins/api_plugins_test.go +++ b/pkg/tests/api/plugins/api_plugins_test.go @@ -10,8 +10,8 @@ import ( "path/filepath" "testing" - "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/stretchr/testify/assert" @@ -41,8 +41,8 @@ func TestPlugins(t *testing.T) { } t.Run("Install", func(t *testing.T) { - createUser(t, store, models.CreateUserCommand{Login: usernameNonAdmin, Password: defaultPassword, IsAdmin: false}) - createUser(t, store, models.CreateUserCommand{Login: usernameAdmin, Password: defaultPassword, IsAdmin: true}) + createUser(t, store, user.CreateUserCommand{Login: usernameNonAdmin, Password: defaultPassword, IsAdmin: false}) + createUser(t, store, user.CreateUserCommand{Login: usernameAdmin, Password: defaultPassword, IsAdmin: true}) t.Run("Request is forbidden if not from an admin", func(t *testing.T) { status, body := makePostRequest(t, grafanaAPIURL(usernameNonAdmin, grafanaListedAddr, "plugins/grafana-plugin/install")) @@ -108,7 +108,7 @@ func TestPlugins(t *testing.T) { }) } -func createUser(t *testing.T, store *sqlstore.SQLStore, cmd models.CreateUserCommand) { +func createUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserCommand) { t.Helper() store.Cfg.AutoAssignOrg = true