aboutsummaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2022-03-29 14:29:02 +0800
committerGitHub <noreply@github.com>2022-03-29 14:29:02 +0800
commitb06b9a056c0af751e576978f6ef3c914ee959b9c (patch)
treeaa0d11413038baa5d47af65fd435665c698fe456 /models
parentd4c789dfc1c341413b77a2f21fe7339982102bed (diff)
downloadgitea-b06b9a056c0af751e576978f6ef3c914ee959b9c.tar.gz
gitea-b06b9a056c0af751e576978f6ef3c914ee959b9c.zip
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>
Diffstat (limited to 'models')
-rw-r--r--models/access.go9
-rw-r--r--models/access_test.go3
-rw-r--r--models/action.go5
-rw-r--r--models/branches.go9
-rw-r--r--models/error.go91
-rw-r--r--models/fixtures/team.yml11
-rw-r--r--models/issue.go17
-rw-r--r--models/issue_comment.go11
-rw-r--r--models/main_test.go3
-rw-r--r--models/notification.go3
-rw-r--r--models/org.go913
-rw-r--r--models/org_team.go712
-rw-r--r--models/org_team_test.go278
-rw-r--r--models/org_test.go610
-rw-r--r--models/organization/main_test.go24
-rw-r--r--models/organization/org.go859
-rw-r--r--models/organization/org_test.go478
-rw-r--r--models/organization/org_user.go83
-rw-r--r--models/organization/org_user_test.go72
-rw-r--r--models/organization/team.go359
-rw-r--r--models/organization/team_repo.go84
-rw-r--r--models/organization/team_test.go199
-rw-r--r--models/organization/team_unit.go52
-rw-r--r--models/organization/team_user.go109
-rw-r--r--models/protected_tag.go3
-rw-r--r--models/repo.go23
-rw-r--r--models/repo/repo.go34
-rw-r--r--models/repo/user_repo.go87
-rw-r--r--models/repo_collaboration.go17
-rw-r--r--models/repo_permission.go14
-rw-r--r--models/repo_permission_test.go5
-rw-r--r--models/repo_transfer.go17
-rw-r--r--models/review.go31
-rw-r--r--models/statistic.go5
-rw-r--r--models/user.go110
-rw-r--r--models/user/user.go56
-rw-r--r--models/user_heatmap.go5
-rw-r--r--models/user_test.go57
-rw-r--r--models/userlist.go14
-rw-r--r--models/userlist_test.go5
40 files changed, 2772 insertions, 2705 deletions
diff --git a/models/access.go b/models/access.go
index 48b65c2c0f..d49d3430dc 100644
--- a/models/access.go
+++ b/models/access.go
@@ -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).
diff --git a/models/access_test.go b/models/access_test.go
index 43e61e812b..7533381dca 100644
--- a/models/access_test.go
+++ b/models/access_test.go
@@ -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})
diff --git a/models/action.go b/models/action.go
index e9f5138b40..d3231641d9 100644
--- a/models/action.go
+++ b/models/action.go
@@ -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)
diff --git a/models/branches.go b/models/branches.go
index e6d8b7441a..8156fd0908 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -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)
}
diff --git a/models/error.go b/models/error.go
index f0e8751d75..3c4d219775 100644
--- a/models/error.go
+++ b/models/error.go
@@ -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)
-}
-
// ____ ___ .__ .___
// | | \______ | | _________ __| _/
// | | /\____ \| | / _ \__ \ / __ |
diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml
index 9a8b0aff76..f6dfd1e9d0 100644
--- a/models/fixtures/team.yml
+++ b/models/fixtures/team.yml
@@ -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
diff --git a/models/issue.go b/models/issue.go
index 79771ce15c..31f7a0edb0 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -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)
}
diff --git a/models/issue_comment.go b/models/issue_comment.go
index 8390d90f8a..7927b0037b 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -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
}
}
diff --git a/models/main_test.go b/models/main_test.go
index 8d5291a8aa..08cb2386c0 100644
--- a/models/main_test.go
+++ b/models/main_test.go
@@ -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{})
}
diff --git a/models/notification.go b/models/notification.go
index b53d236e43..b5217777bf 100644
--- a/models/notification.go
+++ b/models/notification.go
@@ -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
}
diff --git a/models/org.go b/models/org.go
index 70b3fe27b9..1e5b403f12 100644
--- a/models/org.go
+++ b/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
-}
diff --git a/models/org_team.go b/models/org_team.go
index faee23f4f8..cf810cad33 100644
--- a/models/org_team.go
+++ b/models/org_team.go
@@ -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()
-}
diff --git a/models/org_team_test.go b/models/org_team_test.go
index cf3a797991..e125f3c65b 100644
--- a/models/org_team_test.go
+++ b/models/org_team_test.go
@@ -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))
}
diff --git a/models/org_test.go b/models/org_test.go
index ec324cb71a..4d8831858c 100644
--- a/models/org_test.go
+++ b/models/org_test.go
@@ -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{})
}
diff --git a/models/organization/main_test.go b/models/organization/main_test.go
new file mode 100644
index 0000000000..a2cb911021
--- /dev/null
+++ b/models/organization/main_test.go
@@ -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",
+ )
+}
diff --git a/models/organization/org.go b/models/organization/org.go
new file mode 100644
index 0000000000..9e71bbe80d
--- /dev/null
+++ b/models/organization/org.go
@@ -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
+}
diff --git a/models/organization/org_test.go b/models/organization/org_test.go
new file mode 100644
index 0000000000..71cdbd869f
--- /dev/null
+++ b/models/organization/org_test.go
@@ -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)
+}
diff --git a/models/organization/org_user.go b/models/organization/org_user.go
new file mode 100644
index 0000000000..b679246d0b
--- /dev/null
+++ b/models/organization/org_user.go
@@ -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))
+}
diff --git a/models/organization/org_user_test.go b/models/organization/org_user_test.go
new file mode 100644
index 0000000000..b323002934
--- /dev/null
+++ b/models/organization/org_user_test.go
@@ -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)
+}
diff --git a/models/organization/team.go b/models/organization/team.go
new file mode 100644
index 0000000000..1617005841
--- /dev/null
+++ b/models/organization/team.go
@@ -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)
+}
diff --git a/models/organization/team_repo.go b/models/organization/team_repo.go
new file mode 100644
index 0000000000..e6ac751829
--- /dev/null
+++ b/models/organization/team_repo.go
@@ -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)
+}
diff --git a/models/organization/team_test.go b/models/organization/team_test.go
new file mode 100644
index 0000000000..bbf9f789f6
--- /dev/null
+++ b/models/organization/team_test.go
@@ -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
+}
diff --git a/models/organization/team_unit.go b/models/organization/team_unit.go
new file mode 100644
index 0000000000..a712ddb2eb
--- /dev/null
+++ b/models/organization/team_unit.go
@@ -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()
+}
diff --git a/models/organization/team_user.go b/models/organization/team_user.go
new file mode 100644
index 0000000000..e972817f49
--- /dev/null
+++ b/models/organization/team_user.go
@@ -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
+}
diff --git a/models/protected_tag.go b/models/protected_tag.go
index c9cc0fa1ba..db6ff50462 100644
--- a/models/protected_tag.go
+++ b/models/protected_tag.go
@@ -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
}
diff --git a/models/repo.go b/models/repo.go
index d20e5f81d3..8e6f777f9b 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -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 {
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 8cd055c67b..8dd772a4ec 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -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)
-}
diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go
new file mode 100644
index 0000000000..18a04f7267
--- /dev/null
+++ b/models/repo/user_repo.go
@@ -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)
+}
diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go
index 3aca1023e6..d94b61b449 100644
--- a/models/repo_collaboration.go
+++ b/models/repo_collaboration.go
@@ -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
}
diff --git a/models/repo_permission.go b/models/repo_permission.go
index 4e5cbfd558..4dfc63d4e1 100644
--- a/models/repo_permission.go
+++ b/models/repo_permission.go
@@ -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
}
diff --git a/models/repo_permission_test.go b/models/repo_permission_test.go
index f2664d8101..c103a9363f 100644
--- a/models/repo_permission_test.go
+++ b/models/repo_permission_test.go
@@ -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)
diff --git a/models/repo_transfer.go b/models/repo_transfer.go
index f7d5e20990..f9a758a20b 100644
--- a/models/repo_transfer.go
+++ b/models/repo_transfer.go
@@ -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)
}
}
diff --git a/models/review.go b/models/review.go
index 22c47486a1..6ef8d530b6 100644
--- a/models/review.go
+++ b/models/review.go
@@ -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
diff --git a/models/statistic.go b/models/statistic.go
index dfe543d063..67be4c5d42 100644
--- a/models/statistic.go
+++ b/models/statistic.go
@@ -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))
diff --git a/models/user.go b/models/user.go
index 1dbc025155..7744222809 100644
--- a/models/user.go
+++ b/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
-}
diff --git a/models/user/user.go b/models/user/user.go
index a3094a13ce..0e51cf955c 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -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
+}
diff --git a/models/user_heatmap.go b/models/user_heatmap.go
index f331a0c16b..e908837ae8 100644
--- a/models/user_heatmap.go
+++ b/models/user_heatmap.go
@@ -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) {
diff --git a/models/user_test.go b/models/user_test.go
index 83201ff4cb..bf6f71895e 100644
--- a/models/user_test.go
+++ b/models/user_test.go
@@ -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)
-}
diff --git a/models/userlist.go b/models/userlist.go
index 102c587dfe..fbe1995b40 100644
--- a/models/userlist.go
+++ b/models/userlist.go
@@ -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)
diff --git a/models/userlist_test.go b/models/userlist_test.go
index 6776850b60..9b3c796e64 100644
--- a/models/userlist_test.go
+++ b/models/userlist_test.go
@@ -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)