mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Move organization related structs into sub package (#18518)
* Move organization related structs into sub package * Fix test * Fix lint * Move more functions into sub packages * Fix bug * Fix test * Update models/organization/team_repo.go Co-authored-by: KN4CK3R <admin@oldschoolhack.me> * Apply suggestions from code review Co-authored-by: KN4CK3R <admin@oldschoolhack.me> * Fix fmt * Follow suggestion from @Gusted * Fix test * Fix test * Fix bug * Use ctx but db.DefaultContext on routers * Fix bug * Fix bug * fix bug * Update models/organization/team_user.go * Fix bug Co-authored-by: KN4CK3R <admin@oldschoolhack.me> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -149,7 +150,7 @@ func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, i
 | 
			
		||||
		return fmt.Errorf("refreshCollaboratorAccesses: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teams, err := OrgFromUser(repo.Owner).loadTeams(e)
 | 
			
		||||
	teams, err := organization.FindOrgTeams(ctx, repo.Owner.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -163,11 +164,11 @@ func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, i
 | 
			
		||||
		// have relations with repository.
 | 
			
		||||
		if t.IsOwnerTeam() {
 | 
			
		||||
			t.AccessMode = perm.AccessModeOwner
 | 
			
		||||
		} else if !t.hasRepository(e, repo.ID) {
 | 
			
		||||
		} else if !hasRepository(ctx, t, repo.ID) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = t.getMembers(e); err != nil {
 | 
			
		||||
		if err = t.GetMembersCtx(ctx); err != nil {
 | 
			
		||||
			return fmt.Errorf("getMembers '%d': %v", t.ID, err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, m := range t.Members {
 | 
			
		||||
@@ -198,7 +199,7 @@ func recalculateUserAccess(ctx context.Context, repo *repo_model.Repository, uid
 | 
			
		||||
	if err = repo.GetOwner(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if repo.Owner.IsOrganization() {
 | 
			
		||||
		var teams []Team
 | 
			
		||||
		var teams []organization.Team
 | 
			
		||||
		if err := e.Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
			Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
			Where("team.org_id = ?", repo.OwnerID).
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
@@ -127,7 +128,7 @@ func TestRepository_RecalculateAccesses2(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestRepository_RecalculateAccesses3(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	team5 := unittest.AssertExistsAndLoadBean(t, &Team{ID: 5}).(*Team)
 | 
			
		||||
	team5 := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team)
 | 
			
		||||
	user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User)
 | 
			
		||||
 | 
			
		||||
	has, err := db.GetEngine(db.DefaultContext).Get(&Access{UserID: 29, RepoID: 23})
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -318,7 +319,7 @@ func (a *Action) GetIssueContent() string {
 | 
			
		||||
type GetFeedsOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	RequestedUser   *user_model.User       // the user we want activity for
 | 
			
		||||
	RequestedTeam   *Team                  // the team we want activity for
 | 
			
		||||
	RequestedTeam   *organization.Team     // the team we want activity for
 | 
			
		||||
	RequestedRepo   *repo_model.Repository // the repo we want activity for
 | 
			
		||||
	Actor           *user_model.User       // the user viewing the activity
 | 
			
		||||
	IncludePrivate  bool                   // include private actions
 | 
			
		||||
@@ -399,7 +400,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.RequestedTeam != nil {
 | 
			
		||||
		env := OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(opts.RequestedTeam)
 | 
			
		||||
		env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(opts.RequestedTeam)
 | 
			
		||||
		teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("GetTeamRepositories: %v", err)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
@@ -94,7 +95,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	in, err := IsUserInTeams(userID, protectBranch.WhitelistTeamIDs)
 | 
			
		||||
	in, err := organization.IsUserInTeams(db.DefaultContext, userID, protectBranch.WhitelistTeamIDs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("IsUserInTeams: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
@@ -117,7 +118,7 @@ func IsUserMergeWhitelisted(protectBranch *ProtectedBranch, userID int64, permis
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	in, err := IsUserInTeams(userID, protectBranch.MergeWhitelistTeamIDs)
 | 
			
		||||
	in, err := organization.IsUserInTeams(db.DefaultContext, userID, protectBranch.MergeWhitelistTeamIDs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("IsUserInTeams: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
@@ -149,7 +150,7 @@ func isUserOfficialReviewer(ctx context.Context, protectBranch *ProtectedBranch,
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inTeam, err := isUserInTeams(db.GetEngine(ctx), user.ID, protectBranch.ApprovalsWhitelistTeamIDs)
 | 
			
		||||
	inTeam, err := organization.IsUserInTeams(ctx, user.ID, protectBranch.ApprovalsWhitelistTeamIDs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -471,7 +472,7 @@ func updateTeamWhitelist(repo *repo_model.Repository, currentWhitelist, newWhite
 | 
			
		||||
		return currentWhitelist, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teams, err := GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, perm.AccessModeRead)
 | 
			
		||||
	teams, err := organization.GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, perm.AccessModeRead)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("GetTeamsWithAccessToRepo [org_id: %d, repo_id: %d]: %v", repo.OwnerID, repo.ID, err)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -58,19 +58,6 @@ func (err ErrUserHasOrgs) Error() string {
 | 
			
		||||
	return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrUserNotAllowedCreateOrg represents a "UserNotAllowedCreateOrg" kind of error.
 | 
			
		||||
type ErrUserNotAllowedCreateOrg struct{}
 | 
			
		||||
 | 
			
		||||
// IsErrUserNotAllowedCreateOrg checks if an error is an ErrUserNotAllowedCreateOrg.
 | 
			
		||||
func IsErrUserNotAllowedCreateOrg(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrUserNotAllowedCreateOrg)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrUserNotAllowedCreateOrg) Error() string {
 | 
			
		||||
	return "user is not allowed to create organizations"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  __      __.__ __   .__
 | 
			
		||||
// /  \    /  \__|  | _|__|
 | 
			
		||||
// \   \/\/   /  |  |/ /  |
 | 
			
		||||
@@ -158,44 +145,6 @@ func (err ErrAccessTokenEmpty) Error() string {
 | 
			
		||||
	return "access token is empty"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ________                            .__                __  .__
 | 
			
		||||
// \_____  \_______  _________    ____ |__|____________ _/  |_|__| ____   ____
 | 
			
		||||
//  /   |   \_  __ \/ ___\__  \  /    \|  \___   /\__  \\   __\  |/  _ \ /    \
 | 
			
		||||
// /    |    \  | \/ /_/  > __ \|   |  \  |/    /  / __ \|  | |  (  <_> )   |  \
 | 
			
		||||
// \_______  /__|  \___  (____  /___|  /__/_____ \(____  /__| |__|\____/|___|  /
 | 
			
		||||
//         \/     /_____/     \/     \/         \/     \/                    \/
 | 
			
		||||
 | 
			
		||||
// ErrOrgNotExist represents a "OrgNotExist" kind of error.
 | 
			
		||||
type ErrOrgNotExist struct {
 | 
			
		||||
	ID   int64
 | 
			
		||||
	Name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrOrgNotExist checks if an error is a ErrOrgNotExist.
 | 
			
		||||
func IsErrOrgNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrOrgNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrOrgNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("org does not exist [id: %d, name: %s]", err.ID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrLastOrgOwner represents a "LastOrgOwner" kind of error.
 | 
			
		||||
type ErrLastOrgOwner struct {
 | 
			
		||||
	UID int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrLastOrgOwner checks if an error is a ErrLastOrgOwner.
 | 
			
		||||
func IsErrLastOrgOwner(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrLastOrgOwner)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrLastOrgOwner) Error() string {
 | 
			
		||||
	return fmt.Sprintf("user is the last member of owner team [uid: %d]", err.UID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//.____   ____________________
 | 
			
		||||
//|    |  \_   _____/   _____/
 | 
			
		||||
//|    |   |    __) \_____  \
 | 
			
		||||
@@ -1195,46 +1144,6 @@ func (err ErrMilestoneNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("milestone does not exist [id: %d, repo_id: %d]", err.ID, err.RepoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ___________
 | 
			
		||||
// \__    ___/___ _____    _____
 | 
			
		||||
//   |    |_/ __ \\__  \  /     \
 | 
			
		||||
//   |    |\  ___/ / __ \|  Y Y  \
 | 
			
		||||
//   |____| \___  >____  /__|_|  /
 | 
			
		||||
//              \/     \/      \/
 | 
			
		||||
 | 
			
		||||
// ErrTeamAlreadyExist represents a "TeamAlreadyExist" kind of error.
 | 
			
		||||
type ErrTeamAlreadyExist struct {
 | 
			
		||||
	OrgID int64
 | 
			
		||||
	Name  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrTeamAlreadyExist checks if an error is a ErrTeamAlreadyExist.
 | 
			
		||||
func IsErrTeamAlreadyExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrTeamAlreadyExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrTeamAlreadyExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrTeamNotExist represents a "TeamNotExist" error
 | 
			
		||||
type ErrTeamNotExist struct {
 | 
			
		||||
	OrgID  int64
 | 
			
		||||
	TeamID int64
 | 
			
		||||
	Name   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrTeamNotExist checks if an error is a ErrTeamNotExist.
 | 
			
		||||
func IsErrTeamNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrTeamNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrTeamNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  ____ ___        .__                    .___
 | 
			
		||||
// |    |   \______ |  |   _________     __| _/
 | 
			
		||||
// |    |   /\____ \|  |  /  _ \__  \   / __ |
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
  authorize: 4 # owner
 | 
			
		||||
  num_repos: 3
 | 
			
		||||
  num_members: 1
 | 
			
		||||
  can_create_org_repo: true
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 2
 | 
			
		||||
@@ -15,6 +16,7 @@
 | 
			
		||||
  authorize: 2 # write
 | 
			
		||||
  num_repos: 1
 | 
			
		||||
  num_members: 2
 | 
			
		||||
  can_create_org_repo: false
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 3
 | 
			
		||||
@@ -24,6 +26,7 @@
 | 
			
		||||
  authorize: 4 # owner
 | 
			
		||||
  num_repos: 0
 | 
			
		||||
  num_members: 1
 | 
			
		||||
  can_create_org_repo: true
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 4
 | 
			
		||||
@@ -33,6 +36,7 @@
 | 
			
		||||
  authorize: 4 # owner
 | 
			
		||||
  num_repos: 0
 | 
			
		||||
  num_members: 1
 | 
			
		||||
  can_create_org_repo: true
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 5
 | 
			
		||||
@@ -42,6 +46,7 @@
 | 
			
		||||
  authorize: 4 # owner
 | 
			
		||||
  num_repos: 2
 | 
			
		||||
  num_members: 2
 | 
			
		||||
  can_create_org_repo: true
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 6
 | 
			
		||||
@@ -51,6 +56,7 @@
 | 
			
		||||
  authorize: 4 # owner
 | 
			
		||||
  num_repos: 2
 | 
			
		||||
  num_members: 1
 | 
			
		||||
  can_create_org_repo: true
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 7
 | 
			
		||||
@@ -60,6 +66,7 @@
 | 
			
		||||
  authorize: 2 # write
 | 
			
		||||
  num_repos: 1
 | 
			
		||||
  num_members: 1
 | 
			
		||||
  can_create_org_repo: false
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 8
 | 
			
		||||
@@ -69,6 +76,7 @@
 | 
			
		||||
  authorize: 2 # write
 | 
			
		||||
  num_repos: 1
 | 
			
		||||
  num_members: 1
 | 
			
		||||
  can_create_org_repo: false
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 9
 | 
			
		||||
@@ -78,6 +86,7 @@
 | 
			
		||||
  authorize: 1 # read
 | 
			
		||||
  num_repos: 1
 | 
			
		||||
  num_members: 2
 | 
			
		||||
  can_create_org_repo: false
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 10
 | 
			
		||||
@@ -87,6 +96,7 @@
 | 
			
		||||
  authorize: 1 # owner
 | 
			
		||||
  num_repos: 0
 | 
			
		||||
  num_members: 1
 | 
			
		||||
  can_create_org_repo: false
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 11
 | 
			
		||||
@@ -96,6 +106,7 @@
 | 
			
		||||
  authorize: 1 # read
 | 
			
		||||
  num_repos: 0
 | 
			
		||||
  num_members: 0
 | 
			
		||||
  can_create_org_repo: false
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 12
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/foreignreference"
 | 
			
		||||
	"code.gitea.io/gitea/models/issues"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
@@ -1238,9 +1239,9 @@ type IssuesOptions struct {
 | 
			
		||||
	// prioritize issues from this repo
 | 
			
		||||
	PriorityRepoID int64
 | 
			
		||||
	IsArchived     util.OptionalBool
 | 
			
		||||
	Org            *Organization    // issues permission scope
 | 
			
		||||
	Team           *Team            // issues permission scope
 | 
			
		||||
	User           *user_model.User // issues permission scope
 | 
			
		||||
	Org            *organization.Organization // issues permission scope
 | 
			
		||||
	Team           *organization.Team         // issues permission scope
 | 
			
		||||
	User           *user_model.User           // issues permission scope
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sortIssuesSession sort an issues-related session based on the provided
 | 
			
		||||
@@ -1401,7 +1402,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// issuePullAccessibleRepoCond userID must not be zero, this condition require join repository table
 | 
			
		||||
func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *Organization, team *Team, isPull bool) builder.Cond {
 | 
			
		||||
func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organization.Organization, team *organization.Team, isPull bool) builder.Cond {
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
	unitType := unit.TypeIssues
 | 
			
		||||
	if isPull {
 | 
			
		||||
@@ -1749,8 +1750,8 @@ type UserIssueStatsOptions struct {
 | 
			
		||||
	IsArchived util.OptionalBool
 | 
			
		||||
	LabelIDs   []int64
 | 
			
		||||
	RepoCond   builder.Cond
 | 
			
		||||
	Org        *Organization
 | 
			
		||||
	Team       *Team
 | 
			
		||||
	Org        *organization.Organization
 | 
			
		||||
	Team       *organization.Team
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
 | 
			
		||||
@@ -2296,7 +2297,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *user_
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if issue.Repo.Owner.IsOrganization() && len(mentionTeams) > 0 {
 | 
			
		||||
		teams := make([]*Team, 0, len(mentionTeams))
 | 
			
		||||
		teams := make([]*organization.Team, 0, len(mentionTeams))
 | 
			
		||||
		if err := db.GetEngine(ctx).
 | 
			
		||||
			Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
			Where("team_repo.repo_id=?", issue.Repo.ID).
 | 
			
		||||
@@ -2316,7 +2317,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *user_
 | 
			
		||||
					resolved[issue.Repo.Owner.LowerName+"/"+team.LowerName] = true
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				has, err := db.GetEngine(ctx).Get(&TeamUnit{OrgID: issue.Repo.Owner.ID, TeamID: team.ID, Type: unittype})
 | 
			
		||||
				has, err := db.GetEngine(ctx).Get(&organization.TeamUnit{OrgID: issue.Repo.Owner.ID, TeamID: team.ID, Type: unittype})
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, fmt.Errorf("get team units (%d): %v", team.ID, err)
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/issues"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
@@ -213,9 +214,9 @@ type Comment struct {
 | 
			
		||||
	Time             *TrackedTime `xorm:"-"`
 | 
			
		||||
	AssigneeID       int64
 | 
			
		||||
	RemovedAssignee  bool
 | 
			
		||||
	Assignee         *user_model.User `xorm:"-"`
 | 
			
		||||
	AssigneeTeamID   int64            `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
	AssigneeTeam     *Team            `xorm:"-"`
 | 
			
		||||
	Assignee         *user_model.User   `xorm:"-"`
 | 
			
		||||
	AssigneeTeamID   int64              `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
	AssigneeTeam     *organization.Team `xorm:"-"`
 | 
			
		||||
	ResolveDoerID    int64
 | 
			
		||||
	ResolveDoer      *user_model.User `xorm:"-"`
 | 
			
		||||
	OldTitle         string
 | 
			
		||||
@@ -581,8 +582,8 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c.Issue.Repo.Owner.IsOrganization() {
 | 
			
		||||
			c.AssigneeTeam, err = GetTeamByID(c.AssigneeTeamID)
 | 
			
		||||
			if err != nil && !IsErrTeamNotExist(err) {
 | 
			
		||||
			c.AssigneeTeam, err = organization.GetTeamByID(c.AssigneeTeamID)
 | 
			
		||||
			if err != nil && !organization.IsErrTeamNotExist(err) {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ package models
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -30,7 +31,7 @@ func TestFixturesAreConsistent(t *testing.T) {
 | 
			
		||||
		&PullRequest{},
 | 
			
		||||
		&Milestone{},
 | 
			
		||||
		&Label{},
 | 
			
		||||
		&Team{},
 | 
			
		||||
		&organization.Team{},
 | 
			
		||||
		&Action{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -151,7 +152,7 @@ func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *repo_
 | 
			
		||||
	var notify []*Notification
 | 
			
		||||
 | 
			
		||||
	if newOwner.IsOrganization() {
 | 
			
		||||
		users, err := getUsersWhoCanCreateOrgRepo(db.GetEngine(ctx), newOwner.ID)
 | 
			
		||||
		users, err := organization.GetUsersWhoCanCreateOrgRepo(ctx, newOwner.ID)
 | 
			
		||||
		if err != nil || len(users) == 0 {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										913
									
								
								models/org.go
									
									
									
									
									
								
							
							
						
						
									
										913
									
								
								models/org.go
									
									
									
									
									
								
							@@ -11,443 +11,15 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Organization represents an organization
 | 
			
		||||
type Organization user_model.User
 | 
			
		||||
 | 
			
		||||
// OrgFromUser converts user to organization
 | 
			
		||||
func OrgFromUser(user *user_model.User) *Organization {
 | 
			
		||||
	return (*Organization)(user)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableName represents the real table name of Organization
 | 
			
		||||
func (Organization) TableName() string {
 | 
			
		||||
	return "user"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOwnedBy returns true if given user is in the owner team.
 | 
			
		||||
func (org *Organization) IsOwnedBy(uid int64) (bool, error) {
 | 
			
		||||
	return IsOrganizationOwner(org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOrgMember returns true if given user is member of organization.
 | 
			
		||||
func (org *Organization) IsOrgMember(uid int64) (bool, error) {
 | 
			
		||||
	return IsOrganizationMember(org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanCreateOrgRepo returns true if given user can create repo in organization
 | 
			
		||||
func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) {
 | 
			
		||||
	return CanCreateOrgRepo(org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getTeam(e db.Engine, name string) (*Team, error) {
 | 
			
		||||
	return getTeam(e, org.ID, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeam returns named team of organization.
 | 
			
		||||
func (org *Organization) GetTeam(name string) (*Team, error) {
 | 
			
		||||
	return org.getTeam(db.GetEngine(db.DefaultContext), name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getOwnerTeam(e db.Engine) (*Team, error) {
 | 
			
		||||
	return org.getTeam(e, ownerTeamName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnerTeam returns owner team of organization.
 | 
			
		||||
func (org *Organization) GetOwnerTeam() (*Team, error) {
 | 
			
		||||
	return org.getOwnerTeam(db.GetEngine(db.DefaultContext))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) loadTeams(e db.Engine) ([]*Team, error) {
 | 
			
		||||
	var teams []*Team
 | 
			
		||||
	return teams, e.
 | 
			
		||||
		Where("org_id=?", org.ID).
 | 
			
		||||
		OrderBy("CASE WHEN name LIKE '" + ownerTeamName + "' THEN '' ELSE name END").
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadTeams load teams if not loaded.
 | 
			
		||||
func (org *Organization) LoadTeams() ([]*Team, error) {
 | 
			
		||||
	return org.loadTeams(db.GetEngine(db.DefaultContext))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetMembers returns all members of organization.
 | 
			
		||||
func (org *Organization) GetMembers() (user_model.UserList, map[int64]bool, error) {
 | 
			
		||||
	return FindOrgMembers(&FindOrgMembersOpts{
 | 
			
		||||
		OrgID: org.ID,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasMemberWithUserID returns true if user with userID is part of the u organisation.
 | 
			
		||||
func (org *Organization) HasMemberWithUserID(userID int64) bool {
 | 
			
		||||
	return org.hasMemberWithUserID(db.GetEngine(db.DefaultContext), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) hasMemberWithUserID(e db.Engine, userID int64) bool {
 | 
			
		||||
	isMember, err := isOrganizationMember(e, org.ID, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("IsOrganizationMember: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return isMember
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AvatarLink returns the full avatar link with http host
 | 
			
		||||
func (org *Organization) AvatarLink() string {
 | 
			
		||||
	return org.AsUser().AvatarLink()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTMLURL returns the organization's full link.
 | 
			
		||||
func (org *Organization) HTMLURL() string {
 | 
			
		||||
	return org.AsUser().HTMLURL()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OrganisationLink returns the organization sub page link.
 | 
			
		||||
func (org *Organization) OrganisationLink() string {
 | 
			
		||||
	return org.AsUser().OrganisationLink()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ShortName ellipses username to length
 | 
			
		||||
func (org *Organization) ShortName(length int) string {
 | 
			
		||||
	return org.AsUser().ShortName(length)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HomeLink returns the user or organization home page link.
 | 
			
		||||
func (org *Organization) HomeLink() string {
 | 
			
		||||
	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
 | 
			
		||||
type FindOrgMembersOpts struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	OrgID      int64
 | 
			
		||||
	PublicOnly bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrgMembers counts the organization's members
 | 
			
		||||
func CountOrgMembers(opts *FindOrgMembersOpts) (int64, error) {
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).Where("org_id=?", opts.OrgID)
 | 
			
		||||
	if opts.PublicOnly {
 | 
			
		||||
		sess.And("is_public = ?", true)
 | 
			
		||||
	}
 | 
			
		||||
	return sess.Count(new(OrgUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindOrgMembers loads organization members according conditions
 | 
			
		||||
func FindOrgMembers(opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bool, error) {
 | 
			
		||||
	ous, err := GetOrgUsersByOrgID(opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ids := make([]int64, len(ous))
 | 
			
		||||
	idsIsPublic := make(map[int64]bool, len(ous))
 | 
			
		||||
	for i, ou := range ous {
 | 
			
		||||
		ids[i] = ou.UID
 | 
			
		||||
		idsIsPublic[ou.UID] = ou.IsPublic
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	users, err := user_model.GetUsersByIDs(ids)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return users, idsIsPublic, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddMember adds new member to organization.
 | 
			
		||||
func (org *Organization) AddMember(uid int64) error {
 | 
			
		||||
	return AddOrgUser(org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveMember removes member from organization.
 | 
			
		||||
func (org *Organization) RemoveMember(uid int64) error {
 | 
			
		||||
	return RemoveOrgUser(org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) removeOrgRepo(e db.Engine, repoID int64) error {
 | 
			
		||||
	return removeOrgRepo(e, org.ID, repoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveOrgRepo removes all team-repository relations of organization.
 | 
			
		||||
func (org *Organization) RemoveOrgRepo(repoID int64) error {
 | 
			
		||||
	return org.removeOrgRepo(db.GetEngine(db.DefaultContext), repoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AsUser returns the org as user object
 | 
			
		||||
func (org *Organization) AsUser() *user_model.User {
 | 
			
		||||
	return (*user_model.User)(org)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisplayName returns full name if it's not empty,
 | 
			
		||||
// returns username otherwise.
 | 
			
		||||
func (org *Organization) DisplayName() string {
 | 
			
		||||
	return org.AsUser().DisplayName()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CustomAvatarRelativePath returns user custom avatar relative path.
 | 
			
		||||
func (org *Organization) CustomAvatarRelativePath() string {
 | 
			
		||||
	return org.Avatar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateOrganization creates record of a new organization.
 | 
			
		||||
func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
 | 
			
		||||
	if !owner.CanCreateOrganization() {
 | 
			
		||||
		return ErrUserNotAllowedCreateOrg{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = user_model.IsUsableUsername(org.Name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isExist, err := user_model.IsUserExist(0, org.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if isExist {
 | 
			
		||||
		return user_model.ErrUserAlreadyExist{Name: org.Name}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	org.LowerName = strings.ToLower(org.Name)
 | 
			
		||||
	if org.Rands, err = user_model.GetUserSalt(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if org.Salt, err = user_model.GetUserSalt(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	org.UseCustomAvatar = true
 | 
			
		||||
	org.MaxRepoCreation = -1
 | 
			
		||||
	org.NumTeams = 1
 | 
			
		||||
	org.NumMembers = 1
 | 
			
		||||
	org.Type = user_model.UserTypeOrganization
 | 
			
		||||
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err = user_model.DeleteUserRedirect(ctx, org.Name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, org); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert organization: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = user_model.GenerateRandomAvatarCtx(ctx, org.AsUser()); err != nil {
 | 
			
		||||
		return fmt.Errorf("generate random avatar: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add initial creator to organization and owner team.
 | 
			
		||||
	if err = db.Insert(ctx, &OrgUser{
 | 
			
		||||
		UID:   owner.ID,
 | 
			
		||||
		OrgID: org.ID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert org-user relation: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create default owner team.
 | 
			
		||||
	t := &Team{
 | 
			
		||||
		OrgID:                   org.ID,
 | 
			
		||||
		LowerName:               strings.ToLower(ownerTeamName),
 | 
			
		||||
		Name:                    ownerTeamName,
 | 
			
		||||
		AccessMode:              perm.AccessModeOwner,
 | 
			
		||||
		NumMembers:              1,
 | 
			
		||||
		IncludesAllRepositories: true,
 | 
			
		||||
		CanCreateOrgRepo:        true,
 | 
			
		||||
	}
 | 
			
		||||
	if err = db.Insert(ctx, t); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert owner team: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// insert units for team
 | 
			
		||||
	units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
 | 
			
		||||
	for _, tp := range unit.AllRepoUnitTypes {
 | 
			
		||||
		units = append(units, TeamUnit{
 | 
			
		||||
			OrgID:  org.ID,
 | 
			
		||||
			TeamID: t.ID,
 | 
			
		||||
			Type:   tp,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, &units); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, &TeamUser{
 | 
			
		||||
		UID:    owner.ID,
 | 
			
		||||
		OrgID:  org.ID,
 | 
			
		||||
		TeamID: t.ID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert team-user relation: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgByName returns organization by given name.
 | 
			
		||||
func GetOrgByName(name string) (*Organization, error) {
 | 
			
		||||
	if len(name) == 0 {
 | 
			
		||||
		return nil, ErrOrgNotExist{0, name}
 | 
			
		||||
	}
 | 
			
		||||
	u := &Organization{
 | 
			
		||||
		LowerName: strings.ToLower(name),
 | 
			
		||||
		Type:      user_model.UserTypeOrganization,
 | 
			
		||||
	}
 | 
			
		||||
	has, err := db.GetEngine(db.DefaultContext).Get(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, ErrOrgNotExist{0, name}
 | 
			
		||||
	}
 | 
			
		||||
	return u, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrganizations returns number of organizations.
 | 
			
		||||
func CountOrganizations() int64 {
 | 
			
		||||
	count, _ := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("type=1").
 | 
			
		||||
		Count(new(Organization))
 | 
			
		||||
	return count
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOrganization deletes models associated to an organization.
 | 
			
		||||
func DeleteOrganization(ctx context.Context, org *Organization) error {
 | 
			
		||||
	if org.Type != user_model.UserTypeOrganization {
 | 
			
		||||
		return fmt.Errorf("%s is a user not an organization", org.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := db.DeleteBeans(ctx,
 | 
			
		||||
		&Team{OrgID: org.ID},
 | 
			
		||||
		&OrgUser{OrgID: org.ID},
 | 
			
		||||
		&TeamUser{OrgID: org.ID},
 | 
			
		||||
		&TeamUnit{OrgID: org.ID},
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return fmt.Errorf("deleteBeans: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil {
 | 
			
		||||
		return fmt.Errorf("Delete: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ________                ____ ___
 | 
			
		||||
// \_____  \_______  ____ |    |   \______ ___________
 | 
			
		||||
//  /   |   \_  __ \/ ___\|    |   /  ___// __ \_  __ \
 | 
			
		||||
// /    |    \  | \/ /_/  >    |  /\___ \\  ___/|  | \/
 | 
			
		||||
// \_______  /__|  \___  /|______//____  >\___  >__|
 | 
			
		||||
//         \/     /_____/              \/     \/
 | 
			
		||||
 | 
			
		||||
// OrgUser represents an organization-user relation.
 | 
			
		||||
type OrgUser struct {
 | 
			
		||||
	ID       int64 `xorm:"pk autoincr"`
 | 
			
		||||
	UID      int64 `xorm:"INDEX UNIQUE(s)"`
 | 
			
		||||
	OrgID    int64 `xorm:"INDEX UNIQUE(s)"`
 | 
			
		||||
	IsPublic bool  `xorm:"INDEX"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	db.RegisterModel(new(OrgUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isOrganizationOwner(e db.Engine, orgID, uid int64) (bool, error) {
 | 
			
		||||
	ownerTeam, err := getOwnerTeam(e, orgID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if IsErrTeamNotExist(err) {
 | 
			
		||||
			log.Error("Organization does not have owner team: %d", orgID)
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	return isTeamMember(e, orgID, ownerTeam.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOrganizationOwner returns true if given user is in the owner team.
 | 
			
		||||
func IsOrganizationOwner(orgID, uid int64) (bool, error) {
 | 
			
		||||
	return isOrganizationOwner(db.GetEngine(db.DefaultContext), orgID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOrganizationMember returns true if given user is member of organization.
 | 
			
		||||
func IsOrganizationMember(orgID, uid int64) (bool, error) {
 | 
			
		||||
	return isOrganizationMember(db.GetEngine(db.DefaultContext), orgID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isOrganizationMember(e db.Engine, orgID, uid int64) (bool, error) {
 | 
			
		||||
	return e.
 | 
			
		||||
		Where("uid=?", uid).
 | 
			
		||||
		And("org_id=?", orgID).
 | 
			
		||||
		Table("org_user").
 | 
			
		||||
		Exist()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsPublicMembership returns true if given user public his/her membership.
 | 
			
		||||
func IsPublicMembership(orgID, uid int64) (bool, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("uid=?", uid).
 | 
			
		||||
		And("org_id=?", orgID).
 | 
			
		||||
		And("is_public=?", true).
 | 
			
		||||
		Table("org_user").
 | 
			
		||||
		Exist()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanCreateOrgRepo returns true if user can create repo in organization
 | 
			
		||||
func CanCreateOrgRepo(orgID, uid int64) (bool, error) {
 | 
			
		||||
	if owner, err := IsOrganizationOwner(orgID, uid); owner || err != nil {
 | 
			
		||||
		return owner, err
 | 
			
		||||
	}
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where(builder.Eq{"team.can_create_org_repo": true}).
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		And("team_user.uid = ?", uid).
 | 
			
		||||
		And("team_user.org_id = ?", orgID).
 | 
			
		||||
		Exist(new(Team))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization
 | 
			
		||||
func (org *Organization) GetOrgUserMaxAuthorizeLevel(uid int64) (perm.AccessMode, error) {
 | 
			
		||||
	var authorize perm.AccessMode
 | 
			
		||||
	_, err := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Select("max(team.authorize)").
 | 
			
		||||
		Table("team").
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		Where("team_user.uid = ?", uid).
 | 
			
		||||
		And("team_user.org_id = ?", org.ID).
 | 
			
		||||
		Get(&authorize)
 | 
			
		||||
	return authorize, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUsersWhoCanCreateOrgRepo returns users which are able to create repo in organization
 | 
			
		||||
func GetUsersWhoCanCreateOrgRepo(orgID int64) ([]*user_model.User, error) {
 | 
			
		||||
	return getUsersWhoCanCreateOrgRepo(db.GetEngine(db.DefaultContext), orgID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getUsersWhoCanCreateOrgRepo(e db.Engine, orgID int64) ([]*user_model.User, error) {
 | 
			
		||||
	users := make([]*user_model.User, 0, 10)
 | 
			
		||||
	return users, e.
 | 
			
		||||
		Join("INNER", "`team_user`", "`team_user`.uid=`user`.id").
 | 
			
		||||
		Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
 | 
			
		||||
		Where(builder.Eq{"team.can_create_org_repo": true}.Or(builder.Eq{"team.authorize": perm.AccessModeOwner})).
 | 
			
		||||
		And("team_user.org_id = ?", orgID).Asc("`user`.name").Find(&users)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MinimalOrg represents a simple orgnization with only needed columns
 | 
			
		||||
type MinimalOrg = Organization
 | 
			
		||||
type MinimalOrg = organization.Organization
 | 
			
		||||
 | 
			
		||||
// GetUserOrgsList returns one user's all orgs list
 | 
			
		||||
func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
 | 
			
		||||
@@ -486,8 +58,8 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
 | 
			
		||||
		GroupBy(groupByStr)
 | 
			
		||||
 | 
			
		||||
	type OrgCount struct {
 | 
			
		||||
		Organization `xorm:"extends"`
 | 
			
		||||
		OrgCount     int
 | 
			
		||||
		organization.Organization `xorm:"extends"`
 | 
			
		||||
		OrgCount                  int
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgCounts := make([]*OrgCount, 0, 10)
 | 
			
		||||
@@ -507,239 +79,8 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
 | 
			
		||||
	return orgs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchOrganizationsOptions options to filter organizations
 | 
			
		||||
type SearchOrganizationsOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	All bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindOrgOptions finds orgs options
 | 
			
		||||
type FindOrgOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	UserID         int64
 | 
			
		||||
	IncludePrivate bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder {
 | 
			
		||||
	cond := builder.Eq{"uid": userID}
 | 
			
		||||
	if !includePrivate {
 | 
			
		||||
		cond["is_public"] = true
 | 
			
		||||
	}
 | 
			
		||||
	return builder.Select("org_id").From("org_user").Where(cond)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opts FindOrgOptions) toConds() builder.Cond {
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
	if opts.UserID > 0 {
 | 
			
		||||
		cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate)))
 | 
			
		||||
	}
 | 
			
		||||
	if !opts.IncludePrivate {
 | 
			
		||||
		cond = cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic})
 | 
			
		||||
	}
 | 
			
		||||
	return cond
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindOrgs returns a list of organizations according given conditions
 | 
			
		||||
func FindOrgs(opts FindOrgOptions) ([]*Organization, error) {
 | 
			
		||||
	orgs := make([]*Organization, 0, 10)
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where(opts.toConds()).
 | 
			
		||||
		Asc("`user`.name")
 | 
			
		||||
	if opts.Page > 0 && opts.PageSize > 0 {
 | 
			
		||||
		sess.Limit(opts.PageSize, opts.PageSize*(opts.Page-1))
 | 
			
		||||
	}
 | 
			
		||||
	return orgs, sess.Find(&orgs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrgs returns total count organizations according options
 | 
			
		||||
func CountOrgs(opts FindOrgOptions) (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where(opts.toConds()).
 | 
			
		||||
		Count(new(user_model.User))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*Organization, error) {
 | 
			
		||||
	orgs := make([]*Organization, 0, 10)
 | 
			
		||||
	return orgs, sess.
 | 
			
		||||
		Join("INNER", "`team_user`", "`team_user`.org_id=`user`.id").
 | 
			
		||||
		Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
 | 
			
		||||
		Where("`team_user`.uid=?", userID).
 | 
			
		||||
		And("`team`.authorize=?", perm.AccessModeOwner).
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&orgs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasOrgOrUserVisible tells if the given user can see the given org or user
 | 
			
		||||
func HasOrgOrUserVisible(org, user *user_model.User) bool {
 | 
			
		||||
	return hasOrgOrUserVisible(db.GetEngine(db.DefaultContext), org, user)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasOrgOrUserVisible(e db.Engine, orgOrUser, user *user_model.User) bool {
 | 
			
		||||
	// Not SignedUser
 | 
			
		||||
	if user == nil {
 | 
			
		||||
		return orgOrUser.Visibility == structs.VisibleTypePublic
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if user.IsAdmin || orgOrUser.ID == user.ID {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (orgOrUser.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !OrgFromUser(orgOrUser).hasMemberWithUserID(e, user.ID) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasOrgsVisible tells if the given user can see at least one of the orgs provided
 | 
			
		||||
func HasOrgsVisible(orgs []*Organization, user *user_model.User) bool {
 | 
			
		||||
	if len(orgs) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, org := range orgs {
 | 
			
		||||
		if HasOrgOrUserVisible(org.AsUser(), user) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
 | 
			
		||||
func GetOwnedOrgsByUserID(userID int64) ([]*Organization, error) {
 | 
			
		||||
	return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnedOrgsByUserIDDesc returns a list of organizations are owned by
 | 
			
		||||
// given user ID, ordered descending by the given condition.
 | 
			
		||||
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*Organization, error) {
 | 
			
		||||
	return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext).Desc(desc), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID
 | 
			
		||||
// are allowed to create repos.
 | 
			
		||||
func GetOrgsCanCreateRepoByUserID(userID int64) ([]*Organization, error) {
 | 
			
		||||
	orgs := make([]*Organization, 0, 10)
 | 
			
		||||
 | 
			
		||||
	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`", "`team`.id = `team_user`.team_id").
 | 
			
		||||
		Where(builder.Eq{"`team_user`.uid": userID}).
 | 
			
		||||
		And(builder.Eq{"`team`.authorize": perm.AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})))).
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&orgs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgUsersByUserID returns all organization-user relations by user ID.
 | 
			
		||||
func GetOrgUsersByUserID(uid int64, opts *SearchOrganizationsOptions) ([]*OrgUser, error) {
 | 
			
		||||
	ous := make([]*OrgUser, 0, 10)
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Join("LEFT", "`user`", "`org_user`.org_id=`user`.id").
 | 
			
		||||
		Where("`org_user`.uid=?", uid)
 | 
			
		||||
	if !opts.All {
 | 
			
		||||
		// Only show public organizations
 | 
			
		||||
		sess.And("is_public=?", true)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.PageSize != 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, opts)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := sess.
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&ous)
 | 
			
		||||
	return ous, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
 | 
			
		||||
func GetOrgUsersByOrgID(opts *FindOrgMembersOpts) ([]*OrgUser, error) {
 | 
			
		||||
	return getOrgUsersByOrgID(db.GetEngine(db.DefaultContext), opts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getOrgUsersByOrgID(e db.Engine, opts *FindOrgMembersOpts) ([]*OrgUser, error) {
 | 
			
		||||
	sess := e.Where("org_id=?", opts.OrgID)
 | 
			
		||||
	if opts.PublicOnly {
 | 
			
		||||
		sess.And("is_public = ?", true)
 | 
			
		||||
	}
 | 
			
		||||
	if opts.ListOptions.PageSize > 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, opts)
 | 
			
		||||
 | 
			
		||||
		ous := make([]*OrgUser, 0, opts.PageSize)
 | 
			
		||||
		return ous, sess.Find(&ous)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ous []*OrgUser
 | 
			
		||||
	return ous, sess.Find(&ous)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChangeOrgUserStatus changes public or private membership status.
 | 
			
		||||
func ChangeOrgUserStatus(orgID, uid int64, public bool) error {
 | 
			
		||||
	ou := new(OrgUser)
 | 
			
		||||
	has, err := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("uid=?", uid).
 | 
			
		||||
		And("org_id=?", orgID).
 | 
			
		||||
		Get(ou)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ou.IsPublic = public
 | 
			
		||||
	_, err = db.GetEngine(db.DefaultContext).ID(ou.ID).Cols("is_public").Update(ou)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddOrgUser adds new user to given organization.
 | 
			
		||||
func AddOrgUser(orgID, uid int64) error {
 | 
			
		||||
	isAlreadyMember, err := IsOrganizationMember(orgID, uid)
 | 
			
		||||
	if err != nil || isAlreadyMember {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	ou := &OrgUser{
 | 
			
		||||
		UID:      uid,
 | 
			
		||||
		OrgID:    orgID,
 | 
			
		||||
		IsPublic: setting.Service.DefaultOrgMemberVisible,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := db.Insert(ctx, ou); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgByIDCtx returns the user object by given ID if exists.
 | 
			
		||||
func GetOrgByIDCtx(ctx context.Context, id int64) (*Organization, error) {
 | 
			
		||||
	u := new(Organization)
 | 
			
		||||
	has, err := db.GetEngine(ctx).ID(id).Get(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, user_model.ErrUserNotExist{
 | 
			
		||||
			UID:   id,
 | 
			
		||||
			Name:  "",
 | 
			
		||||
			KeyID: 0,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return u, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgByID returns the user object by given ID if exists.
 | 
			
		||||
func GetOrgByID(id int64) (*Organization, error) {
 | 
			
		||||
	return GetOrgByIDCtx(db.DefaultContext, id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeOrgUser(ctx context.Context, orgID, userID int64) error {
 | 
			
		||||
	ou := new(OrgUser)
 | 
			
		||||
	ou := new(organization.OrgUser)
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(ctx)
 | 
			
		||||
 | 
			
		||||
@@ -753,25 +94,25 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	org, err := GetOrgByIDCtx(ctx, orgID)
 | 
			
		||||
	org, err := organization.GetOrgByIDCtx(ctx, orgID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if the user to delete is the last member in owner team.
 | 
			
		||||
	if isOwner, err := isOrganizationOwner(sess, orgID, userID); err != nil {
 | 
			
		||||
	if isOwner, err := organization.IsOrganizationOwner(ctx, orgID, userID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if isOwner {
 | 
			
		||||
		t, err := org.getOwnerTeam(sess)
 | 
			
		||||
		t, err := organization.GetOwnerTeam(ctx, org.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if t.NumMembers == 1 {
 | 
			
		||||
			if err := t.getMembers(sess); err != nil {
 | 
			
		||||
			if err := t.GetMembersCtx(ctx); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if t.Members[0].ID == userID {
 | 
			
		||||
				return ErrLastOrgOwner{UID: userID}
 | 
			
		||||
				return organization.ErrLastOrgOwner{UID: userID}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -783,7 +124,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete all repository accesses and unwatch them.
 | 
			
		||||
	env, err := org.accessibleReposEnv(sess, userID)
 | 
			
		||||
	env, err := organization.AccessibleReposEnv(ctx, org, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("AccessibleReposEnv: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -807,7 +148,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete member in his/her teams.
 | 
			
		||||
	teams, err := getUserOrgTeams(sess, org.ID, userID)
 | 
			
		||||
	teams, err := organization.GetUserOrgTeams(ctx, org.ID, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -832,233 +173,3 @@ func RemoveOrgUser(orgID, userID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeOrgRepo(e db.Engine, orgID, repoID int64) error {
 | 
			
		||||
	teamRepos := make([]*TeamRepo, 0, 10)
 | 
			
		||||
	if err := e.Find(&teamRepos, &TeamRepo{OrgID: orgID, RepoID: repoID}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(teamRepos) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := e.Delete(&TeamRepo{
 | 
			
		||||
		OrgID:  orgID,
 | 
			
		||||
		RepoID: repoID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teamIDs := make([]int64, len(teamRepos))
 | 
			
		||||
	for i, teamRepo := range teamRepos {
 | 
			
		||||
		teamIDs[i] = teamRepo.TeamID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := e.Decr("num_repos").In("id", teamIDs).Update(new(Team))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getUserTeams(e db.Engine, userID int64, cols ...string) ([]*Team, error) {
 | 
			
		||||
	teams := make([]*Team, 0, org.NumTeams)
 | 
			
		||||
	return teams, e.
 | 
			
		||||
		Where("`team_user`.org_id = ?", org.ID).
 | 
			
		||||
		Join("INNER", "team_user", "`team_user`.team_id = team.id").
 | 
			
		||||
		Join("INNER", "`user`", "`user`.id=team_user.uid").
 | 
			
		||||
		And("`team_user`.uid = ?", userID).
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Cols(cols...).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getUserTeamIDs(e db.Engine, userID int64) ([]int64, error) {
 | 
			
		||||
	teamIDs := make([]int64, 0, org.NumTeams)
 | 
			
		||||
	return teamIDs, e.
 | 
			
		||||
		Table("team").
 | 
			
		||||
		Cols("team.id").
 | 
			
		||||
		Where("`team_user`.org_id = ?", org.ID).
 | 
			
		||||
		Join("INNER", "team_user", "`team_user`.team_id = team.id").
 | 
			
		||||
		And("`team_user`.uid = ?", userID).
 | 
			
		||||
		Find(&teamIDs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TeamsWithAccessToRepo returns all teams that have given access level to the repository.
 | 
			
		||||
func (org *Organization) TeamsWithAccessToRepo(repoID int64, mode perm.AccessMode) ([]*Team, error) {
 | 
			
		||||
	return GetTeamsWithAccessToRepo(org.ID, repoID, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
 | 
			
		||||
func (org *Organization) GetUserTeamIDs(userID int64) ([]int64, error) {
 | 
			
		||||
	return org.getUserTeamIDs(db.GetEngine(db.DefaultContext), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserTeams returns all teams that belong to user,
 | 
			
		||||
// and that the user has joined.
 | 
			
		||||
func (org *Organization) GetUserTeams(userID int64) ([]*Team, error) {
 | 
			
		||||
	return org.getUserTeams(db.GetEngine(db.DefaultContext), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AccessibleReposEnvironment operations involving the repositories that are
 | 
			
		||||
// accessible to a particular user
 | 
			
		||||
type AccessibleReposEnvironment interface {
 | 
			
		||||
	CountRepos() (int64, error)
 | 
			
		||||
	RepoIDs(page, pageSize int) ([]int64, error)
 | 
			
		||||
	Repos(page, pageSize int) ([]*repo_model.Repository, error)
 | 
			
		||||
	MirrorRepos() ([]*repo_model.Repository, error)
 | 
			
		||||
	AddKeyword(keyword string)
 | 
			
		||||
	SetSort(db.SearchOrderBy)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type accessibleReposEnv struct {
 | 
			
		||||
	org     *Organization
 | 
			
		||||
	user    *user_model.User
 | 
			
		||||
	team    *Team
 | 
			
		||||
	teamIDs []int64
 | 
			
		||||
	e       db.Engine
 | 
			
		||||
	keyword string
 | 
			
		||||
	orderBy db.SearchOrderBy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AccessibleReposEnv builds an AccessibleReposEnvironment for the repositories in `org`
 | 
			
		||||
// that are accessible to the specified user.
 | 
			
		||||
func (org *Organization) AccessibleReposEnv(userID int64) (AccessibleReposEnvironment, error) {
 | 
			
		||||
	return org.accessibleReposEnv(db.GetEngine(db.DefaultContext), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) accessibleReposEnv(e db.Engine, userID int64) (AccessibleReposEnvironment, error) {
 | 
			
		||||
	var user *user_model.User
 | 
			
		||||
 | 
			
		||||
	if userID > 0 {
 | 
			
		||||
		u, err := user_model.GetUserByIDEngine(e, userID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		user = u
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teamIDs, err := org.getUserTeamIDs(e, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &accessibleReposEnv{
 | 
			
		||||
		org:     org,
 | 
			
		||||
		user:    user,
 | 
			
		||||
		teamIDs: teamIDs,
 | 
			
		||||
		e:       e,
 | 
			
		||||
		orderBy: db.SearchOrderByRecentUpdated,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
 | 
			
		||||
// that are accessible to the specified team.
 | 
			
		||||
func (org *Organization) AccessibleTeamReposEnv(team *Team) AccessibleReposEnvironment {
 | 
			
		||||
	return &accessibleReposEnv{
 | 
			
		||||
		org:     org,
 | 
			
		||||
		team:    team,
 | 
			
		||||
		e:       db.GetEngine(db.DefaultContext),
 | 
			
		||||
		orderBy: db.SearchOrderByRecentUpdated,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) cond() builder.Cond {
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
	if env.team != nil {
 | 
			
		||||
		cond = cond.And(builder.Eq{"team_repo.team_id": env.team.ID})
 | 
			
		||||
	} else {
 | 
			
		||||
		if env.user == nil || !env.user.IsRestricted {
 | 
			
		||||
			cond = cond.Or(builder.Eq{
 | 
			
		||||
				"`repository`.owner_id":   env.org.ID,
 | 
			
		||||
				"`repository`.is_private": false,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		if len(env.teamIDs) > 0 {
 | 
			
		||||
			cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if env.keyword != "" {
 | 
			
		||||
		cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
 | 
			
		||||
	}
 | 
			
		||||
	return cond
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) CountRepos() (int64, error) {
 | 
			
		||||
	repoCount, err := env.e.
 | 
			
		||||
		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
 | 
			
		||||
		Where(env.cond()).
 | 
			
		||||
		Distinct("`repository`.id").
 | 
			
		||||
		Count(&repo_model.Repository{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("count user repositories in organization: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return repoCount, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
 | 
			
		||||
	if page <= 0 {
 | 
			
		||||
		page = 1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repoIDs := make([]int64, 0, pageSize)
 | 
			
		||||
	return repoIDs, env.e.
 | 
			
		||||
		Table("repository").
 | 
			
		||||
		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
 | 
			
		||||
		Where(env.cond()).
 | 
			
		||||
		GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]).
 | 
			
		||||
		OrderBy(string(env.orderBy)).
 | 
			
		||||
		Limit(pageSize, (page-1)*pageSize).
 | 
			
		||||
		Cols("`repository`.id").
 | 
			
		||||
		Find(&repoIDs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*repo_model.Repository, error) {
 | 
			
		||||
	repoIDs, err := env.RepoIDs(page, pageSize)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("GetUserRepositoryIDs: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*repo_model.Repository, 0, len(repoIDs))
 | 
			
		||||
	if len(repoIDs) == 0 {
 | 
			
		||||
		return repos, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repos, env.e.
 | 
			
		||||
		In("`repository`.id", repoIDs).
 | 
			
		||||
		OrderBy(string(env.orderBy)).
 | 
			
		||||
		Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
 | 
			
		||||
	repoIDs := make([]int64, 0, 10)
 | 
			
		||||
	return repoIDs, env.e.
 | 
			
		||||
		Table("repository").
 | 
			
		||||
		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
 | 
			
		||||
		Where(env.cond()).
 | 
			
		||||
		GroupBy("`repository`.id, `repository`.updated_unix").
 | 
			
		||||
		OrderBy(string(env.orderBy)).
 | 
			
		||||
		Cols("`repository`.id").
 | 
			
		||||
		Find(&repoIDs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) MirrorRepos() ([]*repo_model.Repository, error) {
 | 
			
		||||
	repoIDs, err := env.MirrorRepoIDs()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("MirrorRepoIDs: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*repo_model.Repository, 0, len(repoIDs))
 | 
			
		||||
	if len(repoIDs) == 0 {
 | 
			
		||||
		return repos, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repos, env.e.
 | 
			
		||||
		In("`repository`.id", repoIDs).
 | 
			
		||||
		Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) AddKeyword(keyword string) {
 | 
			
		||||
	env.keyword = keyword
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) SetSort(orderBy db.SearchOrderBy) {
 | 
			
		||||
	env.orderBy = orderBy
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,288 +9,24 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ownerTeamName = "Owners"
 | 
			
		||||
 | 
			
		||||
// Team represents a organization team.
 | 
			
		||||
type Team struct {
 | 
			
		||||
	ID                      int64 `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID                   int64 `xorm:"INDEX"`
 | 
			
		||||
	LowerName               string
 | 
			
		||||
	Name                    string
 | 
			
		||||
	Description             string
 | 
			
		||||
	AccessMode              perm.AccessMode          `xorm:"'authorize'"`
 | 
			
		||||
	Repos                   []*repo_model.Repository `xorm:"-"`
 | 
			
		||||
	Members                 []*user_model.User       `xorm:"-"`
 | 
			
		||||
	NumRepos                int
 | 
			
		||||
	NumMembers              int
 | 
			
		||||
	Units                   []*TeamUnit `xorm:"-"`
 | 
			
		||||
	IncludesAllRepositories bool        `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	CanCreateOrgRepo        bool        `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	db.RegisterModel(new(Team))
 | 
			
		||||
	db.RegisterModel(new(TeamUser))
 | 
			
		||||
	db.RegisterModel(new(TeamRepo))
 | 
			
		||||
	db.RegisterModel(new(TeamUnit))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchOrgTeamOptions holds the search options
 | 
			
		||||
type SearchOrgTeamOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	Keyword     string
 | 
			
		||||
	OrgID       int64
 | 
			
		||||
	IncludeDesc bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserTeamOptions holds the search options.
 | 
			
		||||
type GetUserTeamOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	UserID int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchMembersOptions holds the search options
 | 
			
		||||
type SearchMembersOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserTeams search for org teams. Caller is responsible to check permissions.
 | 
			
		||||
func GetUserTeams(opts *GetUserTeamOptions) ([]*Team, int64, error) {
 | 
			
		||||
	if opts.Page <= 0 {
 | 
			
		||||
		opts.Page = 1
 | 
			
		||||
	}
 | 
			
		||||
	if opts.PageSize == 0 {
 | 
			
		||||
		// Default limit
 | 
			
		||||
		opts.PageSize = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext)
 | 
			
		||||
 | 
			
		||||
	sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		And("team_user.uid=?", opts.UserID)
 | 
			
		||||
 | 
			
		||||
	count, err := sess.
 | 
			
		||||
		Count(new(Team))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.PageSize == -1 {
 | 
			
		||||
		opts.PageSize = int(count)
 | 
			
		||||
	} else {
 | 
			
		||||
		sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		And("team_user.uid=?", opts.UserID)
 | 
			
		||||
 | 
			
		||||
	teams := make([]*Team, 0, opts.PageSize)
 | 
			
		||||
	if err = sess.
 | 
			
		||||
		OrderBy("lower_name").
 | 
			
		||||
		Find(&teams); err != nil {
 | 
			
		||||
		return nil, 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return teams, count, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchOrgTeams search for org teams. Caller is responsible to check permissions.
 | 
			
		||||
func SearchOrgTeams(opts *SearchOrgTeamOptions) ([]*Team, int64, error) {
 | 
			
		||||
	if opts.Page <= 0 {
 | 
			
		||||
		opts.Page = 1
 | 
			
		||||
	}
 | 
			
		||||
	if opts.PageSize == 0 {
 | 
			
		||||
		// Default limit
 | 
			
		||||
		opts.PageSize = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
 | 
			
		||||
	if len(opts.Keyword) > 0 {
 | 
			
		||||
		lowerKeyword := strings.ToLower(opts.Keyword)
 | 
			
		||||
		var keywordCond builder.Cond = builder.Like{"lower_name", lowerKeyword}
 | 
			
		||||
		if opts.IncludeDesc {
 | 
			
		||||
			keywordCond = keywordCond.Or(builder.Like{"LOWER(description)", lowerKeyword})
 | 
			
		||||
		}
 | 
			
		||||
		cond = cond.And(keywordCond)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cond = cond.And(builder.Eq{"org_id": opts.OrgID})
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext)
 | 
			
		||||
 | 
			
		||||
	count, err := sess.
 | 
			
		||||
		Where(cond).
 | 
			
		||||
		Count(new(Team))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess = sess.Where(cond)
 | 
			
		||||
	if opts.PageSize == -1 {
 | 
			
		||||
		opts.PageSize = int(count)
 | 
			
		||||
	} else {
 | 
			
		||||
		sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teams := make([]*Team, 0, opts.PageSize)
 | 
			
		||||
	if err = sess.
 | 
			
		||||
		OrderBy("lower_name").
 | 
			
		||||
		Find(&teams); err != nil {
 | 
			
		||||
		return nil, 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return teams, count, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ColorFormat provides a basic color format for a Team
 | 
			
		||||
func (t *Team) ColorFormat(s fmt.State) {
 | 
			
		||||
	if t == nil {
 | 
			
		||||
		log.ColorFprintf(s, "%d:%s (OrgID: %d) %-v",
 | 
			
		||||
			log.NewColoredIDValue(0),
 | 
			
		||||
			"<nil>",
 | 
			
		||||
			log.NewColoredIDValue(0),
 | 
			
		||||
			0)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	log.ColorFprintf(s, "%d:%s (OrgID: %d) %-v",
 | 
			
		||||
		log.NewColoredIDValue(t.ID),
 | 
			
		||||
		t.Name,
 | 
			
		||||
		log.NewColoredIDValue(t.OrgID),
 | 
			
		||||
		t.AccessMode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnits return a list of available units for a team
 | 
			
		||||
func (t *Team) GetUnits() error {
 | 
			
		||||
	return t.getUnits(db.GetEngine(db.DefaultContext))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) getUnits(e db.Engine) (err error) {
 | 
			
		||||
	if t.Units != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.Units, err = getUnitsByTeamID(e, t.ID)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnitNames returns the team units names
 | 
			
		||||
func (t *Team) GetUnitNames() (res []string) {
 | 
			
		||||
	if t.AccessMode >= perm.AccessModeAdmin {
 | 
			
		||||
		return unit.AllUnitKeyNames()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, u := range t.Units {
 | 
			
		||||
		res = append(res, unit.Units[u.Type].NameKey)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnitsMap returns the team units permissions
 | 
			
		||||
func (t *Team) GetUnitsMap() map[string]string {
 | 
			
		||||
	m := make(map[string]string)
 | 
			
		||||
	if t.AccessMode >= perm.AccessModeAdmin {
 | 
			
		||||
		for _, u := range unit.Units {
 | 
			
		||||
			m[u.NameKey] = t.AccessMode.String()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, u := range t.Units {
 | 
			
		||||
			m[u.Unit().NameKey] = u.AccessMode.String()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOwnerTeam returns true if team is owner team.
 | 
			
		||||
func (t *Team) IsOwnerTeam() bool {
 | 
			
		||||
	return t.Name == ownerTeamName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsMember returns true if given user is a member of team.
 | 
			
		||||
func (t *Team) IsMember(userID int64) bool {
 | 
			
		||||
	isMember, err := IsTeamMember(t.OrgID, t.ID, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("IsMember: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return isMember
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) getRepositories(e db.Engine) error {
 | 
			
		||||
	if t.Repos != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return e.Join("INNER", "team_repo", "repository.id = team_repo.repo_id").
 | 
			
		||||
		Where("team_repo.team_id=?", t.ID).
 | 
			
		||||
		OrderBy("repository.name").
 | 
			
		||||
		Find(&t.Repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepositories returns paginated repositories in team of organization.
 | 
			
		||||
func (t *Team) GetRepositories(opts *SearchOrgTeamOptions) error {
 | 
			
		||||
	if opts.Page == 0 {
 | 
			
		||||
		return t.getRepositories(db.GetEngine(db.DefaultContext))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return t.getRepositories(db.GetPaginatedSession(opts))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) getMembers(e db.Engine) (err error) {
 | 
			
		||||
	t.Members, err = getTeamMembers(e, t.ID)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetMembers returns paginated members in team of organization.
 | 
			
		||||
func (t *Team) GetMembers(opts *SearchMembersOptions) (err error) {
 | 
			
		||||
	if opts.Page == 0 {
 | 
			
		||||
		return t.getMembers(db.GetEngine(db.DefaultContext))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return t.getMembers(db.GetPaginatedSession(opts))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddMember adds new membership of the team to the organization,
 | 
			
		||||
// the user will have membership to the organization automatically when needed.
 | 
			
		||||
func (t *Team) AddMember(userID int64) error {
 | 
			
		||||
	return AddTeamMember(t, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveMember removes member from team of organization.
 | 
			
		||||
func (t *Team) RemoveMember(userID int64) error {
 | 
			
		||||
	return RemoveTeamMember(t, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) hasRepository(e db.Engine, repoID int64) bool {
 | 
			
		||||
	return hasTeamRepo(e, t.OrgID, t.ID, repoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasRepository returns true if given repository belong to team.
 | 
			
		||||
func (t *Team) HasRepository(repoID int64) bool {
 | 
			
		||||
	return t.hasRepository(db.GetEngine(db.DefaultContext), repoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) addRepository(ctx context.Context, repo *repo_model.Repository) (err error) {
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
 | 
			
		||||
func addRepository(ctx context.Context, t *organization.Team, repo *repo_model.Repository) (err error) {
 | 
			
		||||
	if err = organization.AddTeamRepo(ctx, t.OrgID, t.ID, repo.ID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = e.Incr("num_repos").ID(t.ID).Update(new(Team)); err != nil {
 | 
			
		||||
	if _, err = db.GetEngine(ctx).Incr("num_repos").ID(t.ID).Update(new(organization.Team)); err != nil {
 | 
			
		||||
		return fmt.Errorf("update team: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -302,7 +38,7 @@ func (t *Team) addRepository(ctx context.Context, repo *repo_model.Repository) (
 | 
			
		||||
 | 
			
		||||
	// Make all team members watch this repo if enabled in global settings
 | 
			
		||||
	if setting.Service.AutoWatchNewRepos {
 | 
			
		||||
		if err = t.getMembers(e); err != nil {
 | 
			
		||||
		if err = t.GetMembersCtx(ctx); err != nil {
 | 
			
		||||
			return fmt.Errorf("getMembers: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, u := range t.Members {
 | 
			
		||||
@@ -317,7 +53,7 @@ func (t *Team) addRepository(ctx context.Context, repo *repo_model.Repository) (
 | 
			
		||||
 | 
			
		||||
// addAllRepositories adds all repositories to the team.
 | 
			
		||||
// If the team already has some repositories they will be left unchanged.
 | 
			
		||||
func (t *Team) addAllRepositories(ctx context.Context) error {
 | 
			
		||||
func addAllRepositories(ctx context.Context, t *organization.Team) error {
 | 
			
		||||
	var orgRepos []repo_model.Repository
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	if err := e.Where("owner_id = ?", t.OrgID).Find(&orgRepos); err != nil {
 | 
			
		||||
@@ -325,8 +61,8 @@ func (t *Team) addAllRepositories(ctx context.Context) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, repo := range orgRepos {
 | 
			
		||||
		if !t.hasRepository(e, repo.ID) {
 | 
			
		||||
			if err := t.addRepository(ctx, &repo); err != nil {
 | 
			
		||||
		if !hasRepository(ctx, t, repo.ID) {
 | 
			
		||||
			if err := addRepository(ctx, t, &repo); err != nil {
 | 
			
		||||
				return fmt.Errorf("addRepository: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -336,14 +72,14 @@ func (t *Team) addAllRepositories(ctx context.Context) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddAllRepositories adds all repositories to the team
 | 
			
		||||
func (t *Team) AddAllRepositories() (err error) {
 | 
			
		||||
func AddAllRepositories(t *organization.Team) (err error) {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err = t.addAllRepositories(ctx); err != nil {
 | 
			
		||||
	if err = addAllRepositories(ctx, t); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -351,10 +87,10 @@ func (t *Team) AddAllRepositories() (err error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddRepository adds new repository to team of organization.
 | 
			
		||||
func (t *Team) AddRepository(repo *repo_model.Repository) (err error) {
 | 
			
		||||
func AddRepository(t *organization.Team, repo *repo_model.Repository) (err error) {
 | 
			
		||||
	if repo.OwnerID != t.OrgID {
 | 
			
		||||
		return errors.New("Repository does not belong to organization")
 | 
			
		||||
	} else if t.HasRepository(repo.ID) {
 | 
			
		||||
	} else if HasRepository(t, repo.ID) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -364,15 +100,20 @@ func (t *Team) AddRepository(repo *repo_model.Repository) (err error) {
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err = t.addRepository(ctx, repo); err != nil {
 | 
			
		||||
	if err = addRepository(ctx, t, repo); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasRepository returns true if given repository belong to team.
 | 
			
		||||
func HasRepository(t *organization.Team, repoID int64) bool {
 | 
			
		||||
	return hasRepository(db.DefaultContext, t, repoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveAllRepositories removes all repositories from team and recalculates access
 | 
			
		||||
func (t *Team) RemoveAllRepositories() (err error) {
 | 
			
		||||
func RemoveAllRepositories(t *organization.Team) (err error) {
 | 
			
		||||
	if t.IncludesAllRepositories {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -383,7 +124,7 @@ func (t *Team) RemoveAllRepositories() (err error) {
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err = t.removeAllRepositories(ctx); err != nil {
 | 
			
		||||
	if err = removeAllRepositories(ctx, t); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -392,7 +133,7 @@ func (t *Team) RemoveAllRepositories() (err error) {
 | 
			
		||||
 | 
			
		||||
// removeAllRepositories removes all repositories from team and recalculates access
 | 
			
		||||
// Note: Shall not be called if team includes all repositories
 | 
			
		||||
func (t *Team) removeAllRepositories(ctx context.Context) (err error) {
 | 
			
		||||
func removeAllRepositories(ctx context.Context, t *organization.Team) (err error) {
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	// Delete all accesses.
 | 
			
		||||
	for _, repo := range t.Repos {
 | 
			
		||||
@@ -423,7 +164,7 @@ func (t *Team) removeAllRepositories(ctx context.Context) (err error) {
 | 
			
		||||
	// Delete team-repo
 | 
			
		||||
	if _, err := e.
 | 
			
		||||
		Where("team_id=?", t.ID).
 | 
			
		||||
		Delete(new(TeamRepo)); err != nil {
 | 
			
		||||
		Delete(new(organization.TeamRepo)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -435,11 +176,15 @@ func (t *Team) removeAllRepositories(ctx context.Context) (err error) {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasRepository(ctx context.Context, t *organization.Team, repoID int64) bool {
 | 
			
		||||
	return organization.HasTeamRepo(ctx, t.OrgID, t.ID, repoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// removeRepository removes a repository from a team and recalculates access
 | 
			
		||||
// Note: Repository shall not be removed from team if it includes all repositories (unless the repository is deleted)
 | 
			
		||||
func (t *Team) removeRepository(ctx context.Context, repo *repo_model.Repository, recalculate bool) (err error) {
 | 
			
		||||
func removeRepository(ctx context.Context, t *organization.Team, repo *repo_model.Repository, recalculate bool) (err error) {
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
 | 
			
		||||
	if err = organization.RemoveTeamRepo(ctx, t.ID, repo.ID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -455,7 +200,7 @@ func (t *Team) removeRepository(ctx context.Context, repo *repo_model.Repository
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teamUsers, err := getTeamUsersByTeamID(e, t.ID)
 | 
			
		||||
	teamUsers, err := organization.GetTeamUsersByTeamID(ctx, t.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("getTeamUsersByTeamID: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -482,8 +227,8 @@ func (t *Team) removeRepository(ctx context.Context, repo *repo_model.Repository
 | 
			
		||||
 | 
			
		||||
// RemoveRepository removes repository from team of organization.
 | 
			
		||||
// If the team shall include all repositories the request is ignored.
 | 
			
		||||
func (t *Team) RemoveRepository(repoID int64) error {
 | 
			
		||||
	if !t.HasRepository(repoID) {
 | 
			
		||||
func RemoveRepository(t *organization.Team, repoID int64) error {
 | 
			
		||||
	if !HasRepository(t, repoID) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -502,58 +247,21 @@ func (t *Team) RemoveRepository(repoID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err = t.removeRepository(ctx, repo, true); err != nil {
 | 
			
		||||
	if err = removeRepository(ctx, t, repo, true); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnitEnabled returns if the team has the given unit type enabled
 | 
			
		||||
func (t *Team) UnitEnabled(tp unit.Type) bool {
 | 
			
		||||
	return t.unitEnabled(db.GetEngine(db.DefaultContext), tp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) unitEnabled(e db.Engine, tp unit.Type) bool {
 | 
			
		||||
	return t.unitAccessMode(e, tp) > perm.AccessModeNone
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnitAccessMode returns if the team has the given unit type enabled
 | 
			
		||||
func (t *Team) UnitAccessMode(tp unit.Type) perm.AccessMode {
 | 
			
		||||
	return t.unitAccessMode(db.GetEngine(db.DefaultContext), tp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) unitAccessMode(e db.Engine, tp unit.Type) perm.AccessMode {
 | 
			
		||||
	if err := t.getUnits(e); err != nil {
 | 
			
		||||
		log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, unit := range t.Units {
 | 
			
		||||
		if unit.Type == tp {
 | 
			
		||||
			return unit.AccessMode
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return perm.AccessModeNone
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUsableTeamName tests if a name could be as team name
 | 
			
		||||
func IsUsableTeamName(name string) error {
 | 
			
		||||
	switch name {
 | 
			
		||||
	case "new":
 | 
			
		||||
		return db.ErrNameReserved{Name: name}
 | 
			
		||||
	default:
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewTeam creates a record of new team.
 | 
			
		||||
// It's caller's responsibility to assign organization ID.
 | 
			
		||||
func NewTeam(t *Team) (err error) {
 | 
			
		||||
func NewTeam(t *organization.Team) (err error) {
 | 
			
		||||
	if len(t.Name) == 0 {
 | 
			
		||||
		return errors.New("empty team name")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = IsUsableTeamName(t.Name); err != nil {
 | 
			
		||||
	if err = organization.IsUsableTeamName(t.Name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -562,19 +270,19 @@ func NewTeam(t *Team) (err error) {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if !has {
 | 
			
		||||
		return ErrOrgNotExist{t.OrgID, ""}
 | 
			
		||||
		return organization.ErrOrgNotExist{ID: t.OrgID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.LowerName = strings.ToLower(t.Name)
 | 
			
		||||
	has, err = db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("org_id=?", t.OrgID).
 | 
			
		||||
		And("lower_name=?", t.LowerName).
 | 
			
		||||
		Get(new(Team))
 | 
			
		||||
		Get(new(organization.Team))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if has {
 | 
			
		||||
		return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
 | 
			
		||||
		return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
@@ -599,7 +307,7 @@ func NewTeam(t *Team) (err error) {
 | 
			
		||||
 | 
			
		||||
	// Add all repositories to the team if it has access to all of them.
 | 
			
		||||
	if t.IncludesAllRepositories {
 | 
			
		||||
		err = t.addAllRepositories(ctx)
 | 
			
		||||
		err = addAllRepositories(ctx, t)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("addAllRepositories: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -612,81 +320,8 @@ func NewTeam(t *Team) (err error) {
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTeam(e db.Engine, orgID int64, name string) (*Team, error) {
 | 
			
		||||
	t := &Team{
 | 
			
		||||
		OrgID:     orgID,
 | 
			
		||||
		LowerName: strings.ToLower(name),
 | 
			
		||||
	}
 | 
			
		||||
	has, err := e.Get(t)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, ErrTeamNotExist{orgID, 0, name}
 | 
			
		||||
	}
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeam returns team by given team name and organization.
 | 
			
		||||
func GetTeam(orgID int64, name string) (*Team, error) {
 | 
			
		||||
	return getTeam(db.GetEngine(db.DefaultContext), orgID, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamIDsByNames returns a slice of team ids corresponds to names.
 | 
			
		||||
func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) {
 | 
			
		||||
	ids := make([]int64, 0, len(names))
 | 
			
		||||
	for _, name := range names {
 | 
			
		||||
		u, err := GetTeam(orgID, name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if ignoreNonExistent {
 | 
			
		||||
				continue
 | 
			
		||||
			} else {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ids = append(ids, u.ID)
 | 
			
		||||
	}
 | 
			
		||||
	return ids, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getOwnerTeam returns team by given team name and organization.
 | 
			
		||||
func getOwnerTeam(e db.Engine, orgID int64) (*Team, error) {
 | 
			
		||||
	return getTeam(e, orgID, ownerTeamName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTeamByID(e db.Engine, teamID int64) (*Team, error) {
 | 
			
		||||
	t := new(Team)
 | 
			
		||||
	has, err := e.ID(teamID).Get(t)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, ErrTeamNotExist{0, teamID, ""}
 | 
			
		||||
	}
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamByID returns team by given ID.
 | 
			
		||||
func GetTeamByID(teamID int64) (*Team, error) {
 | 
			
		||||
	return getTeamByID(db.GetEngine(db.DefaultContext), teamID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamNamesByID returns team's lower name from a list of team ids.
 | 
			
		||||
func GetTeamNamesByID(teamIDs []int64) ([]string, error) {
 | 
			
		||||
	if len(teamIDs) == 0 {
 | 
			
		||||
		return []string{}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var teamNames []string
 | 
			
		||||
	err := db.GetEngine(db.DefaultContext).Table("team").
 | 
			
		||||
		Select("lower_name").
 | 
			
		||||
		In("id", teamIDs).
 | 
			
		||||
		Asc("name").
 | 
			
		||||
		Find(&teamNames)
 | 
			
		||||
 | 
			
		||||
	return teamNames, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateTeam updates information of team.
 | 
			
		||||
func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
 | 
			
		||||
func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err error) {
 | 
			
		||||
	if len(t.Name) == 0 {
 | 
			
		||||
		return errors.New("empty team name")
 | 
			
		||||
	}
 | 
			
		||||
@@ -707,11 +342,11 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
 | 
			
		||||
		Where("org_id=?", t.OrgID).
 | 
			
		||||
		And("lower_name=?", t.LowerName).
 | 
			
		||||
		And("id!=?", t.ID).
 | 
			
		||||
		Get(new(Team))
 | 
			
		||||
		Get(new(organization.Team))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if has {
 | 
			
		||||
		return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
 | 
			
		||||
		return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.ID(t.ID).Cols("name", "lower_name", "description",
 | 
			
		||||
@@ -727,7 +362,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
 | 
			
		||||
		// Delete team-unit.
 | 
			
		||||
		if _, err := sess.
 | 
			
		||||
			Where("team_id=?", t.ID).
 | 
			
		||||
			Delete(new(TeamUnit)); err != nil {
 | 
			
		||||
			Delete(new(organization.TeamUnit)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if _, err = sess.Cols("org_id", "team_id", "type", "access_mode").Insert(&t.Units); err != nil {
 | 
			
		||||
@@ -737,7 +372,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
 | 
			
		||||
 | 
			
		||||
	// Update access for team members if needed.
 | 
			
		||||
	if authChanged {
 | 
			
		||||
		if err = t.getRepositories(sess); err != nil {
 | 
			
		||||
		if err = t.GetRepositoriesCtx(ctx); err != nil {
 | 
			
		||||
			return fmt.Errorf("getRepositories: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -750,7 +385,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
 | 
			
		||||
 | 
			
		||||
	// Add all repositories to the team if it has access to all of them.
 | 
			
		||||
	if includeAllChanged && t.IncludesAllRepositories {
 | 
			
		||||
		err = t.addAllRepositories(ctx)
 | 
			
		||||
		err = addAllRepositories(ctx, t)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("addAllRepositories: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -761,11 +396,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
 | 
			
		||||
 | 
			
		||||
// DeleteTeam deletes given team.
 | 
			
		||||
// It's caller's responsibility to assign organization ID.
 | 
			
		||||
func DeleteTeam(t *Team) error {
 | 
			
		||||
	if err := t.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
func DeleteTeam(t *organization.Team) error {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -773,7 +404,11 @@ func DeleteTeam(t *Team) error {
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
	sess := db.GetEngine(ctx)
 | 
			
		||||
 | 
			
		||||
	if err := t.getMembers(sess); err != nil {
 | 
			
		||||
	if err := t.GetRepositoriesCtx(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := t.GetMembersCtx(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -813,7 +448,7 @@ func DeleteTeam(t *Team) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !t.IncludesAllRepositories {
 | 
			
		||||
		if err := t.removeAllRepositories(ctx); err != nil {
 | 
			
		||||
		if err := removeAllRepositories(ctx, t); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -822,19 +457,19 @@ func DeleteTeam(t *Team) error {
 | 
			
		||||
	if _, err := sess.
 | 
			
		||||
		Where("org_id=?", t.OrgID).
 | 
			
		||||
		Where("team_id=?", t.ID).
 | 
			
		||||
		Delete(new(TeamUser)); err != nil {
 | 
			
		||||
		Delete(new(organization.TeamUser)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete team-unit.
 | 
			
		||||
	if _, err := sess.
 | 
			
		||||
		Where("team_id=?", t.ID).
 | 
			
		||||
		Delete(new(TeamUnit)); err != nil {
 | 
			
		||||
		Delete(new(organization.TeamUnit)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete team.
 | 
			
		||||
	if _, err := sess.ID(t.ID).Delete(new(Team)); err != nil {
 | 
			
		||||
	if _, err := sess.ID(t.ID).Delete(new(organization.Team)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// Update organization number of teams.
 | 
			
		||||
@@ -845,103 +480,15 @@ func DeleteTeam(t *Team) error {
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ___________                    ____ ___
 | 
			
		||||
// \__    ___/___ _____    _____ |    |   \______ ___________
 | 
			
		||||
//   |    |_/ __ \\__  \  /     \|    |   /  ___// __ \_  __ \
 | 
			
		||||
//   |    |\  ___/ / __ \|  Y Y  \    |  /\___ \\  ___/|  | \/
 | 
			
		||||
//   |____| \___  >____  /__|_|  /______//____  >\___  >__|
 | 
			
		||||
//              \/     \/      \/             \/     \/
 | 
			
		||||
 | 
			
		||||
// TeamUser represents an team-user relation.
 | 
			
		||||
type TeamUser struct {
 | 
			
		||||
	ID     int64 `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID  int64 `xorm:"INDEX"`
 | 
			
		||||
	TeamID int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
	UID    int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isTeamMember(e db.Engine, orgID, teamID, userID int64) (bool, error) {
 | 
			
		||||
	return e.
 | 
			
		||||
		Where("org_id=?", orgID).
 | 
			
		||||
		And("team_id=?", teamID).
 | 
			
		||||
		And("uid=?", userID).
 | 
			
		||||
		Table("team_user").
 | 
			
		||||
		Exist()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsTeamMember returns true if given user is a member of team.
 | 
			
		||||
func IsTeamMember(orgID, teamID, userID int64) (bool, error) {
 | 
			
		||||
	return isTeamMember(db.GetEngine(db.DefaultContext), orgID, teamID, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTeamUsersByTeamID(e db.Engine, teamID int64) ([]*TeamUser, error) {
 | 
			
		||||
	teamUsers := make([]*TeamUser, 0, 10)
 | 
			
		||||
	return teamUsers, e.
 | 
			
		||||
		Where("team_id=?", teamID).
 | 
			
		||||
		Find(&teamUsers)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTeamMembers(e db.Engine, teamID int64) (_ []*user_model.User, err error) {
 | 
			
		||||
	teamUsers, err := getTeamUsersByTeamID(e, teamID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("get team-users: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	members := make([]*user_model.User, len(teamUsers))
 | 
			
		||||
	for i, teamUser := range teamUsers {
 | 
			
		||||
		member, err := user_model.GetUserByIDEngine(e, teamUser.UID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("get user '%d': %v", teamUser.UID, err)
 | 
			
		||||
		}
 | 
			
		||||
		members[i] = member
 | 
			
		||||
	}
 | 
			
		||||
	sort.Slice(members, func(i, j int) bool {
 | 
			
		||||
		return members[i].DisplayName() < members[j].DisplayName()
 | 
			
		||||
	})
 | 
			
		||||
	return members, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamMembers returns all members in given team of organization.
 | 
			
		||||
func GetTeamMembers(teamID int64) ([]*user_model.User, error) {
 | 
			
		||||
	return getTeamMembers(db.GetEngine(db.DefaultContext), teamID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getUserOrgTeams(e db.Engine, orgID, userID int64) (teams []*Team, err error) {
 | 
			
		||||
	return teams, e.
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		Where("team.org_id = ?", orgID).
 | 
			
		||||
		And("team_user.uid=?", userID).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getUserRepoTeams(e db.Engine, orgID, userID, repoID int64) (teams []*Team, err error) {
 | 
			
		||||
	return teams, e.
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
		Where("team.org_id = ?", orgID).
 | 
			
		||||
		And("team_user.uid=?", userID).
 | 
			
		||||
		And("team_repo.repo_id=?", repoID).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserOrgTeams returns all teams that user belongs to in given organization.
 | 
			
		||||
func GetUserOrgTeams(orgID, userID int64) ([]*Team, error) {
 | 
			
		||||
	return getUserOrgTeams(db.GetEngine(db.DefaultContext), orgID, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddTeamMember adds new membership of given team to given organization,
 | 
			
		||||
// the user will have membership to given organization automatically when needed.
 | 
			
		||||
func AddTeamMember(team *Team, userID int64) error {
 | 
			
		||||
	isAlreadyMember, err := IsTeamMember(team.OrgID, team.ID, userID)
 | 
			
		||||
func AddTeamMember(team *organization.Team, userID int64) error {
 | 
			
		||||
	isAlreadyMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, userID)
 | 
			
		||||
	if err != nil || isAlreadyMember {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := AddOrgUser(team.OrgID, userID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get team and its repositories.
 | 
			
		||||
	if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
 | 
			
		||||
	if err := organization.AddOrgUser(team.OrgID, userID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -951,15 +498,20 @@ func AddTeamMember(team *Team, userID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	// Get team and its repositories.
 | 
			
		||||
	if err := team.GetRepositoriesCtx(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(ctx)
 | 
			
		||||
 | 
			
		||||
	if err := db.Insert(ctx, &TeamUser{
 | 
			
		||||
	if err := db.Insert(ctx, &organization.TeamUser{
 | 
			
		||||
		UID:    userID,
 | 
			
		||||
		OrgID:  team.OrgID,
 | 
			
		||||
		TeamID: team.ID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if _, err := sess.Incr("num_members").ID(team.ID).Update(new(Team)); err != nil {
 | 
			
		||||
	} else if _, err := sess.Incr("num_members").ID(team.ID).Update(new(organization.Team)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -980,25 +532,25 @@ func AddTeamMember(team *Team, userID int64) error {
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeTeamMember(ctx context.Context, team *Team, userID int64) error {
 | 
			
		||||
func removeTeamMember(ctx context.Context, team *organization.Team, userID int64) error {
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	isMember, err := isTeamMember(e, team.OrgID, team.ID, userID)
 | 
			
		||||
	isMember, err := organization.IsTeamMember(ctx, team.OrgID, team.ID, userID)
 | 
			
		||||
	if err != nil || !isMember {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if the user to delete is the last member in owner team.
 | 
			
		||||
	if team.IsOwnerTeam() && team.NumMembers == 1 {
 | 
			
		||||
		return ErrLastOrgOwner{UID: userID}
 | 
			
		||||
		return organization.ErrLastOrgOwner{UID: userID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	team.NumMembers--
 | 
			
		||||
 | 
			
		||||
	if err := team.getRepositories(e); err != nil {
 | 
			
		||||
	if err := team.GetRepositoriesCtx(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := e.Delete(&TeamUser{
 | 
			
		||||
	if _, err := e.Delete(&organization.TeamUser{
 | 
			
		||||
		UID:    userID,
 | 
			
		||||
		OrgID:  team.OrgID,
 | 
			
		||||
		TeamID: team.ID,
 | 
			
		||||
@@ -1029,7 +581,7 @@ func removeTeamMember(ctx context.Context, team *Team, userID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if the user is a member of any team in the organization.
 | 
			
		||||
	if count, err := e.Count(&TeamUser{
 | 
			
		||||
	if count, err := e.Count(&organization.TeamUser{
 | 
			
		||||
		UID:   userID,
 | 
			
		||||
		OrgID: team.OrgID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
@@ -1042,7 +594,7 @@ func removeTeamMember(ctx context.Context, team *Team, userID int64) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveTeamMember removes member from given team of given organization.
 | 
			
		||||
func RemoveTeamMember(team *Team, userID int64) error {
 | 
			
		||||
func RemoveTeamMember(team *organization.Team, userID int64) error {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -1053,125 +605,3 @@ func RemoveTeamMember(team *Team, userID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUserInTeams returns if a user in some teams
 | 
			
		||||
func IsUserInTeams(userID int64, teamIDs []int64) (bool, error) {
 | 
			
		||||
	return isUserInTeams(db.GetEngine(db.DefaultContext), userID, teamIDs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isUserInTeams(e db.Engine, userID int64, teamIDs []int64) (bool, error) {
 | 
			
		||||
	return e.Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
 | 
			
		||||
func UsersInTeamsCount(userIDs, teamIDs []int64) (int64, error) {
 | 
			
		||||
	var ids []int64
 | 
			
		||||
	if err := db.GetEngine(db.DefaultContext).In("uid", userIDs).In("team_id", teamIDs).
 | 
			
		||||
		Table("team_user").
 | 
			
		||||
		Cols("uid").GroupBy("uid").Find(&ids); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return int64(len(ids)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ___________                  __________
 | 
			
		||||
// \__    ___/___ _____    _____\______   \ ____ ______   ____
 | 
			
		||||
//   |    |_/ __ \\__  \  /     \|       _// __ \\____ \ /  _ \
 | 
			
		||||
//   |    |\  ___/ / __ \|  Y Y  \    |   \  ___/|  |_> >  <_> )
 | 
			
		||||
//   |____| \___  >____  /__|_|  /____|_  /\___  >   __/ \____/
 | 
			
		||||
//              \/     \/      \/       \/     \/|__|
 | 
			
		||||
 | 
			
		||||
// TeamRepo represents an team-repository relation.
 | 
			
		||||
type TeamRepo struct {
 | 
			
		||||
	ID     int64 `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID  int64 `xorm:"INDEX"`
 | 
			
		||||
	TeamID int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
	RepoID int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasTeamRepo(e db.Engine, orgID, teamID, repoID int64) bool {
 | 
			
		||||
	has, _ := e.
 | 
			
		||||
		Where("org_id=?", orgID).
 | 
			
		||||
		And("team_id=?", teamID).
 | 
			
		||||
		And("repo_id=?", repoID).
 | 
			
		||||
		Get(new(TeamRepo))
 | 
			
		||||
	return has
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasTeamRepo returns true if given repository belongs to team.
 | 
			
		||||
func HasTeamRepo(orgID, teamID, repoID int64) bool {
 | 
			
		||||
	return hasTeamRepo(db.GetEngine(db.DefaultContext), orgID, teamID, repoID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addTeamRepo(e db.Engine, orgID, teamID, repoID int64) error {
 | 
			
		||||
	_, err := e.InsertOne(&TeamRepo{
 | 
			
		||||
		OrgID:  orgID,
 | 
			
		||||
		TeamID: teamID,
 | 
			
		||||
		RepoID: repoID,
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeTeamRepo(e db.Engine, teamID, repoID int64) error {
 | 
			
		||||
	_, err := e.Delete(&TeamRepo{
 | 
			
		||||
		TeamID: teamID,
 | 
			
		||||
		RepoID: repoID,
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamsWithAccessToRepo returns all teams in an organization that have given access level to the repository.
 | 
			
		||||
func GetTeamsWithAccessToRepo(orgID, repoID int64, mode perm.AccessMode) ([]*Team, error) {
 | 
			
		||||
	teams := make([]*Team, 0, 5)
 | 
			
		||||
	return teams, db.GetEngine(db.DefaultContext).Where("team.authorize >= ?", mode).
 | 
			
		||||
		Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
		And("team_repo.org_id = ?", orgID).
 | 
			
		||||
		And("team_repo.repo_id = ?", repoID).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ___________                    ____ ___      .__  __
 | 
			
		||||
// \__    ___/___ _____    _____ |    |   \____ |__|/  |_
 | 
			
		||||
//   |    |_/ __ \\__  \  /     \|    |   /    \|  \   __\
 | 
			
		||||
//   |    |\  ___/ / __ \|  Y Y  \    |  /   |  \  ||  |
 | 
			
		||||
//   |____| \___  >____  /__|_|  /______/|___|  /__||__|
 | 
			
		||||
//              \/     \/      \/             \/
 | 
			
		||||
 | 
			
		||||
// TeamUnit describes all units of a repository
 | 
			
		||||
type TeamUnit struct {
 | 
			
		||||
	ID         int64     `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID      int64     `xorm:"INDEX"`
 | 
			
		||||
	TeamID     int64     `xorm:"UNIQUE(s)"`
 | 
			
		||||
	Type       unit.Type `xorm:"UNIQUE(s)"`
 | 
			
		||||
	AccessMode perm.AccessMode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unit returns Unit
 | 
			
		||||
func (t *TeamUnit) Unit() unit.Unit {
 | 
			
		||||
	return unit.Units[t.Type]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getUnitsByTeamID(e db.Engine, teamID int64) (units []*TeamUnit, err error) {
 | 
			
		||||
	return units, e.Where("team_id = ?", teamID).Find(&units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateTeamUnits updates a teams's units
 | 
			
		||||
func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if _, err = db.GetEngine(ctx).Where("team_id = ?", team.ID).Delete(new(TeamUnit)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(units) > 0 {
 | 
			
		||||
		if err = db.Insert(ctx, units); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
@@ -17,68 +18,14 @@ import (
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestTeam_IsOwnerTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team)
 | 
			
		||||
	assert.True(t, team.IsOwnerTeam())
 | 
			
		||||
 | 
			
		||||
	team = unittest.AssertExistsAndLoadBean(t, &Team{ID: 2}).(*Team)
 | 
			
		||||
	assert.False(t, team.IsOwnerTeam())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_IsMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team)
 | 
			
		||||
	assert.True(t, team.IsMember(2))
 | 
			
		||||
	assert.False(t, team.IsMember(4))
 | 
			
		||||
	assert.False(t, team.IsMember(unittest.NonexistentID))
 | 
			
		||||
 | 
			
		||||
	team = unittest.AssertExistsAndLoadBean(t, &Team{ID: 2}).(*Team)
 | 
			
		||||
	assert.True(t, team.IsMember(2))
 | 
			
		||||
	assert.True(t, team.IsMember(4))
 | 
			
		||||
	assert.False(t, team.IsMember(unittest.NonexistentID))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_GetRepositories(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.NoError(t, team.GetRepositories(&SearchOrgTeamOptions{}))
 | 
			
		||||
		assert.Len(t, team.Repos, team.NumRepos)
 | 
			
		||||
		for _, repo := range team.Repos {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repo.ID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(1)
 | 
			
		||||
	test(3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_GetMembers(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.NoError(t, team.GetMembers(&SearchMembersOptions{}))
 | 
			
		||||
		assert.Len(t, team.Members, team.NumMembers)
 | 
			
		||||
		for _, member := range team.Members {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: member.ID, TeamID: teamID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(1)
 | 
			
		||||
	test(3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_AddMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID, userID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.NoError(t, team.AddMember(userID))
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &user_model.User{ID: team.OrgID})
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
 | 
			
		||||
		assert.NoError(t, AddTeamMember(team, userID))
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &user_model.User{ID: team.OrgID})
 | 
			
		||||
	}
 | 
			
		||||
	test(1, 2)
 | 
			
		||||
	test(1, 4)
 | 
			
		||||
@@ -89,27 +36,27 @@ func TestTeam_RemoveMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(teamID, userID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.NoError(t, team.RemoveMember(userID))
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &Team{ID: teamID})
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
 | 
			
		||||
		assert.NoError(t, RemoveTeamMember(team, userID))
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID})
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(1, 4)
 | 
			
		||||
	testSuccess(2, 2)
 | 
			
		||||
	testSuccess(3, 2)
 | 
			
		||||
	testSuccess(3, unittest.NonexistentID)
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team)
 | 
			
		||||
	err := team.RemoveMember(2)
 | 
			
		||||
	assert.True(t, IsErrLastOrgOwner(err))
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team)
 | 
			
		||||
	err := RemoveTeamMember(team, 2)
 | 
			
		||||
	assert.True(t, organization.IsErrLastOrgOwner(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_HasRepository(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID, repoID int64, expected bool) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.Equal(t, expected, team.HasRepository(repoID))
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
 | 
			
		||||
		assert.Equal(t, expected, HasRepository(team, repoID))
 | 
			
		||||
	}
 | 
			
		||||
	test(1, 1, false)
 | 
			
		||||
	test(1, 3, true)
 | 
			
		||||
@@ -124,29 +71,29 @@ func TestTeam_AddRepository(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(teamID, repoID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
 | 
			
		||||
		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
 | 
			
		||||
		assert.NoError(t, team.AddRepository(repo))
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repoID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &repo_model.Repository{ID: repoID})
 | 
			
		||||
		assert.NoError(t, AddRepository(team, repo))
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID})
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, 3)
 | 
			
		||||
	testSuccess(2, 5)
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team)
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team)
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
 | 
			
		||||
	assert.Error(t, team.AddRepository(repo))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Team{ID: 1}, &repo_model.Repository{ID: 1})
 | 
			
		||||
	assert.Error(t, AddRepository(team, repo))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &organization.Team{ID: 1}, &repo_model.Repository{ID: 1})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_RemoveRepository(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(teamID, repoID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.NoError(t, team.RemoveRepository(repoID))
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &TeamRepo{TeamID: teamID, RepoID: repoID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &repo_model.Repository{ID: repoID})
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
 | 
			
		||||
		assert.NoError(t, RemoveRepository(team, repoID))
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID})
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, 3)
 | 
			
		||||
	testSuccess(2, 5)
 | 
			
		||||
@@ -154,97 +101,62 @@ func TestTeam_RemoveRepository(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsUsableTeamName(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, IsUsableTeamName("usable"))
 | 
			
		||||
	assert.True(t, db.IsErrNameReserved(IsUsableTeamName("new")))
 | 
			
		||||
	assert.NoError(t, organization.IsUsableTeamName("usable"))
 | 
			
		||||
	assert.True(t, db.IsErrNameReserved(organization.IsUsableTeamName("new")))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	const teamName = "newTeamName"
 | 
			
		||||
	team := &Team{Name: teamName, OrgID: 3}
 | 
			
		||||
	team := &organization.Team{Name: teamName, OrgID: 3}
 | 
			
		||||
	assert.NoError(t, NewTeam(team))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Team{Name: teamName})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Team{}, &user_model.User{ID: team.OrgID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(orgID int64, name string) {
 | 
			
		||||
		team, err := GetTeam(orgID, name)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, orgID, team.OrgID)
 | 
			
		||||
		assert.Equal(t, name, team.Name)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(3, "Owners")
 | 
			
		||||
	testSuccess(3, "team1")
 | 
			
		||||
 | 
			
		||||
	_, err := GetTeam(3, "nonexistent")
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	_, err = GetTeam(unittest.NonexistentID, "Owners")
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetTeamByID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(teamID int64) {
 | 
			
		||||
		team, err := GetTeamByID(teamID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, teamID, team.ID)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(1)
 | 
			
		||||
	testSuccess(2)
 | 
			
		||||
	testSuccess(3)
 | 
			
		||||
	testSuccess(4)
 | 
			
		||||
 | 
			
		||||
	_, err := GetTeamByID(unittest.NonexistentID)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: teamName})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &organization.Team{}, &user_model.User{ID: team.OrgID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUpdateTeam(t *testing.T) {
 | 
			
		||||
	// successful update
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 2}).(*Team)
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team)
 | 
			
		||||
	team.LowerName = "newname"
 | 
			
		||||
	team.Name = "newName"
 | 
			
		||||
	team.Description = strings.Repeat("A long description!", 100)
 | 
			
		||||
	team.AccessMode = perm.AccessModeAdmin
 | 
			
		||||
	assert.NoError(t, UpdateTeam(team, true, false))
 | 
			
		||||
 | 
			
		||||
	team = unittest.AssertExistsAndLoadBean(t, &Team{Name: "newName"}).(*Team)
 | 
			
		||||
	team = unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: "newName"}).(*organization.Team)
 | 
			
		||||
	assert.True(t, strings.HasPrefix(team.Description, "A long description!"))
 | 
			
		||||
 | 
			
		||||
	access := unittest.AssertExistsAndLoadBean(t, &Access{UserID: 4, RepoID: 3}).(*Access)
 | 
			
		||||
	assert.EqualValues(t, perm.AccessModeAdmin, access.Mode)
 | 
			
		||||
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Team{ID: team.ID})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &organization.Team{ID: team.ID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUpdateTeam2(t *testing.T) {
 | 
			
		||||
	// update to already-existing team
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 2}).(*Team)
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team)
 | 
			
		||||
	team.LowerName = "owners"
 | 
			
		||||
	team.Name = "Owners"
 | 
			
		||||
	team.Description = strings.Repeat("A long description!", 100)
 | 
			
		||||
	err := UpdateTeam(team, true, false)
 | 
			
		||||
	assert.True(t, IsErrTeamAlreadyExist(err))
 | 
			
		||||
	assert.True(t, organization.IsErrTeamAlreadyExist(err))
 | 
			
		||||
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Team{ID: team.ID})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &organization.Team{ID: team.ID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 2}).(*Team)
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team)
 | 
			
		||||
	assert.NoError(t, DeleteTeam(team))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Team{ID: team.ID})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &TeamRepo{TeamID: team.ID})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &TeamUser{TeamID: team.ID})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.Team{ID: team.ID})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.TeamRepo{TeamID: team.ID})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.TeamUser{TeamID: team.ID})
 | 
			
		||||
 | 
			
		||||
	// check that team members don't have "leftover" access to repos
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
 | 
			
		||||
@@ -254,78 +166,14 @@ func TestDeleteTeam(t *testing.T) {
 | 
			
		||||
	assert.True(t, accessMode < perm.AccessModeWrite)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsTeamMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, teamID, userID int64, expected bool) {
 | 
			
		||||
		isMember, err := IsTeamMember(orgID, teamID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expected, isMember)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	test(3, 1, 2, true)
 | 
			
		||||
	test(3, 1, 4, false)
 | 
			
		||||
	test(3, 1, unittest.NonexistentID, false)
 | 
			
		||||
 | 
			
		||||
	test(3, 2, 2, true)
 | 
			
		||||
	test(3, 2, 4, true)
 | 
			
		||||
 | 
			
		||||
	test(3, unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetTeamMembers(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		members, err := GetTeamMembers(teamID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Len(t, members, team.NumMembers)
 | 
			
		||||
		for _, member := range members {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: member.ID, TeamID: teamID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(1)
 | 
			
		||||
	test(3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUserTeams(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(userID int64) {
 | 
			
		||||
		teams, _, err := GetUserTeams(&GetUserTeamOptions{UserID: userID})
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		for _, team := range teams {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(2)
 | 
			
		||||
	test(5)
 | 
			
		||||
	test(unittest.NonexistentID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUserOrgTeams(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64) {
 | 
			
		||||
		teams, err := GetUserOrgTeams(orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		for _, team := range teams {
 | 
			
		||||
			assert.EqualValues(t, orgID, team.OrgID)
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2)
 | 
			
		||||
	test(3, 4)
 | 
			
		||||
	test(3, unittest.NonexistentID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAddTeamMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID, userID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
 | 
			
		||||
		assert.NoError(t, AddTeamMember(team, userID))
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &user_model.User{ID: team.OrgID})
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &user_model.User{ID: team.OrgID})
 | 
			
		||||
	}
 | 
			
		||||
	test(1, 2)
 | 
			
		||||
	test(1, 4)
 | 
			
		||||
@@ -336,47 +184,17 @@ func TestRemoveTeamMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(teamID, userID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
 | 
			
		||||
		assert.NoError(t, RemoveTeamMember(team, userID))
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &Team{ID: teamID})
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID})
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(1, 4)
 | 
			
		||||
	testSuccess(2, 2)
 | 
			
		||||
	testSuccess(3, 2)
 | 
			
		||||
	testSuccess(3, unittest.NonexistentID)
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team)
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team)
 | 
			
		||||
	err := RemoveTeamMember(team, 2)
 | 
			
		||||
	assert.True(t, IsErrLastOrgOwner(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasTeamRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID, repoID int64, expected bool) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.Equal(t, expected, HasTeamRepo(team.OrgID, teamID, repoID))
 | 
			
		||||
	}
 | 
			
		||||
	test(1, 1, false)
 | 
			
		||||
	test(1, 3, true)
 | 
			
		||||
	test(1, 5, true)
 | 
			
		||||
	test(1, unittest.NonexistentID, false)
 | 
			
		||||
 | 
			
		||||
	test(2, 3, true)
 | 
			
		||||
	test(2, 5, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUsersInTeamsCount(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamIDs, userIDs []int64, expected int64) {
 | 
			
		||||
		count, err := UsersInTeamsCount(teamIDs, userIDs)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expected, count)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	test([]int64{2}, []int64{1, 2, 3, 4}, 1)          // only userid 2
 | 
			
		||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2)    // userid 2,4
 | 
			
		||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3) // userid 2,4,5
 | 
			
		||||
	assert.True(t, organization.IsErrLastOrgOwner(err))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,176 +8,81 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestUser_IsOwnedBy(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	for _, testCase := range []struct {
 | 
			
		||||
		OrgID         int64
 | 
			
		||||
		UserID        int64
 | 
			
		||||
		ExpectedOwner bool
 | 
			
		||||
	}{
 | 
			
		||||
		{3, 2, true},
 | 
			
		||||
		{3, 1, false},
 | 
			
		||||
		{3, 3, false},
 | 
			
		||||
		{3, 4, false},
 | 
			
		||||
		{2, 2, false}, // user2 is not an organization
 | 
			
		||||
		{2, 3, false},
 | 
			
		||||
	} {
 | 
			
		||||
		org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: testCase.OrgID}).(*Organization)
 | 
			
		||||
		isOwner, err := org.IsOwnedBy(testCase.UserID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, testCase.ExpectedOwner, isOwner)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_IsOrgMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	for _, testCase := range []struct {
 | 
			
		||||
		OrgID          int64
 | 
			
		||||
		UserID         int64
 | 
			
		||||
		ExpectedMember bool
 | 
			
		||||
	}{
 | 
			
		||||
		{3, 2, true},
 | 
			
		||||
		{3, 4, true},
 | 
			
		||||
		{3, 1, false},
 | 
			
		||||
		{3, 3, false},
 | 
			
		||||
		{2, 2, false}, // user2 is not an organization
 | 
			
		||||
		{2, 3, false},
 | 
			
		||||
	} {
 | 
			
		||||
		org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: testCase.OrgID}).(*Organization)
 | 
			
		||||
		isMember, err := org.IsOrgMember(testCase.UserID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, testCase.ExpectedMember, isMember)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	team, err := org.GetTeam("team1")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, org.ID, team.OrgID)
 | 
			
		||||
	assert.Equal(t, "team1", team.LowerName)
 | 
			
		||||
 | 
			
		||||
	_, err = org.GetTeam("does not exist")
 | 
			
		||||
	assert.True(t, IsErrTeamNotExist(err))
 | 
			
		||||
 | 
			
		||||
	nonOrg := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 2}).(*Organization)
 | 
			
		||||
	_, err = nonOrg.GetTeam("team")
 | 
			
		||||
	assert.True(t, IsErrTeamNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetOwnerTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	team, err := org.GetOwnerTeam()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, org.ID, team.OrgID)
 | 
			
		||||
 | 
			
		||||
	nonOrg := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 2}).(*Organization)
 | 
			
		||||
	_, err = nonOrg.GetOwnerTeam()
 | 
			
		||||
	assert.True(t, IsErrTeamNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetTeams(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	teams, err := org.LoadTeams()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, teams, 4) {
 | 
			
		||||
		assert.Equal(t, int64(1), teams[0].ID)
 | 
			
		||||
		assert.Equal(t, int64(2), teams[1].ID)
 | 
			
		||||
		assert.Equal(t, int64(12), teams[2].ID)
 | 
			
		||||
		assert.Equal(t, int64(7), teams[3].ID)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetMembers(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	members, _, err := org.GetMembers()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, members, 3) {
 | 
			
		||||
		assert.Equal(t, int64(2), members[0].ID)
 | 
			
		||||
		assert.Equal(t, int64(28), members[1].ID)
 | 
			
		||||
		assert.Equal(t, int64(4), members[2].ID)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_AddMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
 | 
			
		||||
	// add a user that is not a member
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &OrgUser{UID: 5, OrgID: 3})
 | 
			
		||||
	prevNumMembers := org.NumMembers
 | 
			
		||||
	assert.NoError(t, org.AddMember(5))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OrgUser{UID: 5, OrgID: 3})
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	assert.Equal(t, prevNumMembers+1, org.NumMembers)
 | 
			
		||||
 | 
			
		||||
	// add a user that is already a member
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OrgUser{UID: 4, OrgID: 3})
 | 
			
		||||
	prevNumMembers = org.NumMembers
 | 
			
		||||
	assert.NoError(t, org.AddMember(4))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OrgUser{UID: 4, OrgID: 3})
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	assert.Equal(t, prevNumMembers, org.NumMembers)
 | 
			
		||||
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_RemoveMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization)
 | 
			
		||||
 | 
			
		||||
	// remove a user that is a member
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OrgUser{UID: 4, OrgID: 3})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &organization.OrgUser{UID: 4, OrgID: 3})
 | 
			
		||||
	prevNumMembers := org.NumMembers
 | 
			
		||||
	assert.NoError(t, org.RemoveMember(4))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &OrgUser{UID: 4, OrgID: 3})
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	assert.NoError(t, RemoveOrgUser(org.ID, 4))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: 4, OrgID: 3})
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization)
 | 
			
		||||
	assert.Equal(t, prevNumMembers-1, org.NumMembers)
 | 
			
		||||
 | 
			
		||||
	// remove a user that is not a member
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &OrgUser{UID: 5, OrgID: 3})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: 5, OrgID: 3})
 | 
			
		||||
	prevNumMembers = org.NumMembers
 | 
			
		||||
	assert.NoError(t, org.RemoveMember(5))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &OrgUser{UID: 5, OrgID: 3})
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	assert.NoError(t, RemoveOrgUser(org.ID, 5))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: 5, OrgID: 3})
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization)
 | 
			
		||||
	assert.Equal(t, prevNumMembers, org.NumMembers)
 | 
			
		||||
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemoveOrgUser(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	testSuccess := func(orgID, userID int64) {
 | 
			
		||||
		org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
 | 
			
		||||
		expectedNumMembers := org.NumMembers
 | 
			
		||||
		if unittest.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) {
 | 
			
		||||
			expectedNumMembers--
 | 
			
		||||
		}
 | 
			
		||||
		assert.NoError(t, RemoveOrgUser(orgID, userID))
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &organization.OrgUser{OrgID: orgID, UID: userID})
 | 
			
		||||
		org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
 | 
			
		||||
		assert.EqualValues(t, expectedNumMembers, org.NumMembers)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(3, 4)
 | 
			
		||||
	testSuccess(3, 4)
 | 
			
		||||
 | 
			
		||||
	err := RemoveOrgUser(7, 5)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, organization.IsErrLastOrgOwner(err))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &organization.OrgUser{OrgID: 7, UID: 5})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_RemoveOrgRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization)
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: org.ID}).(*repo_model.Repository)
 | 
			
		||||
 | 
			
		||||
	// remove a repo that does belong to org
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID})
 | 
			
		||||
	assert.NoError(t, org.RemoveOrgRepo(repo.ID))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{RepoID: repo.ID, OrgID: org.ID})
 | 
			
		||||
	assert.NoError(t, organization.RemoveOrgRepo(db.DefaultContext, org.ID, repo.ID))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.TeamRepo{RepoID: repo.ID, OrgID: org.ID})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) // repo should still exist
 | 
			
		||||
 | 
			
		||||
	// remove a repo that does not belong to org
 | 
			
		||||
	assert.NoError(t, org.RemoveOrgRepo(repo.ID))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID})
 | 
			
		||||
	assert.NoError(t, organization.RemoveOrgRepo(db.DefaultContext, org.ID, repo.ID))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.TeamRepo{RepoID: repo.ID, OrgID: org.ID})
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, org.RemoveOrgRepo(unittest.NonexistentID))
 | 
			
		||||
	assert.NoError(t, organization.RemoveOrgRepo(db.DefaultContext, org.ID, unittest.NonexistentID))
 | 
			
		||||
 | 
			
		||||
	unittest.CheckConsistencyFor(t,
 | 
			
		||||
		&user_model.User{ID: org.ID},
 | 
			
		||||
		&Team{OrgID: org.ID},
 | 
			
		||||
		&organization.Team{OrgID: org.ID},
 | 
			
		||||
		&repo_model.Repository{ID: repo.ID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -187,18 +92,18 @@ func TestCreateOrganization(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	const newOrgName = "neworg"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
	org := &organization.Organization{
 | 
			
		||||
		Name: newOrgName,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &user_model.User{Name: newOrgName, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	assert.NoError(t, CreateOrganization(org, owner))
 | 
			
		||||
	assert.NoError(t, organization.CreateOrganization(org, owner))
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}).(*Organization)
 | 
			
		||||
		&organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}).(*organization.Organization)
 | 
			
		||||
	ownerTeam := unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Team{Name: ownerTeamName, OrgID: org.ID}).(*Team)
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: owner.ID, TeamID: ownerTeam.ID})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
 | 
			
		||||
		&organization.Team{Name: organization.OwnerTeamName, OrgID: org.ID}).(*organization.Team)
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: owner.ID, TeamID: ownerTeam.ID})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateOrganization2(t *testing.T) {
 | 
			
		||||
@@ -207,16 +112,16 @@ func TestCreateOrganization2(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
 | 
			
		||||
	const newOrgName = "neworg"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
	org := &organization.Organization{
 | 
			
		||||
		Name: newOrgName,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	err := CreateOrganization(org, owner)
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	err := organization.CreateOrganization(org, owner)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, IsErrUserNotAllowedCreateOrg(err))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Organization{}, &Team{})
 | 
			
		||||
	assert.True(t, organization.IsErrUserNotAllowedCreateOrg(err))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &organization.Organization{}, &organization.Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateOrganization3(t *testing.T) {
 | 
			
		||||
@@ -224,12 +129,12 @@ func TestCreateOrganization3(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	org := &Organization{Name: "user3"}                                   // should already exist
 | 
			
		||||
	org := &organization.Organization{Name: "user3"}                      // should already exist
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: org.Name}) // sanity check
 | 
			
		||||
	err := CreateOrganization(org, owner)
 | 
			
		||||
	err := organization.CreateOrganization(org, owner)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, user_model.IsErrUserAlreadyExist(err))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateOrganization4(t *testing.T) {
 | 
			
		||||
@@ -237,210 +142,10 @@ func TestCreateOrganization4(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	err := CreateOrganization(&Organization{Name: "assets"}, owner)
 | 
			
		||||
	err := organization.CreateOrganization(&organization.Organization{Name: "assets"}, owner)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, db.IsErrNameReserved(err))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Organization{}, &Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOrgByName(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	org, err := GetOrgByName("user3")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 3, org.ID)
 | 
			
		||||
	assert.Equal(t, "user3", org.Name)
 | 
			
		||||
 | 
			
		||||
	_, err = GetOrgByName("user2") // user2 is an individual
 | 
			
		||||
	assert.True(t, IsErrOrgNotExist(err))
 | 
			
		||||
 | 
			
		||||
	_, err = GetOrgByName("") // corner case
 | 
			
		||||
	assert.True(t, IsErrOrgNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCountOrganizations(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&user_model.User{})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, expected, CountOrganizations())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsOrganizationOwner(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64, expected bool) {
 | 
			
		||||
		isOwner, err := IsOrganizationOwner(orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expected, isOwner)
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2, true)
 | 
			
		||||
	test(3, 3, false)
 | 
			
		||||
	test(6, 5, true)
 | 
			
		||||
	test(6, 4, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsOrganizationMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64, expected bool) {
 | 
			
		||||
		isMember, err := IsOrganizationMember(orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expected, isMember)
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2, true)
 | 
			
		||||
	test(3, 3, false)
 | 
			
		||||
	test(3, 4, true)
 | 
			
		||||
	test(6, 5, true)
 | 
			
		||||
	test(6, 4, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsPublicMembership(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64, expected bool) {
 | 
			
		||||
		isMember, err := IsPublicMembership(orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expected, isMember)
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2, true)
 | 
			
		||||
	test(3, 3, false)
 | 
			
		||||
	test(3, 4, false)
 | 
			
		||||
	test(6, 5, true)
 | 
			
		||||
	test(6, 4, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFindOrgs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgs, err := FindOrgs(FindOrgOptions{
 | 
			
		||||
		UserID:         4,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgs, 1) {
 | 
			
		||||
		assert.EqualValues(t, 3, orgs[0].ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs, err = FindOrgs(FindOrgOptions{
 | 
			
		||||
		UserID:         4,
 | 
			
		||||
		IncludePrivate: false,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgs, 0)
 | 
			
		||||
 | 
			
		||||
	total, err := CountOrgs(FindOrgOptions{
 | 
			
		||||
		UserID:         4,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 1, total)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOwnedOrgsByUserID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgs, err := GetOwnedOrgsByUserID(2)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgs, 1) {
 | 
			
		||||
		assert.EqualValues(t, 3, orgs[0].ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs, err = GetOwnedOrgsByUserID(4)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgs, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOwnedOrgsByUserIDDesc(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgs, err := GetOwnedOrgsByUserIDDesc(5, "id")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgs, 2) {
 | 
			
		||||
		assert.EqualValues(t, 7, orgs[0].ID)
 | 
			
		||||
		assert.EqualValues(t, 6, orgs[1].ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs, err = GetOwnedOrgsByUserIDDesc(4, "id")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgs, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOrgUsersByUserID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgUsers, err := GetOrgUsersByUserID(5, &SearchOrganizationsOptions{All: true})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgUsers, 2) {
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[0].ID,
 | 
			
		||||
			OrgID:    6,
 | 
			
		||||
			UID:      5,
 | 
			
		||||
			IsPublic: true,
 | 
			
		||||
		}, *orgUsers[0])
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[1].ID,
 | 
			
		||||
			OrgID:    7,
 | 
			
		||||
			UID:      5,
 | 
			
		||||
			IsPublic: false,
 | 
			
		||||
		}, *orgUsers[1])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	publicOrgUsers, err := GetOrgUsersByUserID(5, &SearchOrganizationsOptions{All: false})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, publicOrgUsers, 1)
 | 
			
		||||
	assert.Equal(t, *orgUsers[0], *publicOrgUsers[0])
 | 
			
		||||
 | 
			
		||||
	orgUsers, err = GetOrgUsersByUserID(1, &SearchOrganizationsOptions{All: true})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgUsers, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOrgUsersByOrgID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgUsers, err := GetOrgUsersByOrgID(&FindOrgMembersOpts{
 | 
			
		||||
		ListOptions: db.ListOptions{},
 | 
			
		||||
		OrgID:       3,
 | 
			
		||||
		PublicOnly:  false,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgUsers, 3) {
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[0].ID,
 | 
			
		||||
			OrgID:    3,
 | 
			
		||||
			UID:      2,
 | 
			
		||||
			IsPublic: true,
 | 
			
		||||
		}, *orgUsers[0])
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[1].ID,
 | 
			
		||||
			OrgID:    3,
 | 
			
		||||
			UID:      4,
 | 
			
		||||
			IsPublic: false,
 | 
			
		||||
		}, *orgUsers[1])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgUsers, err = GetOrgUsersByOrgID(&FindOrgMembersOpts{
 | 
			
		||||
		ListOptions: db.ListOptions{},
 | 
			
		||||
		OrgID:       unittest.NonexistentID,
 | 
			
		||||
		PublicOnly:  false,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgUsers, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestChangeOrgUserStatus(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(orgID, userID int64, public bool) {
 | 
			
		||||
		assert.NoError(t, ChangeOrgUserStatus(orgID, userID, public))
 | 
			
		||||
		orgUser := unittest.AssertExistsAndLoadBean(t, &OrgUser{OrgID: orgID, UID: userID}).(*OrgUser)
 | 
			
		||||
		assert.Equal(t, public, orgUser.IsPublic)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	testSuccess(3, 2, false)
 | 
			
		||||
	testSuccess(3, 2, false)
 | 
			
		||||
	testSuccess(3, 4, true)
 | 
			
		||||
	assert.NoError(t, ChangeOrgUserStatus(unittest.NonexistentID, unittest.NonexistentID, true))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &organization.Organization{}, &organization.Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAddOrgUser(t *testing.T) {
 | 
			
		||||
@@ -448,11 +153,11 @@ func TestAddOrgUser(t *testing.T) {
 | 
			
		||||
	testSuccess := func(orgID, userID int64, isPublic bool) {
 | 
			
		||||
		org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
 | 
			
		||||
		expectedNumMembers := org.NumMembers
 | 
			
		||||
		if !unittest.BeanExists(t, &OrgUser{OrgID: orgID, UID: userID}) {
 | 
			
		||||
		if !unittest.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) {
 | 
			
		||||
			expectedNumMembers++
 | 
			
		||||
		}
 | 
			
		||||
		assert.NoError(t, AddOrgUser(orgID, userID))
 | 
			
		||||
		ou := &OrgUser{OrgID: orgID, UID: userID}
 | 
			
		||||
		assert.NoError(t, organization.AddOrgUser(orgID, userID))
 | 
			
		||||
		ou := &organization.OrgUser{OrgID: orgID, UID: userID}
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, ou)
 | 
			
		||||
		assert.Equal(t, isPublic, ou.IsPublic)
 | 
			
		||||
		org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
 | 
			
		||||
@@ -467,194 +172,5 @@ func TestAddOrgUser(t *testing.T) {
 | 
			
		||||
	setting.Service.DefaultOrgMemberVisible = true
 | 
			
		||||
	testSuccess(6, 3, true)
 | 
			
		||||
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemoveOrgUser(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	testSuccess := func(orgID, userID int64) {
 | 
			
		||||
		org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
 | 
			
		||||
		expectedNumMembers := org.NumMembers
 | 
			
		||||
		if unittest.BeanExists(t, &OrgUser{OrgID: orgID, UID: userID}) {
 | 
			
		||||
			expectedNumMembers--
 | 
			
		||||
		}
 | 
			
		||||
		assert.NoError(t, RemoveOrgUser(orgID, userID))
 | 
			
		||||
		unittest.AssertNotExistsBean(t, &OrgUser{OrgID: orgID, UID: userID})
 | 
			
		||||
		org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
 | 
			
		||||
		assert.EqualValues(t, expectedNumMembers, org.NumMembers)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(3, 4)
 | 
			
		||||
	testSuccess(3, 4)
 | 
			
		||||
 | 
			
		||||
	err := RemoveOrgUser(7, 5)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, IsErrLastOrgOwner(err))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OrgUser{OrgID: 7, UID: 5})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetUserTeamIDs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID int64, expected []int64) {
 | 
			
		||||
		teamIDs, err := org.GetUserTeamIDs(userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expected, teamIDs)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, []int64{1, 2})
 | 
			
		||||
	testSuccess(4, []int64{2})
 | 
			
		||||
	testSuccess(unittest.NonexistentID, []int64{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_CountRepos(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID, expectedCount int64) {
 | 
			
		||||
		env, err := org.AccessibleReposEnv(userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		count, err := env.CountRepos()
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expectedCount, count)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, 3)
 | 
			
		||||
	testSuccess(4, 2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) {
 | 
			
		||||
		env, err := org.AccessibleReposEnv(userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		repoIDs, err := env.RepoIDs(1, 100)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expectedRepoIDs, repoIDs)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, 1, 100, []int64{3, 5, 32})
 | 
			
		||||
	testSuccess(4, 0, 100, []int64{3, 32})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_Repos(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID int64, expectedRepoIDs []int64) {
 | 
			
		||||
		env, err := org.AccessibleReposEnv(userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		repos, err := env.Repos(1, 100)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs))
 | 
			
		||||
		for i, repoID := range expectedRepoIDs {
 | 
			
		||||
			expectedRepos[i] = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
				&repo_model.Repository{ID: repoID}).(*repo_model.Repository)
 | 
			
		||||
		}
 | 
			
		||||
		assert.Equal(t, expectedRepos, repos)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, []int64{3, 5, 32})
 | 
			
		||||
	testSuccess(4, []int64{3, 32})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_MirrorRepos(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID int64, expectedRepoIDs []int64) {
 | 
			
		||||
		env, err := org.AccessibleReposEnv(userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		repos, err := env.MirrorRepos()
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs))
 | 
			
		||||
		for i, repoID := range expectedRepoIDs {
 | 
			
		||||
			expectedRepos[i] = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
				&repo_model.Repository{ID: repoID}).(*repo_model.Repository)
 | 
			
		||||
		}
 | 
			
		||||
		assert.Equal(t, expectedRepos, repos)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, []int64{5})
 | 
			
		||||
	testSuccess(4, []int64{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasOrgVisibleTypePublic(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
 | 
			
		||||
 | 
			
		||||
	const newOrgName = "test-org-public"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
		Name:       newOrgName,
 | 
			
		||||
		Visibility: structs.VisibleTypePublic,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	assert.NoError(t, CreateOrganization(org, owner))
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
 | 
			
		||||
	test1 := HasOrgOrUserVisible(org.AsUser(), owner)
 | 
			
		||||
	test2 := HasOrgOrUserVisible(org.AsUser(), user3)
 | 
			
		||||
	test3 := HasOrgOrUserVisible(org.AsUser(), nil)
 | 
			
		||||
	assert.True(t, test1) // owner of org
 | 
			
		||||
	assert.True(t, test2) // user not a part of org
 | 
			
		||||
	assert.True(t, test3) // logged out user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasOrgVisibleTypeLimited(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
 | 
			
		||||
 | 
			
		||||
	const newOrgName = "test-org-limited"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
		Name:       newOrgName,
 | 
			
		||||
		Visibility: structs.VisibleTypeLimited,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	assert.NoError(t, CreateOrganization(org, owner))
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
 | 
			
		||||
	test1 := HasOrgOrUserVisible(org.AsUser(), owner)
 | 
			
		||||
	test2 := HasOrgOrUserVisible(org.AsUser(), user3)
 | 
			
		||||
	test3 := HasOrgOrUserVisible(org.AsUser(), nil)
 | 
			
		||||
	assert.True(t, test1)  // owner of org
 | 
			
		||||
	assert.True(t, test2)  // user not a part of org
 | 
			
		||||
	assert.False(t, test3) // logged out user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasOrgVisibleTypePrivate(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
 | 
			
		||||
 | 
			
		||||
	const newOrgName = "test-org-private"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
		Name:       newOrgName,
 | 
			
		||||
		Visibility: structs.VisibleTypePrivate,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	assert.NoError(t, CreateOrganization(org, owner))
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
 | 
			
		||||
	test1 := HasOrgOrUserVisible(org.AsUser(), owner)
 | 
			
		||||
	test2 := HasOrgOrUserVisible(org.AsUser(), user3)
 | 
			
		||||
	test3 := HasOrgOrUserVisible(org.AsUser(), nil)
 | 
			
		||||
	assert.True(t, test1)  // owner of org
 | 
			
		||||
	assert.False(t, test2) // user not a part of org
 | 
			
		||||
	assert.False(t, test3) // logged out user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUsersWhoCanCreateOrgRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	users, err := GetUsersWhoCanCreateOrgRepo(3)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, users, 2)
 | 
			
		||||
	var ids []int64
 | 
			
		||||
	for i := range users {
 | 
			
		||||
		ids = append(ids, users[i].ID)
 | 
			
		||||
	}
 | 
			
		||||
	assert.ElementsMatch(t, ids, []int64{2, 28})
 | 
			
		||||
 | 
			
		||||
	users, err = GetUsersWhoCanCreateOrgRepo(7)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, users, 1)
 | 
			
		||||
	assert.EqualValues(t, 5, users[0].ID)
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								models/organization/main_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								models/organization/main_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
// Copyright 2021 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
	unittest.MainTest(m, filepath.Join("..", ".."),
 | 
			
		||||
		"user.yml",
 | 
			
		||||
		"org_user.yml",
 | 
			
		||||
		"team.yml",
 | 
			
		||||
		"team_repo.yml",
 | 
			
		||||
		"team_unit.yml",
 | 
			
		||||
		"team_user.yml",
 | 
			
		||||
		"repository.yml",
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										859
									
								
								models/organization/org.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										859
									
								
								models/organization/org.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,859 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Copyright 2019 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ________                            .__                __  .__
 | 
			
		||||
// \_____  \_______  _________    ____ |__|____________ _/  |_|__| ____   ____
 | 
			
		||||
//  /   |   \_  __ \/ ___\__  \  /    \|  \___   /\__  \\   __\  |/  _ \ /    \
 | 
			
		||||
// /    |    \  | \/ /_/  > __ \|   |  \  |/    /  / __ \|  | |  (  <_> )   |  \
 | 
			
		||||
// \_______  /__|  \___  (____  /___|  /__/_____ \(____  /__| |__|\____/|___|  /
 | 
			
		||||
//         \/     /_____/     \/     \/         \/     \/                    \/
 | 
			
		||||
 | 
			
		||||
// ErrOrgNotExist represents a "OrgNotExist" kind of error.
 | 
			
		||||
type ErrOrgNotExist struct {
 | 
			
		||||
	ID   int64
 | 
			
		||||
	Name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrOrgNotExist checks if an error is a ErrOrgNotExist.
 | 
			
		||||
func IsErrOrgNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrOrgNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrOrgNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("org does not exist [id: %d, name: %s]", err.ID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrLastOrgOwner represents a "LastOrgOwner" kind of error.
 | 
			
		||||
type ErrLastOrgOwner struct {
 | 
			
		||||
	UID int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrLastOrgOwner checks if an error is a ErrLastOrgOwner.
 | 
			
		||||
func IsErrLastOrgOwner(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrLastOrgOwner)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrLastOrgOwner) Error() string {
 | 
			
		||||
	return fmt.Sprintf("user is the last member of owner team [uid: %d]", err.UID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrUserNotAllowedCreateOrg represents a "UserNotAllowedCreateOrg" kind of error.
 | 
			
		||||
type ErrUserNotAllowedCreateOrg struct{}
 | 
			
		||||
 | 
			
		||||
// IsErrUserNotAllowedCreateOrg checks if an error is an ErrUserNotAllowedCreateOrg.
 | 
			
		||||
func IsErrUserNotAllowedCreateOrg(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrUserNotAllowedCreateOrg)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrUserNotAllowedCreateOrg) Error() string {
 | 
			
		||||
	return "user is not allowed to create organizations"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Organization represents an organization
 | 
			
		||||
type Organization user_model.User
 | 
			
		||||
 | 
			
		||||
// OrgFromUser converts user to organization
 | 
			
		||||
func OrgFromUser(user *user_model.User) *Organization {
 | 
			
		||||
	return (*Organization)(user)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableName represents the real table name of Organization
 | 
			
		||||
func (Organization) TableName() string {
 | 
			
		||||
	return "user"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOwnedBy returns true if given user is in the owner team.
 | 
			
		||||
func (org *Organization) IsOwnedBy(uid int64) (bool, error) {
 | 
			
		||||
	return IsOrganizationOwner(db.DefaultContext, org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOrgMember returns true if given user is member of organization.
 | 
			
		||||
func (org *Organization) IsOrgMember(uid int64) (bool, error) {
 | 
			
		||||
	return IsOrganizationMember(db.DefaultContext, org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanCreateOrgRepo returns true if given user can create repo in organization
 | 
			
		||||
func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) {
 | 
			
		||||
	return CanCreateOrgRepo(org.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getTeam(ctx context.Context, name string) (*Team, error) {
 | 
			
		||||
	return getTeam(ctx, org.ID, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeam returns named team of organization.
 | 
			
		||||
func (org *Organization) GetTeam(name string) (*Team, error) {
 | 
			
		||||
	return org.getTeam(db.DefaultContext, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getOwnerTeam(ctx context.Context) (*Team, error) {
 | 
			
		||||
	return org.getTeam(ctx, OwnerTeamName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnerTeam returns owner team of organization.
 | 
			
		||||
func (org *Organization) GetOwnerTeam() (*Team, error) {
 | 
			
		||||
	return org.getOwnerTeam(db.DefaultContext)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindOrgTeams returns all teams of a given organization
 | 
			
		||||
func FindOrgTeams(ctx context.Context, orgID int64) ([]*Team, error) {
 | 
			
		||||
	var teams []*Team
 | 
			
		||||
	return teams, db.GetEngine(ctx).
 | 
			
		||||
		Where("org_id=?", orgID).
 | 
			
		||||
		OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadTeams load teams if not loaded.
 | 
			
		||||
func (org *Organization) LoadTeams() ([]*Team, error) {
 | 
			
		||||
	return FindOrgTeams(db.DefaultContext, org.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetMembers returns all members of organization.
 | 
			
		||||
func (org *Organization) GetMembers() (user_model.UserList, map[int64]bool, error) {
 | 
			
		||||
	return FindOrgMembers(&FindOrgMembersOpts{
 | 
			
		||||
		OrgID: org.ID,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasMemberWithUserID returns true if user with userID is part of the u organisation.
 | 
			
		||||
func (org *Organization) HasMemberWithUserID(userID int64) bool {
 | 
			
		||||
	return org.hasMemberWithUserID(db.DefaultContext, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) hasMemberWithUserID(ctx context.Context, userID int64) bool {
 | 
			
		||||
	isMember, err := IsOrganizationMember(ctx, org.ID, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("IsOrganizationMember: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return isMember
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AvatarLink returns the full avatar link with http host
 | 
			
		||||
func (org *Organization) AvatarLink() string {
 | 
			
		||||
	return org.AsUser().AvatarLink()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTMLURL returns the organization's full link.
 | 
			
		||||
func (org *Organization) HTMLURL() string {
 | 
			
		||||
	return org.AsUser().HTMLURL()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OrganisationLink returns the organization sub page link.
 | 
			
		||||
func (org *Organization) OrganisationLink() string {
 | 
			
		||||
	return org.AsUser().OrganisationLink()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ShortName ellipses username to length
 | 
			
		||||
func (org *Organization) ShortName(length int) string {
 | 
			
		||||
	return org.AsUser().ShortName(length)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HomeLink returns the user or organization home page link.
 | 
			
		||||
func (org *Organization) HomeLink() string {
 | 
			
		||||
	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
 | 
			
		||||
type FindOrgMembersOpts struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	OrgID      int64
 | 
			
		||||
	PublicOnly bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrgMembers counts the organization's members
 | 
			
		||||
func CountOrgMembers(opts *FindOrgMembersOpts) (int64, error) {
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).Where("org_id=?", opts.OrgID)
 | 
			
		||||
	if opts.PublicOnly {
 | 
			
		||||
		sess.And("is_public = ?", true)
 | 
			
		||||
	}
 | 
			
		||||
	return sess.Count(new(OrgUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindOrgMembers loads organization members according conditions
 | 
			
		||||
func FindOrgMembers(opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bool, error) {
 | 
			
		||||
	ous, err := GetOrgUsersByOrgID(opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ids := make([]int64, len(ous))
 | 
			
		||||
	idsIsPublic := make(map[int64]bool, len(ous))
 | 
			
		||||
	for i, ou := range ous {
 | 
			
		||||
		ids[i] = ou.UID
 | 
			
		||||
		idsIsPublic[ou.UID] = ou.IsPublic
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	users, err := user_model.GetUsersByIDs(ids)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return users, idsIsPublic, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AsUser returns the org as user object
 | 
			
		||||
func (org *Organization) AsUser() *user_model.User {
 | 
			
		||||
	return (*user_model.User)(org)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisplayName returns full name if it's not empty,
 | 
			
		||||
// returns username otherwise.
 | 
			
		||||
func (org *Organization) DisplayName() string {
 | 
			
		||||
	return org.AsUser().DisplayName()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CustomAvatarRelativePath returns user custom avatar relative path.
 | 
			
		||||
func (org *Organization) CustomAvatarRelativePath() string {
 | 
			
		||||
	return org.Avatar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateOrganization creates record of a new organization.
 | 
			
		||||
func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
 | 
			
		||||
	if !owner.CanCreateOrganization() {
 | 
			
		||||
		return ErrUserNotAllowedCreateOrg{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = user_model.IsUsableUsername(org.Name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isExist, err := user_model.IsUserExist(0, org.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if isExist {
 | 
			
		||||
		return user_model.ErrUserAlreadyExist{Name: org.Name}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	org.LowerName = strings.ToLower(org.Name)
 | 
			
		||||
	if org.Rands, err = user_model.GetUserSalt(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if org.Salt, err = user_model.GetUserSalt(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	org.UseCustomAvatar = true
 | 
			
		||||
	org.MaxRepoCreation = -1
 | 
			
		||||
	org.NumTeams = 1
 | 
			
		||||
	org.NumMembers = 1
 | 
			
		||||
	org.Type = user_model.UserTypeOrganization
 | 
			
		||||
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err = user_model.DeleteUserRedirect(ctx, org.Name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, org); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert organization: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = user_model.GenerateRandomAvatarCtx(ctx, org.AsUser()); err != nil {
 | 
			
		||||
		return fmt.Errorf("generate random avatar: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add initial creator to organization and owner team.
 | 
			
		||||
	if err = db.Insert(ctx, &OrgUser{
 | 
			
		||||
		UID:   owner.ID,
 | 
			
		||||
		OrgID: org.ID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert org-user relation: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create default owner team.
 | 
			
		||||
	t := &Team{
 | 
			
		||||
		OrgID:                   org.ID,
 | 
			
		||||
		LowerName:               strings.ToLower(OwnerTeamName),
 | 
			
		||||
		Name:                    OwnerTeamName,
 | 
			
		||||
		AccessMode:              perm.AccessModeOwner,
 | 
			
		||||
		NumMembers:              1,
 | 
			
		||||
		IncludesAllRepositories: true,
 | 
			
		||||
		CanCreateOrgRepo:        true,
 | 
			
		||||
	}
 | 
			
		||||
	if err = db.Insert(ctx, t); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert owner team: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// insert units for team
 | 
			
		||||
	units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
 | 
			
		||||
	for _, tp := range unit.AllRepoUnitTypes {
 | 
			
		||||
		units = append(units, TeamUnit{
 | 
			
		||||
			OrgID:  org.ID,
 | 
			
		||||
			TeamID: t.ID,
 | 
			
		||||
			Type:   tp,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, &units); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, &TeamUser{
 | 
			
		||||
		UID:    owner.ID,
 | 
			
		||||
		OrgID:  org.ID,
 | 
			
		||||
		TeamID: t.ID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return fmt.Errorf("insert team-user relation: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgByName returns organization by given name.
 | 
			
		||||
func GetOrgByName(name string) (*Organization, error) {
 | 
			
		||||
	if len(name) == 0 {
 | 
			
		||||
		return nil, ErrOrgNotExist{0, name}
 | 
			
		||||
	}
 | 
			
		||||
	u := &Organization{
 | 
			
		||||
		LowerName: strings.ToLower(name),
 | 
			
		||||
		Type:      user_model.UserTypeOrganization,
 | 
			
		||||
	}
 | 
			
		||||
	has, err := db.GetEngine(db.DefaultContext).Get(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, ErrOrgNotExist{0, name}
 | 
			
		||||
	}
 | 
			
		||||
	return u, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrganizations returns number of organizations.
 | 
			
		||||
func CountOrganizations() int64 {
 | 
			
		||||
	count, _ := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("type=1").
 | 
			
		||||
		Count(new(Organization))
 | 
			
		||||
	return count
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOrganization deletes models associated to an organization.
 | 
			
		||||
func DeleteOrganization(ctx context.Context, org *Organization) error {
 | 
			
		||||
	if org.Type != user_model.UserTypeOrganization {
 | 
			
		||||
		return fmt.Errorf("%s is a user not an organization", org.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := db.DeleteBeans(ctx,
 | 
			
		||||
		&Team{OrgID: org.ID},
 | 
			
		||||
		&OrgUser{OrgID: org.ID},
 | 
			
		||||
		&TeamUser{OrgID: org.ID},
 | 
			
		||||
		&TeamUnit{OrgID: org.ID},
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return fmt.Errorf("deleteBeans: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil {
 | 
			
		||||
		return fmt.Errorf("Delete: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization
 | 
			
		||||
func (org *Organization) GetOrgUserMaxAuthorizeLevel(uid int64) (perm.AccessMode, error) {
 | 
			
		||||
	var authorize perm.AccessMode
 | 
			
		||||
	_, err := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Select("max(team.authorize)").
 | 
			
		||||
		Table("team").
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		Where("team_user.uid = ?", uid).
 | 
			
		||||
		And("team_user.org_id = ?", org.ID).
 | 
			
		||||
		Get(&authorize)
 | 
			
		||||
	return authorize, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUsersWhoCanCreateOrgRepo returns users which are able to create repo in organization
 | 
			
		||||
func GetUsersWhoCanCreateOrgRepo(ctx context.Context, orgID int64) ([]*user_model.User, error) {
 | 
			
		||||
	users := make([]*user_model.User, 0, 10)
 | 
			
		||||
	return users, db.GetEngine(ctx).
 | 
			
		||||
		Join("INNER", "`team_user`", "`team_user`.uid=`user`.id").
 | 
			
		||||
		Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
 | 
			
		||||
		Where(builder.Eq{"team.can_create_org_repo": true}.Or(builder.Eq{"team.authorize": perm.AccessModeOwner})).
 | 
			
		||||
		And("team_user.org_id = ?", orgID).Asc("`user`.name").Find(&users)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchOrganizationsOptions options to filter organizations
 | 
			
		||||
type SearchOrganizationsOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	All bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindOrgOptions finds orgs options
 | 
			
		||||
type FindOrgOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	UserID         int64
 | 
			
		||||
	IncludePrivate bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder {
 | 
			
		||||
	cond := builder.Eq{"uid": userID}
 | 
			
		||||
	if !includePrivate {
 | 
			
		||||
		cond["is_public"] = true
 | 
			
		||||
	}
 | 
			
		||||
	return builder.Select("org_id").From("org_user").Where(cond)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opts FindOrgOptions) toConds() builder.Cond {
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
	if opts.UserID > 0 {
 | 
			
		||||
		cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate)))
 | 
			
		||||
	}
 | 
			
		||||
	if !opts.IncludePrivate {
 | 
			
		||||
		cond = cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic})
 | 
			
		||||
	}
 | 
			
		||||
	return cond
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindOrgs returns a list of organizations according given conditions
 | 
			
		||||
func FindOrgs(opts FindOrgOptions) ([]*Organization, error) {
 | 
			
		||||
	orgs := make([]*Organization, 0, 10)
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where(opts.toConds()).
 | 
			
		||||
		Asc("`user`.name")
 | 
			
		||||
	if opts.Page > 0 && opts.PageSize > 0 {
 | 
			
		||||
		sess.Limit(opts.PageSize, opts.PageSize*(opts.Page-1))
 | 
			
		||||
	}
 | 
			
		||||
	return orgs, sess.Find(&orgs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrgs returns total count organizations according options
 | 
			
		||||
func CountOrgs(opts FindOrgOptions) (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where(opts.toConds()).
 | 
			
		||||
		Count(new(user_model.User))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*Organization, error) {
 | 
			
		||||
	orgs := make([]*Organization, 0, 10)
 | 
			
		||||
	return orgs, sess.
 | 
			
		||||
		Join("INNER", "`team_user`", "`team_user`.org_id=`user`.id").
 | 
			
		||||
		Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
 | 
			
		||||
		Where("`team_user`.uid=?", userID).
 | 
			
		||||
		And("`team`.authorize=?", perm.AccessModeOwner).
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&orgs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasOrgOrUserVisible tells if the given user can see the given org or user
 | 
			
		||||
func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool {
 | 
			
		||||
	// Not SignedUser
 | 
			
		||||
	if user == nil {
 | 
			
		||||
		return orgOrUser.Visibility == structs.VisibleTypePublic
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if user.IsAdmin || orgOrUser.ID == user.ID {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (orgOrUser.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !OrgFromUser(orgOrUser).hasMemberWithUserID(ctx, user.ID) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasOrgsVisible tells if the given user can see at least one of the orgs provided
 | 
			
		||||
func HasOrgsVisible(orgs []*Organization, user *user_model.User) bool {
 | 
			
		||||
	if len(orgs) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, org := range orgs {
 | 
			
		||||
		if HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
 | 
			
		||||
func GetOwnedOrgsByUserID(userID int64) ([]*Organization, error) {
 | 
			
		||||
	return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnedOrgsByUserIDDesc returns a list of organizations are owned by
 | 
			
		||||
// given user ID, ordered descending by the given condition.
 | 
			
		||||
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*Organization, error) {
 | 
			
		||||
	return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext).Desc(desc), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID
 | 
			
		||||
// are allowed to create repos.
 | 
			
		||||
func GetOrgsCanCreateRepoByUserID(userID int64) ([]*Organization, error) {
 | 
			
		||||
	orgs := make([]*Organization, 0, 10)
 | 
			
		||||
 | 
			
		||||
	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`", "`team`.id = `team_user`.team_id").
 | 
			
		||||
		Where(builder.Eq{"`team_user`.uid": userID}).
 | 
			
		||||
		And(builder.Eq{"`team`.authorize": perm.AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})))).
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&orgs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgUsersByUserID returns all organization-user relations by user ID.
 | 
			
		||||
func GetOrgUsersByUserID(uid int64, opts *SearchOrganizationsOptions) ([]*OrgUser, error) {
 | 
			
		||||
	ous := make([]*OrgUser, 0, 10)
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Join("LEFT", "`user`", "`org_user`.org_id=`user`.id").
 | 
			
		||||
		Where("`org_user`.uid=?", uid)
 | 
			
		||||
	if !opts.All {
 | 
			
		||||
		// Only show public organizations
 | 
			
		||||
		sess.And("is_public=?", true)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.PageSize != 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, opts)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := sess.
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&ous)
 | 
			
		||||
	return ous, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
 | 
			
		||||
func GetOrgUsersByOrgID(opts *FindOrgMembersOpts) ([]*OrgUser, error) {
 | 
			
		||||
	return getOrgUsersByOrgID(db.GetEngine(db.DefaultContext), opts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getOrgUsersByOrgID(e db.Engine, opts *FindOrgMembersOpts) ([]*OrgUser, error) {
 | 
			
		||||
	sess := e.Where("org_id=?", opts.OrgID)
 | 
			
		||||
	if opts.PublicOnly {
 | 
			
		||||
		sess.And("is_public = ?", true)
 | 
			
		||||
	}
 | 
			
		||||
	if opts.ListOptions.PageSize > 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, opts)
 | 
			
		||||
 | 
			
		||||
		ous := make([]*OrgUser, 0, opts.PageSize)
 | 
			
		||||
		return ous, sess.Find(&ous)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ous []*OrgUser
 | 
			
		||||
	return ous, sess.Find(&ous)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChangeOrgUserStatus changes public or private membership status.
 | 
			
		||||
func ChangeOrgUserStatus(orgID, uid int64, public bool) error {
 | 
			
		||||
	ou := new(OrgUser)
 | 
			
		||||
	has, err := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("uid=?", uid).
 | 
			
		||||
		And("org_id=?", orgID).
 | 
			
		||||
		Get(ou)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ou.IsPublic = public
 | 
			
		||||
	_, err = db.GetEngine(db.DefaultContext).ID(ou.ID).Cols("is_public").Update(ou)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddOrgUser adds new user to given organization.
 | 
			
		||||
func AddOrgUser(orgID, uid int64) error {
 | 
			
		||||
	isAlreadyMember, err := IsOrganizationMember(db.DefaultContext, orgID, uid)
 | 
			
		||||
	if err != nil || isAlreadyMember {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	ou := &OrgUser{
 | 
			
		||||
		UID:      uid,
 | 
			
		||||
		OrgID:    orgID,
 | 
			
		||||
		IsPublic: setting.Service.DefaultOrgMemberVisible,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := db.Insert(ctx, ou); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgByIDCtx returns the user object by given ID if exists.
 | 
			
		||||
func GetOrgByIDCtx(ctx context.Context, id int64) (*Organization, error) {
 | 
			
		||||
	u := new(Organization)
 | 
			
		||||
	has, err := db.GetEngine(ctx).ID(id).Get(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, user_model.ErrUserNotExist{
 | 
			
		||||
			UID:   id,
 | 
			
		||||
			Name:  "",
 | 
			
		||||
			KeyID: 0,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return u, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrgByID returns the user object by given ID if exists.
 | 
			
		||||
func GetOrgByID(id int64) (*Organization, error) {
 | 
			
		||||
	return GetOrgByIDCtx(db.DefaultContext, id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveOrgRepo removes all team-repository relations of organization.
 | 
			
		||||
func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error {
 | 
			
		||||
	teamRepos := make([]*TeamRepo, 0, 10)
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	if err := e.Find(&teamRepos, &TeamRepo{OrgID: orgID, RepoID: repoID}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(teamRepos) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := e.Delete(&TeamRepo{
 | 
			
		||||
		OrgID:  orgID,
 | 
			
		||||
		RepoID: repoID,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teamIDs := make([]int64, len(teamRepos))
 | 
			
		||||
	for i, teamRepo := range teamRepos {
 | 
			
		||||
		teamIDs[i] = teamRepo.TeamID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := e.Decr("num_repos").In("id", teamIDs).Update(new(Team))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getUserTeams(e db.Engine, userID int64, cols ...string) ([]*Team, error) {
 | 
			
		||||
	teams := make([]*Team, 0, org.NumTeams)
 | 
			
		||||
	return teams, e.
 | 
			
		||||
		Where("`team_user`.org_id = ?", org.ID).
 | 
			
		||||
		Join("INNER", "team_user", "`team_user`.team_id = team.id").
 | 
			
		||||
		Join("INNER", "`user`", "`user`.id=team_user.uid").
 | 
			
		||||
		And("`team_user`.uid = ?", userID).
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Cols(cols...).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) {
 | 
			
		||||
	teamIDs := make([]int64, 0, org.NumTeams)
 | 
			
		||||
	return teamIDs, db.GetEngine(ctx).
 | 
			
		||||
		Table("team").
 | 
			
		||||
		Cols("team.id").
 | 
			
		||||
		Where("`team_user`.org_id = ?", org.ID).
 | 
			
		||||
		Join("INNER", "team_user", "`team_user`.team_id = team.id").
 | 
			
		||||
		And("`team_user`.uid = ?", userID).
 | 
			
		||||
		Find(&teamIDs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TeamsWithAccessToRepo returns all teams that have given access level to the repository.
 | 
			
		||||
func (org *Organization) TeamsWithAccessToRepo(repoID int64, mode perm.AccessMode) ([]*Team, error) {
 | 
			
		||||
	return GetTeamsWithAccessToRepo(org.ID, repoID, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
 | 
			
		||||
func (org *Organization) GetUserTeamIDs(userID int64) ([]int64, error) {
 | 
			
		||||
	return org.getUserTeamIDs(db.DefaultContext, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserTeams returns all teams that belong to user,
 | 
			
		||||
// and that the user has joined.
 | 
			
		||||
func (org *Organization) GetUserTeams(userID int64) ([]*Team, error) {
 | 
			
		||||
	return org.getUserTeams(db.GetEngine(db.DefaultContext), userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AccessibleReposEnvironment operations involving the repositories that are
 | 
			
		||||
// accessible to a particular user
 | 
			
		||||
type AccessibleReposEnvironment interface {
 | 
			
		||||
	CountRepos() (int64, error)
 | 
			
		||||
	RepoIDs(page, pageSize int) ([]int64, error)
 | 
			
		||||
	Repos(page, pageSize int) ([]*repo_model.Repository, error)
 | 
			
		||||
	MirrorRepos() ([]*repo_model.Repository, error)
 | 
			
		||||
	AddKeyword(keyword string)
 | 
			
		||||
	SetSort(db.SearchOrderBy)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type accessibleReposEnv struct {
 | 
			
		||||
	org     *Organization
 | 
			
		||||
	user    *user_model.User
 | 
			
		||||
	team    *Team
 | 
			
		||||
	teamIDs []int64
 | 
			
		||||
	e       db.Engine
 | 
			
		||||
	keyword string
 | 
			
		||||
	orderBy db.SearchOrderBy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AccessibleReposEnv builds an AccessibleReposEnvironment for the repositories in `org`
 | 
			
		||||
// that are accessible to the specified user.
 | 
			
		||||
func AccessibleReposEnv(ctx context.Context, org *Organization, userID int64) (AccessibleReposEnvironment, error) {
 | 
			
		||||
	var user *user_model.User
 | 
			
		||||
 | 
			
		||||
	if userID > 0 {
 | 
			
		||||
		u, err := user_model.GetUserByIDCtx(ctx, userID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		user = u
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teamIDs, err := org.getUserTeamIDs(ctx, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &accessibleReposEnv{
 | 
			
		||||
		org:     org,
 | 
			
		||||
		user:    user,
 | 
			
		||||
		teamIDs: teamIDs,
 | 
			
		||||
		e:       db.GetEngine(ctx),
 | 
			
		||||
		orderBy: db.SearchOrderByRecentUpdated,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
 | 
			
		||||
// that are accessible to the specified team.
 | 
			
		||||
func (org *Organization) AccessibleTeamReposEnv(team *Team) AccessibleReposEnvironment {
 | 
			
		||||
	return &accessibleReposEnv{
 | 
			
		||||
		org:     org,
 | 
			
		||||
		team:    team,
 | 
			
		||||
		e:       db.GetEngine(db.DefaultContext),
 | 
			
		||||
		orderBy: db.SearchOrderByRecentUpdated,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) cond() builder.Cond {
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
	if env.team != nil {
 | 
			
		||||
		cond = cond.And(builder.Eq{"team_repo.team_id": env.team.ID})
 | 
			
		||||
	} else {
 | 
			
		||||
		if env.user == nil || !env.user.IsRestricted {
 | 
			
		||||
			cond = cond.Or(builder.Eq{
 | 
			
		||||
				"`repository`.owner_id":   env.org.ID,
 | 
			
		||||
				"`repository`.is_private": false,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		if len(env.teamIDs) > 0 {
 | 
			
		||||
			cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if env.keyword != "" {
 | 
			
		||||
		cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
 | 
			
		||||
	}
 | 
			
		||||
	return cond
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) CountRepos() (int64, error) {
 | 
			
		||||
	repoCount, err := env.e.
 | 
			
		||||
		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
 | 
			
		||||
		Where(env.cond()).
 | 
			
		||||
		Distinct("`repository`.id").
 | 
			
		||||
		Count(&repo_model.Repository{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("count user repositories in organization: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return repoCount, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
 | 
			
		||||
	if page <= 0 {
 | 
			
		||||
		page = 1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repoIDs := make([]int64, 0, pageSize)
 | 
			
		||||
	return repoIDs, env.e.
 | 
			
		||||
		Table("repository").
 | 
			
		||||
		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
 | 
			
		||||
		Where(env.cond()).
 | 
			
		||||
		GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]).
 | 
			
		||||
		OrderBy(string(env.orderBy)).
 | 
			
		||||
		Limit(pageSize, (page-1)*pageSize).
 | 
			
		||||
		Cols("`repository`.id").
 | 
			
		||||
		Find(&repoIDs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*repo_model.Repository, error) {
 | 
			
		||||
	repoIDs, err := env.RepoIDs(page, pageSize)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("GetUserRepositoryIDs: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*repo_model.Repository, 0, len(repoIDs))
 | 
			
		||||
	if len(repoIDs) == 0 {
 | 
			
		||||
		return repos, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repos, env.e.
 | 
			
		||||
		In("`repository`.id", repoIDs).
 | 
			
		||||
		OrderBy(string(env.orderBy)).
 | 
			
		||||
		Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
 | 
			
		||||
	repoIDs := make([]int64, 0, 10)
 | 
			
		||||
	return repoIDs, env.e.
 | 
			
		||||
		Table("repository").
 | 
			
		||||
		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
 | 
			
		||||
		Where(env.cond()).
 | 
			
		||||
		GroupBy("`repository`.id, `repository`.updated_unix").
 | 
			
		||||
		OrderBy(string(env.orderBy)).
 | 
			
		||||
		Cols("`repository`.id").
 | 
			
		||||
		Find(&repoIDs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) MirrorRepos() ([]*repo_model.Repository, error) {
 | 
			
		||||
	repoIDs, err := env.MirrorRepoIDs()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("MirrorRepoIDs: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*repo_model.Repository, 0, len(repoIDs))
 | 
			
		||||
	if len(repoIDs) == 0 {
 | 
			
		||||
		return repos, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repos, env.e.
 | 
			
		||||
		In("`repository`.id", repoIDs).
 | 
			
		||||
		Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) AddKeyword(keyword string) {
 | 
			
		||||
	env.keyword = keyword
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (env *accessibleReposEnv) SetSort(orderBy db.SearchOrderBy) {
 | 
			
		||||
	env.orderBy = orderBy
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										478
									
								
								models/organization/org_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										478
									
								
								models/organization/org_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,478 @@
 | 
			
		||||
// Copyright 2017 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestUser_IsOwnedBy(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	for _, testCase := range []struct {
 | 
			
		||||
		OrgID         int64
 | 
			
		||||
		UserID        int64
 | 
			
		||||
		ExpectedOwner bool
 | 
			
		||||
	}{
 | 
			
		||||
		{3, 2, true},
 | 
			
		||||
		{3, 1, false},
 | 
			
		||||
		{3, 3, false},
 | 
			
		||||
		{3, 4, false},
 | 
			
		||||
		{2, 2, false}, // user2 is not an organization
 | 
			
		||||
		{2, 3, false},
 | 
			
		||||
	} {
 | 
			
		||||
		org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: testCase.OrgID}).(*Organization)
 | 
			
		||||
		isOwner, err := org.IsOwnedBy(testCase.UserID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, testCase.ExpectedOwner, isOwner)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_IsOrgMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	for _, testCase := range []struct {
 | 
			
		||||
		OrgID          int64
 | 
			
		||||
		UserID         int64
 | 
			
		||||
		ExpectedMember bool
 | 
			
		||||
	}{
 | 
			
		||||
		{3, 2, true},
 | 
			
		||||
		{3, 4, true},
 | 
			
		||||
		{3, 1, false},
 | 
			
		||||
		{3, 3, false},
 | 
			
		||||
		{2, 2, false}, // user2 is not an organization
 | 
			
		||||
		{2, 3, false},
 | 
			
		||||
	} {
 | 
			
		||||
		org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: testCase.OrgID}).(*Organization)
 | 
			
		||||
		isMember, err := org.IsOrgMember(testCase.UserID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, testCase.ExpectedMember, isMember)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	team, err := org.GetTeam("team1")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, org.ID, team.OrgID)
 | 
			
		||||
	assert.Equal(t, "team1", team.LowerName)
 | 
			
		||||
 | 
			
		||||
	_, err = org.GetTeam("does not exist")
 | 
			
		||||
	assert.True(t, IsErrTeamNotExist(err))
 | 
			
		||||
 | 
			
		||||
	nonOrg := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 2}).(*Organization)
 | 
			
		||||
	_, err = nonOrg.GetTeam("team")
 | 
			
		||||
	assert.True(t, IsErrTeamNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetOwnerTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	team, err := org.GetOwnerTeam()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, org.ID, team.OrgID)
 | 
			
		||||
 | 
			
		||||
	nonOrg := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 2}).(*Organization)
 | 
			
		||||
	_, err = nonOrg.GetOwnerTeam()
 | 
			
		||||
	assert.True(t, IsErrTeamNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetTeams(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	teams, err := org.LoadTeams()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, teams, 4) {
 | 
			
		||||
		assert.Equal(t, int64(1), teams[0].ID)
 | 
			
		||||
		assert.Equal(t, int64(2), teams[1].ID)
 | 
			
		||||
		assert.Equal(t, int64(12), teams[2].ID)
 | 
			
		||||
		assert.Equal(t, int64(7), teams[3].ID)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetMembers(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	members, _, err := org.GetMembers()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, members, 3) {
 | 
			
		||||
		assert.Equal(t, int64(2), members[0].ID)
 | 
			
		||||
		assert.Equal(t, int64(28), members[1].ID)
 | 
			
		||||
		assert.Equal(t, int64(4), members[2].ID)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOrgByName(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	org, err := GetOrgByName("user3")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 3, org.ID)
 | 
			
		||||
	assert.Equal(t, "user3", org.Name)
 | 
			
		||||
 | 
			
		||||
	_, err = GetOrgByName("user2") // user2 is an individual
 | 
			
		||||
	assert.True(t, IsErrOrgNotExist(err))
 | 
			
		||||
 | 
			
		||||
	_, err = GetOrgByName("") // corner case
 | 
			
		||||
	assert.True(t, IsErrOrgNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCountOrganizations(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&user_model.User{})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, expected, CountOrganizations())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsOrganizationOwner(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64, expected bool) {
 | 
			
		||||
		isOwner, err := IsOrganizationOwner(db.DefaultContext, orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expected, isOwner)
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2, true)
 | 
			
		||||
	test(3, 3, false)
 | 
			
		||||
	test(6, 5, true)
 | 
			
		||||
	test(6, 4, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsOrganizationMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64, expected bool) {
 | 
			
		||||
		isMember, err := IsOrganizationMember(db.DefaultContext, orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expected, isMember)
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2, true)
 | 
			
		||||
	test(3, 3, false)
 | 
			
		||||
	test(3, 4, true)
 | 
			
		||||
	test(6, 5, true)
 | 
			
		||||
	test(6, 4, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsPublicMembership(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64, expected bool) {
 | 
			
		||||
		isMember, err := IsPublicMembership(orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expected, isMember)
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2, true)
 | 
			
		||||
	test(3, 3, false)
 | 
			
		||||
	test(3, 4, false)
 | 
			
		||||
	test(6, 5, true)
 | 
			
		||||
	test(6, 4, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFindOrgs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgs, err := FindOrgs(FindOrgOptions{
 | 
			
		||||
		UserID:         4,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgs, 1) {
 | 
			
		||||
		assert.EqualValues(t, 3, orgs[0].ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs, err = FindOrgs(FindOrgOptions{
 | 
			
		||||
		UserID:         4,
 | 
			
		||||
		IncludePrivate: false,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgs, 0)
 | 
			
		||||
 | 
			
		||||
	total, err := CountOrgs(FindOrgOptions{
 | 
			
		||||
		UserID:         4,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 1, total)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOwnedOrgsByUserID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgs, err := GetOwnedOrgsByUserID(2)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgs, 1) {
 | 
			
		||||
		assert.EqualValues(t, 3, orgs[0].ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs, err = GetOwnedOrgsByUserID(4)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgs, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOwnedOrgsByUserIDDesc(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgs, err := GetOwnedOrgsByUserIDDesc(5, "id")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgs, 2) {
 | 
			
		||||
		assert.EqualValues(t, 7, orgs[0].ID)
 | 
			
		||||
		assert.EqualValues(t, 6, orgs[1].ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs, err = GetOwnedOrgsByUserIDDesc(4, "id")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgs, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOrgUsersByUserID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgUsers, err := GetOrgUsersByUserID(5, &SearchOrganizationsOptions{All: true})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgUsers, 2) {
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[0].ID,
 | 
			
		||||
			OrgID:    6,
 | 
			
		||||
			UID:      5,
 | 
			
		||||
			IsPublic: true,
 | 
			
		||||
		}, *orgUsers[0])
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[1].ID,
 | 
			
		||||
			OrgID:    7,
 | 
			
		||||
			UID:      5,
 | 
			
		||||
			IsPublic: false,
 | 
			
		||||
		}, *orgUsers[1])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	publicOrgUsers, err := GetOrgUsersByUserID(5, &SearchOrganizationsOptions{All: false})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, publicOrgUsers, 1)
 | 
			
		||||
	assert.Equal(t, *orgUsers[0], *publicOrgUsers[0])
 | 
			
		||||
 | 
			
		||||
	orgUsers, err = GetOrgUsersByUserID(1, &SearchOrganizationsOptions{All: true})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgUsers, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOrgUsersByOrgID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	orgUsers, err := GetOrgUsersByOrgID(&FindOrgMembersOpts{
 | 
			
		||||
		ListOptions: db.ListOptions{},
 | 
			
		||||
		OrgID:       3,
 | 
			
		||||
		PublicOnly:  false,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, orgUsers, 3) {
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[0].ID,
 | 
			
		||||
			OrgID:    3,
 | 
			
		||||
			UID:      2,
 | 
			
		||||
			IsPublic: true,
 | 
			
		||||
		}, *orgUsers[0])
 | 
			
		||||
		assert.Equal(t, OrgUser{
 | 
			
		||||
			ID:       orgUsers[1].ID,
 | 
			
		||||
			OrgID:    3,
 | 
			
		||||
			UID:      4,
 | 
			
		||||
			IsPublic: false,
 | 
			
		||||
		}, *orgUsers[1])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgUsers, err = GetOrgUsersByOrgID(&FindOrgMembersOpts{
 | 
			
		||||
		ListOptions: db.ListOptions{},
 | 
			
		||||
		OrgID:       unittest.NonexistentID,
 | 
			
		||||
		PublicOnly:  false,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, orgUsers, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestChangeOrgUserStatus(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(orgID, userID int64, public bool) {
 | 
			
		||||
		assert.NoError(t, ChangeOrgUserStatus(orgID, userID, public))
 | 
			
		||||
		orgUser := unittest.AssertExistsAndLoadBean(t, &OrgUser{OrgID: orgID, UID: userID}).(*OrgUser)
 | 
			
		||||
		assert.Equal(t, public, orgUser.IsPublic)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	testSuccess(3, 2, false)
 | 
			
		||||
	testSuccess(3, 2, false)
 | 
			
		||||
	testSuccess(3, 4, true)
 | 
			
		||||
	assert.NoError(t, ChangeOrgUserStatus(unittest.NonexistentID, unittest.NonexistentID, true))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUser_GetUserTeamIDs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID int64, expected []int64) {
 | 
			
		||||
		teamIDs, err := org.GetUserTeamIDs(userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expected, teamIDs)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, []int64{1, 2})
 | 
			
		||||
	testSuccess(4, []int64{2})
 | 
			
		||||
	testSuccess(unittest.NonexistentID, []int64{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_CountRepos(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID, expectedCount int64) {
 | 
			
		||||
		env, err := AccessibleReposEnv(db.DefaultContext, org, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		count, err := env.CountRepos()
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, expectedCount, count)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, 3)
 | 
			
		||||
	testSuccess(4, 2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) {
 | 
			
		||||
		env, err := AccessibleReposEnv(db.DefaultContext, org, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		repoIDs, err := env.RepoIDs(1, 100)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expectedRepoIDs, repoIDs)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, 1, 100, []int64{3, 5, 32})
 | 
			
		||||
	testSuccess(4, 0, 100, []int64{3, 32})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_Repos(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID int64, expectedRepoIDs []int64) {
 | 
			
		||||
		env, err := AccessibleReposEnv(db.DefaultContext, org, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		repos, err := env.Repos(1, 100)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs))
 | 
			
		||||
		for i, repoID := range expectedRepoIDs {
 | 
			
		||||
			expectedRepos[i] = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
				&repo_model.Repository{ID: repoID}).(*repo_model.Repository)
 | 
			
		||||
		}
 | 
			
		||||
		assert.Equal(t, expectedRepos, repos)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, []int64{3, 5, 32})
 | 
			
		||||
	testSuccess(4, []int64{3, 32})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessibleReposEnv_MirrorRepos(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
 | 
			
		||||
	testSuccess := func(userID int64, expectedRepoIDs []int64) {
 | 
			
		||||
		env, err := AccessibleReposEnv(db.DefaultContext, org, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		repos, err := env.MirrorRepos()
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs))
 | 
			
		||||
		for i, repoID := range expectedRepoIDs {
 | 
			
		||||
			expectedRepos[i] = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
				&repo_model.Repository{ID: repoID}).(*repo_model.Repository)
 | 
			
		||||
		}
 | 
			
		||||
		assert.Equal(t, expectedRepos, repos)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, []int64{5})
 | 
			
		||||
	testSuccess(4, []int64{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasOrgVisibleTypePublic(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
 | 
			
		||||
 | 
			
		||||
	const newOrgName = "test-org-public"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
		Name:       newOrgName,
 | 
			
		||||
		Visibility: structs.VisibleTypePublic,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	assert.NoError(t, CreateOrganization(org, owner))
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
 | 
			
		||||
	test1 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner)
 | 
			
		||||
	test2 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user3)
 | 
			
		||||
	test3 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), nil)
 | 
			
		||||
	assert.True(t, test1) // owner of org
 | 
			
		||||
	assert.True(t, test2) // user not a part of org
 | 
			
		||||
	assert.True(t, test3) // logged out user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasOrgVisibleTypeLimited(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
 | 
			
		||||
 | 
			
		||||
	const newOrgName = "test-org-limited"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
		Name:       newOrgName,
 | 
			
		||||
		Visibility: structs.VisibleTypeLimited,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	assert.NoError(t, CreateOrganization(org, owner))
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
 | 
			
		||||
	test1 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner)
 | 
			
		||||
	test2 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user3)
 | 
			
		||||
	test3 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), nil)
 | 
			
		||||
	assert.True(t, test1)  // owner of org
 | 
			
		||||
	assert.True(t, test2)  // user not a part of org
 | 
			
		||||
	assert.False(t, test3) // logged out user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasOrgVisibleTypePrivate(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
 | 
			
		||||
	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
 | 
			
		||||
 | 
			
		||||
	const newOrgName = "test-org-private"
 | 
			
		||||
	org := &Organization{
 | 
			
		||||
		Name:       newOrgName,
 | 
			
		||||
		Visibility: structs.VisibleTypePrivate,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
 | 
			
		||||
	assert.NoError(t, CreateOrganization(org, owner))
 | 
			
		||||
	org = unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
 | 
			
		||||
	test1 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner)
 | 
			
		||||
	test2 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user3)
 | 
			
		||||
	test3 := HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), nil)
 | 
			
		||||
	assert.True(t, test1)  // owner of org
 | 
			
		||||
	assert.False(t, test2) // user not a part of org
 | 
			
		||||
	assert.False(t, test3) // logged out user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUsersWhoCanCreateOrgRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	users, err := GetUsersWhoCanCreateOrgRepo(db.DefaultContext, 3)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, users, 2)
 | 
			
		||||
	var ids []int64
 | 
			
		||||
	for i := range users {
 | 
			
		||||
		ids = append(ids, users[i].ID)
 | 
			
		||||
	}
 | 
			
		||||
	assert.ElementsMatch(t, ids, []int64{2, 28})
 | 
			
		||||
 | 
			
		||||
	users, err = GetUsersWhoCanCreateOrgRepo(db.DefaultContext, 7)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, users, 1)
 | 
			
		||||
	assert.EqualValues(t, 5, users[0].ID)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								models/organization/org_user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								models/organization/org_user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ________                ____ ___
 | 
			
		||||
// \_____  \_______  ____ |    |   \______ ___________
 | 
			
		||||
//  /   |   \_  __ \/ ___\|    |   /  ___// __ \_  __ \
 | 
			
		||||
// /    |    \  | \/ /_/  >    |  /\___ \\  ___/|  | \/
 | 
			
		||||
// \_______  /__|  \___  /|______//____  >\___  >__|
 | 
			
		||||
//         \/     /_____/              \/     \/
 | 
			
		||||
 | 
			
		||||
// OrgUser represents an organization-user relation.
 | 
			
		||||
type OrgUser struct {
 | 
			
		||||
	ID       int64 `xorm:"pk autoincr"`
 | 
			
		||||
	UID      int64 `xorm:"INDEX UNIQUE(s)"`
 | 
			
		||||
	OrgID    int64 `xorm:"INDEX UNIQUE(s)"`
 | 
			
		||||
	IsPublic bool  `xorm:"INDEX"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	db.RegisterModel(new(OrgUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOrganizationCount returns count of membership of organization of the user.
 | 
			
		||||
func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) {
 | 
			
		||||
	return db.GetEngine(ctx).
 | 
			
		||||
		Where("uid=?", u.ID).
 | 
			
		||||
		Count(new(OrgUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOrganizationOwner returns true if given user is in the owner team.
 | 
			
		||||
func IsOrganizationOwner(ctx context.Context, orgID, uid int64) (bool, error) {
 | 
			
		||||
	ownerTeam, err := GetOwnerTeam(ctx, orgID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if IsErrTeamNotExist(err) {
 | 
			
		||||
			log.Error("Organization does not have owner team: %d", orgID)
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	return IsTeamMember(ctx, orgID, ownerTeam.ID, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOrganizationMember returns true if given user is member of organization.
 | 
			
		||||
func IsOrganizationMember(ctx context.Context, orgID, uid int64) (bool, error) {
 | 
			
		||||
	return db.GetEngine(ctx).
 | 
			
		||||
		Where("uid=?", uid).
 | 
			
		||||
		And("org_id=?", orgID).
 | 
			
		||||
		Table("org_user").
 | 
			
		||||
		Exist()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsPublicMembership returns true if the given user's membership of given org is public.
 | 
			
		||||
func IsPublicMembership(orgID, uid int64) (bool, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("uid=?", uid).
 | 
			
		||||
		And("org_id=?", orgID).
 | 
			
		||||
		And("is_public=?", true).
 | 
			
		||||
		Table("org_user").
 | 
			
		||||
		Exist()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanCreateOrgRepo returns true if user can create repo in organization
 | 
			
		||||
func CanCreateOrgRepo(orgID, uid int64) (bool, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where(builder.Eq{"team.can_create_org_repo": true}).
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		And("team_user.uid = ?", uid).
 | 
			
		||||
		And("team_user.org_id = ?", orgID).
 | 
			
		||||
		Exist(new(Team))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								models/organization/org_user_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								models/organization/org_user_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestUserIsPublicMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	tt := []struct {
 | 
			
		||||
		uid      int64
 | 
			
		||||
		orgid    int64
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{2, 3, true},
 | 
			
		||||
		{4, 3, false},
 | 
			
		||||
		{5, 6, true},
 | 
			
		||||
		{5, 7, false},
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range tt {
 | 
			
		||||
		t.Run(fmt.Sprintf("UserId%dIsPublicMemberOf%d", v.uid, v.orgid), func(t *testing.T) {
 | 
			
		||||
			testUserIsPublicMember(t, v.uid, v.orgid, v.expected)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
 | 
			
		||||
	user, err := user_model.GetUserByID(uid)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	is, err := IsPublicMembership(orgID, user.ID)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, expected, is)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsUserOrgOwner(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	tt := []struct {
 | 
			
		||||
		uid      int64
 | 
			
		||||
		orgid    int64
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{2, 3, true},
 | 
			
		||||
		{4, 3, false},
 | 
			
		||||
		{5, 6, true},
 | 
			
		||||
		{5, 7, true},
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range tt {
 | 
			
		||||
		t.Run(fmt.Sprintf("UserId%dIsOrgOwnerOf%d", v.uid, v.orgid), func(t *testing.T) {
 | 
			
		||||
			testIsUserOrgOwner(t, v.uid, v.orgid, v.expected)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
 | 
			
		||||
	user, err := user_model.GetUserByID(uid)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	is, err := IsOrganizationOwner(db.DefaultContext, orgID, user.ID)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, expected, is)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										359
									
								
								models/organization/team.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								models/organization/team.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,359 @@
 | 
			
		||||
// Copyright 2018 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Copyright 2016 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ___________
 | 
			
		||||
// \__    ___/___ _____    _____
 | 
			
		||||
//   |    |_/ __ \\__  \  /     \
 | 
			
		||||
//   |    |\  ___/ / __ \|  Y Y  \
 | 
			
		||||
//   |____| \___  >____  /__|_|  /
 | 
			
		||||
//              \/     \/      \/
 | 
			
		||||
 | 
			
		||||
// ErrTeamAlreadyExist represents a "TeamAlreadyExist" kind of error.
 | 
			
		||||
type ErrTeamAlreadyExist struct {
 | 
			
		||||
	OrgID int64
 | 
			
		||||
	Name  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrTeamAlreadyExist checks if an error is a ErrTeamAlreadyExist.
 | 
			
		||||
func IsErrTeamAlreadyExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrTeamAlreadyExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrTeamAlreadyExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrTeamNotExist represents a "TeamNotExist" error
 | 
			
		||||
type ErrTeamNotExist struct {
 | 
			
		||||
	OrgID  int64
 | 
			
		||||
	TeamID int64
 | 
			
		||||
	Name   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrTeamNotExist checks if an error is a ErrTeamNotExist.
 | 
			
		||||
func IsErrTeamNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrTeamNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrTeamNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OwnerTeamName return the owner team name
 | 
			
		||||
const OwnerTeamName = "Owners"
 | 
			
		||||
 | 
			
		||||
// Team represents a organization team.
 | 
			
		||||
type Team struct {
 | 
			
		||||
	ID                      int64 `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID                   int64 `xorm:"INDEX"`
 | 
			
		||||
	LowerName               string
 | 
			
		||||
	Name                    string
 | 
			
		||||
	Description             string
 | 
			
		||||
	AccessMode              perm.AccessMode          `xorm:"'authorize'"`
 | 
			
		||||
	Repos                   []*repo_model.Repository `xorm:"-"`
 | 
			
		||||
	Members                 []*user_model.User       `xorm:"-"`
 | 
			
		||||
	NumRepos                int
 | 
			
		||||
	NumMembers              int
 | 
			
		||||
	Units                   []*TeamUnit `xorm:"-"`
 | 
			
		||||
	IncludesAllRepositories bool        `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	CanCreateOrgRepo        bool        `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	db.RegisterModel(new(Team))
 | 
			
		||||
	db.RegisterModel(new(TeamUser))
 | 
			
		||||
	db.RegisterModel(new(TeamRepo))
 | 
			
		||||
	db.RegisterModel(new(TeamUnit))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchTeamOptions holds the search options
 | 
			
		||||
type SearchTeamOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	UserID      int64
 | 
			
		||||
	Keyword     string
 | 
			
		||||
	OrgID       int64
 | 
			
		||||
	IncludeDesc bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchTeam search for teams. Caller is responsible to check permissions.
 | 
			
		||||
func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
 | 
			
		||||
	if opts.Page <= 0 {
 | 
			
		||||
		opts.Page = 1
 | 
			
		||||
	}
 | 
			
		||||
	if opts.PageSize == 0 {
 | 
			
		||||
		// Default limit
 | 
			
		||||
		opts.PageSize = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
 | 
			
		||||
	if len(opts.Keyword) > 0 {
 | 
			
		||||
		lowerKeyword := strings.ToLower(opts.Keyword)
 | 
			
		||||
		var keywordCond builder.Cond = builder.Like{"lower_name", lowerKeyword}
 | 
			
		||||
		if opts.IncludeDesc {
 | 
			
		||||
			keywordCond = keywordCond.Or(builder.Like{"LOWER(description)", lowerKeyword})
 | 
			
		||||
		}
 | 
			
		||||
		cond = cond.And(keywordCond)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cond = cond.And(builder.Eq{"org_id": opts.OrgID})
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext)
 | 
			
		||||
 | 
			
		||||
	count, err := sess.
 | 
			
		||||
		Where(cond).
 | 
			
		||||
		Count(new(Team))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess = sess.Where(cond)
 | 
			
		||||
	if opts.PageSize == -1 {
 | 
			
		||||
		opts.PageSize = int(count)
 | 
			
		||||
	} else {
 | 
			
		||||
		sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teams := make([]*Team, 0, opts.PageSize)
 | 
			
		||||
	if err = sess.
 | 
			
		||||
		OrderBy("lower_name").
 | 
			
		||||
		Find(&teams); err != nil {
 | 
			
		||||
		return nil, 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return teams, count, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ColorFormat provides a basic color format for a Team
 | 
			
		||||
func (t *Team) ColorFormat(s fmt.State) {
 | 
			
		||||
	if t == nil {
 | 
			
		||||
		log.ColorFprintf(s, "%d:%s (OrgID: %d) %-v",
 | 
			
		||||
			log.NewColoredIDValue(0),
 | 
			
		||||
			"<nil>",
 | 
			
		||||
			log.NewColoredIDValue(0),
 | 
			
		||||
			0)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	log.ColorFprintf(s, "%d:%s (OrgID: %d) %-v",
 | 
			
		||||
		log.NewColoredIDValue(t.ID),
 | 
			
		||||
		t.Name,
 | 
			
		||||
		log.NewColoredIDValue(t.OrgID),
 | 
			
		||||
		t.AccessMode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnits return a list of available units for a team
 | 
			
		||||
func (t *Team) GetUnits() error {
 | 
			
		||||
	return t.getUnits(db.DefaultContext)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) getUnits(ctx context.Context) (err error) {
 | 
			
		||||
	if t.Units != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.Units, err = getUnitsByTeamID(ctx, t.ID)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnitNames returns the team units names
 | 
			
		||||
func (t *Team) GetUnitNames() (res []string) {
 | 
			
		||||
	if t.AccessMode >= perm.AccessModeAdmin {
 | 
			
		||||
		return unit.AllUnitKeyNames()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, u := range t.Units {
 | 
			
		||||
		res = append(res, unit.Units[u.Type].NameKey)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnitsMap returns the team units permissions
 | 
			
		||||
func (t *Team) GetUnitsMap() map[string]string {
 | 
			
		||||
	m := make(map[string]string)
 | 
			
		||||
	if t.AccessMode >= perm.AccessModeAdmin {
 | 
			
		||||
		for _, u := range unit.Units {
 | 
			
		||||
			m[u.NameKey] = t.AccessMode.String()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, u := range t.Units {
 | 
			
		||||
			m[u.Unit().NameKey] = u.AccessMode.String()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOwnerTeam returns true if team is owner team.
 | 
			
		||||
func (t *Team) IsOwnerTeam() bool {
 | 
			
		||||
	return t.Name == OwnerTeamName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsMember returns true if given user is a member of team.
 | 
			
		||||
func (t *Team) IsMember(userID int64) bool {
 | 
			
		||||
	isMember, err := IsTeamMember(db.DefaultContext, t.OrgID, t.ID, userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("IsMember: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return isMember
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepositoriesCtx returns paginated repositories in team of organization.
 | 
			
		||||
func (t *Team) GetRepositoriesCtx(ctx context.Context) (err error) {
 | 
			
		||||
	if t.Repos != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{
 | 
			
		||||
		TeamID: t.ID,
 | 
			
		||||
	})
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetMembersCtx returns paginated members in team of organization.
 | 
			
		||||
func (t *Team) GetMembersCtx(ctx context.Context) (err error) {
 | 
			
		||||
	t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
 | 
			
		||||
		TeamID: t.ID,
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnitEnabled returns if the team has the given unit type enabled
 | 
			
		||||
func (t *Team) UnitEnabled(tp unit.Type) bool {
 | 
			
		||||
	return t.unitEnabled(db.DefaultContext, tp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) unitEnabled(ctx context.Context, tp unit.Type) bool {
 | 
			
		||||
	return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnitAccessMode returns if the team has the given unit type enabled
 | 
			
		||||
func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode {
 | 
			
		||||
	if err := t.getUnits(ctx); err != nil {
 | 
			
		||||
		log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, unit := range t.Units {
 | 
			
		||||
		if unit.Type == tp {
 | 
			
		||||
			return unit.AccessMode
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return perm.AccessModeNone
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUsableTeamName tests if a name could be as team name
 | 
			
		||||
func IsUsableTeamName(name string) error {
 | 
			
		||||
	switch name {
 | 
			
		||||
	case "new":
 | 
			
		||||
		return db.ErrNameReserved{Name: name}
 | 
			
		||||
	default:
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTeam(ctx context.Context, orgID int64, name string) (*Team, error) {
 | 
			
		||||
	t := &Team{
 | 
			
		||||
		OrgID:     orgID,
 | 
			
		||||
		LowerName: strings.ToLower(name),
 | 
			
		||||
	}
 | 
			
		||||
	has, err := db.GetByBean(ctx, t)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, ErrTeamNotExist{orgID, 0, name}
 | 
			
		||||
	}
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeam returns team by given team name and organization.
 | 
			
		||||
func GetTeam(orgID int64, name string) (*Team, error) {
 | 
			
		||||
	return getTeam(db.DefaultContext, orgID, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamIDsByNames returns a slice of team ids corresponds to names.
 | 
			
		||||
func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) {
 | 
			
		||||
	ids := make([]int64, 0, len(names))
 | 
			
		||||
	for _, name := range names {
 | 
			
		||||
		u, err := GetTeam(orgID, name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if ignoreNonExistent {
 | 
			
		||||
				continue
 | 
			
		||||
			} else {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ids = append(ids, u.ID)
 | 
			
		||||
	}
 | 
			
		||||
	return ids, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetOwnerTeam returns team by given team name and organization.
 | 
			
		||||
func GetOwnerTeam(ctx context.Context, orgID int64) (*Team, error) {
 | 
			
		||||
	return getTeam(ctx, orgID, OwnerTeamName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamByIDCtx returns team by given ID.
 | 
			
		||||
func GetTeamByIDCtx(ctx context.Context, teamID int64) (*Team, error) {
 | 
			
		||||
	t := new(Team)
 | 
			
		||||
	has, err := db.GetEngine(ctx).ID(teamID).Get(t)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, ErrTeamNotExist{0, teamID, ""}
 | 
			
		||||
	}
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamByID returns team by given ID.
 | 
			
		||||
func GetTeamByID(teamID int64) (*Team, error) {
 | 
			
		||||
	return GetTeamByIDCtx(db.DefaultContext, teamID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamNamesByID returns team's lower name from a list of team ids.
 | 
			
		||||
func GetTeamNamesByID(teamIDs []int64) ([]string, error) {
 | 
			
		||||
	if len(teamIDs) == 0 {
 | 
			
		||||
		return []string{}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var teamNames []string
 | 
			
		||||
	err := db.GetEngine(db.DefaultContext).Table("team").
 | 
			
		||||
		Select("lower_name").
 | 
			
		||||
		In("id", teamIDs).
 | 
			
		||||
		Asc("name").
 | 
			
		||||
		Find(&teamNames)
 | 
			
		||||
 | 
			
		||||
	return teamNames, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getRepoTeams(e db.Engine, repo *repo_model.Repository) (teams []*Team, err error) {
 | 
			
		||||
	return teams, e.
 | 
			
		||||
		Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
		Where("team.org_id = ?", repo.OwnerID).
 | 
			
		||||
		And("team_repo.repo_id=?", repo.ID).
 | 
			
		||||
		OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepoTeams gets the list of teams that has access to the repository
 | 
			
		||||
func GetRepoTeams(repo *repo_model.Repository) ([]*Team, error) {
 | 
			
		||||
	return getRepoTeams(db.GetEngine(db.DefaultContext), repo)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								models/organization/team_repo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								models/organization/team_repo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TeamRepo represents an team-repository relation.
 | 
			
		||||
type TeamRepo struct {
 | 
			
		||||
	ID     int64 `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID  int64 `xorm:"INDEX"`
 | 
			
		||||
	TeamID int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
	RepoID int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasTeamRepo returns true if given repository belongs to team.
 | 
			
		||||
func HasTeamRepo(ctx context.Context, orgID, teamID, repoID int64) bool {
 | 
			
		||||
	has, _ := db.GetEngine(ctx).
 | 
			
		||||
		Where("org_id=?", orgID).
 | 
			
		||||
		And("team_id=?", teamID).
 | 
			
		||||
		And("repo_id=?", repoID).
 | 
			
		||||
		Get(new(TeamRepo))
 | 
			
		||||
	return has
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SearchTeamRepoOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	TeamID int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepositories returns paginated repositories in team of organization.
 | 
			
		||||
func GetTeamRepositories(ctx context.Context, opts *SearchTeamRepoOptions) ([]*repo_model.Repository, error) {
 | 
			
		||||
	sess := db.GetEngine(ctx)
 | 
			
		||||
	if opts.TeamID > 0 {
 | 
			
		||||
		sess = sess.In("id",
 | 
			
		||||
			builder.Select("repo_id").
 | 
			
		||||
				From("team_repo").
 | 
			
		||||
				Where(builder.Eq{"team_id": opts.TeamID}),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	if opts.PageSize > 0 {
 | 
			
		||||
		sess.Limit(opts.PageSize, opts.Page*opts.PageSize)
 | 
			
		||||
	}
 | 
			
		||||
	var repos []*repo_model.Repository
 | 
			
		||||
	return repos, sess.OrderBy("repository.name").
 | 
			
		||||
		Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddTeamRepo addes a repo for an organization's team
 | 
			
		||||
func AddTeamRepo(ctx context.Context, orgID, teamID, repoID int64) error {
 | 
			
		||||
	_, err := db.GetEngine(ctx).Insert(&TeamRepo{
 | 
			
		||||
		OrgID:  orgID,
 | 
			
		||||
		TeamID: teamID,
 | 
			
		||||
		RepoID: repoID,
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveTeamRepo remove repository from team
 | 
			
		||||
func RemoveTeamRepo(ctx context.Context, teamID, repoID int64) error {
 | 
			
		||||
	_, err := db.DeleteByBean(ctx, &TeamRepo{
 | 
			
		||||
		TeamID: teamID,
 | 
			
		||||
		RepoID: repoID,
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamsWithAccessToRepo returns all teams in an organization that have given access level to the repository.
 | 
			
		||||
func GetTeamsWithAccessToRepo(orgID, repoID int64, mode perm.AccessMode) ([]*Team, error) {
 | 
			
		||||
	teams := make([]*Team, 0, 5)
 | 
			
		||||
	return teams, db.GetEngine(db.DefaultContext).Where("team.authorize >= ?", mode).
 | 
			
		||||
		Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
		And("team_repo.org_id = ?", orgID).
 | 
			
		||||
		And("team_repo.repo_id = ?", repoID).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										199
									
								
								models/organization/team_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								models/organization/team_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,199 @@
 | 
			
		||||
// Copyright 2017 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestTeam_IsOwnerTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team)
 | 
			
		||||
	assert.True(t, team.IsOwnerTeam())
 | 
			
		||||
 | 
			
		||||
	team = unittest.AssertExistsAndLoadBean(t, &Team{ID: 2}).(*Team)
 | 
			
		||||
	assert.False(t, team.IsOwnerTeam())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_IsMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team)
 | 
			
		||||
	assert.True(t, team.IsMember(2))
 | 
			
		||||
	assert.False(t, team.IsMember(4))
 | 
			
		||||
	assert.False(t, team.IsMember(unittest.NonexistentID))
 | 
			
		||||
 | 
			
		||||
	team = unittest.AssertExistsAndLoadBean(t, &Team{ID: 2}).(*Team)
 | 
			
		||||
	assert.True(t, team.IsMember(2))
 | 
			
		||||
	assert.True(t, team.IsMember(4))
 | 
			
		||||
	assert.False(t, team.IsMember(unittest.NonexistentID))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_GetRepositories(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.NoError(t, team.GetRepositoriesCtx(db.DefaultContext))
 | 
			
		||||
		assert.Len(t, team.Repos, team.NumRepos)
 | 
			
		||||
		for _, repo := range team.Repos {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repo.ID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(1)
 | 
			
		||||
	test(3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_GetMembers(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.NoError(t, team.GetMembersCtx(db.DefaultContext))
 | 
			
		||||
		assert.Len(t, team.Members, team.NumMembers)
 | 
			
		||||
		for _, member := range team.Members {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: member.ID, TeamID: teamID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(1)
 | 
			
		||||
	test(3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetTeam(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(orgID int64, name string) {
 | 
			
		||||
		team, err := GetTeam(orgID, name)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, orgID, team.OrgID)
 | 
			
		||||
		assert.Equal(t, name, team.Name)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(3, "Owners")
 | 
			
		||||
	testSuccess(3, "team1")
 | 
			
		||||
 | 
			
		||||
	_, err := GetTeam(3, "nonexistent")
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	_, err = GetTeam(unittest.NonexistentID, "Owners")
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetTeamByID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(teamID int64) {
 | 
			
		||||
		team, err := GetTeamByID(teamID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, teamID, team.ID)
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(1)
 | 
			
		||||
	testSuccess(2)
 | 
			
		||||
	testSuccess(3)
 | 
			
		||||
	testSuccess(4)
 | 
			
		||||
 | 
			
		||||
	_, err := GetTeamByID(unittest.NonexistentID)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsTeamMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, teamID, userID int64, expected bool) {
 | 
			
		||||
		isMember, err := IsTeamMember(db.DefaultContext, orgID, teamID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expected, isMember)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	test(3, 1, 2, true)
 | 
			
		||||
	test(3, 1, 4, false)
 | 
			
		||||
	test(3, 1, unittest.NonexistentID, false)
 | 
			
		||||
 | 
			
		||||
	test(3, 2, 2, true)
 | 
			
		||||
	test(3, 2, 4, true)
 | 
			
		||||
 | 
			
		||||
	test(3, unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
	test(unittest.NonexistentID, unittest.NonexistentID, unittest.NonexistentID, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetTeamMembers(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		members, err := GetTeamMembers(db.DefaultContext, &SearchMembersOptions{
 | 
			
		||||
			TeamID: teamID,
 | 
			
		||||
		})
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Len(t, members, team.NumMembers)
 | 
			
		||||
		for _, member := range members {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: member.ID, TeamID: teamID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(1)
 | 
			
		||||
	test(3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUserTeams(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(userID int64) {
 | 
			
		||||
		teams, _, err := SearchTeam(&SearchTeamOptions{UserID: userID})
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		for _, team := range teams {
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(2)
 | 
			
		||||
	test(5)
 | 
			
		||||
	test(unittest.NonexistentID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUserOrgTeams(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	test := func(orgID, userID int64) {
 | 
			
		||||
		teams, err := GetUserOrgTeams(db.DefaultContext, orgID, userID)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		for _, team := range teams {
 | 
			
		||||
			assert.EqualValues(t, orgID, team.OrgID)
 | 
			
		||||
			unittest.AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	test(3, 2)
 | 
			
		||||
	test(3, 4)
 | 
			
		||||
	test(3, unittest.NonexistentID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHasTeamRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamID, repoID int64, expected bool) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
 | 
			
		||||
		assert.Equal(t, expected, HasTeamRepo(db.DefaultContext, team.OrgID, teamID, repoID))
 | 
			
		||||
	}
 | 
			
		||||
	test(1, 1, false)
 | 
			
		||||
	test(1, 3, true)
 | 
			
		||||
	test(1, 5, true)
 | 
			
		||||
	test(1, unittest.NonexistentID, false)
 | 
			
		||||
 | 
			
		||||
	test(2, 3, true)
 | 
			
		||||
	test(2, 5, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUsersInTeamsCount(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	test := func(teamIDs, userIDs []int64, expected int64) {
 | 
			
		||||
		count, err := UsersInTeamsCount(teamIDs, userIDs)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Equal(t, expected, count)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	test([]int64{2}, []int64{1, 2, 3, 4}, 1)          // only userid 2
 | 
			
		||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2)    // userid 2,4
 | 
			
		||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3) // userid 2,4,5
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								models/organization/team_unit.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								models/organization/team_unit.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TeamUnit describes all units of a repository
 | 
			
		||||
type TeamUnit struct {
 | 
			
		||||
	ID         int64     `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID      int64     `xorm:"INDEX"`
 | 
			
		||||
	TeamID     int64     `xorm:"UNIQUE(s)"`
 | 
			
		||||
	Type       unit.Type `xorm:"UNIQUE(s)"`
 | 
			
		||||
	AccessMode perm.AccessMode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unit returns Unit
 | 
			
		||||
func (t *TeamUnit) Unit() unit.Unit {
 | 
			
		||||
	return unit.Units[t.Type]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getUnitsByTeamID(ctx context.Context, teamID int64) (units []*TeamUnit, err error) {
 | 
			
		||||
	return units, db.GetEngine(ctx).Where("team_id = ?", teamID).Find(&units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateTeamUnits updates a teams's units
 | 
			
		||||
func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if _, err = db.GetEngine(ctx).Where("team_id = ?", team.ID).Delete(new(TeamUnit)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(units) > 0 {
 | 
			
		||||
		if err = db.Insert(ctx, units); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								models/organization/team_user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								models/organization/team_user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TeamUser represents an team-user relation.
 | 
			
		||||
type TeamUser struct {
 | 
			
		||||
	ID     int64 `xorm:"pk autoincr"`
 | 
			
		||||
	OrgID  int64 `xorm:"INDEX"`
 | 
			
		||||
	TeamID int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
	UID    int64 `xorm:"UNIQUE(s)"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsTeamMember returns true if given user is a member of team.
 | 
			
		||||
func IsTeamMember(ctx context.Context, orgID, teamID, userID int64) (bool, error) {
 | 
			
		||||
	return db.GetEngine(ctx).
 | 
			
		||||
		Where("org_id=?", orgID).
 | 
			
		||||
		And("team_id=?", teamID).
 | 
			
		||||
		And("uid=?", userID).
 | 
			
		||||
		Table("team_user").
 | 
			
		||||
		Exist()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamUsersByTeamID returns team users for a team
 | 
			
		||||
func GetTeamUsersByTeamID(ctx context.Context, teamID int64) ([]*TeamUser, error) {
 | 
			
		||||
	teamUsers := make([]*TeamUser, 0, 10)
 | 
			
		||||
	return teamUsers, db.GetEngine(ctx).
 | 
			
		||||
		Where("team_id=?", teamID).
 | 
			
		||||
		Find(&teamUsers)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchMembersOptions holds the search options
 | 
			
		||||
type SearchMembersOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
	TeamID int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opts SearchMembersOptions) ToConds() builder.Cond {
 | 
			
		||||
	cond := builder.NewCond()
 | 
			
		||||
	if opts.TeamID > 0 {
 | 
			
		||||
		cond = cond.And(builder.Eq{"": opts.TeamID})
 | 
			
		||||
	}
 | 
			
		||||
	return cond
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTeamMembers returns all members in given team of organization.
 | 
			
		||||
func GetTeamMembers(ctx context.Context, opts *SearchMembersOptions) ([]*user_model.User, error) {
 | 
			
		||||
	var members []*user_model.User
 | 
			
		||||
	sess := db.GetEngine(ctx)
 | 
			
		||||
	if opts.TeamID > 0 {
 | 
			
		||||
		sess = sess.In("id",
 | 
			
		||||
			builder.Select("uid").
 | 
			
		||||
				From("team_user").
 | 
			
		||||
				Where(builder.Eq{"team_id": opts.TeamID}),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	if opts.PageSize > 0 && opts.Page > -1 {
 | 
			
		||||
		sess = sess.Limit(opts.PageSize, opts.Page*opts.PageSize)
 | 
			
		||||
	}
 | 
			
		||||
	if err := sess.OrderBy("full_name, name").Find(&members); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return members, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserOrgTeams returns all teams that user belongs to in given organization.
 | 
			
		||||
func GetUserOrgTeams(ctx context.Context, orgID, userID int64) (teams []*Team, err error) {
 | 
			
		||||
	return teams, db.GetEngine(ctx).
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		Where("team.org_id = ?", orgID).
 | 
			
		||||
		And("team_user.uid=?", userID).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserRepoTeams returns user repo's teams
 | 
			
		||||
func GetUserRepoTeams(ctx context.Context, orgID, userID, repoID int64) (teams []*Team, err error) {
 | 
			
		||||
	return teams, db.GetEngine(ctx).
 | 
			
		||||
		Join("INNER", "team_user", "team_user.team_id = team.id").
 | 
			
		||||
		Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
		Where("team.org_id = ?", orgID).
 | 
			
		||||
		And("team_user.uid=?", userID).
 | 
			
		||||
		And("team_repo.repo_id=?", repoID).
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUserInTeams returns if a user in some teams
 | 
			
		||||
func IsUserInTeams(ctx context.Context, userID int64, teamIDs []int64) (bool, error) {
 | 
			
		||||
	return db.GetEngine(ctx).Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
 | 
			
		||||
func UsersInTeamsCount(userIDs, teamIDs []int64) (int64, error) {
 | 
			
		||||
	var ids []int64
 | 
			
		||||
	if err := db.GetEngine(db.DefaultContext).In("uid", userIDs).In("team_id", teamIDs).
 | 
			
		||||
		Table("team_user").
 | 
			
		||||
		Cols("uid").GroupBy("uid").Find(&ids); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return int64(len(ids)), nil
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/modules/base"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
 | 
			
		||||
@@ -83,7 +84,7 @@ func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	in, err := IsUserInTeams(userID, pt.AllowlistTeamIDs)
 | 
			
		||||
	in, err := organization.IsUserInTeams(db.DefaultContext, userID, pt.AllowlistTeamIDs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import (
 | 
			
		||||
	admin_model "code.gitea.io/gitea/models/admin"
 | 
			
		||||
	asymkey_model "code.gitea.io/gitea/models/asymkey"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
@@ -268,7 +269,7 @@ func GetReviewers(repo *repo_model.Repository, doerID, posterID int64) ([]*user_
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetReviewerTeams get all teams can be requested to review
 | 
			
		||||
func GetReviewerTeams(repo *repo_model.Repository) ([]*Team, error) {
 | 
			
		||||
func GetReviewerTeams(repo *repo_model.Repository) ([]*organization.Team, error) {
 | 
			
		||||
	if err := repo.GetOwner(db.DefaultContext); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -276,7 +277,7 @@ func GetReviewerTeams(repo *repo_model.Repository) ([]*Team, error) {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teams, err := GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, perm.AccessModeRead)
 | 
			
		||||
	teams, err := organization.GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, perm.AccessModeRead)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -313,7 +314,7 @@ func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool,
 | 
			
		||||
	if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	ownedOrgs, err := GetOrgsCanCreateRepoByUserID(user.ID)
 | 
			
		||||
	ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(user.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -372,7 +373,7 @@ func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, er
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if repo.Owner.IsOrganization() {
 | 
			
		||||
		isOwner, err := OrgFromUser(repo.Owner).IsOwnedBy(user.ID)
 | 
			
		||||
		isOwner, err := organization.OrgFromUser(repo.Owner).IsOwnedBy(user.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		} else if isOwner {
 | 
			
		||||
@@ -550,19 +551,19 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_
 | 
			
		||||
 | 
			
		||||
	// Give access to all members in teams with access to all repositories.
 | 
			
		||||
	if u.IsOrganization() {
 | 
			
		||||
		teams, err := OrgFromUser(u).loadTeams(db.GetEngine(ctx))
 | 
			
		||||
		teams, err := organization.FindOrgTeams(ctx, u.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("loadTeams: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, t := range teams {
 | 
			
		||||
			if t.IncludesAllRepositories {
 | 
			
		||||
				if err := t.addRepository(ctx, repo); err != nil {
 | 
			
		||||
				if err := addRepository(ctx, t, repo); err != nil {
 | 
			
		||||
					return fmt.Errorf("addRepository: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if isAdmin, err := isUserRepoAdmin(db.GetEngine(ctx), repo, doer); err != nil {
 | 
			
		||||
		if isAdmin, err := isUserRepoAdmin(ctx, repo, doer); err != nil {
 | 
			
		||||
			return fmt.Errorf("isUserRepoAdmin: %v", err)
 | 
			
		||||
		} else if !isAdmin {
 | 
			
		||||
			// Make creator repo admin if it wasn't assigned automatically
 | 
			
		||||
@@ -768,14 +769,14 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if org.IsOrganization() {
 | 
			
		||||
		teams, err := OrgFromUser(org).loadTeams(sess)
 | 
			
		||||
		teams, err := organization.FindOrgTeams(ctx, org.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		for _, t := range teams {
 | 
			
		||||
			if !t.hasRepository(sess, repoID) {
 | 
			
		||||
			if !hasRepository(ctx, t, repoID) {
 | 
			
		||||
				continue
 | 
			
		||||
			} else if err = t.removeRepository(ctx, repo, false); err != nil {
 | 
			
		||||
			} else if err = removeRepository(ctx, t, repo, false); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -1326,7 +1327,7 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("GetRepositoryByID: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		has, err := isUserRepoAdmin(sess, repo, doer)
 | 
			
		||||
		has, err := isUserRepoAdmin(ctx, repo, doer)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("GetUserRepoPermission: %v", err)
 | 
			
		||||
		} else if !has {
 | 
			
		||||
 
 | 
			
		||||
@@ -751,37 +751,3 @@ func countRepositories(userID int64, private bool) int64 {
 | 
			
		||||
func CountRepositories(private bool) int64 {
 | 
			
		||||
	return countRepositories(-1, private)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountUserRepositories returns number of repositories user owns.
 | 
			
		||||
// Argument private only takes effect when it is false,
 | 
			
		||||
// set it true to count all repositories.
 | 
			
		||||
func CountUserRepositories(userID int64, private bool) int64 {
 | 
			
		||||
	return countRepositories(userID, private)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) {
 | 
			
		||||
	return e.Count(&Repository{OwnerID: ownerID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getPublicRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
 | 
			
		||||
	return e.Where("is_private = ?", false).Count(&Repository{OwnerID: u.ID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getPrivateRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
 | 
			
		||||
	return e.Where("is_private = ?", true).Count(&Repository{OwnerID: u.ID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepositoryCount returns the total number of repositories of user.
 | 
			
		||||
func GetRepositoryCount(ctx context.Context, ownerID int64) (int64, error) {
 | 
			
		||||
	return getRepositoryCount(db.GetEngine(ctx), ownerID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPublicRepositoryCount returns the total number of public repositories of user.
 | 
			
		||||
func GetPublicRepositoryCount(u *user_model.User) (int64, error) {
 | 
			
		||||
	return getPublicRepositoryCount(db.GetEngine(db.DefaultContext), u)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPrivateRepositoryCount returns the total number of private repositories of user.
 | 
			
		||||
func GetPrivateRepositoryCount(u *user_model.User) (int64, error) {
 | 
			
		||||
	return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										87
									
								
								models/repo/user_repo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								models/repo/user_repo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetStarredRepos returns the repos starred by a particular user
 | 
			
		||||
func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, error) {
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).Where("star.uid=?", userID).
 | 
			
		||||
		Join("LEFT", "star", "`repository`.id=`star`.repo_id")
 | 
			
		||||
	if !private {
 | 
			
		||||
		sess = sess.And("is_private=?", false)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if listOptions.Page != 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, &listOptions)
 | 
			
		||||
 | 
			
		||||
		repos := make([]*Repository, 0, listOptions.PageSize)
 | 
			
		||||
		return repos, sess.Find(&repos)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*Repository, 0, 10)
 | 
			
		||||
	return repos, sess.Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetWatchedRepos returns the repos watched by a particular user
 | 
			
		||||
func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, int64, error) {
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).Where("watch.user_id=?", userID).
 | 
			
		||||
		And("`watch`.mode<>?", WatchModeDont).
 | 
			
		||||
		Join("LEFT", "watch", "`repository`.id=`watch`.repo_id")
 | 
			
		||||
	if !private {
 | 
			
		||||
		sess = sess.And("is_private=?", false)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if listOptions.Page != 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, &listOptions)
 | 
			
		||||
 | 
			
		||||
		repos := make([]*Repository, 0, listOptions.PageSize)
 | 
			
		||||
		total, err := sess.FindAndCount(&repos)
 | 
			
		||||
		return repos, total, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*Repository, 0, 10)
 | 
			
		||||
	total, err := sess.FindAndCount(&repos)
 | 
			
		||||
	return repos, total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountUserRepositories returns number of repositories user owns.
 | 
			
		||||
// Argument private only takes effect when it is false,
 | 
			
		||||
// set it true to count all repositories.
 | 
			
		||||
func CountUserRepositories(userID int64, private bool) int64 {
 | 
			
		||||
	return countRepositories(userID, private)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) {
 | 
			
		||||
	return e.Count(&Repository{OwnerID: ownerID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getPublicRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
 | 
			
		||||
	return e.Where("is_private = ?", false).Count(&Repository{OwnerID: u.ID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getPrivateRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
 | 
			
		||||
	return e.Where("is_private = ?", true).Count(&Repository{OwnerID: u.ID})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepositoryCount returns the total number of repositories of user.
 | 
			
		||||
func GetRepositoryCount(ctx context.Context, ownerID int64) (int64, error) {
 | 
			
		||||
	return getRepositoryCount(db.GetEngine(ctx), ownerID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPublicRepositoryCount returns the total number of public repositories of user.
 | 
			
		||||
func GetPublicRepositoryCount(u *user_model.User) (int64, error) {
 | 
			
		||||
	return getPublicRepositoryCount(db.GetEngine(db.DefaultContext), u)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPrivateRepositoryCount returns the total number of private repositories of user.
 | 
			
		||||
func GetPrivateRepositoryCount(u *user_model.User) (int64, error) {
 | 
			
		||||
	return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u)
 | 
			
		||||
}
 | 
			
		||||
@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
@@ -259,20 +260,6 @@ func reconsiderWatches(ctx context.Context, repo *repo_model.Repository, uid int
 | 
			
		||||
	return removeIssueWatchersByRepoID(db.GetEngine(ctx), uid, repo.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getRepoTeams(e db.Engine, repo *repo_model.Repository) (teams []*Team, err error) {
 | 
			
		||||
	return teams, e.
 | 
			
		||||
		Join("INNER", "team_repo", "team_repo.team_id = team.id").
 | 
			
		||||
		Where("team.org_id = ?", repo.OwnerID).
 | 
			
		||||
		And("team_repo.repo_id=?", repo.ID).
 | 
			
		||||
		OrderBy("CASE WHEN name LIKE '" + ownerTeamName + "' THEN '' ELSE name END").
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepoTeams gets the list of teams that has access to the repository
 | 
			
		||||
func GetRepoTeams(repo *repo_model.Repository) ([]*Team, error) {
 | 
			
		||||
	return getRepoTeams(db.GetEngine(db.DefaultContext), repo)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository
 | 
			
		||||
func IsOwnerMemberCollaborator(repo *repo_model.Repository, userID int64) (bool, error) {
 | 
			
		||||
	if repo.OwnerID == userID {
 | 
			
		||||
@@ -282,7 +269,7 @@ func IsOwnerMemberCollaborator(repo *repo_model.Repository, userID int64) (bool,
 | 
			
		||||
		Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id").
 | 
			
		||||
		Where("team_repo.repo_id = ?", repo.ID).
 | 
			
		||||
		And("team_unit.`type` = ?", unit.TypeCode).
 | 
			
		||||
		And("team_user.uid = ?", userID).Table("team_user").Exist(&TeamUser{})
 | 
			
		||||
		And("team_user.uid = ?", userID).Table("team_user").Exist(&organization.TeamUser{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	perm_model "code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
@@ -186,7 +187,7 @@ func getUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
 | 
			
		||||
 | 
			
		||||
	// Prevent strangers from checking out public repo of private organization/users
 | 
			
		||||
	// Allow user if they are collaborator of a repo within a private user or a private organization but not a member of the organization itself
 | 
			
		||||
	if !hasOrgOrUserVisible(e, repo.Owner, user) && !is {
 | 
			
		||||
	if !organization.HasOrgOrUserVisible(ctx, repo.Owner, user) && !is {
 | 
			
		||||
		perm.AccessMode = perm_model.AccessModeNone
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -232,7 +233,7 @@ func getUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get units mode from teams
 | 
			
		||||
	teams, err := getUserRepoTeams(e, repo.OwnerID, user.ID, repo.ID)
 | 
			
		||||
	teams, err := organization.GetUserRepoTeams(ctx, repo.OwnerID, user.ID, repo.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -249,7 +250,7 @@ func getUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
 | 
			
		||||
	for _, u := range repo.Units {
 | 
			
		||||
		var found bool
 | 
			
		||||
		for _, team := range teams {
 | 
			
		||||
			teamMode := team.unitAccessMode(e, u.Type)
 | 
			
		||||
			teamMode := team.UnitAccessMode(ctx, u.Type)
 | 
			
		||||
			if teamMode > perm_model.AccessModeNone {
 | 
			
		||||
				m := perm.UnitsMode[u.Type]
 | 
			
		||||
				if m < teamMode {
 | 
			
		||||
@@ -300,10 +301,10 @@ func IsUserRealRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bo
 | 
			
		||||
 | 
			
		||||
// IsUserRepoAdmin return true if user has admin right of a repo
 | 
			
		||||
func IsUserRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bool, error) {
 | 
			
		||||
	return isUserRepoAdmin(db.GetEngine(db.DefaultContext), repo, user)
 | 
			
		||||
	return isUserRepoAdmin(db.DefaultContext, repo, user)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isUserRepoAdmin(e db.Engine, repo *repo_model.Repository, user *user_model.User) (bool, error) {
 | 
			
		||||
func isUserRepoAdmin(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (bool, error) {
 | 
			
		||||
	if user == nil || repo == nil {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -311,6 +312,7 @@ func isUserRepoAdmin(e db.Engine, repo *repo_model.Repository, user *user_model.
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	mode, err := accessLevel(e, user, repo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
@@ -319,7 +321,7 @@ func isUserRepoAdmin(e db.Engine, repo *repo_model.Repository, user *user_model.
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teams, err := getUserRepoTeams(e, repo.OwnerID, user.ID, repo.ID)
 | 
			
		||||
	teams, err := organization.GetUserRepoTeams(ctx, repo.OwnerID, user.ID, repo.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	perm_model "code.gitea.io/gitea/models/perm"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
@@ -227,8 +228,8 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// update team information and then check permission
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 5}).(*Team)
 | 
			
		||||
	err = UpdateTeamUnits(team, nil)
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team)
 | 
			
		||||
	err = organization.UpdateTeamUnits(team, nil)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	perm, err = GetUserRepoPermission(repo, owner)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
@@ -26,7 +27,7 @@ type RepoTransfer struct {
 | 
			
		||||
	Recipient   *user_model.User `xorm:"-"`
 | 
			
		||||
	RepoID      int64
 | 
			
		||||
	TeamIDs     []int64
 | 
			
		||||
	Teams       []*Team `xorm:"-"`
 | 
			
		||||
	Teams       []*organization.Team `xorm:"-"`
 | 
			
		||||
 | 
			
		||||
	CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
 | 
			
		||||
	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL updated"`
 | 
			
		||||
@@ -49,7 +50,7 @@ func (r *RepoTransfer) LoadAttributes() error {
 | 
			
		||||
 | 
			
		||||
	if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) {
 | 
			
		||||
		for _, v := range r.TeamIDs {
 | 
			
		||||
			team, err := GetTeamByID(v)
 | 
			
		||||
			team, err := organization.GetTeamByID(v)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
@@ -87,7 +88,7 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool {
 | 
			
		||||
		return r.RecipientID == u.ID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	allowed, err := CanCreateOrgRepo(r.RecipientID, u.ID)
 | 
			
		||||
	allowed, err := organization.CanCreateOrgRepo(r.RecipientID, u.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("CanCreateOrgRepo: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
@@ -152,7 +153,7 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
 | 
			
		||||
 | 
			
		||||
// CreatePendingRepositoryTransfer transfer a repo from one owner to a new one.
 | 
			
		||||
// it marks the repository transfer as "pending"
 | 
			
		||||
func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int64, teams []*Team) error {
 | 
			
		||||
func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -296,7 +297,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c.ID != newOwner.ID {
 | 
			
		||||
			isMember, err := isOrganizationMember(sess, newOwner.ID, c.ID)
 | 
			
		||||
			isMember, err := organization.IsOrganizationMember(ctx, newOwner.ID, c.ID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("IsOrgMember: %v", err)
 | 
			
		||||
			} else if !isMember {
 | 
			
		||||
@@ -312,19 +313,19 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
 | 
			
		||||
 | 
			
		||||
	// Remove old team-repository relations.
 | 
			
		||||
	if oldOwner.IsOrganization() {
 | 
			
		||||
		if err := OrgFromUser(oldOwner).removeOrgRepo(sess, repo.ID); err != nil {
 | 
			
		||||
		if err := organization.RemoveOrgRepo(ctx, oldOwner.ID, repo.ID); err != nil {
 | 
			
		||||
			return fmt.Errorf("removeOrgRepo: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if newOwner.IsOrganization() {
 | 
			
		||||
		teams, err := OrgFromUser(newOwner).loadTeams(sess)
 | 
			
		||||
		teams, err := organization.FindOrgTeams(ctx, newOwner.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("LoadTeams: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, t := range teams {
 | 
			
		||||
			if t.IncludesAllRepositories {
 | 
			
		||||
				if err := t.addRepository(ctx, repo); err != nil {
 | 
			
		||||
				if err := addRepository(ctx, t, repo); err != nil {
 | 
			
		||||
					return fmt.Errorf("addRepository: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -58,10 +59,10 @@ func (rt ReviewType) Icon() string {
 | 
			
		||||
type Review struct {
 | 
			
		||||
	ID               int64 `xorm:"pk autoincr"`
 | 
			
		||||
	Type             ReviewType
 | 
			
		||||
	Reviewer         *user_model.User `xorm:"-"`
 | 
			
		||||
	ReviewerID       int64            `xorm:"index"`
 | 
			
		||||
	ReviewerTeamID   int64            `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
	ReviewerTeam     *Team            `xorm:"-"`
 | 
			
		||||
	Reviewer         *user_model.User   `xorm:"-"`
 | 
			
		||||
	ReviewerID       int64              `xorm:"index"`
 | 
			
		||||
	ReviewerTeamID   int64              `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
	ReviewerTeam     *organization.Team `xorm:"-"`
 | 
			
		||||
	OriginalAuthor   string
 | 
			
		||||
	OriginalAuthorID int64
 | 
			
		||||
	Issue            *Issue `xorm:"-"`
 | 
			
		||||
@@ -114,12 +115,12 @@ func (r *Review) loadReviewer(e db.Engine) (err error) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Review) loadReviewerTeam(e db.Engine) (err error) {
 | 
			
		||||
func (r *Review) loadReviewerTeam(ctx context.Context) (err error) {
 | 
			
		||||
	if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r.ReviewerTeam, err = getTeamByID(e, r.ReviewerTeamID)
 | 
			
		||||
	r.ReviewerTeam, err = organization.GetTeamByIDCtx(ctx, r.ReviewerTeamID)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -130,7 +131,7 @@ func (r *Review) LoadReviewer() error {
 | 
			
		||||
 | 
			
		||||
// LoadReviewerTeam loads reviewer team
 | 
			
		||||
func (r *Review) LoadReviewerTeam() error {
 | 
			
		||||
	return r.loadReviewerTeam(db.GetEngine(db.DefaultContext))
 | 
			
		||||
	return r.loadReviewerTeam(db.DefaultContext)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadAttributes loads all attributes except CodeComments
 | 
			
		||||
@@ -145,7 +146,7 @@ func (r *Review) LoadAttributes(ctx context.Context) (err error) {
 | 
			
		||||
	if err = r.loadReviewer(e); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err = r.loadReviewerTeam(e); err != nil {
 | 
			
		||||
	if err = r.loadReviewerTeam(ctx); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
@@ -221,7 +222,7 @@ type CreateReviewOptions struct {
 | 
			
		||||
	Type         ReviewType
 | 
			
		||||
	Issue        *Issue
 | 
			
		||||
	Reviewer     *user_model.User
 | 
			
		||||
	ReviewerTeam *Team
 | 
			
		||||
	ReviewerTeam *organization.Team
 | 
			
		||||
	Official     bool
 | 
			
		||||
	CommitID     string
 | 
			
		||||
	Stale        bool
 | 
			
		||||
@@ -255,11 +256,11 @@ func isOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsOfficialReviewerTeam check if reviewer in this team can make official reviews in issue (counts towards required approvals)
 | 
			
		||||
func IsOfficialReviewerTeam(issue *Issue, team *Team) (bool, error) {
 | 
			
		||||
func IsOfficialReviewerTeam(issue *Issue, team *organization.Team) (bool, error) {
 | 
			
		||||
	return isOfficialReviewerTeam(db.DefaultContext, issue, team)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *Team) (bool, error) {
 | 
			
		||||
func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organization.Team) (bool, error) {
 | 
			
		||||
	pr, err := getPullRequestByIssueID(db.GetEngine(ctx), issue.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
@@ -272,7 +273,7 @@ func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *Team) (bool
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !pr.ProtectedBranch.EnableApprovalsWhitelist {
 | 
			
		||||
		return team.UnitAccessMode(unit.TypeCode) >= perm.AccessModeWrite, nil
 | 
			
		||||
		return team.UnitAccessMode(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return base.Int64sContains(pr.ProtectedBranch.ApprovalsWhitelistTeamIDs, team.ID), nil
 | 
			
		||||
@@ -447,7 +448,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, teamReviewRequest := range teamReviewRequests {
 | 
			
		||||
			ok, err := isTeamMember(sess, issue.Repo.OwnerID, teamReviewRequest.ReviewerTeamID, doer.ID)
 | 
			
		||||
			ok, err := organization.IsTeamMember(ctx, issue.Repo.OwnerID, teamReviewRequest.ReviewerTeamID, doer.ID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, nil, err
 | 
			
		||||
			} else if !ok {
 | 
			
		||||
@@ -732,7 +733,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddTeamReviewRequest add a review request from one team
 | 
			
		||||
func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *user_model.User) (*Comment, error) {
 | 
			
		||||
func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
@@ -792,7 +793,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *user_model.User) (
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveTeamReviewRequest remove a review request from one team
 | 
			
		||||
func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *user_model.User) (*Comment, error) {
 | 
			
		||||
func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	asymkey_model "code.gitea.io/gitea/models/asymkey"
 | 
			
		||||
	"code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/models/webhook"
 | 
			
		||||
@@ -47,7 +48,7 @@ type IssueByRepositoryCount struct {
 | 
			
		||||
func GetStatistic() (stats Statistic) {
 | 
			
		||||
	e := db.GetEngine(db.DefaultContext)
 | 
			
		||||
	stats.Counter.User = user_model.CountUsers()
 | 
			
		||||
	stats.Counter.Org = CountOrganizations()
 | 
			
		||||
	stats.Counter.Org = organization.CountOrganizations()
 | 
			
		||||
	stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
 | 
			
		||||
	stats.Counter.Repo = repo_model.CountRepositories(true)
 | 
			
		||||
	stats.Counter.Watch, _ = e.Count(new(repo_model.Watch))
 | 
			
		||||
@@ -103,7 +104,7 @@ func GetStatistic() (stats Statistic) {
 | 
			
		||||
	stats.Counter.Milestone, _ = e.Count(new(Milestone))
 | 
			
		||||
	stats.Counter.Label, _ = e.Count(new(Label))
 | 
			
		||||
	stats.Counter.HookTask, _ = e.Count(new(webhook.HookTask))
 | 
			
		||||
	stats.Counter.Team, _ = e.Count(new(Team))
 | 
			
		||||
	stats.Counter.Team, _ = e.Count(new(organization.Team))
 | 
			
		||||
	stats.Counter.Attachment, _ = e.Count(new(repo_model.Attachment))
 | 
			
		||||
	stats.Counter.Project, _ = e.Count(new(Project))
 | 
			
		||||
	stats.Counter.ProjectBoard, _ = e.Count(new(ProjectBoard))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								models/user.go
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								models/user.go
									
									
									
									
									
								
							@@ -14,22 +14,13 @@ import (
 | 
			
		||||
 | 
			
		||||
	asymkey_model "code.gitea.io/gitea/models/asymkey"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetOrganizationCount returns count of membership of organization of the user.
 | 
			
		||||
func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) {
 | 
			
		||||
	return db.GetEngine(ctx).
 | 
			
		||||
		Where("uid=?", u.ID).
 | 
			
		||||
		Count(new(OrgUser))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteUser deletes models associated to an user.
 | 
			
		||||
func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
@@ -86,7 +77,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
 | 
			
		||||
		&user_model.EmailAddress{UID: u.ID},
 | 
			
		||||
		&user_model.UserOpenID{UID: u.ID},
 | 
			
		||||
		&Reaction{UserID: u.ID},
 | 
			
		||||
		&TeamUser{UID: u.ID},
 | 
			
		||||
		&organization.TeamUser{UID: u.ID},
 | 
			
		||||
		&Collaboration{UserID: u.ID},
 | 
			
		||||
		&Stopwatch{UserID: u.ID},
 | 
			
		||||
		&user_model.Setting{UserID: u.ID},
 | 
			
		||||
@@ -204,100 +195,3 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetStarredRepos returns the repos starred by a particular user
 | 
			
		||||
func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]*repo_model.Repository, error) {
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).Where("star.uid=?", userID).
 | 
			
		||||
		Join("LEFT", "star", "`repository`.id=`star`.repo_id")
 | 
			
		||||
	if !private {
 | 
			
		||||
		sess = sess.And("is_private=?", false)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if listOptions.Page != 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, &listOptions)
 | 
			
		||||
 | 
			
		||||
		repos := make([]*repo_model.Repository, 0, listOptions.PageSize)
 | 
			
		||||
		return repos, sess.Find(&repos)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*repo_model.Repository, 0, 10)
 | 
			
		||||
	return repos, sess.Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetWatchedRepos returns the repos watched by a particular user
 | 
			
		||||
func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]*repo_model.Repository, int64, error) {
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).Where("watch.user_id=?", userID).
 | 
			
		||||
		And("`watch`.mode<>?", repo_model.WatchModeDont).
 | 
			
		||||
		Join("LEFT", "watch", "`repository`.id=`watch`.repo_id")
 | 
			
		||||
	if !private {
 | 
			
		||||
		sess = sess.And("is_private=?", false)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if listOptions.Page != 0 {
 | 
			
		||||
		sess = db.SetSessionPagination(sess, &listOptions)
 | 
			
		||||
 | 
			
		||||
		repos := make([]*repo_model.Repository, 0, listOptions.PageSize)
 | 
			
		||||
		total, err := sess.FindAndCount(&repos)
 | 
			
		||||
		return repos, total, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos := make([]*repo_model.Repository, 0, 10)
 | 
			
		||||
	total, err := sess.FindAndCount(&repos)
 | 
			
		||||
	return repos, total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUserVisibleToViewer check if viewer is able to see user profile
 | 
			
		||||
func IsUserVisibleToViewer(u, viewer *user_model.User) bool {
 | 
			
		||||
	return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isUserVisibleToViewer(e db.Engine, u, viewer *user_model.User) bool {
 | 
			
		||||
	if viewer != nil && viewer.IsAdmin {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch u.Visibility {
 | 
			
		||||
	case structs.VisibleTypePublic:
 | 
			
		||||
		return true
 | 
			
		||||
	case structs.VisibleTypeLimited:
 | 
			
		||||
		if viewer == nil || viewer.IsRestricted {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	case structs.VisibleTypePrivate:
 | 
			
		||||
		if viewer == nil || viewer.IsRestricted {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If they follow - they see each over
 | 
			
		||||
		follower := user_model.IsFollowing(u.ID, viewer.ID)
 | 
			
		||||
		if follower {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Now we need to check if they in some organization together
 | 
			
		||||
		count, err := e.Table("team_user").
 | 
			
		||||
			Where(
 | 
			
		||||
				builder.And(
 | 
			
		||||
					builder.Eq{"uid": viewer.ID},
 | 
			
		||||
					builder.Or(
 | 
			
		||||
						builder.Eq{"org_id": u.ID},
 | 
			
		||||
						builder.In("org_id",
 | 
			
		||||
							builder.Select("org_id").
 | 
			
		||||
								From("team_user", "t2").
 | 
			
		||||
								Where(builder.Eq{"uid": u.ID}))))).
 | 
			
		||||
			Count(new(TeamUser))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if count < 0 {
 | 
			
		||||
			// No common organization
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// they are in an organization together
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1211,3 +1211,59 @@ func GetAdminUser() (*User, error) {
 | 
			
		||||
 | 
			
		||||
	return &admin, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUserVisibleToViewer check if viewer is able to see user profile
 | 
			
		||||
func IsUserVisibleToViewer(u, viewer *User) bool {
 | 
			
		||||
	return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isUserVisibleToViewer(e db.Engine, u, viewer *User) bool {
 | 
			
		||||
	if viewer != nil && viewer.IsAdmin {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch u.Visibility {
 | 
			
		||||
	case structs.VisibleTypePublic:
 | 
			
		||||
		return true
 | 
			
		||||
	case structs.VisibleTypeLimited:
 | 
			
		||||
		if viewer == nil || viewer.IsRestricted {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	case structs.VisibleTypePrivate:
 | 
			
		||||
		if viewer == nil || viewer.IsRestricted {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If they follow - they see each over
 | 
			
		||||
		follower := IsFollowing(u.ID, viewer.ID)
 | 
			
		||||
		if follower {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Now we need to check if they in some organization together
 | 
			
		||||
		count, err := e.Table("team_user").
 | 
			
		||||
			Where(
 | 
			
		||||
				builder.And(
 | 
			
		||||
					builder.Eq{"uid": viewer.ID},
 | 
			
		||||
					builder.Or(
 | 
			
		||||
						builder.Eq{"org_id": u.ID},
 | 
			
		||||
						builder.In("org_id",
 | 
			
		||||
							builder.Select("org_id").
 | 
			
		||||
								From("team_user", "t2").
 | 
			
		||||
								Where(builder.Eq{"uid": u.ID}))))).
 | 
			
		||||
			Count()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if count < 0 {
 | 
			
		||||
			// No common organization
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// they are in an organization together
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
@@ -23,11 +24,11 @@ func GetUserHeatmapDataByUser(user, doer *user_model.User) ([]*UserHeatmapData,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
 | 
			
		||||
func GetUserHeatmapDataByUserTeam(user *user_model.User, team *Team, doer *user_model.User) ([]*UserHeatmapData, error) {
 | 
			
		||||
func GetUserHeatmapDataByUserTeam(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
 | 
			
		||||
	return getUserHeatmapData(user, team, doer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getUserHeatmapData(user *user_model.User, team *Team, doer *user_model.User) ([]*UserHeatmapData, error) {
 | 
			
		||||
func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
 | 
			
		||||
	hdata := make([]*UserHeatmapData, 0)
 | 
			
		||||
 | 
			
		||||
	if !activityReadable(user, doer) {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
@@ -42,59 +41,3 @@ func TestUnfollowUser(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &user_model.User{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUserIsPublicMember(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	tt := []struct {
 | 
			
		||||
		uid      int64
 | 
			
		||||
		orgid    int64
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{2, 3, true},
 | 
			
		||||
		{4, 3, false},
 | 
			
		||||
		{5, 6, true},
 | 
			
		||||
		{5, 7, false},
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range tt {
 | 
			
		||||
		t.Run(fmt.Sprintf("UserId%dIsPublicMemberOf%d", v.uid, v.orgid), func(t *testing.T) {
 | 
			
		||||
			testUserIsPublicMember(t, v.uid, v.orgid, v.expected)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
 | 
			
		||||
	user, err := user_model.GetUserByID(uid)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	is, err := IsPublicMembership(orgID, user.ID)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, expected, is)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsUserOrgOwner(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	tt := []struct {
 | 
			
		||||
		uid      int64
 | 
			
		||||
		orgid    int64
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{2, 3, true},
 | 
			
		||||
		{4, 3, false},
 | 
			
		||||
		{5, 6, true},
 | 
			
		||||
		{5, 7, true},
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range tt {
 | 
			
		||||
		t.Run(fmt.Sprintf("UserId%dIsOrgOwnerOf%d", v.uid, v.orgid), func(t *testing.T) {
 | 
			
		||||
			testIsUserOrgOwner(t, v.uid, v.orgid, v.expected)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
 | 
			
		||||
	user, err := user_model.GetUserByID(uid)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	is, err := IsOrganizationOwner(orgID, user.ID)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, expected, is)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,11 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
)
 | 
			
		||||
@@ -18,7 +20,7 @@ func IsUserOrgOwner(users user_model.UserList, orgID int64) map[int64]bool {
 | 
			
		||||
	for _, user := range users {
 | 
			
		||||
		results[user.ID] = false // Set default to false
 | 
			
		||||
	}
 | 
			
		||||
	ownerMaps, err := loadOrganizationOwners(db.GetEngine(db.DefaultContext), users, orgID)
 | 
			
		||||
	ownerMaps, err := loadOrganizationOwners(db.DefaultContext, users, orgID)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		for _, owner := range ownerMaps {
 | 
			
		||||
			results[owner.UID] = true
 | 
			
		||||
@@ -27,13 +29,13 @@ func IsUserOrgOwner(users user_model.UserList, orgID int64) map[int64]bool {
 | 
			
		||||
	return results
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func loadOrganizationOwners(e db.Engine, users user_model.UserList, orgID int64) (map[int64]*TeamUser, error) {
 | 
			
		||||
func loadOrganizationOwners(ctx context.Context, users user_model.UserList, orgID int64) (map[int64]*organization.TeamUser, error) {
 | 
			
		||||
	if len(users) == 0 {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	ownerTeam, err := getOwnerTeam(e, orgID)
 | 
			
		||||
	ownerTeam, err := organization.GetOwnerTeam(ctx, orgID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if IsErrTeamNotExist(err) {
 | 
			
		||||
		if organization.IsErrTeamNotExist(err) {
 | 
			
		||||
			log.Error("Organization does not have owner team: %d", orgID)
 | 
			
		||||
			return nil, nil
 | 
			
		||||
		}
 | 
			
		||||
@@ -41,8 +43,8 @@ func loadOrganizationOwners(e db.Engine, users user_model.UserList, orgID int64)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	userIDs := users.GetUserIDs()
 | 
			
		||||
	ownerMaps := make(map[int64]*TeamUser)
 | 
			
		||||
	err = e.In("uid", userIDs).
 | 
			
		||||
	ownerMaps := make(map[int64]*organization.TeamUser)
 | 
			
		||||
	err = db.GetEngine(ctx).In("uid", userIDs).
 | 
			
		||||
		And("org_id=?", orgID).
 | 
			
		||||
		And("team_id=?", ownerTeam.ID).
 | 
			
		||||
		Find(&ownerMaps)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -33,7 +34,7 @@ func TestUserListIsPublicMember(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) {
 | 
			
		||||
	org, err := GetOrgByID(orgID)
 | 
			
		||||
	org, err := organization.GetOrgByID(orgID)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	_, membersIsPublic, err := org.GetMembers()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
@@ -60,7 +61,7 @@ func TestUserListIsUserOrgOwner(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) {
 | 
			
		||||
	org, err := GetOrgByID(orgID)
 | 
			
		||||
	org, err := organization.GetOrgByID(orgID)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	members, _, err := org.GetMembers()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user