1
1
mirror of https://github.com/go-gitea/gitea synced 2024-12-22 16:44:26 +00:00

Move RepoTransfer from models to models/repo sub package (#32506)

`RepoTransfer` now is at models, but if we want to move it into `repo`
model, it will depend on `Team`. So this PR also makes repo model depend
on org model to make it possible. Just refactor, no code change.

- [x] Move `DeleteOrganization` from `models/organization` to service
layer
- [x] Move `AccessibleTeamReposEnv` to `models/repo`
- [x] Move `RepoTransfer` from `models` to `models/repo`
- [x] Merge `getUserTeamIDs` and `GetUserTeamIDs`, Merge `GetUserTeams`
and `getUserTeams`.
- [x] Remove `Team`'s `Repos []*repo_model.Repository` to avoid dependency recycle.
This commit is contained in:
Lunny Xiao 2024-12-17 19:44:16 -08:00 committed by GitHub
parent b945742293
commit e4c4629465
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 383 additions and 389 deletions

View File

@ -511,7 +511,7 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
} }
if opts.RequestedTeam != nil { if opts.RequestedTeam != nil {
env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam) env := repo_model.AccessibleTeamReposEnv(ctx, organization.OrgFromUser(opts.RequestedUser), 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: %w", err) return nil, fmt.Errorf("GetTeamRepositories: %w", err)

View File

@ -72,48 +72,6 @@ func (err ErrDeleteLastAdminUser) Error() string {
return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID) return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID)
} }
// ErrNoPendingRepoTransfer is an error type for repositories without a pending
// transfer request
type ErrNoPendingRepoTransfer struct {
RepoID int64
}
func (err ErrNoPendingRepoTransfer) Error() string {
return fmt.Sprintf("repository doesn't have a pending transfer [repo_id: %d]", err.RepoID)
}
// IsErrNoPendingTransfer is an error type when a repository has no pending
// transfers
func IsErrNoPendingTransfer(err error) bool {
_, ok := err.(ErrNoPendingRepoTransfer)
return ok
}
func (err ErrNoPendingRepoTransfer) Unwrap() error {
return util.ErrNotExist
}
// ErrRepoTransferInProgress represents the state of a repository that has an
// ongoing transfer
type ErrRepoTransferInProgress struct {
Uname string
Name string
}
// IsErrRepoTransferInProgress checks if an error is a ErrRepoTransferInProgress.
func IsErrRepoTransferInProgress(err error) bool {
_, ok := err.(ErrRepoTransferInProgress)
return ok
}
func (err ErrRepoTransferInProgress) Error() string {
return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name)
}
func (err ErrRepoTransferInProgress) Unwrap() error {
return util.ErrAlreadyExist
}
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error. // ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
type ErrInvalidCloneAddr struct { type ErrInvalidCloneAddr struct {
Host string Host string

View File

@ -9,11 +9,8 @@ import (
"fmt" "fmt"
"strings" "strings"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
"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/log" "code.gitea.io/gitea/modules/log"
@ -407,33 +404,6 @@ func GetOrgByName(ctx context.Context, name string) (*Organization, error) {
return u, nil return u, nil
} }
// 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},
&TeamInvite{OrgID: org.ID},
&secret_model.Secret{OwnerID: org.ID},
&user_model.Blocking{BlockerID: org.ID},
&actions_model.ActionRunner{OwnerID: org.ID},
&actions_model.ActionRunnerToken{OwnerID: org.ID},
); err != nil {
return fmt.Errorf("DeleteBeans: %w", err)
}
if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil {
return fmt.Errorf("Delete: %w", err)
}
return nil
}
// GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization // GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization
func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) { func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) {
var authorize perm.AccessMode var authorize perm.AccessMode
@ -604,7 +574,9 @@ func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error {
return err return err
} }
func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) { // GetUserTeams returns all teams that belong to user,
// and that the user has joined.
func (org *Organization) GetUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) {
teams := make([]*Team, 0, org.NumTeams) teams := make([]*Team, 0, org.NumTeams)
return teams, db.GetEngine(ctx). return teams, db.GetEngine(ctx).
Where("`team_user`.org_id = ?", org.ID). Where("`team_user`.org_id = ?", org.ID).
@ -616,7 +588,8 @@ func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ..
Find(&teams) Find(&teams)
} }
func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) { // GetUserTeamIDs returns of all team IDs of the organization that user is member of.
func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) {
teamIDs := make([]int64, 0, org.NumTeams) teamIDs := make([]int64, 0, org.NumTeams)
return teamIDs, db.GetEngine(ctx). return teamIDs, db.GetEngine(ctx).
Table("team"). Table("team").
@ -640,175 +613,3 @@ func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder {
func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) { func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) {
return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode) return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode)
} }
// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) {
return org.getUserTeamIDs(ctx, userID)
}
// GetUserTeams returns all teams that belong to user,
// and that the user has joined.
func (org *Organization) GetUserTeams(ctx context.Context, userID int64) ([]*Team, error) {
return org.getUserTeams(ctx, 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.RepositoryList, error)
MirrorRepos() (repo_model.RepositoryList, error)
AddKeyword(keyword string)
SetSort(db.SearchOrderBy)
}
type accessibleReposEnv struct {
org *Organization
user *user_model.User
team *Team
teamIDs []int64
ctx context.Context
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.GetUserByID(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,
ctx: ctx,
orderBy: db.SearchOrderByRecentUpdated,
}, nil
}
// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
// that are accessible to the specified team.
func (org *Organization) AccessibleTeamReposEnv(ctx context.Context, team *Team) AccessibleReposEnvironment {
return &accessibleReposEnv{
org: org,
team: team,
ctx: ctx,
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 := db.GetEngine(env.ctx).
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: %w", 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, db.GetEngine(env.ctx).
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.RepositoryList, error) {
repoIDs, err := env.RepoIDs(page, pageSize)
if err != nil {
return nil, fmt.Errorf("GetUserRepositoryIDs: %w", err)
}
repos := make([]*repo_model.Repository, 0, len(repoIDs))
if len(repoIDs) == 0 {
return repos, nil
}
return repos, db.GetEngine(env.ctx).
In("`repository`.id", repoIDs).
OrderBy(string(env.orderBy)).
Find(&repos)
}
func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
repoIDs := make([]int64, 0, 10)
return repoIDs, db.GetEngine(env.ctx).
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.RepositoryList, error) {
repoIDs, err := env.MirrorRepoIDs()
if err != nil {
return nil, fmt.Errorf("MirrorRepoIDs: %w", err)
}
repos := make([]*repo_model.Repository, 0, len(repoIDs))
if len(repoIDs) == 0 {
return repos, nil
}
return repos, db.GetEngine(env.ctx).
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
}

View File

@ -1,17 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package organization
import (
"context"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
)
// GetOrgRepositories get repos belonging to the given organization
func GetOrgRepositories(ctx context.Context, orgID int64) (repo_model.RepositoryList, error) {
var orgRepos []*repo_model.Repository
return orgRepos, db.GetEngine(ctx).Where("owner_id = ?", orgID).Find(&orgRepos)
}

View File

@ -318,7 +318,7 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
testSuccess := func(userID, expectedCount int64) { testSuccess := func(userID, expectedCount int64) {
env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
assert.NoError(t, err) assert.NoError(t, err)
count, err := env.CountRepos() count, err := env.CountRepos()
assert.NoError(t, err) assert.NoError(t, err)
@ -332,7 +332,7 @@ func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
testSuccess := func(userID int64, expectedRepoIDs []int64) { testSuccess := func(userID int64, expectedRepoIDs []int64) {
env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
assert.NoError(t, err) assert.NoError(t, err)
repoIDs, err := env.RepoIDs(1, 100) repoIDs, err := env.RepoIDs(1, 100)
assert.NoError(t, err) assert.NoError(t, err)
@ -346,7 +346,7 @@ func TestAccessibleReposEnv_Repos(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
testSuccess := func(userID int64, expectedRepoIDs []int64) { testSuccess := func(userID int64, expectedRepoIDs []int64) {
env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
assert.NoError(t, err) assert.NoError(t, err)
repos, err := env.Repos(1, 100) repos, err := env.Repos(1, 100)
assert.NoError(t, err) assert.NoError(t, err)
@ -365,7 +365,7 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
testSuccess := func(userID int64, expectedRepoIDs []int64) { testSuccess := func(userID int64, expectedRepoIDs []int64) {
env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) env, err := repo_model.AccessibleReposEnv(db.DefaultContext, org, userID)
assert.NoError(t, err) assert.NoError(t, err)
repos, err := env.MirrorRepos() repos, err := env.MirrorRepos()
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -11,7 +11,6 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
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"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -78,9 +77,8 @@ type Team struct {
LowerName string LowerName string
Name string Name string
Description string Description string
AccessMode perm.AccessMode `xorm:"'authorize'"` AccessMode perm.AccessMode `xorm:"'authorize'"`
Repos []*repo_model.Repository `xorm:"-"` Members []*user_model.User `xorm:"-"`
Members []*user_model.User `xorm:"-"`
NumRepos int NumRepos int
NumMembers int NumMembers int
Units []*TeamUnit `xorm:"-"` Units []*TeamUnit `xorm:"-"`
@ -155,17 +153,6 @@ func (t *Team) IsMember(ctx context.Context, userID int64) bool {
return isMember return isMember
} }
// LoadRepositories returns paginated repositories in team of organization.
func (t *Team) LoadRepositories(ctx context.Context) (err error) {
if t.Repos != nil {
return nil
}
t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{
TeamID: t.ID,
})
return err
}
// LoadMembers returns paginated members in team of organization. // LoadMembers returns paginated members in team of organization.
func (t *Team) LoadMembers(ctx context.Context) (err error) { func (t *Team) LoadMembers(ctx context.Context) (err error) {
t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{ t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{

View File

@ -9,7 +9,6 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
"xorm.io/builder" "xorm.io/builder"
@ -98,11 +97,11 @@ func SearchTeam(ctx context.Context, opts *SearchTeamOptions) (TeamList, int64,
} }
// GetRepoTeams gets the list of teams that has access to the repository // GetRepoTeams gets the list of teams that has access to the repository
func GetRepoTeams(ctx context.Context, repo *repo_model.Repository) (teams TeamList, err error) { func GetRepoTeams(ctx context.Context, orgID, repoID int64) (teams TeamList, err error) {
return teams, db.GetEngine(ctx). return teams, 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.org_id = ?", repo.OwnerID). Where("team.org_id = ?", orgID).
And("team_repo.repo_id=?", repo.ID). And("team_repo.repo_id=?", repoID).
OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END"). OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
Find(&teams) Find(&teams)
} }

View File

@ -8,10 +8,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
"xorm.io/builder"
) )
// TeamRepo represents an team-repository relation. // TeamRepo represents an team-repository relation.
@ -32,29 +29,6 @@ func HasTeamRepo(ctx context.Context, orgID, teamID, repoID int64) bool {
return has 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.RepositoryList, 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-1)*opts.PageSize)
}
var repos []*repo_model.Repository
return repos, sess.OrderBy("repository.name").
Find(&repos)
}
// AddTeamRepo adds a repo for an organization's team // AddTeamRepo adds a repo for an organization's team
func AddTeamRepo(ctx context.Context, orgID, teamID, repoID int64) error { func AddTeamRepo(ctx context.Context, orgID, teamID, repoID int64) error {
_, err := db.GetEngine(ctx).Insert(&TeamRepo{ _, err := db.GetEngine(ctx).Insert(&TeamRepo{

View File

@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -42,9 +43,12 @@ func TestTeam_GetRepositories(t *testing.T) {
test := func(teamID int64) { test := func(teamID int64) {
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
assert.NoError(t, team.LoadRepositories(db.DefaultContext)) repos, err := repo_model.GetTeamRepositories(db.DefaultContext, &repo_model.SearchTeamRepoOptions{
assert.Len(t, team.Repos, team.NumRepos) TeamID: team.ID,
for _, repo := range team.Repos { })
assert.NoError(t, err)
assert.Len(t, repos, team.NumRepos)
for _, repo := range repos {
unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID}) unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID})
} }
} }

206
models/repo/org_repo.go Normal file
View File

@ -0,0 +1,206 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"context"
"fmt"
"strings"
"code.gitea.io/gitea/models/db"
org_model "code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
"xorm.io/builder"
)
// GetOrgRepositories get repos belonging to the given organization
func GetOrgRepositories(ctx context.Context, orgID int64) (RepositoryList, error) {
var orgRepos []*Repository
return orgRepos, db.GetEngine(ctx).Where("owner_id = ?", orgID).Find(&orgRepos)
}
type SearchTeamRepoOptions struct {
db.ListOptions
TeamID int64
}
// GetRepositories returns paginated repositories in team of organization.
func GetTeamRepositories(ctx context.Context, opts *SearchTeamRepoOptions) (RepositoryList, 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-1)*opts.PageSize)
}
var repos []*Repository
return repos, sess.OrderBy("repository.name").
Find(&repos)
}
// 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) (RepositoryList, error)
MirrorRepos() (RepositoryList, error)
AddKeyword(keyword string)
SetSort(db.SearchOrderBy)
}
type accessibleReposEnv struct {
org *org_model.Organization
user *user_model.User
team *org_model.Team
teamIDs []int64
ctx context.Context
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 *org_model.Organization, userID int64) (AccessibleReposEnvironment, error) {
var user *user_model.User
if userID > 0 {
u, err := user_model.GetUserByID(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,
ctx: ctx,
orderBy: db.SearchOrderByRecentUpdated,
}, nil
}
// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
// that are accessible to the specified team.
func AccessibleTeamReposEnv(ctx context.Context, org *org_model.Organization, team *org_model.Team) AccessibleReposEnvironment {
return &accessibleReposEnv{
org: org,
team: team,
ctx: ctx,
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 := db.GetEngine(env.ctx).
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
Where(env.cond()).
Distinct("`repository`.id").
Count(&Repository{})
if err != nil {
return 0, fmt.Errorf("count user repositories in organization: %w", 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, db.GetEngine(env.ctx).
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) (RepositoryList, error) {
repoIDs, err := env.RepoIDs(page, pageSize)
if err != nil {
return nil, fmt.Errorf("GetUserRepositoryIDs: %w", err)
}
repos := make([]*Repository, 0, len(repoIDs))
if len(repoIDs) == 0 {
return repos, nil
}
return repos, db.GetEngine(env.ctx).
In("`repository`.id", repoIDs).
OrderBy(string(env.orderBy)).
Find(&repos)
}
func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
repoIDs := make([]int64, 0, 10)
return repoIDs, db.GetEngine(env.ctx).
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() (RepositoryList, error) {
repoIDs, err := env.MirrorRepoIDs()
if err != nil {
return nil, fmt.Errorf("MirrorRepoIDs: %w", err)
}
repos := make([]*Repository, 0, len(repoIDs))
if len(repoIDs) == 0 {
return repos, nil
}
return repos, db.GetEngine(env.ctx).
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
}

View File

@ -1,7 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved. // Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
package models package repo
import ( import (
"context" "context"
@ -10,16 +10,58 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
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"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
) )
// ErrNoPendingRepoTransfer is an error type for repositories without a pending
// transfer request
type ErrNoPendingRepoTransfer struct {
RepoID int64
}
func (err ErrNoPendingRepoTransfer) Error() string {
return fmt.Sprintf("repository doesn't have a pending transfer [repo_id: %d]", err.RepoID)
}
// IsErrNoPendingTransfer is an error type when a repository has no pending
// transfers
func IsErrNoPendingTransfer(err error) bool {
_, ok := err.(ErrNoPendingRepoTransfer)
return ok
}
func (err ErrNoPendingRepoTransfer) Unwrap() error {
return util.ErrNotExist
}
// ErrRepoTransferInProgress represents the state of a repository that has an
// ongoing transfer
type ErrRepoTransferInProgress struct {
Uname string
Name string
}
// IsErrRepoTransferInProgress checks if an error is a ErrRepoTransferInProgress.
func IsErrRepoTransferInProgress(err error) bool {
_, ok := err.(ErrRepoTransferInProgress)
return ok
}
func (err ErrRepoTransferInProgress) Error() string {
return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name)
}
func (err ErrRepoTransferInProgress) Unwrap() error {
return util.ErrAlreadyExist
}
// RepoTransfer is used to manage repository transfers // RepoTransfer is used to manage repository transfers
type RepoTransfer struct { type RepoTransfer struct { //nolint
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
DoerID int64 DoerID int64
Doer *user_model.User `xorm:"-"` Doer *user_model.User `xorm:"-"`
@ -126,7 +168,7 @@ func GetPendingRepositoryTransfers(ctx context.Context, opts *PendingRepositoryT
// GetPendingRepositoryTransfer fetches the most recent and ongoing transfer // GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
// process for the repository // process for the repository
func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) (*RepoTransfer, error) { func GetPendingRepositoryTransfer(ctx context.Context, repo *Repository) (*RepoTransfer, error) {
transfers, err := GetPendingRepositoryTransfers(ctx, &PendingRepositoryTransferOptions{RepoID: repo.ID}) transfers, err := GetPendingRepositoryTransfers(ctx, &PendingRepositoryTransferOptions{RepoID: repo.ID})
if err != nil { if err != nil {
return nil, err return nil, err
@ -145,11 +187,11 @@ func DeleteRepositoryTransfer(ctx context.Context, repoID int64) error {
} }
// TestRepositoryReadyForTransfer make sure repo is ready to transfer // TestRepositoryReadyForTransfer make sure repo is ready to transfer
func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error { func TestRepositoryReadyForTransfer(status RepositoryStatus) error {
switch status { switch status {
case repo_model.RepositoryBeingMigrated: case RepositoryBeingMigrated:
return errors.New("repo is not ready, currently migrating") return errors.New("repo is not ready, currently migrating")
case repo_model.RepositoryPendingTransfer: case RepositoryPendingTransfer:
return ErrRepoTransferInProgress{} return ErrRepoTransferInProgress{}
} }
return nil return nil
@ -159,7 +201,7 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
// it marks the repository transfer as "pending" // it marks the repository transfer as "pending"
func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error { func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
return db.WithTx(ctx, func(ctx context.Context) error { return db.WithTx(ctx, func(ctx context.Context) error {
repo, err := repo_model.GetRepositoryByID(ctx, repoID) repo, err := GetRepositoryByID(ctx, repoID)
if err != nil { if err != nil {
return err return err
} }
@ -169,16 +211,16 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m
return err return err
} }
repo.Status = repo_model.RepositoryPendingTransfer repo.Status = RepositoryPendingTransfer
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { if err := UpdateRepositoryCols(ctx, repo, "status"); err != nil {
return err return err
} }
// Check if new owner has repository with same name. // Check if new owner has repository with same name.
if has, err := repo_model.IsRepositoryModelExist(ctx, newOwner, repo.Name); err != nil { if has, err := IsRepositoryModelExist(ctx, newOwner, repo.Name); err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err) return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has { } else if has {
return repo_model.ErrRepoAlreadyExist{ return ErrRepoAlreadyExist{
Uname: newOwner.LowerName, Uname: newOwner.LowerName,
Name: repo.Name, Name: repo.Name,
} }

View File

@ -573,19 +573,19 @@ func GetTeamRepos(ctx *context.APIContext) {
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
team := ctx.Org.Team team := ctx.Org.Team
teamRepos, err := organization.GetTeamRepositories(ctx, &organization.SearchTeamRepoOptions{ teamRepos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
ListOptions: utils.GetListOptions(ctx), ListOptions: utils.GetListOptions(ctx),
TeamID: team.ID, TeamID: team.ID,
}) })
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) ctx.Error(http.StatusInternalServerError, "GetTeamRepositories", err)
return return
} }
repos := make([]*api.Repository, len(teamRepos)) repos := make([]*api.Repository, len(teamRepos))
for i, repo := range teamRepos { for i, repo := range teamRepos {
permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
return return
} }
repos[i] = convert.ToRepo(ctx, repo, permission) repos[i] = convert.ToRepo(ctx, repo, permission)

View File

@ -42,7 +42,7 @@ func ListTeams(ctx *context.APIContext) {
return return
} }
teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository) teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return

View File

@ -8,7 +8,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access" access_model "code.gitea.io/gitea/models/perm/access"
@ -108,7 +107,7 @@ func Transfer(ctx *context.APIContext) {
oldFullname := ctx.Repo.Repository.FullName() oldFullname := ctx.Repo.Repository.FullName()
if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil { if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil {
if models.IsErrRepoTransferInProgress(err) { if repo_model.IsErrRepoTransferInProgress(err) {
ctx.Error(http.StatusConflict, "StartRepositoryTransfer", err) ctx.Error(http.StatusConflict, "StartRepositoryTransfer", err)
return return
} }
@ -213,9 +212,9 @@ func RejectTransfer(ctx *context.APIContext) {
} }
func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil { if err != nil {
if models.IsErrNoPendingTransfer(err) { if repo_model.IsErrNoPendingTransfer(err) {
ctx.NotFound() ctx.NotFound()
return nil return nil
} }

View File

@ -410,11 +410,15 @@ func TeamRepositories(ctx *context.Context) {
return return
} }
if err := ctx.Org.Team.LoadRepositories(ctx); err != nil { repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
ctx.ServerError("GetRepositories", err) TeamID: ctx.Org.Team.ID,
})
if err != nil {
ctx.ServerError("GetTeamRepositories", err)
return return
} }
ctx.Data["Units"] = unit_model.Units ctx.Data["Units"] = unit_model.Units
ctx.Data["TeamRepos"] = repos
ctx.HTML(http.StatusOK, tplTeamRepositories) ctx.HTML(http.StatusOK, tplTeamRepositories)
} }

View File

@ -11,7 +11,6 @@ import (
"slices" "slices"
"strings" "strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git" git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
@ -378,7 +377,7 @@ func Action(ctx *context.Context) {
} }
func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error { func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error {
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil { if err != nil {
return err return err
} }

View File

@ -32,7 +32,7 @@ func Collaboration(ctx *context.Context) {
} }
ctx.Data["Collaborators"] = users ctx.Data["Collaborators"] = users
teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository) teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID)
if err != nil { if err != nil {
ctx.ServerError("GetRepoTeams", err) ctx.ServerError("GetRepoTeams", err)
return return

View File

@ -788,7 +788,7 @@ func SettingsPost(ctx *context.Context) {
if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil { if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil {
if repo_model.IsErrRepoAlreadyExist(err) { if repo_model.IsErrRepoAlreadyExist(err) {
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
} else if models.IsErrRepoTransferInProgress(err) { } else if repo_model.IsErrRepoTransferInProgress(err) {
ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil) ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
} else if errors.Is(err, user_model.ErrBlockedUser) { } else if errors.Is(err, user_model.ErrBlockedUser) {
ctx.RenderWithErr(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil) ctx.RenderWithErr(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil)
@ -814,9 +814,9 @@ func SettingsPost(ctx *context.Context) {
return return
} }
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil { if err != nil {
if models.IsErrNoPendingTransfer(err) { if repo_model.IsErrNoPendingTransfer(err) {
ctx.Flash.Error("repo.settings.transfer_abort_invalid") ctx.Flash.Error("repo.settings.transfer_abort_invalid")
ctx.Redirect(repo.Link() + "/settings") ctx.Redirect(repo.Link() + "/settings")
} else { } else {

View File

@ -14,7 +14,6 @@ import (
"path" "path"
"strings" "strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git" git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
@ -709,7 +708,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer { if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil { if err != nil {
ctx.ServerError("GetPendingRepositoryTransfer", err) ctx.ServerError("GetPendingRepositoryTransfer", err)
return cancel return cancel

View File

@ -7,7 +7,6 @@ import (
"context" "context"
"time" "time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access" access_model "code.gitea.io/gitea/models/perm/access"
@ -158,8 +157,8 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
var transfer *api.RepoTransfer var transfer *api.RepoTransfer
if repo.Status == repo_model.RepositoryPendingTransfer { if repo.Status == repo_model.RepositoryPendingTransfer {
t, err := models.GetPendingRepositoryTransfer(ctx, repo) t, err := repo_model.GetPendingRepositoryTransfer(ctx, repo)
if err != nil && !models.IsErrNoPendingTransfer(err) { if err != nil && !repo_model.IsErrNoPendingTransfer(err) {
log.Warn("GetPendingRepositoryTransfer: %v", err) log.Warn("GetPendingRepositoryTransfer: %v", err)
} else { } else {
if err := t.LoadAttributes(ctx); err != nil { if err := t.LoadAttributes(ctx); err != nil {
@ -248,7 +247,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
} }
// ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer // ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer
func ToRepoTransfer(ctx context.Context, t *models.RepoTransfer) *api.RepoTransfer { func ToRepoTransfer(ctx context.Context, t *repo_model.RepoTransfer) *api.RepoTransfer {
teams, _ := ToTeams(ctx, t.Teams, false) teams, _ := ToTeams(ctx, t.Teams, false)
return &api.RepoTransfer{ return &api.RepoTransfer{

View File

@ -8,16 +8,45 @@ import (
"fmt" "fmt"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
org_model "code.gitea.io/gitea/models/organization" org_model "code.gitea.io/gitea/models/organization"
packages_model "code.gitea.io/gitea/models/packages" packages_model "code.gitea.io/gitea/models/packages"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
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"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
repo_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository"
) )
// deleteOrganization deletes models associated to an organization.
func deleteOrganization(ctx context.Context, org *org_model.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,
&org_model.Team{OrgID: org.ID},
&org_model.OrgUser{OrgID: org.ID},
&org_model.TeamUser{OrgID: org.ID},
&org_model.TeamUnit{OrgID: org.ID},
&org_model.TeamInvite{OrgID: org.ID},
&secret_model.Secret{OwnerID: org.ID},
&user_model.Blocking{BlockerID: org.ID},
&actions_model.ActionRunner{OwnerID: org.ID},
&actions_model.ActionRunnerToken{OwnerID: org.ID},
); err != nil {
return fmt.Errorf("DeleteBeans: %w", err)
}
if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil {
return fmt.Errorf("Delete: %w", err)
}
return nil
}
// DeleteOrganization completely and permanently deletes everything of organization. // DeleteOrganization completely and permanently deletes everything of organization.
func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error { func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error {
ctx, committer, err := db.TxContext(ctx) ctx, committer, err := db.TxContext(ctx)
@ -48,7 +77,7 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge
return models.ErrUserOwnPackages{UID: org.ID} return models.ErrUserOwnPackages{UID: org.ID}
} }
if err := org_model.DeleteOrganization(ctx, org); err != nil { if err := deleteOrganization(ctx, org); err != nil {
return fmt.Errorf("DeleteOrganization: %w", err) return fmt.Errorf("DeleteOrganization: %w", err)
} }

View File

@ -141,11 +141,14 @@ func UpdateTeam(ctx context.Context, t *organization.Team, authChanged, includeA
// Update access for team members if needed. // Update access for team members if needed.
if authChanged { if authChanged {
if err = t.LoadRepositories(ctx); err != nil { repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
return fmt.Errorf("LoadRepositories: %w", err) TeamID: t.ID,
})
if err != nil {
return fmt.Errorf("GetTeamRepositories: %w", err)
} }
for _, repo := range t.Repos { for _, repo := range repos {
if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil { if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
return fmt.Errorf("recalculateTeamAccesses: %w", err) return fmt.Errorf("recalculateTeamAccesses: %w", err)
} }
@ -172,10 +175,6 @@ func DeleteTeam(ctx context.Context, t *organization.Team) error {
} }
defer committer.Close() defer committer.Close()
if err := t.LoadRepositories(ctx); err != nil {
return err
}
if err := t.LoadMembers(ctx); err != nil { if err := t.LoadMembers(ctx); err != nil {
return err return err
} }
@ -301,8 +300,11 @@ func AddTeamMember(ctx context.Context, team *organization.Team, user *user_mode
// FIXME: Update watch repos batchly // FIXME: Update watch repos batchly
if setting.Service.AutoWatchNewRepos { if setting.Service.AutoWatchNewRepos {
// Get team and its repositories. // Get team and its repositories.
if err := team.LoadRepositories(ctx); err != nil { repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
log.Error("team.LoadRepositories failed: %v", err) TeamID: team.ID,
})
if err != nil {
log.Error("GetTeamRepositories failed: %v", err)
} }
// FIXME: in the goroutine, it can't access the "ctx", it could only use db.DefaultContext at the moment // FIXME: in the goroutine, it can't access the "ctx", it could only use db.DefaultContext at the moment
@ -312,7 +314,7 @@ func AddTeamMember(ctx context.Context, team *organization.Team, user *user_mode
log.Error("watch repo failed: %v", err) log.Error("watch repo failed: %v", err)
} }
} }
}(team.Repos) }(repos)
} }
return nil return nil
@ -332,7 +334,10 @@ func removeTeamMember(ctx context.Context, team *organization.Team, user *user_m
team.NumMembers-- team.NumMembers--
if err := team.LoadRepositories(ctx); err != nil { repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
TeamID: team.ID,
})
if err != nil {
return err return err
} }
@ -350,7 +355,7 @@ func removeTeamMember(ctx context.Context, team *organization.Team, user *user_m
} }
// Delete access to team repositories. // Delete access to team repositories.
for _, repo := range team.Repos { for _, repo := range repos {
if err := access_model.RecalculateUserAccess(ctx, repo, user.ID); err != nil { if err := access_model.RecalculateUserAccess(ctx, repo, user.ID); err != nil {
return err return err
} }

View File

@ -189,9 +189,12 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
testTeamRepositories := func(teamID int64, repoIDs []int64) { testTeamRepositories := func(teamID int64, repoIDs []int64) {
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
assert.NoError(t, team.LoadRepositories(db.DefaultContext), "%s: GetRepositories", team.Name) repos, err := repo_model.GetTeamRepositories(db.DefaultContext, &repo_model.SearchTeamRepoOptions{
assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name) TeamID: team.ID,
assert.Len(t, team.Repos, len(repoIDs), "%s: repo count", team.Name) })
assert.NoError(t, err, "%s: GetTeamRepositories", team.Name)
assert.Len(t, repos, team.NumRepos, "%s: len repo", team.Name)
assert.Len(t, 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, repo_service.HasRepository(db.DefaultContext, team, rid), "%s: HasRepository(%d) %d", rid, i) assert.True(t, repo_service.HasRepository(db.DefaultContext, team, rid), "%s: HasRepository(%d) %d", rid, i)
@ -310,5 +313,5 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
assert.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, user, rid), "DeleteRepository %d", i) assert.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, user, rid), "DeleteRepository %d", i)
} }
} }
assert.NoError(t, organization.DeleteOrganization(db.DefaultContext, org), "DeleteOrganization") assert.NoError(t, DeleteOrganization(db.DefaultContext, org, false), "DeleteOrganization")
} }

View File

@ -60,7 +60,7 @@ func RemoveOrgUser(ctx context.Context, org *organization.Organization, user *us
} }
// Delete all repository accesses and unwatch them. // Delete all repository accesses and unwatch them.
env, err := organization.AccessibleReposEnv(ctx, org, user.ID) env, err := repo_model.AccessibleReposEnv(ctx, org, user.ID)
if err != nil { if err != nil {
return fmt.Errorf("AccessibleReposEnv: %w", err) return fmt.Errorf("AccessibleReposEnv: %w", err)
} }

View File

@ -63,7 +63,7 @@ func addRepositoryToTeam(ctx context.Context, t *organization.Team, repo *repo_m
// 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 AddAllRepositoriesToTeam(ctx context.Context, t *organization.Team) error { func AddAllRepositoriesToTeam(ctx context.Context, t *organization.Team) error {
return db.WithTx(ctx, func(ctx context.Context) error { return db.WithTx(ctx, func(ctx context.Context) error {
orgRepos, err := organization.GetOrgRepositories(ctx, t.OrgID) orgRepos, err := repo_model.GetOrgRepositories(ctx, t.OrgID)
if err != nil { if err != nil {
return fmt.Errorf("get org repos: %w", err) return fmt.Errorf("get org repos: %w", err)
} }
@ -103,8 +103,15 @@ func RemoveAllRepositoriesFromTeam(ctx context.Context, t *organization.Team) (e
// Note: Shall not be called if team includes all repositories // Note: Shall not be called if team includes all repositories
func removeAllRepositoriesFromTeam(ctx context.Context, t *organization.Team) (err error) { func removeAllRepositoriesFromTeam(ctx context.Context, t *organization.Team) (err error) {
e := db.GetEngine(ctx) e := db.GetEngine(ctx)
repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
TeamID: t.ID,
})
if err != nil {
return fmt.Errorf("GetTeamRepositories: %w", err)
}
// Delete all accesses. // Delete all accesses.
for _, repo := range t.Repos { for _, repo := range repos {
if err := access_model.RecalculateTeamAccesses(ctx, repo, t.ID); err != nil { if err := access_model.RecalculateTeamAccesses(ctx, repo, t.ID); err != nil {
return err return err
} }

View File

@ -9,7 +9,6 @@ import (
"os" "os"
"strings" "strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
@ -285,7 +284,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
wikiRenamed = true wikiRenamed = true
} }
if err := models.DeleteRepositoryTransfer(ctx, repo.ID); err != nil { if err := repo_model.DeleteRepositoryTransfer(ctx, repo.ID); err != nil {
return fmt.Errorf("deleteRepositoryTransfer: %w", err) return fmt.Errorf("deleteRepositoryTransfer: %w", err)
} }
repo.Status = repo_model.RepositoryReady repo.Status = repo_model.RepositoryReady
@ -388,7 +387,7 @@ func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo
// 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(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
if err := models.TestRepositoryReadyForTransfer(repo.Status); err != nil { if err := repo_model.TestRepositoryReadyForTransfer(repo.Status); err != nil {
return err return err
} }
@ -425,7 +424,7 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use
// Make repo as pending for transfer // Make repo as pending for transfer
repo.Status = repo_model.RepositoryPendingTransfer repo.Status = repo_model.RepositoryPendingTransfer
if err := models.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams); err != nil { if err := repo_model.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams); err != nil {
return err return err
} }
@ -449,7 +448,7 @@ func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository)
return err return err
} }
if err := models.DeleteRepositoryTransfer(ctx, repo.ID); err != nil { if err := repo_model.DeleteRepositoryTransfer(ctx, repo.ID); err != nil {
return err return err
} }

View File

@ -7,7 +7,6 @@ import (
"sync" "sync"
"testing" "testing"
"code.gitea.io/gitea/models"
activities_model "code.gitea.io/gitea/models/activities" activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
@ -86,23 +85,23 @@ func TestRepositoryTransfer(t *testing.T) {
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
transfer, err := models.GetPendingRepositoryTransfer(db.DefaultContext, repo) transfer, err := repo_model.GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, transfer) assert.NotNil(t, transfer)
// Cancel transfer // Cancel transfer
assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo)) assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo))
transfer, err = models.GetPendingRepositoryTransfer(db.DefaultContext, repo) transfer, err = repo_model.GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, transfer) assert.Nil(t, transfer)
assert.True(t, models.IsErrNoPendingTransfer(err)) assert.True(t, repo_model.IsErrNoPendingTransfer(err))
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
assert.NoError(t, models.CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil)) assert.NoError(t, repo_model.CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil))
transfer, err = models.GetPendingRepositoryTransfer(db.DefaultContext, repo) transfer, err = repo_model.GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, transfer.LoadAttributes(db.DefaultContext)) assert.NoError(t, transfer.LoadAttributes(db.DefaultContext))
assert.Equal(t, "user2", transfer.Recipient.Name) assert.Equal(t, "user2", transfer.Recipient.Name)
@ -110,12 +109,12 @@ func TestRepositoryTransfer(t *testing.T) {
org6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) org6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// Only transfer can be started at any given time // Only transfer can be started at any given time
err = models.CreatePendingRepositoryTransfer(db.DefaultContext, doer, org6, repo.ID, nil) err = repo_model.CreatePendingRepositoryTransfer(db.DefaultContext, doer, org6, repo.ID, nil)
assert.Error(t, err) assert.Error(t, err)
assert.True(t, models.IsErrRepoTransferInProgress(err)) assert.True(t, repo_model.IsErrRepoTransferInProgress(err))
// Unknown user // Unknown user
err = models.CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil) err = repo_model.CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
assert.Error(t, err) assert.Error(t, err)
// Cancel transfer // Cancel transfer

View File

@ -6,7 +6,6 @@ package user
import ( import (
"context" "context"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
org_model "code.gitea.io/gitea/models/organization" org_model "code.gitea.io/gitea/models/organization"
@ -194,7 +193,7 @@ func unwatchRepos(ctx context.Context, watcher, repoOwner *user_model.User) erro
} }
func cancelRepositoryTransfers(ctx context.Context, sender, recipient *user_model.User) error { func cancelRepositoryTransfers(ctx context.Context, sender, recipient *user_model.User) error {
transfers, err := models.GetPendingRepositoryTransfers(ctx, &models.PendingRepositoryTransferOptions{ transfers, err := repo_model.GetPendingRepositoryTransfers(ctx, &repo_model.PendingRepositoryTransferOptions{
SenderID: sender.ID, SenderID: sender.ID,
RecipientID: recipient.ID, RecipientID: recipient.ID,
}) })

View File

@ -27,7 +27,7 @@
{{end}} {{end}}
<div class="ui{{if not $canAddRemove}} top{{end}} attached segment"> <div class="ui{{if not $canAddRemove}} top{{end}} attached segment">
<div class="flex-list"> <div class="flex-list">
{{range .Team.Repos}} {{range $.TeamRepos}}
<div class="flex-item tw-items-center"> <div class="flex-item tw-items-center">
<div class="flex-item-leading"> <div class="flex-item-leading">
{{template "repo/icon" .}} {{template "repo/icon" .}}

View File

@ -8,7 +8,6 @@ import (
"net/http" "net/http"
"testing" "testing"
"code.gitea.io/gitea/models"
auth_model "code.gitea.io/gitea/models/auth" auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
@ -42,7 +41,7 @@ func TestBlockUser(t *testing.T) {
} }
countRepositoryTransfers := func(t *testing.T, senderID, recipientID int64) int64 { countRepositoryTransfers := func(t *testing.T, senderID, recipientID int64) int64 {
transfers, err := models.GetPendingRepositoryTransfers(db.DefaultContext, &models.PendingRepositoryTransferOptions{ transfers, err := repo_model.GetPendingRepositoryTransfers(db.DefaultContext, &repo_model.PendingRepositoryTransferOptions{
SenderID: senderID, SenderID: senderID,
RecipientID: recipientID, RecipientID: recipientID,
}) })