Chore: Move user errors to user service (#52460)
* Move user not found err to user service * User ErrCaseInsensitive from user pkg * User ErrUserAlreadyExists from user pkg * User ErrLastGrafanaAdmin from user pkg * Remove errors from model
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type flatResourcePermission struct {
|
||||
@@ -39,18 +40,18 @@ func (p *flatResourcePermission) IsInherited(scope string) bool {
|
||||
}
|
||||
|
||||
func (s *AccessControlStore) SetUserResourcePermission(
|
||||
ctx context.Context, orgID int64, user accesscontrol.User,
|
||||
ctx context.Context, orgID int64, usr accesscontrol.User,
|
||||
cmd types.SetResourcePermissionCommand,
|
||||
hook types.UserResourceHookFunc,
|
||||
) (*accesscontrol.ResourcePermission, error) {
|
||||
if user.ID == 0 {
|
||||
return nil, models.ErrUserNotFound
|
||||
if usr.ID == 0 {
|
||||
return nil, user.ErrUserNotFound
|
||||
}
|
||||
|
||||
var err error
|
||||
var permission *accesscontrol.ResourcePermission
|
||||
err = s.sql.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
permission, err = s.setUserResourcePermission(sess, orgID, user, cmd, hook)
|
||||
permission, err = s.setUserResourcePermission(sess, orgID, usr, cmd, hook)
|
||||
return err
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/login"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
const InvalidJWT = "Invalid JWT"
|
||||
@@ -79,7 +80,7 @@ func (h *ContextHandler) initContextWithJWT(ctx *models.ReqContext, orgId int64)
|
||||
}
|
||||
|
||||
if err := h.SQLStore.GetSignedInUserWithCacheCtx(ctx.Req.Context(), &query); err != nil {
|
||||
if errors.Is(err, models.ErrUserNotFound) {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
ctx.Logger.Debug(
|
||||
"Failed to find user using JWT claims",
|
||||
"email_claim", query.Email,
|
||||
|
||||
@@ -95,7 +95,7 @@ type FakeGetSignUserStore struct {
|
||||
|
||||
func (f *FakeGetSignUserStore) GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error {
|
||||
if query.UserId != userID {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
query.Result = &models.SignedInUser{
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"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/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
@@ -346,7 +347,7 @@ func (h *ContextHandler) initContextWithBasicAuth(reqContext *models.ReqContext,
|
||||
"err", err,
|
||||
)
|
||||
|
||||
if errors.Is(err, models.ErrUserNotFound) {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
err = login.ErrInvalidCredentials
|
||||
}
|
||||
reqContext.JsonApiErr(401, InvalidUsernamePassword, err)
|
||||
|
||||
@@ -55,7 +55,7 @@ func (s *AuthInfoStore) GetExternalUserInfoByLogin(ctx context.Context, query *m
|
||||
|
||||
func (s *AuthInfoStore) GetAuthInfo(ctx context.Context, query *models.GetAuthInfoQuery) error {
|
||||
if query.UserId == 0 && query.AuthId == "" {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
userAuth := &models.UserAuth{
|
||||
@@ -76,7 +76,7 @@ func (s *AuthInfoStore) GetAuthInfo(ctx context.Context, query *models.GetAuthIn
|
||||
}
|
||||
|
||||
if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
secretAccessToken, err := s.decodeAndDecrypt(userAuth.OAuthAccessToken)
|
||||
|
||||
@@ -38,7 +38,7 @@ func (s *Implementation) LookupAndFix(ctx context.Context, query *models.GetUser
|
||||
authQuery.AuthId = query.AuthId
|
||||
|
||||
err := s.authInfoStore.GetAuthInfo(ctx, authQuery)
|
||||
if !errors.Is(err, models.ErrUserNotFound) {
|
||||
if !errors.Is(err, user.ErrUserNotFound) {
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
@@ -53,11 +53,11 @@ func (s *Implementation) LookupAndFix(ctx context.Context, query *models.GetUser
|
||||
s.logger.Error("Error removing user_auth entry", "error", err)
|
||||
}
|
||||
|
||||
return false, nil, nil, models.ErrUserNotFound
|
||||
return false, nil, nil, user.ErrUserNotFound
|
||||
} else {
|
||||
user, err := s.authInfoStore.GetUserById(ctx, authQuery.Result.UserId)
|
||||
usr, err := s.authInfoStore.GetUserById(ctx, authQuery.Result.UserId)
|
||||
if err != nil {
|
||||
if errors.Is(err, models.ErrUserNotFound) {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
// if the user has been deleted then remove the entry
|
||||
if errDel := s.authInfoStore.DeleteAuthInfo(ctx, &models.DeleteAuthInfoCommand{
|
||||
UserAuth: authQuery.Result,
|
||||
@@ -65,53 +65,53 @@ func (s *Implementation) LookupAndFix(ctx context.Context, query *models.GetUser
|
||||
s.logger.Error("Error removing user_auth entry", "error", errDel)
|
||||
}
|
||||
|
||||
return false, nil, nil, models.ErrUserNotFound
|
||||
return false, nil, nil, user.ErrUserNotFound
|
||||
}
|
||||
|
||||
return false, nil, nil, err
|
||||
}
|
||||
|
||||
return true, user, authQuery.Result, nil
|
||||
return true, usr, authQuery.Result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil, nil, models.ErrUserNotFound
|
||||
return false, nil, nil, user.ErrUserNotFound
|
||||
}
|
||||
|
||||
func (s *Implementation) LookupByOneOf(ctx context.Context, params *models.UserLookupParams) (*user.User, error) {
|
||||
var user *user.User
|
||||
var usr *user.User
|
||||
var err error
|
||||
|
||||
// If not found, try to find the user by id
|
||||
if params.UserID != nil && *params.UserID != 0 {
|
||||
user, err = s.authInfoStore.GetUserById(ctx, *params.UserID)
|
||||
if err != nil && !errors.Is(err, models.ErrUserNotFound) {
|
||||
usr, err = s.authInfoStore.GetUserById(ctx, *params.UserID)
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, try to find the user by email address
|
||||
if user == nil && params.Email != nil && *params.Email != "" {
|
||||
user, err = s.authInfoStore.GetUserByEmail(ctx, *params.Email)
|
||||
if err != nil && !errors.Is(err, models.ErrUserNotFound) {
|
||||
if usr == nil && params.Email != nil && *params.Email != "" {
|
||||
usr, err = s.authInfoStore.GetUserByEmail(ctx, *params.Email)
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, try to find the user by login
|
||||
if user == nil && params.Login != nil && *params.Login != "" {
|
||||
user, err = s.authInfoStore.GetUserByLogin(ctx, *params.Login)
|
||||
if err != nil && !errors.Is(err, models.ErrUserNotFound) {
|
||||
if usr == nil && params.Login != nil && *params.Login != "" {
|
||||
usr, err = s.authInfoStore.GetUserByLogin(ctx, *params.Login)
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return nil, models.ErrUserNotFound
|
||||
if usr == nil {
|
||||
return nil, user.ErrUserNotFound
|
||||
}
|
||||
|
||||
return user, nil
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
func (s *Implementation) GenericOAuthLookup(ctx context.Context, authModule string, authId string, userID int64) (*models.UserAuth, error) {
|
||||
@@ -133,26 +133,26 @@ func (s *Implementation) GenericOAuthLookup(ctx context.Context, authModule stri
|
||||
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)
|
||||
if err != nil && !errors.Is(err, models.ErrUserNotFound) {
|
||||
foundUser, usr, authInfo, err := s.LookupAndFix(ctx, query)
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. FindByUserDetails
|
||||
if !foundUser {
|
||||
user, err = s.LookupByOneOf(ctx, &query.UserLookupParams)
|
||||
usr, err = s.LookupByOneOf(ctx, &query.UserLookupParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.UserProtectionService.AllowUserMapping(user, query.AuthModule); err != nil {
|
||||
if err := s.UserProtectionService.AllowUserMapping(usr, query.AuthModule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Special case for generic oauth duplicates
|
||||
ai, err := s.GenericOAuthLookup(ctx, query.AuthModule, query.AuthId, user.ID)
|
||||
if !errors.Is(err, models.ErrUserNotFound) {
|
||||
ai, err := s.GenericOAuthLookup(ctx, query.AuthModule, query.AuthId, usr.ID)
|
||||
if !errors.Is(err, user.ErrUserNotFound) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func (s *Implementation) LookupAndUpdate(ctx context.Context, query *models.GetU
|
||||
if query.AuthModule != "" {
|
||||
if authInfo == nil {
|
||||
cmd := &models.SetAuthInfoCommand{
|
||||
UserId: user.ID,
|
||||
UserId: usr.ID,
|
||||
AuthModule: query.AuthModule,
|
||||
AuthId: query.AuthId,
|
||||
}
|
||||
@@ -178,7 +178,7 @@ func (s *Implementation) LookupAndUpdate(ctx context.Context, query *models.GetU
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
func (s *Implementation) GetAuthInfo(ctx context.Context, query *models.GetAuthInfoQuery) error {
|
||||
|
||||
@@ -44,95 +44,95 @@ func TestUserAuth(t *testing.T) {
|
||||
login := "loginuser0"
|
||||
|
||||
query := &models.GetUserByAuthInfoQuery{UserLookupParams: models.UserLookupParams{Login: &login}}
|
||||
user, err := srv.LookupAndUpdate(context.Background(), query)
|
||||
usr, err := srv.LookupAndUpdate(context.Background(), query)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, user.Login, login)
|
||||
require.Equal(t, usr.Login, login)
|
||||
|
||||
// By ID
|
||||
id := user.ID
|
||||
id := usr.ID
|
||||
|
||||
user, err = srv.LookupByOneOf(context.Background(), &models.UserLookupParams{
|
||||
usr, err = srv.LookupByOneOf(context.Background(), &models.UserLookupParams{
|
||||
UserID: &id,
|
||||
})
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, user.ID, id)
|
||||
require.Equal(t, usr.ID, id)
|
||||
|
||||
// By Email
|
||||
email := "user1@test.com"
|
||||
|
||||
user, err = srv.LookupByOneOf(context.Background(), &models.UserLookupParams{
|
||||
usr, err = srv.LookupByOneOf(context.Background(), &models.UserLookupParams{
|
||||
Email: &email,
|
||||
})
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, user.Email, email)
|
||||
require.Equal(t, usr.Email, email)
|
||||
|
||||
// Don't find nonexistent user
|
||||
email = "nonexistent@test.com"
|
||||
|
||||
user, err = srv.LookupByOneOf(context.Background(), &models.UserLookupParams{
|
||||
usr, err = srv.LookupByOneOf(context.Background(), &models.UserLookupParams{
|
||||
Email: &email,
|
||||
})
|
||||
|
||||
require.Equal(t, models.ErrUserNotFound, err)
|
||||
require.Nil(t, user)
|
||||
require.Equal(t, user.ErrUserNotFound, err)
|
||||
require.Nil(t, usr)
|
||||
})
|
||||
|
||||
t.Run("Can set & locate by AuthModule and AuthId", func(t *testing.T) {
|
||||
// get nonexistent user_auth entry
|
||||
query := &models.GetUserByAuthInfoQuery{AuthModule: "test", AuthId: "test"}
|
||||
user, err := srv.LookupAndUpdate(context.Background(), query)
|
||||
usr, err := srv.LookupAndUpdate(context.Background(), query)
|
||||
|
||||
require.Equal(t, models.ErrUserNotFound, err)
|
||||
require.Nil(t, user)
|
||||
require.Equal(t, user.ErrUserNotFound, err)
|
||||
require.Nil(t, usr)
|
||||
|
||||
// create user_auth entry
|
||||
login := "loginuser0"
|
||||
|
||||
query.UserLookupParams.Login = &login
|
||||
user, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
usr, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, user.Login, login)
|
||||
require.Equal(t, usr.Login, login)
|
||||
|
||||
// get via user_auth
|
||||
query = &models.GetUserByAuthInfoQuery{AuthModule: "test", AuthId: "test"}
|
||||
user, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
usr, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, user.Login, login)
|
||||
require.Equal(t, usr.Login, login)
|
||||
|
||||
// get with non-matching id
|
||||
idPlusOne := user.ID + 1
|
||||
idPlusOne := usr.ID + 1
|
||||
|
||||
query.UserLookupParams.UserID = &idPlusOne
|
||||
user, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
usr, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, user.Login, "loginuser1")
|
||||
require.Equal(t, usr.Login, "loginuser1")
|
||||
|
||||
// get via user_auth
|
||||
query = &models.GetUserByAuthInfoQuery{AuthModule: "test", AuthId: "test"}
|
||||
user, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
usr, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, user.Login, "loginuser1")
|
||||
require.Equal(t, usr.Login, "loginuser1")
|
||||
|
||||
// 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=?", usr.ID)
|
||||
return err
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// get via user_auth for deleted user
|
||||
query = &models.GetUserByAuthInfoQuery{AuthModule: "test", AuthId: "test"}
|
||||
user, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
usr, err = srv.LookupAndUpdate(context.Background(), query)
|
||||
|
||||
require.Equal(t, err, models.ErrUserNotFound)
|
||||
require.Nil(t, user)
|
||||
require.Equal(t, err, user.ErrUserNotFound)
|
||||
require.Nil(t, usr)
|
||||
})
|
||||
|
||||
t.Run("Can set & retrieve oauth token information", func(t *testing.T) {
|
||||
|
||||
@@ -54,7 +54,7 @@ func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUser
|
||||
UserLookupParams: cmd.UserLookupParams,
|
||||
})
|
||||
if err != nil {
|
||||
if !errors.Is(err, models.ErrUserNotFound) {
|
||||
if !errors.Is(err, user.ErrUserNotFound) {
|
||||
return err
|
||||
}
|
||||
if !cmd.SignupAllowed {
|
||||
|
||||
@@ -27,7 +27,7 @@ func (s LoginServiceMock) CreateUser(cmd user.CreateUserCommand) (*user.User, er
|
||||
}
|
||||
|
||||
if cmd.Login == s.AlreadyExitingLogin {
|
||||
return nil, models.ErrUserAlreadyExists
|
||||
return nil, user.ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
if s.ExpectedUserForm.Login == cmd.Login && s.ExpectedUserForm.Email == cmd.Email &&
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -35,19 +36,19 @@ func ProvideService(socialService social.Service, authInfoService login.AuthInfo
|
||||
}
|
||||
|
||||
// GetCurrentOAuthToken returns the OAuth token, if any, for the authenticated user. Will try to refresh the token if it has expired.
|
||||
func (o *Service) GetCurrentOAuthToken(ctx context.Context, user *models.SignedInUser) *oauth2.Token {
|
||||
if user == nil {
|
||||
func (o *Service) GetCurrentOAuthToken(ctx context.Context, usr *models.SignedInUser) *oauth2.Token {
|
||||
if usr == nil {
|
||||
// No user, therefore no token
|
||||
return nil
|
||||
}
|
||||
|
||||
authInfoQuery := &models.GetAuthInfoQuery{UserId: user.UserId}
|
||||
authInfoQuery := &models.GetAuthInfoQuery{UserId: usr.UserId}
|
||||
if err := o.AuthInfoService.GetAuthInfo(ctx, authInfoQuery); err != nil {
|
||||
if errors.Is(err, models.ErrUserNotFound) {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
// Not necessarily an error. User may be logged in another way.
|
||||
logger.Debug("no OAuth token for user found", "userId", user.UserId, "username", user.Login)
|
||||
logger.Debug("no OAuth token for user found", "userId", usr.UserId, "username", usr.Login)
|
||||
} else {
|
||||
logger.Error("failed to get OAuth token for user", "userId", user.UserId, "username", user.Login, "error", err)
|
||||
logger.Error("failed to get OAuth token for user", "userId", usr.UserId, "username", usr.Login, "error", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -80,7 +81,7 @@ func (o *Service) GetCurrentOAuthToken(ctx context.Context, user *models.SignedI
|
||||
// TokenSource handles refreshing the token if it has expired
|
||||
token, err := connect.TokenSource(ctx, persistedToken).Token()
|
||||
if err != nil {
|
||||
logger.Error("failed to retrieve OAuth access token", "provider", authInfoQuery.Result.AuthModule, "userId", user.UserId, "username", user.Login, "error", err)
|
||||
logger.Error("failed to retrieve OAuth access token", "provider", authInfoQuery.Result.AuthModule, "userId", usr.UserId, "username", usr.Login, "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -93,10 +94,10 @@ func (o *Service) GetCurrentOAuthToken(ctx context.Context, user *models.SignedI
|
||||
OAuthToken: token,
|
||||
}
|
||||
if err := o.AuthInfoService.UpdateAuthInfo(ctx, updateAuthCommand); err != nil {
|
||||
logger.Error("failed to update auth info during token refresh", "userId", user.UserId, "username", user.Login, "error", err)
|
||||
logger.Error("failed to update auth info during token refresh", "userId", usr.UserId, "username", usr.Login, "error", err)
|
||||
return nil
|
||||
}
|
||||
logger.Debug("updated OAuth info for user", "userId", user.UserId, "username", user.Login)
|
||||
logger.Debug("updated OAuth info for user", "userId", usr.UserId, "username", usr.Login)
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, org
|
||||
})
|
||||
|
||||
if createErr != nil {
|
||||
if errors.Is(createErr, models.ErrUserAlreadyExists) {
|
||||
if errors.Is(createErr, user.ErrUserAlreadyExists) {
|
||||
return nil, ErrServiceAccountAlreadyExists
|
||||
}
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ func TestIntegrationAccountDataAccess(t *testing.T) {
|
||||
require.True(t, remCmd.UserWasDeleted)
|
||||
|
||||
err = sqlStore.GetSignedInUser(context.Background(), &models.GetSignedInUserQuery{UserId: ac2.ID})
|
||||
require.Equal(t, err, models.ErrUserNotFound)
|
||||
require.Equal(t, err, user.ErrUserNotFound)
|
||||
})
|
||||
|
||||
t.Run("Cannot delete last admin org user", func(t *testing.T) {
|
||||
|
||||
@@ -15,19 +15,19 @@ import (
|
||||
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 user.User
|
||||
var usr user.User
|
||||
session := sess.ID(cmd.UserId)
|
||||
if !cmd.AllowAddingServiceAccount {
|
||||
session = session.Where(notServiceAccountFilter(ss))
|
||||
}
|
||||
|
||||
if exists, err := session.Get(&user); err != nil {
|
||||
if exists, err := session.Get(&usr); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return models.ErrUserNotFound
|
||||
return user.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, usr.ID); err != nil {
|
||||
return err
|
||||
} else if len(res) == 1 {
|
||||
return models.ErrOrgUserAlreadyAdded
|
||||
@@ -55,7 +55,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=?", usr.ID, usr.OrgID)
|
||||
sess.Cols("org.name", "org_user.role", "org_user.org_id")
|
||||
err = sess.Find(&userOrgs)
|
||||
|
||||
@@ -64,7 +64,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, usr.ID, cmd.OrgId)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -249,11 +249,11 @@ 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 user.User
|
||||
if exists, err := sess.ID(cmd.UserId).Where(notServiceAccountFilter(ss)).Get(&user); err != nil {
|
||||
var usr user.User
|
||||
if exists, err := sess.ID(cmd.UserId).Where(notServiceAccountFilter(ss)).Get(&usr); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
deletes := []string{
|
||||
@@ -279,7 +279,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=?", usr.ID)
|
||||
sess.Cols("org.name", "org_user.role", "org_user.org_id")
|
||||
err := sess.Find(&userOrgs)
|
||||
|
||||
@@ -290,28 +290,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 usr.OrgID == userOrg.OrgId {
|
||||
hasCurrentOrgSet = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasCurrentOrgSet {
|
||||
err = setUsingOrgInTransaction(sess, user.ID, userOrgs[0].OrgId)
|
||||
err = setUsingOrgInTransaction(sess, usr.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: usr.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, usr.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ func TestSQLStore_AddOrgUser(t *testing.T) {
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -20,7 +20,7 @@ type ErrCaseInsensitiveLoginConflict struct {
|
||||
}
|
||||
|
||||
func (e *ErrCaseInsensitiveLoginConflict) Unwrap() error {
|
||||
return models.ErrCaseInsensitive
|
||||
return user.ErrCaseInsensitive
|
||||
}
|
||||
|
||||
func (e *ErrCaseInsensitiveLoginConflict) Error() string {
|
||||
@@ -100,7 +100,7 @@ func (ss *SQLStore) createUser(ctx context.Context, sess *DBSession, args user.C
|
||||
return usr, err
|
||||
}
|
||||
if exists {
|
||||
return usr, models.ErrUserAlreadyExists
|
||||
return usr, user.ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
// create user
|
||||
@@ -196,25 +196,25 @@ 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(user.User)
|
||||
usr := new(user.User)
|
||||
|
||||
has, err := sess.ID(query.Id).
|
||||
Where(notServiceAccountFilter(ss)).
|
||||
Get(user)
|
||||
Get(usr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
@@ -223,7 +223,7 @@ func (ss *SQLStore) GetUserById(ctx context.Context, query *models.GetUserByIdQu
|
||||
func (ss *SQLStore) GetUserByLogin(ctx context.Context, query *models.GetUserByLoginQuery) error {
|
||||
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||
if query.LoginOrEmail == "" {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
// Try and find the user by login first.
|
||||
@@ -254,7 +254,7 @@ func (ss *SQLStore) GetUserByLogin(ctx context.Context, query *models.GetUserByL
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
if ss.Cfg.CaseInsensitiveLogin {
|
||||
@@ -272,30 +272,30 @@ func (ss *SQLStore) GetUserByLogin(ctx context.Context, query *models.GetUserByL
|
||||
func (ss *SQLStore) GetUserByEmail(ctx context.Context, query *models.GetUserByEmailQuery) error {
|
||||
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||
if query.Email == "" {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
user := &user.User{}
|
||||
usr := &user.User{}
|
||||
where := "email=?"
|
||||
if ss.Cfg.CaseInsensitiveLogin {
|
||||
where = "LOWER(email)=LOWER(?)"
|
||||
}
|
||||
|
||||
has, err := sess.Where(notServiceAccountFilter(ss)).Where(where, query.Email).Get(user)
|
||||
has, err := sess.Where(notServiceAccountFilter(ss)).Where(where, query.Email).Get(usr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
@@ -405,26 +405,26 @@ 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 user.User
|
||||
has, err := sess.ID(query.UserId).Where(notServiceAccountFilter(ss)).Get(&user)
|
||||
var usr user.User
|
||||
has, err := sess.ID(query.UserId).Where(notServiceAccountFilter(ss)).Get(&usr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
query.Result = models.UserProfileDTO{
|
||||
Id: user.ID,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
Login: user.Login,
|
||||
Theme: user.Theme,
|
||||
IsGrafanaAdmin: user.IsAdmin,
|
||||
IsDisabled: user.IsDisabled,
|
||||
OrgId: user.OrgID,
|
||||
UpdatedAt: user.Updated,
|
||||
CreatedAt: user.Created,
|
||||
Id: usr.ID,
|
||||
Name: usr.Name,
|
||||
Email: usr.Email,
|
||||
Login: usr.Login,
|
||||
Theme: usr.Theme,
|
||||
IsGrafanaAdmin: usr.IsAdmin,
|
||||
IsDisabled: usr.IsDisabled,
|
||||
OrgId: usr.OrgID,
|
||||
UpdatedAt: usr.Updated,
|
||||
CreatedAt: usr.Created,
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -536,35 +536,35 @@ func (ss *SQLStore) GetSignedInUser(ctx context.Context, query *models.GetSigned
|
||||
}
|
||||
}
|
||||
|
||||
var user models.SignedInUser
|
||||
has, err := sess.Get(&user)
|
||||
var usr models.SignedInUser
|
||||
has, err := sess.Get(&usr)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.OrgRole == "" {
|
||||
user.OrgId = -1
|
||||
user.OrgName = "Org missing"
|
||||
if usr.OrgRole == "" {
|
||||
usr.OrgId = -1
|
||||
usr.OrgName = "Org missing"
|
||||
}
|
||||
|
||||
if user.ExternalAuthModule != "oauth_grafana_com" {
|
||||
user.ExternalAuthId = ""
|
||||
if usr.ExternalAuthModule != "oauth_grafana_com" {
|
||||
usr.ExternalAuthId = ""
|
||||
}
|
||||
|
||||
// tempUser is used to retrieve the teams for the signed in user for internal use.
|
||||
tempUser := &models.SignedInUser{
|
||||
OrgId: user.OrgId,
|
||||
OrgId: usr.OrgId,
|
||||
Permissions: map[int64]map[string][]string{
|
||||
user.OrgId: {
|
||||
usr.OrgId: {
|
||||
ac.ActionTeamsRead: {ac.ScopeTeamsAll},
|
||||
},
|
||||
},
|
||||
}
|
||||
getTeamsByUserQuery := &models.GetTeamsByUserQuery{
|
||||
OrgId: user.OrgId,
|
||||
UserId: user.UserId,
|
||||
OrgId: usr.OrgId,
|
||||
UserId: usr.UserId,
|
||||
SignedInUser: tempUser,
|
||||
}
|
||||
err = ss.GetTeamsByUser(ctx, getTeamsByUserQuery)
|
||||
@@ -572,12 +572,12 @@ func (ss *SQLStore) GetSignedInUser(ctx context.Context, query *models.GetSigned
|
||||
return err
|
||||
}
|
||||
|
||||
user.Teams = make([]int64, len(getTeamsByUserQuery.Result))
|
||||
usr.Teams = make([]int64, len(getTeamsByUserQuery.Result))
|
||||
for i, t := range getTeamsByUserQuery.Result {
|
||||
user.Teams[i] = t.Id
|
||||
usr.Teams[i] = t.Id
|
||||
}
|
||||
|
||||
query.Result = &user
|
||||
query.Result = &usr
|
||||
return err
|
||||
})
|
||||
}
|
||||
@@ -699,19 +699,19 @@ 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 := user.User{}
|
||||
usr := user.User{}
|
||||
sess := dbSess.Table("user")
|
||||
|
||||
if has, err := sess.ID(cmd.UserId).Where(notServiceAccountFilter(ss)).Get(&user); err != nil {
|
||||
if has, err := sess.ID(cmd.UserId).Where(notServiceAccountFilter(ss)).Get(&usr); err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
|
||||
user.IsDisabled = cmd.IsDisabled
|
||||
usr.IsDisabled = cmd.IsDisabled
|
||||
sess.UseBool("is_disabled")
|
||||
|
||||
_, err := sess.ID(cmd.UserId).Update(&user)
|
||||
_, err := sess.ID(cmd.UserId).Update(&usr)
|
||||
return err
|
||||
})
|
||||
}
|
||||
@@ -745,13 +745,13 @@ 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 := user.User{ID: cmd.UserId}
|
||||
has, err := sess.Where(notServiceAccountFilter(ss)).Get(&user)
|
||||
usr := user.User{ID: cmd.UserId}
|
||||
has, err := sess.Where(notServiceAccountFilter(ss)).Get(&usr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
for _, sql := range UserDeletions() {
|
||||
_, err := sess.Exec(sql, cmd.UserId)
|
||||
@@ -864,7 +864,7 @@ func validateOneAdminLeft(sess *DBSession) error {
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return models.ErrLastGrafanaAdmin
|
||||
return user.ErrLastGrafanaAdmin
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -662,7 +662,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
// Cannot make themselves a non-admin
|
||||
updatePermsError := ss.UpdateUserPermissions(usr.ID, false)
|
||||
|
||||
require.Equal(t, updatePermsError, models.ErrLastGrafanaAdmin)
|
||||
require.Equal(t, updatePermsError, user.ErrLastGrafanaAdmin)
|
||||
|
||||
query := models.GetUserByIdQuery{Id: usr.ID}
|
||||
getUserError := ss.GetUserById(context.Background(), &query)
|
||||
@@ -689,7 +689,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
SkipOrgSetup: true,
|
||||
}
|
||||
_, err = ss.CreateUser(context.Background(), createUserCmd)
|
||||
require.Equal(t, err, models.ErrUserAlreadyExists)
|
||||
require.Equal(t, err, user.ErrUserAlreadyExists)
|
||||
|
||||
// When trying to create a new user with the same login, an error is returned
|
||||
createUserCmd = user.CreateUserCommand{
|
||||
@@ -699,7 +699,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
SkipOrgSetup: true,
|
||||
}
|
||||
_, err = ss.CreateUser(context.Background(), createUserCmd)
|
||||
require.Equal(t, err, models.ErrUserAlreadyExists)
|
||||
require.Equal(t, err, user.ErrUserAlreadyExists)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type HelpFlags1 uint64
|
||||
|
||||
// Typed errors
|
||||
var (
|
||||
ErrCaseInsensitive = errors.New("case insensitive conflict")
|
||||
ErrUserNotFound = errors.New("user not found")
|
||||
ErrUserAlreadyExists = errors.New("user already exists")
|
||||
ErrLastGrafanaAdmin = errors.New("cannot remove last grafana admin")
|
||||
ErrProtectedUser = errors.New("cannot adopt protected user")
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
Version int
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/sqlstore/migrator"
|
||||
@@ -52,7 +51,7 @@ func (ss *sqlStore) Get(ctx context.Context, usr *user.User) (*user.User, error)
|
||||
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
exists, err := sess.Where("email=? OR login=?", usr.Email, usr.Login).Get(usr)
|
||||
if !exists {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -78,18 +77,18 @@ func (ss *sqlStore) Delete(ctx context.Context, userID int64) error {
|
||||
}
|
||||
|
||||
func (ss *sqlStore) GetNotServiceAccount(ctx context.Context, userID int64) (*user.User, error) {
|
||||
user := user.User{ID: userID}
|
||||
usr := user.User{ID: userID}
|
||||
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
has, err := sess.Where(ss.notServiceAccountFilter()).Get(&user)
|
||||
has, err := sess.Where(ss.notServiceAccountFilter()).Get(&usr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has {
|
||||
return models.ErrUserNotFound
|
||||
return user.ErrUserNotFound
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return &user, err
|
||||
return &usr, err
|
||||
}
|
||||
|
||||
func (ss *sqlStore) notServiceAccountFilter() string {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
|
||||
@@ -28,7 +27,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Login: "test1",
|
||||
},
|
||||
)
|
||||
require.Error(t, err, models.ErrUserNotFound)
|
||||
require.Error(t, err, user.ErrUserNotFound)
|
||||
})
|
||||
|
||||
t.Run("insert user", func(t *testing.T) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@@ -84,7 +83,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
Email: cmd.Email,
|
||||
}
|
||||
usr, err = s.store.Get(ctx, usr)
|
||||
if err != nil && !errors.Is(err, models.ErrUserNotFound) {
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return usr, err
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||
@@ -46,12 +45,12 @@ func TestUserService(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("delete user store returns error", func(t *testing.T) {
|
||||
userStore.ExpectedDeleteUserError = models.ErrUserNotFound
|
||||
userStore.ExpectedDeleteUserError = user.ErrUserNotFound
|
||||
t.Cleanup(func() {
|
||||
userStore.ExpectedDeleteUserError = nil
|
||||
})
|
||||
err := userService.Delete(context.Background(), &user.DeleteUserCommand{UserID: 1})
|
||||
require.Error(t, err, models.ErrUserNotFound)
|
||||
require.Error(t, err, user.ErrUserNotFound)
|
||||
})
|
||||
|
||||
t.Run("delete user returns from team", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user