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>
tokarchuk/v1.17
Lunny Xiao 3 years ago committed by GitHub
parent d4c789dfc1
commit b06b9a056c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      integrations/api_repo_teams_test.go
  2. 18
      integrations/api_team_test.go
  3. 34
      integrations/auth_ldap_test.go
  4. 5
      integrations/delete_user_test.go
  5. 4
      integrations/org_count_test.go
  6. 9
      models/access.go
  7. 3
      models/access_test.go
  8. 5
      models/action.go
  9. 9
      models/branches.go
  10. 91
      models/error.go
  11. 11
      models/fixtures/team.yml
  12. 15
      models/issue.go
  13. 7
      models/issue_comment.go
  14. 3
      models/main_test.go
  15. 3
      models/notification.go
  16. 911
      models/org.go
  17. 712
      models/org_team.go
  18. 278
      models/org_team_test.go
  19. 610
      models/org_test.go
  20. 24
      models/organization/main_test.go
  21. 859
      models/organization/org.go
  22. 478
      models/organization/org_test.go
  23. 83
      models/organization/org_user.go
  24. 72
      models/organization/org_user_test.go
  25. 359
      models/organization/team.go
  26. 84
      models/organization/team_repo.go
  27. 199
      models/organization/team_test.go
  28. 52
      models/organization/team_unit.go
  29. 109
      models/organization/team_user.go
  30. 3
      models/protected_tag.go
  31. 23
      models/repo.go
  32. 34
      models/repo/repo.go
  33. 87
      models/repo/user_repo.go
  34. 17
      models/repo_collaboration.go
  35. 14
      models/repo_permission.go
  36. 5
      models/repo_permission_test.go
  37. 17
      models/repo_transfer.go
  38. 25
      models/review.go
  39. 5
      models/statistic.go
  40. 110
      models/user.go
  41. 56
      models/user/user.go
  42. 5
      models/user_heatmap.go
  43. 57
      models/user_test.go
  44. 14
      models/userlist.go
  45. 5
      models/userlist_test.go
  46. 8
      modules/context/api_org.go
  47. 14
      modules/context/org.go
  48. 13
      modules/convert/convert.go
  49. 15
      modules/repository/create_test.go
  50. 3
      modules/repository/repo.go
  51. 3
      modules/templates/helper.go
  52. 8
      routers/api/v1/admin/org.go
  53. 19
      routers/api/v1/api.go
  54. 17
      routers/api/v1/org/member.go
  55. 20
      routers/api/v1/org/org.go
  56. 60
      routers/api/v1/org/team.go
  57. 25
      routers/api/v1/repo/branch.go
  58. 5
      routers/api/v1/repo/fork.go
  59. 5
      routers/api/v1/repo/issue.go
  60. 3
      routers/api/v1/repo/migrate.go
  61. 9
      routers/api/v1/repo/pull_review.go
  62. 9
      routers/api/v1/repo/repo.go
  63. 17
      routers/api/v1/repo/teams.go
  64. 9
      routers/api/v1/repo/transfer.go
  65. 2
      routers/api/v1/user/star.go
  66. 2
      routers/api/v1/user/user.go
  67. 2
      routers/api/v1/user/watch.go
  68. 9
      routers/web/org/home.go
  69. 19
      routers/web/org/members.go
  70. 8
      routers/web/org/org.go
  71. 49
      routers/web/org/teams.go
  72. 15
      routers/web/repo/issue.go
  73. 3
      routers/web/repo/issue_label.go
  74. 7
      routers/web/repo/pull.go
  75. 7
      routers/web/repo/repo.go
  76. 17
      routers/web/repo/setting.go
  77. 3
      routers/web/repo/setting_protected_branch.go
  78. 17
      routers/web/repo/settings_test.go
  79. 3
      routers/web/repo/tag.go
  80. 13
      routers/web/user/home.go
  81. 7
      routers/web/user/profile.go
  82. 7
      routers/web/user/setting/profile.go
  83. 10
      services/auth/source/ldap/source_authenticate.go
  84. 27
      services/auth/source/ldap/source_group_sync.go
  85. 6
      services/auth/source/ldap/source_sync.go
  86. 15
      services/issue/assignee.go
  87. 5
      services/mailer/mail_repo.go
  88. 5
      services/org/org.go
  89. 15
      services/org/org_test.go
  90. 3
      services/repository/repository.go
  91. 9
      services/repository/transfer.go
  92. 5
      services/repository/transfer_test.go
  93. 3
      services/user/user.go
  94. 7
      services/user/user_test.go

@ -37,7 +37,7 @@ func TestAPIRepoTeams(t *testing.T) {
DecodeJSON(t, res, &teams) DecodeJSON(t, res, &teams)
if assert.Len(t, teams, 2) { if assert.Len(t, teams, 2) {
assert.EqualValues(t, "Owners", teams[0].Name) assert.EqualValues(t, "Owners", teams[0].Name)
assert.False(t, teams[0].CanCreateOrgRepo) assert.True(t, teams[0].CanCreateOrgRepo)
assert.True(t, util.IsEqualSlice(unit.AllUnitKeyNames(), teams[0].Units), fmt.Sprintf("%v == %v", unit.AllUnitKeyNames(), teams[0].Units)) assert.True(t, util.IsEqualSlice(unit.AllUnitKeyNames(), teams[0].Units), fmt.Sprintf("%v == %v", unit.AllUnitKeyNames(), teams[0].Units))
assert.EqualValues(t, "owner", teams[0].Permission) assert.EqualValues(t, "owner", teams[0].Permission)

@ -10,7 +10,7 @@ import (
"sort" "sort"
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -23,8 +23,8 @@ import (
func TestAPITeam(t *testing.T) { func TestAPITeam(t *testing.T) {
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
teamUser := unittest.AssertExistsAndLoadBean(t, &models.TeamUser{}).(*models.TeamUser) teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{}).(*organization.TeamUser)
team := unittest.AssertExistsAndLoadBean(t, &models.Team{ID: teamUser.TeamID}).(*models.Team) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID}).(*organization.Team)
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID}).(*user_model.User) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID}).(*user_model.User)
session := loginUser(t, user.Name) session := loginUser(t, user.Name)
@ -38,7 +38,7 @@ func TestAPITeam(t *testing.T) {
assert.Equal(t, team.Name, apiTeam.Name) assert.Equal(t, team.Name, apiTeam.Name)
// non team member user will not access the teams details // non team member user will not access the teams details
teamUser2 := unittest.AssertExistsAndLoadBean(t, &models.TeamUser{ID: 3}).(*models.TeamUser) teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3}).(*organization.TeamUser)
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID}).(*user_model.User) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID}).(*user_model.User)
session = loginUser(t, user2.Name) session = loginUser(t, user2.Name)
@ -107,7 +107,7 @@ func TestAPITeam(t *testing.T) {
teamToEdit.Permission, unit.AllUnitKeyNames(), nil) teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
// Read team. // Read team.
teamRead := unittest.AssertExistsAndLoadBean(t, &models.Team{ID: teamID}).(*models.Team) teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
assert.NoError(t, teamRead.GetUnits()) assert.NoError(t, teamRead.GetUnits())
req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID) req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID)
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
@ -119,7 +119,7 @@ func TestAPITeam(t *testing.T) {
// Delete team. // Delete team.
req = NewRequestf(t, "DELETE", "/api/v1/teams/%d?token="+token, teamID) req = NewRequestf(t, "DELETE", "/api/v1/teams/%d?token="+token, teamID)
session.MakeRequest(t, req, http.StatusNoContent) session.MakeRequest(t, req, http.StatusNoContent)
unittest.AssertNotExistsBean(t, &models.Team{ID: teamID}) unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
// create team again via UnitsMap // create team again via UnitsMap
// Create team. // Create team.
@ -173,7 +173,7 @@ func TestAPITeam(t *testing.T) {
"read", nil, teamToEdit.UnitsMap) "read", nil, teamToEdit.UnitsMap)
// Read team. // Read team.
teamRead = unittest.AssertExistsAndLoadBean(t, &models.Team{ID: teamID}).(*models.Team) teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID) req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID)
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
apiTeam = api.Team{} apiTeam = api.Team{}
@ -185,7 +185,7 @@ func TestAPITeam(t *testing.T) {
// Delete team. // Delete team.
req = NewRequestf(t, "DELETE", "/api/v1/teams/%d?token="+token, teamID) req = NewRequestf(t, "DELETE", "/api/v1/teams/%d?token="+token, teamID)
session.MakeRequest(t, req, http.StatusNoContent) session.MakeRequest(t, req, http.StatusNoContent)
unittest.AssertNotExistsBean(t, &models.Team{ID: teamID}) unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
} }
func checkTeamResponse(t *testing.T, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) { func checkTeamResponse(t *testing.T, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
@ -206,7 +206,7 @@ func checkTeamResponse(t *testing.T, apiTeam *api.Team, name, description string
} }
func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) { func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
team := unittest.AssertExistsAndLoadBean(t, &models.Team{ID: id}).(*models.Team) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id}).(*organization.Team)
assert.NoError(t, team.GetUnits(), "GetUnits") assert.NoError(t, team.GetUnits(), "GetUnits")
checkTeamResponse(t, convert.ToTeam(team), name, description, includesAllRepositories, permission, units, unitsMap) checkTeamResponse(t, convert.ToTeam(team), name, description, includesAllRepositories, permission, units, unitsMap)
} }

@ -12,6 +12,8 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/auth"
@ -317,37 +319,37 @@ func TestLDAPGroupTeamSyncAddMember(t *testing.T) {
} }
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
addAuthSourceLDAP(t, "", "on", `{"cn=ship_crew,ou=people,dc=planetexpress,dc=com":{"org26": ["team11"]},"cn=admin_staff,ou=people,dc=planetexpress,dc=com": {"non-existent": ["non-existent"]}}`) addAuthSourceLDAP(t, "", "on", `{"cn=ship_crew,ou=people,dc=planetexpress,dc=com":{"org26": ["team11"]},"cn=admin_staff,ou=people,dc=planetexpress,dc=com": {"non-existent": ["non-existent"]}}`)
org, err := models.GetOrgByName("org26") org, err := organization.GetOrgByName("org26")
assert.NoError(t, err) assert.NoError(t, err)
team, err := models.GetTeam(org.ID, "team11") team, err := organization.GetTeam(org.ID, "team11")
assert.NoError(t, err) assert.NoError(t, err)
auth.SyncExternalUsers(context.Background(), true) auth.SyncExternalUsers(context.Background(), true)
for _, gitLDAPUser := range gitLDAPUsers { for _, gitLDAPUser := range gitLDAPUsers {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{
Name: gitLDAPUser.UserName, Name: gitLDAPUser.UserName,
}).(*user_model.User) }).(*user_model.User)
usersOrgs, err := models.FindOrgs(models.FindOrgOptions{ usersOrgs, err := organization.FindOrgs(organization.FindOrgOptions{
UserID: user.ID, UserID: user.ID,
IncludePrivate: true, IncludePrivate: true,
}) })
assert.NoError(t, err) assert.NoError(t, err)
allOrgTeams, err := models.GetUserOrgTeams(org.ID, user.ID) allOrgTeams, err := organization.GetUserOrgTeams(db.DefaultContext, org.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
if user.Name == "fry" || user.Name == "leela" || user.Name == "bender" { if user.Name == "fry" || user.Name == "leela" || user.Name == "bender" {
// assert members of LDAP group "cn=ship_crew" are added to mapped teams // assert members of LDAP group "cn=ship_crew" are added to mapped teams
assert.Equal(t, len(usersOrgs), 1, "User [%s] should be member of one organization", user.Name) assert.Equal(t, len(usersOrgs), 1, "User [%s] should be member of one organization", user.Name)
assert.Equal(t, usersOrgs[0].Name, "org26", "Membership should be added to the right organization") assert.Equal(t, usersOrgs[0].Name, "org26", "Membership should be added to the right organization")
isMember, err := models.IsTeamMember(usersOrgs[0].ID, team.ID, user.ID) isMember, err := organization.IsTeamMember(db.DefaultContext, usersOrgs[0].ID, team.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, isMember, "Membership should be added to the right team") assert.True(t, isMember, "Membership should be added to the right team")
err = team.RemoveMember(user.ID) err = models.RemoveTeamMember(team, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
err = usersOrgs[0].RemoveMember(user.ID) err = models.RemoveOrgUser(usersOrgs[0].ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
} else { } else {
// assert members of LDAP group "cn=admin_staff" keep initial team membership since mapped team does not exist // assert members of LDAP group "cn=admin_staff" keep initial team membership since mapped team does not exist
assert.Empty(t, usersOrgs, "User should be member of no organization") assert.Empty(t, usersOrgs, "User should be member of no organization")
isMember, err := models.IsTeamMember(org.ID, team.ID, user.ID) isMember, err := organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, isMember, "User should no be added to this team") assert.False(t, isMember, "User should no be added to this team")
assert.Empty(t, allOrgTeams, "User should not be added to any team") assert.Empty(t, allOrgTeams, "User should not be added to any team")
@ -362,30 +364,30 @@ func TestLDAPGroupTeamSyncRemoveMember(t *testing.T) {
} }
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
addAuthSourceLDAP(t, "", "on", `{"cn=dispatch,ou=people,dc=planetexpress,dc=com": {"org26": ["team11"]}}`) addAuthSourceLDAP(t, "", "on", `{"cn=dispatch,ou=people,dc=planetexpress,dc=com": {"org26": ["team11"]}}`)
org, err := models.GetOrgByName("org26") org, err := organization.GetOrgByName("org26")
assert.NoError(t, err) assert.NoError(t, err)
team, err := models.GetTeam(org.ID, "team11") team, err := organization.GetTeam(org.ID, "team11")
assert.NoError(t, err) assert.NoError(t, err)
loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password) loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password)
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{
Name: gitLDAPUsers[0].UserName, Name: gitLDAPUsers[0].UserName,
}).(*user_model.User) }).(*user_model.User)
err = org.AddMember(user.ID) err = organization.AddOrgUser(org.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
err = team.AddMember(user.ID) err = models.AddTeamMember(team, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
isMember, err := models.IsOrganizationMember(org.ID, user.ID) isMember, err := organization.IsOrganizationMember(db.DefaultContext, org.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, isMember, "User should be member of this organization") assert.True(t, isMember, "User should be member of this organization")
isMember, err = models.IsTeamMember(org.ID, team.ID, user.ID) isMember, err = organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, isMember, "User should be member of this team") assert.True(t, isMember, "User should be member of this team")
// assert team member "professor" gets removed from org26 team11 // assert team member "professor" gets removed from org26 team11
loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password) loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password)
isMember, err = models.IsOrganizationMember(org.ID, user.ID) isMember, err = organization.IsOrganizationMember(db.DefaultContext, org.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, isMember, "User membership should have been removed from organization") assert.False(t, isMember, "User membership should have been removed from organization")
isMember, err = models.IsTeamMember(org.ID, team.ID, user.ID) isMember, err = organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, isMember, "User membership should have been removed from team") assert.False(t, isMember, "User membership should have been removed from team")
} }

@ -10,6 +10,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -21,9 +22,9 @@ func assertUserDeleted(t *testing.T, userID int64) {
unittest.AssertNotExistsBean(t, &user_model.Follow{FollowID: userID}) unittest.AssertNotExistsBean(t, &user_model.Follow{FollowID: userID})
unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerID: userID}) unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerID: userID})
unittest.AssertNotExistsBean(t, &models.Access{UserID: userID}) unittest.AssertNotExistsBean(t, &models.Access{UserID: userID})
unittest.AssertNotExistsBean(t, &models.OrgUser{UID: userID}) unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: userID})
unittest.AssertNotExistsBean(t, &models.IssueUser{UID: userID}) unittest.AssertNotExistsBean(t, &models.IssueUser{UID: userID})
unittest.AssertNotExistsBean(t, &models.TeamUser{UID: userID}) unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID})
unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID}) unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID})
} }

@ -9,7 +9,7 @@ import (
"strings" "strings"
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
@ -117,7 +117,7 @@ func doCheckOrgCounts(username string, orgCounts map[string]int, strict bool, ca
Name: username, Name: username,
}).(*user_model.User) }).(*user_model.User)
orgs, err := models.FindOrgs(models.FindOrgOptions{ orgs, err := organization.FindOrgs(organization.FindOrgOptions{
UserID: user.ID, UserID: user.ID,
IncludePrivate: true, IncludePrivate: true,
}) })

@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" 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) return fmt.Errorf("refreshCollaboratorAccesses: %v", err)
} }
teams, err := OrgFromUser(repo.Owner).loadTeams(e) teams, err := organization.FindOrgTeams(ctx, repo.Owner.ID)
if err != nil { if err != nil {
return err return err
} }
@ -163,11 +164,11 @@ func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, i
// have relations with repository. // have relations with repository.
if t.IsOwnerTeam() { if t.IsOwnerTeam() {
t.AccessMode = perm.AccessModeOwner t.AccessMode = perm.AccessModeOwner
} else if !t.hasRepository(e, repo.ID) { } else if !hasRepository(ctx, t, repo.ID) {
continue continue
} }
if err = t.getMembers(e); err != nil { if err = t.GetMembersCtx(ctx); err != nil {
return fmt.Errorf("getMembers '%d': %v", t.ID, err) return fmt.Errorf("getMembers '%d': %v", t.ID, err)
} }
for _, m := range t.Members { 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 { if err = repo.GetOwner(ctx); err != nil {
return err return err
} else if repo.Owner.IsOrganization() { } 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"). if err := e.Join("INNER", "team_repo", "team_repo.team_id = team.id").
Join("INNER", "team_user", "team_user.team_id = team.id"). Join("INNER", "team_user", "team_user.team_id = team.id").
Where("team.org_id = ?", repo.OwnerID). Where("team.org_id = ?", repo.OwnerID).

@ -8,6 +8,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
@ -127,7 +128,7 @@ func TestRepository_RecalculateAccesses2(t *testing.T) {
func TestRepository_RecalculateAccesses3(t *testing.T) { func TestRepository_RecalculateAccesses3(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) 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) user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User)
has, err := db.GetEngine(db.DefaultContext).Get(&Access{UserID: 29, RepoID: 23}) has, err := db.GetEngine(db.DefaultContext).Get(&Access{UserID: 29, RepoID: 23})

@ -15,6 +15,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -318,7 +319,7 @@ func (a *Action) GetIssueContent() string {
type GetFeedsOptions struct { type GetFeedsOptions struct {
db.ListOptions db.ListOptions
RequestedUser *user_model.User // the user we want activity for 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 RequestedRepo *repo_model.Repository // the repo we want activity for
Actor *user_model.User // the user viewing the activity Actor *user_model.User // the user viewing the activity
IncludePrivate bool // include private actions IncludePrivate bool // include private actions
@ -399,7 +400,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
} }
if opts.RequestedTeam != nil { 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) teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
if err != nil { if err != nil {
return nil, fmt.Errorf("GetTeamRepositories: %v", err) return nil, fmt.Errorf("GetTeamRepositories: %v", err)

@ -11,6 +11,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
@ -94,7 +95,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
return false return false
} }
in, err := IsUserInTeams(userID, protectBranch.WhitelistTeamIDs) in, err := organization.IsUserInTeams(db.DefaultContext, userID, protectBranch.WhitelistTeamIDs)
if err != nil { if err != nil {
log.Error("IsUserInTeams: %v", err) log.Error("IsUserInTeams: %v", err)
return false return false
@ -117,7 +118,7 @@ func IsUserMergeWhitelisted(protectBranch *ProtectedBranch, userID int64, permis
return false return false
} }
in, err := IsUserInTeams(userID, protectBranch.MergeWhitelistTeamIDs) in, err := organization.IsUserInTeams(db.DefaultContext, userID, protectBranch.MergeWhitelistTeamIDs)
if err != nil { if err != nil {
log.Error("IsUserInTeams: %v", err) log.Error("IsUserInTeams: %v", err)
return false return false
@ -149,7 +150,7 @@ func isUserOfficialReviewer(ctx context.Context, protectBranch *ProtectedBranch,
return true, nil 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 { if err != nil {
return false, err return false, err
} }
@ -471,7 +472,7 @@ func updateTeamWhitelist(repo *repo_model.Repository, currentWhitelist, newWhite
return currentWhitelist, nil 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 { if err != nil {
return nil, fmt.Errorf("GetTeamsWithAccessToRepo [org_id: %d, repo_id: %d]: %v", repo.OwnerID, repo.ID, err) return nil, fmt.Errorf("GetTeamsWithAccessToRepo [org_id: %d, repo_id: %d]: %v", repo.OwnerID, repo.ID, err)
} }

@ -58,19 +58,6 @@ func (err ErrUserHasOrgs) Error() string {
return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID) 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" 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) return fmt.Sprintf("milestone does not exist [id: %d, repo_id: %d]", err.ID, err.RepoID)
} }
// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
// | |\ ___/ / __ \| Y Y \
// |____| \___ >____ /__|_| /
// \/ \/ \/
// ErrTeamAlreadyExist represents a "TeamAlreadyExist" kind of error.
type ErrTeamAlreadyExist struct {
OrgID int64
Name string
}
// IsErrTeamAlreadyExist checks if an error is a ErrTeamAlreadyExist.
func IsErrTeamAlreadyExist(err error) bool {
_, ok := err.(ErrTeamAlreadyExist)
return ok
}
func (err ErrTeamAlreadyExist) Error() string {
return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
}
// ErrTeamNotExist represents a "TeamNotExist" error
type ErrTeamNotExist struct {
OrgID int64
TeamID int64
Name string
}
// IsErrTeamNotExist checks if an error is a ErrTeamNotExist.
func IsErrTeamNotExist(err error) bool {
_, ok := err.(ErrTeamNotExist)
return ok
}
func (err ErrTeamNotExist) Error() string {
return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name)
}
// ____ ___ .__ .___ // ____ ___ .__ .___
// | | \______ | | _________ __| _/ // | | \______ | | _________ __| _/
// | | /\____ \| | / _ \__ \ / __ | // | | /\____ \| | / _ \__ \ / __ |

@ -6,6 +6,7 @@
authorize: 4 # owner authorize: 4 # owner
num_repos: 3 num_repos: 3
num_members: 1 num_members: 1
can_create_org_repo: true
- -
id: 2 id: 2
@ -15,6 +16,7 @@
authorize: 2 # write authorize: 2 # write
num_repos: 1 num_repos: 1
num_members: 2 num_members: 2
can_create_org_repo: false
- -
id: 3 id: 3
@ -24,6 +26,7 @@
authorize: 4 # owner authorize: 4 # owner
num_repos: 0 num_repos: 0
num_members: 1 num_members: 1
can_create_org_repo: true
- -
id: 4 id: 4
@ -33,6 +36,7 @@
authorize: 4 # owner authorize: 4 # owner
num_repos: 0 num_repos: 0
num_members: 1 num_members: 1
can_create_org_repo: true
- -
id: 5 id: 5
@ -42,6 +46,7 @@
authorize: 4 # owner authorize: 4 # owner
num_repos: 2 num_repos: 2
num_members: 2 num_members: 2
can_create_org_repo: true
- -
id: 6 id: 6
@ -51,6 +56,7 @@
authorize: 4 # owner authorize: 4 # owner
num_repos: 2 num_repos: 2
num_members: 1 num_members: 1
can_create_org_repo: true
- -
id: 7 id: 7
@ -60,6 +66,7 @@
authorize: 2 # write authorize: 2 # write
num_repos: 1 num_repos: 1
num_members: 1 num_members: 1
can_create_org_repo: false
- -
id: 8 id: 8
@ -69,6 +76,7 @@
authorize: 2 # write authorize: 2 # write
num_repos: 1 num_repos: 1
num_members: 1 num_members: 1
can_create_org_repo: false
- -
id: 9 id: 9
@ -78,6 +86,7 @@
authorize: 1 # read authorize: 1 # read
num_repos: 1 num_repos: 1
num_members: 2 num_members: 2
can_create_org_repo: false
- -
id: 10 id: 10
@ -87,6 +96,7 @@
authorize: 1 # owner authorize: 1 # owner
num_repos: 0 num_repos: 0
num_members: 1 num_members: 1
can_create_org_repo: false
- -
id: 11 id: 11
@ -96,6 +106,7 @@
authorize: 1 # read authorize: 1 # read
num_repos: 0 num_repos: 0
num_members: 0 num_members: 0
can_create_org_repo: false
- -
id: 12 id: 12

@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference" "code.gitea.io/gitea/models/foreignreference"
"code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
@ -1238,8 +1239,8 @@ type IssuesOptions struct {
// prioritize issues from this repo // prioritize issues from this repo
PriorityRepoID int64 PriorityRepoID int64
IsArchived util.OptionalBool IsArchived util.OptionalBool
Org *Organization // issues permission scope Org *organization.Organization // issues permission scope
Team *Team // issues permission scope Team *organization.Team // issues permission scope
User *user_model.User // issues permission scope User *user_model.User // issues permission scope
} }
@ -1401,7 +1402,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
} }
// issuePullAccessibleRepoCond userID must not be zero, this condition require join repository table // 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() cond := builder.NewCond()
unitType := unit.TypeIssues unitType := unit.TypeIssues
if isPull { if isPull {
@ -1749,8 +1750,8 @@ type UserIssueStatsOptions struct {
IsArchived util.OptionalBool IsArchived util.OptionalBool
LabelIDs []int64 LabelIDs []int64
RepoCond builder.Cond RepoCond builder.Cond
Org *Organization Org *organization.Organization
Team *Team Team *organization.Team
} }
// GetUserIssueStats returns issue statistic information for dashboard by given conditions. // 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 { 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). if err := db.GetEngine(ctx).
Join("INNER", "team_repo", "team_repo.team_id = team.id"). Join("INNER", "team_repo", "team_repo.team_id = team.id").
Where("team_repo.repo_id=?", issue.Repo.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 resolved[issue.Repo.Owner.LowerName+"/"+team.LowerName] = true
continue 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 { if err != nil {
return nil, fmt.Errorf("get team units (%d): %v", team.ID, err) return nil, fmt.Errorf("get team units (%d): %v", team.ID, err)
} }

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -215,7 +216,7 @@ type Comment struct {
RemovedAssignee bool RemovedAssignee bool
Assignee *user_model.User `xorm:"-"` Assignee *user_model.User `xorm:"-"`
AssigneeTeamID int64 `xorm:"NOT NULL DEFAULT 0"` AssigneeTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
AssigneeTeam *Team `xorm:"-"` AssigneeTeam *organization.Team `xorm:"-"`
ResolveDoerID int64 ResolveDoerID int64
ResolveDoer *user_model.User `xorm:"-"` ResolveDoer *user_model.User `xorm:"-"`
OldTitle string OldTitle string
@ -581,8 +582,8 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
} }
if c.Issue.Repo.Owner.IsOrganization() { if c.Issue.Repo.Owner.IsOrganization() {
c.AssigneeTeam, err = GetTeamByID(c.AssigneeTeamID) c.AssigneeTeam, err = organization.GetTeamByID(c.AssigneeTeamID)
if err != nil && !IsErrTeamNotExist(err) { if err != nil && !organization.IsErrTeamNotExist(err) {
return err return err
} }
} }

@ -7,6 +7,7 @@ package models
import ( import (
"testing" "testing"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -30,7 +31,7 @@ func TestFixturesAreConsistent(t *testing.T) {
&PullRequest{}, &PullRequest{},
&Milestone{}, &Milestone{},
&Label{}, &Label{},
&Team{}, &organization.Team{},
&Action{}) &Action{})
} }

@ -11,6 +11,7 @@ import (
"strconv" "strconv"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -151,7 +152,7 @@ func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *repo_
var notify []*Notification var notify []*Notification
if newOwner.IsOrganization() { if newOwner.IsOrganization() {
users, err := getUsersWhoCanCreateOrgRepo(db.GetEngine(ctx), newOwner.ID) users, err := organization.GetUsersWhoCanCreateOrgRepo(ctx, newOwner.ID)
if err != nil || len(users) == 0 { if err != nil || len(users) == 0 {
return err return err
} }

@ -11,443 +11,15 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models/db" "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" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" 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" "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 // MinimalOrg represents a simple orgnization with only needed columns
type MinimalOrg = Organization type MinimalOrg = organization.Organization
// GetUserOrgsList returns one user's all orgs list // GetUserOrgsList returns one user's all orgs list
func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) { func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
@ -486,7 +58,7 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
GroupBy(groupByStr) GroupBy(groupByStr)
type OrgCount struct { type OrgCount struct {
Organization `xorm:"extends"` organization.Organization `xorm:"extends"`
OrgCount int OrgCount int
} }
@ -507,239 +79,8 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
return orgs, nil 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 { func removeOrgUser(ctx context.Context, orgID, userID int64) error {
ou := new(OrgUser) ou := new(organization.OrgUser)
sess := db.GetEngine(ctx) sess := db.GetEngine(ctx)
@ -753,25 +94,25 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
return nil return nil
} }
org, err := GetOrgByIDCtx(ctx, orgID) org, err := organization.GetOrgByIDCtx(ctx, orgID)
if err != nil { if err != nil {
return fmt.Errorf("GetUserByID [%d]: %v", orgID, err) return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
} }
// Check if the user to delete is the last member in owner team. // 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 return err
} else if isOwner { } else if isOwner {
t, err := org.getOwnerTeam(sess) t, err := organization.GetOwnerTeam(ctx, org.ID)
if err != nil { if err != nil {
return err return err
} }
if t.NumMembers == 1 { if t.NumMembers == 1 {
if err := t.getMembers(sess); err != nil { if err := t.GetMembersCtx(ctx); err != nil {
return err return err
} }
if t.Members[0].ID == userID { 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. // Delete all repository accesses and unwatch them.
env, err := org.accessibleReposEnv(sess, userID) env, err := organization.AccessibleReposEnv(ctx, org, userID)
if err != nil { if err != nil {
return fmt.Errorf("AccessibleReposEnv: %v", err) 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. // Delete member in his/her teams.
teams, err := getUserOrgTeams(sess, org.ID, userID) teams, err := organization.GetUserOrgTeams(ctx, org.ID, userID)
if err != nil { if err != nil {
return err return err
} }
@ -832,233 +173,3 @@ func RemoveOrgUser(orgID, userID int64) error {
} }
return committer.Commit() return committer.Commit()
} }
func removeOrgRepo(e db.Engine, orgID, repoID int64) error {
teamRepos := make([]*TeamRepo, 0, 10)
if err := e.Find(&teamRepos, &TeamRepo{OrgID: orgID, RepoID: repoID}); err != nil {
return err
}
if len(teamRepos) == 0 {
return nil
}
if _, err := e.Delete(&TeamRepo{
OrgID: orgID,
RepoID: repoID,
}); err != nil {
return err
}
teamIDs := make([]int64, len(teamRepos))
for i, teamRepo := range teamRepos {
teamIDs[i] = teamRepo.TeamID
}
_, err := e.Decr("num_repos").In("id", teamIDs).Update(new(Team))
return err
}
func (org *Organization) getUserTeams(e db.Engine, userID int64, cols ...string) ([]*Team, error) {
teams := make([]*Team, 0, org.NumTeams)
return teams, e.
Where("`team_user`.org_id = ?", org.ID).
Join("INNER", "team_user", "`team_user`.team_id = team.id").
Join("INNER", "`user`", "`user`.id=team_user.uid").
And("`team_user`.uid = ?", userID).
Asc("`user`.name").
Cols(cols...).
Find(&teams)
}
func (org *Organization) getUserTeamIDs(e db.Engine, userID int64) ([]int64, error) {
teamIDs := make([]int64, 0, org.NumTeams)
return teamIDs, e.
Table("team").
Cols("team.id").
Where("`team_user`.org_id = ?", org.ID).
Join("INNER", "team_user", "`team_user`.team_id = team.id").
And("`team_user`.uid = ?", userID).
Find(&teamIDs)
}
// TeamsWithAccessToRepo returns all teams that have given access level to the repository.
func (org *Organization) TeamsWithAccessToRepo(repoID int64, mode perm.AccessMode) ([]*Team, error) {
return GetTeamsWithAccessToRepo(org.ID, repoID, mode)
}
// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
func (org *Organization) GetUserTeamIDs(userID int64) ([]int64, error) {
return org.getUserTeamIDs(db.GetEngine(db.DefaultContext), userID)
}
// GetUserTeams returns all teams that belong to user,
// and that the user has joined.
func (org *Organization) GetUserTeams(userID int64) ([]*Team, error) {
return org.getUserTeams(db.GetEngine(db.DefaultContext), userID)
}
// AccessibleReposEnvironment operations involving the repositories that are
// accessible to a particular user
type AccessibleReposEnvironment interface {
CountRepos() (int64, error)
RepoIDs(page, pageSize int) ([]int64, error)
Repos(page, pageSize int) ([]*repo_model.Repository, error)
MirrorRepos() ([]*repo_model.Repository, error)
AddKeyword(keyword string)
SetSort(db.SearchOrderBy)
}
type accessibleReposEnv struct {
org *Organization
user *user_model.User
team *Team
teamIDs []int64
e db.Engine
keyword string
orderBy db.SearchOrderBy
}
// AccessibleReposEnv builds an AccessibleReposEnvironment for the repositories in `org`
// that are accessible to the specified user.
func (org *Organization) AccessibleReposEnv(userID int64) (AccessibleReposEnvironment, error) {
return org.accessibleReposEnv(db.GetEngine(db.DefaultContext), userID)
}
func (org *Organization) accessibleReposEnv(e db.Engine, userID int64) (AccessibleReposEnvironment, error) {
var user *user_model.User
if userID > 0 {
u, err := user_model.GetUserByIDEngine(e, userID)
if err != nil {
return nil, err
}
user = u
}
teamIDs, err := org.getUserTeamIDs(e, userID)
if err != nil {
return nil, err
}
return &accessibleReposEnv{
org: org,
user: user,
teamIDs: teamIDs,
e: e,
orderBy: db.SearchOrderByRecentUpdated,
}, nil
}
// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
// that are accessible to the specified team.
func (org *Organization) AccessibleTeamReposEnv(team *Team) AccessibleReposEnvironment {
return &accessibleReposEnv{
org: org,
team: team,
e: db.GetEngine(db.DefaultContext),
orderBy: db.SearchOrderByRecentUpdated,
}
}
func (env *accessibleReposEnv) cond() builder.Cond {
cond := builder.NewCond()
if env.team != nil {
cond = cond.And(builder.Eq{"team_repo.team_id": env.team.ID})
} else {
if env.user == nil || !env.user.IsRestricted {
cond = cond.Or(builder.Eq{
"`repository`.owner_id": env.org.ID,
"`repository`.is_private": false,
})
}
if len(env.teamIDs) > 0 {
cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
}
}
if env.keyword != "" {
cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
}
return cond
}
func (env *accessibleReposEnv) CountRepos() (int64, error) {
repoCount, err := env.e.
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
Where(env.cond()).
Distinct("`repository`.id").
Count(&repo_model.Repository{})
if err != nil {
return 0, fmt.Errorf("count user repositories in organization: %v", err)
}
return repoCount, nil
}
func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
if page <= 0 {
page = 1
}
repoIDs := make([]int64, 0, pageSize)
return repoIDs, env.e.
Table("repository").
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
Where(env.cond()).
GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]).
OrderBy(string(env.orderBy)).
Limit(pageSize, (page-1)*pageSize).
Cols("`repository`.id").
Find(&repoIDs)
}
func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*repo_model.Repository, error) {
repoIDs, err := env.RepoIDs(page, pageSize)
if err != nil {
return nil, fmt.Errorf("GetUserRepositoryIDs: %v", err)
}
repos := make([]*repo_model.Repository, 0, len(repoIDs))
if len(repoIDs) == 0 {
return repos, nil
}
return repos, env.e.
In("`repository`.id", repoIDs).
OrderBy(string(env.orderBy)).
Find(&repos)
}
func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
repoIDs := make([]int64, 0, 10)
return repoIDs, env.e.
Table("repository").
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
Where(env.cond()).
GroupBy("`repository`.id, `repository`.updated_unix").
OrderBy(string(env.orderBy)).
Cols("`repository`.id").
Find(&repoIDs)
}
func (env *accessibleReposEnv) MirrorRepos() ([]*repo_model.Repository, error) {
repoIDs, err := env.MirrorRepoIDs()
if err != nil {
return nil, fmt.Errorf("MirrorRepoIDs: %v", err)
}
repos := make([]*repo_model.Repository, 0, len(repoIDs))
if len(repoIDs) == 0 {
return repos, nil
}
return repos, env.e.
In("`repository`.id", repoIDs).
Find(&repos)
}
func (env *accessibleReposEnv) AddKeyword(keyword string) {
env.keyword = keyword
}
func (env *accessibleReposEnv) SetSort(orderBy db.SearchOrderBy) {
env.orderBy = orderBy
}

@ -9,288 +9,24 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"sort"
"strings" "strings"
"code.gitea.io/gitea/models/db" "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" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" 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/setting"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
) )
const ownerTeamName = "Owners" 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 {
// 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 {
return err 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) 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 // Make all team members watch this repo if enabled in global settings
if setting.Service.AutoWatchNewRepos { if setting.Service.AutoWatchNewRepos {
if err = t.getMembers(e); err != nil { if err = t.GetMembersCtx(ctx); err != nil {
return fmt.Errorf("getMembers: %v", err) return fmt.Errorf("getMembers: %v", err)
} }
for _, u := range t.Members { 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. // addAllRepositories adds all repositories to the team.
// If the team already has some repositories they will be left unchanged. // 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 var orgRepos []repo_model.Repository
e := db.GetEngine(ctx) e := db.GetEngine(ctx)
if err := e.Where("owner_id = ?", t.OrgID).Find(&orgRepos); err != nil { 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 { for _, repo := range orgRepos {
if !t.hasRepository(e, repo.ID) { if !hasRepository(ctx, t, repo.ID) {
if err := t.addRepository(ctx, &repo); err != nil { if err := addRepository(ctx, t, &repo); err != nil {
return fmt.Errorf("addRepository: %v", err) 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 // 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() ctx, committer, err := db.TxContext()
if err != nil { if err != nil {
return err return err
} }
defer committer.Close() defer committer.Close()
if err = t.addAllRepositories(ctx); err != nil { if err = addAllRepositories(ctx, t); err != nil {
return err return err
} }
@ -351,10 +87,10 @@ func (t *Team) AddAllRepositories() (err error) {
} }
// AddRepository adds new repository to team of organization. // 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 { if repo.OwnerID != t.OrgID {
return errors.New("Repository does not belong to organization") return errors.New("Repository does not belong to organization")
} else if t.HasRepository(repo.ID) { } else if HasRepository(t, repo.ID) {
return nil return nil
} }
@ -364,15 +100,20 @@ func (t *Team) AddRepository(repo *repo_model.Repository) (err error) {
} }
defer committer.Close() defer committer.Close()
if err = t.addRepository(ctx, repo); err != nil { if err = addRepository(ctx, t, repo); err != nil {
return err return err
} }
return committer.Commit() 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 // 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 { if t.IncludesAllRepositories {
return nil return nil
} }
@ -383,7 +124,7 @@ func (t *Team) RemoveAllRepositories() (err error) {
} }
defer committer.Close() defer committer.Close()
if err = t.removeAllRepositories(ctx); err != nil { if err = removeAllRepositories(ctx, t); err != nil {
return err return err
} }
@ -392,7 +133,7 @@ func (t *Team) RemoveAllRepositories() (err error) {
// removeAllRepositories removes all repositories from team and recalculates access // removeAllRepositories removes all repositories from team and recalculates access
// Note: Shall not be called if team includes all repositories // 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) e := db.GetEngine(ctx)
// Delete all accesses. // Delete all accesses.
for _, repo := range t.Repos { for _, repo := range t.Repos {
@ -423,7 +164,7 @@ func (t *Team) removeAllRepositories(ctx context.Context) (err error) {
// Delete team-repo // Delete team-repo
if _, err := e. if _, err := e.
Where("team_id=?", t.ID). Where("team_id=?", t.ID).
Delete(new(TeamRepo)); err != nil { Delete(new(organization.TeamRepo)); err != nil {
return err return err
} }
@ -435,11 +176,15 @@ func (t *Team) removeAllRepositories(ctx context.Context) (err error) {
return nil 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 // 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) // 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) 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 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 { if err != nil {
return fmt.Errorf("getTeamUsersByTeamID: %v", err) 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. // RemoveRepository removes repository from team of organization.
// If the team shall include all repositories the request is ignored. // If the team shall include all repositories the request is ignored.
func (t *Team) RemoveRepository(repoID int64) error { func RemoveRepository(t *organization.Team, repoID int64) error {
if !t.HasRepository(repoID) { if !HasRepository(t, repoID) {
return nil return nil
} }
@ -502,58 +247,21 @@ func (t *Team) RemoveRepository(repoID int64) error {
} }
defer committer.Close() defer committer.Close()
if err = t.removeRepository(ctx, repo, true); err != nil { if err = removeRepository(ctx, t, repo, true); err != nil {
return err return err
} }
return committer.Commit() 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. // NewTeam creates a record of new team.
// It's caller's responsibility to assign organization ID. // 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 { if len(t.Name) == 0 {
return errors.New("empty team name") return errors.New("empty team name")
} }
if err = IsUsableTeamName(t.Name); err != nil { if err = organization.IsUsableTeamName(t.Name); err != nil {
return err return err
} }
@ -562,19 +270,19 @@ func NewTeam(t *Team) (err error) {
return err return err
} }
if !has { if !has {
return ErrOrgNotExist{t.OrgID, ""} return organization.ErrOrgNotExist{ID: t.OrgID}
} }
t.LowerName = strings.ToLower(t.Name) t.LowerName = strings.ToLower(t.Name)
has, err = db.GetEngine(db.DefaultContext). has, err = db.GetEngine(db.DefaultContext).
Where("org_id=?", t.OrgID). Where("org_id=?", t.OrgID).
And("lower_name=?", t.LowerName). And("lower_name=?", t.LowerName).
Get(new(Team)) Get(new(organization.Team))
if err != nil { if err != nil {
return err return err
} }
if has { if has {
return ErrTeamAlreadyExist{t.OrgID, t.LowerName} return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName}
} }
ctx, committer, err := db.TxContext() 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. // Add all repositories to the team if it has access to all of them.
if t.IncludesAllRepositories { if t.IncludesAllRepositories {
err = t.addAllRepositories(ctx) err = addAllRepositories(ctx, t)
if err != nil { if err != nil {
return fmt.Errorf("addAllRepositories: %v", err) return fmt.Errorf("addAllRepositories: %v", err)
} }
@ -612,81 +320,8 @@ func NewTeam(t *Team) (err error) {
return committer.Commit() 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. // 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 { if len(t.Name) == 0 {
return errors.New("empty team name") return errors.New("empty team name")
} }
@ -707,11 +342,11 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
Where("org_id=?", t.OrgID). Where("org_id=?", t.OrgID).
And("lower_name=?", t.LowerName). And("lower_name=?", t.LowerName).
And("id!=?", t.ID). And("id!=?", t.ID).
Get(new(Team)) Get(new(organization.Team))
if err != nil { if err != nil {
return err return err
} else if has { } 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", 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. // Delete team-unit.
if _, err := sess. if _, err := sess.
Where("team_id=?", t.ID). Where("team_id=?", t.ID).
Delete(new(TeamUnit)); err != nil { Delete(new(organization.TeamUnit)); err != nil {
return err return err
} }
if _, err = sess.Cols("org_id", "team_id", "type", "access_mode").Insert(&t.Units); err != nil { 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. // Update access for team members if needed.
if authChanged { if authChanged {
if err = t.getRepositories(sess); err != nil { if err = t.GetRepositoriesCtx(ctx); err != nil {
return fmt.Errorf("getRepositories: %v", err) 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. // Add all repositories to the team if it has access to all of them.
if includeAllChanged && t.IncludesAllRepositories { if includeAllChanged && t.IncludesAllRepositories {
err = t.addAllRepositories(ctx) err = addAllRepositories(ctx, t)
if err != nil { if err != nil {
return fmt.Errorf("addAllRepositories: %v", err) return fmt.Errorf("addAllRepositories: %v", err)
} }
@ -761,11 +396,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
// DeleteTeam deletes given team. // DeleteTeam deletes given team.
// It's caller's responsibility to assign organization ID. // It's caller's responsibility to assign organization ID.
func DeleteTeam(t *Team) error { func DeleteTeam(t *organization.Team) error {
if err := t.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
return err
}
ctx, committer, err := db.TxContext() ctx, committer, err := db.TxContext()
if err != nil { if err != nil {
return err return err
@ -773,7 +404,11 @@ func DeleteTeam(t *Team) error {
defer committer.Close() defer committer.Close()
sess := db.GetEngine(ctx) 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 return err
} }
@ -813,7 +448,7 @@ func DeleteTeam(t *Team) error {
} }
if !t.IncludesAllRepositories { if !t.IncludesAllRepositories {
if err := t.removeAllRepositories(ctx); err != nil { if err := removeAllRepositories(ctx, t); err != nil {
return err return err
} }
} }
@ -822,19 +457,19 @@ func DeleteTeam(t *Team) error {
if _, err := sess. if _, err := sess.
Where("org_id=?", t.OrgID). Where("org_id=?", t.OrgID).
Where("team_id=?", t.ID). Where("team_id=?", t.ID).
Delete(new(TeamUser)); err != nil { Delete(new(organization.TeamUser)); err != nil {
return err return err
} }
// Delete team-unit. // Delete team-unit.
if _, err := sess. if _, err := sess.
Where("team_id=?", t.ID). Where("team_id=?", t.ID).
Delete(new(TeamUnit)); err != nil { Delete(new(organization.TeamUnit)); err != nil {
return err return err
} }
// Delete team. // 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 return err
} }
// Update organization number of teams. // Update organization number of teams.
@ -845,103 +480,15 @@ func DeleteTeam(t *Team) error {
return committer.Commit() 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, // AddTeamMember adds new membership of given team to given organization,
// the user will have membership to given organization automatically when needed. // the user will have membership to given organization automatically when needed.
func AddTeamMember(team *Team, userID int64) error { func AddTeamMember(team *organization.Team, userID int64) error {
isAlreadyMember, err := IsTeamMember(team.OrgID, team.ID, userID) isAlreadyMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, userID)
if err != nil || isAlreadyMember { if err != nil || isAlreadyMember {
return err return err
} }
if err := AddOrgUser(team.OrgID, userID); err != nil { if err := organization.AddOrgUser(team.OrgID, userID); err != nil {
return err
}
// Get team and its repositories.
if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
return err return err
} }
@ -951,15 +498,20 @@ func AddTeamMember(team *Team, userID int64) error {
} }
defer committer.Close() defer committer.Close()
// Get team and its repositories.
if err := team.GetRepositoriesCtx(ctx); err != nil {
return err
}
sess := db.GetEngine(ctx) sess := db.GetEngine(ctx)
if err := db.Insert(ctx, &TeamUser{ if err := db.Insert(ctx, &organization.TeamUser{
UID: userID, UID: userID,
OrgID: team.OrgID, OrgID: team.OrgID,
TeamID: team.ID, TeamID: team.ID,
}); err != nil { }); err != nil {
return err 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 return err
} }
@ -980,25 +532,25 @@ func AddTeamMember(team *Team, userID int64) error {
return committer.Commit() 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) 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 { if err != nil || !isMember {
return err return err
} }
// Check if the user to delete is the last member in owner team. // Check if the user to delete is the last member in owner team.
if team.IsOwnerTeam() && team.NumMembers == 1 { if team.IsOwnerTeam() && team.NumMembers == 1 {
return ErrLastOrgOwner{UID: userID} return organization.ErrLastOrgOwner{UID: userID}
} }
team.NumMembers-- team.NumMembers--
if err := team.getRepositories(e); err != nil { if err := team.GetRepositoriesCtx(ctx); err != nil {
return err return err
} }
if _, err := e.Delete(&TeamUser{ if _, err := e.Delete(&organization.TeamUser{
UID: userID, UID: userID,
OrgID: team.OrgID, OrgID: team.OrgID,
TeamID: team.ID, 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. // 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, UID: userID,
OrgID: team.OrgID, OrgID: team.OrgID,
}); err != nil { }); 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. // 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() ctx, committer, err := db.TxContext()
if err != nil { if err != nil {
return err return err
@ -1053,125 +605,3 @@ func RemoveTeamMember(team *Team, userID int64) error {
} }
return committer.Commit() return committer.Commit()
} }
// IsUserInTeams returns if a user in some teams
func IsUserInTeams(userID int64, teamIDs []int64) (bool, error) {
return isUserInTeams(db.GetEngine(db.DefaultContext), userID, teamIDs)
}
func isUserInTeams(e db.Engine, userID int64, teamIDs []int64) (bool, error) {
return e.Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser))
}
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
func UsersInTeamsCount(userIDs, teamIDs []int64) (int64, error) {
var ids []int64
if err := db.GetEngine(db.DefaultContext).In("uid", userIDs).In("team_id", teamIDs).
Table("team_user").
Cols("uid").GroupBy("uid").Find(&ids); err != nil {
return 0, err
}
return int64(len(ids)), nil
}
// ___________ __________
// \__ ___/___ _____ _____\______ \ ____ ______ ____
// | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
// | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
// |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
// \/ \/ \/ \/ \/|__|
// TeamRepo represents an team-repository relation.
type TeamRepo struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
RepoID int64 `xorm:"UNIQUE(s)"`
}
func hasTeamRepo(e db.Engine, orgID, teamID, repoID int64) bool {
has, _ := e.
Where("org_id=?", orgID).
And("team_id=?", teamID).
And("repo_id=?", repoID).
Get(new(TeamRepo))
return has
}
// HasTeamRepo returns true if given repository belongs to team.
func HasTeamRepo(orgID, teamID, repoID int64) bool {
return hasTeamRepo(db.GetEngine(db.DefaultContext), orgID, teamID, repoID)
}
func addTeamRepo(e db.Engine, orgID, teamID, repoID int64) error {
_, err := e.InsertOne(&TeamRepo{
OrgID: orgID,
TeamID: teamID,
RepoID: repoID,
})
return err
}
func removeTeamRepo(e db.Engine, teamID, repoID int64) error {
_, err := e.Delete(&TeamRepo{
TeamID: teamID,
RepoID: repoID,
})
return err
}
// GetTeamsWithAccessToRepo returns all teams in an organization that have given access level to the repository.
func GetTeamsWithAccessToRepo(orgID, repoID int64, mode perm.AccessMode) ([]*Team, error) {
teams := make([]*Team, 0, 5)
return teams, db.GetEngine(db.DefaultContext).Where("team.authorize >= ?", mode).
Join("INNER", "team_repo", "team_repo.team_id = team.id").
And("team_repo.org_id = ?", orgID).
And("team_repo.repo_id = ?", repoID).
Find(&teams)
}
// ___________ ____ ___ .__ __
// \__ ___/___ _____ _____ | | \____ |__|/ |_
// | |_/ __ \\__ \ / \| | / \| \ __\
// | |\ ___/ / __ \| Y Y \ | / | \ || |
// |____| \___ >____ /__|_| /______/|___| /__||__|
// \/ \/ \/ \/
// TeamUnit describes all units of a repository
type TeamUnit struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
Type unit.Type `xorm:"UNIQUE(s)"`
AccessMode perm.AccessMode
}
// Unit returns Unit
func (t *TeamUnit) Unit() unit.Unit {
return unit.Units[t.Type]
}
func getUnitsByTeamID(e db.Engine, teamID int64) (units []*TeamUnit, err error) {
return units, e.Where("team_id = ?", teamID).Find(&units)
}
// UpdateTeamUnits updates a teams's units
func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
}
defer committer.Close()
if _, err = db.GetEngine(ctx).Where("team_id = ?", team.ID).Delete(new(TeamUnit)); err != nil {
return err
}
if len(units) > 0 {
if err = db.Insert(ctx, units); err != nil {
return err
}
}
return committer.Commit()
}

@ -9,6 +9,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
@ -17,68 +18,14 @@ import (
"github.com/stretchr/testify/assert" "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) { func TestTeam_AddMember(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
test := func(teamID, userID int64) { 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, team.AddMember(userID)) assert.NoError(t, AddTeamMember(team, userID))
unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: userID, TeamID: teamID}) unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &user_model.User{ID: team.OrgID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &user_model.User{ID: team.OrgID})
} }
test(1, 2) test(1, 2)
test(1, 4) test(1, 4)
@ -89,27 +36,27 @@ func TestTeam_RemoveMember(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(teamID, userID int64) { 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, team.RemoveMember(userID)) assert.NoError(t, RemoveTeamMember(team, userID))
unittest.AssertNotExistsBean(t, &TeamUser{UID: userID, TeamID: teamID}) unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
unittest.CheckConsistencyFor(t, &Team{ID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID})
} }
testSuccess(1, 4) testSuccess(1, 4)
testSuccess(2, 2) testSuccess(2, 2)
testSuccess(3, 2) testSuccess(3, 2)
testSuccess(3, unittest.NonexistentID) testSuccess(3, unittest.NonexistentID)
team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team)
err := team.RemoveMember(2) err := RemoveTeamMember(team, 2)
assert.True(t, IsErrLastOrgOwner(err)) assert.True(t, organization.IsErrLastOrgOwner(err))
} }
func TestTeam_HasRepository(t *testing.T) { func TestTeam_HasRepository(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
test := func(teamID, repoID int64, expected bool) { test := func(teamID, repoID int64, expected bool) {
team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
assert.Equal(t, expected, team.HasRepository(repoID)) assert.Equal(t, expected, HasRepository(team, repoID))
} }
test(1, 1, false) test(1, 1, false)
test(1, 3, true) test(1, 3, true)
@ -124,29 +71,29 @@ func TestTeam_AddRepository(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(teamID, repoID int64) { 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) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
assert.NoError(t, team.AddRepository(repo)) assert.NoError(t, AddRepository(team, repo))
unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repoID}) unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID})
unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &repo_model.Repository{ID: repoID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID})
} }
testSuccess(2, 3) testSuccess(2, 3)
testSuccess(2, 5) 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) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
assert.Error(t, team.AddRepository(repo)) assert.Error(t, AddRepository(team, repo))
unittest.CheckConsistencyFor(t, &Team{ID: 1}, &repo_model.Repository{ID: 1}) unittest.CheckConsistencyFor(t, &organization.Team{ID: 1}, &repo_model.Repository{ID: 1})
} }
func TestTeam_RemoveRepository(t *testing.T) { func TestTeam_RemoveRepository(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(teamID, repoID int64) { testSuccess := func(teamID, repoID int64) {
team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
assert.NoError(t, team.RemoveRepository(repoID)) assert.NoError(t, RemoveRepository(team, repoID))
unittest.AssertNotExistsBean(t, &TeamRepo{TeamID: teamID, RepoID: repoID}) unittest.AssertNotExistsBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID})
unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &repo_model.Repository{ID: repoID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID})
} }
testSuccess(2, 3) testSuccess(2, 3)
testSuccess(2, 5) testSuccess(2, 5)
@ -154,97 +101,62 @@ func TestTeam_RemoveRepository(t *testing.T) {
} }
func TestIsUsableTeamName(t *testing.T) { func TestIsUsableTeamName(t *testing.T) {
assert.NoError(t, IsUsableTeamName("usable")) assert.NoError(t, organization.IsUsableTeamName("usable"))
assert.True(t, db.IsErrNameReserved(IsUsableTeamName("new"))) assert.True(t, db.IsErrNameReserved(organization.IsUsableTeamName("new")))
} }
func TestNewTeam(t *testing.T) { func TestNewTeam(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
const teamName = "newTeamName" const teamName = "newTeamName"
team := &Team{Name: teamName, OrgID: 3} team := &organization.Team{Name: teamName, OrgID: 3}
assert.NoError(t, NewTeam(team)) assert.NoError(t, NewTeam(team))
unittest.AssertExistsAndLoadBean(t, &Team{Name: teamName}) unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: teamName})
unittest.CheckConsistencyFor(t, &Team{}, &user_model.User{ID: team.OrgID}) unittest.CheckConsistencyFor(t, &organization.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)
} }
func TestUpdateTeam(t *testing.T) { func TestUpdateTeam(t *testing.T) {
// successful update // successful update
assert.NoError(t, unittest.PrepareTestDatabase()) 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.LowerName = "newname"
team.Name = "newName" team.Name = "newName"
team.Description = strings.Repeat("A long description!", 100) team.Description = strings.Repeat("A long description!", 100)
team.AccessMode = perm.AccessModeAdmin team.AccessMode = perm.AccessModeAdmin
assert.NoError(t, UpdateTeam(team, true, false)) 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!")) assert.True(t, strings.HasPrefix(team.Description, "A long description!"))
access := unittest.AssertExistsAndLoadBean(t, &Access{UserID: 4, RepoID: 3}).(*Access) access := unittest.AssertExistsAndLoadBean(t, &Access{UserID: 4, RepoID: 3}).(*Access)
assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) 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) { func TestUpdateTeam2(t *testing.T) {
// update to already-existing team // update to already-existing team
assert.NoError(t, unittest.PrepareTestDatabase()) 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.LowerName = "owners"
team.Name = "Owners" team.Name = "Owners"
team.Description = strings.Repeat("A long description!", 100) team.Description = strings.Repeat("A long description!", 100)
err := UpdateTeam(team, true, false) 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) { func TestDeleteTeam(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) 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)) assert.NoError(t, DeleteTeam(team))
unittest.AssertNotExistsBean(t, &Team{ID: team.ID}) unittest.AssertNotExistsBean(t, &organization.Team{ID: team.ID})
unittest.AssertNotExistsBean(t, &TeamRepo{TeamID: team.ID}) unittest.AssertNotExistsBean(t, &organization.TeamRepo{TeamID: team.ID})
unittest.AssertNotExistsBean(t, &TeamUser{TeamID: team.ID}) unittest.AssertNotExistsBean(t, &organization.TeamUser{TeamID: team.ID})
// check that team members don't have "leftover" access to repos // check that team members don't have "leftover" access to repos
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) 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) 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) { func TestAddTeamMember(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
test := func(teamID, userID int64) { 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)) assert.NoError(t, AddTeamMember(team, userID))
unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: userID, TeamID: teamID}) unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &user_model.User{ID: team.OrgID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &user_model.User{ID: team.OrgID})
} }
test(1, 2) test(1, 2)
test(1, 4) test(1, 4)
@ -336,47 +184,17 @@ func TestRemoveTeamMember(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(teamID, userID int64) { 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)) assert.NoError(t, RemoveTeamMember(team, userID))
unittest.AssertNotExistsBean(t, &TeamUser{UID: userID, TeamID: teamID}) unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID, TeamID: teamID})
unittest.CheckConsistencyFor(t, &Team{ID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID})
} }
testSuccess(1, 4) testSuccess(1, 4)
testSuccess(2, 2) testSuccess(2, 2)
testSuccess(3, 2) testSuccess(3, 2)
testSuccess(3, unittest.NonexistentID) 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) err := RemoveTeamMember(team, 2)
assert.True(t, IsErrLastOrgOwner(err)) assert.True(t, organization.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
} }

@ -8,176 +8,81 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert" "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) { func TestUser_RemoveMember(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) 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 // 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 prevNumMembers := org.NumMembers
assert.NoError(t, org.RemoveMember(4)) assert.NoError(t, RemoveOrgUser(org.ID, 4))
unittest.AssertNotExistsBean(t, &OrgUser{UID: 4, OrgID: 3}) unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: 4, OrgID: 3})
org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization)
assert.Equal(t, prevNumMembers-1, org.NumMembers) assert.Equal(t, prevNumMembers-1, org.NumMembers)
// remove a user that is not a member // 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 prevNumMembers = org.NumMembers
assert.NoError(t, org.RemoveMember(5)) assert.NoError(t, RemoveOrgUser(org.ID, 5))
unittest.AssertNotExistsBean(t, &OrgUser{UID: 5, OrgID: 3}) unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: 5, OrgID: 3})
org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization)
assert.Equal(t, prevNumMembers, org.NumMembers) 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) { func TestUser_RemoveOrgRepo(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) 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) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: org.ID}).(*repo_model.Repository)
// remove a repo that does belong to org // remove a repo that does belong to org
unittest.AssertExistsAndLoadBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID}) unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{RepoID: repo.ID, OrgID: org.ID})
assert.NoError(t, org.RemoveOrgRepo(repo.ID)) assert.NoError(t, organization.RemoveOrgRepo(db.DefaultContext, org.ID, repo.ID))
unittest.AssertNotExistsBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.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 unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) // repo should still exist
// remove a repo that does not belong to org // remove a repo that does not belong to org
assert.NoError(t, org.RemoveOrgRepo(repo.ID)) assert.NoError(t, organization.RemoveOrgRepo(db.DefaultContext, org.ID, repo.ID))
unittest.AssertNotExistsBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.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, unittest.CheckConsistencyFor(t,
&user_model.User{ID: org.ID}, &user_model.User{ID: org.ID},
&Team{OrgID: org.ID}, &organization.Team{OrgID: org.ID},
&repo_model.Repository{ID: repo.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) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
const newOrgName = "neworg" const newOrgName = "neworg"
org := &Organization{ org := &organization.Organization{
Name: newOrgName, Name: newOrgName,
} }
unittest.AssertNotExistsBean(t, &user_model.User{Name: newOrgName, Type: user_model.UserTypeOrganization}) 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, 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, ownerTeam := unittest.AssertExistsAndLoadBean(t,
&Team{Name: ownerTeamName, OrgID: org.ID}).(*Team) &organization.Team{Name: organization.OwnerTeamName, OrgID: org.ID}).(*organization.Team)
unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: owner.ID, TeamID: ownerTeam.ID}) unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: owner.ID, TeamID: ownerTeam.ID})
unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{}) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})
} }
func TestCreateOrganization2(t *testing.T) { 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) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
const newOrgName = "neworg" const newOrgName = "neworg"
org := &Organization{ org := &organization.Organization{
Name: newOrgName, Name: newOrgName,
} }
unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}) unittest.AssertNotExistsBean(t, &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
err := CreateOrganization(org, owner) err := organization.CreateOrganization(org, owner)
assert.Error(t, err) assert.Error(t, err)
assert.True(t, IsErrUserNotAllowedCreateOrg(err)) assert.True(t, organization.IsErrUserNotAllowedCreateOrg(err))
unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}) unittest.AssertNotExistsBean(t, &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
unittest.CheckConsistencyFor(t, &Organization{}, &Team{}) unittest.CheckConsistencyFor(t, &organization.Organization{}, &organization.Team{})
} }
func TestCreateOrganization3(t *testing.T) { func TestCreateOrganization3(t *testing.T) {
@ -224,12 +129,12 @@ func TestCreateOrganization3(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) 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 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.Error(t, err)
assert.True(t, user_model.IsErrUserAlreadyExist(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) { func TestCreateOrganization4(t *testing.T) {
@ -237,210 +142,10 @@ func TestCreateOrganization4(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) 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.Error(t, err)
assert.True(t, db.IsErrNameReserved(err)) assert.True(t, db.IsErrNameReserved(err))
unittest.CheckConsistencyFor(t, &Organization{}, &Team{}) unittest.CheckConsistencyFor(t, &organization.Organization{}, &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))
} }
func TestAddOrgUser(t *testing.T) { func TestAddOrgUser(t *testing.T) {
@ -448,11 +153,11 @@ func TestAddOrgUser(t *testing.T) {
testSuccess := func(orgID, userID int64, isPublic bool) { testSuccess := func(orgID, userID int64, isPublic bool) {
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User) org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
expectedNumMembers := org.NumMembers expectedNumMembers := org.NumMembers
if !unittest.BeanExists(t, &OrgUser{OrgID: orgID, UID: userID}) { if !unittest.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) {
expectedNumMembers++ expectedNumMembers++
} }
assert.NoError(t, AddOrgUser(orgID, userID)) assert.NoError(t, organization.AddOrgUser(orgID, userID))
ou := &OrgUser{OrgID: orgID, UID: userID} ou := &organization.OrgUser{OrgID: orgID, UID: userID}
unittest.AssertExistsAndLoadBean(t, ou) unittest.AssertExistsAndLoadBean(t, ou)
assert.Equal(t, isPublic, ou.IsPublic) assert.Equal(t, isPublic, ou.IsPublic)
org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User) 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 setting.Service.DefaultOrgMemberVisible = true
testSuccess(6, 3, true) testSuccess(6, 3, true)
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, &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)
} }

@ -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",
)
}

@ -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
}

@ -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)
}

@ -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))
}

@ -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)
}

@ -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)
}

@ -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)
}

@ -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
}

@ -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()
}

@ -0,0 +1,109 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package organization
import (
"context"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"xorm.io/builder"
)
// TeamUser represents an team-user relation.
type TeamUser struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
UID int64 `xorm:"UNIQUE(s)"`
}
// IsTeamMember returns true if given user is a member of team.
func IsTeamMember(ctx context.Context, orgID, teamID, userID int64) (bool, error) {
return db.GetEngine(ctx).
Where("org_id=?", orgID).
And("team_id=?", teamID).
And("uid=?", userID).
Table("team_user").
Exist()
}
// GetTeamUsersByTeamID returns team users for a team
func GetTeamUsersByTeamID(ctx context.Context, teamID int64) ([]*TeamUser, error) {
teamUsers := make([]*TeamUser, 0, 10)
return teamUsers, db.GetEngine(ctx).
Where("team_id=?", teamID).
Find(&teamUsers)
}
// SearchMembersOptions holds the search options
type SearchMembersOptions struct {
db.ListOptions
TeamID int64
}
func (opts SearchMembersOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.TeamID > 0 {
cond = cond.And(builder.Eq{"": opts.TeamID})
}
return cond
}
// GetTeamMembers returns all members in given team of organization.
func GetTeamMembers(ctx context.Context, opts *SearchMembersOptions) ([]*user_model.User, error) {
var members []*user_model.User
sess := db.GetEngine(ctx)
if opts.TeamID > 0 {
sess = sess.In("id",
builder.Select("uid").
From("team_user").
Where(builder.Eq{"team_id": opts.TeamID}),
)
}
if opts.PageSize > 0 && opts.Page > -1 {
sess = sess.Limit(opts.PageSize, opts.Page*opts.PageSize)
}
if err := sess.OrderBy("full_name, name").Find(&members); err != nil {
return nil, err
}
return members, nil
}
// GetUserOrgTeams returns all teams that user belongs to in given organization.
func GetUserOrgTeams(ctx context.Context, orgID, userID int64) (teams []*Team, err error) {
return teams, db.GetEngine(ctx).
Join("INNER", "team_user", "team_user.team_id = team.id").
Where("team.org_id = ?", orgID).
And("team_user.uid=?", userID).
Find(&teams)
}
// GetUserRepoTeams returns user repo's teams
func GetUserRepoTeams(ctx context.Context, orgID, userID, repoID int64) (teams []*Team, err error) {
return teams, db.GetEngine(ctx).
Join("INNER", "team_user", "team_user.team_id = team.id").
Join("INNER", "team_repo", "team_repo.team_id = team.id").
Where("team.org_id = ?", orgID).
And("team_user.uid=?", userID).
And("team_repo.repo_id=?", repoID).
Find(&teams)
}
// IsUserInTeams returns if a user in some teams
func IsUserInTeams(ctx context.Context, userID int64, teamIDs []int64) (bool, error) {
return db.GetEngine(ctx).Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser))
}
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
func UsersInTeamsCount(userIDs, teamIDs []int64) (int64, error) {
var ids []int64
if err := db.GetEngine(db.DefaultContext).In("uid", userIDs).In("team_id", teamIDs).
Table("team_user").
Cols("uid").GroupBy("uid").Find(&ids); err != nil {
return 0, err
}
return int64(len(ids)), nil
}

@ -9,6 +9,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
@ -83,7 +84,7 @@ func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) {
return false, nil return false, nil
} }
in, err := IsUserInTeams(userID, pt.AllowlistTeamIDs) in, err := organization.IsUserInTeams(db.DefaultContext, userID, pt.AllowlistTeamIDs)
if err != nil { if err != nil {
return false, err return false, err
} }

@ -20,6 +20,7 @@ import (
admin_model "code.gitea.io/gitea/models/admin" admin_model "code.gitea.io/gitea/models/admin"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "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 // 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 { if err := repo.GetOwner(db.DefaultContext); err != nil {
return nil, err return nil, err
} }
@ -276,7 +277,7 @@ func GetReviewerTeams(repo *repo_model.Repository) ([]*Team, error) {
return nil, nil 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 { if err != nil {
return nil, err 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) { if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) {
return true, nil return true, nil
} }
ownedOrgs, err := GetOrgsCanCreateRepoByUserID(user.ID) ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(user.ID)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -372,7 +373,7 @@ func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, er
} }
if repo.Owner.IsOrganization() { if repo.Owner.IsOrganization() {
isOwner, err := OrgFromUser(repo.Owner).IsOwnedBy(user.ID) isOwner, err := organization.OrgFromUser(repo.Owner).IsOwnedBy(user.ID)
if err != nil { if err != nil {
return false, err return false, err
} else if isOwner { } 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. // Give access to all members in teams with access to all repositories.
if u.IsOrganization() { if u.IsOrganization() {
teams, err := OrgFromUser(u).loadTeams(db.GetEngine(ctx)) teams, err := organization.FindOrgTeams(ctx, u.ID)
if err != nil { if err != nil {
return fmt.Errorf("loadTeams: %v", err) return fmt.Errorf("loadTeams: %v", err)
} }
for _, t := range teams { for _, t := range teams {
if t.IncludesAllRepositories { 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) 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) return fmt.Errorf("isUserRepoAdmin: %v", err)
} else if !isAdmin { } else if !isAdmin {
// Make creator repo admin if it wasn't assigned automatically // 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() { if org.IsOrganization() {
teams, err := OrgFromUser(org).loadTeams(sess) teams, err := organization.FindOrgTeams(ctx, org.ID)
if err != nil { if err != nil {
return err return err
} }
for _, t := range teams { for _, t := range teams {
if !t.hasRepository(sess, repoID) { if !hasRepository(ctx, t, repoID) {
continue continue
} else if err = t.removeRepository(ctx, repo, false); err != nil { } else if err = removeRepository(ctx, t, repo, false); err != nil {
return err return err
} }
} }
@ -1326,7 +1327,7 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error
if err != nil { if err != nil {
return fmt.Errorf("GetRepositoryByID: %v", err) return fmt.Errorf("GetRepositoryByID: %v", err)
} }
has, err := isUserRepoAdmin(sess, repo, doer) has, err := isUserRepoAdmin(ctx, repo, doer)
if err != nil { if err != nil {
return fmt.Errorf("GetUserRepoPermission: %v", err) return fmt.Errorf("GetUserRepoPermission: %v", err)
} else if !has { } else if !has {

@ -751,37 +751,3 @@ func countRepositories(userID int64, private bool) int64 {
func CountRepositories(private bool) int64 { func CountRepositories(private bool) int64 {
return countRepositories(-1, private) 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)
}

@ -0,0 +1,87 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"context"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
)
// GetStarredRepos returns the repos starred by a particular user
func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, error) {
sess := db.GetEngine(db.DefaultContext).Where("star.uid=?", userID).
Join("LEFT", "star", "`repository`.id=`star`.repo_id")
if !private {
sess = sess.And("is_private=?", false)
}
if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions)
repos := make([]*Repository, 0, listOptions.PageSize)
return repos, sess.Find(&repos)
}
repos := make([]*Repository, 0, 10)
return repos, sess.Find(&repos)
}
// GetWatchedRepos returns the repos watched by a particular user
func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, int64, error) {
sess := db.GetEngine(db.DefaultContext).Where("watch.user_id=?", userID).
And("`watch`.mode<>?", WatchModeDont).
Join("LEFT", "watch", "`repository`.id=`watch`.repo_id")
if !private {
sess = sess.And("is_private=?", false)
}
if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions)
repos := make([]*Repository, 0, listOptions.PageSize)
total, err := sess.FindAndCount(&repos)
return repos, total, err
}
repos := make([]*Repository, 0, 10)
total, err := sess.FindAndCount(&repos)
return repos, total, err
}
// CountUserRepositories returns number of repositories user owns.
// Argument private only takes effect when it is false,
// set it true to count all repositories.
func CountUserRepositories(userID int64, private bool) int64 {
return countRepositories(userID, private)
}
func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) {
return e.Count(&Repository{OwnerID: ownerID})
}
func getPublicRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
return e.Where("is_private = ?", false).Count(&Repository{OwnerID: u.ID})
}
func getPrivateRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
return e.Where("is_private = ?", true).Count(&Repository{OwnerID: u.ID})
}
// GetRepositoryCount returns the total number of repositories of user.
func GetRepositoryCount(ctx context.Context, ownerID int64) (int64, error) {
return getRepositoryCount(db.GetEngine(ctx), ownerID)
}
// GetPublicRepositoryCount returns the total number of public repositories of user.
func GetPublicRepositoryCount(u *user_model.User) (int64, error) {
return getPublicRepositoryCount(db.GetEngine(db.DefaultContext), u)
}
// GetPrivateRepositoryCount returns the total number of private repositories of user.
func GetPrivateRepositoryCount(u *user_model.User) (int64, error) {
return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u)
}

@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "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) 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 // 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) { func IsOwnerMemberCollaborator(repo *repo_model.Repository, userID int64) (bool, error) {
if repo.OwnerID == userID { 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"). Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id").
Where("team_repo.repo_id = ?", repo.ID). Where("team_repo.repo_id = ?", repo.ID).
And("team_unit.`type` = ?", unit.TypeCode). 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 { if err != nil {
return false, err return false, err
} }

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
perm_model "code.gitea.io/gitea/models/perm" perm_model "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "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 // 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 // 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 perm.AccessMode = perm_model.AccessModeNone
return return
} }
@ -232,7 +233,7 @@ func getUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
} }
// get units mode from teams // 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 { if err != nil {
return return
} }
@ -249,7 +250,7 @@ func getUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
for _, u := range repo.Units { for _, u := range repo.Units {
var found bool var found bool
for _, team := range teams { for _, team := range teams {
teamMode := team.unitAccessMode(e, u.Type) teamMode := team.UnitAccessMode(ctx, u.Type)
if teamMode > perm_model.AccessModeNone { if teamMode > perm_model.AccessModeNone {
m := perm.UnitsMode[u.Type] m := perm.UnitsMode[u.Type]
if m < teamMode { 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 // IsUserRepoAdmin return true if user has admin right of a repo
func IsUserRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bool, error) { 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 { if user == nil || repo == nil {
return false, nil return false, nil
} }
@ -311,6 +312,7 @@ func isUserRepoAdmin(e db.Engine, repo *repo_model.Repository, user *user_model.
return true, nil return true, nil
} }
e := db.GetEngine(ctx)
mode, err := accessLevel(e, user, repo) mode, err := accessLevel(e, user, repo)
if err != nil { if err != nil {
return false, err return false, err
@ -319,7 +321,7 @@ func isUserRepoAdmin(e db.Engine, repo *repo_model.Repository, user *user_model.
return true, nil 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 { if err != nil {
return false, err return false, err
} }

@ -8,6 +8,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
perm_model "code.gitea.io/gitea/models/perm" perm_model "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
@ -227,8 +228,8 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
} }
// update team information and then check permission // update team information and then check permission
team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 5}).(*Team) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team)
err = UpdateTeamUnits(team, nil) err = organization.UpdateTeamUnits(team, nil)
assert.NoError(t, err) assert.NoError(t, err)
perm, err = GetUserRepoPermission(repo, owner) perm, err = GetUserRepoPermission(repo, owner)
assert.NoError(t, err) assert.NoError(t, err)

@ -10,6 +10,7 @@ import (
"os" "os"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -26,7 +27,7 @@ type RepoTransfer struct {
Recipient *user_model.User `xorm:"-"` Recipient *user_model.User `xorm:"-"`
RepoID int64 RepoID int64
TeamIDs []int64 TeamIDs []int64
Teams []*Team `xorm:"-"` Teams []*organization.Team `xorm:"-"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL updated"` 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) { if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) {
for _, v := range r.TeamIDs { for _, v := range r.TeamIDs {
team, err := GetTeamByID(v) team, err := organization.GetTeamByID(v)
if err != nil { if err != nil {
return err return err
} }
@ -87,7 +88,7 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool {
return r.RecipientID == u.ID return r.RecipientID == u.ID
} }
allowed, err := CanCreateOrgRepo(r.RecipientID, u.ID) allowed, err := organization.CanCreateOrgRepo(r.RecipientID, u.ID)
if err != nil { if err != nil {
log.Error("CanCreateOrgRepo: %v", err) log.Error("CanCreateOrgRepo: %v", err)
return false return false
@ -152,7 +153,7 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
// CreatePendingRepositoryTransfer transfer a repo from one owner to a new one. // CreatePendingRepositoryTransfer transfer a repo from one owner to a new one.
// it marks the repository transfer as "pending" // 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() ctx, committer, err := db.TxContext()
if err != nil { if err != nil {
return err return err
@ -296,7 +297,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
} }
if c.ID != newOwner.ID { 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 { if err != nil {
return fmt.Errorf("IsOrgMember: %v", err) return fmt.Errorf("IsOrgMember: %v", err)
} else if !isMember { } else if !isMember {
@ -312,19 +313,19 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
// Remove old team-repository relations. // Remove old team-repository relations.
if oldOwner.IsOrganization() { 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) return fmt.Errorf("removeOrgRepo: %v", err)
} }
} }
if newOwner.IsOrganization() { if newOwner.IsOrganization() {
teams, err := OrgFromUser(newOwner).loadTeams(sess) teams, err := organization.FindOrgTeams(ctx, newOwner.ID)
if err != nil { if err != nil {
return fmt.Errorf("LoadTeams: %v", err) return fmt.Errorf("LoadTeams: %v", err)
} }
for _, t := range teams { for _, t := range teams {
if t.IncludesAllRepositories { 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) return fmt.Errorf("addRepository: %v", err)
} }
} }

@ -10,6 +10,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -61,7 +62,7 @@ type Review struct {
Reviewer *user_model.User `xorm:"-"` Reviewer *user_model.User `xorm:"-"`
ReviewerID int64 `xorm:"index"` ReviewerID int64 `xorm:"index"`
ReviewerTeamID int64 `xorm:"NOT NULL DEFAULT 0"` ReviewerTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
ReviewerTeam *Team `xorm:"-"` ReviewerTeam *organization.Team `xorm:"-"`
OriginalAuthor string OriginalAuthor string
OriginalAuthorID int64 OriginalAuthorID int64
Issue *Issue `xorm:"-"` Issue *Issue `xorm:"-"`
@ -114,12 +115,12 @@ func (r *Review) loadReviewer(e db.Engine) (err error) {
return 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 { if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil {
return return
} }
r.ReviewerTeam, err = getTeamByID(e, r.ReviewerTeamID) r.ReviewerTeam, err = organization.GetTeamByIDCtx(ctx, r.ReviewerTeamID)
return return
} }
@ -130,7 +131,7 @@ func (r *Review) LoadReviewer() error {
// LoadReviewerTeam loads reviewer team // LoadReviewerTeam loads reviewer team
func (r *Review) LoadReviewerTeam() error { func (r *Review) LoadReviewerTeam() error {
return r.loadReviewerTeam(db.GetEngine(db.DefaultContext)) return r.loadReviewerTeam(db.DefaultContext)
} }
// LoadAttributes loads all attributes except CodeComments // 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 { if err = r.loadReviewer(e); err != nil {
return return
} }
if err = r.loadReviewerTeam(e); err != nil { if err = r.loadReviewerTeam(ctx); err != nil {
return return
} }
return return
@ -221,7 +222,7 @@ type CreateReviewOptions struct {
Type ReviewType Type ReviewType
Issue *Issue Issue *Issue
Reviewer *user_model.User Reviewer *user_model.User
ReviewerTeam *Team ReviewerTeam *organization.Team
Official bool Official bool
CommitID string CommitID string
Stale bool 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) // 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) 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) pr, err := getPullRequestByIssueID(db.GetEngine(ctx), issue.ID)
if err != nil { if err != nil {
return false, err return false, err
@ -272,7 +273,7 @@ func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *Team) (bool
} }
if !pr.ProtectedBranch.EnableApprovalsWhitelist { 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 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 { 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 { if err != nil {
return nil, nil, err return nil, nil, err
} else if !ok { } 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 // 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() ctx, committer, err := db.TxContext()
if err != nil { if err != nil {
return nil, err 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 // 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() ctx, committer, err := db.TxContext()
if err != nil { if err != nil {
return nil, err return nil, err

@ -8,6 +8,7 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/models/webhook"
@ -47,7 +48,7 @@ type IssueByRepositoryCount struct {
func GetStatistic() (stats Statistic) { func GetStatistic() (stats Statistic) {
e := db.GetEngine(db.DefaultContext) e := db.GetEngine(db.DefaultContext)
stats.Counter.User = user_model.CountUsers() 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.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
stats.Counter.Repo = repo_model.CountRepositories(true) stats.Counter.Repo = repo_model.CountRepositories(true)
stats.Counter.Watch, _ = e.Count(new(repo_model.Watch)) 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.Milestone, _ = e.Count(new(Milestone))
stats.Counter.Label, _ = e.Count(new(Label)) stats.Counter.Label, _ = e.Count(new(Label))
stats.Counter.HookTask, _ = e.Count(new(webhook.HookTask)) 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.Attachment, _ = e.Count(new(repo_model.Attachment))
stats.Counter.Project, _ = e.Count(new(Project)) stats.Counter.Project, _ = e.Count(new(Project))
stats.Counter.ProjectBoard, _ = e.Count(new(ProjectBoard)) stats.Counter.ProjectBoard, _ = e.Count(new(ProjectBoard))

@ -14,22 +14,13 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util" "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. // DeleteUser deletes models associated to an user.
func DeleteUser(ctx context.Context, u *user_model.User) (err error) { func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
e := db.GetEngine(ctx) 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.EmailAddress{UID: u.ID},
&user_model.UserOpenID{UID: u.ID}, &user_model.UserOpenID{UID: u.ID},
&Reaction{UserID: u.ID}, &Reaction{UserID: u.ID},
&TeamUser{UID: u.ID}, &organization.TeamUser{UID: u.ID},
&Collaboration{UserID: u.ID}, &Collaboration{UserID: u.ID},
&Stopwatch{UserID: u.ID}, &Stopwatch{UserID: u.ID},
&user_model.Setting{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 return nil
} }
// GetStarredRepos returns the repos starred by a particular user
func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]*repo_model.Repository, error) {
sess := db.GetEngine(db.DefaultContext).Where("star.uid=?", userID).
Join("LEFT", "star", "`repository`.id=`star`.repo_id")
if !private {
sess = sess.And("is_private=?", false)
}
if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions)
repos := make([]*repo_model.Repository, 0, listOptions.PageSize)
return repos, sess.Find(&repos)
}
repos := make([]*repo_model.Repository, 0, 10)
return repos, sess.Find(&repos)
}
// GetWatchedRepos returns the repos watched by a particular user
func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]*repo_model.Repository, int64, error) {
sess := db.GetEngine(db.DefaultContext).Where("watch.user_id=?", userID).
And("`watch`.mode<>?", repo_model.WatchModeDont).
Join("LEFT", "watch", "`repository`.id=`watch`.repo_id")
if !private {
sess = sess.And("is_private=?", false)
}
if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions)
repos := make([]*repo_model.Repository, 0, listOptions.PageSize)
total, err := sess.FindAndCount(&repos)
return repos, total, err
}
repos := make([]*repo_model.Repository, 0, 10)
total, err := sess.FindAndCount(&repos)
return repos, total, err
}
// IsUserVisibleToViewer check if viewer is able to see user profile
func IsUserVisibleToViewer(u, viewer *user_model.User) bool {
return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer)
}
func isUserVisibleToViewer(e db.Engine, u, viewer *user_model.User) bool {
if viewer != nil && viewer.IsAdmin {
return true
}
switch u.Visibility {
case structs.VisibleTypePublic:
return true
case structs.VisibleTypeLimited:
if viewer == nil || viewer.IsRestricted {
return false
}
return true
case structs.VisibleTypePrivate:
if viewer == nil || viewer.IsRestricted {
return false
}
// If they follow - they see each over
follower := user_model.IsFollowing(u.ID, viewer.ID)
if follower {
return true
}
// Now we need to check if they in some organization together
count, err := e.Table("team_user").
Where(
builder.And(
builder.Eq{"uid": viewer.ID},
builder.Or(
builder.Eq{"org_id": u.ID},
builder.In("org_id",
builder.Select("org_id").
From("team_user", "t2").
Where(builder.Eq{"uid": u.ID}))))).
Count(new(TeamUser))
if err != nil {
return false
}
if count < 0 {
// No common organization
return false
}
// they are in an organization together
return true
}
return false
}

@ -1211,3 +1211,59 @@ func GetAdminUser() (*User, error) {
return &admin, nil return &admin, nil
} }
// IsUserVisibleToViewer check if viewer is able to see user profile
func IsUserVisibleToViewer(u, viewer *User) bool {
return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer)
}
func isUserVisibleToViewer(e db.Engine, u, viewer *User) bool {
if viewer != nil && viewer.IsAdmin {
return true
}
switch u.Visibility {
case structs.VisibleTypePublic:
return true
case structs.VisibleTypeLimited:
if viewer == nil || viewer.IsRestricted {
return false
}
return true
case structs.VisibleTypePrivate:
if viewer == nil || viewer.IsRestricted {
return false
}
// If they follow - they see each over
follower := IsFollowing(u.ID, viewer.ID)
if follower {
return true
}
// Now we need to check if they in some organization together
count, err := e.Table("team_user").
Where(
builder.And(
builder.Eq{"uid": viewer.ID},
builder.Or(
builder.Eq{"org_id": u.ID},
builder.In("org_id",
builder.Select("org_id").
From("team_user", "t2").
Where(builder.Eq{"uid": u.ID}))))).
Count()
if err != nil {
return false
}
if count < 0 {
// No common organization
return false
}
// they are in an organization together
return true
}
return false
}

@ -6,6 +6,7 @@ package models
import ( import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
@ -23,11 +24,11 @@ func GetUserHeatmapDataByUser(user, doer *user_model.User) ([]*UserHeatmapData,
} }
// GetUserHeatmapDataByUserTeam returns an array of 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) 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) hdata := make([]*UserHeatmapData, 0)
if !activityReadable(user, doer) { if !activityReadable(user, doer) {

@ -5,7 +5,6 @@
package models package models
import ( import (
"fmt"
"testing" "testing"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
@ -42,59 +41,3 @@ func TestUnfollowUser(t *testing.T) {
unittest.CheckConsistencyFor(t, &user_model.User{}) unittest.CheckConsistencyFor(t, &user_model.User{})
} }
func TestUserIsPublicMember(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
tt := []struct {
uid int64
orgid int64
expected bool
}{
{2, 3, true},
{4, 3, false},
{5, 6, true},
{5, 7, false},
}
for _, v := range tt {
t.Run(fmt.Sprintf("UserId%dIsPublicMemberOf%d", v.uid, v.orgid), func(t *testing.T) {
testUserIsPublicMember(t, v.uid, v.orgid, v.expected)
})
}
}
func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
user, err := user_model.GetUserByID(uid)
assert.NoError(t, err)
is, err := IsPublicMembership(orgID, user.ID)
assert.NoError(t, err)
assert.Equal(t, expected, is)
}
func TestIsUserOrgOwner(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
tt := []struct {
uid int64
orgid int64
expected bool
}{
{2, 3, true},
{4, 3, false},
{5, 6, true},
{5, 7, true},
}
for _, v := range tt {
t.Run(fmt.Sprintf("UserId%dIsOrgOwnerOf%d", v.uid, v.orgid), func(t *testing.T) {
testIsUserOrgOwner(t, v.uid, v.orgid, v.expected)
})
}
}
func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
user, err := user_model.GetUserByID(uid)
assert.NoError(t, err)
is, err := IsOrganizationOwner(orgID, user.ID)
assert.NoError(t, err)
assert.Equal(t, expected, is)
}

@ -5,9 +5,11 @@
package models package models
import ( import (
"context"
"fmt" "fmt"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "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 { for _, user := range users {
results[user.ID] = false // Set default to false 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 { if err == nil {
for _, owner := range ownerMaps { for _, owner := range ownerMaps {
results[owner.UID] = true results[owner.UID] = true
@ -27,13 +29,13 @@ func IsUserOrgOwner(users user_model.UserList, orgID int64) map[int64]bool {
return results 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 { if len(users) == 0 {
return nil, nil return nil, nil
} }
ownerTeam, err := getOwnerTeam(e, orgID) ownerTeam, err := organization.GetOwnerTeam(ctx, orgID)
if err != nil { if err != nil {
if IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
log.Error("Organization does not have owner team: %d", orgID) log.Error("Organization does not have owner team: %d", orgID)
return nil, nil return nil, nil
} }
@ -41,8 +43,8 @@ func loadOrganizationOwners(e db.Engine, users user_model.UserList, orgID int64)
} }
userIDs := users.GetUserIDs() userIDs := users.GetUserIDs()
ownerMaps := make(map[int64]*TeamUser) ownerMaps := make(map[int64]*organization.TeamUser)
err = e.In("uid", userIDs). err = db.GetEngine(ctx).In("uid", userIDs).
And("org_id=?", orgID). And("org_id=?", orgID).
And("team_id=?", ownerTeam.ID). And("team_id=?", ownerTeam.ID).
Find(&ownerMaps) Find(&ownerMaps)

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"github.com/stretchr/testify/assert" "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) { func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) {
org, err := GetOrgByID(orgID) org, err := organization.GetOrgByID(orgID)
assert.NoError(t, err) assert.NoError(t, err)
_, membersIsPublic, err := org.GetMembers() _, membersIsPublic, err := org.GetMembers()
assert.NoError(t, err) assert.NoError(t, err)
@ -60,7 +61,7 @@ func TestUserListIsUserOrgOwner(t *testing.T) {
} }
func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) { func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) {
org, err := GetOrgByID(orgID) org, err := organization.GetOrgByID(orgID)
assert.NoError(t, err) assert.NoError(t, err)
members, _, err := org.GetMembers() members, _, err := org.GetMembers()
assert.NoError(t, err) assert.NoError(t, err)

@ -4,12 +4,10 @@
package context package context
import ( import "code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models"
)
// APIOrganization contains organization and team // APIOrganization contains organization and team
type APIOrganization struct { type APIOrganization struct {
Organization *models.Organization Organization *organization.Organization
Team *models.Team Team *organization.Team
} }

@ -8,7 +8,7 @@ package context
import ( import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
) )
@ -19,12 +19,12 @@ type Organization struct {
IsMember bool IsMember bool
IsTeamMember bool // Is member of team. IsTeamMember bool // Is member of team.
IsTeamAdmin bool // In owner team or team that has admin permission level. IsTeamAdmin bool // In owner team or team that has admin permission level.
Organization *models.Organization Organization *organization.Organization
OrgLink string OrgLink string
CanCreateOrgRepo bool CanCreateOrgRepo bool
Team *models.Team Team *organization.Team
Teams []*models.Team Teams []*organization.Team
} }
// HandleOrgAssignment handles organization assignment // HandleOrgAssignment handles organization assignment
@ -51,9 +51,9 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
orgName := ctx.Params(":org") orgName := ctx.Params(":org")
var err error var err error
ctx.Org.Organization, err = models.GetOrgByName(orgName) ctx.Org.Organization, err = organization.GetOrgByName(orgName)
if err != nil { if err != nil {
if models.IsErrOrgNotExist(err) { if organization.IsErrOrgNotExist(err) {
redirectUserID, err := user_model.LookupUserRedirect(orgName) redirectUserID, err := user_model.LookupUserRedirect(orgName)
if err == nil { if err == nil {
RedirectToUser(ctx, orgName, redirectUserID) RedirectToUser(ctx, orgName, redirectUserID)
@ -120,7 +120,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
ctx.Data["IsPublicMember"] = func(uid int64) bool { ctx.Data["IsPublicMember"] = func(uid int64) bool {
is, _ := models.IsPublicMembership(ctx.Org.Organization.ID, uid) is, _ := organization.IsPublicMembership(ctx.Org.Organization.ID, uid)
return is return is
} }
ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
@ -98,15 +99,15 @@ func ToBranchProtection(bp *models.ProtectedBranch) *api.BranchProtection {
if err != nil { if err != nil {
log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err) log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err)
} }
pushWhitelistTeams, err := models.GetTeamNamesByID(bp.WhitelistTeamIDs) pushWhitelistTeams, err := organization.GetTeamNamesByID(bp.WhitelistTeamIDs)
if err != nil { if err != nil {
log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err) log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err)
} }
mergeWhitelistTeams, err := models.GetTeamNamesByID(bp.MergeWhitelistTeamIDs) mergeWhitelistTeams, err := organization.GetTeamNamesByID(bp.MergeWhitelistTeamIDs)
if err != nil { if err != nil {
log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err) log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err)
} }
approvalsWhitelistTeams, err := models.GetTeamNamesByID(bp.ApprovalsWhitelistTeamIDs) approvalsWhitelistTeams, err := organization.GetTeamNamesByID(bp.ApprovalsWhitelistTeamIDs)
if err != nil { if err != nil {
log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err) log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err)
} }
@ -280,7 +281,7 @@ func ToDeployKey(apiLink string, key *asymkey_model.DeployKey) *api.DeployKey {
} }
// ToOrganization convert user_model.User to api.Organization // ToOrganization convert user_model.User to api.Organization
func ToOrganization(org *models.Organization) *api.Organization { func ToOrganization(org *organization.Organization) *api.Organization {
return &api.Organization{ return &api.Organization{
ID: org.ID, ID: org.ID,
AvatarURL: org.AsUser().AvatarLink(), AvatarURL: org.AsUser().AvatarLink(),
@ -294,8 +295,8 @@ func ToOrganization(org *models.Organization) *api.Organization {
} }
} }
// ToTeam convert models.Team to api.Team // ToTeam convert organization.Team to api.Team
func ToTeam(team *models.Team) *api.Team { func ToTeam(team *organization.Team) *api.Team {
if team == nil { if team == nil {
return nil return nil
} }

@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -22,13 +23,13 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
testTeamRepositories := func(teamID int64, repoIds []int64) { testTeamRepositories := func(teamID int64, repoIds []int64) {
team := unittest.AssertExistsAndLoadBean(t, &models.Team{ID: teamID}).(*models.Team) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team)
assert.NoError(t, team.GetRepositories(&models.SearchOrgTeamOptions{}), "%s: GetRepositories", team.Name) assert.NoError(t, team.GetRepositoriesCtx(db.DefaultContext), "%s: GetRepositories", team.Name)
assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name) assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name)
assert.Len(t, team.Repos, len(repoIds), "%s: repo count", team.Name) assert.Len(t, team.Repos, len(repoIds), "%s: repo count", team.Name)
for i, rid := range repoIds { for i, rid := range repoIds {
if rid > 0 { if rid > 0 {
assert.True(t, team.HasRepository(rid), "%s: HasRepository(%d) %d", rid, i) assert.True(t, models.HasRepository(team, rid), "%s: HasRepository(%d) %d", rid, i)
} }
} }
} }
@ -38,13 +39,13 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
assert.NoError(t, err, "GetUserByID") assert.NoError(t, err, "GetUserByID")
// Create org. // Create org.
org := &models.Organization{ org := &organization.Organization{
Name: "All_repo", Name: "All_repo",
IsActive: true, IsActive: true,
Type: user_model.UserTypeOrganization, Type: user_model.UserTypeOrganization,
Visibility: structs.VisibleTypePublic, Visibility: structs.VisibleTypePublic,
} }
assert.NoError(t, models.CreateOrganization(org, user), "CreateOrganization") assert.NoError(t, organization.CreateOrganization(org, user), "CreateOrganization")
// Check Owner team. // Check Owner team.
ownerTeam, err := org.GetOwnerTeam() ownerTeam, err := org.GetOwnerTeam()
@ -65,7 +66,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
assert.NoError(t, err, "GetOwnerTeam") assert.NoError(t, err, "GetOwnerTeam")
// Create teams and check repositories. // Create teams and check repositories.
teams := []*models.Team{ teams := []*organization.Team{
ownerTeam, ownerTeam,
{ {
OrgID: org.ID, OrgID: org.ID,
@ -144,5 +145,5 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
assert.NoError(t, models.DeleteRepository(user, org.ID, rid), "DeleteRepository %d", i) assert.NoError(t, models.DeleteRepository(user, org.ID, rid), "DeleteRepository %d", i)
} }
} }
assert.NoError(t, models.DeleteOrganization(db.DefaultContext, org), "DeleteOrganization") assert.NoError(t, organization.DeleteOrganization(db.DefaultContext, org), "DeleteOrganization")
} }

@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -55,7 +56,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
repoPath := repo_model.RepoPath(u.Name, opts.RepoName) repoPath := repo_model.RepoPath(u.Name, opts.RepoName)
if u.IsOrganization() { if u.IsOrganization() {
t, err := models.OrgFromUser(u).GetOwnerTeam() t, err := organization.OrgFromUser(u).GetOwnerTeam()
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -25,6 +25,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/avatars" "code.gitea.io/gitea/models/avatars"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
@ -569,7 +570,7 @@ func Avatar(item interface{}, others ...interface{}) template.HTML {
if src != "" { if src != "" {
return AvatarHTML(src, size, class, t.DisplayName()) return AvatarHTML(src, size, class, t.DisplayName())
} }
case *models.Organization: case *organization.Organization:
src := t.AsUser().AvatarLinkWithSize(size * setting.Avatar.RenderedSizeFactor) src := t.AsUser().AvatarLinkWithSize(size * setting.Avatar.RenderedSizeFactor)
if src != "" { if src != "" {
return AvatarHTML(src, size, class, t.AsUser().DisplayName()) return AvatarHTML(src, size, class, t.AsUser().DisplayName())

@ -8,8 +8,8 @@ package admin
import ( import (
"net/http" "net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
@ -52,7 +52,7 @@ func CreateOrg(ctx *context.APIContext) {
visibility = api.VisibilityModes[form.Visibility] visibility = api.VisibilityModes[form.Visibility]
} }
org := &models.Organization{ org := &organization.Organization{
Name: form.UserName, Name: form.UserName,
FullName: form.FullName, FullName: form.FullName,
Description: form.Description, Description: form.Description,
@ -63,7 +63,7 @@ func CreateOrg(ctx *context.APIContext) {
Visibility: visibility, Visibility: visibility,
} }
if err := models.CreateOrganization(org, ctx.ContextUser); err != nil { if err := organization.CreateOrganization(org, ctx.ContextUser); err != nil {
if user_model.IsErrUserAlreadyExist(err) || if user_model.IsErrUserAlreadyExist(err) ||
db.IsErrNameReserved(err) || db.IsErrNameReserved(err) ||
db.IsErrNameCharsNotAllowed(err) || db.IsErrNameCharsNotAllowed(err) ||
@ -115,7 +115,7 @@ func GetAllOrgs(ctx *context.APIContext) {
} }
orgs := make([]*api.Organization, len(users)) orgs := make([]*api.Organization, len(users))
for i := range users { for i := range users {
orgs[i] = convert.ToOrganization(models.OrgFromUser(users[i])) orgs[i] = convert.ToOrganization(organization.OrgFromUser(users[i]))
} }
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)

@ -71,6 +71,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -309,7 +310,7 @@ func reqOrgOwnership() func(ctx *context.APIContext) {
return return
} }
isOwner, err := models.IsOrganizationOwner(orgID, ctx.Doer.ID) isOwner, err := organization.IsOrganizationOwner(ctx, orgID, ctx.Doer.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err) ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err)
return return
@ -336,7 +337,7 @@ func reqTeamMembership() func(ctx *context.APIContext) {
} }
orgID := ctx.Org.Team.OrgID orgID := ctx.Org.Team.OrgID
isOwner, err := models.IsOrganizationOwner(orgID, ctx.Doer.ID) isOwner, err := organization.IsOrganizationOwner(ctx, orgID, ctx.Doer.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err) ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err)
return return
@ -344,11 +345,11 @@ func reqTeamMembership() func(ctx *context.APIContext) {
return return
} }
if isTeamMember, err := models.IsTeamMember(orgID, ctx.Org.Team.ID, ctx.Doer.ID); err != nil { if isTeamMember, err := organization.IsTeamMember(ctx, orgID, ctx.Org.Team.ID, ctx.Doer.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "IsTeamMember", err) ctx.Error(http.StatusInternalServerError, "IsTeamMember", err)
return return
} else if !isTeamMember { } else if !isTeamMember {
isOrgMember, err := models.IsOrganizationMember(orgID, ctx.Doer.ID) isOrgMember, err := organization.IsOrganizationMember(ctx, orgID, ctx.Doer.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err) ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
} else if isOrgMember { } else if isOrgMember {
@ -378,7 +379,7 @@ func reqOrgMembership() func(ctx *context.APIContext) {
return return
} }
if isMember, err := models.IsOrganizationMember(orgID, ctx.Doer.ID); err != nil { if isMember, err := organization.IsOrganizationMember(ctx, orgID, ctx.Doer.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err) ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
return return
} else if !isMember { } else if !isMember {
@ -427,9 +428,9 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) {
var err error var err error
if assignOrg { if assignOrg {
ctx.Org.Organization, err = models.GetOrgByName(ctx.Params(":org")) ctx.Org.Organization, err = organization.GetOrgByName(ctx.Params(":org"))
if err != nil { if err != nil {
if models.IsErrOrgNotExist(err) { if organization.IsErrOrgNotExist(err) {
redirectUserID, err := user_model.LookupUserRedirect(ctx.Params(":org")) redirectUserID, err := user_model.LookupUserRedirect(ctx.Params(":org"))
if err == nil { if err == nil {
context.RedirectToUser(ctx.Context, ctx.Params(":org"), redirectUserID) context.RedirectToUser(ctx.Context, ctx.Params(":org"), redirectUserID)
@ -447,9 +448,9 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) {
} }
if assignTeam { if assignTeam {
ctx.Org.Team, err = models.GetTeamByID(ctx.ParamsInt64(":teamid")) ctx.Org.Team, err = organization.GetTeamByID(ctx.ParamsInt64(":teamid"))
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.NotFound() ctx.NotFound()
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetTeamById", err) ctx.Error(http.StatusInternalServerError, "GetTeamById", err)

@ -9,6 +9,7 @@ import (
"net/url" "net/url"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -19,19 +20,19 @@ import (
// listMembers list an organization's members // listMembers list an organization's members
func listMembers(ctx *context.APIContext, publicOnly bool) { func listMembers(ctx *context.APIContext, publicOnly bool) {
opts := &models.FindOrgMembersOpts{ opts := &organization.FindOrgMembersOpts{
OrgID: ctx.Org.Organization.ID, OrgID: ctx.Org.Organization.ID,
PublicOnly: publicOnly, PublicOnly: publicOnly,
ListOptions: utils.GetListOptions(ctx), ListOptions: utils.GetListOptions(ctx),
} }
count, err := models.CountOrgMembers(opts) count, err := organization.CountOrgMembers(opts)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
} }
members, _, err := models.FindOrgMembers(opts) members, _, err := organization.FindOrgMembers(opts)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
@ -190,7 +191,7 @@ func IsPublicMember(ctx *context.APIContext) {
if ctx.Written() { if ctx.Written() {
return return
} }
is, err := models.IsPublicMembership(ctx.Org.Organization.ID, userToCheck.ID) is, err := organization.IsPublicMembership(ctx.Org.Organization.ID, userToCheck.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsPublicMembership", err) ctx.Error(http.StatusInternalServerError, "IsPublicMembership", err)
return return
@ -234,7 +235,7 @@ func PublicizeMember(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "", "Cannot publicize another member") ctx.Error(http.StatusForbidden, "", "Cannot publicize another member")
return return
} }
err := models.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToPublicize.ID, true) err := organization.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToPublicize.ID, true)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err) ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err)
return return
@ -274,7 +275,7 @@ func ConcealMember(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "", "Cannot conceal another member") ctx.Error(http.StatusForbidden, "", "Cannot conceal another member")
return return
} }
err := models.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToConceal.ID, false) err := organization.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToConceal.ID, false)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err) ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err)
return return
@ -308,8 +309,8 @@ func DeleteMember(ctx *context.APIContext) {
if ctx.Written() { if ctx.Written() {
return return
} }
if err := ctx.Org.Organization.RemoveMember(member.ID); err != nil { if err := models.RemoveOrgUser(ctx.Org.Organization.ID, member.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "RemoveMember", err) ctx.Error(http.StatusInternalServerError, "RemoveOrgUser", err)
} }
ctx.Status(http.StatusNoContent) ctx.Status(http.StatusNoContent)
} }

@ -8,8 +8,8 @@ package org
import ( import (
"net/http" "net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -25,17 +25,17 @@ func listUserOrgs(ctx *context.APIContext, u *user_model.User) {
listOptions := utils.GetListOptions(ctx) listOptions := utils.GetListOptions(ctx)
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == u.ID) showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == u.ID)
opts := models.FindOrgOptions{ opts := organization.FindOrgOptions{
ListOptions: listOptions, ListOptions: listOptions,
UserID: u.ID, UserID: u.ID,
IncludePrivate: showPrivate, IncludePrivate: showPrivate,
} }
orgs, err := models.FindOrgs(opts) orgs, err := organization.FindOrgs(opts)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "FindOrgs", err) ctx.Error(http.StatusInternalServerError, "FindOrgs", err)
return return
} }
maxResults, err := models.CountOrgs(opts) maxResults, err := organization.CountOrgs(opts)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "CountOrgs", err) ctx.Error(http.StatusInternalServerError, "CountOrgs", err)
return return
@ -135,12 +135,12 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
op := api.OrganizationPermissions{} op := api.OrganizationPermissions{}
if !models.HasOrgOrUserVisible(o, ctx.ContextUser) { if !organization.HasOrgOrUserVisible(ctx, o, ctx.ContextUser) {
ctx.NotFound("HasOrgOrUserVisible", nil) ctx.NotFound("HasOrgOrUserVisible", nil)
return return
} }
org := models.OrgFromUser(o) org := organization.OrgFromUser(o)
authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(ctx.ContextUser.ID) authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(ctx.ContextUser.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err) ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err)
@ -212,7 +212,7 @@ func GetAll(ctx *context.APIContext) {
} }
orgs := make([]*api.Organization, len(publicOrgs)) orgs := make([]*api.Organization, len(publicOrgs))
for i := range publicOrgs { for i := range publicOrgs {
orgs[i] = convert.ToOrganization(models.OrgFromUser(publicOrgs[i])) orgs[i] = convert.ToOrganization(organization.OrgFromUser(publicOrgs[i]))
} }
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)
@ -252,7 +252,7 @@ func Create(ctx *context.APIContext) {
visibility = api.VisibilityModes[form.Visibility] visibility = api.VisibilityModes[form.Visibility]
} }
org := &models.Organization{ org := &organization.Organization{
Name: form.UserName, Name: form.UserName,
FullName: form.FullName, FullName: form.FullName,
Description: form.Description, Description: form.Description,
@ -263,7 +263,7 @@ func Create(ctx *context.APIContext) {
Visibility: visibility, Visibility: visibility,
RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess, RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess,
} }
if err := models.CreateOrganization(org, ctx.Doer); err != nil { if err := organization.CreateOrganization(org, ctx.Doer); err != nil {
if user_model.IsErrUserAlreadyExist(err) || if user_model.IsErrUserAlreadyExist(err) ||
db.IsErrNameReserved(err) || db.IsErrNameReserved(err) ||
db.IsErrNameCharsNotAllowed(err) || db.IsErrNameCharsNotAllowed(err) ||
@ -295,7 +295,7 @@ func Get(ctx *context.APIContext) {
// "200": // "200":
// "$ref": "#/responses/Organization" // "$ref": "#/responses/Organization"
if !models.HasOrgOrUserVisible(ctx.Org.Organization.AsUser(), ctx.Doer) { if !organization.HasOrgOrUserVisible(ctx, ctx.Org.Organization.AsUser(), ctx.Doer) {
ctx.NotFound("HasOrgOrUserVisible", nil) ctx.NotFound("HasOrgOrUserVisible", nil)
return return
} }

@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit" unit_model "code.gitea.io/gitea/models/unit"
@ -47,7 +48,7 @@ func ListTeams(ctx *context.APIContext) {
// "200": // "200":
// "$ref": "#/responses/TeamList" // "$ref": "#/responses/TeamList"
teams, count, err := models.SearchOrgTeams(&models.SearchOrgTeamOptions{ teams, count, err := organization.SearchTeam(&organization.SearchTeamOptions{
ListOptions: utils.GetListOptions(ctx), ListOptions: utils.GetListOptions(ctx),
OrgID: ctx.Org.Organization.ID, OrgID: ctx.Org.Organization.ID,
}) })
@ -90,7 +91,7 @@ func ListUserTeams(ctx *context.APIContext) {
// "200": // "200":
// "$ref": "#/responses/TeamList" // "$ref": "#/responses/TeamList"
teams, count, err := models.GetUserTeams(&models.GetUserTeamOptions{ teams, count, err := organization.SearchTeam(&organization.SearchTeamOptions{
ListOptions: utils.GetListOptions(ctx), ListOptions: utils.GetListOptions(ctx),
UserID: ctx.Doer.ID, UserID: ctx.Doer.ID,
}) })
@ -104,7 +105,7 @@ func ListUserTeams(ctx *context.APIContext) {
for i := range teams { for i := range teams {
apiOrg, ok := cache[teams[i].OrgID] apiOrg, ok := cache[teams[i].OrgID]
if !ok { if !ok {
org, err := models.GetOrgByID(teams[i].OrgID) org, err := organization.GetOrgByID(teams[i].OrgID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserByID", err) ctx.Error(http.StatusInternalServerError, "GetUserByID", err)
return return
@ -150,11 +151,11 @@ func GetTeam(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, convert.ToTeam(ctx.Org.Team)) ctx.JSON(http.StatusOK, convert.ToTeam(ctx.Org.Team))
} }
func attachTeamUnits(team *models.Team, units []string) { func attachTeamUnits(team *organization.Team, units []string) {
unitTypes := unit_model.FindUnitTypes(units...) unitTypes := unit_model.FindUnitTypes(units...)
team.Units = make([]*models.TeamUnit, 0, len(units)) team.Units = make([]*organization.TeamUnit, 0, len(units))
for _, tp := range unitTypes { for _, tp := range unitTypes {
team.Units = append(team.Units, &models.TeamUnit{ team.Units = append(team.Units, &organization.TeamUnit{
OrgID: team.OrgID, OrgID: team.OrgID,
Type: tp, Type: tp,
AccessMode: team.AccessMode, AccessMode: team.AccessMode,
@ -170,10 +171,10 @@ func convertUnitsMap(unitsMap map[string]string) map[unit_model.Type]perm.Access
return res return res
} }
func attachTeamUnitsMap(team *models.Team, unitsMap map[string]string) { func attachTeamUnitsMap(team *organization.Team, unitsMap map[string]string) {
team.Units = make([]*models.TeamUnit, 0, len(unitsMap)) team.Units = make([]*organization.TeamUnit, 0, len(unitsMap))
for unitKey, p := range unitsMap { for unitKey, p := range unitsMap {
team.Units = append(team.Units, &models.TeamUnit{ team.Units = append(team.Units, &organization.TeamUnit{
OrgID: team.OrgID, OrgID: team.OrgID,
Type: unit_model.TypeFromKey(unitKey), Type: unit_model.TypeFromKey(unitKey),
AccessMode: perm.ParseAccessMode(p), AccessMode: perm.ParseAccessMode(p),
@ -210,7 +211,7 @@ func CreateTeam(ctx *context.APIContext) {
if p < perm.AccessModeAdmin && len(form.UnitsMap) > 0 { if p < perm.AccessModeAdmin && len(form.UnitsMap) > 0 {
p = unit_model.MinUnitAccessMode(convertUnitsMap(form.UnitsMap)) p = unit_model.MinUnitAccessMode(convertUnitsMap(form.UnitsMap))
} }
team := &models.Team{ team := &organization.Team{
OrgID: ctx.Org.Organization.ID, OrgID: ctx.Org.Organization.ID,
Name: form.Name, Name: form.Name,
Description: form.Description, Description: form.Description,
@ -231,7 +232,7 @@ func CreateTeam(ctx *context.APIContext) {
} }
if err := models.NewTeam(team); err != nil { if err := models.NewTeam(team); err != nil {
if models.IsErrTeamAlreadyExist(err) { if organization.IsErrTeamAlreadyExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err) ctx.Error(http.StatusUnprocessableEntity, "", err)
} else { } else {
ctx.Error(http.StatusInternalServerError, "NewTeam", err) ctx.Error(http.StatusInternalServerError, "NewTeam", err)
@ -368,7 +369,7 @@ func GetTeamMembers(ctx *context.APIContext) {
// "200": // "200":
// "$ref": "#/responses/UserList" // "$ref": "#/responses/UserList"
isMember, err := models.IsOrganizationMember(ctx.Org.Team.OrgID, ctx.Doer.ID) isMember, err := organization.IsOrganizationMember(ctx, ctx.Org.Team.OrgID, ctx.Doer.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err) ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
return return
@ -377,14 +378,17 @@ func GetTeamMembers(ctx *context.APIContext) {
return return
} }
if err := ctx.Org.Team.GetMembers(&models.SearchMembersOptions{ teamMembers, err := organization.GetTeamMembers(ctx, &organization.SearchMembersOptions{
ListOptions: utils.GetListOptions(ctx), ListOptions: utils.GetListOptions(ctx),
}); err != nil { TeamID: ctx.Org.Team.ID,
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetTeamMembers", err) ctx.Error(http.StatusInternalServerError, "GetTeamMembers", err)
return return
} }
members := make([]*api.User, len(ctx.Org.Team.Members)) members := make([]*api.User, len(ctx.Org.Team.Members))
for i, member := range ctx.Org.Team.Members { for i, member := range teamMembers {
members[i] = convert.ToUser(member, ctx.Doer) members[i] = convert.ToUser(member, ctx.Doer)
} }
@ -422,7 +426,7 @@ func GetTeamMember(ctx *context.APIContext) {
return return
} }
teamID := ctx.ParamsInt64("teamid") teamID := ctx.ParamsInt64("teamid")
isTeamMember, err := models.IsUserInTeams(u.ID, []int64{teamID}) isTeamMember, err := organization.IsUserInTeams(ctx, u.ID, []int64{teamID})
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsUserInTeams", err) ctx.Error(http.StatusInternalServerError, "IsUserInTeams", err)
return return
@ -462,7 +466,7 @@ func AddTeamMember(ctx *context.APIContext) {
if ctx.Written() { if ctx.Written() {
return return
} }
if err := ctx.Org.Team.AddMember(u.ID); err != nil { if err := models.AddTeamMember(ctx.Org.Team, u.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "AddMember", err) ctx.Error(http.StatusInternalServerError, "AddMember", err)
return return
} }
@ -499,8 +503,8 @@ func RemoveTeamMember(ctx *context.APIContext) {
return return
} }
if err := ctx.Org.Team.RemoveMember(u.ID); err != nil { if err := models.RemoveTeamMember(ctx.Org.Team, u.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "RemoveMember", err) ctx.Error(http.StatusInternalServerError, "RemoveTeamMember", err)
return return
} }
ctx.Status(http.StatusNoContent) ctx.Status(http.StatusNoContent)
@ -533,13 +537,16 @@ func GetTeamRepos(ctx *context.APIContext) {
// "$ref": "#/responses/RepositoryList" // "$ref": "#/responses/RepositoryList"
team := ctx.Org.Team team := ctx.Org.Team
if err := team.GetRepositories(&models.SearchOrgTeamOptions{ teamRepos, err := organization.GetTeamRepositories(ctx, &organization.SearchTeamRepoOptions{
ListOptions: utils.GetListOptions(ctx), ListOptions: utils.GetListOptions(ctx),
}); err != nil { TeamID: team.ID,
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
return
} }
repos := make([]*api.Repository, len(team.Repos)) repos := make([]*api.Repository, len(team.Repos))
for i, repo := range team.Repos { for i, repo := range teamRepos {
access, err := models.AccessLevel(ctx.Doer, repo) access, err := models.AccessLevel(ctx.Doer, repo)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
@ -606,7 +613,7 @@ func AddTeamRepository(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository") ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository")
return return
} }
if err := ctx.Org.Team.AddRepository(repo); err != nil { if err := models.AddRepository(ctx.Org.Team, repo); err != nil {
ctx.Error(http.StatusInternalServerError, "AddRepository", err) ctx.Error(http.StatusInternalServerError, "AddRepository", err)
return return
} }
@ -656,7 +663,7 @@ func RemoveTeamRepository(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository") ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository")
return return
} }
if err := ctx.Org.Team.RemoveRepository(repo.ID); err != nil { if err := models.RemoveRepository(ctx.Org.Team, repo.ID); err != nil {
ctx.Error(http.StatusInternalServerError, "RemoveRepository", err) ctx.Error(http.StatusInternalServerError, "RemoveRepository", err)
return return
} }
@ -707,14 +714,15 @@ func SearchTeam(ctx *context.APIContext) {
listOptions := utils.GetListOptions(ctx) listOptions := utils.GetListOptions(ctx)
opts := &models.SearchOrgTeamOptions{ opts := &organization.SearchTeamOptions{
UserID: ctx.Doer.ID,
Keyword: ctx.FormTrim("q"), Keyword: ctx.FormTrim("q"),
OrgID: ctx.Org.Organization.ID, OrgID: ctx.Org.Organization.ID,
IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"), IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"),
ListOptions: listOptions, ListOptions: listOptions,
} }
teams, maxResults, err := models.SearchOrgTeams(opts) teams, maxResults, err := organization.SearchTeam(opts)
if err != nil { if err != nil {
log.Error("SearchTeam failed: %v", err) log.Error("SearchTeam failed: %v", err)
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ ctx.JSON(http.StatusInternalServerError, map[string]interface{}{

@ -11,6 +11,7 @@ import (
"net/http" "net/http"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
@ -448,27 +449,27 @@ func CreateBranchProtection(ctx *context.APIContext) {
} }
var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64 var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
if repo.Owner.IsOrganization() { if repo.Owner.IsOrganization() {
whitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false) whitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
return return
} }
ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err) ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
return return
} }
mergeWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false) mergeWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
return return
} }
ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err) ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
return return
} }
approvalsWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false) approvalsWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
return return
} }
@ -692,9 +693,9 @@ func EditBranchProtection(ctx *context.APIContext) {
var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64 var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
if repo.Owner.IsOrganization() { if repo.Owner.IsOrganization() {
if form.PushWhitelistTeams != nil { if form.PushWhitelistTeams != nil {
whitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false) whitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
return return
} }
@ -705,9 +706,9 @@ func EditBranchProtection(ctx *context.APIContext) {
whitelistTeams = protectBranch.WhitelistTeamIDs whitelistTeams = protectBranch.WhitelistTeamIDs
} }
if form.MergeWhitelistTeams != nil { if form.MergeWhitelistTeams != nil {
mergeWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false) mergeWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
return return
} }
@ -718,9 +719,9 @@ func EditBranchProtection(ctx *context.APIContext) {
mergeWhitelistTeams = protectBranch.MergeWhitelistTeamIDs mergeWhitelistTeams = protectBranch.MergeWhitelistTeamIDs
} }
if form.ApprovalsWhitelistTeams != nil { if form.ApprovalsWhitelistTeams != nil {
approvalsWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false) approvalsWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
return return
} }

@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -108,9 +109,9 @@ func CreateFork(ctx *context.APIContext) {
if form.Organization == nil { if form.Organization == nil {
forker = ctx.Doer forker = ctx.Doer
} else { } else {
org, err := models.GetOrgByName(*form.Organization) org, err := organization.GetOrgByName(*form.Organization)
if err != nil { if err != nil {
if models.IsErrOrgNotExist(err) { if organization.IsErrOrgNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err) ctx.Error(http.StatusUnprocessableEntity, "", err)
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetOrgByName", err) ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -161,9 +162,9 @@ func SearchIssues(ctx *context.APIContext) {
ctx.Error(http.StatusBadRequest, "", "Owner organisation is required for filtering on team") ctx.Error(http.StatusBadRequest, "", "Owner organisation is required for filtering on team")
return return
} }
team, err := models.GetTeam(opts.OwnerID, ctx.FormString("team")) team, err := organization.GetTeam(opts.OwnerID, ctx.FormString("team"))
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusBadRequest, "Team not found", err) ctx.Error(http.StatusBadRequest, "Team not found", err)
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetUserByName", err) ctx.Error(http.StatusInternalServerError, "GetUserByName", err)

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -90,7 +91,7 @@ func Migrate(ctx *context.APIContext) {
if repoOwner.IsOrganization() { if repoOwner.IsOrganization() {
// Check ownership of organization. // Check ownership of organization.
isOwner, err := models.OrgFromUser(repoOwner).IsOwnedBy(ctx.Doer.ID) isOwner, err := organization.OrgFromUser(repoOwner).IsOwnedBy(ctx.Doer.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOwnedBy", err) ctx.Error(http.StatusInternalServerError, "IsOwnedBy", err)
return return

@ -10,6 +10,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
@ -722,12 +723,12 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions
if ctx.Repo.Repository.Owner.IsOrganization() && len(opts.TeamReviewers) > 0 { if ctx.Repo.Repository.Owner.IsOrganization() && len(opts.TeamReviewers) > 0 {
teamReviewers := make([]*models.Team, 0, len(opts.TeamReviewers)) teamReviewers := make([]*organization.Team, 0, len(opts.TeamReviewers))
for _, t := range opts.TeamReviewers { for _, t := range opts.TeamReviewers {
var teamReviewer *models.Team var teamReviewer *organization.Team
teamReviewer, err = models.GetTeam(ctx.Repo.Owner.ID, t) teamReviewer, err = organization.GetTeam(ctx.Repo.Owner.ID, t)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.NotFound("TeamNotExist", fmt.Sprintf("Team '%s' not exist", t)) ctx.NotFound("TeamNotExist", fmt.Sprintf("Team '%s' not exist", t))
return return
} }

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit" unit_model "code.gitea.io/gitea/models/unit"
@ -398,7 +399,7 @@ func Generate(ctx *context.APIContext) {
} }
if !ctx.Doer.IsAdmin { if !ctx.Doer.IsAdmin {
canCreate, err := models.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.Doer.ID) canCreate, err := organization.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.Doer.ID)
if err != nil { if err != nil {
ctx.ServerError("CanCreateOrgRepo", err) ctx.ServerError("CanCreateOrgRepo", err)
return return
@ -484,9 +485,9 @@ func CreateOrgRepo(ctx *context.APIContext) {
// "403": // "403":
// "$ref": "#/responses/forbidden" // "$ref": "#/responses/forbidden"
opt := web.GetForm(ctx).(*api.CreateRepoOption) opt := web.GetForm(ctx).(*api.CreateRepoOption)
org, err := models.GetOrgByName(ctx.Params(":org")) org, err := organization.GetOrgByName(ctx.Params(":org"))
if err != nil { if err != nil {
if models.IsErrOrgNotExist(err) { if organization.IsErrOrgNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err) ctx.Error(http.StatusUnprocessableEntity, "", err)
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetOrgByName", err) ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)
@ -494,7 +495,7 @@ func CreateOrgRepo(ctx *context.APIContext) {
return return
} }
if !models.HasOrgOrUserVisible(org.AsUser(), ctx.Doer) { if !organization.HasOrgOrUserVisible(ctx, org.AsUser(), ctx.Doer) {
ctx.NotFound("HasOrgOrUserVisible", nil) ctx.NotFound("HasOrgOrUserVisible", nil)
return return
} }

@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
@ -41,7 +42,7 @@ func ListTeams(ctx *context.APIContext) {
return return
} }
teams, err := models.GetRepoTeams(ctx.Repo.Repository) teams, err := organization.GetRepoTeams(ctx.Repo.Repository)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
@ -101,7 +102,7 @@ func IsTeam(ctx *context.APIContext) {
return return
} }
if team.HasRepository(ctx.Repo.Repository.ID) { if models.HasRepository(team, ctx.Repo.Repository.ID) {
if err := team.GetUnits(); err != nil { if err := team.GetUnits(); err != nil {
ctx.Error(http.StatusInternalServerError, "GetUnits", err) ctx.Error(http.StatusInternalServerError, "GetUnits", err)
return return
@ -196,20 +197,20 @@ func changeRepoTeam(ctx *context.APIContext, add bool) {
return return
} }
repoHasTeam := team.HasRepository(ctx.Repo.Repository.ID) repoHasTeam := models.HasRepository(team, ctx.Repo.Repository.ID)
var err error var err error
if add { if add {
if repoHasTeam { if repoHasTeam {
ctx.Error(http.StatusUnprocessableEntity, "alreadyAdded", fmt.Errorf("team '%s' is already added to repo", team.Name)) ctx.Error(http.StatusUnprocessableEntity, "alreadyAdded", fmt.Errorf("team '%s' is already added to repo", team.Name))
return return
} }
err = team.AddRepository(ctx.Repo.Repository) err = models.AddRepository(team, ctx.Repo.Repository)
} else { } else {
if !repoHasTeam { if !repoHasTeam {
ctx.Error(http.StatusUnprocessableEntity, "notAdded", fmt.Errorf("team '%s' was not added to repo", team.Name)) ctx.Error(http.StatusUnprocessableEntity, "notAdded", fmt.Errorf("team '%s' was not added to repo", team.Name))
return return
} }
err = team.RemoveRepository(ctx.Repo.Repository.ID) err = models.RemoveRepository(team, ctx.Repo.Repository.ID)
} }
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
@ -219,10 +220,10 @@ func changeRepoTeam(ctx *context.APIContext, add bool) {
ctx.Status(http.StatusNoContent) ctx.Status(http.StatusNoContent)
} }
func getTeamByParam(ctx *context.APIContext) *models.Team { func getTeamByParam(ctx *context.APIContext) *organization.Team {
team, err := models.GetTeam(ctx.Repo.Owner.ID, ctx.Params(":team")) team, err := organization.GetTeam(ctx.Repo.Owner.ID, ctx.Params(":team"))
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusNotFound, "TeamNotExit", err) ctx.Error(http.StatusNotFound, "TeamNotExit", err)
return nil return nil
} }

@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -67,23 +68,23 @@ func Transfer(ctx *context.APIContext) {
} }
if newOwner.Type == user_model.UserTypeOrganization { if newOwner.Type == user_model.UserTypeOrganization {
if !ctx.Doer.IsAdmin && newOwner.Visibility == api.VisibleTypePrivate && !models.OrgFromUser(newOwner).HasMemberWithUserID(ctx.Doer.ID) { if !ctx.Doer.IsAdmin && newOwner.Visibility == api.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx.Doer.ID) {
// The user shouldn't know about this organization // The user shouldn't know about this organization
ctx.Error(http.StatusNotFound, "", "The new owner does not exist or cannot be found") ctx.Error(http.StatusNotFound, "", "The new owner does not exist or cannot be found")
return return
} }
} }
var teams []*models.Team var teams []*organization.Team
if opts.TeamIDs != nil { if opts.TeamIDs != nil {
if !newOwner.IsOrganization() { if !newOwner.IsOrganization() {
ctx.Error(http.StatusUnprocessableEntity, "repoTransfer", "Teams can only be added to organization-owned repositories") ctx.Error(http.StatusUnprocessableEntity, "repoTransfer", "Teams can only be added to organization-owned repositories")
return return
} }
org := convert.ToOrganization(models.OrgFromUser(newOwner)) org := convert.ToOrganization(organization.OrgFromUser(newOwner))
for _, tID := range *opts.TeamIDs { for _, tID := range *opts.TeamIDs {
team, err := models.GetTeamByID(tID) team, err := organization.GetTeamByID(tID)
if err != nil { if err != nil {
ctx.Error(http.StatusUnprocessableEntity, "team", fmt.Errorf("team %d not found", tID)) ctx.Error(http.StatusUnprocessableEntity, "team", fmt.Errorf("team %d not found", tID))
return return

@ -21,7 +21,7 @@ import (
// getStarredRepos returns the repos that the user with the specified userID has // getStarredRepos returns the repos that the user with the specified userID has
// starred // starred
func getStarredRepos(user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, error) { func getStarredRepos(user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, error) {
starredRepos, err := models.GetStarredRepos(user.ID, private, listOptions) starredRepos, err := repo_model.GetStarredRepos(user.ID, private, listOptions)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -98,7 +98,7 @@ func GetInfo(ctx *context.APIContext) {
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
if !models.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) { if !user_model.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) {
// fake ErrUserNotExist error message to not leak information about existence // fake ErrUserNotExist error message to not leak information about existence
ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")}) ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")})
return return

@ -19,7 +19,7 @@ import (
// getWatchedRepos returns the repos that the user with the specified userID is watching // getWatchedRepos returns the repos that the user with the specified userID is watching
func getWatchedRepos(user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, int64, error) { func getWatchedRepos(user *user_model.User, private bool, listOptions db.ListOptions) ([]*api.Repository, int64, error) {
watchedRepos, total, err := models.GetWatchedRepos(user.ID, private, listOptions) watchedRepos, total, err := repo_model.GetWatchedRepos(user.ID, private, listOptions)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }

@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -39,7 +40,7 @@ func Home(ctx *context.Context) {
org := ctx.Org.Organization org := ctx.Org.Organization
if !models.HasOrgOrUserVisible(org.AsUser(), ctx.Doer) { if !organization.HasOrgOrUserVisible(ctx, org.AsUser(), ctx.Doer) {
ctx.NotFound("HasOrgOrUserVisible", nil) ctx.NotFound("HasOrgOrUserVisible", nil)
return return
} }
@ -122,7 +123,7 @@ func Home(ctx *context.Context) {
return return
} }
opts := &models.FindOrgMembersOpts{ opts := &organization.FindOrgMembersOpts{
OrgID: org.ID, OrgID: org.ID,
PublicOnly: true, PublicOnly: true,
ListOptions: db.ListOptions{Page: 1, PageSize: 25}, ListOptions: db.ListOptions{Page: 1, PageSize: 25},
@ -137,13 +138,13 @@ func Home(ctx *context.Context) {
opts.PublicOnly = !isMember && !ctx.Doer.IsAdmin opts.PublicOnly = !isMember && !ctx.Doer.IsAdmin
} }
members, _, err := models.FindOrgMembers(opts) members, _, err := organization.FindOrgMembers(opts)
if err != nil { if err != nil {
ctx.ServerError("FindOrgMembers", err) ctx.ServerError("FindOrgMembers", err)
return return
} }
membersCount, err := models.CountOrgMembers(opts) membersCount, err := organization.CountOrgMembers(opts)
if err != nil { if err != nil {
ctx.ServerError("CountOrgMembers", err) ctx.ServerError("CountOrgMembers", err)
return return

@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -31,7 +32,7 @@ func Members(ctx *context.Context) {
page = 1 page = 1
} }
opts := &models.FindOrgMembersOpts{ opts := &organization.FindOrgMembersOpts{
OrgID: org.ID, OrgID: org.ID,
PublicOnly: true, PublicOnly: true,
} }
@ -45,7 +46,7 @@ func Members(ctx *context.Context) {
opts.PublicOnly = !isMember && !ctx.Doer.IsAdmin opts.PublicOnly = !isMember && !ctx.Doer.IsAdmin
} }
total, err := models.CountOrgMembers(opts) total, err := organization.CountOrgMembers(opts)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "CountOrgMembers") ctx.Error(http.StatusInternalServerError, "CountOrgMembers")
return return
@ -54,7 +55,7 @@ func Members(ctx *context.Context) {
pager := context.NewPagination(int(total), setting.UI.MembersPagingNum, page, 5) pager := context.NewPagination(int(total), setting.UI.MembersPagingNum, page, 5)
opts.ListOptions.Page = page opts.ListOptions.Page = page
opts.ListOptions.PageSize = setting.UI.MembersPagingNum opts.ListOptions.PageSize = setting.UI.MembersPagingNum
members, membersIsPublic, err := models.FindOrgMembers(opts) members, membersIsPublic, err := organization.FindOrgMembers(opts)
if err != nil { if err != nil {
ctx.ServerError("GetMembers", err) ctx.ServerError("GetMembers", err)
return return
@ -84,20 +85,20 @@ func MembersAction(ctx *context.Context) {
ctx.Error(http.StatusNotFound) ctx.Error(http.StatusNotFound)
return return
} }
err = models.ChangeOrgUserStatus(org.ID, uid, false) err = organization.ChangeOrgUserStatus(org.ID, uid, false)
case "public": case "public":
if ctx.Doer.ID != uid && !ctx.Org.IsOwner { if ctx.Doer.ID != uid && !ctx.Org.IsOwner {
ctx.Error(http.StatusNotFound) ctx.Error(http.StatusNotFound)
return return
} }
err = models.ChangeOrgUserStatus(org.ID, uid, true) err = organization.ChangeOrgUserStatus(org.ID, uid, true)
case "remove": case "remove":
if !ctx.Org.IsOwner { if !ctx.Org.IsOwner {
ctx.Error(http.StatusNotFound) ctx.Error(http.StatusNotFound)
return return
} }
err = org.RemoveMember(uid) err = models.RemoveOrgUser(org.ID, uid)
if models.IsErrLastOrgOwner(err) { if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
ctx.JSON(http.StatusOK, map[string]interface{}{ ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": ctx.Org.OrgLink + "/members", "redirect": ctx.Org.OrgLink + "/members",
@ -105,8 +106,8 @@ func MembersAction(ctx *context.Context) {
return return
} }
case "leave": case "leave":
err = org.RemoveMember(ctx.Doer.ID) err = models.RemoveOrgUser(org.ID, ctx.Doer.ID)
if models.IsErrLastOrgOwner(err) { if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
ctx.JSON(http.StatusOK, map[string]interface{}{ ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": ctx.Org.OrgLink + "/members", "redirect": ctx.Org.OrgLink + "/members",

@ -9,8 +9,8 @@ import (
"errors" "errors"
"net/http" "net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -51,7 +51,7 @@ func CreatePost(ctx *context.Context) {
return return
} }
org := &models.Organization{ org := &organization.Organization{
Name: form.OrgName, Name: form.OrgName,
IsActive: true, IsActive: true,
Type: user_model.UserTypeOrganization, Type: user_model.UserTypeOrganization,
@ -59,7 +59,7 @@ func CreatePost(ctx *context.Context) {
RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess, RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess,
} }
if err := models.CreateOrganization(org, ctx.Doer); err != nil { if err := organization.CreateOrganization(org, ctx.Doer); err != nil {
ctx.Data["Err_OrgName"] = true ctx.Data["Err_OrgName"] = true
switch { switch {
case user_model.IsErrUserAlreadyExist(err): case user_model.IsErrUserAlreadyExist(err):
@ -68,7 +68,7 @@ func CreatePost(ctx *context.Context) {
ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(db.ErrNameReserved).Name), tplCreateOrg, &form) ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(db.ErrNameReserved).Name), tplCreateOrg, &form)
case db.IsErrNamePatternNotAllowed(err): case db.IsErrNamePatternNotAllowed(err):
ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplCreateOrg, &form) ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplCreateOrg, &form)
case models.IsErrUserNotAllowedCreateOrg(err): case organization.IsErrUserNotAllowedCreateOrg(err):
ctx.RenderWithErr(ctx.Tr("org.form.create_org_not_allowed"), tplCreateOrg, &form) ctx.RenderWithErr(ctx.Tr("org.form.create_org_not_allowed"), tplCreateOrg, &form)
default: default:
ctx.ServerError("CreateOrganization", err) ctx.ServerError("CreateOrganization", err)

@ -13,6 +13,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit" unit_model "code.gitea.io/gitea/models/unit"
@ -43,7 +44,7 @@ func Teams(ctx *context.Context) {
ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeams"] = true
for _, t := range ctx.Org.Teams { for _, t := range ctx.Org.Teams {
if err := t.GetMembers(&models.SearchMembersOptions{}); err != nil { if err := t.GetMembersCtx(ctx); err != nil {
ctx.ServerError("GetMembers", err) ctx.ServerError("GetMembers", err)
return return
} }
@ -69,11 +70,11 @@ func TeamsAction(ctx *context.Context) {
ctx.Error(http.StatusNotFound) ctx.Error(http.StatusNotFound)
return return
} }
err = ctx.Org.Team.AddMember(ctx.Doer.ID) err = models.AddTeamMember(ctx.Org.Team, ctx.Doer.ID)
case "leave": case "leave":
err = ctx.Org.Team.RemoveMember(ctx.Doer.ID) err = models.RemoveTeamMember(ctx.Org.Team, ctx.Doer.ID)
if err != nil { if err != nil {
if models.IsErrLastOrgOwner(err) { if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
} else { } else {
log.Error("Action(%s): %v", ctx.Params(":action"), err) log.Error("Action(%s): %v", ctx.Params(":action"), err)
@ -94,9 +95,9 @@ func TeamsAction(ctx *context.Context) {
ctx.Error(http.StatusNotFound) ctx.Error(http.StatusNotFound)
return return
} }
err = ctx.Org.Team.RemoveMember(uid) err = models.RemoveTeamMember(ctx.Org.Team, uid)
if err != nil { if err != nil {
if models.IsErrLastOrgOwner(err) { if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
} else { } else {
log.Error("Action(%s): %v", ctx.Params(":action"), err) log.Error("Action(%s): %v", ctx.Params(":action"), err)
@ -139,14 +140,14 @@ func TeamsAction(ctx *context.Context) {
if ctx.Org.Team.IsMember(u.ID) { if ctx.Org.Team.IsMember(u.ID) {
ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users")) ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users"))
} else { } else {
err = ctx.Org.Team.AddMember(u.ID) err = models.AddTeamMember(ctx.Org.Team, u.ID)
} }
page = "team" page = "team"
} }
if err != nil { if err != nil {
if models.IsErrLastOrgOwner(err) { if organization.IsErrLastOrgOwner(err) {
ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
} else { } else {
log.Error("Action(%s): %v", ctx.Params(":action"), err) log.Error("Action(%s): %v", ctx.Params(":action"), err)
@ -191,13 +192,13 @@ func TeamsRepoAction(ctx *context.Context) {
ctx.ServerError("GetRepositoryByName", err) ctx.ServerError("GetRepositoryByName", err)
return return
} }
err = ctx.Org.Team.AddRepository(repo) err = models.AddRepository(ctx.Org.Team, repo)
case "remove": case "remove":
err = ctx.Org.Team.RemoveRepository(ctx.FormInt64("repoid")) err = models.RemoveRepository(ctx.Org.Team, ctx.FormInt64("repoid"))
case "addall": case "addall":
err = ctx.Org.Team.AddAllRepositories() err = models.AddAllRepositories(ctx.Org.Team)
case "removeall": case "removeall":
err = ctx.Org.Team.RemoveAllRepositories() err = models.RemoveAllRepositories(ctx.Org.Team)
} }
if err != nil { if err != nil {
@ -220,7 +221,7 @@ func NewTeam(ctx *context.Context) {
ctx.Data["Title"] = ctx.Org.Organization.FullName ctx.Data["Title"] = ctx.Org.Organization.FullName
ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeams"] = true
ctx.Data["PageIsOrgTeamsNew"] = true ctx.Data["PageIsOrgTeamsNew"] = true
ctx.Data["Team"] = &models.Team{} ctx.Data["Team"] = &organization.Team{}
ctx.Data["Units"] = unit_model.Units ctx.Data["Units"] = unit_model.Units
ctx.HTML(http.StatusOK, tplTeamNew) ctx.HTML(http.StatusOK, tplTeamNew)
} }
@ -251,7 +252,7 @@ func NewTeamPost(ctx *context.Context) {
p = unit_model.MinUnitAccessMode(unitPerms) p = unit_model.MinUnitAccessMode(unitPerms)
} }
t := &models.Team{ t := &organization.Team{
OrgID: ctx.Org.Organization.ID, OrgID: ctx.Org.Organization.ID,
Name: form.TeamName, Name: form.TeamName,
Description: form.Description, Description: form.Description,
@ -261,9 +262,9 @@ func NewTeamPost(ctx *context.Context) {
} }
if t.AccessMode < perm.AccessModeAdmin { if t.AccessMode < perm.AccessModeAdmin {
units := make([]*models.TeamUnit, 0, len(unitPerms)) units := make([]*organization.TeamUnit, 0, len(unitPerms))
for tp, perm := range unitPerms { for tp, perm := range unitPerms {
units = append(units, &models.TeamUnit{ units = append(units, &organization.TeamUnit{
OrgID: ctx.Org.Organization.ID, OrgID: ctx.Org.Organization.ID,
Type: tp, Type: tp,
AccessMode: perm, AccessMode: perm,
@ -291,7 +292,7 @@ func NewTeamPost(ctx *context.Context) {
if err := models.NewTeam(t); err != nil { if err := models.NewTeam(t); err != nil {
ctx.Data["Err_TeamName"] = true ctx.Data["Err_TeamName"] = true
switch { switch {
case models.IsErrTeamAlreadyExist(err): case organization.IsErrTeamAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form) ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
default: default:
ctx.ServerError("NewTeam", err) ctx.ServerError("NewTeam", err)
@ -307,7 +308,7 @@ func TeamMembers(ctx *context.Context) {
ctx.Data["Title"] = ctx.Org.Team.Name ctx.Data["Title"] = ctx.Org.Team.Name
ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeams"] = true
ctx.Data["PageIsOrgTeamMembers"] = true ctx.Data["PageIsOrgTeamMembers"] = true
if err := ctx.Org.Team.GetMembers(&models.SearchMembersOptions{}); err != nil { if err := ctx.Org.Team.GetMembersCtx(ctx); err != nil {
ctx.ServerError("GetMembers", err) ctx.ServerError("GetMembers", err)
return return
} }
@ -320,7 +321,7 @@ func TeamRepositories(ctx *context.Context) {
ctx.Data["Title"] = ctx.Org.Team.Name ctx.Data["Title"] = ctx.Org.Team.Name
ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeams"] = true
ctx.Data["PageIsOrgTeamRepos"] = true ctx.Data["PageIsOrgTeamRepos"] = true
if err := ctx.Org.Team.GetRepositories(&models.SearchOrgTeamOptions{}); err != nil { if err := ctx.Org.Team.GetRepositoriesCtx(ctx); err != nil {
ctx.ServerError("GetRepositories", err) ctx.ServerError("GetRepositories", err)
return return
} }
@ -374,17 +375,17 @@ func EditTeamPost(ctx *context.Context) {
} }
t.Description = form.Description t.Description = form.Description
if t.AccessMode < perm.AccessModeAdmin { if t.AccessMode < perm.AccessModeAdmin {
units := make([]models.TeamUnit, 0, len(unitPerms)) units := make([]organization.TeamUnit, 0, len(unitPerms))
for tp, perm := range unitPerms { for tp, perm := range unitPerms {
units = append(units, models.TeamUnit{ units = append(units, organization.TeamUnit{
OrgID: t.OrgID, OrgID: t.OrgID,
TeamID: t.ID, TeamID: t.ID,
Type: tp, Type: tp,
AccessMode: perm, AccessMode: perm,
}) })
} }
if err := models.UpdateTeamUnits(t, units); err != nil { if err := organization.UpdateTeamUnits(t, units); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error()) ctx.Error(http.StatusInternalServerError, "UpdateTeamUnits", err.Error())
return return
} }
} }
@ -403,7 +404,7 @@ func EditTeamPost(ctx *context.Context) {
if err := models.UpdateTeam(t, isAuthChanged, isIncludeAllChanged); err != nil { if err := models.UpdateTeam(t, isAuthChanged, isIncludeAllChanged); err != nil {
ctx.Data["Err_TeamName"] = true ctx.Data["Err_TeamName"] = true
switch { switch {
case models.IsErrTeamAlreadyExist(err): case organization.IsErrTeamAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form) ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
default: default:
ctx.ServerError("UpdateTeam", err) ctx.ServerError("UpdateTeam", err)

@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -471,7 +472,7 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) {
// repoReviewerSelection items to bee shown // repoReviewerSelection items to bee shown
type repoReviewerSelection struct { type repoReviewerSelection struct {
IsTeam bool IsTeam bool
Team *models.Team Team *organization.Team
User *user_model.User User *user_model.User
Review *models.Review Review *models.Review
CanChange bool CanChange bool
@ -504,7 +505,7 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is
pullReviews []*repoReviewerSelection pullReviews []*repoReviewerSelection
reviewersResult []*repoReviewerSelection reviewersResult []*repoReviewerSelection
teamReviewersResult []*repoReviewerSelection teamReviewersResult []*repoReviewerSelection
teamReviewers []*models.Team teamReviewers []*organization.Team
reviewers []*user_model.User reviewers []*user_model.User
) )
@ -586,7 +587,7 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is
item.User = item.Review.Reviewer item.User = item.Review.Reviewer
} else if item.Review.ReviewerTeamID > 0 { } else if item.Review.ReviewerTeamID > 0 {
if err = item.Review.LoadReviewerTeam(); err != nil { if err = item.Review.LoadReviewerTeam(); err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
continue continue
} }
ctx.ServerError("LoadReviewerTeam", err) ctx.ServerError("LoadReviewerTeam", err)
@ -1965,9 +1966,9 @@ func UpdatePullReviewRequest(ctx *context.Context) {
return return
} }
team, err := models.GetTeamByID(-reviewID) team, err := organization.GetTeamByID(-reviewID)
if err != nil { if err != nil {
ctx.ServerError("models.GetTeamByID", err) ctx.ServerError("GetTeamByID", err)
return return
} }
@ -2702,8 +2703,8 @@ func handleTeamMentions(ctx *context.Context) {
var isAdmin bool var isAdmin bool
var err error var err error
var teams []*models.Team var teams []*organization.Team
org := models.OrgFromUser(ctx.Repo.Owner) org := organization.OrgFromUser(ctx.Repo.Owner)
// Admin has super access. // Admin has super access.
if ctx.Doer.IsAdmin { if ctx.Doer.IsAdmin {
isAdmin = true isAdmin = true

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -77,7 +78,7 @@ func RetrieveLabels(ctx *context.Context) {
} }
ctx.Data["OrgLabels"] = orgLabels ctx.Data["OrgLabels"] = orgLabels
org, err := models.GetOrgByName(ctx.Repo.Owner.LowerName) org, err := organization.GetOrgByName(ctx.Repo.Owner.LowerName)
if err != nil { if err != nil {
ctx.ServerError("GetOrgByName", err) ctx.ServerError("GetOrgByName", err)
return return

@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -111,12 +112,12 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
ctx.Data["ForkRepo"] = forkRepo ctx.Data["ForkRepo"] = forkRepo
ownedOrgs, err := models.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID) ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID)
if err != nil { if err != nil {
ctx.ServerError("GetOrgsCanCreateRepoByUserID", err) ctx.ServerError("GetOrgsCanCreateRepoByUserID", err)
return nil return nil
} }
var orgs []*models.Organization var orgs []*organization.Organization
for _, org := range ownedOrgs { for _, org := range ownedOrgs {
if forkRepo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, forkRepo.ID) { if forkRepo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, forkRepo.ID) {
orgs = append(orgs, org) orgs = append(orgs, org)
@ -216,7 +217,7 @@ func ForkPost(ctx *context.Context) {
// Check if user is allowed to create repo's on the organization. // Check if user is allowed to create repo's on the organization.
if ctxUser.IsOrganization() { if ctxUser.IsOrganization() {
isAllowedToFork, err := models.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.Doer.ID) isAllowedToFork, err := organization.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.Doer.ID)
if err != nil { if err != nil {
ctx.ServerError("CanCreateOrgRepo", err) ctx.ServerError("CanCreateOrgRepo", err)
return return

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -57,14 +58,14 @@ func MustBeAbleToUpload(ctx *context.Context) {
} }
func checkContextUser(ctx *context.Context, uid int64) *user_model.User { func checkContextUser(ctx *context.Context, uid int64) *user_model.User {
orgs, err := models.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID) orgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID)
if err != nil { if err != nil {
ctx.ServerError("GetOrgsCanCreateRepoByUserID", err) ctx.ServerError("GetOrgsCanCreateRepoByUserID", err)
return nil return nil
} }
if !ctx.Doer.IsAdmin { if !ctx.Doer.IsAdmin {
orgsAvailable := []*models.Organization{} orgsAvailable := []*organization.Organization{}
for i := 0; i < len(orgs); i++ { for i := 0; i < len(orgs); i++ {
if orgs[i].CanCreateRepo() { if orgs[i].CanCreateRepo() {
orgsAvailable = append(orgsAvailable, orgs[i]) orgsAvailable = append(orgsAvailable, orgs[i])
@ -96,7 +97,7 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User {
return nil return nil
} }
if !ctx.Doer.IsAdmin { if !ctx.Doer.IsAdmin {
canCreate, err := models.OrgFromUser(org).CanCreateOrgRepo(ctx.Doer.ID) canCreate, err := organization.OrgFromUser(org).CanCreateOrgRepo(ctx.Doer.ID)
if err != nil { if err != nil {
ctx.ServerError("CanCreateOrgRepo", err) ctx.ServerError("CanCreateOrgRepo", err)
return nil return nil

@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit" unit_model "code.gitea.io/gitea/models/unit"
@ -648,7 +649,7 @@ func SettingsPost(ctx *context.Context) {
} }
if newOwner.Type == user_model.UserTypeOrganization { if newOwner.Type == user_model.UserTypeOrganization {
if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !models.OrgFromUser(newOwner).HasMemberWithUserID(ctx.Doer.ID) { if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx.Doer.ID) {
// The user shouldn't know about this organization // The user shouldn't know about this organization
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
return return
@ -835,7 +836,7 @@ func Collaboration(ctx *context.Context) {
} }
ctx.Data["Collaborators"] = users ctx.Data["Collaborators"] = users
teams, err := models.GetRepoTeams(ctx.Repo.Repository) teams, err := organization.GetRepoTeams(ctx.Repo.Repository)
if err != nil { if err != nil {
ctx.ServerError("GetRepoTeams", err) ctx.ServerError("GetRepoTeams", err)
return return
@ -938,9 +939,9 @@ func AddTeamPost(ctx *context.Context) {
return return
} }
team, err := models.OrgFromUser(ctx.Repo.Owner).GetTeam(name) team, err := organization.OrgFromUser(ctx.Repo.Owner).GetTeam(name)
if err != nil { if err != nil {
if models.IsErrTeamNotExist(err) { if organization.IsErrTeamNotExist(err) {
ctx.Flash.Error(ctx.Tr("form.team_not_exist")) ctx.Flash.Error(ctx.Tr("form.team_not_exist"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
} else { } else {
@ -955,13 +956,13 @@ func AddTeamPost(ctx *context.Context) {
return return
} }
if models.HasTeamRepo(ctx.Repo.Repository.OwnerID, team.ID, ctx.Repo.Repository.ID) { if organization.HasTeamRepo(ctx, ctx.Repo.Repository.OwnerID, team.ID, ctx.Repo.Repository.ID) {
ctx.Flash.Error(ctx.Tr("repo.settings.add_team_duplicate")) ctx.Flash.Error(ctx.Tr("repo.settings.add_team_duplicate"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
return return
} }
if err = team.AddRepository(ctx.Repo.Repository); err != nil { if err = models.AddRepository(team, ctx.Repo.Repository); err != nil {
ctx.ServerError("team.AddRepository", err) ctx.ServerError("team.AddRepository", err)
return return
} }
@ -978,13 +979,13 @@ func DeleteTeam(ctx *context.Context) {
return return
} }
team, err := models.GetTeamByID(ctx.FormInt64("id")) team, err := organization.GetTeamByID(ctx.FormInt64("id"))
if err != nil { if err != nil {
ctx.ServerError("GetTeamByID", err) ctx.ServerError("GetTeamByID", err)
return return
} }
if err = team.RemoveRepository(ctx.Repo.Repository.ID); err != nil { if err = models.RemoveRepository(team, ctx.Repo.Repository.ID); err != nil {
ctx.ServerError("team.RemoveRepositorys", err) ctx.ServerError("team.RemoveRepositorys", err)
return return
} }

@ -11,6 +11,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
@ -158,7 +159,7 @@ func SettingsProtectedBranch(c *context.Context) {
} }
if c.Repo.Owner.IsOrganization() { if c.Repo.Owner.IsOrganization() {
teams, err := models.OrgFromUser(c.Repo.Owner).TeamsWithAccessToRepo(c.Repo.Repository.ID, perm.AccessModeRead) teams, err := organization.OrgFromUser(c.Repo.Owner).TeamsWithAccessToRepo(c.Repo.Repository.ID, perm.AccessModeRead)
if err != nil { if err != nil {
c.ServerError("Repo.Owner.TeamsWithAccessToRepo", err) c.ServerError("Repo.Owner.TeamsWithAccessToRepo", err)
return return

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
@ -231,7 +232,7 @@ func TestAddTeamPost(t *testing.T) {
Type: user_model.UserTypeOrganization, Type: user_model.UserTypeOrganization,
} }
team := &models.Team{ team := &organization.Team{
ID: 11, ID: 11,
OrgID: 26, OrgID: 26,
} }
@ -255,7 +256,7 @@ func TestAddTeamPost(t *testing.T) {
AddTeamPost(ctx) AddTeamPost(ctx)
assert.True(t, team.HasRepository(re.ID)) assert.True(t, models.HasRepository(team, re.ID))
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.Empty(t, ctx.Flash.ErrorMsg) assert.Empty(t, ctx.Flash.ErrorMsg)
} }
@ -271,7 +272,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) {
Type: user_model.UserTypeOrganization, Type: user_model.UserTypeOrganization,
} }
team := &models.Team{ team := &organization.Team{
ID: 11, ID: 11,
OrgID: 26, OrgID: 26,
} }
@ -295,7 +296,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) {
AddTeamPost(ctx) AddTeamPost(ctx)
assert.False(t, team.HasRepository(re.ID)) assert.False(t, models.HasRepository(team, re.ID))
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg) assert.NotEmpty(t, ctx.Flash.ErrorMsg)
} }
@ -311,7 +312,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) {
Type: user_model.UserTypeOrganization, Type: user_model.UserTypeOrganization,
} }
team := &models.Team{ team := &organization.Team{
ID: 11, ID: 11,
OrgID: 26, OrgID: 26,
} }
@ -336,7 +337,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) {
AddTeamPost(ctx) AddTeamPost(ctx)
AddTeamPost(ctx) AddTeamPost(ctx)
assert.True(t, team.HasRepository(re.ID)) assert.True(t, models.HasRepository(team, re.ID))
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
assert.NotEmpty(t, ctx.Flash.ErrorMsg) assert.NotEmpty(t, ctx.Flash.ErrorMsg)
} }
@ -385,7 +386,7 @@ func TestDeleteTeam(t *testing.T) {
Type: user_model.UserTypeOrganization, Type: user_model.UserTypeOrganization,
} }
team := &models.Team{ team := &organization.Team{
ID: 2, ID: 2,
OrgID: 3, OrgID: 3,
} }
@ -409,5 +410,5 @@ func TestDeleteTeam(t *testing.T) {
DeleteTeam(ctx) DeleteTeam(ctx)
assert.False(t, team.HasRepository(re.ID)) assert.False(t, models.HasRepository(team, re.ID))
} }

@ -10,6 +10,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -150,7 +151,7 @@ func setTagsContext(ctx *context.Context) error {
ctx.Data["Users"] = users ctx.Data["Users"] = users
if ctx.Repo.Owner.IsOrganization() { if ctx.Repo.Owner.IsOrganization() {
teams, err := models.OrgFromUser(ctx.Repo.Owner).TeamsWithAccessToRepo(ctx.Repo.Repository.ID, perm.AccessModeRead) teams, err := organization.OrgFromUser(ctx.Repo.Owner).TeamsWithAccessToRepo(ctx.Repo.Repository.ID, perm.AccessModeRead)
if err != nil { if err != nil {
ctx.ServerError("Repo.Owner.TeamsWithAccessToRepo", err) ctx.ServerError("Repo.Owner.TeamsWithAccessToRepo", err)
return err return err

@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -74,7 +75,7 @@ func Dashboard(ctx *context.Context) {
ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard") ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
ctx.Data["PageIsDashboard"] = true ctx.Data["PageIsDashboard"] = true
ctx.Data["PageIsNews"] = true ctx.Data["PageIsNews"] = true
cnt, _ := models.GetOrganizationCount(ctx, ctxUser) cnt, _ := organization.GetOrganizationCount(ctx, ctxUser)
ctx.Data["UserOrgsCount"] = cnt ctx.Data["UserOrgsCount"] = cnt
var uid int64 var uid int64
@ -99,11 +100,11 @@ func Dashboard(ctx *context.Context) {
var err error var err error
var mirrors []*repo_model.Repository var mirrors []*repo_model.Repository
if ctxUser.IsOrganization() { if ctxUser.IsOrganization() {
var env models.AccessibleReposEnvironment var env organization.AccessibleReposEnvironment
if ctx.Org.Team != nil { if ctx.Org.Team != nil {
env = models.OrgFromUser(ctxUser).AccessibleTeamReposEnv(ctx.Org.Team) env = organization.OrgFromUser(ctxUser).AccessibleTeamReposEnv(ctx.Org.Team)
} else { } else {
env, err = models.OrgFromUser(ctxUser).AccessibleReposEnv(ctx.Doer.ID) env, err = organization.AccessibleReposEnv(ctx, organization.OrgFromUser(ctxUser), ctx.Doer.ID)
if err != nil { if err != nil {
ctx.ServerError("AccessibleReposEnv", err) ctx.ServerError("AccessibleReposEnv", err)
return return
@ -404,8 +405,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Get repository IDs where User/Org/Team has access. // Get repository IDs where User/Org/Team has access.
var team *models.Team var team *organization.Team
var org *models.Organization var org *organization.Organization
if ctx.Org != nil { if ctx.Org != nil {
org = ctx.Org.Organization org = ctx.Org.Organization
team = ctx.Org.Team team = ctx.Org.Team

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -40,7 +41,7 @@ func Profile(ctx *context.Context) {
} }
// check view permissions // check view permissions
if !models.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) { if !user_model.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) {
ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name)) ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
return return
} }
@ -91,7 +92,7 @@ func Profile(ctx *context.Context) {
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
orgs, err := models.FindOrgs(models.FindOrgOptions{ orgs, err := organization.FindOrgs(organization.FindOrgOptions{
UserID: ctx.ContextUser.ID, UserID: ctx.ContextUser.ID,
IncludePrivate: showPrivate, IncludePrivate: showPrivate,
}) })
@ -101,7 +102,7 @@ func Profile(ctx *context.Context) {
} }
ctx.Data["Orgs"] = orgs ctx.Data["Orgs"] = orgs
ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.Doer) ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer)
tab := ctx.FormString("tab") tab := ctx.FormString("tab")
ctx.Data["TabName"] = tab ctx.Data["TabName"] = tab

@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
@ -218,7 +219,7 @@ func Organization(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsOrganization"] = true ctx.Data["PageIsSettingsOrganization"] = true
opts := models.FindOrgOptions{ opts := organization.FindOrgOptions{
ListOptions: db.ListOptions{ ListOptions: db.ListOptions{
PageSize: setting.UI.Admin.UserPagingNum, PageSize: setting.UI.Admin.UserPagingNum,
Page: ctx.FormInt("page"), Page: ctx.FormInt("page"),
@ -231,12 +232,12 @@ func Organization(ctx *context.Context) {
opts.Page = 1 opts.Page = 1
} }
orgs, err := models.FindOrgs(opts) orgs, err := organization.FindOrgs(opts)
if err != nil { if err != nil {
ctx.ServerError("FindOrgs", err) ctx.ServerError("FindOrgs", err)
return return
} }
total, err := models.CountOrgs(opts) total, err := organization.CountOrgs(opts)
if err != nil { if err != nil {
ctx.ServerError("CountOrgs", err) ctx.ServerError("CountOrgs", err)
return return

@ -8,10 +8,10 @@ import (
"fmt" "fmt"
"strings" "strings"
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
user_service "code.gitea.io/gitea/services/user" user_service "code.gitea.io/gitea/services/user"
@ -65,8 +65,8 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
if user != nil { if user != nil {
if source.GroupsEnabled && (source.GroupTeamMap != "" || source.GroupTeamMapRemoval) { if source.GroupsEnabled && (source.GroupTeamMap != "" || source.GroupTeamMapRemoval) {
orgCache := make(map[string]*models.Organization) orgCache := make(map[string]*organization.Organization)
teamCache := make(map[string]*models.Team) teamCache := make(map[string]*organization.Team)
source.SyncLdapGroupsToTeams(user, sr.LdapTeamAdd, sr.LdapTeamRemove, orgCache, teamCache) source.SyncLdapGroupsToTeams(user, sr.LdapTeamAdd, sr.LdapTeamRemove, orgCache, teamCache)
} }
if isAttributeSSHPublicKeySet && asymkey_model.SynchronizePublicKeys(user, source.authSource, sr.SSHPublicKey) { if isAttributeSSHPublicKeySet && asymkey_model.SynchronizePublicKeys(user, source.authSource, sr.SSHPublicKey) {
@ -111,8 +111,8 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
_ = user_service.UploadAvatar(user, sr.Avatar) _ = user_service.UploadAvatar(user, sr.Avatar)
} }
if source.GroupsEnabled && (source.GroupTeamMap != "" || source.GroupTeamMapRemoval) { if source.GroupsEnabled && (source.GroupTeamMap != "" || source.GroupTeamMapRemoval) {
orgCache := make(map[string]*models.Organization) orgCache := make(map[string]*organization.Organization)
teamCache := make(map[string]*models.Team) teamCache := make(map[string]*organization.Team)
source.SyncLdapGroupsToTeams(user, sr.LdapTeamAdd, sr.LdapTeamRemove, orgCache, teamCache) source.SyncLdapGroupsToTeams(user, sr.LdapTeamAdd, sr.LdapTeamRemove, orgCache, teamCache)
} }

@ -6,12 +6,14 @@ package ldap
import ( import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
) )
// SyncLdapGroupsToTeams maps LDAP groups to organization and team memberships // SyncLdapGroupsToTeams maps LDAP groups to organization and team memberships
func (source *Source) SyncLdapGroupsToTeams(user *user_model.User, ldapTeamAdd, ldapTeamRemove map[string][]string, orgCache map[string]*models.Organization, teamCache map[string]*models.Team) { func (source *Source) SyncLdapGroupsToTeams(user *user_model.User, ldapTeamAdd, ldapTeamRemove map[string][]string, orgCache map[string]*organization.Organization, teamCache map[string]*organization.Team) {
var err error var err error
if source.GroupsEnabled && source.GroupTeamMapRemoval { if source.GroupsEnabled && source.GroupTeamMapRemoval {
// when the user is not a member of configs LDAP group, remove mapped organizations/teams memberships // when the user is not a member of configs LDAP group, remove mapped organizations/teams memberships
@ -20,7 +22,7 @@ func (source *Source) SyncLdapGroupsToTeams(user *user_model.User, ldapTeamAdd,
for orgName, teamNames := range ldapTeamAdd { for orgName, teamNames := range ldapTeamAdd {
org, ok := orgCache[orgName] org, ok := orgCache[orgName]
if !ok { if !ok {
org, err = models.GetOrgByName(orgName) org, err = organization.GetOrgByName(orgName)
if err != nil { if err != nil {
// organization must be created before LDAP group sync // organization must be created before LDAP group sync
log.Warn("LDAP group sync: Could not find organisation %s: %v", orgName, err) log.Warn("LDAP group sync: Could not find organisation %s: %v", orgName, err)
@ -28,14 +30,7 @@ func (source *Source) SyncLdapGroupsToTeams(user *user_model.User, ldapTeamAdd,
} }
orgCache[orgName] = org orgCache[orgName] = org
} }
if isMember, err := models.IsOrganizationMember(org.ID, user.ID); !isMember && err == nil {
log.Trace("LDAP group sync: adding user [%s] to organization [%s]", user.Name, org.Name)
err = org.AddMember(user.ID)
if err != nil {
log.Error("LDAP group sync: Could not add user to organization: %v", err)
continue
}
}
for _, teamName := range teamNames { for _, teamName := range teamNames {
team, ok := teamCache[orgName+teamName] team, ok := teamCache[orgName+teamName]
if !ok { if !ok {
@ -47,12 +42,12 @@ func (source *Source) SyncLdapGroupsToTeams(user *user_model.User, ldapTeamAdd,
} }
teamCache[orgName+teamName] = team teamCache[orgName+teamName] = team
} }
if isMember, err := models.IsTeamMember(org.ID, team.ID, user.ID); !isMember && err == nil { if isMember, err := organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID); !isMember && err == nil {
log.Trace("LDAP group sync: adding user [%s] to team [%s]", user.Name, org.Name) log.Trace("LDAP group sync: adding user [%s] to team [%s]", user.Name, org.Name)
} else { } else {
continue continue
} }
err := team.AddMember(user.ID) err := models.AddTeamMember(team, user.ID)
if err != nil { if err != nil {
log.Error("LDAP group sync: Could not add user to team: %v", err) log.Error("LDAP group sync: Could not add user to team: %v", err)
} }
@ -63,12 +58,12 @@ func (source *Source) SyncLdapGroupsToTeams(user *user_model.User, ldapTeamAdd,
// remove membership to organizations/teams if user is not member of corresponding LDAP group // remove membership to organizations/teams if user is not member of corresponding LDAP group
// e.g. lets assume user is member of LDAP group "x", but LDAP group team map contains LDAP groups "x" and "y" // e.g. lets assume user is member of LDAP group "x", but LDAP group team map contains LDAP groups "x" and "y"
// then users membership gets removed for all organizations/teams mapped by LDAP group "y" // then users membership gets removed for all organizations/teams mapped by LDAP group "y"
func removeMappedMemberships(user *user_model.User, ldapTeamRemove map[string][]string, orgCache map[string]*models.Organization, teamCache map[string]*models.Team) { func removeMappedMemberships(user *user_model.User, ldapTeamRemove map[string][]string, orgCache map[string]*organization.Organization, teamCache map[string]*organization.Team) {
var err error var err error
for orgName, teamNames := range ldapTeamRemove { for orgName, teamNames := range ldapTeamRemove {
org, ok := orgCache[orgName] org, ok := orgCache[orgName]
if !ok { if !ok {
org, err = models.GetOrgByName(orgName) org, err = organization.GetOrgByName(orgName)
if err != nil { if err != nil {
// organization must be created before LDAP group sync // organization must be created before LDAP group sync
log.Warn("LDAP group sync: Could not find organisation %s: %v", orgName, err) log.Warn("LDAP group sync: Could not find organisation %s: %v", orgName, err)
@ -86,12 +81,12 @@ func removeMappedMemberships(user *user_model.User, ldapTeamRemove map[string][]
continue continue
} }
} }
if isMember, err := models.IsTeamMember(org.ID, team.ID, user.ID); isMember && err == nil { if isMember, err := organization.IsTeamMember(db.DefaultContext, org.ID, team.ID, user.ID); isMember && err == nil {
log.Trace("LDAP group sync: removing user [%s] from team [%s]", user.Name, org.Name) log.Trace("LDAP group sync: removing user [%s] from team [%s]", user.Name, org.Name)
} else { } else {
continue continue
} }
err = team.RemoveMember(user.ID) err = models.RemoveTeamMember(team, user.ID)
if err != nil { if err != nil {
log.Error("LDAP group sync: Could not remove user from team: %v", err) log.Error("LDAP group sync: Could not remove user from team: %v", err)
} }

@ -10,9 +10,9 @@ import (
"sort" "sort"
"strings" "strings"
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
user_service "code.gitea.io/gitea/services/user" user_service "code.gitea.io/gitea/services/user"
@ -62,8 +62,8 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
}) })
userPos := 0 userPos := 0
orgCache := make(map[string]*models.Organization) orgCache := make(map[string]*organization.Organization)
teamCache := make(map[string]*models.Team) teamCache := make(map[string]*organization.Team)
for _, su := range sr { for _, su := range sr {
select { select {

@ -6,6 +6,8 @@ package issue
import ( import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -166,7 +168,7 @@ func IsValidReviewRequest(reviewer, doer *user_model.User, isAdd bool, issue *mo
} }
// IsValidTeamReviewRequest Check permission for ReviewRequest Team // IsValidTeamReviewRequest Check permission for ReviewRequest Team
func IsValidTeamReviewRequest(reviewer *models.Team, doer *user_model.User, isAdd bool, issue *models.Issue) error { func IsValidTeamReviewRequest(reviewer *organization.Team, doer *user_model.User, isAdd bool, issue *models.Issue) error {
if doer.IsOrganization() { if doer.IsOrganization() {
return models.ErrNotValidReviewRequest{ return models.ErrNotValidReviewRequest{
Reason: "Organization can't be doer to add reviewer", Reason: "Organization can't be doer to add reviewer",
@ -183,7 +185,7 @@ func IsValidTeamReviewRequest(reviewer *models.Team, doer *user_model.User, isAd
if isAdd { if isAdd {
if issue.Repo.IsPrivate { if issue.Repo.IsPrivate {
hasTeam := models.HasTeamRepo(reviewer.OrgID, reviewer.ID, issue.RepoID) hasTeam := organization.HasTeamRepo(db.DefaultContext, reviewer.OrgID, reviewer.ID, issue.RepoID)
if !hasTeam { if !hasTeam {
return models.ErrNotValidReviewRequest{ return models.ErrNotValidReviewRequest{
@ -221,7 +223,7 @@ func IsValidTeamReviewRequest(reviewer *models.Team, doer *user_model.User, isAd
} }
// TeamReviewRequest add or remove a review request from a team for this PR, and make comment for it. // TeamReviewRequest add or remove a review request from a team for this PR, and make comment for it.
func TeamReviewRequest(issue *models.Issue, doer *user_model.User, reviewer *models.Team, isAdd bool) (comment *models.Comment, err error) { func TeamReviewRequest(issue *models.Issue, doer *user_model.User, reviewer *organization.Team, isAdd bool) (comment *models.Comment, err error) {
if isAdd { if isAdd {
comment, err = models.AddTeamReviewRequest(issue, reviewer, doer) comment, err = models.AddTeamReviewRequest(issue, reviewer, doer)
} else { } else {
@ -241,11 +243,14 @@ func TeamReviewRequest(issue *models.Issue, doer *user_model.User, reviewer *mod
return return
} }
if err = reviewer.GetMembers(&models.SearchMembersOptions{}); err != nil { members, err := organization.GetTeamMembers(db.DefaultContext, &organization.SearchMembersOptions{
TeamID: reviewer.ID,
})
if err != nil {
return return
} }
for _, member := range reviewer.Members { for _, member := range members {
if member.ID == comment.Issue.PosterID { if member.ID == comment.Issue.PosterID {
continue continue
} }

@ -8,7 +8,8 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -24,7 +25,7 @@ func SendRepoTransferNotifyMail(doer, newOwner *user_model.User, repo *repo_mode
} }
if newOwner.IsOrganization() { if newOwner.IsOrganization() {
users, err := models.GetUsersWhoCanCreateOrgRepo(newOwner.ID) users, err := organization.GetUsersWhoCanCreateOrgRepo(db.DefaultContext, newOwner.ID)
if err != nil { if err != nil {
return err return err
} }

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
@ -16,7 +17,7 @@ import (
) )
// DeleteOrganization completely and permanently deletes everything of organization. // DeleteOrganization completely and permanently deletes everything of organization.
func DeleteOrganization(org *models.Organization) error { func DeleteOrganization(org *organization.Organization) error {
ctx, commiter, err := db.TxContext() ctx, commiter, err := db.TxContext()
if err != nil { if err != nil {
return err return err
@ -31,7 +32,7 @@ func DeleteOrganization(org *models.Organization) error {
return models.ErrUserOwnRepos{UID: org.ID} return models.ErrUserOwnRepos{UID: org.ID}
} }
if err := models.DeleteOrganization(ctx, org); err != nil { if err := organization.DeleteOrganization(ctx, org); err != nil {
return fmt.Errorf("DeleteOrganization: %v", err) return fmt.Errorf("DeleteOrganization: %v", err)
} }

@ -9,6 +9,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -21,18 +22,18 @@ func TestMain(m *testing.M) {
func TestDeleteOrganization(t *testing.T) { func TestDeleteOrganization(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &models.Organization{ID: 6}).(*models.Organization) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 6}).(*organization.Organization)
assert.NoError(t, DeleteOrganization(org)) assert.NoError(t, DeleteOrganization(org))
unittest.AssertNotExistsBean(t, &models.Organization{ID: 6}) unittest.AssertNotExistsBean(t, &organization.Organization{ID: 6})
unittest.AssertNotExistsBean(t, &models.OrgUser{OrgID: 6}) unittest.AssertNotExistsBean(t, &organization.OrgUser{OrgID: 6})
unittest.AssertNotExistsBean(t, &models.Team{OrgID: 6}) unittest.AssertNotExistsBean(t, &organization.Team{OrgID: 6})
org = unittest.AssertExistsAndLoadBean(t, &models.Organization{ID: 3}).(*models.Organization) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization)
err := DeleteOrganization(org) err := DeleteOrganization(org)
assert.Error(t, err) assert.Error(t, err)
assert.True(t, models.IsErrUserOwnRepos(err)) assert.True(t, models.IsErrUserOwnRepos(err))
user := unittest.AssertExistsAndLoadBean(t, &models.Organization{ID: 5}).(*models.Organization) user := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 5}).(*organization.Organization)
assert.Error(t, DeleteOrganization(user)) assert.Error(t, DeleteOrganization(user))
unittest.CheckConsistencyFor(t, &user_model.User{}, &models.Team{}) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})
} }

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -50,7 +51,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod
func PushCreateRepo(authUser, owner *user_model.User, repoName string) (*repo_model.Repository, error) { func PushCreateRepo(authUser, owner *user_model.User, repoName string) (*repo_model.Repository, error) {
if !authUser.IsAdmin { if !authUser.IsAdmin {
if owner.IsOrganization() { if owner.IsOrganization() {
if ok, err := models.CanCreateOrgRepo(owner.ID, authUser.ID); err != nil { if ok, err := organization.CanCreateOrgRepo(owner.ID, authUser.ID); err != nil {
return nil, err return nil, err
} else if !ok { } else if !ok {
return nil, fmt.Errorf("cannot push-create repository for org") return nil, fmt.Errorf("cannot push-create repository for org")

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -21,7 +22,7 @@ import (
var repoWorkingPool = sync.NewExclusivePool() var repoWorkingPool = sync.NewExclusivePool()
// TransferOwnership transfers all corresponding setting from old user to new one. // TransferOwnership transfers all corresponding setting from old user to new one.
func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*models.Team) error { func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
if err := repo.GetOwner(db.DefaultContext); err != nil { if err := repo.GetOwner(db.DefaultContext); err != nil {
return err return err
} }
@ -46,7 +47,7 @@ func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Reposit
} }
for _, team := range teams { for _, team := range teams {
if err := team.AddRepository(newRepo); err != nil { if err := models.AddRepository(team, newRepo); err != nil {
return err return err
} }
} }
@ -81,7 +82,7 @@ func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, ne
// StartRepositoryTransfer transfer a repo from one owner to a new one. // StartRepositoryTransfer transfer a repo from one owner to a new one.
// it make repository into pending transfer state, if doer can not create repo for new owner. // it make repository into pending transfer state, if doer can not create repo for new owner.
func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*models.Team) error { func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
if err := models.TestRepositoryReadyForTransfer(repo.Status); err != nil { if err := models.TestRepositoryReadyForTransfer(repo.Status); err != nil {
return err return err
} }
@ -93,7 +94,7 @@ func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.R
// If new owner is an org and user can create repos he can transfer directly too // If new owner is an org and user can create repos he can transfer directly too
if newOwner.IsOrganization() { if newOwner.IsOrganization() {
allowed, err := models.CanCreateOrgRepo(newOwner.ID, doer.ID) allowed, err := organization.CanCreateOrgRepo(newOwner.ID, doer.ID)
if err != nil { if err != nil {
return err return err
} }

@ -9,6 +9,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -53,7 +54,7 @@ func TestTransferOwnership(t *testing.T) {
Content: "user3/repo3", Content: "user3/repo3",
}) })
unittest.CheckConsistencyFor(t, &repo_model.Repository{}, &user_model.User{}, &models.Team{}) unittest.CheckConsistencyFor(t, &repo_model.Repository{}, &user_model.User{}, &organization.Team{})
} }
func TestStartRepositoryTransferSetPermission(t *testing.T) { func TestStartRepositoryTransferSetPermission(t *testing.T) {
@ -74,5 +75,5 @@ func TestStartRepositoryTransferSetPermission(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, hasAccess) assert.True(t, hasAccess)
unittest.CheckConsistencyFor(t, &repo_model.Repository{}, &user_model.User{}, &models.Team{}) unittest.CheckConsistencyFor(t, &repo_model.Repository{}, &user_model.User{}, &organization.Team{})
} }

@ -16,6 +16,7 @@ import (
admin_model "code.gitea.io/gitea/models/admin" admin_model "code.gitea.io/gitea/models/admin"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/avatar" "code.gitea.io/gitea/modules/avatar"
@ -50,7 +51,7 @@ func DeleteUser(u *user_model.User) error {
} }
// Check membership of organization. // Check membership of organization.
count, err = models.GetOrganizationCount(ctx, u) count, err = organization.GetOrganizationCount(ctx, u)
if err != nil { if err != nil {
return fmt.Errorf("GetOrganizationCount: %v", err) return fmt.Errorf("GetOrganizationCount: %v", err)
} else if count > 0 { } else if count > 0 {

@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -36,11 +37,11 @@ func TestDeleteUser(t *testing.T) {
return return
} }
orgUsers := make([]*models.OrgUser, 0, 10) orgUsers := make([]*organization.OrgUser, 0, 10)
assert.NoError(t, db.GetEngine(db.DefaultContext).Find(&orgUsers, &models.OrgUser{UID: userID})) assert.NoError(t, db.GetEngine(db.DefaultContext).Find(&orgUsers, &organization.OrgUser{UID: userID}))
for _, orgUser := range orgUsers { for _, orgUser := range orgUsers {
if err := models.RemoveOrgUser(orgUser.OrgID, orgUser.UID); err != nil { if err := models.RemoveOrgUser(orgUser.OrgID, orgUser.UID); err != nil {
assert.True(t, models.IsErrLastOrgOwner(err)) assert.True(t, organization.IsErrLastOrgOwner(err))
return return
} }
} }

Loading…
Cancel
Save