mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Redirect on changed user and org name (#11649)
* Add redirect for user * Add redirect for orgs * Add user redirect test * Appease linter * Add comment to DeleteUserRedirect function * Fix locale changes * Fix GetUserByParams * Fix orgAssignment * Remove debug logging * Add redirect prompt * Dont Export DeleteUserRedirect & only use it within a session * Unexport newUserRedirect * cleanup * Fix & Dedub API code * Format Template * Add Migration & rm dublicat * Refactor: unexport newRepoRedirect() & rm dedub del exec * if this fails we'll need to re-rename the user directory Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
		@@ -146,6 +146,21 @@ func (err ErrUserNotExist) Error() string {
 | 
				
			|||||||
	return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
 | 
						return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrUserRedirectNotExist represents a "UserRedirectNotExist" kind of error.
 | 
				
			||||||
 | 
					type ErrUserRedirectNotExist struct {
 | 
				
			||||||
 | 
						Name string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsErrUserRedirectNotExist check if an error is an ErrUserRedirectNotExist.
 | 
				
			||||||
 | 
					func IsErrUserRedirectNotExist(err error) bool {
 | 
				
			||||||
 | 
						_, ok := err.(ErrUserRedirectNotExist)
 | 
				
			||||||
 | 
						return ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (err ErrUserRedirectNotExist) Error() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("user redirect does not exist [name: %s]", err.Name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrUserProhibitLogin represents a "ErrUserProhibitLogin" kind of error.
 | 
					// ErrUserProhibitLogin represents a "ErrUserProhibitLogin" kind of error.
 | 
				
			||||||
type ErrUserProhibitLogin struct {
 | 
					type ErrUserProhibitLogin struct {
 | 
				
			||||||
	UID  int64
 | 
						UID  int64
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								models/fixtures/user_redirect.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								models/fixtures/user_redirect.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					-
 | 
				
			||||||
 | 
					  id: 1
 | 
				
			||||||
 | 
					  lower_name: olduser1
 | 
				
			||||||
 | 
					  redirect_user_id: 1
 | 
				
			||||||
@@ -279,6 +279,8 @@ var migrations = []Migration{
 | 
				
			|||||||
	NewMigration("Convert hook task type from char(16) to varchar(16) and trim the column", convertHookTaskTypeToVarcharAndTrim),
 | 
						NewMigration("Convert hook task type from char(16) to varchar(16) and trim the column", convertHookTaskTypeToVarcharAndTrim),
 | 
				
			||||||
	// v166 -> v167
 | 
						// v166 -> v167
 | 
				
			||||||
	NewMigration("Where Password is Valid with Empty String delete it", recalculateUserEmptyPWD),
 | 
						NewMigration("Where Password is Valid with Empty String delete it", recalculateUserEmptyPWD),
 | 
				
			||||||
 | 
						// v167 -> v168
 | 
				
			||||||
 | 
						NewMigration("Add user redirect", addUserRedirect),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetCurrentDBVersion returns the current db version
 | 
					// GetCurrentDBVersion returns the current db version
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								models/migrations/v167.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								models/migrations/v167.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					// Copyright 2021 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package migrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"xorm.io/xorm"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func addUserRedirect(x *xorm.Engine) (err error) {
 | 
				
			||||||
 | 
						type UserRedirect struct {
 | 
				
			||||||
 | 
							ID             int64  `xorm:"pk autoincr"`
 | 
				
			||||||
 | 
							LowerName      string `xorm:"UNIQUE(s) INDEX NOT NULL"`
 | 
				
			||||||
 | 
							RedirectUserID int64
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := x.Sync2(new(UserRedirect)); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("Sync2: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -128,6 +128,7 @@ func init() {
 | 
				
			|||||||
		new(Task),
 | 
							new(Task),
 | 
				
			||||||
		new(LanguageStat),
 | 
							new(LanguageStat),
 | 
				
			||||||
		new(EmailHash),
 | 
							new(EmailHash),
 | 
				
			||||||
 | 
							new(UserRedirect),
 | 
				
			||||||
		new(Project),
 | 
							new(Project),
 | 
				
			||||||
		new(ProjectBoard),
 | 
							new(ProjectBoard),
 | 
				
			||||||
		new(ProjectIssue),
 | 
							new(ProjectIssue),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -171,6 +171,10 @@ func CreateOrganization(org, owner *User) (err error) {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = deleteUserRedirect(sess, org.Name); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err = sess.Insert(org); err != nil {
 | 
						if _, err = sess.Insert(org); err != nil {
 | 
				
			||||||
		return fmt.Errorf("insert organization: %v", err)
 | 
							return fmt.Errorf("insert organization: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1312,8 +1312,8 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
 | 
				
			|||||||
		return fmt.Errorf("delete repo redirect: %v", err)
 | 
							return fmt.Errorf("delete repo redirect: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := NewRepoRedirect(DBContext{sess}, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
 | 
						if err := newRepoRedirect(sess, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
 | 
				
			||||||
		return fmt.Errorf("NewRepoRedirect: %v", err)
 | 
							return fmt.Errorf("newRepoRedirect: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sess.Commit()
 | 
						return sess.Commit()
 | 
				
			||||||
@@ -1361,12 +1361,7 @@ func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err
 | 
				
			|||||||
		return fmt.Errorf("sess.Begin: %v", err)
 | 
							return fmt.Errorf("sess.Begin: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If there was previously a redirect at this location, remove it.
 | 
						if err := newRepoRedirect(sess, repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
 | 
				
			||||||
	if err = deleteRepoRedirect(sess, repo.OwnerID, newRepoName); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("delete repo redirect: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := NewRepoRedirect(DBContext{sess}, repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,16 +28,16 @@ func LookupRepoRedirect(ownerID int64, repoName string) (int64, error) {
 | 
				
			|||||||
	return redirect.RedirectRepoID, nil
 | 
						return redirect.RedirectRepoID, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewRepoRedirect create a new repo redirect
 | 
					// newRepoRedirect create a new repo redirect
 | 
				
			||||||
func NewRepoRedirect(ctx DBContext, ownerID, repoID int64, oldRepoName, newRepoName string) error {
 | 
					func newRepoRedirect(e Engine, ownerID, repoID int64, oldRepoName, newRepoName string) error {
 | 
				
			||||||
	oldRepoName = strings.ToLower(oldRepoName)
 | 
						oldRepoName = strings.ToLower(oldRepoName)
 | 
				
			||||||
	newRepoName = strings.ToLower(newRepoName)
 | 
						newRepoName = strings.ToLower(newRepoName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := deleteRepoRedirect(ctx.e, ownerID, newRepoName); err != nil {
 | 
						if err := deleteRepoRedirect(e, ownerID, newRepoName); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := ctx.e.Insert(&RepoRedirect{
 | 
						if _, err := e.Insert(&RepoRedirect{
 | 
				
			||||||
		OwnerID:        ownerID,
 | 
							OwnerID:        ownerID,
 | 
				
			||||||
		LowerName:      oldRepoName,
 | 
							LowerName:      oldRepoName,
 | 
				
			||||||
		RedirectRepoID: repoID,
 | 
							RedirectRepoID: repoID,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ func TestNewRepoRedirect(t *testing.T) {
 | 
				
			|||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
						repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
				
			||||||
	assert.NoError(t, NewRepoRedirect(DefaultDBContext(), repo.OwnerID, repo.ID, repo.Name, "newreponame"))
 | 
						assert.NoError(t, newRepoRedirect(x, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AssertExistsAndLoadBean(t, &RepoRedirect{
 | 
						AssertExistsAndLoadBean(t, &RepoRedirect{
 | 
				
			||||||
		OwnerID:        repo.OwnerID,
 | 
							OwnerID:        repo.OwnerID,
 | 
				
			||||||
@@ -45,7 +45,7 @@ func TestNewRepoRedirect2(t *testing.T) {
 | 
				
			|||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
						repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
				
			||||||
	assert.NoError(t, NewRepoRedirect(DefaultDBContext(), repo.OwnerID, repo.ID, repo.Name, "oldrepo1"))
 | 
						assert.NoError(t, newRepoRedirect(x, repo.OwnerID, repo.ID, repo.Name, "oldrepo1"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AssertExistsAndLoadBean(t, &RepoRedirect{
 | 
						AssertExistsAndLoadBean(t, &RepoRedirect{
 | 
				
			||||||
		OwnerID:        repo.OwnerID,
 | 
							OwnerID:        repo.OwnerID,
 | 
				
			||||||
@@ -64,7 +64,7 @@ func TestNewRepoRedirect3(t *testing.T) {
 | 
				
			|||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
 | 
						repo := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
 | 
				
			||||||
	assert.NoError(t, NewRepoRedirect(DefaultDBContext(), repo.OwnerID, repo.ID, repo.Name, "newreponame"))
 | 
						assert.NoError(t, newRepoRedirect(x, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AssertExistsAndLoadBean(t, &RepoRedirect{
 | 
						AssertExistsAndLoadBean(t, &RepoRedirect{
 | 
				
			||||||
		OwnerID:        repo.OwnerID,
 | 
							OwnerID:        repo.OwnerID,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -863,6 +863,10 @@ func CreateUser(u *User) (err error) {
 | 
				
			|||||||
		return ErrUserAlreadyExist{u.Name}
 | 
							return ErrUserAlreadyExist{u.Name}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = deleteUserRedirect(sess, u.Name); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u.Email = strings.ToLower(u.Email)
 | 
						u.Email = strings.ToLower(u.Email)
 | 
				
			||||||
	isExist, err = sess.
 | 
						isExist, err = sess.
 | 
				
			||||||
		Where("email=?", u.Email).
 | 
							Where("email=?", u.Email).
 | 
				
			||||||
@@ -973,6 +977,7 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ChangeUserName changes all corresponding setting from old user name to new one.
 | 
					// ChangeUserName changes all corresponding setting from old user name to new one.
 | 
				
			||||||
func ChangeUserName(u *User, newUserName string) (err error) {
 | 
					func ChangeUserName(u *User, newUserName string) (err error) {
 | 
				
			||||||
 | 
						oldUserName := u.Name
 | 
				
			||||||
	if err = IsUsableUsername(newUserName); err != nil {
 | 
						if err = IsUsableUsername(newUserName); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -990,16 +995,28 @@ func ChangeUserName(u *User, newUserName string) (err error) {
 | 
				
			|||||||
		return ErrUserAlreadyExist{newUserName}
 | 
							return ErrUserAlreadyExist{newUserName}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, u.Name); err != nil {
 | 
						if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, oldUserName); err != nil {
 | 
				
			||||||
		return fmt.Errorf("Change repo owner name: %v", err)
 | 
							return fmt.Errorf("Change repo owner name: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Do not fail if directory does not exist
 | 
						// Do not fail if directory does not exist
 | 
				
			||||||
	if err = os.Rename(UserPath(u.Name), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
 | 
						if err = os.Rename(UserPath(oldUserName), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
 | 
				
			||||||
		return fmt.Errorf("Rename user directory: %v", err)
 | 
							return fmt.Errorf("Rename user directory: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sess.Commit()
 | 
						if err = newUserRedirect(sess, u.ID, oldUserName, newUserName); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = sess.Commit(); err != nil {
 | 
				
			||||||
 | 
							if err2 := os.Rename(UserPath(newUserName), UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) {
 | 
				
			||||||
 | 
								log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2)
 | 
				
			||||||
 | 
								return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// checkDupEmail checks whether there are the same email with the user
 | 
					// checkDupEmail checks whether there are the same email with the user
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										52
									
								
								models/user_redirect.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								models/user_redirect.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UserRedirect represents that a user name should be redirected to another
 | 
				
			||||||
 | 
					type UserRedirect struct {
 | 
				
			||||||
 | 
						ID             int64  `xorm:"pk autoincr"`
 | 
				
			||||||
 | 
						LowerName      string `xorm:"UNIQUE(s) INDEX NOT NULL"`
 | 
				
			||||||
 | 
						RedirectUserID int64  // userID to redirect to
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LookupUserRedirect look up userID if a user has a redirect name
 | 
				
			||||||
 | 
					func LookupUserRedirect(userName string) (int64, error) {
 | 
				
			||||||
 | 
						userName = strings.ToLower(userName)
 | 
				
			||||||
 | 
						redirect := &UserRedirect{LowerName: userName}
 | 
				
			||||||
 | 
						if has, err := x.Get(redirect); err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						} else if !has {
 | 
				
			||||||
 | 
							return 0, ErrUserRedirectNotExist{Name: userName}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return redirect.RedirectUserID, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// newUserRedirect create a new user redirect
 | 
				
			||||||
 | 
					func newUserRedirect(e Engine, ID int64, oldUserName, newUserName string) error {
 | 
				
			||||||
 | 
						oldUserName = strings.ToLower(oldUserName)
 | 
				
			||||||
 | 
						newUserName = strings.ToLower(newUserName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := deleteUserRedirect(e, newUserName); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := e.Insert(&UserRedirect{
 | 
				
			||||||
 | 
							LowerName:      oldUserName,
 | 
				
			||||||
 | 
							RedirectUserID: ID,
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// deleteUserRedirect delete any redirect from the specified user name to
 | 
				
			||||||
 | 
					// anything else
 | 
				
			||||||
 | 
					func deleteUserRedirect(e Engine, userName string) error {
 | 
				
			||||||
 | 
						userName = strings.ToLower(userName)
 | 
				
			||||||
 | 
						_, err := e.Delete(&UserRedirect{LowerName: userName})
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										69
									
								
								models/user_redirect_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								models/user_redirect_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLookupUserRedirect(t *testing.T) {
 | 
				
			||||||
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						userID, err := LookupUserRedirect("olduser1")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.EqualValues(t, 1, userID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = LookupUserRedirect("doesnotexist")
 | 
				
			||||||
 | 
						assert.True(t, IsErrUserRedirectNotExist(err))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNewUserRedirect(t *testing.T) {
 | 
				
			||||||
 | 
						// redirect to a completely new name
 | 
				
			||||||
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
 | 
				
			||||||
 | 
						assert.NoError(t, newUserRedirect(x, user.ID, user.Name, "newusername"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AssertExistsAndLoadBean(t, &UserRedirect{
 | 
				
			||||||
 | 
							LowerName:      user.LowerName,
 | 
				
			||||||
 | 
							RedirectUserID: user.ID,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						AssertExistsAndLoadBean(t, &UserRedirect{
 | 
				
			||||||
 | 
							LowerName:      "olduser1",
 | 
				
			||||||
 | 
							RedirectUserID: user.ID,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNewUserRedirect2(t *testing.T) {
 | 
				
			||||||
 | 
						// redirect to previously used name
 | 
				
			||||||
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
 | 
				
			||||||
 | 
						assert.NoError(t, newUserRedirect(x, user.ID, user.Name, "olduser1"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AssertExistsAndLoadBean(t, &UserRedirect{
 | 
				
			||||||
 | 
							LowerName:      user.LowerName,
 | 
				
			||||||
 | 
							RedirectUserID: user.ID,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						AssertNotExistsBean(t, &UserRedirect{
 | 
				
			||||||
 | 
							LowerName:      "olduser1",
 | 
				
			||||||
 | 
							RedirectUserID: user.ID,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNewUserRedirect3(t *testing.T) {
 | 
				
			||||||
 | 
						// redirect for a previously-unredirected user
 | 
				
			||||||
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 | 
				
			||||||
 | 
						assert.NoError(t, newUserRedirect(x, user.ID, user.Name, "newusername"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AssertExistsAndLoadBean(t, &UserRedirect{
 | 
				
			||||||
 | 
							LowerName:      user.LowerName,
 | 
				
			||||||
 | 
							RedirectUserID: user.ID,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -90,6 +90,26 @@ func (ctx *Context) IsUserRepoReaderAny() bool {
 | 
				
			|||||||
	return ctx.Repo.HasAccess()
 | 
						return ctx.Repo.HasAccess()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RedirectToUser redirect to a differently-named user
 | 
				
			||||||
 | 
					func RedirectToUser(ctx *Context, userName string, redirectUserID int64) {
 | 
				
			||||||
 | 
						user, err := models.GetUserByID(redirectUserID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.ServerError("GetUserByID", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						redirectPath := strings.Replace(
 | 
				
			||||||
 | 
							ctx.Req.URL.Path,
 | 
				
			||||||
 | 
							userName,
 | 
				
			||||||
 | 
							user.Name,
 | 
				
			||||||
 | 
							1,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if ctx.Req.URL.RawQuery != "" {
 | 
				
			||||||
 | 
							redirectPath += "?" + ctx.Req.URL.RawQuery
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// HasAPIError returns true if error occurs in form validation.
 | 
					// HasAPIError returns true if error occurs in form validation.
 | 
				
			||||||
func (ctx *Context) HasAPIError() bool {
 | 
					func (ctx *Context) HasAPIError() bool {
 | 
				
			||||||
	hasErr, ok := ctx.Data["HasError"]
 | 
						hasErr, ok := ctx.Data["HasError"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,14 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 | 
				
			|||||||
	ctx.Org.Organization, err = models.GetUserByName(orgName)
 | 
						ctx.Org.Organization, err = models.GetUserByName(orgName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if models.IsErrUserNotExist(err) {
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
								redirectUserID, err := models.LookupUserRedirect(orgName)
 | 
				
			||||||
 | 
								if err == nil {
 | 
				
			||||||
 | 
									RedirectToUser(ctx, orgName, redirectUserID)
 | 
				
			||||||
 | 
								} else if models.IsErrUserRedirectNotExist(err) {
 | 
				
			||||||
				ctx.NotFound("GetUserByName", err)
 | 
									ctx.NotFound("GetUserByName", err)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ctx.ServerError("LookupUserRedirect", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ctx.ServerError("GetUserByName", err)
 | 
								ctx.ServerError("GetUserByName", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -411,11 +411,18 @@ func RepoAssignment() macaron.Handler {
 | 
				
			|||||||
			owner, err = models.GetUserByName(userName)
 | 
								owner, err = models.GetUserByName(userName)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				if models.IsErrUserNotExist(err) {
 | 
									if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
										redirectUserID, err := models.LookupUserRedirect(userName)
 | 
				
			||||||
 | 
										if err == nil {
 | 
				
			||||||
 | 
											RedirectToUser(ctx, userName, redirectUserID)
 | 
				
			||||||
 | 
										} else if models.IsErrUserRedirectNotExist(err) {
 | 
				
			||||||
						if ctx.Query("go-get") == "1" {
 | 
											if ctx.Query("go-get") == "1" {
 | 
				
			||||||
							EarlyResponseForGoGetMeta(ctx)
 | 
												EarlyResponseForGoGetMeta(ctx)
 | 
				
			||||||
							return
 | 
												return
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						ctx.NotFound("GetUserByName", nil)
 | 
											ctx.NotFound("GetUserByName", nil)
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											ctx.ServerError("LookupUserRedirect", err)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					ctx.ServerError("GetUserByName", err)
 | 
										ctx.ServerError("GetUserByName", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -450,6 +450,7 @@ update_language_not_found = Language '%s' is not available.
 | 
				
			|||||||
update_profile_success = Your profile has been updated.
 | 
					update_profile_success = Your profile has been updated.
 | 
				
			||||||
change_username = Your username has been changed.
 | 
					change_username = Your username has been changed.
 | 
				
			||||||
change_username_prompt = Note: username changes also change your account URL.
 | 
					change_username_prompt = Note: username changes also change your account URL.
 | 
				
			||||||
 | 
					change_username_redirect_prompt = The old username will redirect until it is claimed.
 | 
				
			||||||
continue = Continue
 | 
					continue = Continue
 | 
				
			||||||
cancel = Cancel
 | 
					cancel = Cancel
 | 
				
			||||||
language = Language
 | 
					language = Language
 | 
				
			||||||
@@ -1941,6 +1942,7 @@ settings.visibility.private_shortname = Private
 | 
				
			|||||||
settings.update_settings = Update Settings
 | 
					settings.update_settings = Update Settings
 | 
				
			||||||
settings.update_setting_success = Organization settings have been updated.
 | 
					settings.update_setting_success = Organization settings have been updated.
 | 
				
			||||||
settings.change_orgname_prompt = Note: changing the organization name also changes the organization's URL.
 | 
					settings.change_orgname_prompt = Note: changing the organization name also changes the organization's URL.
 | 
				
			||||||
 | 
					settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed.
 | 
				
			||||||
settings.update_avatar_success = The organization's avatar has been updated.
 | 
					settings.update_avatar_success = The organization's avatar has been updated.
 | 
				
			||||||
settings.delete = Delete Organization
 | 
					settings.delete = Delete Organization
 | 
				
			||||||
settings.delete_account = Delete This Organization
 | 
					settings.delete_account = Delete This Organization
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,7 +134,13 @@ func repoAssignment() macaron.Handler {
 | 
				
			|||||||
			owner, err = models.GetUserByName(userName)
 | 
								owner, err = models.GetUserByName(userName)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				if models.IsErrUserNotExist(err) {
 | 
									if models.IsErrUserNotExist(err) {
 | 
				
			||||||
					ctx.NotFound()
 | 
										if redirectUserID, err := models.LookupUserRedirect(userName); err == nil {
 | 
				
			||||||
 | 
											context.RedirectToUser(ctx.Context, userName, redirectUserID)
 | 
				
			||||||
 | 
										} else if models.IsErrUserRedirectNotExist(err) {
 | 
				
			||||||
 | 
											ctx.NotFound("GetUserByName", err)
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											ctx.Error(http.StatusInternalServerError, "LookupUserRedirect", err)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
 | 
										ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -393,7 +399,14 @@ func orgAssignment(args ...bool) macaron.Handler {
 | 
				
			|||||||
			ctx.Org.Organization, err = models.GetOrgByName(ctx.Params(":org"))
 | 
								ctx.Org.Organization, err = models.GetOrgByName(ctx.Params(":org"))
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				if models.IsErrOrgNotExist(err) {
 | 
									if models.IsErrOrgNotExist(err) {
 | 
				
			||||||
					ctx.NotFound()
 | 
										redirectUserID, err := models.LookupUserRedirect(ctx.Params(":org"))
 | 
				
			||||||
 | 
										if err == nil {
 | 
				
			||||||
 | 
											context.RedirectToUser(ctx.Context, ctx.Params(":org"), redirectUserID)
 | 
				
			||||||
 | 
										} else if models.IsErrUserRedirectNotExist(err) {
 | 
				
			||||||
 | 
											ctx.NotFound("GetOrgByName", err)
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											ctx.Error(http.StatusInternalServerError, "LookupUserRedirect", err)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)
 | 
										ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								routers/api/v1/user/helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								routers/api/v1/user/helper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					// Copyright 2021 The Gitea Authors.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetUserByParamsName get user by name
 | 
				
			||||||
 | 
					func GetUserByParamsName(ctx *context.APIContext, name string) *models.User {
 | 
				
			||||||
 | 
						username := ctx.Params(name)
 | 
				
			||||||
 | 
						user, err := models.GetUserByName(username)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
								if redirectUserID, err := models.LookupUserRedirect(username); err == nil {
 | 
				
			||||||
 | 
									context.RedirectToUser(ctx.Context, username, redirectUserID)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ctx.NotFound("GetUserByName", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return user
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetUserByParams returns user whose name is presented in URL (":username").
 | 
				
			||||||
 | 
					func GetUserByParams(ctx *context.APIContext) *models.User {
 | 
				
			||||||
 | 
						return GetUserByParamsName(ctx, ":username")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -39,25 +39,6 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defa
 | 
				
			|||||||
	return apiKey, nil
 | 
						return apiKey, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetUserByParamsName get user by name
 | 
					 | 
				
			||||||
func GetUserByParamsName(ctx *context.APIContext, name string) *models.User {
 | 
					 | 
				
			||||||
	user, err := models.GetUserByName(ctx.Params(name))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if models.IsErrUserNotExist(err) {
 | 
					 | 
				
			||||||
			ctx.NotFound()
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return user
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetUserByParams returns user whose name is presented in URL paramenter.
 | 
					 | 
				
			||||||
func GetUserByParams(ctx *context.APIContext) *models.User {
 | 
					 | 
				
			||||||
	return GetUserByParamsName(ctx, ":username")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func composePublicKeysAPILink() string {
 | 
					func composePublicKeysAPILink() string {
 | 
				
			||||||
	return setting.AppURL + "api/v1/user/keys/"
 | 
						return setting.AppURL + "api/v1/user/keys/"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,13 +107,8 @@ func GetInfo(ctx *context.APIContext) {
 | 
				
			|||||||
	//   "404":
 | 
						//   "404":
 | 
				
			||||||
	//     "$ref": "#/responses/notFound"
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u, err := models.GetUserByName(ctx.Params(":username"))
 | 
						u := GetUserByParams(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if ctx.Written() {
 | 
				
			||||||
		if models.IsErrUserNotExist(err) {
 | 
					 | 
				
			||||||
			ctx.NotFound()
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -153,14 +148,8 @@ func GetUserHeatmapData(ctx *context.APIContext) {
 | 
				
			|||||||
	//   "404":
 | 
						//   "404":
 | 
				
			||||||
	//     "$ref": "#/responses/notFound"
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get the user to throw an error if it does not exist
 | 
						user := GetUserByParams(ctx)
 | 
				
			||||||
	user, err := models.GetUserByName(ctx.Params(":username"))
 | 
						if ctx.Written() {
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if models.IsErrUserNotExist(err) {
 | 
					 | 
				
			||||||
			ctx.Status(http.StatusNotFound)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,8 +102,15 @@ func HTTP(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	owner, err := models.GetUserByName(username)
 | 
						owner, err := models.GetUserByName(username)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error("Attempted access of unknown user from %s", ctx.RemoteAddr())
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
		ctx.NotFoundOrServerError("GetUserByName", models.IsErrUserNotExist, err)
 | 
								if redirectUserID, err := models.LookupUserRedirect(username); err == nil {
 | 
				
			||||||
 | 
									context.RedirectToUser(ctx, username, redirectUserID)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ctx.NotFound("GetUserByName", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ctx.ServerError("GetUserByName", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !owner.IsOrganization() && !owner.IsActive {
 | 
						if !owner.IsOrganization() && !owner.IsActive {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,11 @@ func GetUserByName(ctx *context.Context, name string) *models.User {
 | 
				
			|||||||
	user, err := models.GetUserByName(name)
 | 
						user, err := models.GetUserByName(name)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if models.IsErrUserNotExist(err) {
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
			ctx.NotFound("GetUserByName", nil)
 | 
								if redirectUserID, err := models.LookupUserRedirect(name); err == nil {
 | 
				
			||||||
 | 
									context.RedirectToUser(ctx, name, redirectUserID)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ctx.NotFound("GetUserByName", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ctx.ServerError("GetUserByName", err)
 | 
								ctx.ServerError("GetUserByName", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,10 @@
 | 
				
			|||||||
					<form class="ui form" action="{{.Link}}" method="post">
 | 
										<form class="ui form" action="{{.Link}}" method="post">
 | 
				
			||||||
						{{.CsrfTokenHtml}}
 | 
											{{.CsrfTokenHtml}}
 | 
				
			||||||
						<div class="required field {{if .Err_Name}}error{{end}}">
 | 
											<div class="required field {{if .Err_Name}}error{{end}}">
 | 
				
			||||||
							<label for="org_name">{{.i18n.Tr "org.org_name_holder"}}<span class="text red hide" id="org-name-change-prompt"> {{.i18n.Tr "org.settings.change_orgname_prompt"}}</span></label>
 | 
												<label for="org_name">{{.i18n.Tr "org.org_name_holder"}}
 | 
				
			||||||
 | 
													<span class="text red hide" id="org-name-change-prompt"> {{.i18n.Tr "org.settings.change_orgname_prompt"}}</span>
 | 
				
			||||||
 | 
													<span class="text red hide" id="org-name-change-redirect-prompt"> {{.i18n.Tr "org.settings.change_orgname_redirect_prompt"}}</span>
 | 
				
			||||||
 | 
												</label>
 | 
				
			||||||
							<input id="org_name" name="name" value="{{.Org.Name}}" data-org-name="{{.Org.Name}}" autofocus required>
 | 
												<input id="org_name" name="name" value="{{.Org.Name}}" data-org-name="{{.Org.Name}}" autofocus required>
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
						<div class="field {{if .Err_FullName}}error{{end}}">
 | 
											<div class="field {{if .Err_FullName}}error{{end}}">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,10 @@
 | 
				
			|||||||
			<form class="ui form" action="{{.Link}}" method="post">
 | 
								<form class="ui form" action="{{.Link}}" method="post">
 | 
				
			||||||
				{{.CsrfTokenHtml}}
 | 
									{{.CsrfTokenHtml}}
 | 
				
			||||||
				<div class="required field {{if .Err_Name}}error{{end}}">
 | 
									<div class="required field {{if .Err_Name}}error{{end}}">
 | 
				
			||||||
					<label for="username">{{.i18n.Tr "username"}}<span class="text red hide" id="name-change-prompt"> {{.i18n.Tr "settings.change_username_prompt"}}</span></label>
 | 
										<label for="username">{{.i18n.Tr "username"}}
 | 
				
			||||||
 | 
											<span class="text red hide" id="name-change-prompt"> {{.i18n.Tr "settings.change_username_prompt"}}</span>
 | 
				
			||||||
 | 
											<span class="text red hide" id="name-change-redirect-prompt"> {{.i18n.Tr "settings.change_username_redirect_prompt"}}</span>
 | 
				
			||||||
 | 
										</label>
 | 
				
			||||||
					<input id="username" name="name" value="{{.SignedUser.Name}}" data-name="{{.SignedUser.Name}}" autofocus required {{if not .SignedUser.IsLocal}}disabled{{end}}>
 | 
										<input id="username" name="name" value="{{.SignedUser.Name}}" data-name="{{.SignedUser.Name}}" autofocus required {{if not .SignedUser.IsLocal}}disabled{{end}}>
 | 
				
			||||||
					{{if not .SignedUser.IsLocal}}
 | 
										{{if not .SignedUser.IsLocal}}
 | 
				
			||||||
					<p class="help text blue">{{$.i18n.Tr "settings.password_username_disabled"}}</p>
 | 
										<p class="help text blue">{{$.i18n.Tr "settings.password_username_disabled"}}</p>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1736,10 +1736,13 @@ function initOrganization() {
 | 
				
			|||||||
  if ($('.organization.settings.options').length > 0) {
 | 
					  if ($('.organization.settings.options').length > 0) {
 | 
				
			||||||
    $('#org_name').on('keyup', function () {
 | 
					    $('#org_name').on('keyup', function () {
 | 
				
			||||||
      const $prompt = $('#org-name-change-prompt');
 | 
					      const $prompt = $('#org-name-change-prompt');
 | 
				
			||||||
 | 
					      const $prompt_redirect = $('#org-name-change-redirect-prompt');
 | 
				
			||||||
      if ($(this).val().toString().toLowerCase() !== $(this).data('org-name').toString().toLowerCase()) {
 | 
					      if ($(this).val().toString().toLowerCase() !== $(this).data('org-name').toString().toLowerCase()) {
 | 
				
			||||||
        $prompt.show();
 | 
					        $prompt.show();
 | 
				
			||||||
 | 
					        $prompt_redirect.show();
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        $prompt.hide();
 | 
					        $prompt.hide();
 | 
				
			||||||
 | 
					        $prompt_redirect.hide();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -1755,10 +1758,13 @@ function initUserSettings() {
 | 
				
			|||||||
  if ($('.user.settings.profile').length > 0) {
 | 
					  if ($('.user.settings.profile').length > 0) {
 | 
				
			||||||
    $('#username').on('keyup', function () {
 | 
					    $('#username').on('keyup', function () {
 | 
				
			||||||
      const $prompt = $('#name-change-prompt');
 | 
					      const $prompt = $('#name-change-prompt');
 | 
				
			||||||
 | 
					      const $prompt_redirect = $('#name-change-redirect-prompt');
 | 
				
			||||||
      if ($(this).val().toString().toLowerCase() !== $(this).data('name').toString().toLowerCase()) {
 | 
					      if ($(this).val().toString().toLowerCase() !== $(this).data('name').toString().toLowerCase()) {
 | 
				
			||||||
        $prompt.show();
 | 
					        $prompt.show();
 | 
				
			||||||
 | 
					        $prompt_redirect.show();
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        $prompt.hide();
 | 
					        $prompt.hide();
 | 
				
			||||||
 | 
					        $prompt_redirect.hide();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user