mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Remove unnecessary attributes of User struct (#17745)
* Remove unnecessary functions of User struct * Move more database methods out of user struct * Move more database methods out of user struct * Fix template failure * Fix bug * Remove finished FIXME * remove unnecessary code
This commit is contained in:
		@@ -366,7 +366,7 @@ func runChangePassword(c *cli.Context) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = models.UpdateUserCols(user, "passwd", "passwd_hash_algo", "salt"); err != nil {
 | 
						if err = models.UpdateUserCols(db.DefaultContext, user, "passwd", "passwd_hash_algo", "salt"); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,66 +105,6 @@ func accessLevel(e db.Engine, user *User, repo *Repository) (AccessMode, error)
 | 
				
			|||||||
	return a.Mode, nil
 | 
						return a.Mode, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type repoAccess struct {
 | 
					 | 
				
			||||||
	Access     `xorm:"extends"`
 | 
					 | 
				
			||||||
	Repository `xorm:"extends"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (repoAccess) TableName() string {
 | 
					 | 
				
			||||||
	return "access"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetRepositoryAccesses finds all repositories with their access mode where a user has access but does not own.
 | 
					 | 
				
			||||||
func (user *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
 | 
					 | 
				
			||||||
	rows, err := db.GetEngine(db.DefaultContext).
 | 
					 | 
				
			||||||
		Join("INNER", "repository", "repository.id = access.repo_id").
 | 
					 | 
				
			||||||
		Where("access.user_id = ?", user.ID).
 | 
					 | 
				
			||||||
		And("repository.owner_id <> ?", user.ID).
 | 
					 | 
				
			||||||
		Rows(new(repoAccess))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer rows.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	repos := make(map[*Repository]AccessMode, 10)
 | 
					 | 
				
			||||||
	ownerCache := make(map[int64]*User, 10)
 | 
					 | 
				
			||||||
	for rows.Next() {
 | 
					 | 
				
			||||||
		var repo repoAccess
 | 
					 | 
				
			||||||
		err = rows.Scan(&repo)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var ok bool
 | 
					 | 
				
			||||||
		if repo.Owner, ok = ownerCache[repo.OwnerID]; !ok {
 | 
					 | 
				
			||||||
			if err = repo.GetOwner(); err != nil {
 | 
					 | 
				
			||||||
				return nil, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			ownerCache[repo.OwnerID] = repo.Owner
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		repos[&repo.Repository] = repo.Access.Mode
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return repos, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetAccessibleRepositories finds repositories which the user has access but does not own.
 | 
					 | 
				
			||||||
// If limit is smaller than 1 means returns all found results.
 | 
					 | 
				
			||||||
func (user *User) GetAccessibleRepositories(limit int) (repos []*Repository, _ error) {
 | 
					 | 
				
			||||||
	sess := db.GetEngine(db.DefaultContext).
 | 
					 | 
				
			||||||
		Where("owner_id !=? ", user.ID).
 | 
					 | 
				
			||||||
		Desc("updated_unix")
 | 
					 | 
				
			||||||
	if limit > 0 {
 | 
					 | 
				
			||||||
		sess.Limit(limit)
 | 
					 | 
				
			||||||
		repos = make([]*Repository, 0, limit)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		repos = make([]*Repository, 0, 10)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return repos, sess.
 | 
					 | 
				
			||||||
		Join("INNER", "access", "access.user_id = ? AND access.repo_id = repository.id", user.ID).
 | 
					 | 
				
			||||||
		Find(&repos)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func maxAccessMode(modes ...AccessMode) AccessMode {
 | 
					func maxAccessMode(modes ...AccessMode) AccessMode {
 | 
				
			||||||
	max := AccessModeNone
 | 
						max := AccessModeNone
 | 
				
			||||||
	for _, mode := range modes {
 | 
						for _, mode := range modes {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,39 +90,6 @@ func TestHasAccess(t *testing.T) {
 | 
				
			|||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestUser_GetRepositoryAccesses(t *testing.T) {
 | 
					 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
 | 
					 | 
				
			||||||
	accesses, err := user1.GetRepositoryAccesses()
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Len(t, accesses, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user29 := unittest.AssertExistsAndLoadBean(t, &User{ID: 29}).(*User)
 | 
					 | 
				
			||||||
	accesses, err = user29.GetRepositoryAccesses()
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Len(t, accesses, 2)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestUser_GetAccessibleRepositories(t *testing.T) {
 | 
					 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
 | 
					 | 
				
			||||||
	repos, err := user1.GetAccessibleRepositories(0)
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Len(t, repos, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 | 
					 | 
				
			||||||
	repos, err = user2.GetAccessibleRepositories(0)
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Len(t, repos, 4)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user29 := unittest.AssertExistsAndLoadBean(t, &User{ID: 29}).(*User)
 | 
					 | 
				
			||||||
	repos, err = user29.GetAccessibleRepositories(0)
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Len(t, repos, 2)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestRepository_RecalculateAccesses(t *testing.T) {
 | 
					func TestRepository_RecalculateAccesses(t *testing.T) {
 | 
				
			||||||
	// test with organization repo
 | 
						// test with organization repo
 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
						assert.NoError(t, unittest.PrepareTestDatabase())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -125,6 +125,12 @@ func (org *Organization) HomeLink() string {
 | 
				
			|||||||
	return org.AsUser().HomeLink()
 | 
						return org.AsUser().HomeLink()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CanCreateRepo returns if user login can create a repository
 | 
				
			||||||
 | 
					// NOTE: functions calling this assume a failure due to repository count limit; if new checks are added, those functions should be revised
 | 
				
			||||||
 | 
					func (org *Organization) CanCreateRepo() bool {
 | 
				
			||||||
 | 
						return org.AsUser().CanCreateRepo()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindOrgMembersOpts represensts find org members conditions
 | 
					// FindOrgMembersOpts represensts find org members conditions
 | 
				
			||||||
type FindOrgMembersOpts struct {
 | 
					type FindOrgMembersOpts struct {
 | 
				
			||||||
	db.ListOptions
 | 
						db.ListOptions
 | 
				
			||||||
@@ -240,7 +246,7 @@ func CreateOrganization(org *Organization, owner *User) (err error) {
 | 
				
			|||||||
	if err = db.Insert(ctx, org); err != nil {
 | 
						if err = db.Insert(ctx, org); err != nil {
 | 
				
			||||||
		return fmt.Errorf("insert organization: %v", err)
 | 
							return fmt.Errorf("insert organization: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err = org.AsUser().generateRandomAvatar(db.GetEngine(ctx)); err != nil {
 | 
						if err = generateRandomAvatar(db.GetEngine(ctx), org.AsUser()); err != nil {
 | 
				
			||||||
		return fmt.Errorf("generate random avatar: %v", err)
 | 
							return fmt.Errorf("generate random avatar: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -546,8 +552,8 @@ func CountOrgs(opts FindOrgOptions) (int64, error) {
 | 
				
			|||||||
		Count(new(User))
 | 
							Count(new(User))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*User, error) {
 | 
					func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*Organization, error) {
 | 
				
			||||||
	orgs := make([]*User, 0, 10)
 | 
						orgs := make([]*Organization, 0, 10)
 | 
				
			||||||
	return orgs, sess.
 | 
						return orgs, sess.
 | 
				
			||||||
		Join("INNER", "`team_user`", "`team_user`.org_id=`user`.id").
 | 
							Join("INNER", "`team_user`", "`team_user`.org_id=`user`.id").
 | 
				
			||||||
		Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
 | 
							Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
 | 
				
			||||||
@@ -593,20 +599,20 @@ func HasOrgsVisible(orgs []*Organization, user *User) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
 | 
					// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
 | 
				
			||||||
func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
 | 
					func GetOwnedOrgsByUserID(userID int64) ([]*Organization, error) {
 | 
				
			||||||
	return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext), userID)
 | 
						return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext), userID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetOwnedOrgsByUserIDDesc returns a list of organizations are owned by
 | 
					// GetOwnedOrgsByUserIDDesc returns a list of organizations are owned by
 | 
				
			||||||
// given user ID, ordered descending by the given condition.
 | 
					// given user ID, ordered descending by the given condition.
 | 
				
			||||||
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
 | 
					func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*Organization, error) {
 | 
				
			||||||
	return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext).Desc(desc), userID)
 | 
						return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext).Desc(desc), userID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID
 | 
					// GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID
 | 
				
			||||||
// are allowed to create repos.
 | 
					// are allowed to create repos.
 | 
				
			||||||
func GetOrgsCanCreateRepoByUserID(userID int64) ([]*User, error) {
 | 
					func GetOrgsCanCreateRepoByUserID(userID int64) ([]*Organization, error) {
 | 
				
			||||||
	orgs := make([]*User, 0, 10)
 | 
						orgs := make([]*Organization, 0, 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return orgs, db.GetEngine(db.DefaultContext).Where(builder.In("id", builder.Select("`user`.id").From("`user`").
 | 
						return orgs, db.GetEngine(db.DefaultContext).Where(builder.In("id", builder.Select("`user`.id").From("`user`").
 | 
				
			||||||
		Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id").
 | 
							Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id").
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -754,19 +754,20 @@ func (repo *Repository) UpdateSize(ctx context.Context) error {
 | 
				
			|||||||
	return repo.updateSize(db.GetEngine(ctx))
 | 
						return repo.updateSize(db.GetEngine(ctx))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CanUserFork returns true if specified user can fork repository.
 | 
					// CanUserForkRepo returns true if specified user can fork repository.
 | 
				
			||||||
func (repo *Repository) CanUserFork(user *User) (bool, error) {
 | 
					func CanUserForkRepo(user *User, repo *Repository) (bool, error) {
 | 
				
			||||||
	if user == nil {
 | 
						if user == nil {
 | 
				
			||||||
		return false, nil
 | 
							return false, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if repo.OwnerID != user.ID && !user.HasForkedRepo(repo.ID) {
 | 
						if repo.OwnerID != user.ID && !HasForkedRepo(user.ID, repo.ID) {
 | 
				
			||||||
		return true, nil
 | 
							return true, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := user.GetOwnedOrganizations(); err != nil {
 | 
						ownedOrgs, err := GetOwnedOrgsByUserID(user.ID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
		return false, err
 | 
							return false, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, org := range user.OwnedOrgs {
 | 
						for _, org := range ownedOrgs {
 | 
				
			||||||
		if repo.OwnerID != org.ID && !org.HasForkedRepo(repo.ID) {
 | 
							if repo.OwnerID != org.ID && !HasForkedRepo(org.ID, repo.ID) {
 | 
				
			||||||
			return true, nil
 | 
								return true, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -2036,13 +2037,25 @@ func (repo *Repository) SetArchiveRepoState(isArchived bool) (err error) {
 | 
				
			|||||||
//  \___  / \____/|__|  |__|_ \
 | 
					//  \___  / \____/|__|  |__|_ \
 | 
				
			||||||
//      \/                   \/
 | 
					//      \/                   \/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// HasForkedRepo checks if given user has already forked a repository with given ID.
 | 
					// GetForkedRepo checks if given user has already forked a repository with given ID.
 | 
				
			||||||
func HasForkedRepo(ownerID, repoID int64) (*Repository, bool) {
 | 
					func GetForkedRepo(ownerID, repoID int64) *Repository {
 | 
				
			||||||
	repo := new(Repository)
 | 
						repo := new(Repository)
 | 
				
			||||||
	has, _ := db.GetEngine(db.DefaultContext).
 | 
						has, _ := db.GetEngine(db.DefaultContext).
 | 
				
			||||||
		Where("owner_id=? AND fork_id=?", ownerID, repoID).
 | 
							Where("owner_id=? AND fork_id=?", ownerID, repoID).
 | 
				
			||||||
		Get(repo)
 | 
							Get(repo)
 | 
				
			||||||
	return repo, has
 | 
						if has {
 | 
				
			||||||
 | 
							return repo
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HasForkedRepo checks if given user has already forked a repository with given ID.
 | 
				
			||||||
 | 
					func HasForkedRepo(ownerID, repoID int64) bool {
 | 
				
			||||||
 | 
						has, _ := db.GetEngine(db.DefaultContext).
 | 
				
			||||||
 | 
							Table("repository").
 | 
				
			||||||
 | 
							Where("owner_id=? AND fork_id=?", ownerID, repoID).
 | 
				
			||||||
 | 
							Exist()
 | 
				
			||||||
 | 
						return has
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CopyLFS copies LFS data from one repo to another
 | 
					// CopyLFS copies LFS data from one repo to another
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,7 +74,7 @@ func isStaring(e db.Engine, userID, repoID int64) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetStargazers returns the users that starred the repo.
 | 
					// GetStargazers returns the users that starred the repo.
 | 
				
			||||||
func (repo *Repository) GetStargazers(opts db.ListOptions) ([]*User, error) {
 | 
					func GetStargazers(repo *Repository, opts db.ListOptions) ([]*User, error) {
 | 
				
			||||||
	sess := db.GetEngine(db.DefaultContext).Where("star.repo_id = ?", repo.ID).
 | 
						sess := db.GetEngine(db.DefaultContext).Where("star.repo_id = ?", repo.ID).
 | 
				
			||||||
		Join("LEFT", "star", "`user`.id = star.uid")
 | 
							Join("LEFT", "star", "`user`.id = star.uid")
 | 
				
			||||||
	if opts.Page > 0 {
 | 
						if opts.Page > 0 {
 | 
				
			||||||
@@ -87,48 +87,3 @@ func (repo *Repository) GetStargazers(opts db.ListOptions) ([]*User, error) {
 | 
				
			|||||||
	users := make([]*User, 0, 8)
 | 
						users := make([]*User, 0, 8)
 | 
				
			||||||
	return users, sess.Find(&users)
 | 
						return users, sess.Find(&users)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetStarredRepos returns the repos the user starred.
 | 
					 | 
				
			||||||
func (u *User) GetStarredRepos(private bool, page, pageSize int, orderBy string) (repos RepositoryList, err error) {
 | 
					 | 
				
			||||||
	if len(orderBy) == 0 {
 | 
					 | 
				
			||||||
		orderBy = "updated_unix DESC"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sess := db.GetEngine(db.DefaultContext).
 | 
					 | 
				
			||||||
		Join("INNER", "star", "star.repo_id = repository.id").
 | 
					 | 
				
			||||||
		Where("star.uid = ?", u.ID).
 | 
					 | 
				
			||||||
		OrderBy(orderBy)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !private {
 | 
					 | 
				
			||||||
		sess = sess.And("is_private = ?", false)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if page <= 0 {
 | 
					 | 
				
			||||||
		page = 1
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sess.Limit(pageSize, (page-1)*pageSize)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	repos = make([]*Repository, 0, pageSize)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = sess.Find(&repos); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = repos.loadAttributes(db.GetEngine(db.DefaultContext)); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetStarredRepoCount returns the numbers of repo the user starred.
 | 
					 | 
				
			||||||
func (u *User) GetStarredRepoCount(private bool) (int64, error) {
 | 
					 | 
				
			||||||
	sess := db.GetEngine(db.DefaultContext).
 | 
					 | 
				
			||||||
		Join("INNER", "star", "star.repo_id = repository.id").
 | 
					 | 
				
			||||||
		Where("star.uid = ?", u.ID)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !private {
 | 
					 | 
				
			||||||
		sess = sess.And("is_private = ?", false)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sess.Count(&Repository{})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,7 +36,7 @@ func TestRepository_GetStargazers(t *testing.T) {
 | 
				
			|||||||
	// repo with stargazers
 | 
						// repo with stargazers
 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
						assert.NoError(t, unittest.PrepareTestDatabase())
 | 
				
			||||||
	repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository)
 | 
						repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository)
 | 
				
			||||||
	gazers, err := repo.GetStargazers(db.ListOptions{Page: 0})
 | 
						gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	if assert.Len(t, gazers, 1) {
 | 
						if assert.Len(t, gazers, 1) {
 | 
				
			||||||
		assert.Equal(t, int64(2), gazers[0].ID)
 | 
							assert.Equal(t, int64(2), gazers[0].ID)
 | 
				
			||||||
@@ -47,53 +47,7 @@ func TestRepository_GetStargazers2(t *testing.T) {
 | 
				
			|||||||
	// repo with stargazers
 | 
						// repo with stargazers
 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
						assert.NoError(t, unittest.PrepareTestDatabase())
 | 
				
			||||||
	repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
 | 
						repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
 | 
				
			||||||
	gazers, err := repo.GetStargazers(db.ListOptions{Page: 0})
 | 
						gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Len(t, gazers, 0)
 | 
						assert.Len(t, gazers, 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestUser_GetStarredRepos(t *testing.T) {
 | 
					 | 
				
			||||||
	// user who has starred repos
 | 
					 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 | 
					 | 
				
			||||||
	starred, err := user.GetStarredRepos(false, 1, 10, "")
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	if assert.Len(t, starred, 1) {
 | 
					 | 
				
			||||||
		assert.Equal(t, int64(4), starred[0].ID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	starred, err = user.GetStarredRepos(true, 1, 10, "")
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	if assert.Len(t, starred, 2) {
 | 
					 | 
				
			||||||
		assert.Equal(t, int64(2), starred[0].ID)
 | 
					 | 
				
			||||||
		assert.Equal(t, int64(4), starred[1].ID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestUser_GetStarredRepos2(t *testing.T) {
 | 
					 | 
				
			||||||
	// user who has no starred repos
 | 
					 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
 | 
					 | 
				
			||||||
	starred, err := user.GetStarredRepos(false, 1, 10, "")
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Len(t, starred, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	starred, err = user.GetStarredRepos(true, 1, 10, "")
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Len(t, starred, 0)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestUserGetStarredRepoCount(t *testing.T) {
 | 
					 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 | 
					 | 
				
			||||||
	counts, err := user.GetStarredRepoCount(false)
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Equal(t, int64(1), counts)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	counts, err = user.GetStarredRepoCount(true)
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Equal(t, int64(2), counts)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										118
									
								
								models/user.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								models/user.go
									
									
									
									
									
								
							@@ -113,8 +113,6 @@ type User struct {
 | 
				
			|||||||
	LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
 | 
						LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
 | 
				
			||||||
	LoginName   string
 | 
						LoginName   string
 | 
				
			||||||
	Type        UserType
 | 
						Type        UserType
 | 
				
			||||||
	OwnedOrgs   []*User       `xorm:"-"`
 | 
					 | 
				
			||||||
	Repos       []*Repository `xorm:"-"`
 | 
					 | 
				
			||||||
	Location    string
 | 
						Location    string
 | 
				
			||||||
	Website     string
 | 
						Website     string
 | 
				
			||||||
	Rands       string `xorm:"VARCHAR(10)"`
 | 
						Rands       string `xorm:"VARCHAR(10)"`
 | 
				
			||||||
@@ -219,16 +217,16 @@ func (u *User) SetLastLogin() {
 | 
				
			|||||||
	u.LastLoginUnix = timeutil.TimeStampNow()
 | 
						u.LastLoginUnix = timeutil.TimeStampNow()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateDiffViewStyle updates the users diff view style
 | 
					// UpdateUserDiffViewStyle updates the users diff view style
 | 
				
			||||||
func (u *User) UpdateDiffViewStyle(style string) error {
 | 
					func UpdateUserDiffViewStyle(u *User, style string) error {
 | 
				
			||||||
	u.DiffViewStyle = style
 | 
						u.DiffViewStyle = style
 | 
				
			||||||
	return UpdateUserCols(u, "diff_view_style")
 | 
						return UpdateUserCols(db.DefaultContext, u, "diff_view_style")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateTheme updates a users' theme irrespective of the site wide theme
 | 
					// UpdateUserTheme updates a users' theme irrespective of the site wide theme
 | 
				
			||||||
func (u *User) UpdateTheme(themeName string) error {
 | 
					func UpdateUserTheme(u *User, themeName string) error {
 | 
				
			||||||
	u.Theme = themeName
 | 
						u.Theme = themeName
 | 
				
			||||||
	return UpdateUserCols(u, "theme")
 | 
						return UpdateUserCols(db.DefaultContext, u, "theme")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetEmail returns an noreply email, if the user has set to keep his
 | 
					// GetEmail returns an noreply email, if the user has set to keep his
 | 
				
			||||||
@@ -256,12 +254,6 @@ func (u *User) IsOAuth2() bool {
 | 
				
			|||||||
	return u.LoginType == login.OAuth2
 | 
						return u.LoginType == login.OAuth2
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// HasForkedRepo checks if user has already forked a repository with given ID.
 | 
					 | 
				
			||||||
func (u *User) HasForkedRepo(repoID int64) bool {
 | 
					 | 
				
			||||||
	_, has := HasForkedRepo(u.ID, repoID)
 | 
					 | 
				
			||||||
	return has
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MaxCreationLimit returns the number of repositories a user is allowed to create
 | 
					// MaxCreationLimit returns the number of repositories a user is allowed to create
 | 
				
			||||||
func (u *User) MaxCreationLimit() int {
 | 
					func (u *User) MaxCreationLimit() int {
 | 
				
			||||||
	if u.MaxRepoCreation <= -1 {
 | 
						if u.MaxRepoCreation <= -1 {
 | 
				
			||||||
@@ -337,8 +329,8 @@ func (u *User) GenerateEmailActivateCode(email string) string {
 | 
				
			|||||||
	return code
 | 
						return code
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetFollowers returns range of user's followers.
 | 
					// GetUserFollowers returns range of user's followers.
 | 
				
			||||||
func (u *User) GetFollowers(listOptions db.ListOptions) ([]*User, error) {
 | 
					func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) {
 | 
				
			||||||
	sess := db.GetEngine(db.DefaultContext).
 | 
						sess := db.GetEngine(db.DefaultContext).
 | 
				
			||||||
		Where("follow.follow_id=?", u.ID).
 | 
							Where("follow.follow_id=?", u.ID).
 | 
				
			||||||
		Join("LEFT", "follow", "`user`.id=follow.user_id")
 | 
							Join("LEFT", "follow", "`user`.id=follow.user_id")
 | 
				
			||||||
@@ -354,13 +346,8 @@ func (u *User) GetFollowers(listOptions db.ListOptions) ([]*User, error) {
 | 
				
			|||||||
	return users, sess.Find(&users)
 | 
						return users, sess.Find(&users)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsFollowing returns true if user is following followID.
 | 
					// GetUserFollowing returns range of user's following.
 | 
				
			||||||
func (u *User) IsFollowing(followID int64) bool {
 | 
					func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) {
 | 
				
			||||||
	return user_model.IsFollowing(u.ID, followID)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetFollowing returns range of user's following.
 | 
					 | 
				
			||||||
func (u *User) GetFollowing(listOptions db.ListOptions) ([]*User, error) {
 | 
					 | 
				
			||||||
	sess := db.GetEngine(db.DefaultContext).
 | 
						sess := db.GetEngine(db.DefaultContext).
 | 
				
			||||||
		Where("follow.user_id=?", u.ID).
 | 
							Where("follow.user_id=?", u.ID).
 | 
				
			||||||
		Join("LEFT", "follow", "`user`.id=follow.follow_id")
 | 
							Join("LEFT", "follow", "`user`.id=follow.follow_id")
 | 
				
			||||||
@@ -442,12 +429,12 @@ func (u *User) IsPasswordSet() bool {
 | 
				
			|||||||
	return len(u.Passwd) != 0
 | 
						return len(u.Passwd) != 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsVisibleToUser check if viewer is able to see user profile
 | 
					// IsUserVisibleToViewer check if viewer is able to see user profile
 | 
				
			||||||
func (u *User) IsVisibleToUser(viewer *User) bool {
 | 
					func IsUserVisibleToViewer(u *User, viewer *User) bool {
 | 
				
			||||||
	return u.isVisibleToUser(db.GetEngine(db.DefaultContext), viewer)
 | 
						return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (u *User) isVisibleToUser(e db.Engine, viewer *User) bool {
 | 
					func isUserVisibleToViewer(e db.Engine, u *User, viewer *User) bool {
 | 
				
			||||||
	if viewer != nil && viewer.IsAdmin {
 | 
						if viewer != nil && viewer.IsAdmin {
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -503,26 +490,6 @@ func (u *User) IsOrganization() bool {
 | 
				
			|||||||
	return u.Type == UserTypeOrganization
 | 
						return u.Type == UserTypeOrganization
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsUserOrgOwner returns true if user is in the owner team of given organization.
 | 
					 | 
				
			||||||
func (u *User) IsUserOrgOwner(orgID int64) bool {
 | 
					 | 
				
			||||||
	isOwner, err := IsOrganizationOwner(orgID, u.ID)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Error("IsOrganizationOwner: %v", err)
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return isOwner
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsPublicMember returns true if user public his/her membership in given organization.
 | 
					 | 
				
			||||||
func (u *User) IsPublicMember(orgID int64) bool {
 | 
					 | 
				
			||||||
	isMember, err := IsPublicMembership(orgID, u.ID)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Error("IsPublicMembership: %v", err)
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return isMember
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetOrganizationCount returns count of membership of organization of the user.
 | 
					// GetOrganizationCount returns count of membership of organization of the user.
 | 
				
			||||||
func GetOrganizationCount(ctx context.Context, u *User) (int64, error) {
 | 
					func GetOrganizationCount(ctx context.Context, u *User) (int64, error) {
 | 
				
			||||||
	return db.GetEngine(ctx).
 | 
						return db.GetEngine(ctx).
 | 
				
			||||||
@@ -530,17 +497,6 @@ func GetOrganizationCount(ctx context.Context, u *User) (int64, error) {
 | 
				
			|||||||
		Count(new(OrgUser))
 | 
							Count(new(OrgUser))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetOrganizationCount returns count of membership of organization of user.
 | 
					 | 
				
			||||||
func (u *User) GetOrganizationCount() (int64, error) {
 | 
					 | 
				
			||||||
	return GetOrganizationCount(db.DefaultContext, u)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetRepositories returns repositories that user owns, including private repositories.
 | 
					 | 
				
			||||||
func (u *User) GetRepositories(listOpts db.ListOptions, names ...string) (err error) {
 | 
					 | 
				
			||||||
	u.Repos, _, err = GetUserRepositories(&SearchRepoOptions{Actor: u, Private: true, ListOptions: listOpts, LowerNames: names})
 | 
					 | 
				
			||||||
	return err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetRepositoryIDs returns repositories IDs where user owned and has unittypes
 | 
					// GetRepositoryIDs returns repositories IDs where user owned and has unittypes
 | 
				
			||||||
// Caller shall check that units is not globally disabled
 | 
					// Caller shall check that units is not globally disabled
 | 
				
			||||||
func (u *User) GetRepositoryIDs(units ...unit.Type) ([]int64, error) {
 | 
					func (u *User) GetRepositoryIDs(units ...unit.Type) ([]int64, error) {
 | 
				
			||||||
@@ -644,17 +600,6 @@ func (u *User) GetActiveAccessRepoIDs(units ...unit.Type) ([]int64, error) {
 | 
				
			|||||||
	return append(ids, ids2...), nil
 | 
						return append(ids, ids2...), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetMirrorRepositories returns mirror repositories that user owns, including private repositories.
 | 
					 | 
				
			||||||
func (u *User) GetMirrorRepositories() ([]*Repository, error) {
 | 
					 | 
				
			||||||
	return GetUserMirrorRepositories(u.ID)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetOwnedOrganizations returns all organizations that user owns.
 | 
					 | 
				
			||||||
func (u *User) GetOwnedOrganizations() (err error) {
 | 
					 | 
				
			||||||
	u.OwnedOrgs, err = GetOwnedOrgsByUserID(u.ID)
 | 
					 | 
				
			||||||
	return err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// DisplayName returns full name if it's not empty,
 | 
					// DisplayName returns full name if it's not empty,
 | 
				
			||||||
// returns username otherwise.
 | 
					// returns username otherwise.
 | 
				
			||||||
func (u *User) DisplayName() string {
 | 
					func (u *User) DisplayName() string {
 | 
				
			||||||
@@ -714,9 +659,9 @@ func (u *User) EmailNotifications() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetEmailNotifications sets the user's email notification preference
 | 
					// SetEmailNotifications sets the user's email notification preference
 | 
				
			||||||
func (u *User) SetEmailNotifications(set string) error {
 | 
					func SetEmailNotifications(u *User, set string) error {
 | 
				
			||||||
	u.EmailNotificationsPreference = set
 | 
						u.EmailNotificationsPreference = set
 | 
				
			||||||
	if err := UpdateUserCols(u, "email_notifications_preference"); err != nil {
 | 
						if err := UpdateUserCols(db.DefaultContext, u, "email_notifications_preference"); err != nil {
 | 
				
			||||||
		log.Error("SetEmailNotifications: %v", err)
 | 
							log.Error("SetEmailNotifications: %v", err)
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -983,25 +928,6 @@ func VerifyUserActiveCode(code string) (user *User) {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// VerifyActiveEmailCode verifies active email code when active account
 | 
					 | 
				
			||||||
func VerifyActiveEmailCode(code, email string) *user_model.EmailAddress {
 | 
					 | 
				
			||||||
	minutes := setting.Service.ActiveCodeLives
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if user := getVerifyUser(code); user != nil {
 | 
					 | 
				
			||||||
		// time limit code
 | 
					 | 
				
			||||||
		prefix := code[:base.TimeLimitCodeLength]
 | 
					 | 
				
			||||||
		data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if base.VerifyTimeLimitCode(data, minutes, prefix) {
 | 
					 | 
				
			||||||
			emailAddress := &user_model.EmailAddress{UID: user.ID, Email: email}
 | 
					 | 
				
			||||||
			if has, _ := db.GetEngine(db.DefaultContext).Get(emailAddress); has {
 | 
					 | 
				
			||||||
				return emailAddress
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 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
 | 
						oldUserName := u.Name
 | 
				
			||||||
@@ -1090,8 +1016,8 @@ func UpdateUser(u *User) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateUserCols update user according special columns
 | 
					// UpdateUserCols update user according special columns
 | 
				
			||||||
func UpdateUserCols(u *User, cols ...string) error {
 | 
					func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
 | 
				
			||||||
	return updateUserCols(db.GetEngine(db.DefaultContext), u, cols...)
 | 
						return updateUserCols(db.GetEngine(ctx), u, cols...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func updateUserCols(e db.Engine, u *User, cols ...string) error {
 | 
					func updateUserCols(e db.Engine, u *User, cols ...string) error {
 | 
				
			||||||
@@ -1228,14 +1154,6 @@ func DeleteUser(ctx context.Context, u *User) (err error) {
 | 
				
			|||||||
	if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil {
 | 
						if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil {
 | 
				
			||||||
		return fmt.Errorf("deletePublicKeys: %v", err)
 | 
							return fmt.Errorf("deletePublicKeys: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = rewriteAllPublicKeys(e)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = rewriteAllPrincipalKeys(e)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// ***** END: PublicKey *****
 | 
						// ***** END: PublicKey *****
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ***** START: GPGPublicKey *****
 | 
						// ***** START: GPGPublicKey *****
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,11 +25,11 @@ func (u *User) CustomAvatarRelativePath() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GenerateRandomAvatar generates a random avatar for user.
 | 
					// GenerateRandomAvatar generates a random avatar for user.
 | 
				
			||||||
func (u *User) GenerateRandomAvatar() error {
 | 
					func GenerateRandomAvatar(u *User) error {
 | 
				
			||||||
	return u.generateRandomAvatar(db.GetEngine(db.DefaultContext))
 | 
						return generateRandomAvatar(db.GetEngine(db.DefaultContext), u)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (u *User) generateRandomAvatar(e db.Engine) error {
 | 
					func generateRandomAvatar(e db.Engine, u *User) error {
 | 
				
			||||||
	seed := u.Email
 | 
						seed := u.Email
 | 
				
			||||||
	if len(seed) == 0 {
 | 
						if len(seed) == 0 {
 | 
				
			||||||
		seed = u.Name
 | 
							seed = u.Name
 | 
				
			||||||
@@ -80,7 +80,7 @@ func (u *User) AvatarLinkWithSize(size int) string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if useLocalAvatar {
 | 
						if useLocalAvatar {
 | 
				
			||||||
		if u.Avatar == "" && autoGenerateAvatar {
 | 
							if u.Avatar == "" && autoGenerateAvatar {
 | 
				
			||||||
			if err := u.GenerateRandomAvatar(); err != nil {
 | 
								if err := GenerateRandomAvatar(u); err != nil {
 | 
				
			||||||
				log.Error("GenerateRandomAvatar: %v", err)
 | 
									log.Error("GenerateRandomAvatar: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -101,42 +101,6 @@ func (u *User) AvatarLink() string {
 | 
				
			|||||||
	return link
 | 
						return link
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UploadAvatar saves custom avatar for user.
 | 
					 | 
				
			||||||
// FIXME: split uploads to different subdirs in case we have massive users.
 | 
					 | 
				
			||||||
func (u *User) UploadAvatar(data []byte) error {
 | 
					 | 
				
			||||||
	m, err := avatar.Prepare(data)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx, committer, err := db.TxContext()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer committer.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	u.UseCustomAvatar = true
 | 
					 | 
				
			||||||
	// Different users can upload same image as avatar
 | 
					 | 
				
			||||||
	// If we prefix it with u.ID, it will be separated
 | 
					 | 
				
			||||||
	// Otherwise, if any of the users delete his avatar
 | 
					 | 
				
			||||||
	// Other users will lose their avatars too.
 | 
					 | 
				
			||||||
	u.Avatar = fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data)))))
 | 
					 | 
				
			||||||
	if err = updateUserCols(db.GetEngine(ctx), u, "use_custom_avatar", "avatar"); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("updateUser: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
 | 
					 | 
				
			||||||
		if err := png.Encode(w, *m); err != nil {
 | 
					 | 
				
			||||||
			log.Error("Encode: %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("Failed to create dir %s: %v", u.CustomAvatarRelativePath(), err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return committer.Commit()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data
 | 
					// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data
 | 
				
			||||||
func (u *User) IsUploadAvatarChanged(data []byte) bool {
 | 
					func (u *User) IsUploadAvatarChanged(data []byte) bool {
 | 
				
			||||||
	if !u.UseCustomAvatar || len(u.Avatar) == 0 {
 | 
						if !u.UseCustomAvatar || len(u.Avatar) == 0 {
 | 
				
			||||||
@@ -145,21 +109,3 @@ func (u *User) IsUploadAvatarChanged(data []byte) bool {
 | 
				
			|||||||
	avatarID := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data)))))
 | 
						avatarID := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data)))))
 | 
				
			||||||
	return u.Avatar != avatarID
 | 
						return u.Avatar != avatarID
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// DeleteAvatar deletes the user's custom avatar.
 | 
					 | 
				
			||||||
func (u *User) DeleteAvatar() error {
 | 
					 | 
				
			||||||
	aPath := u.CustomAvatarRelativePath()
 | 
					 | 
				
			||||||
	log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
 | 
					 | 
				
			||||||
	if len(u.Avatar) > 0 {
 | 
					 | 
				
			||||||
		if err := storage.Avatars.Delete(aPath); err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("Failed to remove %s: %v", aPath, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	u.UseCustomAvatar = false
 | 
					 | 
				
			||||||
	u.Avatar = ""
 | 
					 | 
				
			||||||
	if _, err := db.GetEngine(db.DefaultContext).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("UpdateUser: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,8 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	user_model "code.gitea.io/gitea/models/user"
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"xorm.io/builder"
 | 
						"xorm.io/builder"
 | 
				
			||||||
@@ -93,6 +95,25 @@ func MakeEmailPrimary(email *user_model.EmailAddress) error {
 | 
				
			|||||||
	return committer.Commit()
 | 
						return committer.Commit()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VerifyActiveEmailCode verifies active email code when active account
 | 
				
			||||||
 | 
					func VerifyActiveEmailCode(code, email string) *user_model.EmailAddress {
 | 
				
			||||||
 | 
						minutes := setting.Service.ActiveCodeLives
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if user := getVerifyUser(code); user != nil {
 | 
				
			||||||
 | 
							// time limit code
 | 
				
			||||||
 | 
							prefix := code[:base.TimeLimitCodeLength]
 | 
				
			||||||
 | 
							data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if base.VerifyTimeLimitCode(data, minutes, prefix) {
 | 
				
			||||||
 | 
								emailAddress := &user_model.EmailAddress{UID: user.ID, Email: email}
 | 
				
			||||||
 | 
								if has, _ := db.GetEngine(db.DefaultContext).Get(emailAddress); has {
 | 
				
			||||||
 | 
									return emailAddress
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SearchEmailOrderBy is used to sort the results from SearchEmails()
 | 
					// SearchEmailOrderBy is used to sort the results from SearchEmails()
 | 
				
			||||||
type SearchEmailOrderBy string
 | 
					type SearchEmailOrderBy string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,9 @@ func TestUserIsPublicMember(t *testing.T) {
 | 
				
			|||||||
func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
 | 
					func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
 | 
				
			||||||
	user, err := GetUserByID(uid)
 | 
						user, err := GetUserByID(uid)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Equal(t, expected, user.IsPublicMember(orgID))
 | 
						is, err := IsPublicMembership(orgID, user.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.Equal(t, expected, is)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestIsUserOrgOwner(t *testing.T) {
 | 
					func TestIsUserOrgOwner(t *testing.T) {
 | 
				
			||||||
@@ -78,7 +80,9 @@ func TestIsUserOrgOwner(t *testing.T) {
 | 
				
			|||||||
func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
 | 
					func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
 | 
				
			||||||
	user, err := GetUserByID(uid)
 | 
						user, err := GetUserByID(uid)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Equal(t, expected, user.IsUserOrgOwner(orgID))
 | 
						is, err := IsOrganizationOwner(orgID, user.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.Equal(t, expected, is)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetUserEmailsByNames(t *testing.T) {
 | 
					func TestGetUserEmailsByNames(t *testing.T) {
 | 
				
			||||||
@@ -198,13 +202,13 @@ func TestEmailNotificationPreferences(t *testing.T) {
 | 
				
			|||||||
		assert.Equal(t, test.expected, user.EmailNotifications())
 | 
							assert.Equal(t, test.expected, user.EmailNotifications())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Try all possible settings
 | 
							// Try all possible settings
 | 
				
			||||||
		assert.NoError(t, user.SetEmailNotifications(EmailNotificationsEnabled))
 | 
							assert.NoError(t, SetEmailNotifications(user, EmailNotificationsEnabled))
 | 
				
			||||||
		assert.Equal(t, EmailNotificationsEnabled, user.EmailNotifications())
 | 
							assert.Equal(t, EmailNotificationsEnabled, user.EmailNotifications())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.NoError(t, user.SetEmailNotifications(EmailNotificationsOnMention))
 | 
							assert.NoError(t, SetEmailNotifications(user, EmailNotificationsOnMention))
 | 
				
			||||||
		assert.Equal(t, EmailNotificationsOnMention, user.EmailNotifications())
 | 
							assert.Equal(t, EmailNotificationsOnMention, user.EmailNotifications())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.NoError(t, user.SetEmailNotifications(EmailNotificationsDisabled))
 | 
							assert.NoError(t, SetEmailNotifications(user, EmailNotificationsDisabled))
 | 
				
			||||||
		assert.Equal(t, EmailNotificationsDisabled, user.EmailNotifications())
 | 
							assert.Equal(t, EmailNotificationsDisabled, user.EmailNotifications())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,6 +117,10 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
 | 
						ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
 | 
				
			||||||
	ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
 | 
						ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
 | 
				
			||||||
 | 
						ctx.Data["IsPublicMember"] = func(uid int64) bool {
 | 
				
			||||||
 | 
							is, _ := models.IsPublicMembership(ctx.Org.Organization.ID, uid)
 | 
				
			||||||
 | 
							return is
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo
 | 
						ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Org.OrgLink = org.AsUser().OrganisationLink()
 | 
						ctx.Org.OrgLink = org.AsUser().OrganisationLink()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -491,8 +491,8 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
 | 
				
			|||||||
	ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
 | 
						ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
 | 
				
			||||||
	ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
 | 
						ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ctx.Data["CanSignedUserFork"], err = ctx.Repo.Repository.CanUserFork(ctx.User); err != nil {
 | 
						if ctx.Data["CanSignedUserFork"], err = models.CanUserForkRepo(ctx.User, ctx.Repo.Repository); err != nil {
 | 
				
			||||||
		ctx.ServerError("CanUserFork", err)
 | 
							ctx.ServerError("CanSignedUserFork", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -577,7 +577,8 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
 | 
				
			|||||||
	ctx.Data["BranchName"] = ctx.Repo.BranchName
 | 
						ctx.Data["BranchName"] = ctx.Repo.BranchName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// People who have push access or have forked repository can propose a new pull request.
 | 
						// People who have push access or have forked repository can propose a new pull request.
 | 
				
			||||||
	canPush := ctx.Repo.CanWrite(unit_model.TypeCode) || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID))
 | 
						canPush := ctx.Repo.CanWrite(unit_model.TypeCode) ||
 | 
				
			||||||
 | 
							(ctx.IsSigned && models.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID))
 | 
				
			||||||
	canCompare := false
 | 
						canCompare := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Pull request is allowed if this is a fork repository
 | 
						// Pull request is allowed if this is a fork repository
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -190,7 +190,12 @@ func IsPublicMember(ctx *context.APIContext) {
 | 
				
			|||||||
	if ctx.Written() {
 | 
						if ctx.Written() {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if userToCheck.IsPublicMember(ctx.Org.Organization.ID) {
 | 
						is, err := models.IsPublicMembership(ctx.Org.Organization.ID, userToCheck.ID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "IsPublicMembership", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if is {
 | 
				
			||||||
		ctx.Status(http.StatusNoContent)
 | 
							ctx.Status(http.StatusNoContent)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.NotFound()
 | 
							ctx.NotFound()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/convert"
 | 
						"code.gitea.io/gitea/modules/convert"
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
@@ -343,7 +344,7 @@ func Edit(ctx *context.APIContext) {
 | 
				
			|||||||
	if form.RepoAdminChangeTeamAccess != nil {
 | 
						if form.RepoAdminChangeTeamAccess != nil {
 | 
				
			||||||
		org.RepoAdminChangeTeamAccess = *form.RepoAdminChangeTeamAccess
 | 
							org.RepoAdminChangeTeamAccess = *form.RepoAdminChangeTeamAccess
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := models.UpdateUserCols(org.AsUser(),
 | 
						if err := models.UpdateUserCols(db.DefaultContext, org.AsUser(),
 | 
				
			||||||
		"full_name", "description", "website", "location",
 | 
							"full_name", "description", "website", "location",
 | 
				
			||||||
		"visibility", "repo_admin_change_team_access",
 | 
							"visibility", "repo_admin_change_team_access",
 | 
				
			||||||
	); err != nil {
 | 
						); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -953,10 +953,10 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check if current user has fork of repository or in the same repository.
 | 
						// Check if current user has fork of repository or in the same repository.
 | 
				
			||||||
	headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID)
 | 
						headRepo := models.GetForkedRepo(headUser.ID, baseRepo.ID)
 | 
				
			||||||
	if !has && !isSameRepo {
 | 
						if headRepo == nil && !isSameRepo {
 | 
				
			||||||
		log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
 | 
							log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
 | 
				
			||||||
		ctx.NotFound("HasForkedRepo")
 | 
							ctx.NotFound("GetForkedRepo")
 | 
				
			||||||
		return nil, nil, nil, nil, "", ""
 | 
							return nil, nil, nil, nil, "", ""
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package repo
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/convert"
 | 
						"code.gitea.io/gitea/modules/convert"
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
@@ -43,7 +44,7 @@ func ListStargazers(ctx *context.APIContext) {
 | 
				
			|||||||
	//   "200":
 | 
						//   "200":
 | 
				
			||||||
	//     "$ref": "#/responses/UserList"
 | 
						//     "$ref": "#/responses/UserList"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stargazers, err := ctx.Repo.Repository.GetStargazers(utils.GetListOptions(ctx))
 | 
						stargazers, err := models.GetStargazers(ctx.Repo.Repository, utils.GetListOptions(ctx))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "GetStargazers", err)
 | 
							ctx.Error(http.StatusInternalServerError, "GetStargazers", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@ func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func listUserFollowers(ctx *context.APIContext, u *models.User) {
 | 
					func listUserFollowers(ctx *context.APIContext, u *models.User) {
 | 
				
			||||||
	users, err := u.GetFollowers(utils.GetListOptions(ctx))
 | 
						users, err := models.GetUserFollowers(u, utils.GetListOptions(ctx))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
 | 
							ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -91,9 +91,9 @@ func ListFollowers(ctx *context.APIContext) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func listUserFollowing(ctx *context.APIContext, u *models.User) {
 | 
					func listUserFollowing(ctx *context.APIContext, u *models.User) {
 | 
				
			||||||
	users, err := u.GetFollowing(utils.GetListOptions(ctx))
 | 
						users, err := models.GetUserFollowing(u, utils.GetListOptions(ctx))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "GetFollowing", err)
 | 
							ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -157,7 +157,7 @@ func ListFollowing(ctx *context.APIContext) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkUserFollowing(ctx *context.APIContext, u *models.User, followID int64) {
 | 
					func checkUserFollowing(ctx *context.APIContext, u *models.User, followID int64) {
 | 
				
			||||||
	if u.IsFollowing(followID) {
 | 
						if user_model.IsFollowing(u.ID, followID) {
 | 
				
			||||||
		ctx.Status(http.StatusNoContent)
 | 
							ctx.Status(http.StatusNoContent)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.NotFound()
 | 
							ctx.NotFound()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,7 @@ func GetInfo(ctx *context.APIContext) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !u.IsVisibleToUser(ctx.User) {
 | 
						if !models.IsUserVisibleToViewer(u, ctx.User) {
 | 
				
			||||||
		// fake ErrUserNotExist error message to not leak information about existence
 | 
							// fake ErrUserNotExist error message to not leak information about existence
 | 
				
			||||||
		ctx.NotFound("GetUserByName", models.ErrUserNotExist{Name: ctx.Params(":username")})
 | 
							ctx.NotFound("GetUserByName", models.ErrUserNotExist{Name: ctx.Params(":username")})
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,10 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/web"
 | 
						"code.gitea.io/gitea/modules/web"
 | 
				
			||||||
	"code.gitea.io/gitea/routers/web/explore"
 | 
						"code.gitea.io/gitea/routers/web/explore"
 | 
				
			||||||
	router_user_setting "code.gitea.io/gitea/routers/web/user/setting"
 | 
						user_setting "code.gitea.io/gitea/routers/web/user/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/services/forms"
 | 
						"code.gitea.io/gitea/services/forms"
 | 
				
			||||||
	"code.gitea.io/gitea/services/mailer"
 | 
						"code.gitea.io/gitea/services/mailer"
 | 
				
			||||||
	"code.gitea.io/gitea/services/user"
 | 
						user_service "code.gitea.io/gitea/services/user"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -309,7 +309,7 @@ func EditUserPost(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(form.UserName) != 0 && u.Name != form.UserName {
 | 
						if len(form.UserName) != 0 && u.Name != form.UserName {
 | 
				
			||||||
		if err := router_user_setting.HandleUsernameChange(ctx, u, form.UserName); err != nil {
 | 
							if err := user_setting.HandleUsernameChange(ctx, u, form.UserName); err != nil {
 | 
				
			||||||
			ctx.Redirect(setting.AppSubURL + "/admin/users")
 | 
								ctx.Redirect(setting.AppSubURL + "/admin/users")
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -378,7 +378,7 @@ func DeleteUser(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = user.DeleteUser(u); err != nil {
 | 
						if err = user_service.DeleteUser(u); err != nil {
 | 
				
			||||||
		switch {
 | 
							switch {
 | 
				
			||||||
		case models.IsErrUserOwnRepos(err):
 | 
							case models.IsErrUserOwnRepos(err):
 | 
				
			||||||
			ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo"))
 | 
								ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo"))
 | 
				
			||||||
@@ -411,7 +411,7 @@ func AvatarPost(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	form := web.GetForm(ctx).(*forms.AvatarForm)
 | 
						form := web.GetForm(ctx).(*forms.AvatarForm)
 | 
				
			||||||
	if err := router_user_setting.UpdateAvatarSetting(ctx, form, u); err != nil {
 | 
						if err := user_setting.UpdateAvatarSetting(ctx, form, u); err != nil {
 | 
				
			||||||
		ctx.Flash.Error(err.Error())
 | 
							ctx.Flash.Error(err.Error())
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Flash.Success(ctx.Tr("settings.update_user_avatar_success"))
 | 
							ctx.Flash.Success(ctx.Tr("settings.update_user_avatar_success"))
 | 
				
			||||||
@@ -427,7 +427,7 @@ func DeleteAvatar(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := u.DeleteAvatar(); err != nil {
 | 
						if err := user_service.DeleteAvatar(u); err != nil {
 | 
				
			||||||
		ctx.Flash.Error(err.Error())
 | 
							ctx.Flash.Error(err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -141,7 +141,6 @@ func Home(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["MembersTotal"] = membersCount
 | 
						ctx.Data["MembersTotal"] = membersCount
 | 
				
			||||||
	ctx.Data["Members"] = members
 | 
						ctx.Data["Members"] = members
 | 
				
			||||||
	ctx.Data["Teams"] = ctx.Org.Teams
 | 
						ctx.Data["Teams"] = ctx.Org.Teams
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull
 | 
						ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pager := context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5)
 | 
						pager := context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,9 +18,10 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/web"
 | 
						"code.gitea.io/gitea/modules/web"
 | 
				
			||||||
	userSetting "code.gitea.io/gitea/routers/web/user/setting"
 | 
						user_setting "code.gitea.io/gitea/routers/web/user/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/services/forms"
 | 
						"code.gitea.io/gitea/services/forms"
 | 
				
			||||||
	"code.gitea.io/gitea/services/org"
 | 
						"code.gitea.io/gitea/services/org"
 | 
				
			||||||
 | 
						user_service "code.gitea.io/gitea/services/user"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -136,7 +137,7 @@ func SettingsPost(ctx *context.Context) {
 | 
				
			|||||||
func SettingsAvatar(ctx *context.Context) {
 | 
					func SettingsAvatar(ctx *context.Context) {
 | 
				
			||||||
	form := web.GetForm(ctx).(*forms.AvatarForm)
 | 
						form := web.GetForm(ctx).(*forms.AvatarForm)
 | 
				
			||||||
	form.Source = forms.AvatarLocal
 | 
						form.Source = forms.AvatarLocal
 | 
				
			||||||
	if err := userSetting.UpdateAvatarSetting(ctx, form, ctx.Org.Organization.AsUser()); err != nil {
 | 
						if err := user_setting.UpdateAvatarSetting(ctx, form, ctx.Org.Organization.AsUser()); err != nil {
 | 
				
			||||||
		ctx.Flash.Error(err.Error())
 | 
							ctx.Flash.Error(err.Error())
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Flash.Success(ctx.Tr("org.settings.update_avatar_success"))
 | 
							ctx.Flash.Success(ctx.Tr("org.settings.update_avatar_success"))
 | 
				
			||||||
@@ -147,7 +148,7 @@ func SettingsAvatar(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// SettingsDeleteAvatar response for delete avatar on settings page
 | 
					// SettingsDeleteAvatar response for delete avatar on settings page
 | 
				
			||||||
func SettingsDeleteAvatar(ctx *context.Context) {
 | 
					func SettingsDeleteAvatar(ctx *context.Context) {
 | 
				
			||||||
	if err := ctx.Org.Organization.AsUser().DeleteAvatar(); err != nil {
 | 
						if err := user_service.DeleteAvatar(ctx.Org.Organization.AsUser()); err != nil {
 | 
				
			||||||
		ctx.Flash.Error(err.Error())
 | 
							ctx.Flash.Error(err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,8 @@ func Branches(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
 | 
						ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
 | 
				
			||||||
	ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
 | 
						ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
 | 
				
			||||||
	ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
 | 
						ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
 | 
				
			||||||
	ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID))
 | 
						ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) ||
 | 
				
			||||||
 | 
							(ctx.IsSigned && models.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID))
 | 
				
			||||||
	ctx.Data["PageIsViewCode"] = true
 | 
						ctx.Data["PageIsViewCode"] = true
 | 
				
			||||||
	ctx.Data["PageIsBranches"] = true
 | 
						ctx.Data["PageIsBranches"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -331,8 +331,8 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 | 
				
			|||||||
	// "OwnForkRepo"
 | 
						// "OwnForkRepo"
 | 
				
			||||||
	var ownForkRepo *models.Repository
 | 
						var ownForkRepo *models.Repository
 | 
				
			||||||
	if ctx.User != nil && baseRepo.OwnerID != ctx.User.ID {
 | 
						if ctx.User != nil && baseRepo.OwnerID != ctx.User.ID {
 | 
				
			||||||
		repo, has := models.HasForkedRepo(ctx.User.ID, baseRepo.ID)
 | 
							repo := models.GetForkedRepo(ctx.User.ID, baseRepo.ID)
 | 
				
			||||||
		if has {
 | 
							if repo != nil {
 | 
				
			||||||
			ownForkRepo = repo
 | 
								ownForkRepo = repo
 | 
				
			||||||
			ctx.Data["OwnForkRepo"] = ownForkRepo
 | 
								ctx.Data["OwnForkRepo"] = ownForkRepo
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -355,12 +355,14 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 5. If the headOwner has a fork of the baseRepo - use that
 | 
						// 5. If the headOwner has a fork of the baseRepo - use that
 | 
				
			||||||
	if !has {
 | 
						if !has {
 | 
				
			||||||
		ci.HeadRepo, has = models.HasForkedRepo(ci.HeadUser.ID, baseRepo.ID)
 | 
							ci.HeadRepo = models.GetForkedRepo(ci.HeadUser.ID, baseRepo.ID)
 | 
				
			||||||
 | 
							has = ci.HeadRepo != nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 6. If the baseRepo is a fork and the headUser has a fork of that use that
 | 
						// 6. If the baseRepo is a fork and the headUser has a fork of that use that
 | 
				
			||||||
	if !has && baseRepo.IsFork {
 | 
						if !has && baseRepo.IsFork {
 | 
				
			||||||
		ci.HeadRepo, has = models.HasForkedRepo(ci.HeadUser.ID, baseRepo.ForkID)
 | 
							ci.HeadRepo = models.GetForkedRepo(ci.HeadUser.ID, baseRepo.ForkID)
 | 
				
			||||||
 | 
							has = ci.HeadRepo != nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 7. Otherwise if we're not the same repo and haven't found a repo give up
 | 
						// 7. Otherwise if we're not the same repo and haven't found a repo give up
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,7 +106,7 @@ func MustAllowPulls(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// User can send pull request if owns a forked repository.
 | 
						// User can send pull request if owns a forked repository.
 | 
				
			||||||
	if ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID) {
 | 
						if ctx.IsSigned && models.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID) {
 | 
				
			||||||
		ctx.Repo.PullRequest.Allowed = true
 | 
							ctx.Repo.PullRequest.Allowed = true
 | 
				
			||||||
		ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.User.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
 | 
							ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.User.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package repo
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	admin_model "code.gitea.io/gitea/models/admin"
 | 
						admin_model "code.gitea.io/gitea/models/admin"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
@@ -55,7 +56,7 @@ func SetDiffViewStyle(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["IsSplitStyle"] = style == "split"
 | 
						ctx.Data["IsSplitStyle"] = style == "split"
 | 
				
			||||||
	if err := ctx.User.UpdateDiffViewStyle(style); err != nil {
 | 
						if err := models.UpdateUserDiffViewStyle(ctx.User, style); err != nil {
 | 
				
			||||||
		ctx.ServerError("ErrUpdateDiffViewStyle", err)
 | 
							ctx.ServerError("ErrUpdateDiffViewStyle", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,23 +108,23 @@ func getForkRepository(ctx *context.Context) *models.Repository {
 | 
				
			|||||||
	ctx.Data["repo_name"] = forkRepo.Name
 | 
						ctx.Data["repo_name"] = forkRepo.Name
 | 
				
			||||||
	ctx.Data["description"] = forkRepo.Description
 | 
						ctx.Data["description"] = forkRepo.Description
 | 
				
			||||||
	ctx.Data["IsPrivate"] = forkRepo.IsPrivate || forkRepo.Owner.Visibility == structs.VisibleTypePrivate
 | 
						ctx.Data["IsPrivate"] = forkRepo.IsPrivate || forkRepo.Owner.Visibility == structs.VisibleTypePrivate
 | 
				
			||||||
	canForkToUser := forkRepo.OwnerID != ctx.User.ID && !ctx.User.HasForkedRepo(forkRepo.ID)
 | 
						canForkToUser := forkRepo.OwnerID != ctx.User.ID && !models.HasForkedRepo(ctx.User.ID, forkRepo.ID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["ForkRepo"] = forkRepo
 | 
						ctx.Data["ForkRepo"] = forkRepo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := ctx.User.GetOwnedOrganizations(); err != nil {
 | 
						ownedOrgs, err := models.GetOwnedOrgsByUserID(ctx.User.ID)
 | 
				
			||||||
		ctx.ServerError("GetOwnedOrganizations", err)
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.ServerError("GetOwnedOrgsByUserID", err)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var orgs []*models.User
 | 
						var orgs []*models.Organization
 | 
				
			||||||
	for _, org := range ctx.User.OwnedOrgs {
 | 
						for _, org := range ownedOrgs {
 | 
				
			||||||
		if forkRepo.OwnerID != org.ID && !org.HasForkedRepo(forkRepo.ID) {
 | 
							if forkRepo.OwnerID != org.ID && !models.HasForkedRepo(org.ID, forkRepo.ID) {
 | 
				
			||||||
			orgs = append(orgs, org)
 | 
								orgs = append(orgs, org)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var traverseParentRepo = forkRepo
 | 
						var traverseParentRepo = forkRepo
 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		if ctx.User.ID == traverseParentRepo.OwnerID {
 | 
							if ctx.User.ID == traverseParentRepo.OwnerID {
 | 
				
			||||||
			canForkToUser = false
 | 
								canForkToUser = false
 | 
				
			||||||
@@ -200,8 +200,8 @@ func ForkPost(ctx *context.Context) {
 | 
				
			|||||||
			ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		repo, has := models.HasForkedRepo(ctxUser.ID, traverseParentRepo.ID)
 | 
							repo := models.GetForkedRepo(ctxUser.ID, traverseParentRepo.ID)
 | 
				
			||||||
		if has {
 | 
							if repo != nil {
 | 
				
			||||||
			ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
 | 
								ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,7 +63,7 @@ func checkContextUser(ctx *context.Context, uid int64) *models.User {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !ctx.User.IsAdmin {
 | 
						if !ctx.User.IsAdmin {
 | 
				
			||||||
		orgsAvailable := []*models.User{}
 | 
							orgsAvailable := []*models.Organization{}
 | 
				
			||||||
		for i := 0; i < len(orgs); i++ {
 | 
							for i := 0; i < len(orgs); i++ {
 | 
				
			||||||
			if orgs[i].CanCreateRepo() {
 | 
								if orgs[i].CanCreateRepo() {
 | 
				
			||||||
				orgsAvailable = append(orgsAvailable, orgs[i])
 | 
									orgsAvailable = append(orgsAvailable, orgs[i])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -928,7 +928,9 @@ func Stars(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Title"] = ctx.Tr("repo.stargazers")
 | 
						ctx.Data["Title"] = ctx.Tr("repo.stargazers")
 | 
				
			||||||
	ctx.Data["CardsTitle"] = ctx.Tr("repo.stargazers")
 | 
						ctx.Data["CardsTitle"] = ctx.Tr("repo.stargazers")
 | 
				
			||||||
	ctx.Data["PageIsStargazers"] = true
 | 
						ctx.Data["PageIsStargazers"] = true
 | 
				
			||||||
	RenderUserCards(ctx, ctx.Repo.Repository.NumStars, ctx.Repo.Repository.GetStargazers, tplWatchers)
 | 
						RenderUserCards(ctx, ctx.Repo.Repository.NumStars, func(opts db.ListOptions) ([]*models.User, error) {
 | 
				
			||||||
 | 
							return models.GetStargazers(ctx.Repo.Repository, opts)
 | 
				
			||||||
 | 
						}, tplWatchers)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Forks render repository's forked users
 | 
					// Forks render repository's forked users
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/services/externalaccount"
 | 
						"code.gitea.io/gitea/services/externalaccount"
 | 
				
			||||||
	"code.gitea.io/gitea/services/forms"
 | 
						"code.gitea.io/gitea/services/forms"
 | 
				
			||||||
	"code.gitea.io/gitea/services/mailer"
 | 
						"code.gitea.io/gitea/services/mailer"
 | 
				
			||||||
 | 
						user_service "code.gitea.io/gitea/services/user"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/markbates/goth"
 | 
						"github.com/markbates/goth"
 | 
				
			||||||
	"github.com/tstranex/u2f"
 | 
						"github.com/tstranex/u2f"
 | 
				
			||||||
@@ -564,7 +565,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
 | 
				
			|||||||
	// If the user does not have a locale set, we save the current one.
 | 
						// If the user does not have a locale set, we save the current one.
 | 
				
			||||||
	if len(u.Language) == 0 {
 | 
						if len(u.Language) == 0 {
 | 
				
			||||||
		u.Language = ctx.Locale.Language()
 | 
							u.Language = ctx.Locale.Language()
 | 
				
			||||||
		if err := models.UpdateUserCols(u, "language"); err != nil {
 | 
							if err := models.UpdateUserCols(db.DefaultContext, u, "language"); err != nil {
 | 
				
			||||||
			log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language))
 | 
								log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language))
 | 
				
			||||||
			return setting.AppSubURL + "/"
 | 
								return setting.AppSubURL + "/"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -581,7 +582,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Register last login
 | 
						// Register last login
 | 
				
			||||||
	u.SetLastLogin()
 | 
						u.SetLastLogin()
 | 
				
			||||||
	if err := models.UpdateUserCols(u, "last_login_unix"); err != nil {
 | 
						if err := models.UpdateUserCols(db.DefaultContext, u, "last_login_unix"); err != nil {
 | 
				
			||||||
		ctx.ServerError("UpdateUserCols", err)
 | 
							ctx.ServerError("UpdateUserCols", err)
 | 
				
			||||||
		return setting.AppSubURL + "/"
 | 
							return setting.AppSubURL + "/"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -736,7 +737,7 @@ func updateAvatarIfNeed(url string, u *models.User) {
 | 
				
			|||||||
		if err == nil && resp.StatusCode == http.StatusOK {
 | 
							if err == nil && resp.StatusCode == http.StatusOK {
 | 
				
			||||||
			data, err := io.ReadAll(io.LimitReader(resp.Body, setting.Avatar.MaxFileSize+1))
 | 
								data, err := io.ReadAll(io.LimitReader(resp.Body, setting.Avatar.MaxFileSize+1))
 | 
				
			||||||
			if err == nil && int64(len(data)) <= setting.Avatar.MaxFileSize {
 | 
								if err == nil && int64(len(data)) <= setting.Avatar.MaxFileSize {
 | 
				
			||||||
				_ = u.UploadAvatar(data)
 | 
									_ = user_service.UploadAvatar(u, data)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -773,7 +774,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *login.Source, u *models.Us
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Register last login
 | 
							// Register last login
 | 
				
			||||||
		u.SetLastLogin()
 | 
							u.SetLastLogin()
 | 
				
			||||||
		if err := models.UpdateUserCols(u, "last_login_unix"); err != nil {
 | 
							if err := models.UpdateUserCols(db.DefaultContext, u, "last_login_unix"); err != nil {
 | 
				
			||||||
			ctx.ServerError("UpdateUserCols", err)
 | 
								ctx.ServerError("UpdateUserCols", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1345,7 +1346,7 @@ func handleUserCreated(ctx *context.Context, u *models.User, gothUser *goth.User
 | 
				
			|||||||
		u.IsAdmin = true
 | 
							u.IsAdmin = true
 | 
				
			||||||
		u.IsActive = true
 | 
							u.IsActive = true
 | 
				
			||||||
		u.SetLastLogin()
 | 
							u.SetLastLogin()
 | 
				
			||||||
		if err := models.UpdateUserCols(u, "is_admin", "is_active", "last_login_unix"); err != nil {
 | 
							if err := models.UpdateUserCols(db.DefaultContext, u, "is_admin", "is_active", "last_login_unix"); err != nil {
 | 
				
			||||||
			ctx.ServerError("UpdateUser", err)
 | 
								ctx.ServerError("UpdateUser", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1466,7 +1467,7 @@ func handleAccountActivation(ctx *context.Context, user *models.User) {
 | 
				
			|||||||
		ctx.ServerError("UpdateUser", err)
 | 
							ctx.ServerError("UpdateUser", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := models.UpdateUserCols(user, "is_active", "rands"); err != nil {
 | 
						if err := models.UpdateUserCols(db.DefaultContext, user, "is_active", "rands"); err != nil {
 | 
				
			||||||
		if models.IsErrUserNotExist(err) {
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
			ctx.NotFound("UpdateUserCols", err)
 | 
								ctx.NotFound("UpdateUserCols", err)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@@ -1726,7 +1727,7 @@ func ResetPasswdPost(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	u.MustChangePassword = false
 | 
						u.MustChangePassword = false
 | 
				
			||||||
	if err := models.UpdateUserCols(u, "must_change_password", "passwd", "passwd_hash_algo", "rands", "salt"); err != nil {
 | 
						if err := models.UpdateUserCols(db.DefaultContext, u, "must_change_password", "passwd", "passwd_hash_algo", "rands", "salt"); err != nil {
 | 
				
			||||||
		ctx.ServerError("UpdateUser", err)
 | 
							ctx.ServerError("UpdateUser", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1802,7 +1803,7 @@ func MustChangePasswordPost(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	u.MustChangePassword = false
 | 
						u.MustChangePassword = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := models.UpdateUserCols(u, "must_change_password", "passwd", "passwd_hash_algo", "salt"); err != nil {
 | 
						if err := models.UpdateUserCols(db.DefaultContext, u, "must_change_password", "passwd", "passwd_hash_algo", "salt"); err != nil {
 | 
				
			||||||
		ctx.ServerError("UpdateUser", err)
 | 
							ctx.ServerError("UpdateUser", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,6 +72,8 @@ func Dashboard(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
 | 
						ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
 | 
				
			||||||
	ctx.Data["PageIsDashboard"] = true
 | 
						ctx.Data["PageIsDashboard"] = true
 | 
				
			||||||
	ctx.Data["PageIsNews"] = true
 | 
						ctx.Data["PageIsNews"] = true
 | 
				
			||||||
 | 
						cnt, _ := models.GetOrganizationCount(db.DefaultContext, ctxUser)
 | 
				
			||||||
 | 
						ctx.Data["UserOrgsCount"] = cnt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var uid int64
 | 
						var uid int64
 | 
				
			||||||
	if ctxUser != nil {
 | 
						if ctxUser != nil {
 | 
				
			||||||
@@ -111,9 +113,9 @@ func Dashboard(ctx *context.Context) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		mirrors, err = ctxUser.GetMirrorRepositories()
 | 
							mirrors, err = models.GetUserMirrorRepositories(ctxUser.ID)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("GetMirrorRepositories", err)
 | 
								ctx.ServerError("GetUserMirrorRepositories", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,7 +107,7 @@ func Profile(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check view permissions
 | 
						// check view permissions
 | 
				
			||||||
	if !ctxUser.IsVisibleToUser(ctx.User) {
 | 
						if !models.IsUserVisibleToViewer(ctxUser, ctx.User) {
 | 
				
			||||||
		ctx.NotFound("user", fmt.Errorf(uname))
 | 
							ctx.NotFound("user", fmt.Errorf(uname))
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -137,10 +137,16 @@ func Profile(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var isFollowing bool
 | 
				
			||||||
 | 
						if ctx.User != nil && ctxUser != nil {
 | 
				
			||||||
 | 
							isFollowing = user_model.IsFollowing(ctx.User.ID, ctxUser.ID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["Title"] = ctxUser.DisplayName()
 | 
						ctx.Data["Title"] = ctxUser.DisplayName()
 | 
				
			||||||
	ctx.Data["PageIsUserProfile"] = true
 | 
						ctx.Data["PageIsUserProfile"] = true
 | 
				
			||||||
	ctx.Data["Owner"] = ctxUser
 | 
						ctx.Data["Owner"] = ctxUser
 | 
				
			||||||
	ctx.Data["OpenIDs"] = openIDs
 | 
						ctx.Data["OpenIDs"] = openIDs
 | 
				
			||||||
 | 
						ctx.Data["IsFollowing"] = isFollowing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Service.EnableUserHeatmap {
 | 
						if setting.Service.EnableUserHeatmap {
 | 
				
			||||||
		data, err := models.GetUserHeatmapDataByUser(ctxUser, ctx.User)
 | 
							data, err := models.GetUserHeatmapDataByUser(ctxUser, ctx.User)
 | 
				
			||||||
@@ -227,24 +233,24 @@ func Profile(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Keyword"] = keyword
 | 
						ctx.Data["Keyword"] = keyword
 | 
				
			||||||
	switch tab {
 | 
						switch tab {
 | 
				
			||||||
	case "followers":
 | 
						case "followers":
 | 
				
			||||||
		items, err := ctxUser.GetFollowers(db.ListOptions{
 | 
							items, err := models.GetUserFollowers(ctxUser, db.ListOptions{
 | 
				
			||||||
			PageSize: setting.UI.User.RepoPagingNum,
 | 
								PageSize: setting.UI.User.RepoPagingNum,
 | 
				
			||||||
			Page:     page,
 | 
								Page:     page,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("GetFollowers", err)
 | 
								ctx.ServerError("GetUserFollowers", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ctx.Data["Cards"] = items
 | 
							ctx.Data["Cards"] = items
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		total = ctxUser.NumFollowers
 | 
							total = ctxUser.NumFollowers
 | 
				
			||||||
	case "following":
 | 
						case "following":
 | 
				
			||||||
		items, err := ctxUser.GetFollowing(db.ListOptions{
 | 
							items, err := models.GetUserFollowing(ctxUser, db.ListOptions{
 | 
				
			||||||
			PageSize: setting.UI.User.RepoPagingNum,
 | 
								PageSize: setting.UI.User.RepoPagingNum,
 | 
				
			||||||
			Page:     page,
 | 
								Page:     page,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("GetFollowing", err)
 | 
								ctx.ServerError("GetUserFollowing", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ctx.Data["Cards"] = items
 | 
							ctx.Data["Cards"] = items
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	user_model "code.gitea.io/gitea/models/user"
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
@@ -74,7 +75,7 @@ func AccountPost(ctx *context.Context) {
 | 
				
			|||||||
			ctx.ServerError("UpdateUser", err)
 | 
								ctx.ServerError("UpdateUser", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := models.UpdateUserCols(ctx.User, "salt", "passwd_hash_algo", "passwd"); err != nil {
 | 
							if err := models.UpdateUserCols(db.DefaultContext, ctx.User, "salt", "passwd_hash_algo", "passwd"); err != nil {
 | 
				
			||||||
			ctx.ServerError("UpdateUser", err)
 | 
								ctx.ServerError("UpdateUser", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -158,7 +159,7 @@ func EmailPost(ctx *context.Context) {
 | 
				
			|||||||
			ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
 | 
								ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := ctx.User.SetEmailNotifications(preference); err != nil {
 | 
							if err := models.SetEmailNotifications(ctx.User, preference); err != nil {
 | 
				
			||||||
			log.Error("Set Email Notifications failed: %v", err)
 | 
								log.Error("Set Email Notifications failed: %v", err)
 | 
				
			||||||
			ctx.ServerError("SetEmailNotifications", err)
 | 
								ctx.ServerError("SetEmailNotifications", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/web/middleware"
 | 
						"code.gitea.io/gitea/modules/web/middleware"
 | 
				
			||||||
	"code.gitea.io/gitea/services/agit"
 | 
						"code.gitea.io/gitea/services/agit"
 | 
				
			||||||
	"code.gitea.io/gitea/services/forms"
 | 
						"code.gitea.io/gitea/services/forms"
 | 
				
			||||||
 | 
						user_service "code.gitea.io/gitea/services/user"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/unknwon/i18n"
 | 
						"github.com/unknwon/i18n"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -171,18 +172,18 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
 | 
				
			|||||||
		if !(st.IsImage() && !st.IsSvgImage()) {
 | 
							if !(st.IsImage() && !st.IsSvgImage()) {
 | 
				
			||||||
			return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
 | 
								return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err = ctxUser.UploadAvatar(data); err != nil {
 | 
							if err = user_service.UploadAvatar(ctxUser, data); err != nil {
 | 
				
			||||||
			return fmt.Errorf("UploadAvatar: %v", err)
 | 
								return fmt.Errorf("UploadAvatar: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if ctxUser.UseCustomAvatar && ctxUser.Avatar == "" {
 | 
						} else if ctxUser.UseCustomAvatar && ctxUser.Avatar == "" {
 | 
				
			||||||
		// No avatar is uploaded but setting has been changed to enable,
 | 
							// No avatar is uploaded but setting has been changed to enable,
 | 
				
			||||||
		// generate a random one when needed.
 | 
							// generate a random one when needed.
 | 
				
			||||||
		if err := ctxUser.GenerateRandomAvatar(); err != nil {
 | 
							if err := models.GenerateRandomAvatar(ctxUser); err != nil {
 | 
				
			||||||
			log.Error("GenerateRandomAvatar[%d]: %v", ctxUser.ID, err)
 | 
								log.Error("GenerateRandomAvatar[%d]: %v", ctxUser.ID, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := models.UpdateUserCols(ctxUser, "avatar", "avatar_email", "use_custom_avatar"); err != nil {
 | 
						if err := models.UpdateUserCols(db.DefaultContext, ctxUser, "avatar", "avatar_email", "use_custom_avatar"); err != nil {
 | 
				
			||||||
		return fmt.Errorf("UpdateUser: %v", err)
 | 
							return fmt.Errorf("UpdateUser: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,7 +204,7 @@ func AvatarPost(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DeleteAvatar render delete avatar page
 | 
					// DeleteAvatar render delete avatar page
 | 
				
			||||||
func DeleteAvatar(ctx *context.Context) {
 | 
					func DeleteAvatar(ctx *context.Context) {
 | 
				
			||||||
	if err := ctx.User.DeleteAvatar(); err != nil {
 | 
						if err := user_service.DeleteAvatar(ctx.User); err != nil {
 | 
				
			||||||
		ctx.Flash.Error(err.Error())
 | 
							ctx.Flash.Error(err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -301,11 +302,20 @@ func Repos(ctx *context.Context) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := ctxUser.GetRepositories(db.ListOptions{Page: 1, PageSize: setting.UI.Admin.UserPagingNum}, repoNames...); err != nil {
 | 
							userRepos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{
 | 
				
			||||||
			ctx.ServerError("GetRepositories", err)
 | 
								Actor:   ctxUser,
 | 
				
			||||||
 | 
								Private: true,
 | 
				
			||||||
 | 
								ListOptions: db.ListOptions{
 | 
				
			||||||
 | 
									Page:     1,
 | 
				
			||||||
 | 
									PageSize: setting.UI.Admin.UserPagingNum,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								LowerNames: repoNames,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("GetUserRepositories", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, repo := range ctxUser.Repos {
 | 
							for _, repo := range userRepos {
 | 
				
			||||||
			if repo.IsFork {
 | 
								if repo.IsFork {
 | 
				
			||||||
				if err := repo.GetBaseRepo(); err != nil {
 | 
									if err := repo.GetBaseRepo(); err != nil {
 | 
				
			||||||
					ctx.ServerError("GetBaseRepo", err)
 | 
										ctx.ServerError("GetBaseRepo", err)
 | 
				
			||||||
@@ -317,16 +327,12 @@ func Repos(ctx *context.Context) {
 | 
				
			|||||||
		ctx.Data["Dirs"] = repoNames
 | 
							ctx.Data["Dirs"] = repoNames
 | 
				
			||||||
		ctx.Data["ReposMap"] = repos
 | 
							ctx.Data["ReposMap"] = repos
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		var err error
 | 
							repos, count64, err := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts})
 | 
				
			||||||
		var count64 int64
 | 
					 | 
				
			||||||
		ctxUser.Repos, count64, err = models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("GetRepositories", err)
 | 
								ctx.ServerError("GetUserRepositories", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		count = int(count64)
 | 
							count = int(count64)
 | 
				
			||||||
		repos := ctxUser.Repos
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for i := range repos {
 | 
							for i := range repos {
 | 
				
			||||||
			if repos[i].IsFork {
 | 
								if repos[i].IsFork {
 | 
				
			||||||
@@ -371,7 +377,7 @@ func UpdateUIThemePost(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := ctx.User.UpdateTheme(form.Theme); err != nil {
 | 
						if err := models.UpdateUserTheme(ctx.User, form.Theme); err != nil {
 | 
				
			||||||
		ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
 | 
							ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
 | 
				
			||||||
		ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
 | 
							ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/web/middleware"
 | 
						"code.gitea.io/gitea/modules/web/middleware"
 | 
				
			||||||
@@ -127,7 +128,7 @@ func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore
 | 
				
			|||||||
	if len(user.Language) == 0 {
 | 
						if len(user.Language) == 0 {
 | 
				
			||||||
		lc := middleware.Locale(resp, req)
 | 
							lc := middleware.Locale(resp, req)
 | 
				
			||||||
		user.Language = lc.Language()
 | 
							user.Language = lc.Language()
 | 
				
			||||||
		if err := models.UpdateUserCols(user, "language"); err != nil {
 | 
							if err := models.UpdateUserCols(db.DefaultContext, user, "language"); err != nil {
 | 
				
			||||||
			log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", user.ID, user.Language))
 | 
								log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", user.ID, user.Language))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package db
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +25,7 @@ func Authenticate(user *models.User, login, password string) (*models.User, erro
 | 
				
			|||||||
		if err := user.SetPassword(password); err != nil {
 | 
							if err := user.SetPassword(password); err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := models.UpdateUserCols(user, "passwd", "passwd_hash_algo", "salt"); err != nil {
 | 
							if err := models.UpdateUserCols(db.DefaultContext, user, "passwd", "passwd_hash_algo", "salt"); err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,10 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	"code.gitea.io/gitea/models/login"
 | 
						"code.gitea.io/gitea/models/login"
 | 
				
			||||||
	"code.gitea.io/gitea/services/mailer"
 | 
						"code.gitea.io/gitea/services/mailer"
 | 
				
			||||||
 | 
						user_service "code.gitea.io/gitea/services/user"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Authenticate queries if login/password is valid against the LDAP directory pool,
 | 
					// Authenticate queries if login/password is valid against the LDAP directory pool,
 | 
				
			||||||
@@ -47,7 +49,7 @@ func (source *Source) Authenticate(user *models.User, userName, password string)
 | 
				
			|||||||
				cols = append(cols, "is_restricted")
 | 
									cols = append(cols, "is_restricted")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if len(cols) > 0 {
 | 
								if len(cols) > 0 {
 | 
				
			||||||
				err = models.UpdateUserCols(user, cols...)
 | 
									err = models.UpdateUserCols(db.DefaultContext, user, cols...)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return nil, err
 | 
										return nil, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -97,7 +99,7 @@ func (source *Source) Authenticate(user *models.User, userName, password string)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err == nil && len(source.AttributeAvatar) > 0 {
 | 
						if err == nil && len(source.AttributeAvatar) > 0 {
 | 
				
			||||||
		_ = user.UploadAvatar(sr.Avatar)
 | 
							_ = user_service.UploadAvatar(user, sr.Avatar)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return user, err
 | 
						return user, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						user_service "code.gitea.io/gitea/services/user"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Sync causes this ldap source to synchronize its users with the db
 | 
					// Sync causes this ldap source to synchronize its users with the db
 | 
				
			||||||
@@ -123,7 +124,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err == nil && len(source.AttributeAvatar) > 0 {
 | 
								if err == nil && len(source.AttributeAvatar) > 0 {
 | 
				
			||||||
				_ = usr.UploadAvatar(su.Avatar)
 | 
									_ = user_service.UploadAvatar(usr, su.Avatar)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if updateExisting {
 | 
							} else if updateExisting {
 | 
				
			||||||
			// Synchronize SSH Public Key if that attribute is set
 | 
								// Synchronize SSH Public Key if that attribute is set
 | 
				
			||||||
@@ -152,7 +153,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
				usr.IsActive = true
 | 
									usr.IsActive = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				err = models.UpdateUserCols(usr, "full_name", "email", "is_admin", "is_restricted", "is_active")
 | 
									err = models.UpdateUserCols(db.DefaultContext, usr, "full_name", "email", "is_admin", "is_restricted", "is_active")
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", source.loginSource.Name, usr.Name, err)
 | 
										log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", source.loginSource.Name, usr.Name, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -160,7 +161,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if usr.IsUploadAvatarChanged(su.Avatar) {
 | 
								if usr.IsUploadAvatarChanged(su.Avatar) {
 | 
				
			||||||
				if err == nil && len(source.AttributeAvatar) > 0 {
 | 
									if err == nil && len(source.AttributeAvatar) > 0 {
 | 
				
			||||||
					_ = usr.UploadAvatar(su.Avatar)
 | 
										_ = user_service.UploadAvatar(usr, su.Avatar)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -193,7 +194,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
 | 
				
			|||||||
				log.Trace("SyncExternalUsers[%s]: Deactivating user %s", source.loginSource.Name, usr.Name)
 | 
									log.Trace("SyncExternalUsers[%s]: Deactivating user %s", source.loginSource.Name, usr.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				usr.IsActive = false
 | 
									usr.IsActive = false
 | 
				
			||||||
				err = models.UpdateUserCols(usr, "is_active")
 | 
									err = models.UpdateUserCols(db.DefaultContext, usr, "is_active")
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					log.Error("SyncExternalUsers[%s]: Error deactivating user %s: %v", source.loginSource.Name, usr.Name, err)
 | 
										log.Error("SyncExternalUsers[%s]: Error deactivating user %s: %v", source.loginSource.Name, usr.Name, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,13 +6,18 @@ package user
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"crypto/md5"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"image/png"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	admin_model "code.gitea.io/gitea/models/admin"
 | 
						admin_model "code.gitea.io/gitea/models/admin"
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	user_model "code.gitea.io/gitea/models/user"
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/avatar"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/storage"
 | 
						"code.gitea.io/gitea/modules/storage"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -58,6 +63,13 @@ func DeleteUser(u *models.User) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = models.RewriteAllPublicKeys(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err = models.RewriteAllPrincipalKeys(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Note: There are something just cannot be roll back,
 | 
						// Note: There are something just cannot be roll back,
 | 
				
			||||||
	//	so just keep error logs of those operations.
 | 
						//	so just keep error logs of those operations.
 | 
				
			||||||
	path := models.UserPath(u.Name)
 | 
						path := models.UserPath(u.Name)
 | 
				
			||||||
@@ -104,3 +116,56 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return user_model.DeleteInactiveEmailAddresses(ctx)
 | 
						return user_model.DeleteInactiveEmailAddresses(ctx)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UploadAvatar saves custom avatar for user.
 | 
				
			||||||
 | 
					func UploadAvatar(u *models.User, data []byte) error {
 | 
				
			||||||
 | 
						m, err := avatar.Prepare(data)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx, committer, err := db.TxContext()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer committer.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u.UseCustomAvatar = true
 | 
				
			||||||
 | 
						// Different users can upload same image as avatar
 | 
				
			||||||
 | 
						// If we prefix it with u.ID, it will be separated
 | 
				
			||||||
 | 
						// Otherwise, if any of the users delete his avatar
 | 
				
			||||||
 | 
						// Other users will lose their avatars too.
 | 
				
			||||||
 | 
						u.Avatar = fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data)))))
 | 
				
			||||||
 | 
						if err = models.UpdateUserCols(ctx, u, "use_custom_avatar", "avatar"); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("updateUser: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
 | 
				
			||||||
 | 
							if err := png.Encode(w, *m); err != nil {
 | 
				
			||||||
 | 
								log.Error("Encode: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to create dir %s: %v", u.CustomAvatarRelativePath(), err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return committer.Commit()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeleteAvatar deletes the user's custom avatar.
 | 
				
			||||||
 | 
					func DeleteAvatar(u *models.User) error {
 | 
				
			||||||
 | 
						aPath := u.CustomAvatarRelativePath()
 | 
				
			||||||
 | 
						log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
 | 
				
			||||||
 | 
						if len(u.Avatar) > 0 {
 | 
				
			||||||
 | 
							if err := storage.Avatars.Delete(aPath); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("Failed to remove %s: %v", aPath, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u.UseCustomAvatar = false
 | 
				
			||||||
 | 
						u.Avatar = ""
 | 
				
			||||||
 | 
						if _, err := db.GetEngine(db.DefaultContext).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("UpdateUser: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@
 | 
				
			|||||||
				<div class="ui attached segment members">
 | 
									<div class="ui attached segment members">
 | 
				
			||||||
					{{$isMember := .IsOrganizationMember}}
 | 
										{{$isMember := .IsOrganizationMember}}
 | 
				
			||||||
					{{range .Members}}
 | 
										{{range .Members}}
 | 
				
			||||||
						{{if or $isMember (.IsPublicMember $.Org.ID)}}
 | 
											{{if or $isMember (call $.IsPublicMember .ID)}}
 | 
				
			||||||
							<a href="{{.HomeLink}}" title="{{.Name}}{{if .FullName}} ({{.FullName}}){{end}}">
 | 
												<a href="{{.HomeLink}}" title="{{.Name}}{{if .FullName}} ({{.FullName}}){{end}}">
 | 
				
			||||||
								{{avatar .}}
 | 
													{{avatar .}}
 | 
				
			||||||
							</a>
 | 
												</a>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
	{{end}}
 | 
						{{end}}
 | 
				
			||||||
	]"
 | 
						]"
 | 
				
			||||||
	:is-organization="false"
 | 
						:is-organization="false"
 | 
				
			||||||
	:organizations-total-count="{{.ContextUser.GetOrganizationCount}}"
 | 
						:organizations-total-count="{{.UserOrgsCount}}"
 | 
				
			||||||
	:can-create-organization="{{.SignedUser.CanCreateOrganization}}"
 | 
						:can-create-organization="{{.SignedUser.CanCreateOrganization}}"
 | 
				
			||||||
	{{end}}
 | 
						{{end}}
 | 
				
			||||||
	inline-template
 | 
						inline-template
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,7 @@
 | 
				
			|||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
							{{if and .IsSigned (ne .SignedUserName .Owner.Name)}}
 | 
												{{if and .IsSigned (ne .SignedUserName .Owner.Name)}}
 | 
				
			||||||
							<li class="follow">
 | 
												<li class="follow">
 | 
				
			||||||
								{{if .SignedUser.IsFollowing .Owner.ID}}
 | 
													{{if $.IsFollowing}}
 | 
				
			||||||
									<form method="post" action="{{.Link}}/action/unfollow?redirect_to={{$.Link}}">
 | 
														<form method="post" action="{{.Link}}/action/unfollow?redirect_to={{$.Link}}">
 | 
				
			||||||
										{{$.CsrfTokenHtml}}
 | 
															{{$.CsrfTokenHtml}}
 | 
				
			||||||
										<button type="submit" class="ui basic red button">{{svg "octicon-person"}} {{.i18n.Tr "user.unfollow"}}</button>
 | 
															<button type="submit" class="ui basic red button">{{svg "octicon-person"}} {{.i18n.Tr "user.unfollow"}}</button>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user