diff options
-rw-r--r-- | internal/conf/mocks.go | 9 | ||||
-rw-r--r-- | internal/db/pull.go | 27 | ||||
-rw-r--r-- | internal/db/repo.go | 12 | ||||
-rw-r--r-- | internal/db/user.go | 35 | ||||
-rw-r--r-- | internal/db/users.go | 86 | ||||
-rw-r--r-- | internal/db/users_test.go | 107 | ||||
-rw-r--r-- | internal/repoutil/repoutil.go | 13 | ||||
-rw-r--r-- | internal/repoutil/repoutil_test.go | 36 | ||||
-rw-r--r-- | internal/route/lfs/mocks_test.go | 124 | ||||
-rw-r--r-- | internal/route/org/setting.go | 7 | ||||
-rw-r--r-- | internal/route/user/setting.go | 6 |
11 files changed, 394 insertions, 68 deletions
diff --git a/internal/conf/mocks.go b/internal/conf/mocks.go index 2c10c1ce..51d1fb14 100644 --- a/internal/conf/mocks.go +++ b/internal/conf/mocks.go @@ -5,6 +5,7 @@ package conf import ( + "sync" "testing" ) @@ -24,11 +25,15 @@ func SetMockAuth(t *testing.T, otps AuthOpts) { }) } +var mockServer sync.Mutex + func SetMockServer(t *testing.T, opts ServerOpts) { + mockServer.Lock() before := Server Server = opts t.Cleanup(func() { Server = before + mockServer.Unlock() }) } @@ -40,11 +45,15 @@ func SetMockSSH(t *testing.T, opts SSHOpts) { }) } +var mockRepository sync.Mutex + func SetMockRepository(t *testing.T, opts RepositoryOpts) { + mockRepository.Lock() before := Repository Repository = opts t.Cleanup(func() { Repository = before + mockRepository.Unlock() }) } diff --git a/internal/db/pull.go b/internal/db/pull.go index e2f55361..b0f723fa 100644 --- a/internal/db/pull.go +++ b/internal/db/pull.go @@ -9,7 +9,6 @@ import ( "fmt" "os" "path/filepath" - "strings" "time" "github.com/unknwon/com" @@ -45,28 +44,28 @@ const ( // PullRequest represents relation between pull request and repositories. type PullRequest struct { - ID int64 + ID int64 `gorm:"primaryKey"` Type PullRequestType Status PullRequestStatus - IssueID int64 `xorm:"INDEX"` - Issue *Issue `xorm:"-" json:"-"` + IssueID int64 `xorm:"INDEX" gorm:"index"` + Issue *Issue `xorm:"-" json:"-" gorm:"-"` Index int64 HeadRepoID int64 - HeadRepo *Repository `xorm:"-" json:"-"` + HeadRepo *Repository `xorm:"-" json:"-" gorm:"-"` BaseRepoID int64 - BaseRepo *Repository `xorm:"-" json:"-"` + BaseRepo *Repository `xorm:"-" json:"-" gorm:"-"` HeadUserName string HeadBranch string BaseBranch string - MergeBase string `xorm:"VARCHAR(40)"` + MergeBase string `xorm:"VARCHAR(40)" gorm:"type:VARCHAR(40)"` HasMerged bool - MergedCommitID string `xorm:"VARCHAR(40)"` + MergedCommitID string `xorm:"VARCHAR(40)" gorm:"type:VARCHAR(40)"` MergerID int64 - Merger *User `xorm:"-" json:"-"` - Merged time.Time `xorm:"-" json:"-"` + Merger *User `xorm:"-" json:"-" gorm:"-"` + Merged time.Time `xorm:"-" json:"-" gorm:"-"` MergedUnix int64 } @@ -823,14 +822,6 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool } } -func ChangeUsernameInPullRequests(oldUserName, newUserName string) error { - pr := PullRequest{ - HeadUserName: strings.ToLower(newUserName), - } - _, err := x.Cols("head_user_name").Where("head_user_name = ?", strings.ToLower(oldUserName)).Update(pr) - return err -} - // checkAndUpdateStatus checks if pull request is possible to leaving checking status, // and set to be either conflict or mergeable. func (pr *PullRequest) checkAndUpdateStatus() { diff --git a/internal/db/repo.go b/internal/db/repo.go index f9e19468..8abe47ed 100644 --- a/internal/db/repo.go +++ b/internal/db/repo.go @@ -1444,7 +1444,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error return fmt.Errorf("rename repository directory: %v", err) } - deleteRepoLocalCopy(repo) + deleteRepoLocalCopy(repo.ID) // Rename remote wiki repository to new path and delete local copy. wikiPath := WikiPath(owner.Name, repo.Name) @@ -1458,10 +1458,10 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error return sess.Commit() } -func deleteRepoLocalCopy(repo *Repository) { - repoWorkingPool.CheckIn(com.ToStr(repo.ID)) - defer repoWorkingPool.CheckOut(com.ToStr(repo.ID)) - RemoveAllWithNotice("Delete repository local copy", repo.LocalCopyPath()) +func deleteRepoLocalCopy(repoID int64) { + repoWorkingPool.CheckIn(com.ToStr(repoID)) + defer repoWorkingPool.CheckOut(com.ToStr(repoID)) + RemoveAllWithNotice(fmt.Sprintf("Delete repository %d local copy", repoID), repoutil.RepositoryLocalPath(repoID)) } // ChangeRepositoryName changes all corresponding setting from old repository name to new one. @@ -1497,7 +1497,7 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error) RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath()) } - deleteRepoLocalCopy(repo) + deleteRepoLocalCopy(repo.ID) return nil } diff --git a/internal/db/user.go b/internal/db/user.go index 922a340a..5d75bfca 100644 --- a/internal/db/user.go +++ b/internal/db/user.go @@ -12,7 +12,6 @@ import ( "strings" "time" - "github.com/unknwon/com" log "unknwon.dev/clog/v2" "xorm.io/xorm" @@ -57,40 +56,6 @@ func (u *User) getOrganizationCount(e Engine) (int64, error) { return e.Where("uid=?", u.ID).Count(new(OrgUser)) } -// ChangeUserName changes all corresponding setting from old user name to new one. -func ChangeUserName(u *User, newUserName string) (err error) { - if err = isUsernameAllowed(newUserName); err != nil { - return err - } - - if Users.IsUsernameUsed(context.TODO(), newUserName) { - return ErrUserAlreadyExist{args: errutil.Args{"name": newUserName}} - } - - if err = ChangeUsernameInPullRequests(u.Name, newUserName); err != nil { - return fmt.Errorf("ChangeUsernameInPullRequests: %v", err) - } - - // Delete all local copies of repositories and wikis the user owns. - if err = x.Where("owner_id=?", u.ID).Iterate(new(Repository), func(idx int, bean interface{}) error { - repo := bean.(*Repository) - deleteRepoLocalCopy(repo) - // TODO: By the same reasoning, shouldn't we also sync access to the local wiki path? - RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath()) - return nil - }); err != nil { - return fmt.Errorf("delete repository and wiki local copy: %v", err) - } - - // Rename or create user base directory - baseDir := repoutil.UserPath(u.Name) - newBaseDir := repoutil.UserPath(newUserName) - if com.IsExist(baseDir) { - return os.Rename(baseDir, newBaseDir) - } - return os.MkdirAll(newBaseDir, os.ModePerm) -} - func updateUser(e Engine, u *User) error { // Organization does not need email if !u.IsOrganization() { diff --git a/internal/db/users.go b/internal/db/users.go index f12eca09..12fa90a2 100644 --- a/internal/db/users.go +++ b/internal/db/users.go @@ -24,6 +24,7 @@ import ( "gogs.io/gogs/internal/dbutil" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/osutil" + "gogs.io/gogs/internal/repoutil" "gogs.io/gogs/internal/strutil" "gogs.io/gogs/internal/tool" "gogs.io/gogs/internal/userutil" @@ -45,11 +46,17 @@ type UsersStore interface { // When the "loginSourceID" is positive, it tries to authenticate via given // login source and creates a new user when not yet exists in the database. Authenticate(ctx context.Context, username, password string, loginSourceID int64) (*User, error) + // ChangeUsername changes the username of the given user and updates all + // references to the old username. It returns ErrNameNotAllowed if the given + // name or pattern of the name is not allowed as a username, or + // ErrUserAlreadyExist when another user with same name already exists. + ChangeUsername(ctx context.Context, userID int64, newUsername string) error // Count returns the total number of users. Count(ctx context.Context) int64 // Create creates a new user and persists to database. It returns - // ErrUserAlreadyExist when a user with same name already exists, or - // ErrEmailAlreadyUsed if the email has been used by another user. + // ErrNameNotAllowed if the given name or pattern of the name is not allowed as + // a username, or ErrUserAlreadyExist when a user with same name already exists, + // or ErrEmailAlreadyUsed if the email has been used by another user. Create(ctx context.Context, username, email string, opts CreateUserOptions) (*User, error) // DeleteCustomAvatar deletes the current user custom avatar and falls back to // use look up avatar by email. @@ -188,6 +195,81 @@ func (db *users) Authenticate(ctx context.Context, login, password string, login ) } +func (db *users) ChangeUsername(ctx context.Context, userID int64, newUsername string) error { + err := isUsernameAllowed(newUsername) + if err != nil { + return err + } + + if db.IsUsernameUsed(ctx, newUsername) { + return ErrUserAlreadyExist{ + args: errutil.Args{ + "name": newUsername, + }, + } + } + + user, err := db.GetByID(ctx, userID) + if err != nil { + return errors.Wrap(err, "get user") + } + + return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + err := tx.Model(&User{}). + Where("id = ?", user.ID). + Updates(map[string]any{ + "lower_name": strings.ToLower(newUsername), + "name": newUsername, + }).Error + if err != nil { + return errors.Wrap(err, "update user name") + } + + // Update all references to the user name in pull requests + err = tx.Model(&PullRequest{}). + Where("head_user_name = ?", user.LowerName). + Update("head_user_name", strings.ToLower(newUsername)). + Error + if err != nil { + return errors.Wrap(err, `update "pull_request.head_user_name"`) + } + + // Delete local copies of repositories and their wikis that are owned by the user + rows, err := tx.Model(&Repository{}).Where("owner_id = ?", user.ID).Rows() + if err != nil { + return errors.Wrap(err, "iterate repositories") + } + defer func() { _ = rows.Close() }() + + for rows.Next() { + var repo struct { + ID int64 + } + err = tx.ScanRows(rows, &repo) + if err != nil { + return errors.Wrap(err, "scan rows") + } + + deleteRepoLocalCopy(repo.ID) + RemoveAllWithNotice(fmt.Sprintf("Delete repository %d wiki local copy", repo.ID), repoutil.RepositoryLocalWikiPath(repo.ID)) + } + if err = rows.Err(); err != nil { + return errors.Wrap(err, "check rows.Err") + } + + // Rename user directory if exists + userPath := repoutil.UserPath(user.Name) + if osutil.IsExist(userPath) { + newUserPath := repoutil.UserPath(newUsername) + err = os.Rename(userPath, newUserPath) + if err != nil { + return errors.Wrap(err, "rename user directory") + } + } + return nil + }) +} + func (db *users) Count(ctx context.Context) int64 { var count int64 db.WithContext(ctx).Model(&User{}).Where("type = ?", UserTypeIndividual).Count(&count) diff --git a/internal/db/users_test.go b/internal/db/users_test.go index 40006330..697bad8f 100644 --- a/internal/db/users_test.go +++ b/internal/db/users_test.go @@ -8,6 +8,7 @@ import ( "context" "fmt" "os" + "path/filepath" "strings" "testing" "time" @@ -17,10 +18,12 @@ import ( "gorm.io/gorm" "gogs.io/gogs/internal/auth" + "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/dbtest" "gogs.io/gogs/internal/dbutil" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/osutil" + "gogs.io/gogs/internal/repoutil" "gogs.io/gogs/internal/userutil" "gogs.io/gogs/public" ) @@ -79,7 +82,7 @@ func TestUsers(t *testing.T) { } t.Parallel() - tables := []interface{}{new(User), new(EmailAddress), new(Repository), new(Follow)} + tables := []interface{}{new(User), new(EmailAddress), new(Repository), new(Follow), new(PullRequest)} db := &users{ DB: dbtest.NewDB(t, "users", tables...), } @@ -89,6 +92,7 @@ func TestUsers(t *testing.T) { test func(t *testing.T, db *users) }{ {"Authenticate", usersAuthenticate}, + {"ChangeUsername", usersChangeUsername}, {"Count", usersCount}, {"Create", usersCreate}, {"DeleteCustomAvatar", usersDeleteCustomAvatar}, @@ -212,6 +216,107 @@ func usersAuthenticate(t *testing.T, db *users) { }) } +func usersChangeUsername(t *testing.T, db *users) { + ctx := context.Background() + + alice, err := db.Create( + ctx, + "alice", + "alice@example.com", + CreateUserOptions{ + Activated: true, + }, + ) + require.NoError(t, err) + + t.Run("name not allowed", func(t *testing.T) { + err := db.ChangeUsername(ctx, alice.ID, "-") + wantErr := ErrNameNotAllowed{ + args: errutil.Args{ + "reason": "reserved", + "name": "-", + }, + } + assert.Equal(t, wantErr, err) + }) + + t.Run("name already exists", func(t *testing.T) { + err := db.ChangeUsername(ctx, alice.ID, alice.Name) + wantErr := ErrUserAlreadyExist{ + args: errutil.Args{ + "name": alice.Name, + }, + } + assert.Equal(t, wantErr, err) + }) + + tempRepositoryRoot := filepath.Join(os.TempDir(), "usersChangeUsername-tempRepositoryRoot") + conf.SetMockRepository( + t, + conf.RepositoryOpts{ + Root: tempRepositoryRoot, + }, + ) + err = os.RemoveAll(tempRepositoryRoot) + require.NoError(t, err) + defer func() { _ = os.RemoveAll(tempRepositoryRoot) }() + + tempServerAppDataPath := filepath.Join(os.TempDir(), "usersChangeUsername-tempServerAppDataPath") + conf.SetMockServer( + t, + conf.ServerOpts{ + AppDataPath: tempServerAppDataPath, + }, + ) + err = os.RemoveAll(tempServerAppDataPath) + require.NoError(t, err) + defer func() { _ = os.RemoveAll(tempServerAppDataPath) }() + + repo, err := NewReposStore(db.DB).Create( + ctx, + alice.ID, + CreateRepoOptions{ + Name: "test-repo-1", + }, + ) + require.NoError(t, err) + + // TODO: Use PullRequests.Create to replace SQL hack when the method is available. + err = db.Exec(`INSERT INTO pull_request (head_user_name) VALUES (?)`, alice.Name).Error + require.NoError(t, err) + + err = os.MkdirAll(repoutil.UserPath(alice.Name), os.ModePerm) + require.NoError(t, err) + err = os.MkdirAll(repoutil.RepositoryLocalPath(repo.ID), os.ModePerm) + require.NoError(t, err) + err = os.MkdirAll(repoutil.RepositoryLocalWikiPath(repo.ID), os.ModePerm) + require.NoError(t, err) + + // Make sure mock data is set up correctly + assert.True(t, osutil.IsExist(repoutil.UserPath(alice.Name))) + assert.True(t, osutil.IsExist(repoutil.RepositoryLocalPath(repo.ID))) + assert.True(t, osutil.IsExist(repoutil.RepositoryLocalWikiPath(repo.ID))) + + const newUsername = "alice-new" + err = db.ChangeUsername(ctx, alice.ID, newUsername) + require.NoError(t, err) + + // TODO: Use PullRequests.GetByID to replace SQL hack when the method is available. + var headUserName string + err = db.Select("head_user_name").Table("pull_request").Row().Scan(&headUserName) + require.NoError(t, err) + assert.Equal(t, headUserName, newUsername) + + assert.True(t, osutil.IsExist(repoutil.UserPath(newUsername))) + assert.False(t, osutil.IsExist(repoutil.UserPath(alice.Name))) + assert.False(t, osutil.IsExist(repoutil.RepositoryLocalPath(repo.ID))) + assert.False(t, osutil.IsExist(repoutil.RepositoryLocalWikiPath(repo.ID))) + + alice, err = db.GetByID(ctx, alice.ID) + require.NoError(t, err) + assert.Equal(t, newUsername, alice.Name) +} + func usersCount(t *testing.T, db *users) { ctx := context.Background() diff --git a/internal/repoutil/repoutil.go b/internal/repoutil/repoutil.go index 658f896f..bb5afc08 100644 --- a/internal/repoutil/repoutil.go +++ b/internal/repoutil/repoutil.go @@ -7,6 +7,7 @@ package repoutil import ( "fmt" "path/filepath" + "strconv" "strings" "gogs.io/gogs/internal/conf" @@ -60,3 +61,15 @@ func UserPath(user string) string { func RepositoryPath(owner, repo string) string { return filepath.Join(UserPath(owner), strings.ToLower(repo)+".git") } + +// RepositoryLocalPath returns the absolute path of the repository local copy +// with the given ID. +func RepositoryLocalPath(repoID int64) string { + return filepath.Join(conf.Server.AppDataPath, "tmp", "local-repo", strconv.FormatInt(repoID, 10)) +} + +// RepositoryLocalWikiPath returns the absolute path of the repository local +// wiki copy with the given ID. +func RepositoryLocalWikiPath(repoID int64) string { + return filepath.Join(conf.Server.AppDataPath, "tmp", "local-wiki", strconv.FormatInt(repoID, 10)) +} diff --git a/internal/repoutil/repoutil_test.go b/internal/repoutil/repoutil_test.go index 232ecc52..cd0e7e44 100644 --- a/internal/repoutil/repoutil_test.go +++ b/internal/repoutil/repoutil_test.go @@ -125,3 +125,39 @@ func TestRepositoryPath(t *testing.T) { want := "/home/git/gogs-repositories/alice/example.git" assert.Equal(t, want, got) } + +func TestRepositoryLocalPath(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Skipping testing on Windows") + return + } + + conf.SetMockServer( + t, + conf.ServerOpts{ + AppDataPath: "data", + }, + ) + + got := RepositoryLocalPath(1) + want := "data/tmp/local-repo/1" + assert.Equal(t, want, got) +} + +func TestRepositoryLocalWikiPath(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Skipping testing on Windows") + return + } + + conf.SetMockServer( + t, + conf.ServerOpts{ + AppDataPath: "data", + }, + ) + + got := RepositoryLocalWikiPath(1) + want := "data/tmp/local-wiki/1" + assert.Equal(t, want, got) +} diff --git a/internal/route/lfs/mocks_test.go b/internal/route/lfs/mocks_test.go index 3677261c..a1e89f85 100644 --- a/internal/route/lfs/mocks_test.go +++ b/internal/route/lfs/mocks_test.go @@ -2295,6 +2295,9 @@ type MockUsersStore struct { // AuthenticateFunc is an instance of a mock function object controlling // the behavior of the method Authenticate. AuthenticateFunc *UsersStoreAuthenticateFunc + // ChangeUsernameFunc is an instance of a mock function object + // controlling the behavior of the method ChangeUsername. + ChangeUsernameFunc *UsersStoreChangeUsernameFunc // CountFunc is an instance of a mock function object controlling the // behavior of the method Count. CountFunc *UsersStoreCountFunc @@ -2342,6 +2345,11 @@ func NewMockUsersStore() *MockUsersStore { return }, }, + ChangeUsernameFunc: &UsersStoreChangeUsernameFunc{ + defaultHook: func(context.Context, int64, string) (r0 error) { + return + }, + }, CountFunc: &UsersStoreCountFunc{ defaultHook: func(context.Context) (r0 int64) { return @@ -2414,6 +2422,11 @@ func NewStrictMockUsersStore() *MockUsersStore { panic("unexpected invocation of MockUsersStore.Authenticate") }, }, + ChangeUsernameFunc: &UsersStoreChangeUsernameFunc{ + defaultHook: func(context.Context, int64, string) error { + panic("unexpected invocation of MockUsersStore.ChangeUsername") + }, + }, CountFunc: &UsersStoreCountFunc{ defaultHook: func(context.Context) int64 { panic("unexpected invocation of MockUsersStore.Count") @@ -2484,6 +2497,9 @@ func NewMockUsersStoreFrom(i db.UsersStore) *MockUsersStore { AuthenticateFunc: &UsersStoreAuthenticateFunc{ defaultHook: i.Authenticate, }, + ChangeUsernameFunc: &UsersStoreChangeUsernameFunc{ + defaultHook: i.ChangeUsername, + }, CountFunc: &UsersStoreCountFunc{ defaultHook: i.Count, }, @@ -2637,6 +2653,114 @@ func (c UsersStoreAuthenticateFuncCall) Results() []interface{} { return []interface{}{c.Result0, c.Result1} } +// UsersStoreChangeUsernameFunc describes the behavior when the +// ChangeUsername method of the parent MockUsersStore instance is invoked. +type UsersStoreChangeUsernameFunc struct { + defaultHook func(context.Context, int64, string) error + hooks []func(context.Context, int64, string) error + history []UsersStoreChangeUsernameFuncCall + mutex sync.Mutex +} + +// ChangeUsername delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockUsersStore) ChangeUsername(v0 context.Context, v1 int64, v2 string) error { + r0 := m.ChangeUsernameFunc.nextHook()(v0, v1, v2) + m.ChangeUsernameFunc.appendCall(UsersStoreChangeUsernameFuncCall{v0, v1, v2, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the ChangeUsername +// method of the parent MockUsersStore instance is invoked and the hook +// queue is empty. +func (f *UsersStoreChangeUsernameFunc) SetDefaultHook(hook func(context.Context, int64, string) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// ChangeUsername method of the parent MockUsersStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *UsersStoreChangeUsernameFunc) PushHook(hook func(context.Context, int64, string) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *UsersStoreChangeUsernameFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, int64, string) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *UsersStoreChangeUsernameFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, int64, string) error { + return r0 + }) +} + +func (f *UsersStoreChangeUsernameFunc) nextHook() func(context.Context, int64, string) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *UsersStoreChangeUsernameFunc) appendCall(r0 UsersStoreChangeUsernameFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of UsersStoreChangeUsernameFuncCall objects +// describing the invocations of this function. +func (f *UsersStoreChangeUsernameFunc) History() []UsersStoreChangeUsernameFuncCall { + f.mutex.Lock() + history := make([]UsersStoreChangeUsernameFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// UsersStoreChangeUsernameFuncCall is an object that describes an +// invocation of method ChangeUsername on an instance of MockUsersStore. +type UsersStoreChangeUsernameFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int64 + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c UsersStoreChangeUsernameFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c UsersStoreChangeUsernameFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + // UsersStoreCountFunc describes the behavior when the Count method of the // parent MockUsersStore instance is invoked. type UsersStoreCountFunc struct { diff --git a/internal/route/org/setting.go b/internal/route/org/setting.go index 198012ef..f3e65b9b 100644 --- a/internal/route/org/setting.go +++ b/internal/route/org/setting.go @@ -7,6 +7,7 @@ package org import ( "strings" + "github.com/pkg/errors" log "unknwon.dev/clog/v2" "gogs.io/gogs/internal/auth" @@ -45,13 +46,13 @@ func SettingsPost(c *context.Context, f form.UpdateOrgSetting) { c.Data["OrgName"] = true c.RenderWithErr(c.Tr("form.username_been_taken"), SETTINGS_OPTIONS, &f) return - } else if err := db.ChangeUserName(org, f.Name); err != nil { + } else if err := db.Users.ChangeUsername(c.Req.Context(), org.ID, f.Name); err != nil { c.Data["OrgName"] = true switch { - case db.IsErrNameNotAllowed(err): + case db.IsErrNameNotAllowed(errors.Cause(err)): c.RenderWithErr(c.Tr("user.form.name_not_allowed", err.(db.ErrNameNotAllowed).Value()), SETTINGS_OPTIONS, &f) default: - c.Error(err, "change user name") + c.Error(err, "change organization name") } return } diff --git a/internal/route/user/setting.go b/internal/route/user/setting.go index c873aeaf..2924a8f0 100644 --- a/internal/route/user/setting.go +++ b/internal/route/user/setting.go @@ -71,13 +71,13 @@ func SettingsPost(c *context.Context, f form.UpdateProfile) { if c.User.IsLocal() { // Check if username characters have been changed if c.User.LowerName != strings.ToLower(f.Name) { - if err := db.ChangeUserName(c.User, f.Name); err != nil { + if err := db.Users.ChangeUsername(c.Req.Context(), c.User.ID, f.Name); err != nil { c.FormErr("Name") var msg string switch { - case db.IsErrUserAlreadyExist(err): + case db.IsErrUserAlreadyExist(errors.Cause(err)): msg = c.Tr("form.username_been_taken") - case db.IsErrNameNotAllowed(err): + case db.IsErrNameNotAllowed(errors.Cause(err)): msg = c.Tr("user.form.name_not_allowed", err.(db.ErrNameNotAllowed).Value()) default: c.Error(err, "change user name") |