diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2021-12-10 09:27:50 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-10 09:27:50 +0800 |
commit | 719bddcd76610a63dadc8555760072957a11cf30 (patch) | |
tree | 0df26092fba7e3e21444fe493e6b349473b6b0cb /models | |
parent | fb8166c6c6b652a0e6fa98681780a6a71090faf3 (diff) | |
download | gitea-719bddcd76610a63dadc8555760072957a11cf30.tar.gz gitea-719bddcd76610a63dadc8555760072957a11cf30.zip |
Move repository model into models/repo (#17933)
* Some refactors related repository model
* Move more methods out of repository
* Move repository into models/repo
* Fix test
* Fix test
* some improvements
* Remove unnecessary function
Diffstat (limited to 'models')
91 files changed, 2012 insertions, 1924 deletions
diff --git a/models/access.go b/models/access.go index f7252019aa..6a97bcffcf 100644 --- a/models/access.go +++ b/models/access.go @@ -6,10 +6,12 @@ package models import ( + "context" "fmt" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" ) @@ -27,7 +29,7 @@ func init() { db.RegisterModel(new(Access)) } -func accessLevel(e db.Engine, user *user_model.User, repo *Repository) (perm.AccessMode, error) { +func accessLevel(e db.Engine, user *user_model.User, repo *repo_model.Repository) (perm.AccessMode, error) { mode := perm.AccessModeNone var userID int64 restricted := false @@ -81,7 +83,7 @@ func updateUserAccess(accessMap map[int64]*userAccess, user *user_model.User, mo } // FIXME: do cross-comparison so reduce deletions and additions to the minimum? -func (repo *Repository) refreshAccesses(e db.Engine, accessMap map[int64]*userAccess) (err error) { +func refreshAccesses(e db.Engine, repo *repo_model.Repository, accessMap map[int64]*userAccess) (err error) { minMode := perm.AccessModeRead if !repo.IsPrivate { minMode = perm.AccessModeWrite @@ -115,8 +117,8 @@ func (repo *Repository) refreshAccesses(e db.Engine, accessMap map[int64]*userAc } // refreshCollaboratorAccesses retrieves repository collaborations with their access modes. -func (repo *Repository) refreshCollaboratorAccesses(e db.Engine, accessMap map[int64]*userAccess) error { - collaborators, err := repo.getCollaborators(e, db.ListOptions{}) +func refreshCollaboratorAccesses(e db.Engine, repoID int64, accessMap map[int64]*userAccess) error { + collaborators, err := getCollaborators(e, repoID, db.ListOptions{}) if err != nil { return fmt.Errorf("getCollaborations: %v", err) } @@ -132,16 +134,18 @@ func (repo *Repository) refreshCollaboratorAccesses(e db.Engine, accessMap map[i // recalculateTeamAccesses recalculates new accesses for teams of an organization // except the team whose ID is given. It is used to assign a team ID when // remove repository from that team. -func (repo *Repository) recalculateTeamAccesses(e db.Engine, ignTeamID int64) (err error) { +func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, ignTeamID int64) (err error) { accessMap := make(map[int64]*userAccess, 20) - if err = repo.getOwner(e); err != nil { + if err = repo.GetOwner(ctx); err != nil { return err } else if !repo.Owner.IsOrganization() { return fmt.Errorf("owner is not an organization: %d", repo.OwnerID) } - if err = repo.refreshCollaboratorAccesses(e, accessMap); err != nil { + e := db.GetEngine(ctx) + + if err = refreshCollaboratorAccesses(e, repo.ID, accessMap); err != nil { return fmt.Errorf("refreshCollaboratorAccesses: %v", err) } @@ -171,26 +175,27 @@ func (repo *Repository) recalculateTeamAccesses(e db.Engine, ignTeamID int64) (e } } - return repo.refreshAccesses(e, accessMap) + return refreshAccesses(e, repo, accessMap) } // recalculateUserAccess recalculates new access for a single user // Usable if we know access only affected one user -func (repo *Repository) recalculateUserAccess(e db.Engine, uid int64) (err error) { +func recalculateUserAccess(ctx context.Context, repo *repo_model.Repository, uid int64) (err error) { minMode := perm.AccessModeRead if !repo.IsPrivate { minMode = perm.AccessModeWrite } accessMode := perm.AccessModeNone - collaborator, err := repo.getCollaboration(e, uid) + e := db.GetEngine(ctx) + collaborator, err := getCollaboration(e, repo.ID, uid) if err != nil { return err } else if collaborator != nil { accessMode = collaborator.Mode } - if err = repo.getOwner(e); err != nil { + if err = repo.GetOwner(ctx); err != nil { return err } else if repo.Owner.IsOrganization() { var teams []Team @@ -223,19 +228,20 @@ func (repo *Repository) recalculateUserAccess(e db.Engine, uid int64) (err error return nil } -func (repo *Repository) recalculateAccesses(e db.Engine) error { +func recalculateAccesses(ctx context.Context, repo *repo_model.Repository) error { if repo.Owner.IsOrganization() { - return repo.recalculateTeamAccesses(e, 0) + return recalculateTeamAccesses(ctx, repo, 0) } + e := db.GetEngine(ctx) accessMap := make(map[int64]*userAccess, 20) - if err := repo.refreshCollaboratorAccesses(e, accessMap); err != nil { + if err := refreshCollaboratorAccesses(e, repo.ID, accessMap); err != nil { return fmt.Errorf("refreshCollaboratorAccesses: %v", err) } - return repo.refreshAccesses(e, accessMap) + return refreshAccesses(e, repo, accessMap) } // RecalculateAccesses recalculates all accesses for repository. -func (repo *Repository) RecalculateAccesses() error { - return repo.recalculateAccesses(db.GetEngine(db.DefaultContext)) +func RecalculateAccesses(repo *repo_model.Repository) error { + return recalculateAccesses(db.DefaultContext, repo) } diff --git a/models/access_test.go b/models/access_test.go index 05bd1656e9..43e61e812b 100644 --- a/models/access_test.go +++ b/models/access_test.go @@ -9,6 +9,7 @@ import ( "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/unittest" user_model "code.gitea.io/gitea/models/user" @@ -22,17 +23,17 @@ func TestAccessLevel(t *testing.T) { user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User) // A public repository owned by User 2 - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) assert.False(t, repo1.IsPrivate) // A private repository owned by Org 3 - repo3 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) assert.True(t, repo3.IsPrivate) // Another public repository - repo4 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) + repo4 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) assert.False(t, repo4.IsPrivate) // org. owned private repo - repo24 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 24}).(*Repository) + repo24 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}).(*repo_model.Repository) level, err := AccessLevel(user2, repo1) assert.NoError(t, err) @@ -72,10 +73,10 @@ func TestHasAccess(t *testing.T) { user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) // A public repository owned by User 2 - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) assert.False(t, repo1.IsPrivate) // A private repository owned by Org 3 - repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) assert.True(t, repo2.IsPrivate) has, err := HasAccess(user1.ID, repo1) @@ -95,12 +96,12 @@ func TestHasAccess(t *testing.T) { func TestRepository_RecalculateAccesses(t *testing.T) { // test with organization repo assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) - assert.NoError(t, repo1.GetOwner()) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + assert.NoError(t, repo1.GetOwner(db.DefaultContext)) _, err := db.GetEngine(db.DefaultContext).Delete(&Collaboration{UserID: 2, RepoID: 3}) assert.NoError(t, err) - assert.NoError(t, repo1.RecalculateAccesses()) + assert.NoError(t, RecalculateAccesses(repo1)) access := &Access{UserID: 2, RepoID: 3} has, err := db.GetEngine(db.DefaultContext).Get(access) @@ -112,12 +113,12 @@ func TestRepository_RecalculateAccesses(t *testing.T) { func TestRepository_RecalculateAccesses2(t *testing.T) { // test with non-organization repo assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) - assert.NoError(t, repo1.GetOwner()) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + assert.NoError(t, repo1.GetOwner(db.DefaultContext)) _, err := db.GetEngine(db.DefaultContext).Delete(&Collaboration{UserID: 4, RepoID: 4}) assert.NoError(t, err) - assert.NoError(t, repo1.RecalculateAccesses()) + assert.NoError(t, RecalculateAccesses(repo1)) has, err := db.GetEngine(db.DefaultContext).Get(&Access{UserID: 4, RepoID: 4}) assert.NoError(t, err) diff --git a/models/action.go b/models/action.go index 66fa78f268..16d6c42aa5 100644 --- a/models/action.go +++ b/models/action.go @@ -6,6 +6,7 @@ package models import ( + "context" "fmt" "net/url" "path" @@ -14,6 +15,7 @@ import ( "time" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" @@ -64,13 +66,13 @@ type Action struct { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"INDEX"` // Receiver user id. OpType ActionType - ActUserID int64 `xorm:"INDEX"` // Action user id. - ActUser *user_model.User `xorm:"-"` - RepoID int64 `xorm:"INDEX"` - Repo *Repository `xorm:"-"` - CommentID int64 `xorm:"INDEX"` - Comment *Comment `xorm:"-"` - IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"` + ActUserID int64 `xorm:"INDEX"` // Action user id. + ActUser *user_model.User `xorm:"-"` + RepoID int64 `xorm:"INDEX"` + Repo *repo_model.Repository `xorm:"-"` + CommentID int64 `xorm:"INDEX"` + Comment *Comment `xorm:"-"` + IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"` RefName string IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"` Content string `xorm:"TEXT"` @@ -107,9 +109,9 @@ func (a *Action) loadRepo() { return } var err error - a.Repo, err = GetRepositoryByID(a.RepoID) + a.Repo, err = repo_model.GetRepositoryByID(a.RepoID) if err != nil { - log.Error("GetRepositoryByID(%d): %v", a.RepoID, err) + log.Error("repo_model.GetRepositoryByID(%d): %v", a.RepoID, err) } } @@ -191,16 +193,16 @@ func (a *Action) GetRepoLink() string { return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName())) } -// GetRepositoryFromMatch returns a *Repository from a username and repo strings -func GetRepositoryFromMatch(ownerName, repoName string) (*Repository, error) { +// GetRepositoryFromMatch returns a *repo_model.Repository from a username and repo strings +func GetRepositoryFromMatch(ownerName, repoName string) (*repo_model.Repository, error) { var err error - refRepo, err := GetRepositoryByOwnerAndName(ownerName, repoName) + refRepo, err := repo_model.GetRepositoryByOwnerAndName(ownerName, repoName) if err != nil { - if IsErrRepoNotExist(err) { + if repo_model.IsErrRepoNotExist(err) { log.Warn("Repository referenced in commit but does not exist: %v", err) return nil, err } - log.Error("GetRepositoryByOwnerAndName: %v", err) + log.Error("repo_model.GetRepositoryByOwnerAndName: %v", err) return nil, err } return refRepo, nil @@ -208,13 +210,14 @@ func GetRepositoryFromMatch(ownerName, repoName string) (*Repository, error) { // GetCommentLink returns link to action comment. func (a *Action) GetCommentLink() string { - return a.getCommentLink(db.GetEngine(db.DefaultContext)) + return a.getCommentLink(db.DefaultContext) } -func (a *Action) getCommentLink(e db.Engine) string { +func (a *Action) getCommentLink(ctx context.Context) string { if a == nil { return "#" } + e := db.GetEngine(ctx) if a.Comment == nil && a.CommentID != 0 { a.Comment, _ = getCommentByID(e, a.CommentID) } @@ -236,7 +239,7 @@ func (a *Action) getCommentLink(e db.Engine) string { return "#" } - if err = issue.loadRepo(e); err != nil { + if err = issue.loadRepo(ctx); err != nil { return "#" } diff --git a/models/action_list.go b/models/action_list.go index 4f2024cfcf..3f52d3cd5e 100644 --- a/models/action_list.go +++ b/models/action_list.go @@ -8,6 +8,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" ) @@ -59,13 +60,13 @@ func (actions ActionList) getRepoIDs() []int64 { return keysInt64(repoIDs) } -func (actions ActionList) loadRepositories(e db.Engine) ([]*Repository, error) { +func (actions ActionList) loadRepositories(e db.Engine) ([]*repo_model.Repository, error) { if len(actions) == 0 { return nil, nil } repoIDs := actions.getRepoIDs() - repoMaps := make(map[int64]*Repository, len(repoIDs)) + repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs)) err := e. In("id", repoIDs). Find(&repoMaps) @@ -80,7 +81,7 @@ func (actions ActionList) loadRepositories(e db.Engine) ([]*Repository, error) { } // LoadRepositories loads actions' all repositories -func (actions ActionList) LoadRepositories() ([]*Repository, error) { +func (actions ActionList) LoadRepositories() ([]*repo_model.Repository, error) { return actions.loadRepositories(db.GetEngine(db.DefaultContext)) } diff --git a/models/action_test.go b/models/action_test.go index 8ab88bb97e..02edae2df7 100644 --- a/models/action_test.go +++ b/models/action_test.go @@ -8,6 +8,7 @@ import ( "path" "testing" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" @@ -17,7 +18,7 @@ import ( func TestAction_GetRepoPath(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) action := &Action{RepoID: repo.ID} assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath()) @@ -25,7 +26,7 @@ func TestAction_GetRepoPath(t *testing.T) { func TestAction_GetRepoLink(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) action := &Action{RepoID: repo.ID} setting.AppSubURL = "/suburl" diff --git a/models/branches.go b/models/branches.go index 3d377cf0fa..e6d8b7441a 100644 --- a/models/branches.go +++ b/models/branches.go @@ -12,6 +12,7 @@ import ( "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/base" @@ -74,8 +75,8 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool { if user, err := user_model.GetUserByID(userID); err != nil { log.Error("GetUserByID: %v", err) return false - } else if repo, err := GetRepositoryByID(protectBranch.RepoID); err != nil { - log.Error("GetRepositoryByID: %v", err) + } else if repo, err := repo_model.GetRepositoryByID(protectBranch.RepoID); err != nil { + log.Error("repo_model.GetRepositoryByID: %v", err) return false } else if writeAccess, err := HasAccessUnit(user, repo, unit.TypeCode, perm.AccessModeWrite); err != nil { log.Error("HasAccessUnit: %v", err) @@ -102,7 +103,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool { } // IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch -func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64, permissionInRepo Permission) bool { +func IsUserMergeWhitelisted(protectBranch *ProtectedBranch, userID int64, permissionInRepo Permission) bool { if !protectBranch.EnableMergeWhitelist { // Then we need to fall back on whether the user has write permission return permissionInRepo.CanWrite(unit.TypeCode) @@ -125,19 +126,19 @@ func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64, permi } // IsUserOfficialReviewer check if user is official reviewer for the branch (counts towards required approvals) -func (protectBranch *ProtectedBranch) IsUserOfficialReviewer(user *user_model.User) (bool, error) { - return protectBranch.isUserOfficialReviewer(db.GetEngine(db.DefaultContext), user) +func IsUserOfficialReviewer(protectBranch *ProtectedBranch, user *user_model.User) (bool, error) { + return isUserOfficialReviewer(db.DefaultContext, protectBranch, user) } -func (protectBranch *ProtectedBranch) isUserOfficialReviewer(e db.Engine, user *user_model.User) (bool, error) { - repo, err := getRepositoryByID(e, protectBranch.RepoID) +func isUserOfficialReviewer(ctx context.Context, protectBranch *ProtectedBranch, user *user_model.User) (bool, error) { + repo, err := repo_model.GetRepositoryByIDCtx(ctx, protectBranch.RepoID) if err != nil { return false, err } if !protectBranch.EnableApprovalsWhitelist { // Anyone with write access is considered official reviewer - writeAccess, err := hasAccessUnit(e, user, repo, unit.TypeCode, perm.AccessModeWrite) + writeAccess, err := hasAccessUnit(ctx, user, repo, unit.TypeCode, perm.AccessModeWrite) if err != nil { return false, err } @@ -148,7 +149,7 @@ func (protectBranch *ProtectedBranch) isUserOfficialReviewer(e db.Engine, user * return true, nil } - inTeam, err := isUserInTeams(e, user.ID, protectBranch.ApprovalsWhitelistTeamIDs) + inTeam, err := isUserInTeams(db.GetEngine(ctx), user.ID, protectBranch.ApprovalsWhitelistTeamIDs) if err != nil { return false, err } @@ -335,8 +336,8 @@ type WhitelistOptions struct { // If ID is 0, it creates a new record. Otherwise, updates existing record. // This function also performs check if whitelist user and team's IDs have been changed // to avoid unnecessary whitelist delete and regenerate. -func UpdateProtectBranch(repo *Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) { - if err = repo.GetOwner(); err != nil { +func UpdateProtectBranch(repo *repo_model.Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) { + if err = repo.GetOwner(db.DefaultContext); err != nil { return fmt.Errorf("GetOwner: %v", err) } @@ -393,20 +394,15 @@ func UpdateProtectBranch(repo *Repository, protectBranch *ProtectedBranch, opts } // GetProtectedBranches get all protected branches -func (repo *Repository) GetProtectedBranches() ([]*ProtectedBranch, error) { +func GetProtectedBranches(repoID int64) ([]*ProtectedBranch, error) { protectedBranches := make([]*ProtectedBranch, 0) - return protectedBranches, db.GetEngine(db.DefaultContext).Find(&protectedBranches, &ProtectedBranch{RepoID: repo.ID}) -} - -// GetBranchProtection get the branch protection of a branch -func (repo *Repository) GetBranchProtection(branchName string) (*ProtectedBranch, error) { - return GetProtectedBranchBy(repo.ID, branchName) + return protectedBranches, db.GetEngine(db.DefaultContext).Find(&protectedBranches, &ProtectedBranch{RepoID: repoID}) } // IsProtectedBranch checks if branch is protected -func (repo *Repository) IsProtectedBranch(branchName string) (bool, error) { +func IsProtectedBranch(repoID int64, branchName string) (bool, error) { protectedBranch := &ProtectedBranch{ - RepoID: repo.ID, + RepoID: repoID, BranchName: branchName, } @@ -419,7 +415,7 @@ func (repo *Repository) IsProtectedBranch(branchName string) (bool, error) { // updateApprovalWhitelist checks whether the user whitelist changed and returns a whitelist with // the users from newWhitelist which have explicit read or write access to the repo. -func updateApprovalWhitelist(repo *Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { +func updateApprovalWhitelist(repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { hasUsersChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist) if !hasUsersChanged { return currentWhitelist, nil @@ -427,7 +423,7 @@ func updateApprovalWhitelist(repo *Repository, currentWhitelist, newWhitelist [] whitelist = make([]int64, 0, len(newWhitelist)) for _, userID := range newWhitelist { - if reader, err := repo.IsReader(userID); err != nil { + if reader, err := IsRepoReader(repo, userID); err != nil { return nil, err } else if !reader { continue @@ -440,7 +436,7 @@ func updateApprovalWhitelist(repo *Repository, currentWhitelist, newWhitelist [] // updateUserWhitelist checks whether the user whitelist changed and returns a whitelist with // the users from newWhitelist which have write access to the repo. -func updateUserWhitelist(repo *Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { +func updateUserWhitelist(repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { hasUsersChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist) if !hasUsersChanged { return currentWhitelist, nil @@ -469,7 +465,7 @@ func updateUserWhitelist(repo *Repository, currentWhitelist, newWhitelist []int6 // updateTeamWhitelist checks whether the team whitelist changed and returns a whitelist with // the teams from newWhitelist which have write access to the repo. -func updateTeamWhitelist(repo *Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { +func updateTeamWhitelist(repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { hasTeamsChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist) if !hasTeamsChanged { return currentWhitelist, nil @@ -491,9 +487,9 @@ func updateTeamWhitelist(repo *Repository, currentWhitelist, newWhitelist []int6 } // DeleteProtectedBranch removes ProtectedBranch relation between the user and repository. -func (repo *Repository) DeleteProtectedBranch(id int64) (err error) { +func DeleteProtectedBranch(repoID, id int64) (err error) { protectedBranch := &ProtectedBranch{ - RepoID: repo.ID, + RepoID: repoID, ID: id, } @@ -518,28 +514,28 @@ type DeletedBranch struct { } // AddDeletedBranch adds a deleted branch to the database -func (repo *Repository) AddDeletedBranch(branchName, commit string, deletedByID int64) error { +func AddDeletedBranch(repoID int64, branchName, commit string, deletedByID int64) error { deletedBranch := &DeletedBranch{ - RepoID: repo.ID, + RepoID: repoID, Name: branchName, Commit: commit, DeletedByID: deletedByID, } - _, err := db.GetEngine(db.DefaultContext).InsertOne(deletedBranch) + _, err := db.GetEngine(db.DefaultContext).Insert(deletedBranch) return err } // GetDeletedBranches returns all the deleted branches -func (repo *Repository) GetDeletedBranches() ([]*DeletedBranch, error) { +func GetDeletedBranches(repoID int64) ([]*DeletedBranch, error) { deletedBranches := make([]*DeletedBranch, 0) - return deletedBranches, db.GetEngine(db.DefaultContext).Where("repo_id = ?", repo.ID).Desc("deleted_unix").Find(&deletedBranches) + return deletedBranches, db.GetEngine(db.DefaultContext).Where("repo_id = ?", repoID).Desc("deleted_unix").Find(&deletedBranches) } // GetDeletedBranchByID get a deleted branch by its ID -func (repo *Repository) GetDeletedBranchByID(id int64) (*DeletedBranch, error) { +func GetDeletedBranchByID(repoID, id int64) (*DeletedBranch, error) { deletedBranch := &DeletedBranch{} - has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ?", repo.ID).And("id = ?", id).Get(deletedBranch) + has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ?", repoID).And("id = ?", id).Get(deletedBranch) if err != nil { return nil, err } @@ -549,10 +545,10 @@ func (repo *Repository) GetDeletedBranchByID(id int64) (*DeletedBranch, error) { return deletedBranch, nil } -// RemoveDeletedBranch removes a deleted branch from the database -func (repo *Repository) RemoveDeletedBranch(id int64) (err error) { +// RemoveDeletedBranchByID removes a deleted branch from the database +func RemoveDeletedBranchByID(repoID, id int64) (err error) { deletedBranch := &DeletedBranch{ - RepoID: repo.ID, + RepoID: repoID, ID: id, } @@ -575,8 +571,8 @@ func (deletedBranch *DeletedBranch) LoadUser() { deletedBranch.DeletedBy = user } -// RemoveDeletedBranch removes all deleted branches -func RemoveDeletedBranch(repoID int64, branch string) error { +// RemoveDeletedBranchByName removes all deleted branches +func RemoveDeletedBranchByName(repoID int64, branch string) error { _, err := db.GetEngine(db.DefaultContext).Where("repo_id=? AND name=?", repoID, branch).Delete(new(DeletedBranch)) return err } @@ -615,7 +611,7 @@ func FindRenamedBranch(repoID int64, from string) (branch *RenamedBranch, exist } // RenameBranch rename a branch -func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault bool) error) (err error) { +func RenameBranch(repo *repo_model.Repository, from, to string, gitAction func(isDefault bool) error) (err error) { ctx, committer, err := db.TxContext() if err != nil { return err diff --git a/models/branches_test.go b/models/branches_test.go index 187f23d41b..e1a71853f2 100644 --- a/models/branches_test.go +++ b/models/branches_test.go @@ -7,6 +7,7 @@ package models import ( "testing" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -14,18 +15,18 @@ import ( func TestAddDeletedBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) firstBranch := unittest.AssertExistsAndLoadBean(t, &DeletedBranch{ID: 1}).(*DeletedBranch) - assert.Error(t, repo.AddDeletedBranch(firstBranch.Name, firstBranch.Commit, firstBranch.DeletedByID)) - assert.NoError(t, repo.AddDeletedBranch("test", "5655464564554545466464656", int64(1))) + assert.Error(t, AddDeletedBranch(repo.ID, firstBranch.Name, firstBranch.Commit, firstBranch.DeletedByID)) + assert.NoError(t, AddDeletedBranch(repo.ID, "test", "5655464564554545466464656", int64(1))) } func TestGetDeletedBranches(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - branches, err := repo.GetDeletedBranches() + branches, err := GetDeletedBranches(repo.ID) assert.NoError(t, err) assert.Len(t, branches, 2) } @@ -58,20 +59,20 @@ func TestDeletedBranchLoadUser(t *testing.T) { func TestRemoveDeletedBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) firstBranch := unittest.AssertExistsAndLoadBean(t, &DeletedBranch{ID: 1}).(*DeletedBranch) - err := repo.RemoveDeletedBranch(1) + err := RemoveDeletedBranchByID(repo.ID, 1) assert.NoError(t, err) unittest.AssertNotExistsBean(t, firstBranch) unittest.AssertExistsAndLoadBean(t, &DeletedBranch{ID: 2}) } func getDeletedBranch(t *testing.T, branch *DeletedBranch) *DeletedBranch { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - deletedBranch, err := repo.GetDeletedBranchByID(branch.ID) + deletedBranch, err := GetDeletedBranchByID(repo.ID, branch.ID) assert.NoError(t, err) assert.Equal(t, branch.ID, deletedBranch.ID) assert.Equal(t, branch.Name, deletedBranch.Name) @@ -95,7 +96,7 @@ func TestFindRenamedBranch(t *testing.T) { func TestRenameBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) _isDefault := false err := UpdateProtectBranch(repo1, &ProtectedBranch{ @@ -104,13 +105,13 @@ func TestRenameBranch(t *testing.T) { }, WhitelistOptions{}) assert.NoError(t, err) - assert.NoError(t, repo1.RenameBranch("master", "main", func(isDefault bool) error { + assert.NoError(t, RenameBranch(repo1, "master", "main", func(isDefault bool) error { _isDefault = isDefault return nil })) assert.Equal(t, true, _isDefault) - repo1 = unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) assert.Equal(t, "main", repo1.DefaultBranch) pull := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest) // merged @@ -136,9 +137,9 @@ func TestOnlyGetDeletedBranchOnCorrectRepo(t *testing.T) { // Get deletedBranch with ID of 1 on repo with ID 2. // This should return a nil branch as this deleted branch // is actually on repo with ID 1. - repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - deletedBranch, err := repo2.GetDeletedBranchByID(1) + deletedBranch, err := GetDeletedBranchByID(repo2.ID, 1) // Expect no error, and the returned branch is nil. assert.NoError(t, err) @@ -146,9 +147,9 @@ func TestOnlyGetDeletedBranchOnCorrectRepo(t *testing.T) { // Now get the deletedBranch with ID of 1 on repo with ID 1. // This should return the deletedBranch. - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - deletedBranch, err = repo1.GetDeletedBranchByID(1) + deletedBranch, err = GetDeletedBranchByID(repo1.ID, 1) // Expect no error, and the returned branch to be not nil. assert.NoError(t, err) diff --git a/models/commit.go b/models/commit.go index 12aecdae84..8de71da1b3 100644 --- a/models/commit.go +++ b/models/commit.go @@ -5,12 +5,13 @@ package models import ( + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" ) // ConvertFromGitCommit converts git commits into SignCommitWithStatuses -func ConvertFromGitCommit(commits []*git.Commit, repo *Repository) []*SignCommitWithStatuses { +func ConvertFromGitCommit(commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses { return ParseCommitsWithStatus( ParseCommitsWithSignature( user_model.ValidateCommitsWithEmails(commits), diff --git a/models/commit_status.go b/models/commit_status.go index bba39fde87..e0942d2028 100644 --- a/models/commit_status.go +++ b/models/commit_status.go @@ -5,6 +5,7 @@ package models import ( + "context" "crypto/sha1" "fmt" "net/url" @@ -12,6 +13,7 @@ import ( "time" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -23,17 +25,17 @@ import ( // CommitStatus holds a single Status of a single Commit type CommitStatus struct { - ID int64 `xorm:"pk autoincr"` - Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` - Repo *Repository `xorm:"-"` - State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` - SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` - TargetURL string `xorm:"TEXT"` - Description string `xorm:"TEXT"` - ContextHash string `xorm:"char(40) index"` - Context string `xorm:"TEXT"` - Creator *user_model.User `xorm:"-"` + ID int64 `xorm:"pk autoincr"` + Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` + Repo *repo_model.Repository `xorm:"-"` + State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` + SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` + TargetURL string `xorm:"TEXT"` + Description string `xorm:"TEXT"` + ContextHash string `xorm:"char(40) index"` + Context string `xorm:"TEXT"` + Creator *user_model.User `xorm:"-"` CreatorID int64 CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` @@ -120,15 +122,15 @@ func getNextCommitStatusIndex(repoID int64, sha string) (int64, error) { return curIdx, nil } -func (status *CommitStatus) loadAttributes(e db.Engine) (err error) { +func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { if status.Repo == nil { - status.Repo, err = getRepositoryByID(e, status.RepoID) + status.Repo, err = repo_model.GetRepositoryByIDCtx(ctx, status.RepoID) if err != nil { return fmt.Errorf("getRepositoryByID [%d]: %v", status.RepoID, err) } } if status.Creator == nil && status.CreatorID > 0 { - status.Creator, err = user_model.GetUserByIDEngine(e, status.CreatorID) + status.Creator, err = user_model.GetUserByIDEngine(db.GetEngine(ctx), status.CreatorID) if err != nil { return fmt.Errorf("getUserByID [%d]: %v", status.CreatorID, err) } @@ -138,7 +140,7 @@ func (status *CommitStatus) loadAttributes(e db.Engine) (err error) { // APIURL returns the absolute APIURL to this commit-status. func (status *CommitStatus) APIURL() string { - _ = status.loadAttributes(db.GetEngine(db.DefaultContext)) + _ = status.loadAttributes(db.DefaultContext) return status.Repo.APIURL() + "/statuses/" + url.PathEscape(status.SHA) } @@ -170,7 +172,7 @@ type CommitStatusOptions struct { } // GetCommitStatuses returns all statuses for a given commit. -func GetCommitStatuses(repo *Repository, sha string, opts *CommitStatusOptions) ([]*CommitStatus, int64, error) { +func GetCommitStatuses(repo *repo_model.Repository, sha string, opts *CommitStatusOptions) ([]*CommitStatus, int64, error) { if opts.Page <= 0 { opts.Page = 1 } @@ -193,7 +195,7 @@ func GetCommitStatuses(repo *Repository, sha string, opts *CommitStatusOptions) return statuses, maxResults, findSession.Find(&statuses) } -func listCommitStatusesStatement(repo *Repository, sha string, opts *CommitStatusOptions) *xorm.Session { +func listCommitStatusesStatement(repo *repo_model.Repository, sha string, opts *CommitStatusOptions) *xorm.Session { sess := db.GetEngine(db.DefaultContext).Where("repo_id = ?", repo.ID).And("sha = ?", sha) switch opts.State { case "pending", "success", "error", "failure", "warning": @@ -274,7 +276,7 @@ func FindRepoRecentCommitStatusContexts(repoID int64, before time.Duration) ([]s // NewCommitStatusOptions holds options for creating a CommitStatus type NewCommitStatusOptions struct { - Repo *Repository + Repo *repo_model.Repository Creator *user_model.User SHA string CommitStatus *CommitStatus @@ -330,7 +332,7 @@ type SignCommitWithStatuses struct { } // ParseCommitsWithStatus checks commits latest statuses and calculates its worst status state -func ParseCommitsWithStatus(oldCommits []*SignCommit, repo *Repository) []*SignCommitWithStatuses { +func ParseCommitsWithStatus(oldCommits []*SignCommit, repo *repo_model.Repository) []*SignCommitWithStatuses { newCommits := make([]*SignCommitWithStatuses, 0, len(oldCommits)) for _, c := range oldCommits { diff --git a/models/commit_status_test.go b/models/commit_status_test.go index 02e3849357..bb9e375072 100644 --- a/models/commit_status_test.go +++ b/models/commit_status_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/structs" @@ -17,7 +18,7 @@ import ( func TestGetCommitStatuses(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) sha1 := "1234123412341234123412341234123412341234" diff --git a/models/consistency.go b/models/consistency.go index d16e7f5e99..0b9d9fd2c3 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -7,6 +7,7 @@ package models import ( admin_model "code.gitea.io/gitea/models/admin" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "xorm.io/builder" @@ -158,12 +159,12 @@ func DeleteOrphanedObjects(subject, refobject, joinCond string) error { // CountNullArchivedRepository counts the number of repositories with is_archived is null func CountNullArchivedRepository() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(Repository)) + return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(repo_model.Repository)) } // FixNullArchivedRepository sets is_archived to false where it is null func FixNullArchivedRepository() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&Repository{ + return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&repo_model.Repository{ IsArchived: false, }) } diff --git a/models/error.go b/models/error.go index 36c70e49ad..20ed7f90e1 100644 --- a/models/error.go +++ b/models/error.go @@ -9,6 +9,7 @@ import ( "fmt" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" ) @@ -548,32 +549,6 @@ func (err ErrLFSFileLocked) Error() string { return fmt.Sprintf("File is lfs locked [repo: %d, locked by: %s, path: %s]", err.RepoID, err.UserName, err.Path) } -// __________ .__ __ -// \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. -// | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | -// | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ | -// |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____| -// \/ \/|__| \/ \/ - -// ErrRepoNotExist represents a "RepoNotExist" kind of error. -type ErrRepoNotExist struct { - ID int64 - UID int64 - OwnerName string - Name string -} - -// IsErrRepoNotExist checks if an error is a ErrRepoNotExist. -func IsErrRepoNotExist(err error) bool { - _, ok := err.(ErrRepoNotExist) - return ok -} - -func (err ErrRepoNotExist) Error() string { - return fmt.Sprintf("repository does not exist [id: %d, uid: %d, owner_name: %s, name: %s]", - err.ID, err.UID, err.OwnerName, err.Name) -} - // ErrNoPendingRepoTransfer is an error type for repositories without a pending // transfer request type ErrNoPendingRepoTransfer struct { @@ -1283,7 +1258,7 @@ func (err ErrPullRequestHeadRepoMissing) Error() string { // ErrInvalidMergeStyle represents an error if merging with disabled merge strategy type ErrInvalidMergeStyle struct { ID int64 - Style MergeStyle + Style repo_model.MergeStyle } // IsErrInvalidMergeStyle checks if an error is a ErrInvalidMergeStyle. @@ -1299,7 +1274,7 @@ func (err ErrInvalidMergeStyle) Error() string { // ErrMergeConflicts represents an error if merging fails with a conflict type ErrMergeConflicts struct { - Style MergeStyle + Style repo_model.MergeStyle StdOut string StdErr string Err error @@ -1317,7 +1292,7 @@ func (err ErrMergeConflicts) Error() string { // ErrMergeUnrelatedHistories represents an error if merging fails due to unrelated histories type ErrMergeUnrelatedHistories struct { - Style MergeStyle + Style repo_model.MergeStyle StdOut string StdErr string Err error @@ -1335,7 +1310,7 @@ func (err ErrMergeUnrelatedHistories) Error() string { // ErrRebaseConflicts represents an error if rebase fails with a conflict type ErrRebaseConflicts struct { - Style MergeStyle + Style repo_model.MergeStyle CommitSHA string StdOut string StdErr string diff --git a/models/fixture_generation.go b/models/fixture_generation.go index c87909d01b..56baa1c345 100644 --- a/models/fixture_generation.go +++ b/models/fixture_generation.go @@ -9,19 +9,20 @@ import ( "strings" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" ) // GetYamlFixturesAccess returns a string containing the contents // for the access table, as recalculated using repo.RecalculateAccesses() func GetYamlFixturesAccess() (string, error) { - repos := make([]*Repository, 0, 50) + repos := make([]*repo_model.Repository, 0, 50) if err := db.GetEngine(db.DefaultContext).Find(&repos); err != nil { return "", err } for _, repo := range repos { repo.MustOwner() - if err := repo.RecalculateAccesses(); err != nil { + if err := RecalculateAccesses(repo); err != nil { return "", err } } diff --git a/models/gpg_key_commit_verification.go b/models/gpg_key_commit_verification.go index 5eeeb69ef5..48f58c07b6 100644 --- a/models/gpg_key_commit_verification.go +++ b/models/gpg_key_commit_verification.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" @@ -69,7 +70,7 @@ const ( ) // ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys. -func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repository *Repository) []*SignCommit { +func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repository *repo_model.Repository) []*SignCommit { newCommits := make([]*SignCommit, 0, len(oldCommits)) keyMap := map[string]bool{} @@ -447,7 +448,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use } // CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository -func CalculateTrustStatus(verification *CommitVerification, repository *Repository, keyMap *map[string]bool) (err error) { +func CalculateTrustStatus(verification *CommitVerification, repository *repo_model.Repository, keyMap *map[string]bool) (err error) { if !verification.Verified { return } @@ -458,7 +459,7 @@ func CalculateTrustStatus(verification *CommitVerification, repository *Reposito // In the Committer trust model a signature is trusted if it matches the committer // - it doesn't matter if they're a collaborator, the owner, Gitea or Github // NB: This model is commit verification only - if trustModel == CommitterTrustModel { + if trustModel == repo_model.CommitterTrustModel { // default to "unmatched" verification.TrustStatus = "unmatched" @@ -479,9 +480,9 @@ func CalculateTrustStatus(verification *CommitVerification, repository *Reposito if verification.SigningUser.ID == 0 { // This commit is signed by the default key - but this key is not assigned to a user in the DB. - // However in the CollaboratorCommitterTrustModel we cannot mark this as trusted + // However in the repo_model.CollaboratorCommitterTrustModel we cannot mark this as trusted // unless the default key matches the email of a non-user. - if trustModel == CollaboratorCommitterTrustModel && (verification.CommittingUser.ID != 0 || + if trustModel == repo_model.CollaboratorCommitterTrustModel && (verification.CommittingUser.ID != 0 || verification.SigningUser.Email != verification.CommittingUser.Email) { verification.TrustStatus = "untrusted" } @@ -493,11 +494,11 @@ func CalculateTrustStatus(verification *CommitVerification, repository *Reposito var has bool isMember, has = (*keyMap)[verification.SigningKey.KeyID] if !has { - isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID) + isMember, err = IsOwnerMemberCollaborator(repository, verification.SigningUser.ID) (*keyMap)[verification.SigningKey.KeyID] = isMember } } else { - isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID) + isMember, err = IsOwnerMemberCollaborator(repository, verification.SigningUser.ID) } if !isMember { @@ -507,7 +508,7 @@ func CalculateTrustStatus(verification *CommitVerification, repository *Reposito // This should be marked as questionable unless the signing user is a collaborator/team member etc. verification.TrustStatus = "unmatched" } - } else if trustModel == CollaboratorCommitterTrustModel && verification.CommittingUser.ID != verification.SigningUser.ID { + } else if trustModel == repo_model.CollaboratorCommitterTrustModel && verification.CommittingUser.ID != verification.SigningUser.ID { // The committing user and the signing user are not the same and our trustmodel states that they must match verification.TrustStatus = "unmatched" } diff --git a/models/helper.go b/models/helper.go index 41dd1ccd53..15df424539 100644 --- a/models/helper.go +++ b/models/helper.go @@ -5,10 +5,8 @@ package models import ( - "encoding/binary" - + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/json" ) func keysInt64(m map[int64]struct{}) []int64 { @@ -19,8 +17,8 @@ func keysInt64(m map[int64]struct{}) []int64 { return keys } -func valuesRepository(m map[int64]*Repository) []*Repository { - values := make([]*Repository, 0, len(m)) +func valuesRepository(m map[int64]*repo_model.Repository) []*repo_model.Repository { + values := make([]*repo_model.Repository, 0, len(m)) for _, v := range m { values = append(values, v) } @@ -34,32 +32,3 @@ func valuesUser(m map[int64]*user_model.User) []*user_model.User { } return values } - -// JSONUnmarshalHandleDoubleEncode - due to a bug in xorm (see https://gitea.com/xorm/xorm/pulls/1957) - it's -// possible that a Blob may be double encoded or gain an unwanted prefix of 0xff 0xfe. -func JSONUnmarshalHandleDoubleEncode(bs []byte, v interface{}) error { - err := json.Unmarshal(bs, v) - if err != nil { - ok := true - rs := []byte{} - temp := make([]byte, 2) - for _, rn := range string(bs) { - if rn > 0xffff { - ok = false - break - } - binary.LittleEndian.PutUint16(temp, uint16(rn)) - rs = append(rs, temp...) - } - if ok { - if len(rs) > 1 && rs[0] == 0xff && rs[1] == 0xfe { - rs = rs[2:] - } - err = json.Unmarshal(rs, v) - } - } - if err != nil && len(bs) > 2 && bs[0] == 0xff && bs[1] == 0xfe { - err = json.Unmarshal(bs[2:], v) - } - return err -} diff --git a/models/helper_environment.go b/models/helper_environment.go index 3e98f60ffd..57ec3ea1e9 100644 --- a/models/helper_environment.go +++ b/models/helper_environment.go @@ -9,6 +9,7 @@ import ( "os" "strings" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" ) @@ -33,19 +34,19 @@ const ( // It is recommended to avoid using this unless you are pushing within a transaction // or if you absolutely are sure that post-receive and pre-receive will do nothing // We provide the full pushing-environment for other hook providers -func InternalPushingEnvironment(doer *user_model.User, repo *Repository) []string { +func InternalPushingEnvironment(doer *user_model.User, repo *repo_model.Repository) []string { return append(PushingEnvironment(doer, repo), EnvIsInternal+"=true", ) } // PushingEnvironment returns an os environment to allow hooks to work on push -func PushingEnvironment(doer *user_model.User, repo *Repository) []string { +func PushingEnvironment(doer *user_model.User, repo *repo_model.Repository) []string { return FullPushingEnvironment(doer, doer, repo, repo.Name, 0) } // FullPushingEnvironment returns an os environment to allow hooks to work on push -func FullPushingEnvironment(author, committer *user_model.User, repo *Repository, repoName string, prID int64) []string { +func FullPushingEnvironment(author, committer *user_model.User, repo *repo_model.Repository, repoName string, prID int64) []string { isWiki := "false" if strings.HasSuffix(repoName, ".wiki") { isWiki = "true" diff --git a/models/issue.go b/models/issue.go index 58649c754a..595f0c9422 100644 --- a/models/issue.go +++ b/models/issue.go @@ -33,12 +33,12 @@ import ( // Issue represents an issue or pull request of repository. type Issue struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"` - Repo *Repository `xorm:"-"` - Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository. - PosterID int64 `xorm:"INDEX"` - Poster *user_model.User `xorm:"-"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"` + Repo *repo_model.Repository `xorm:"-"` + Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository. + PosterID int64 `xorm:"INDEX"` + Poster *user_model.User `xorm:"-"` OriginalAuthor string OriginalAuthorID int64 `xorm:"index"` Title string `xorm:"name"` @@ -118,12 +118,12 @@ func (issue *Issue) IsOverdue() bool { // LoadRepo loads issue's repository func (issue *Issue) LoadRepo() error { - return issue.loadRepo(db.GetEngine(db.DefaultContext)) + return issue.loadRepo(db.DefaultContext) } -func (issue *Issue) loadRepo(e db.Engine) (err error) { +func (issue *Issue) loadRepo(ctx context.Context) (err error) { if issue.Repo == nil { - issue.Repo, err = getRepositoryByID(e, issue.RepoID) + issue.Repo, err = repo_model.GetRepositoryByIDCtx(ctx, issue.RepoID) if err != nil { return fmt.Errorf("getRepositoryByID [%d]: %v", issue.RepoID, err) } @@ -133,11 +133,11 @@ func (issue *Issue) loadRepo(e db.Engine) (err error) { // IsTimetrackerEnabled returns true if the repo enables timetracking func (issue *Issue) IsTimetrackerEnabled() bool { - return issue.isTimetrackerEnabled(db.GetEngine(db.DefaultContext)) + return issue.isTimetrackerEnabled(db.DefaultContext) } -func (issue *Issue) isTimetrackerEnabled(e db.Engine) bool { - if err := issue.loadRepo(e); err != nil { +func (issue *Issue) isTimetrackerEnabled(ctx context.Context) bool { + if err := issue.loadRepo(ctx); err != nil { log.Error(fmt.Sprintf("loadRepo: %v", err)) return false } @@ -233,17 +233,18 @@ func (issue *Issue) loadCommentsByType(e db.Engine, tp CommentType) (err error) return err } -func (issue *Issue) loadReactions(e db.Engine) (err error) { +func (issue *Issue) loadReactions(ctx context.Context) (err error) { if issue.Reactions != nil { return nil } + e := db.GetEngine(ctx) reactions, err := findReactions(e, FindReactionsOptions{ IssueID: issue.ID, }) if err != nil { return err } - if err = issue.loadRepo(e); err != nil { + if err = issue.loadRepo(ctx); err != nil { return err } // Load reaction user data @@ -279,7 +280,7 @@ func (issue *Issue) loadMilestone(e db.Engine) (err error) { func (issue *Issue) loadAttributes(ctx context.Context) (err error) { e := db.GetEngine(ctx) - if err = issue.loadRepo(e); err != nil { + if err = issue.loadRepo(ctx); err != nil { return } @@ -319,16 +320,16 @@ func (issue *Issue) loadAttributes(ctx context.Context) (err error) { return err } - if err = CommentList(issue.Comments).loadAttributes(e); err != nil { + if err = CommentList(issue.Comments).loadAttributes(ctx); err != nil { return err } - if issue.isTimetrackerEnabled(e) { + if issue.isTimetrackerEnabled(ctx) { if err = issue.loadTotalTimes(e); err != nil { return err } } - return issue.loadReactions(e) + return issue.loadReactions(ctx) } // LoadAttributes loads the attribute of this issue. @@ -478,13 +479,13 @@ func (issue *Issue) ClearLabels(doer *user_model.User) (err error) { } defer committer.Close() - if err := issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } else if err = issue.loadPullRequest(db.GetEngine(ctx)); err != nil { return err } - perm, err := getUserRepoPermission(db.GetEngine(ctx), issue.Repo, doer) + perm, err := getUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return err } @@ -526,7 +527,7 @@ func (issue *Issue) ReplaceLabels(labels []*Label, doer *user_model.User) (err e } defer committer.Close() - if err = issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err = issue.loadRepo(ctx); err != nil { return err } @@ -627,7 +628,7 @@ func (issue *Issue) changeStatus(ctx context.Context, doer *user_model.User, isC func (issue *Issue) doChangeStatus(ctx context.Context, doer *user_model.User, isMergePull bool) (*Comment, error) { e := db.GetEngine(ctx) // Check for open dependencies - if issue.IsClosed && issue.Repo.isDependenciesEnabled(e) { + if issue.IsClosed && issue.Repo.IsDependenciesEnabledCtx(ctx) { // only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies noDeps, err := issueNoDependenciesLeft(e, issue) if err != nil { @@ -694,7 +695,7 @@ func (issue *Issue) ChangeStatus(doer *user_model.User, isClosed bool) (*Comment } defer committer.Close() - if err := issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err := issue.loadRepo(ctx); err != nil { return nil, err } if err := issue.loadPoster(db.GetEngine(ctx)); err != nil { @@ -725,7 +726,7 @@ func (issue *Issue) ChangeTitle(doer *user_model.User, oldTitle string) (err err return fmt.Errorf("updateIssueCols: %v", err) } - if err = issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err = issue.loadRepo(ctx); err != nil { return fmt.Errorf("loadRepo: %v", err) } @@ -759,7 +760,7 @@ func (issue *Issue) ChangeRef(doer *user_model.User, oldRef string) (err error) return fmt.Errorf("updateIssueCols: %v", err) } - if err = issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err = issue.loadRepo(ctx); err != nil { return fmt.Errorf("loadRepo: %v", err) } oldRefFriendly := strings.TrimPrefix(oldRef, git.BranchPrefix) @@ -781,7 +782,7 @@ func (issue *Issue) ChangeRef(doer *user_model.User, oldRef string) (err error) } // AddDeletePRBranchComment adds delete branch comment for pull request issue -func AddDeletePRBranchComment(doer *user_model.User, repo *Repository, issueID int64, branchName string) error { +func AddDeletePRBranchComment(doer *user_model.User, repo *repo_model.Repository, issueID int64, branchName string) error { issue, err := getIssueByID(db.GetEngine(db.DefaultContext), issueID) if err != nil { return err @@ -918,7 +919,7 @@ func (issue *Issue) GetLastEventLabelFake() string { // NewIssueOptions represents the options of a new issue. type NewIssueOptions struct { - Repo *Repository + Repo *repo_model.Repository Issue *Issue LabelIDs []int64 Attachments []string // In UUID format. @@ -1005,7 +1006,7 @@ func newIssue(ctx context.Context, doer *user_model.User, opts NewIssueOptions) } } - if err = newIssueUsers(e, opts.Repo, opts.Issue); err != nil { + if err = newIssueUsers(ctx, opts.Repo, opts.Issue); err != nil { return err } @@ -1055,7 +1056,7 @@ func RecalculateIssueIndexForRepo(repoID int64) error { } // NewIssue creates new issue with labels for repository. -func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { +func NewIssue(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { idx, err := db.GetNextResourceIndex("issue_index", repo.ID) if err != nil { return fmt.Errorf("generate issue index failed: %v", err) @@ -1856,7 +1857,7 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment defer committer.Close() sess := db.GetEngine(ctx) - if err := issue.loadRepo(sess); err != nil { + if err := issue.loadRepo(ctx); err != nil { return nil, false, fmt.Errorf("loadRepo: %v", err) } @@ -1930,8 +1931,8 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *us // DependencyInfo represents high level information about an issue which is a dependency of another issue. type DependencyInfo struct { - Issue `xorm:"extends"` - Repository `xorm:"extends"` + Issue `xorm:"extends"` + repo_model.Repository `xorm:"extends"` } // getParticipantIDsByIssue returns all userIDs who are participated in comments of an issue and issue author @@ -2040,14 +2041,14 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *user_ if len(mentions) == 0 { return } - if err = issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err = issue.loadRepo(ctx); err != nil { return } resolved := make(map[string]bool, 10) var mentionTeams []string - if err := issue.Repo.getOwner(db.GetEngine(ctx)); err != nil { + if err := issue.Repo.GetOwner(ctx); err != nil { return nil, err } @@ -2155,7 +2156,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *user_ continue } // Normal users must have read access to the referencing issue - perm, err := getUserRepoPermission(db.GetEngine(ctx), issue.Repo, user) + perm, err := getUserRepoPermission(ctx, issue.Repo, user) if err != nil { return nil, fmt.Errorf("getUserRepoPermission [%d]: %v", user.ID, err) } diff --git a/models/issue_assignees.go b/models/issue_assignees.go index 527549171e..b3511f8b59 100644 --- a/models/issue_assignees.go +++ b/models/issue_assignees.go @@ -120,7 +120,7 @@ func (issue *Issue) toggleAssignee(ctx context.Context, doer *user_model.User, a } // Repo infos - if err = issue.loadRepo(sess); err != nil { + if err = issue.loadRepo(ctx); err != nil { return false, nil, fmt.Errorf("loadRepo: %v", err) } diff --git a/models/issue_comment.go b/models/issue_comment.go index 417caccfaf..754fa3439e 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -219,9 +219,9 @@ type Comment struct { RefAction references.XRefAction `xorm:"SMALLINT"` // What happens if RefIssueID resolves RefIsPull bool - RefRepo *Repository `xorm:"-"` - RefIssue *Issue `xorm:"-"` - RefComment *Comment `xorm:"-"` + RefRepo *repo_model.Repository `xorm:"-"` + RefIssue *Issue `xorm:"-"` + RefComment *Comment `xorm:"-"` Commits []*SignCommitWithStatuses `xorm:"-"` OldCommit string `xorm:"-"` @@ -316,7 +316,7 @@ func (c *Comment) HTMLURL() string { log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.loadRepo(db.GetEngine(db.DefaultContext)) + err = c.Issue.loadRepo(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -345,7 +345,7 @@ func (c *Comment) APIURL() string { log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.loadRepo(db.GetEngine(db.DefaultContext)) + err = c.Issue.loadRepo(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -366,7 +366,7 @@ func (c *Comment) IssueURL() string { return "" } - err = c.Issue.loadRepo(db.GetEngine(db.DefaultContext)) + err = c.Issue.loadRepo(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -382,7 +382,7 @@ func (c *Comment) PRURL() string { return "" } - err = c.Issue.loadRepo(db.GetEngine(db.DefaultContext)) + err = c.Issue.loadRepo(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -536,7 +536,7 @@ func (c *Comment) LoadAssigneeUserAndTeam() error { return err } - if err = c.Issue.Repo.GetOwner(); err != nil { + if err = c.Issue.Repo.GetOwner(db.DefaultContext); err != nil { return err } @@ -589,7 +589,7 @@ func (c *Comment) LoadTime() error { return err } -func (c *Comment) loadReactions(e db.Engine, repo *Repository) (err error) { +func (c *Comment) loadReactions(e db.Engine, repo *repo_model.Repository) (err error) { if c.Reactions != nil { return nil } @@ -608,7 +608,7 @@ func (c *Comment) loadReactions(e db.Engine, repo *Repository) (err error) { } // LoadReactions loads comment reactions -func (c *Comment) LoadReactions(repo *Repository) error { +func (c *Comment) LoadReactions(repo *repo_model.Repository) error { return c.loadReactions(db.GetEngine(db.DefaultContext), repo) } @@ -675,7 +675,7 @@ func (c *Comment) CodeCommentURL() string { log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.loadRepo(db.GetEngine(db.DefaultContext)) + err = c.Issue.loadRepo(db.DefaultContext) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -764,7 +764,7 @@ func createComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, return nil, err } - if err = opts.Repo.getOwner(e); err != nil { + if err = opts.Repo.GetOwner(ctx); err != nil { return nil, err } @@ -843,7 +843,7 @@ func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Is content = newDeadlineUnix.Format("2006-01-02") + "|" + issue.DeadlineUnix.Format("2006-01-02") } - if err := issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err := issue.loadRepo(ctx); err != nil { return nil, err } @@ -867,7 +867,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is if !add { cType = CommentTypeRemoveDependency } - if err = issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err = issue.loadRepo(ctx); err != nil { return } @@ -898,7 +898,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is type CreateCommentOptions struct { Type CommentType Doer *user_model.User - Repo *Repository + Repo *repo_model.Repository Issue *Issue Label *Label @@ -953,7 +953,7 @@ func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) { } // CreateRefComment creates a commit reference comment to issue. -func CreateRefComment(doer *user_model.User, repo *Repository, issue *Issue, content, commitSHA string) error { +func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue *Issue, content, commitSHA string) error { if len(commitSHA) == 0 { return fmt.Errorf("cannot create reference with empty commit SHA") } @@ -1144,11 +1144,11 @@ func deleteComment(e db.Engine, comment *Comment) error { // CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS type CodeComments map[string]map[int64][]*Comment -func fetchCodeComments(e db.Engine, issue *Issue, currentUser *user_model.User) (CodeComments, error) { - return fetchCodeCommentsByReview(e, issue, currentUser, nil) +func fetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User) (CodeComments, error) { + return fetchCodeCommentsByReview(ctx, issue, currentUser, nil) } -func fetchCodeCommentsByReview(e db.Engine, issue *Issue, currentUser *user_model.User, review *Review) (CodeComments, error) { +func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *user_model.User, review *Review) (CodeComments, error) { pathToLineToComment := make(CodeComments) if review == nil { review = &Review{ID: 0} @@ -1159,7 +1159,7 @@ func fetchCodeCommentsByReview(e db.Engine, issue *Issue, currentUser *user_mode ReviewID: review.ID, } - comments, err := findCodeComments(e, opts, issue, currentUser, review) + comments, err := findCodeComments(ctx, opts, issue, currentUser, review) if err != nil { return nil, err } @@ -1173,7 +1173,7 @@ func fetchCodeCommentsByReview(e db.Engine, issue *Issue, currentUser *user_mode return pathToLineToComment, nil } -func findCodeComments(e db.Engine, opts FindCommentsOptions, issue *Issue, currentUser *user_model.User, review *Review) ([]*Comment, error) { +func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issue, currentUser *user_model.User, review *Review) ([]*Comment, error) { var comments []*Comment if review == nil { review = &Review{ID: 0} @@ -1182,6 +1182,7 @@ func findCodeComments(e db.Engine, opts FindCommentsOptions, issue *Issue, curre if review.ID == 0 { conds = conds.And(builder.Eq{"invalidated": false}) } + e := db.GetEngine(ctx) if err := e.Where(conds). Asc("comment.created_unix"). Asc("comment.id"). @@ -1189,7 +1190,7 @@ func findCodeComments(e db.Engine, opts FindCommentsOptions, issue *Issue, curre return nil, err } - if err := issue.loadRepo(e); err != nil { + if err := issue.loadRepo(ctx); err != nil { return nil, err } @@ -1249,12 +1250,12 @@ func FetchCodeCommentsByLine(issue *Issue, currentUser *user_model.User, treePat TreePath: treePath, Line: line, } - return findCodeComments(db.GetEngine(db.DefaultContext), opts, issue, currentUser, nil) + return findCodeComments(db.DefaultContext, opts, issue, currentUser, nil) } // FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line func FetchCodeComments(issue *Issue, currentUser *user_model.User) (CodeComments, error) { - return fetchCodeComments(db.GetEngine(db.DefaultContext), issue, currentUser) + return fetchCodeComments(db.DefaultContext, issue, currentUser) } // UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id @@ -1313,7 +1314,7 @@ func CreatePushPullComment(pusher *user_model.User, pr *PullRequest, oldCommitID // getCommitsFromRepo get commit IDs from repo in between oldCommitID and newCommitID // isForcePush will be true if oldCommit isn't on the branch // Commit on baseBranch will skip -func getCommitIDsFromRepo(repo *Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) { +func getCommitIDsFromRepo(repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) { repoPath := repo.RepoPath() gitRepo, err := git.OpenRepository(repoPath) if err != nil { diff --git a/models/issue_comment_list.go b/models/issue_comment_list.go index ef6aff9cbe..23a2756dcf 100644 --- a/models/issue_comment_list.go +++ b/models/issue_comment_list.go @@ -5,6 +5,8 @@ package models import ( + "context" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -343,11 +345,12 @@ func (comments CommentList) getDependentIssueIDs() []int64 { return keysInt64(ids) } -func (comments CommentList) loadDependentIssues(e db.Engine) error { +func (comments CommentList) loadDependentIssues(ctx context.Context) error { if len(comments) == 0 { return nil } + e := db.GetEngine(ctx) issueIDs := comments.getDependentIssueIDs() issues := make(map[int64]*Issue, len(issueIDs)) left := len(issueIDs) @@ -383,7 +386,7 @@ func (comments CommentList) loadDependentIssues(e db.Engine) error { if comment.DependentIssue == nil { comment.DependentIssue = issues[comment.DependentIssueID] if comment.DependentIssue != nil { - if err := comment.DependentIssue.loadRepo(e); err != nil { + if err := comment.DependentIssue.loadRepo(ctx); err != nil { return err } } @@ -487,7 +490,8 @@ func (comments CommentList) loadReviews(e db.Engine) error { } // loadAttributes loads all attributes -func (comments CommentList) loadAttributes(e db.Engine) (err error) { +func (comments CommentList) loadAttributes(ctx context.Context) (err error) { + e := db.GetEngine(ctx) if err = comments.loadPosters(e); err != nil { return } @@ -520,7 +524,7 @@ func (comments CommentList) loadAttributes(e db.Engine) (err error) { return } - if err = comments.loadDependentIssues(e); err != nil { + if err = comments.loadDependentIssues(ctx); err != nil { return } @@ -530,7 +534,7 @@ func (comments CommentList) loadAttributes(e db.Engine) (err error) { // LoadAttributes loads attributes of the comments, except for attachments and // comments func (comments CommentList) LoadAttributes() error { - return comments.loadAttributes(db.GetEngine(db.DefaultContext)) + return comments.loadAttributes(db.DefaultContext) } // LoadAttachments loads attachments diff --git a/models/issue_comment_test.go b/models/issue_comment_test.go index 5ab4892bc7..ec318688ee 100644 --- a/models/issue_comment_test.go +++ b/models/issue_comment_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -18,7 +19,7 @@ func TestCreateComment(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) issue := unittest.AssertExistsAndLoadBean(t, &Issue{}).(*Issue) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: issue.RepoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) now := time.Now().Unix() diff --git a/models/issue_dependency.go b/models/issue_dependency.go index 9fef652b4e..d2c5785b90 100644 --- a/models/issue_dependency.go +++ b/models/issue_dependency.go @@ -6,10 +6,7 @@ package models import ( "code.gitea.io/gitea/models/db" - "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/timeutil" ) @@ -135,18 +132,3 @@ func issueNoDependenciesLeft(e db.Engine, issue *Issue) (bool, error) { return !exists, err } - -// IsDependenciesEnabled returns if dependencies are enabled and returns the default setting if not set. -func (repo *Repository) IsDependenciesEnabled() bool { - return repo.isDependenciesEnabled(db.GetEngine(db.DefaultContext)) -} - -func (repo *Repository) isDependenciesEnabled(e db.Engine) bool { - var u *RepoUnit - var err error - if u, err = repo.getUnit(e, unit.TypeIssues); err != nil { - log.Trace("%s", err) - return setting.Service.DefaultEnableDependencies - } - return u.IssuesConfig().EnableDependencies -} diff --git a/models/issue_label.go b/models/issue_label.go index 9b36d8dfdf..53d28c0596 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -675,7 +675,7 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m return err } - if err = issue.loadRepo(e); err != nil { + if err = issue.loadRepo(ctx); err != nil { return } @@ -707,7 +707,7 @@ func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error defer committer.Close() sess := db.GetEngine(ctx) - if err = issue.loadRepo(sess); err != nil { + if err = issue.loadRepo(ctx); err != nil { return err } @@ -731,7 +731,7 @@ func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error // newIssueLabels add labels to an issue. It will check if the labels are valid for the issue func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *user_model.User) (err error) { e := db.GetEngine(ctx) - if err = issue.loadRepo(e); err != nil { + if err = issue.loadRepo(ctx); err != nil { return err } for _, label := range labels { @@ -780,7 +780,7 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use return nil } - if err = issue.loadRepo(e); err != nil { + if err = issue.loadRepo(ctx); err != nil { return } diff --git a/models/issue_label_test.go b/models/issue_label_test.go index aa3c92b282..887f7f1425 100644 --- a/models/issue_label_test.go +++ b/models/issue_label_test.go @@ -9,6 +9,7 @@ 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" @@ -49,7 +50,7 @@ func TestNewLabels(t *testing.T) { for _, label := range labels { unittest.AssertExistsAndLoadBean(t, label, unittest.Cond("id = ?", label.ID)) } - unittest.CheckConsistencyFor(t, &Label{}, &Repository{}) + unittest.CheckConsistencyFor(t, &Label{}, &repo_model.Repository{}) } func TestGetLabelByID(t *testing.T) { @@ -270,7 +271,7 @@ func TestUpdateLabel(t *testing.T) { assert.EqualValues(t, label.Color, newLabel.Color) assert.EqualValues(t, label.Name, newLabel.Name) assert.EqualValues(t, label.Description, newLabel.Description) - unittest.CheckConsistencyFor(t, &Label{}, &Repository{}) + unittest.CheckConsistencyFor(t, &Label{}, &repo_model.Repository{}) } func TestDeleteLabel(t *testing.T) { @@ -283,7 +284,7 @@ func TestDeleteLabel(t *testing.T) { unittest.AssertNotExistsBean(t, &Label{ID: label.ID}) assert.NoError(t, DeleteLabel(unittest.NonexistentID, unittest.NonexistentID)) - unittest.CheckConsistencyFor(t, &Label{}, &Repository{}) + unittest.CheckConsistencyFor(t, &Label{}, &repo_model.Repository{}) } func TestHasIssueLabel(t *testing.T) { diff --git a/models/issue_list.go b/models/issue_list.go index 7c98f60b3a..5d8a9f6921 100644 --- a/models/issue_list.go +++ b/models/issue_list.go @@ -32,13 +32,13 @@ func (issues IssueList) getRepoIDs() []int64 { return keysInt64(repoIDs) } -func (issues IssueList) loadRepositories(e db.Engine) ([]*Repository, error) { +func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository, error) { if len(issues) == 0 { return nil, nil } repoIDs := issues.getRepoIDs() - repoMaps := make(map[int64]*Repository, len(repoIDs)) + repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs)) left := len(repoIDs) for left > 0 { limit := defaultMaxInSize @@ -65,7 +65,7 @@ func (issues IssueList) loadRepositories(e db.Engine) ([]*Repository, error) { } // LoadRepositories loads issues' all repositories -func (issues IssueList) LoadRepositories() ([]*Repository, error) { +func (issues IssueList) LoadRepositories() ([]*repo_model.Repository, error) { return issues.loadRepositories(db.GetEngine(db.DefaultContext)) } diff --git a/models/issue_milestone.go b/models/issue_milestone.go index a85c865464..f0949e8b1f 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -11,6 +11,7 @@ import ( "time" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -21,9 +22,9 @@ import ( // Milestone represents a milestone of repository. type Milestone struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX"` - Repo *Repository `xorm:"-"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` + Repo *repo_model.Repository `xorm:"-"` Name string Content string `xorm:"TEXT"` RenderedContent string `xorm:"-"` @@ -287,7 +288,7 @@ func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *Is } if oldMilestoneID > 0 || issue.MilestoneID > 0 { - if err := issue.loadRepo(e); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } @@ -335,7 +336,7 @@ func DeleteMilestoneByRepoID(repoID, id int64) error { return err } - repo, err := GetRepositoryByID(m.RepoID) + repo, err := repo_model.GetRepositoryByID(m.RepoID) if err != nil { return err } diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go index 21d90a6118..9b40144e65 100644 --- a/models/issue_milestone_test.go +++ b/models/issue_milestone_test.go @@ -9,6 +9,7 @@ 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/setting" @@ -34,7 +35,7 @@ func TestNewMilestone(t *testing.T) { assert.NoError(t, NewMilestone(milestone)) unittest.AssertExistsAndLoadBean(t, milestone) - unittest.CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &Milestone{}) } func TestGetMilestoneByRepoID(t *testing.T) { @@ -52,7 +53,7 @@ func TestGetMilestoneByRepoID(t *testing.T) { func TestGetMilestonesByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64, state api.StateType) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) milestones, _, err := GetMilestones(GetMilestonesOption{ RepoID: repo.ID, State: state, @@ -100,7 +101,7 @@ func TestGetMilestonesByRepoID(t *testing.T) { func TestGetMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) test := func(sortType string, sortCond func(*Milestone) int) { for _, page := range []int{0, 1} { milestones, _, err := GetMilestones(GetMilestonesOption{ @@ -174,7 +175,7 @@ func TestUpdateMilestone(t *testing.T) { func TestCountRepoMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) count, err := countRepoMilestones(db.GetEngine(db.DefaultContext), repoID) assert.NoError(t, err) assert.EqualValues(t, repo.NumMilestones, count) @@ -191,7 +192,7 @@ func TestCountRepoMilestones(t *testing.T) { func TestCountRepoClosedMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) count, err := CountRepoClosedMilestones(repoID) assert.NoError(t, err) assert.EqualValues(t, repo.NumClosedMilestones, count) @@ -211,11 +212,11 @@ func TestChangeMilestoneStatus(t *testing.T) { assert.NoError(t, ChangeMilestoneStatus(milestone, true)) unittest.AssertExistsAndLoadBean(t, &Milestone{ID: 1}, "is_closed=1") - unittest.CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &Milestone{}) assert.NoError(t, ChangeMilestoneStatus(milestone, false)) unittest.AssertExistsAndLoadBean(t, &Milestone{ID: 1}, "is_closed=0") - unittest.CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &Milestone{}) } func TestUpdateMilestoneCounters(t *testing.T) { @@ -261,7 +262,7 @@ func TestDeleteMilestoneByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, DeleteMilestoneByRepoID(1, 1)) unittest.AssertNotExistsBean(t, &Milestone{ID: 1}) - unittest.CheckConsistencyFor(t, &Repository{ID: 1}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: 1}) assert.NoError(t, DeleteMilestoneByRepoID(unittest.NonexistentID, unittest.NonexistentID)) } @@ -280,7 +281,7 @@ func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) { func TestCountMilestonesByRepoIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) milestonesCount := func(repoID int64) (int, int) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) return repo.NumOpenMilestones, repo.NumClosedMilestones } repo1OpenCount, repo1ClosedCount := milestonesCount(1) @@ -299,8 +300,8 @@ func TestCountMilestonesByRepoIDs(t *testing.T) { func TestGetMilestonesByRepoIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) test := func(sortType string, sortCond func(*Milestone) int) { for _, page := range []int{0, 1} { openMilestones, err := GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, false, sortType) @@ -355,7 +356,7 @@ func TestGetMilestonesStats(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) stats, err := GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": repoID})) assert.NoError(t, err) assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, stats.OpenCount) @@ -370,8 +371,8 @@ func TestGetMilestonesStats(t *testing.T) { assert.EqualValues(t, 0, stats.OpenCount) assert.EqualValues(t, 0, stats.ClosedCount) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) milestoneStats, err := GetMilestonesStatsByRepoCond(builder.In("repo_id", []int64{repo1.ID, repo2.ID})) assert.NoError(t, err) diff --git a/models/issue_reaction.go b/models/issue_reaction.go index fb34db4ed5..4072733a1c 100644 --- a/models/issue_reaction.go +++ b/models/issue_reaction.go @@ -9,6 +9,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -286,7 +287,7 @@ func (list ReactionList) getUserIDs() []int64 { return keysInt64(userIDs) } -func (list ReactionList) loadUsers(e db.Engine, repo *Repository) ([]*user_model.User, error) { +func (list ReactionList) loadUsers(e db.Engine, repo *repo_model.Repository) ([]*user_model.User, error) { if len(list) == 0 { return nil, nil } @@ -313,7 +314,7 @@ func (list ReactionList) loadUsers(e db.Engine, repo *Repository) ([]*user_model } // LoadUsers loads reactions' all users -func (list ReactionList) LoadUsers(repo *Repository) ([]*user_model.User, error) { +func (list ReactionList) LoadUsers(repo *repo_model.Repository) ([]*user_model.User, error) { return list.loadUsers(db.GetEngine(db.DefaultContext), repo) } diff --git a/models/issue_reaction_test.go b/models/issue_reaction_test.go index 458250ac58..886d19e55f 100644 --- a/models/issue_reaction_test.go +++ b/models/issue_reaction_test.go @@ -7,6 +7,7 @@ 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/setting" @@ -95,7 +96,7 @@ func TestIssueReactionCount(t *testing.T) { addReaction(t, user4, issue, nil, "heart") addReaction(t, ghost, issue, nil, "-1") - err := issue.loadReactions(db.GetEngine(db.DefaultContext)) + err := issue.loadReactions(db.DefaultContext) assert.NoError(t, err) assert.Len(t, issue.Reactions, 7) @@ -135,7 +136,7 @@ func TestIssueCommentDeleteReaction(t *testing.T) { user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: issue1.RepoID}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue1.RepoID}).(*repo_model.Repository) comment1 := unittest.AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) diff --git a/models/issue_stopwatch.go b/models/issue_stopwatch.go index 7754e90a86..530a524218 100644 --- a/models/issue_stopwatch.go +++ b/models/issue_stopwatch.go @@ -156,7 +156,7 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss return err } - if err := issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } @@ -177,7 +177,7 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss // CreateIssueStopwatch creates a stopwatch if not exist, otherwise return an error func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error { e := db.GetEngine(ctx) - if err := issue.loadRepo(e); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } @@ -207,7 +207,7 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss return err } - if err := issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } @@ -248,11 +248,7 @@ func cancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) e return err } - if err := issue.loadRepo(e); err != nil { - return err - } - - if err := issue.loadRepo(db.GetEngine(ctx)); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } diff --git a/models/issue_test.go b/models/issue_test.go index a9e19438d6..eadeb66ab9 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -12,6 +12,7 @@ import ( "time" "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" @@ -23,7 +24,7 @@ func TestIssue_ReplaceLabels(t *testing.T) { testSuccess := func(issueID int64, labelIDs []int64) { issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issueID}).(*Issue) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: issue.RepoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) labels := make([]*Label, len(labelIDs)) @@ -354,7 +355,7 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) { func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *Issue { var newIssue Issue t.Run(title, func(t *testing.T) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) issue := Issue{ @@ -398,7 +399,7 @@ func TestIssue_ResolveMentions(t *testing.T) { testSuccess := func(owner, repo, doer string, mentions []string, expected []int64) { o := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: owner}).(*user_model.User) - r := unittest.AssertExistsAndLoadBean(t, &Repository{OwnerID: o.ID, LowerName: repo}).(*Repository) + r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: o.ID, LowerName: repo}).(*repo_model.Repository) issue := &Issue{RepoID: r.ID} d := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: doer}).(*user_model.User) resolved, err := issue.ResolveMentionsByVisibility(db.DefaultContext, d, mentions) diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go index 392bf91e19..c887baae15 100644 --- a/models/issue_tracked_time.go +++ b/models/issue_tracked_time.go @@ -5,6 +5,7 @@ package models import ( + "context" "time" "code.gitea.io/gitea/models/db" @@ -41,16 +42,17 @@ func (t *TrackedTime) AfterLoad() { // LoadAttributes load Issue, User func (t *TrackedTime) LoadAttributes() (err error) { - return t.loadAttributes(db.GetEngine(db.DefaultContext)) + return t.loadAttributes(db.DefaultContext) } -func (t *TrackedTime) loadAttributes(e db.Engine) (err error) { +func (t *TrackedTime) loadAttributes(ctx context.Context) (err error) { + e := db.GetEngine(ctx) if t.Issue == nil { t.Issue, err = getIssueByID(e, t.IssueID) if err != nil { return } - err = t.Issue.loadRepo(e) + err = t.Issue.loadRepo(ctx) if err != nil { return } @@ -167,7 +169,7 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim return nil, err } - if err := issue.loadRepo(sess); err != nil { + if err := issue.loadRepo(ctx); err != nil { return nil, err } @@ -251,7 +253,7 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { return ErrNotExist{} } - if err := issue.loadRepo(sess); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } if _, err := createComment(ctx, &CreateCommentOptions{ @@ -274,13 +276,12 @@ func DeleteTime(t *TrackedTime) error { return err } defer committer.Close() - sess := db.GetEngine(ctx) - if err := t.loadAttributes(sess); err != nil { + if err := t.loadAttributes(ctx); err != nil { return err } - if err := deleteTime(sess, t); err != nil { + if err := deleteTime(db.GetEngine(ctx), t); err != nil { return err } diff --git a/models/issue_user.go b/models/issue_user.go index b112441e5b..0b1f8204ba 100644 --- a/models/issue_user.go +++ b/models/issue_user.go @@ -9,6 +9,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" ) // IssueUser represents an issue-user relation. @@ -24,8 +25,8 @@ func init() { db.RegisterModel(new(IssueUser)) } -func newIssueUsers(e db.Engine, repo *Repository, issue *Issue) error { - assignees, err := repo.getAssignees(e) +func newIssueUsers(ctx context.Context, repo *repo_model.Repository, issue *Issue) error { + assignees, err := getRepoAssignees(ctx, repo) if err != nil { return fmt.Errorf("getAssignees: %v", err) } @@ -50,10 +51,7 @@ func newIssueUsers(e db.Engine, repo *Repository, issue *Issue) error { }) } - if _, err = e.Insert(issueUsers); err != nil { - return err - } - return nil + return db.Insert(ctx, issueUsers) } // UpdateIssueUserByRead updates issue-user relation for reading. diff --git a/models/issue_user_test.go b/models/issue_user_test.go index daa68d731e..946da6e18d 100644 --- a/models/issue_user_test.go +++ b/models/issue_user_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -16,7 +17,7 @@ import ( func Test_newIssueUsers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) newIssue := &Issue{ RepoID: repo.ID, PosterID: 4, @@ -28,7 +29,7 @@ func Test_newIssueUsers(t *testing.T) { // artificially insert new issue unittest.AssertSuccessfulInsert(t, newIssue) - assert.NoError(t, newIssueUsers(db.GetEngine(db.DefaultContext), repo, newIssue)) + assert.NoError(t, newIssueUsers(db.DefaultContext, repo, newIssue)) // issue_user table should now have entries for new issue unittest.AssertExistsAndLoadBean(t, &IssueUser{IssueID: newIssue.ID, UID: newIssue.PosterID}) diff --git a/models/issue_xref.go b/models/issue_xref.go index ceaff62be1..fdabedf29a 100644 --- a/models/issue_xref.go +++ b/models/issue_xref.go @@ -9,6 +9,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/references" @@ -79,7 +80,7 @@ func (issue *Issue) addCrossReferences(stdCtx context.Context, doer *user_model. func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossReferencesContext, plaincontent, mdcontent string) error { e := db.GetEngine(stdCtx) - xreflist, err := ctx.OrigIssue.getCrossReferences(e, ctx, plaincontent, mdcontent) + xreflist, err := ctx.OrigIssue.getCrossReferences(stdCtx, ctx, plaincontent, mdcontent) if err != nil { return err } @@ -136,35 +137,34 @@ func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossRefe return nil } -func (issue *Issue) getCrossReferences(e db.Engine, ctx *crossReferencesContext, plaincontent, mdcontent string) ([]*crossReference, error) { +func (issue *Issue) getCrossReferences(stdCtx context.Context, ctx *crossReferencesContext, plaincontent, mdcontent string) ([]*crossReference, error) { xreflist := make([]*crossReference, 0, 5) var ( - refRepo *Repository + refRepo *repo_model.Repository refIssue *Issue refAction references.XRefAction err error ) allrefs := append(references.FindAllIssueReferences(plaincontent), references.FindAllIssueReferencesMarkdown(mdcontent)...) - for _, ref := range allrefs { if ref.Owner == "" && ref.Name == "" { // Issues in the same repository - if err := ctx.OrigIssue.loadRepo(e); err != nil { + if err := ctx.OrigIssue.loadRepo(stdCtx); err != nil { return nil, err } refRepo = ctx.OrigIssue.Repo } else { // Issues in other repositories - refRepo, err = getRepositoryByOwnerAndName(e, ref.Owner, ref.Name) + refRepo, err = repo_model.GetRepositoryByOwnerAndNameCtx(stdCtx, ref.Owner, ref.Name) if err != nil { - if IsErrRepoNotExist(err) { + if repo_model.IsErrRepoNotExist(err) { continue } return nil, err } } - if refIssue, refAction, err = ctx.OrigIssue.verifyReferencedIssue(e, ctx, refRepo, ref); err != nil { + if refIssue, refAction, err = ctx.OrigIssue.verifyReferencedIssue(stdCtx, ctx, refRepo, ref); err != nil { return nil, err } if refIssue != nil { @@ -194,15 +194,16 @@ func (issue *Issue) updateCrossReferenceList(list []*crossReference, xref *cross } // verifyReferencedIssue will check if the referenced issue exists, and whether the doer has permission to do what -func (issue *Issue) verifyReferencedIssue(e db.Engine, ctx *crossReferencesContext, repo *Repository, +func (issue *Issue) verifyReferencedIssue(stdCtx context.Context, ctx *crossReferencesContext, repo *repo_model.Repository, ref references.IssueReference) (*Issue, references.XRefAction, error) { refIssue := &Issue{RepoID: repo.ID, Index: ref.Index} refAction := ref.Action + e := db.GetEngine(stdCtx) if has, _ := e.Get(refIssue); !has { return nil, references.XRefActionNone, nil } - if err := refIssue.loadRepo(e); err != nil { + if err := refIssue.loadRepo(stdCtx); err != nil { return nil, references.XRefActionNone, err } @@ -213,7 +214,7 @@ func (issue *Issue) verifyReferencedIssue(e db.Engine, ctx *crossReferencesConte // Check doer permissions; set action to None if the doer can't change the destination if refIssue.RepoID != ctx.OrigIssue.RepoID || ref.Action != references.XRefActionNone { - perm, err := getUserRepoPermission(e, refIssue.Repo, ctx.Doer) + perm, err := getUserRepoPermission(stdCtx, refIssue.Repo, ctx.Doer) if err != nil { return nil, references.XRefActionNone, err } @@ -280,7 +281,7 @@ func (comment *Comment) LoadRefIssue() (err error) { } comment.RefIssue, err = GetIssueByID(comment.RefIssueID) if err == nil { - err = comment.RefIssue.loadRepo(db.GetEngine(db.DefaultContext)) + err = comment.RefIssue.loadRepo(db.DefaultContext) } return } diff --git a/models/issue_xref_test.go b/models/issue_xref_test.go index 06f937c80d..9b1cb5e2d5 100644 --- a/models/issue_xref_test.go +++ b/models/issue_xref_test.go @@ -9,6 +9,7 @@ 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/references" @@ -126,7 +127,7 @@ func TestXRef_ResolveCrossReferences(t *testing.T) { } func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispull bool) *Issue { - r := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repo}).(*Repository) + r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository) d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User) idx, err := db.GetNextResourceIndex("issue_index", r.ID) @@ -157,7 +158,7 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu } func testCreatePR(t *testing.T, repo, doer int64, title, content string) *PullRequest { - r := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repo}).(*Repository) + r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository) d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User) i := &Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true} pr := &PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: PullRequestStatusMergeable} diff --git a/models/lfs.go b/models/lfs.go index da5e61ed0b..56924ffcf2 100644 --- a/models/lfs.go +++ b/models/lfs.go @@ -5,9 +5,11 @@ package models import ( + "context" "errors" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/timeutil" @@ -71,12 +73,12 @@ func NewLFSMetaObject(m *LFSMetaObject) (*LFSMetaObject, error) { // GetLFSMetaObjectByOid selects a LFSMetaObject entry from database by its OID. // It may return ErrLFSObjectNotExist or a database error. If the error is nil, // the returned pointer is a valid LFSMetaObject. -func (repo *Repository) GetLFSMetaObjectByOid(oid string) (*LFSMetaObject, error) { +func GetLFSMetaObjectByOid(repoID int64, oid string) (*LFSMetaObject, error) { if len(oid) == 0 { return nil, ErrLFSObjectNotExist } - m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repo.ID} + m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repoID} has, err := db.GetEngine(db.DefaultContext).Get(m) if err != nil { return nil, err @@ -88,7 +90,7 @@ func (repo *Repository) GetLFSMetaObjectByOid(oid string) (*LFSMetaObject, error // RemoveLFSMetaObjectByOid removes a LFSMetaObject entry from database by its OID. // It may return ErrLFSObjectNotExist or a database error. -func (repo *Repository) RemoveLFSMetaObjectByOid(oid string) (int64, error) { +func RemoveLFSMetaObjectByOid(repoID int64, oid string) (int64, error) { if len(oid) == 0 { return 0, ErrLFSObjectNotExist } @@ -99,7 +101,7 @@ func (repo *Repository) RemoveLFSMetaObjectByOid(oid string) (int64, error) { } defer committer.Close() - m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repo.ID} + m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repoID} if _, err := db.DeleteByBean(ctx, m); err != nil { return -1, err } @@ -113,7 +115,7 @@ func (repo *Repository) RemoveLFSMetaObjectByOid(oid string) (int64, error) { } // GetLFSMetaObjects returns all LFSMetaObjects associated with a repository -func (repo *Repository) GetLFSMetaObjects(page, pageSize int) ([]*LFSMetaObject, error) { +func GetLFSMetaObjects(repoID int64, page, pageSize int) ([]*LFSMetaObject, error) { sess := db.GetEngine(db.DefaultContext) if page >= 0 && pageSize > 0 { @@ -124,12 +126,12 @@ func (repo *Repository) GetLFSMetaObjects(page, pageSize int) ([]*LFSMetaObject, sess.Limit(pageSize, start) } lfsObjects := make([]*LFSMetaObject, 0, pageSize) - return lfsObjects, sess.Find(&lfsObjects, &LFSMetaObject{RepositoryID: repo.ID}) + return lfsObjects, sess.Find(&lfsObjects, &LFSMetaObject{RepositoryID: repoID}) } // CountLFSMetaObjects returns a count of all LFSMetaObjects associated with a repository -func (repo *Repository) CountLFSMetaObjects() (int64, error) { - return db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{RepositoryID: repo.ID}) +func CountLFSMetaObjects(repoID int64) (int64, error) { + return db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{RepositoryID: repoID}) } // LFSObjectAccessible checks if a provided Oid is accessible to the user @@ -202,3 +204,21 @@ func IterateLFS(f func(mo *LFSMetaObject) error) error { } } } + +// CopyLFS copies LFS data from one repo to another +func CopyLFS(ctx context.Context, newRepo, oldRepo *repo_model.Repository) error { + var lfsObjects []*LFSMetaObject + if err := db.GetEngine(ctx).Where("repository_id=?", oldRepo.ID).Find(&lfsObjects); err != nil { + return err + } + + for _, v := range lfsObjects { + v.ID = 0 + v.RepositoryID = newRepo.ID + if _, err := db.GetEngine(ctx).Insert(v); err != nil { + return err + } + } + + return nil +} diff --git a/models/lfs_lock.go b/models/lfs_lock.go index 7cd8e1279b..a77dd24e9f 100644 --- a/models/lfs_lock.go +++ b/models/lfs_lock.go @@ -12,21 +12,19 @@ import ( "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/xorm" + "code.gitea.io/gitea/modules/setting" ) // LFSLock represents a git lfs lock of repository. type LFSLock struct { - ID int64 `xorm:"pk autoincr"` - Repo *Repository `xorm:"-"` - RepoID int64 `xorm:"INDEX NOT NULL"` - OwnerID int64 `xorm:"INDEX NOT NULL"` - Path string `xorm:"TEXT"` - Created time.Time `xorm:"created"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX NOT NULL"` + OwnerID int64 `xorm:"INDEX NOT NULL"` + Path string `xorm:"TEXT"` + Created time.Time `xorm:"created"` } func init() { @@ -35,33 +33,24 @@ func init() { // BeforeInsert is invoked from XORM before inserting an object of this type. func (l *LFSLock) BeforeInsert() { - l.RepoID = l.Repo.ID l.Path = cleanPath(l.Path) } -// AfterLoad is invoked from XORM after setting the values of all fields of this object. -func (l *LFSLock) AfterLoad(session *xorm.Session) { - var err error - l.Repo, err = getRepositoryByID(session, l.RepoID) - if err != nil { - log.Error("LFS lock AfterLoad failed RepoId[%d] not found: %v", l.RepoID, err) - } -} - func cleanPath(p string) string { return path.Clean("/" + p)[1:] } // CreateLFSLock creates a new lock. -func CreateLFSLock(lock *LFSLock) (*LFSLock, error) { - err := CheckLFSAccessForRepo(lock.OwnerID, lock.Repo, perm.AccessModeWrite) +func CreateLFSLock(repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) { + err := CheckLFSAccessForRepo(lock.OwnerID, repo, perm.AccessModeWrite) if err != nil { return nil, err } lock.Path = cleanPath(lock.Path) + lock.RepoID = repo.ID - l, err := GetLFSLock(lock.Repo, lock.Path) + l, err := GetLFSLock(repo, lock.Path) if err == nil { return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path} } @@ -69,12 +58,12 @@ func CreateLFSLock(lock *LFSLock) (*LFSLock, error) { return nil, err } - _, err = db.GetEngine(db.DefaultContext).InsertOne(lock) + err = db.Insert(db.DefaultContext, lock) return lock, err } // GetLFSLock returns release by given path. -func GetLFSLock(repo *Repository, path string) (*LFSLock, error) { +func GetLFSLock(repo *repo_model.Repository, path string) (*LFSLock, error) { path = cleanPath(path) rel := &LFSLock{RepoID: repo.ID} has, err := db.GetEngine(db.DefaultContext).Where("lower(path) = ?", strings.ToLower(path)).Get(rel) @@ -113,19 +102,37 @@ func GetLFSLockByRepoID(repoID int64, page, pageSize int) ([]*LFSLock, error) { return lfsLocks, e.Find(&lfsLocks, &LFSLock{RepoID: repoID}) } +// GetTreePathLock returns LSF lock for the treePath +func GetTreePathLock(repoID int64, treePath string) (*LFSLock, error) { + if !setting.LFS.StartServer { + return nil, nil + } + + locks, err := GetLFSLockByRepoID(repoID, 0, 0) + if err != nil { + return nil, err + } + for _, lock := range locks { + if lock.Path == treePath { + return lock, nil + } + } + return nil, nil +} + // CountLFSLockByRepoID returns a count of all LFSLocks associated with a repository. func CountLFSLockByRepoID(repoID int64) (int64, error) { return db.GetEngine(db.DefaultContext).Count(&LFSLock{RepoID: repoID}) } // DeleteLFSLockByID deletes a lock by given ID. -func DeleteLFSLockByID(id int64, u *user_model.User, force bool) (*LFSLock, error) { +func DeleteLFSLockByID(id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) { lock, err := GetLFSLockByID(id) if err != nil { return nil, err } - err = CheckLFSAccessForRepo(u.ID, lock.Repo, perm.AccessModeWrite) + err = CheckLFSAccessForRepo(u.ID, repo, perm.AccessModeWrite) if err != nil { return nil, err } @@ -139,7 +146,7 @@ func DeleteLFSLockByID(id int64, u *user_model.User, force bool) (*LFSLock, erro } // CheckLFSAccessForRepo check needed access mode base on action -func CheckLFSAccessForRepo(ownerID int64, repo *Repository, mode perm.AccessMode) error { +func CheckLFSAccessForRepo(ownerID int64, repo *repo_model.Repository, mode perm.AccessMode) error { if ownerID == 0 { return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode} } diff --git a/models/main_test.go b/models/main_test.go index 87e59f5b11..20107eab1e 100644 --- a/models/main_test.go +++ b/models/main_test.go @@ -7,6 +7,7 @@ package models import ( "testing" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -18,7 +19,7 @@ func TestFixturesAreConsistent(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) unittest.CheckConsistencyFor(t, &user_model.User{}, - &Repository{}, + &repo_model.Repository{}, &Issue{}, &PullRequest{}, &Milestone{}, diff --git a/models/notification.go b/models/notification.go index ef8a1e83b8..b71973823a 100644 --- a/models/notification.go +++ b/models/notification.go @@ -11,6 +11,7 @@ import ( "strconv" "code.gitea.io/gitea/models/db" + 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" @@ -63,10 +64,10 @@ type Notification struct { UpdatedBy int64 `xorm:"INDEX NOT NULL"` - Issue *Issue `xorm:"-"` - Repository *Repository `xorm:"-"` - Comment *Comment `xorm:"-"` - User *user_model.User `xorm:"-"` + Issue *Issue `xorm:"-"` + Repository *repo_model.Repository `xorm:"-"` + Comment *Comment `xorm:"-"` + User *user_model.User `xorm:"-"` CreatedUnix timeutil.TimeStamp `xorm:"created INDEX NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated INDEX NOT NULL"` @@ -140,7 +141,7 @@ func CountNotifications(opts *FindNotificationOptions) (int64, error) { } // CreateRepoTransferNotification creates notification for the user a repository was transferred to -func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *Repository) error { +func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *repo_model.Repository) error { ctx, committer, err := db.TxContext() if err != nil { return err @@ -190,14 +191,15 @@ func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID, } defer committer.Close() - if err := createOrUpdateIssueNotifications(db.GetEngine(ctx), issueID, commentID, notificationAuthorID, receiverID); err != nil { + if err := createOrUpdateIssueNotifications(ctx, issueID, commentID, notificationAuthorID, receiverID); err != nil { return err } return committer.Commit() } -func createOrUpdateIssueNotifications(e db.Engine, issueID, commentID, notificationAuthorID, receiverID int64) error { +func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error { + e := db.GetEngine(ctx) // init var toNotify map[int64]struct{} notifications, err := getNotificationsByIssueID(e, issueID) @@ -251,7 +253,7 @@ func createOrUpdateIssueNotifications(e db.Engine, issueID, commentID, notificat } } - err = issue.loadRepo(e) + err = issue.loadRepo(ctx) if err != nil { return err } @@ -267,10 +269,10 @@ func createOrUpdateIssueNotifications(e db.Engine, issueID, commentID, notificat return err } - if issue.IsPull && !issue.Repo.checkUnitUser(e, user, unit.TypePullRequests) { + if issue.IsPull && !checkRepoUnitUser(ctx, issue.Repo, user, unit.TypePullRequests) { continue } - if !issue.IsPull && !issue.Repo.checkUnitUser(e, user, unit.TypeIssues) { + if !issue.IsPull && !checkRepoUnitUser(ctx, issue.Repo, user, unit.TypeIssues) { continue } @@ -399,7 +401,7 @@ func (n *Notification) LoadAttributes() (err error) { func (n *Notification) loadAttributes(ctx context.Context) (err error) { e := db.GetEngine(ctx) - if err = n.loadRepo(e); err != nil { + if err = n.loadRepo(ctx); err != nil { return } if err = n.loadIssue(ctx); err != nil { @@ -414,9 +416,9 @@ func (n *Notification) loadAttributes(ctx context.Context) (err error) { return } -func (n *Notification) loadRepo(e db.Engine) (err error) { +func (n *Notification) loadRepo(ctx context.Context) (err error) { if n.Repository == nil { - n.Repository, err = getRepositoryByID(e, n.RepoID) + n.Repository, err = repo_model.GetRepositoryByIDCtx(ctx, n.RepoID) if err != nil { return fmt.Errorf("getRepositoryByID [%d]: %v", n.RepoID, err) } @@ -462,8 +464,8 @@ func (n *Notification) loadUser(e db.Engine) (err error) { } // GetRepo returns the repo of the notification -func (n *Notification) GetRepo() (*Repository, error) { - return n.Repository, n.loadRepo(db.GetEngine(db.DefaultContext)) +func (n *Notification) GetRepo() (*repo_model.Repository, error) { + return n.Repository, n.loadRepo(db.DefaultContext) } // GetIssue returns the issue of the notification @@ -526,7 +528,7 @@ func (nl NotificationList) LoadRepos() (RepositoryList, []int, error) { } repoIDs := nl.getPendingRepoIDs() - repos := make(map[int64]*Repository, len(repoIDs)) + repos := make(map[int64]*repo_model.Repository, len(repoIDs)) left := len(repoIDs) for left > 0 { limit := defaultMaxInSize @@ -535,13 +537,13 @@ func (nl NotificationList) LoadRepos() (RepositoryList, []int, error) { } rows, err := db.GetEngine(db.DefaultContext). In("id", repoIDs[:limit]). - Rows(new(Repository)) + Rows(new(repo_model.Repository)) if err != nil { return nil, nil, err } for rows.Next() { - var repo Repository + var repo repo_model.Repository err = rows.Scan(&repo) if err != nil { rows.Close() diff --git a/models/org.go b/models/org.go index becfa4cb05..e5cd80ab78 100644 --- a/models/org.go +++ b/models/org.go @@ -12,6 +12,7 @@ import ( "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" @@ -904,8 +905,8 @@ func (org *Organization) GetUserTeams(userID int64) ([]*Team, error) { type AccessibleReposEnvironment interface { CountRepos() (int64, error) RepoIDs(page, pageSize int) ([]int64, error) - Repos(page, pageSize int) ([]*Repository, error) - MirrorRepos() ([]*Repository, error) + Repos(page, pageSize int) ([]*repo_model.Repository, error) + MirrorRepos() ([]*repo_model.Repository, error) AddKeyword(keyword string) SetSort(db.SearchOrderBy) } @@ -987,7 +988,7 @@ func (env *accessibleReposEnv) CountRepos() (int64, error) { Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id"). Where(env.cond()). Distinct("`repository`.id"). - Count(&Repository{}) + Count(&repo_model.Repository{}) if err != nil { return 0, fmt.Errorf("count user repositories in organization: %v", err) } @@ -1011,13 +1012,13 @@ func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) { Find(&repoIDs) } -func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*Repository, error) { +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([]*Repository, 0, len(repoIDs)) + repos := make([]*repo_model.Repository, 0, len(repoIDs)) if len(repoIDs) == 0 { return repos, nil } @@ -1040,13 +1041,13 @@ func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) { Find(&repoIDs) } -func (env *accessibleReposEnv) MirrorRepos() ([]*Repository, error) { +func (env *accessibleReposEnv) MirrorRepos() ([]*repo_model.Repository, error) { repoIDs, err := env.MirrorRepoIDs() if err != nil { return nil, fmt.Errorf("MirrorRepoIDs: %v", err) } - repos := make([]*Repository, 0, len(repoIDs)) + repos := make([]*repo_model.Repository, 0, len(repoIDs)) if len(repoIDs) == 0 { return repos, nil } diff --git a/models/org_team.go b/models/org_team.go index dc16fa5030..c42312323c 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -14,6 +14,7 @@ import ( "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" @@ -32,8 +33,8 @@ type Team struct { Name string Description string Authorize perm.AccessMode - Repos []*Repository `xorm:"-"` - Members []*user_model.User `xorm:"-"` + Repos []*repo_model.Repository `xorm:"-"` + Members []*user_model.User `xorm:"-"` NumRepos int NumMembers int Units []*TeamUnit `xorm:"-"` @@ -215,7 +216,8 @@ func (t *Team) HasRepository(repoID int64) bool { return t.hasRepository(db.GetEngine(db.DefaultContext), repoID) } -func (t *Team) addRepository(e db.Engine, repo *Repository) (err error) { +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 } @@ -226,7 +228,7 @@ func (t *Team) addRepository(e db.Engine, repo *Repository) (err error) { t.NumRepos++ - if err = repo.recalculateTeamAccesses(e, 0); err != nil { + if err = recalculateTeamAccesses(ctx, repo, 0); err != nil { return fmt.Errorf("recalculateAccesses: %v", err) } @@ -247,15 +249,16 @@ func (t *Team) addRepository(e db.Engine, repo *Repository) (err error) { // addAllRepositories adds all repositories to the team. // If the team already has some repositories they will be left unchanged. -func (t *Team) addAllRepositories(e db.Engine) error { - var orgRepos []Repository +func (t *Team) addAllRepositories(ctx context.Context) error { + var orgRepos []repo_model.Repository + e := db.GetEngine(ctx) if err := e.Where("owner_id = ?", t.OrgID).Find(&orgRepos); err != nil { return fmt.Errorf("get org repos: %v", err) } for _, repo := range orgRepos { if !t.hasRepository(e, repo.ID) { - if err := t.addRepository(e, &repo); err != nil { + if err := t.addRepository(ctx, &repo); err != nil { return fmt.Errorf("addRepository: %v", err) } } @@ -272,7 +275,7 @@ func (t *Team) AddAllRepositories() (err error) { } defer committer.Close() - if err = t.addAllRepositories(db.GetEngine(ctx)); err != nil { + if err = t.addAllRepositories(ctx); err != nil { return err } @@ -280,7 +283,7 @@ func (t *Team) AddAllRepositories() (err error) { } // AddRepository adds new repository to team of organization. -func (t *Team) AddRepository(repo *Repository) (err error) { +func (t *Team) AddRepository(repo *repo_model.Repository) (err error) { if repo.OwnerID != t.OrgID { return errors.New("Repository does not belong to organization") } else if t.HasRepository(repo.ID) { @@ -293,7 +296,7 @@ func (t *Team) AddRepository(repo *Repository) (err error) { } defer committer.Close() - if err = t.addRepository(db.GetEngine(ctx), repo); err != nil { + if err = t.addRepository(ctx, repo); err != nil { return err } @@ -312,7 +315,7 @@ func (t *Team) RemoveAllRepositories() (err error) { } defer committer.Close() - if err = t.removeAllRepositories(db.GetEngine(ctx)); err != nil { + if err = t.removeAllRepositories(ctx); err != nil { return err } @@ -321,16 +324,17 @@ func (t *Team) RemoveAllRepositories() (err error) { // removeAllRepositories removes all repositories from team and recalculates access // Note: Shall not be called if team includes all repositories -func (t *Team) removeAllRepositories(e db.Engine) (err error) { +func (t *Team) removeAllRepositories(ctx context.Context) (err error) { + e := db.GetEngine(ctx) // Delete all accesses. for _, repo := range t.Repos { - if err := repo.recalculateTeamAccesses(e, t.ID); err != nil { + if err := recalculateTeamAccesses(ctx, repo, t.ID); err != nil { return err } // Remove watches from all users and now unaccessible repos for _, user := range t.Members { - has, err := hasAccess(e, user.ID, repo) + has, err := hasAccess(ctx, user.ID, repo) if err != nil { return err } else if has { @@ -365,7 +369,8 @@ func (t *Team) removeAllRepositories(e db.Engine) (err error) { // removeRepository removes a repository from a team and recalculates access // Note: Repository shall not be removed from team if it includes all repositories (unless the repository is deleted) -func (t *Team) removeRepository(e db.Engine, repo *Repository, recalculate bool) (err error) { +func (t *Team) removeRepository(ctx context.Context, repo *repo_model.Repository, recalculate bool) (err error) { + e := db.GetEngine(ctx) if err = removeTeamRepo(e, t.ID, repo.ID); err != nil { return err } @@ -377,7 +382,7 @@ func (t *Team) removeRepository(e db.Engine, repo *Repository, recalculate bool) // Don't need to recalculate when delete a repository from organization. if recalculate { - if err = repo.recalculateTeamAccesses(e, t.ID); err != nil { + if err = recalculateTeamAccesses(ctx, repo, t.ID); err != nil { return err } } @@ -387,7 +392,7 @@ func (t *Team) removeRepository(e db.Engine, repo *Repository, recalculate bool) return fmt.Errorf("getTeamUsersByTeamID: %v", err) } for _, teamUser := range teamUsers { - has, err := hasAccess(e, teamUser.UID, repo) + has, err := hasAccess(ctx, teamUser.UID, repo) if err != nil { return err } else if has { @@ -418,7 +423,7 @@ func (t *Team) RemoveRepository(repoID int64) error { return nil } - repo, err := GetRepositoryByID(repoID) + repo, err := repo_model.GetRepositoryByID(repoID) if err != nil { return err } @@ -429,7 +434,7 @@ func (t *Team) RemoveRepository(repoID int64) error { } defer committer.Close() - if err = t.removeRepository(db.GetEngine(ctx), repo, true); err != nil { + if err = t.removeRepository(ctx, repo, true); err != nil { return err } @@ -517,7 +522,7 @@ func NewTeam(t *Team) (err error) { // Add all repositories to the team if it has access to all of them. if t.IncludesAllRepositories { - err = t.addAllRepositories(db.GetEngine(ctx)) + err = t.addAllRepositories(ctx) if err != nil { return fmt.Errorf("addAllRepositories: %v", err) } @@ -660,7 +665,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) { } for _, repo := range t.Repos { - if err = repo.recalculateTeamAccesses(sess, 0); err != nil { + if err = recalculateTeamAccesses(ctx, repo, 0); err != nil { return fmt.Errorf("recalculateTeamAccesses: %v", err) } } @@ -668,7 +673,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) { // Add all repositories to the team if it has access to all of them. if includeAllChanged && t.IncludesAllRepositories { - err = t.addAllRepositories(sess) + err = t.addAllRepositories(ctx) if err != nil { return fmt.Errorf("addAllRepositories: %v", err) } @@ -695,7 +700,7 @@ func DeleteTeam(t *Team) error { return err } - if err := t.removeAllRepositories(sess); err != nil { + if err := t.removeAllRepositories(ctx); err != nil { return err } @@ -848,7 +853,7 @@ func AddTeamMember(team *Team, userID int64) error { // Give access to team repositories. for _, repo := range team.Repos { - if err := repo.recalculateUserAccess(sess, userID); err != nil { + if err := recalculateUserAccess(ctx, repo, userID); err != nil { return err } if setting.Service.AutoWatchNewRepos { @@ -894,17 +899,17 @@ func removeTeamMember(ctx context.Context, team *Team, userID int64) error { // Delete access to team repositories. for _, repo := range team.Repos { - if err := repo.recalculateUserAccess(e, userID); err != nil { + if err := recalculateUserAccess(ctx, repo, userID); err != nil { return err } // Remove watches from now unaccessible - if err := repo.reconsiderWatches(e, userID); err != nil { + if err := reconsiderWatches(ctx, repo, userID); err != nil { return err } // Remove issue assignments from now unaccessible - if err := repo.reconsiderIssueAssignees(e, userID); err != nil { + if err := reconsiderRepoIssuesAssignee(ctx, repo, userID); err != nil { return err } } diff --git a/models/org_team_test.go b/models/org_team_test.go index 084e376cc9..59b7b6d5a8 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -10,6 +10,7 @@ import ( "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/unittest" user_model "code.gitea.io/gitea/models/user" @@ -124,18 +125,18 @@ func TestTeam_AddRepository(t *testing.T) { testSuccess := func(teamID, repoID int64) { team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) assert.NoError(t, team.AddRepository(repo)) unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repoID}) - unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &Repository{ID: repoID}) + unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &repo_model.Repository{ID: repoID}) } testSuccess(2, 3) testSuccess(2, 5) team := unittest.AssertExistsAndLoadBean(t, &Team{ID: 1}).(*Team) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) assert.Error(t, team.AddRepository(repo)) - unittest.CheckConsistencyFor(t, &Team{ID: 1}, &Repository{ID: 1}) + unittest.CheckConsistencyFor(t, &Team{ID: 1}, &repo_model.Repository{ID: 1}) } func TestTeam_RemoveRepository(t *testing.T) { @@ -145,7 +146,7 @@ func TestTeam_RemoveRepository(t *testing.T) { team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) assert.NoError(t, team.RemoveRepository(repoID)) unittest.AssertNotExistsBean(t, &TeamRepo{TeamID: teamID, RepoID: repoID}) - unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &Repository{ID: repoID}) + unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &repo_model.Repository{ID: repoID}) } testSuccess(2, 3) testSuccess(2, 5) @@ -247,7 +248,7 @@ func TestDeleteTeam(t *testing.T) { // check that team members don't have "leftover" access to repos user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) accessMode, err := AccessLevel(user, repo) assert.NoError(t, err) assert.True(t, accessMode < perm.AccessModeWrite) diff --git a/models/org_test.go b/models/org_test.go index c24064c5b8..ec324cb71a 100644 --- a/models/org_test.go +++ b/models/org_test.go @@ -8,6 +8,7 @@ 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/setting" @@ -160,13 +161,13 @@ func TestUser_RemoveMember(t *testing.T) { func TestUser_RemoveOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{OwnerID: org.ID}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: org.ID}).(*repo_model.Repository) // remove a repo that does belong to org unittest.AssertExistsAndLoadBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID}) assert.NoError(t, org.RemoveOrgRepo(repo.ID)) unittest.AssertNotExistsBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID}) - unittest.AssertExistsAndLoadBean(t, &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 assert.NoError(t, org.RemoveOrgRepo(repo.ID)) @@ -177,7 +178,7 @@ func TestUser_RemoveOrgRepo(t *testing.T) { unittest.CheckConsistencyFor(t, &user_model.User{ID: org.ID}, &Team{OrgID: org.ID}, - &Repository{ID: repo.ID}) + &repo_model.Repository{ID: repo.ID}) } func TestCreateOrganization(t *testing.T) { @@ -541,10 +542,10 @@ func TestAccessibleReposEnv_Repos(t *testing.T) { assert.NoError(t, err) repos, err := env.Repos(1, 100) assert.NoError(t, err) - expectedRepos := make([]*Repository, len(expectedRepoIDs)) + expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs)) for i, repoID := range expectedRepoIDs { expectedRepos[i] = unittest.AssertExistsAndLoadBean(t, - &Repository{ID: repoID}).(*Repository) + &repo_model.Repository{ID: repoID}).(*repo_model.Repository) } assert.Equal(t, expectedRepos, repos) } @@ -560,10 +561,10 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) { assert.NoError(t, err) repos, err := env.MirrorRepos() assert.NoError(t, err) - expectedRepos := make([]*Repository, len(expectedRepoIDs)) + expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs)) for i, repoID := range expectedRepoIDs { expectedRepos[i] = unittest.AssertExistsAndLoadBean(t, - &Repository{ID: repoID}).(*Repository) + &repo_model.Repository{ID: repoID}).(*repo_model.Repository) } assert.Equal(t, expectedRepos, repos) } diff --git a/models/project_issue.go b/models/project_issue.go index c1421485b0..c7735addcc 100644 --- a/models/project_issue.go +++ b/models/project_issue.go @@ -154,7 +154,7 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U return err } - if err := issue.loadRepo(e); err != nil { + if err := issue.loadRepo(ctx); err != nil { return err } diff --git a/models/protected_tag.go b/models/protected_tag.go index 93318300e8..c9cc0fa1ba 100644 --- a/models/protected_tag.go +++ b/models/protected_tag.go @@ -33,6 +33,28 @@ func init() { db.RegisterModel(new(ProtectedTag)) } +// EnsureCompiledPattern ensures the glob pattern is compiled +func (pt *ProtectedTag) EnsureCompiledPattern() error { + if pt.RegexPattern != nil || pt.GlobPattern != nil { + return nil + } + + var err error + if len(pt.NamePattern) >= 2 && strings.HasPrefix(pt.NamePattern, "/") && strings.HasSuffix(pt.NamePattern, "/") { + pt.RegexPattern, err = regexp.Compile(pt.NamePattern[1 : len(pt.NamePattern)-1]) + } else { + pt.GlobPattern, err = glob.Compile(pt.NamePattern) + } + return err +} + +func (pt *ProtectedTag) matchString(name string) bool { + if pt.RegexPattern != nil { + return pt.RegexPattern.MatchString(name) + } + return pt.GlobPattern.Match(name) +} + // InsertProtectedTag inserts a protected tag to database func InsertProtectedTag(pt *ProtectedTag) error { _, err := db.GetEngine(db.DefaultContext).Insert(pt) @@ -51,23 +73,8 @@ func DeleteProtectedTag(pt *ProtectedTag) error { return err } -// EnsureCompiledPattern ensures the glob pattern is compiled -func (pt *ProtectedTag) EnsureCompiledPattern() error { - if pt.RegexPattern != nil || pt.GlobPattern != nil { - return nil - } - - var err error - if len(pt.NamePattern) >= 2 && strings.HasPrefix(pt.NamePattern, "/") && strings.HasSuffix(pt.NamePattern, "/") { - pt.RegexPattern, err = regexp.Compile(pt.NamePattern[1 : len(pt.NamePattern)-1]) - } else { - pt.GlobPattern, err = glob.Compile(pt.NamePattern) - } - return err -} - -// IsUserAllowed returns true if the user is allowed to modify the tag -func (pt *ProtectedTag) IsUserAllowed(userID int64) (bool, error) { +// IsUserAllowedModifyTag returns true if the user is allowed to modify the tag +func IsUserAllowedModifyTag(pt *ProtectedTag, userID int64) (bool, error) { if base.Int64sContains(pt.AllowlistUserIDs, userID) { return true, nil } @@ -84,9 +91,9 @@ func (pt *ProtectedTag) IsUserAllowed(userID int64) (bool, error) { } // GetProtectedTags gets all protected tags of the repository -func (repo *Repository) GetProtectedTags() ([]*ProtectedTag, error) { +func GetProtectedTags(repoID int64) ([]*ProtectedTag, error) { tags := make([]*ProtectedTag, 0) - return tags, db.GetEngine(db.DefaultContext).Find(&tags, &ProtectedTag{RepoID: repo.ID}) + return tags, db.GetEngine(db.DefaultContext).Find(&tags, &ProtectedTag{RepoID: repoID}) } // GetProtectedTagByID gets the protected tag with the specific id @@ -116,7 +123,7 @@ func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int6 continue } - isAllowed, err = tag.IsUserAllowed(userID) + isAllowed, err = IsUserAllowedModifyTag(tag, userID) if err != nil { return false, err } @@ -127,10 +134,3 @@ func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int6 return isAllowed, nil } - -func (pt *ProtectedTag) matchString(name string) bool { - if pt.RegexPattern != nil { - return pt.RegexPattern.MatchString(name) - } - return pt.GlobPattern.Match(name) -} diff --git a/models/protected_tag_test.go b/models/protected_tag_test.go index ed838483d2..bbd5086092 100644 --- a/models/protected_tag_test.go +++ b/models/protected_tag_test.go @@ -16,29 +16,29 @@ func TestIsUserAllowed(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) pt := &ProtectedTag{} - allowed, err := pt.IsUserAllowed(1) + allowed, err := IsUserAllowedModifyTag(pt, 1) assert.NoError(t, err) assert.False(t, allowed) pt = &ProtectedTag{ AllowlistUserIDs: []int64{1}, } - allowed, err = pt.IsUserAllowed(1) + allowed, err = IsUserAllowedModifyTag(pt, 1) assert.NoError(t, err) assert.True(t, allowed) - allowed, err = pt.IsUserAllowed(2) + allowed, err = IsUserAllowedModifyTag(pt, 2) assert.NoError(t, err) assert.False(t, allowed) pt = &ProtectedTag{ AllowlistTeamIDs: []int64{1}, } - allowed, err = pt.IsUserAllowed(1) + allowed, err = IsUserAllowedModifyTag(pt, 1) assert.NoError(t, err) assert.False(t, allowed) - allowed, err = pt.IsUserAllowed(2) + allowed, err = IsUserAllowedModifyTag(pt, 2) assert.NoError(t, err) assert.True(t, allowed) @@ -46,11 +46,11 @@ func TestIsUserAllowed(t *testing.T) { AllowlistUserIDs: []int64{1}, AllowlistTeamIDs: []int64{1}, } - allowed, err = pt.IsUserAllowed(1) + allowed, err = IsUserAllowedModifyTag(pt, 1) assert.NoError(t, err) assert.True(t, allowed) - allowed, err = pt.IsUserAllowed(2) + allowed, err = IsUserAllowedModifyTag(pt, 2) assert.NoError(t, err) assert.True(t, allowed) } diff --git a/models/pull.go b/models/pull.go index aa58322bce..243d40b1fa 100644 --- a/models/pull.go +++ b/models/pull.go @@ -6,11 +6,13 @@ package models import ( + "context" "fmt" "io" "strings" "code.gitea.io/gitea/models/db" + 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/git" @@ -67,10 +69,10 @@ type PullRequest struct { Issue *Issue `xorm:"-"` Index int64 - HeadRepoID int64 `xorm:"INDEX"` - HeadRepo *Repository `xorm:"-"` - BaseRepoID int64 `xorm:"INDEX"` - BaseRepo *Repository `xorm:"-"` + HeadRepoID int64 `xorm:"INDEX"` + HeadRepo *repo_model.Repository `xorm:"-"` + BaseRepoID int64 `xorm:"INDEX"` + BaseRepo *repo_model.Repository `xorm:"-"` HeadBranch string HeadCommitID string `xorm:"-"` BaseBranch string @@ -95,7 +97,7 @@ func init() { // MustHeadUserName returns the HeadRepo's username if failed return blank func (pr *PullRequest) MustHeadUserName() string { if err := pr.LoadHeadRepo(); err != nil { - if !IsErrRepoNotExist(err) { + if !repo_model.IsErrRepoNotExist(err) { log.Error("LoadHeadRepo: %v", err) } else { log.Warn("LoadHeadRepo %d but repository does not exist: %v", pr.HeadRepoID, err) @@ -128,7 +130,7 @@ func (pr *PullRequest) LoadAttributes() error { return pr.loadAttributes(db.GetEngine(db.DefaultContext)) } -func (pr *PullRequest) loadHeadRepo(e db.Engine) (err error) { +func (pr *PullRequest) loadHeadRepo(ctx context.Context) (err error) { if !pr.isHeadRepoLoaded && pr.HeadRepo == nil && pr.HeadRepoID > 0 { if pr.HeadRepoID == pr.BaseRepoID { if pr.BaseRepo != nil { @@ -140,8 +142,8 @@ func (pr *PullRequest) loadHeadRepo(e db.Engine) (err error) { } } - pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID) - if err != nil && !IsErrRepoNotExist(err) { // Head repo maybe deleted, but it should still work + pr.HeadRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.HeadRepoID) + if err != nil && !repo_model.IsErrRepoNotExist(err) { // Head repo maybe deleted, but it should still work return fmt.Errorf("getRepositoryByID(head): %v", err) } pr.isHeadRepoLoaded = true @@ -151,15 +153,15 @@ func (pr *PullRequest) loadHeadRepo(e db.Engine) (err error) { // LoadHeadRepo loads the head repository func (pr *PullRequest) LoadHeadRepo() error { - return pr.loadHeadRepo(db.GetEngine(db.DefaultContext)) + return pr.loadHeadRepo(db.DefaultContext) } // LoadBaseRepo loads the target repository func (pr *PullRequest) LoadBaseRepo() error { - return pr.loadBaseRepo(db.GetEngine(db.DefaultContext)) + return pr.loadBaseRepo(db.DefaultContext) } -func (pr *PullRequest) loadBaseRepo(e db.Engine) (err error) { +func (pr *PullRequest) loadBaseRepo(ctx context.Context) (err error) { if pr.BaseRepo != nil { return nil } @@ -174,9 +176,9 @@ func (pr *PullRequest) loadBaseRepo(e db.Engine) (err error) { return nil } - pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID) + pr.BaseRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.BaseRepoID) if err != nil { - return fmt.Errorf("GetRepositoryByID(base): %v", err) + return fmt.Errorf("repo_model.GetRepositoryByID(base): %v", err) } return nil } @@ -200,21 +202,21 @@ func (pr *PullRequest) loadIssue(e db.Engine) (err error) { // LoadProtectedBranch loads the protected branch of the base branch func (pr *PullRequest) LoadProtectedBranch() (err error) { - return pr.loadProtectedBranch(db.GetEngine(db.DefaultContext)) + return pr.loadProtectedBranch(db.DefaultContext) } -func (pr *PullRequest) loadProtectedBranch(e db.Engine) (err error) { +func (pr *PullRequest) loadProtectedBranch(ctx context.Context) (err error) { if pr.ProtectedBranch == nil { if pr.BaseRepo == nil { if pr.BaseRepoID == 0 { return nil } - pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID) + pr.BaseRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.BaseRepoID) if err != nil { return } } - pr.ProtectedBranch, err = getProtectedBranchBy(e, pr.BaseRepo.ID, pr.BaseBranch) + pr.ProtectedBranch, err = getProtectedBranchBy(db.GetEngine(ctx), pr.BaseRepo.ID, pr.BaseBranch) } return } @@ -223,7 +225,7 @@ func (pr *PullRequest) loadProtectedBranch(e db.Engine) (err error) { func (pr *PullRequest) GetDefaultMergeMessage() string { if pr.HeadRepo == nil { var err error - pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID) + pr.HeadRepo, err = repo_model.GetRepositoryByID(pr.HeadRepoID) if err != nil { log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err) return "" @@ -368,24 +370,6 @@ func (pr *PullRequest) IsEmpty() bool { return pr.Status == PullRequestStatusEmpty } -// MergeStyle represents the approach to merge commits into base branch. -type MergeStyle string - -const ( - // MergeStyleMerge create merge commit - MergeStyleMerge MergeStyle = "merge" - // MergeStyleRebase rebase before merging - MergeStyleRebase MergeStyle = "rebase" - // MergeStyleRebaseMerge rebase before merging with merge commit (--no-ff) - MergeStyleRebaseMerge MergeStyle = "rebase-merge" - // MergeStyleSquash squash commits into single commit before merging - MergeStyleSquash MergeStyle = "squash" - // MergeStyleManuallyMerged pr has been merged manually, just mark it as merged directly - MergeStyleManuallyMerged MergeStyle = "manually-merged" - // MergeStyleRebaseUpdate not a merge style, used to update pull head by rebase - MergeStyleRebaseUpdate MergeStyle = "rebase-update-only" -) - // SetMerged sets a pull request to merged and closes the corresponding issue func (pr *PullRequest) SetMerged() (bool, error) { if pr.HasMerged { @@ -428,11 +412,11 @@ func (pr *PullRequest) SetMerged() (bool, error) { return false, fmt.Errorf("PullRequest[%d] already closed", pr.Index) } - if err := pr.Issue.loadRepo(sess); err != nil { + if err := pr.Issue.loadRepo(ctx); err != nil { return false, err } - if err := pr.Issue.Repo.getOwner(sess); err != nil { + if err := pr.Issue.Repo.GetOwner(ctx); err != nil { return false, err } @@ -452,7 +436,7 @@ func (pr *PullRequest) SetMerged() (bool, error) { } // NewPullRequest creates new pull request with labels for repository. -func NewPullRequest(repo *Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) { +func NewPullRequest(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) { idx, err := db.GetNextResourceIndex("issue_index", repo.ID) if err != nil { return fmt.Errorf("generate pull request index failed: %v", err) diff --git a/models/pull_test.go b/models/pull_test.go index 2281dbffda..f5e9d486ff 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -258,15 +259,15 @@ func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) { func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - externalTracker := RepoUnit{ + externalTracker := repo_model.RepoUnit{ Type: unit.TypeExternalTracker, - Config: &ExternalTrackerConfig{ + Config: &repo_model.ExternalTrackerConfig{ ExternalTrackerFormat: "https://someurl.com/{user}/{repo}/{issue}", }, } - baseRepo := &Repository{Name: "testRepo", ID: 1} + baseRepo := &repo_model.Repository{Name: "testRepo", ID: 1} baseRepo.Owner = &user_model.User{Name: "testOwner"} - baseRepo.Units = []*RepoUnit{&externalTracker} + baseRepo.Units = []*repo_model.RepoUnit{&externalTracker} pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2, BaseRepo: baseRepo}).(*PullRequest) diff --git a/models/release.go b/models/release.go index f60024c710..a19d4f937f 100644 --- a/models/release.go +++ b/models/release.go @@ -25,12 +25,12 @@ import ( // Release represents a release of repository. type Release struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(n)"` - Repo *Repository `xorm:"-"` - PublisherID int64 `xorm:"INDEX"` - Publisher *user_model.User `xorm:"-"` - TagName string `xorm:"INDEX UNIQUE(n)"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(n)"` + Repo *repo_model.Repository `xorm:"-"` + PublisherID int64 `xorm:"INDEX"` + Publisher *user_model.User `xorm:"-"` + TagName string `xorm:"INDEX UNIQUE(n)"` OriginalAuthor string OriginalAuthorID int64 `xorm:"index"` LowerTagName string @@ -55,7 +55,7 @@ func init() { func (r *Release) loadAttributes(e db.Engine) error { var err error if r.Repo == nil { - r.Repo, err = GetRepositoryByID(r.RepoID) + r.Repo, err = repo_model.GetRepositoryByID(r.RepoID) if err != nil { return err } diff --git a/models/repo.go b/models/repo.go index 4f6b1c3464..6bdc4c20d2 100644 --- a/models/repo.go +++ b/models/repo.go @@ -7,11 +7,7 @@ package models import ( "context" - "errors" "fmt" - "html/template" - "net" - "net/url" "os" "path" "path/filepath" @@ -32,23 +28,16 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) var ( - // ErrMirrorNotExist mirror does not exist error - ErrMirrorNotExist = errors.New("Mirror does not exist") -) - -var ( // Gitignores contains the gitiginore files Gitignores []string @@ -137,241 +126,16 @@ func NewRepoContext() { admin_model.RemoveAllWithNotice(db.DefaultContext, "Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) } -// RepositoryStatus defines the status of repository -type RepositoryStatus int - -// all kinds of RepositoryStatus -const ( - RepositoryReady RepositoryStatus = iota // a normal repository - RepositoryBeingMigrated // repository is migrating - RepositoryPendingTransfer // repository pending in ownership transfer state - RepositoryBroken // repository is in a permanently broken state -) - -// TrustModelType defines the types of trust model for this repository -type TrustModelType int - -// kinds of TrustModel -const ( - DefaultTrustModel TrustModelType = iota // default trust model - CommitterTrustModel - CollaboratorTrustModel - CollaboratorCommitterTrustModel -) - -// String converts a TrustModelType to a string -func (t TrustModelType) String() string { - switch t { - case DefaultTrustModel: - return "default" - case CommitterTrustModel: - return "committer" - case CollaboratorTrustModel: - return "collaborator" - case CollaboratorCommitterTrustModel: - return "collaboratorcommitter" - } - return "default" -} - -// ToTrustModel converts a string to a TrustModelType -func ToTrustModel(model string) TrustModelType { - switch strings.ToLower(strings.TrimSpace(model)) { - case "default": - return DefaultTrustModel - case "collaborator": - return CollaboratorTrustModel - case "committer": - return CommitterTrustModel - case "collaboratorcommitter": - return CollaboratorCommitterTrustModel - } - return DefaultTrustModel -} - -// Repository represents a git repository. -type Repository struct { - ID int64 `xorm:"pk autoincr"` - OwnerID int64 `xorm:"UNIQUE(s) index"` - OwnerName string - Owner *user_model.User `xorm:"-"` - LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` - Name string `xorm:"INDEX NOT NULL"` - Description string `xorm:"TEXT"` - Website string `xorm:"VARCHAR(2048)"` - OriginalServiceType api.GitServiceType `xorm:"index"` - OriginalURL string `xorm:"VARCHAR(2048)"` - DefaultBranch string - - NumWatches int - NumStars int - NumForks int - NumIssues int - NumClosedIssues int - NumOpenIssues int `xorm:"-"` - NumPulls int - NumClosedPulls int - NumOpenPulls int `xorm:"-"` - NumMilestones int `xorm:"NOT NULL DEFAULT 0"` - NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0"` - NumOpenMilestones int `xorm:"-"` - NumProjects int `xorm:"NOT NULL DEFAULT 0"` - NumClosedProjects int `xorm:"NOT NULL DEFAULT 0"` - NumOpenProjects int `xorm:"-"` - - IsPrivate bool `xorm:"INDEX"` - IsEmpty bool `xorm:"INDEX"` - IsArchived bool `xorm:"INDEX"` - IsMirror bool `xorm:"INDEX"` - *Mirror `xorm:"-"` - PushMirrors []*PushMirror `xorm:"-"` - Status RepositoryStatus `xorm:"NOT NULL DEFAULT 0"` - - RenderingMetas map[string]string `xorm:"-"` - DocumentRenderingMetas map[string]string `xorm:"-"` - Units []*RepoUnit `xorm:"-"` - PrimaryLanguage *LanguageStat `xorm:"-"` - - IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"` - ForkID int64 `xorm:"INDEX"` - BaseRepo *Repository `xorm:"-"` - IsTemplate bool `xorm:"INDEX NOT NULL DEFAULT false"` - TemplateID int64 `xorm:"INDEX"` - TemplateRepo *Repository `xorm:"-"` - Size int64 `xorm:"NOT NULL DEFAULT 0"` - CodeIndexerStatus *RepoIndexerStatus `xorm:"-"` - StatsIndexerStatus *RepoIndexerStatus `xorm:"-"` - IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"` - CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"` - Topics []string `xorm:"TEXT JSON"` - - TrustModel TrustModelType - - // Avatar: ID(10-20)-md5(32) - must fit into 64 symbols - Avatar string `xorm:"VARCHAR(64)"` - - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` -} - -func init() { - db.RegisterModel(new(Repository)) -} - -// SanitizedOriginalURL returns a sanitized OriginalURL -func (repo *Repository) SanitizedOriginalURL() string { - if repo.OriginalURL == "" { - return "" - } - u, err := url.Parse(repo.OriginalURL) - if err != nil { - return "" - } - u.User = nil - return u.String() -} - -// ColorFormat returns a colored string to represent this repo -func (repo *Repository) ColorFormat(s fmt.State) { - log.ColorFprintf(s, "%d:%s/%s", - log.NewColoredIDValue(repo.ID), - repo.OwnerName, - repo.Name) -} - -// IsBeingMigrated indicates that repository is being migrated -func (repo *Repository) IsBeingMigrated() bool { - return repo.Status == RepositoryBeingMigrated -} - -// IsBeingCreated indicates that repository is being migrated or forked -func (repo *Repository) IsBeingCreated() bool { - return repo.IsBeingMigrated() -} - -// IsBroken indicates that repository is broken -func (repo *Repository) IsBroken() bool { - return repo.Status == RepositoryBroken -} - -// AfterLoad is invoked from XORM after setting the values of all fields of this object. -func (repo *Repository) AfterLoad() { - // FIXME: use models migration to solve all at once. - if len(repo.DefaultBranch) == 0 { - repo.DefaultBranch = setting.Repository.DefaultBranch - } - - repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues - repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls - repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones - repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects -} - -// MustOwner always returns a valid *user_model.User object to avoid -// conceptually impossible error handling. -// It creates a fake object that contains error details -// when error occurs. -func (repo *Repository) MustOwner() *user_model.User { - return repo.mustOwner(db.GetEngine(db.DefaultContext)) -} - -// FullName returns the repository full name -func (repo *Repository) FullName() string { - return repo.OwnerName + "/" + repo.Name -} - -// HTMLURL returns the repository HTML URL -func (repo *Repository) HTMLURL() string { - return setting.AppURL + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) +// CheckRepoUnitUser check whether user could visit the unit of this repository +func CheckRepoUnitUser(repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { + return checkRepoUnitUser(db.DefaultContext, repo, user, unitType) } -// CommitLink make link to by commit full ID -// note: won't check whether it's an right id -func (repo *Repository) CommitLink(commitID string) (result string) { - if commitID == "" || commitID == "0000000000000000000000000000000000000000" { - result = "" - } else { - result = repo.HTMLURL() + "/commit/" + url.PathEscape(commitID) - } - return -} - -// APIURL returns the repository API URL -func (repo *Repository) APIURL() string { - return setting.AppURL + "api/v1/repos/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) -} - -// GetCommitsCountCacheKey returns cache key used for commits count caching. -func (repo *Repository) GetCommitsCountCacheKey(contextName string, isRef bool) string { - var prefix string - if isRef { - prefix = "ref" - } else { - prefix = "commit" - } - return fmt.Sprintf("commits-count-%d-%s-%s", repo.ID, prefix, contextName) -} - -func (repo *Repository) getUnits(e db.Engine) (err error) { - if repo.Units != nil { - return nil - } - - repo.Units, err = getUnitsByRepoID(e, repo.ID) - log.Trace("repo.Units: %-+v", repo.Units) - return err -} - -// CheckUnitUser check whether user could visit the unit of this repository -func (repo *Repository) CheckUnitUser(user *user_model.User, unitType unit.Type) bool { - return repo.checkUnitUser(db.GetEngine(db.DefaultContext), user, unitType) -} - -func (repo *Repository) checkUnitUser(e db.Engine, user *user_model.User, unitType unit.Type) bool { +func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { if user.IsAdmin { return true } - perm, err := getUserRepoPermission(e, repo, user) + perm, err := getUserRepoPermission(ctx, repo, user) if err != nil { log.Error("getUserRepoPermission(): %v", err) return false @@ -380,167 +144,12 @@ func (repo *Repository) checkUnitUser(e db.Engine, user *user_model.User, unitTy return perm.CanRead(unitType) } -// UnitEnabled if this repository has the given unit enabled -func (repo *Repository) UnitEnabled(tp unit.Type) bool { - if err := repo.getUnits(db.GetEngine(db.DefaultContext)); err != nil { - log.Warn("Error loading repository (ID: %d) units: %s", repo.ID, err.Error()) - } - for _, unit := range repo.Units { - if unit.Type == tp { - return true - } - } - return false -} - -// ErrUnitTypeNotExist represents a "UnitTypeNotExist" kind of error. -type ErrUnitTypeNotExist struct { - UT unit.Type -} - -// IsErrUnitTypeNotExist checks if an error is a ErrUnitNotExist. -func IsErrUnitTypeNotExist(err error) bool { - _, ok := err.(ErrUnitTypeNotExist) - return ok -} - -func (err ErrUnitTypeNotExist) Error() string { - return fmt.Sprintf("Unit type does not exist: %s", err.UT.String()) -} - -// MustGetUnit always returns a RepoUnit object -func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit { - ru, err := repo.GetUnit(tp) - if err == nil { - return ru - } - - if tp == unit.TypeExternalWiki { - return &RepoUnit{ - Type: tp, - Config: new(ExternalWikiConfig), - } - } else if tp == unit.TypeExternalTracker { - return &RepoUnit{ - Type: tp, - Config: new(ExternalTrackerConfig), - } - } else if tp == unit.TypePullRequests { - return &RepoUnit{ - Type: tp, - Config: new(PullRequestsConfig), - } - } else if tp == unit.TypeIssues { - return &RepoUnit{ - Type: tp, - Config: new(IssuesConfig), - } - } - return &RepoUnit{ - Type: tp, - Config: new(UnitConfig), - } -} - -// GetUnit returns a RepoUnit object -func (repo *Repository) GetUnit(tp unit.Type) (*RepoUnit, error) { - return repo.getUnit(db.GetEngine(db.DefaultContext), tp) -} - -func (repo *Repository) getUnit(e db.Engine, tp unit.Type) (*RepoUnit, error) { - if err := repo.getUnits(e); err != nil { - return nil, err - } - for _, unit := range repo.Units { - if unit.Type == tp { - return unit, nil - } - } - return nil, ErrUnitTypeNotExist{tp} -} - -func (repo *Repository) getOwner(e db.Engine) (err error) { - if repo.Owner != nil { - return nil - } - - repo.Owner, err = user_model.GetUserByIDEngine(e, repo.OwnerID) - return err -} - -// GetOwner returns the repository owner -func (repo *Repository) GetOwner() error { - return repo.getOwner(db.GetEngine(db.DefaultContext)) -} - -func (repo *Repository) mustOwner(e db.Engine) *user_model.User { - if err := repo.getOwner(e); err != nil { - return &user_model.User{ - Name: "error", - FullName: err.Error(), - } - } - - return repo.Owner -} - -// ComposeMetas composes a map of metas for properly rendering issue links and external issue trackers. -func (repo *Repository) ComposeMetas() map[string]string { - if len(repo.RenderingMetas) == 0 { - metas := map[string]string{ - "user": repo.OwnerName, - "repo": repo.Name, - "repoPath": repo.RepoPath(), - "mode": "comment", - } - - unit, err := repo.GetUnit(unit.TypeExternalTracker) - if err == nil { - metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat - switch unit.ExternalTrackerConfig().ExternalTrackerStyle { - case markup.IssueNameStyleAlphanumeric: - metas["style"] = markup.IssueNameStyleAlphanumeric - default: - metas["style"] = markup.IssueNameStyleNumeric - } - } - - repo.MustOwner() - if repo.Owner.IsOrganization() { - teams := make([]string, 0, 5) - _ = db.GetEngine(db.DefaultContext).Table("team_repo"). - Join("INNER", "team", "team.id = team_repo.team_id"). - Where("team_repo.repo_id = ?", repo.ID). - Select("team.lower_name"). - OrderBy("team.lower_name"). - Find(&teams) - metas["teams"] = "," + strings.Join(teams, ",") + "," - metas["org"] = strings.ToLower(repo.OwnerName) - } - - repo.RenderingMetas = metas - } - return repo.RenderingMetas -} - -// ComposeDocumentMetas composes a map of metas for properly rendering documents -func (repo *Repository) ComposeDocumentMetas() map[string]string { - if len(repo.DocumentRenderingMetas) == 0 { - metas := map[string]string{} - for k, v := range repo.ComposeMetas() { - metas[k] = v - } - metas["mode"] = "document" - repo.DocumentRenderingMetas = metas - } - return repo.DocumentRenderingMetas -} - -func (repo *Repository) getAssignees(e db.Engine) (_ []*user_model.User, err error) { - if err = repo.getOwner(e); err != nil { +func getRepoAssignees(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) { + if err = repo.GetOwner(ctx); err != nil { return nil, err } + e := db.GetEngine(ctx) accesses := make([]*Access, 0, 10) if err = e. Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite). @@ -568,19 +177,20 @@ func (repo *Repository) getAssignees(e db.Engine) (_ []*user_model.User, err err return users, nil } -// GetAssignees returns all users that have write access and can be assigned to issues +// GetRepoAssignees returns all users that have write access and can be assigned to issues // of the repository, -func (repo *Repository) GetAssignees() (_ []*user_model.User, err error) { - return repo.getAssignees(db.GetEngine(db.DefaultContext)) +func GetRepoAssignees(repo *repo_model.Repository) (_ []*user_model.User, err error) { + return getRepoAssignees(db.DefaultContext, repo) } -func (repo *Repository) getReviewers(e db.Engine, doerID, posterID int64) ([]*user_model.User, error) { +func getReviewers(ctx context.Context, repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) { // Get the owner of the repository - this often already pre-cached and if so saves complexity for the following queries - if err := repo.getOwner(e); err != nil { + if err := repo.GetOwner(ctx); err != nil { return nil, err } var users []*user_model.User + e := db.GetEngine(ctx) if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate { // This a private repository: @@ -622,13 +232,13 @@ func (repo *Repository) getReviewers(e db.Engine, doerID, posterID int64) ([]*us // * for public repositories this returns all users that have read access or higher to the repository, // all repo watchers and all organization members. // TODO: may be we should have a busy choice for users to block review request to them. -func (repo *Repository) GetReviewers(doerID, posterID int64) ([]*user_model.User, error) { - return repo.getReviewers(db.GetEngine(db.DefaultContext), doerID, posterID) +func GetReviewers(repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) { + return getReviewers(db.DefaultContext, repo, doerID, posterID) } // GetReviewerTeams get all teams can be requested to review -func (repo *Repository) GetReviewerTeams() ([]*Team, error) { - if err := repo.GetOwner(); err != nil { +func GetReviewerTeams(repo *repo_model.Repository) ([]*Team, error) { + if err := repo.GetOwner(db.DefaultContext); err != nil { return nil, err } if !repo.Owner.IsOrganization() { @@ -643,102 +253,7 @@ func (repo *Repository) GetReviewerTeams() ([]*Team, error) { return teams, err } -// GetMilestoneByID returns the milestone belongs to repository by given ID. -func (repo *Repository) GetMilestoneByID(milestoneID int64) (*Milestone, error) { - return GetMilestoneByRepoID(repo.ID, milestoneID) -} - -// IssueStats returns number of open and closed repository issues by given filter mode. -func (repo *Repository) IssueStats(uid int64, filterMode int, isPull bool) (int64, int64) { - return GetRepoIssueStats(repo.ID, uid, filterMode, isPull) -} - -// GetMirror sets the repository mirror, returns an error upon failure -func (repo *Repository) GetMirror() (err error) { - repo.Mirror, err = GetMirrorByRepoID(repo.ID) - return err -} - -// LoadPushMirrors populates the repository push mirrors. -func (repo *Repository) LoadPushMirrors() (err error) { - repo.PushMirrors, err = GetPushMirrorsByRepoID(repo.ID) - return err -} - -// GetBaseRepo populates repo.BaseRepo for a fork repository and -// returns an error on failure (NOTE: no error is returned for -// non-fork repositories, and BaseRepo will be left untouched) -func (repo *Repository) GetBaseRepo() (err error) { - return repo.getBaseRepo(db.GetEngine(db.DefaultContext)) -} - -func (repo *Repository) getBaseRepo(e db.Engine) (err error) { - if !repo.IsFork { - return nil - } - - repo.BaseRepo, err = getRepositoryByID(e, repo.ForkID) - return err -} - -// IsGenerated returns whether _this_ repository was generated from a template -func (repo *Repository) IsGenerated() bool { - return repo.TemplateID != 0 -} - -// GetTemplateRepo populates repo.TemplateRepo for a generated repository and -// returns an error on failure (NOTE: no error is returned for -// non-generated repositories, and TemplateRepo will be left untouched) -func (repo *Repository) GetTemplateRepo() (err error) { - return repo.getTemplateRepo(db.GetEngine(db.DefaultContext)) -} - -func (repo *Repository) getTemplateRepo(e db.Engine) (err error) { - if !repo.IsGenerated() { - return nil - } - - repo.TemplateRepo, err = getRepositoryByID(e, repo.TemplateID) - return err -} - -// RepoPath returns the repository path -func (repo *Repository) RepoPath() string { - return RepoPath(repo.OwnerName, repo.Name) -} - -// GitConfigPath returns the path to a repository's git config/ directory -func GitConfigPath(repoPath string) string { - return filepath.Join(repoPath, "config") -} - -// GitConfigPath returns the repository git config path -func (repo *Repository) GitConfigPath() string { - return GitConfigPath(repo.RepoPath()) -} - -// Link returns the repository link -func (repo *Repository) Link() string { - return setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) -} - -// ComposeCompareURL returns the repository comparison URL -func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) string { - return fmt.Sprintf("%s/%s/compare/%s...%s", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), util.PathEscapeSegments(oldCommitID), util.PathEscapeSegments(newCommitID)) -} - -// UpdateDefaultBranch updates the default branch -func (repo *Repository) UpdateDefaultBranch() error { - _, err := db.GetEngine(db.DefaultContext).ID(repo.ID).Cols("default_branch").Update(repo) - return err -} - -// IsOwnedBy returns true when user owns this repository -func (repo *Repository) IsOwnedBy(userID int64) bool { - return repo.OwnerID == userID -} - -func (repo *Repository) updateSize(e db.Engine) error { +func updateRepoSize(e db.Engine, repo *repo_model.Repository) error { size, err := util.GetDirectorySize(repo.RepoPath()) if err != nil { return fmt.Errorf("updateSize: %v", err) @@ -754,13 +269,13 @@ func (repo *Repository) updateSize(e db.Engine) error { return err } -// UpdateSize updates the repository size, calculating it using util.GetDirectorySize -func (repo *Repository) UpdateSize(ctx context.Context) error { - return repo.updateSize(db.GetEngine(ctx)) +// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize +func UpdateRepoSize(ctx context.Context, repo *repo_model.Repository) error { + return updateRepoSize(db.GetEngine(ctx), repo) } // CanUserForkRepo returns true if specified user can fork repository. -func CanUserForkRepo(user *user_model.User, repo *Repository) (bool, error) { +func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool, error) { if user == nil { return false, nil } @@ -780,12 +295,12 @@ func CanUserForkRepo(user *user_model.User, repo *Repository) (bool, error) { } // CanUserDelete returns true if user could delete the repository -func (repo *Repository) CanUserDelete(user *user_model.User) (bool, error) { +func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, error) { if user.IsAdmin || user.ID == repo.OwnerID { return true, nil } - if err := repo.GetOwner(); err != nil { + if err := repo.GetOwner(db.DefaultContext); err != nil { return false, err } @@ -801,33 +316,18 @@ func (repo *Repository) CanUserDelete(user *user_model.User) (bool, error) { return false, nil } -// CanEnablePulls returns true if repository meets the requirements of accepting pulls. -func (repo *Repository) CanEnablePulls() bool { - return !repo.IsMirror && !repo.IsEmpty +// GetRepoReaders returns all users that have explicit read access or higher to the repository. +func GetRepoReaders(repo *repo_model.Repository) (_ []*user_model.User, err error) { + return getUsersWithAccessMode(db.DefaultContext, repo, perm.AccessModeRead) } -// AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled. -func (repo *Repository) AllowsPulls() bool { - return repo.CanEnablePulls() && repo.UnitEnabled(unit.TypePullRequests) +// GetRepoWriters returns all users that have write access to the repository. +func GetRepoWriters(repo *repo_model.Repository) (_ []*user_model.User, err error) { + return getUsersWithAccessMode(db.DefaultContext, repo, perm.AccessModeWrite) } -// CanEnableEditor returns true if repository meets the requirements of web editor. -func (repo *Repository) CanEnableEditor() bool { - return !repo.IsMirror -} - -// GetReaders returns all users that have explicit read access or higher to the repository. -func (repo *Repository) GetReaders() (_ []*user_model.User, err error) { - return repo.getUsersWithAccessMode(db.GetEngine(db.DefaultContext), perm.AccessModeRead) -} - -// GetWriters returns all users that have write access to the repository. -func (repo *Repository) GetWriters() (_ []*user_model.User, err error) { - return repo.getUsersWithAccessMode(db.GetEngine(db.DefaultContext), perm.AccessModeWrite) -} - -// IsReader returns true if user has explicit read access or higher to the repository. -func (repo *Repository) IsReader(userID int64) (bool, error) { +// IsRepoReader returns true if user has explicit read access or higher to the repository. +func IsRepoReader(repo *repo_model.Repository, userID int64) (bool, error) { if repo.OwnerID == userID { return true, nil } @@ -835,11 +335,12 @@ func (repo *Repository) IsReader(userID int64) (bool, error) { } // getUsersWithAccessMode returns users that have at least given access mode to the repository. -func (repo *Repository) getUsersWithAccessMode(e db.Engine, mode perm.AccessMode) (_ []*user_model.User, err error) { - if err = repo.getOwner(e); err != nil { +func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode) (_ []*user_model.User, err error) { + if err = repo.GetOwner(ctx); err != nil { return nil, err } + e := db.GetEngine(ctx) accesses := make([]*Access, 0, 10) if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil { return nil, err @@ -865,88 +366,9 @@ func (repo *Repository) getUsersWithAccessMode(e db.Engine, mode perm.AccessMode return users, nil } -// DescriptionHTML does special handles to description and return HTML string. -func (repo *Repository) DescriptionHTML() template.HTML { - desc, err := markup.RenderDescriptionHTML(&markup.RenderContext{ - URLPrefix: repo.HTMLURL(), - Metas: repo.ComposeMetas(), - }, repo.Description) - if err != nil { - log.Error("Failed to render description for %s (ID: %d): %v", repo.Name, repo.ID, err) - return template.HTML(markup.Sanitize(repo.Description)) - } - return template.HTML(markup.Sanitize(string(desc))) -} - -// ReadBy sets repo to be visited by given user. -func (repo *Repository) ReadBy(userID int64) error { - return setRepoNotificationStatusReadIfUnread(db.GetEngine(db.DefaultContext), userID, repo.ID) -} - -func isRepositoryExist(e db.Engine, u *user_model.User, repoName string) (bool, error) { - has, err := e.Get(&Repository{ - OwnerID: u.ID, - LowerName: strings.ToLower(repoName), - }) - if err != nil { - return false, err - } - isDir, err := util.IsDir(RepoPath(u.Name, repoName)) - return has && isDir, err -} - -// IsRepositoryExist returns true if the repository with given name under user has already existed. -func IsRepositoryExist(u *user_model.User, repoName string) (bool, error) { - return isRepositoryExist(db.GetEngine(db.DefaultContext), u, repoName) -} - -// CloneLink represents different types of clone URLs of repository. -type CloneLink struct { - SSH string - HTTPS string - Git string -} - -// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name. -func ComposeHTTPSCloneURL(owner, repo string) string { - return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.PathEscape(owner), url.PathEscape(repo)) -} - -func (repo *Repository) cloneLink(isWiki bool) *CloneLink { - repoName := repo.Name - if isWiki { - repoName += ".wiki" - } - - sshUser := setting.RunUser - if setting.SSH.StartBuiltinServer { - sshUser = setting.SSH.BuiltinServerUser - } - - cl := new(CloneLink) - - // if we have a ipv6 literal we need to put brackets around it - // for the git cloning to work. - sshDomain := setting.SSH.Domain - ip := net.ParseIP(setting.SSH.Domain) - if ip != nil && ip.To4() == nil { - sshDomain = "[" + setting.SSH.Domain + "]" - } - - if setting.SSH.Port != 22 { - cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) - } else if setting.Repository.UseCompatSSHURI { - cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) - } else { - cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) - } - cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName) - return cl -} - -// CloneLink returns clone URLs of repository. -func (repo *Repository) CloneLink() (cl *CloneLink) { - return repo.cloneLink(false) +// SetRepoReadBy sets repo to be visited by given user. +func SetRepoReadBy(repoID, userID int64) error { + return setRepoNotificationStatusReadIfUnread(db.GetEngine(db.DefaultContext), userID, repoID) } // CheckCreateRepository check if could created a repository @@ -959,16 +381,17 @@ func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdo return err } - has, err := isRepositoryExist(db.GetEngine(db.DefaultContext), u, name) + has, err := repo_model.IsRepositoryExist(u, name) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { return ErrRepoAlreadyExist{u.Name, name} } - isExist, err := util.IsExist(RepoPath(u.Name, name)) + repoPath := repo_model.RepoPath(u.Name, name) + isExist, err := util.IsExist(repoPath) if err != nil { - log.Error("Unable to check if %s exists. Error: %v", RepoPath(u.Name, name), err) + log.Error("Unable to check if %s exists. Error: %v", repoPath, err) return err } if !overwriteOrAdopt && isExist { @@ -992,14 +415,14 @@ type CreateRepoOptions struct { IsMirror bool IsTemplate bool AutoInit bool - Status RepositoryStatus - TrustModel TrustModelType + Status repo_model.RepositoryStatus + TrustModel repo_model.TrustModelType MirrorInterval string } // ForkRepoOptions contains the fork repository options type ForkRepoOptions struct { - BaseRepo *Repository + BaseRepo *repo_model.Repository Name string Description string } @@ -1048,19 +471,19 @@ func IsUsableRepoName(name string) error { } // CreateRepository creates a repository for the user/organization. -func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *Repository, overwriteOrAdopt bool) (err error) { +func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository, overwriteOrAdopt bool) (err error) { if err = IsUsableRepoName(repo.Name); err != nil { return err } - has, err := isRepositoryExist(db.GetEngine(ctx), u, repo.Name) + has, err := repo_model.IsRepositoryExistCtx(ctx, u, repo.Name) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { return ErrRepoAlreadyExist{u.Name, repo.Name} } - repoPath := RepoPath(u.Name, repo.Name) + repoPath := repo_model.RepoPath(u.Name, repo.Name) isExist, err := util.IsExist(repoPath) if err != nil { log.Error("Unable to check if %s exists. Error: %v", repoPath, err) @@ -1074,7 +497,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *Repos } } - if _, err = db.GetEngine(ctx).Insert(repo); err != nil { + if err = db.Insert(ctx, repo); err != nil { return err } if err = deleteRepoRedirect(db.GetEngine(ctx), u.ID, repo.Name); err != nil { @@ -1082,33 +505,33 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *Repos } // insert units for repo - units := make([]RepoUnit, 0, len(unit.DefaultRepoUnits)) + units := make([]repo_model.RepoUnit, 0, len(unit.DefaultRepoUnits)) for _, tp := range unit.DefaultRepoUnits { if tp == unit.TypeIssues { - units = append(units, RepoUnit{ + units = append(units, repo_model.RepoUnit{ RepoID: repo.ID, Type: tp, - Config: &IssuesConfig{ + Config: &repo_model.IssuesConfig{ EnableTimetracker: setting.Service.DefaultEnableTimetracking, AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime, EnableDependencies: setting.Service.DefaultEnableDependencies, }, }) } else if tp == unit.TypePullRequests { - units = append(units, RepoUnit{ + units = append(units, repo_model.RepoUnit{ RepoID: repo.ID, Type: tp, - Config: &PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, DefaultMergeStyle: MergeStyleMerge}, + Config: &repo_model.PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, DefaultMergeStyle: repo_model.MergeStyleMerge}, }) } else { - units = append(units, RepoUnit{ + units = append(units, repo_model.RepoUnit{ RepoID: repo.ID, Type: tp, }) } } - if _, err = db.GetEngine(ctx).Insert(&units); err != nil { + if err = db.Insert(ctx, units); err != nil { return err } @@ -1131,7 +554,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *Repos } for _, t := range teams { if t.IncludesAllRepositories { - if err := t.addRepository(db.GetEngine(ctx), repo); err != nil { + if err := t.addRepository(ctx, repo); err != nil { return fmt.Errorf("addRepository: %v", err) } } @@ -1141,14 +564,14 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *Repos return fmt.Errorf("isUserRepoAdmin: %v", err) } else if !isAdmin { // Make creator repo admin if it wan't assigned automatically - if err = repo.addCollaborator(db.GetEngine(ctx), doer); err != nil { + if err = addCollaborator(ctx, repo, doer); err != nil { return fmt.Errorf("AddCollaborator: %v", err) } - if err = repo.changeCollaborationAccessMode(db.GetEngine(ctx), doer.ID, perm.AccessModeAdmin); err != nil { + if err = changeCollaborationAccessMode(db.GetEngine(ctx), repo, doer.ID, perm.AccessModeAdmin); err != nil { return fmt.Errorf("ChangeCollaborationAccessMode: %v", err) } } - } else if err = repo.recalculateAccesses(db.GetEngine(ctx)); err != nil { + } else if err = recalculateAccesses(ctx, repo); err != nil { // Organization automatically called this in addRepository method. return fmt.Errorf("recalculateAccesses: %v", err) } @@ -1167,9 +590,8 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *Repos } // CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon... -func (repo *Repository) CheckDaemonExportOK(ctx context.Context) error { - e := db.GetEngine(ctx) - if err := repo.getOwner(e); err != nil { +func CheckDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error { + if err := repo.GetOwner(ctx); err != nil { return err } @@ -1198,42 +620,6 @@ func (repo *Repository) CheckDaemonExportOK(ctx context.Context) error { return nil } -func countRepositories(userID int64, private bool) int64 { - sess := db.GetEngine(db.DefaultContext).Where("id > 0") - - if userID > 0 { - sess.And("owner_id = ?", userID) - } - if !private { - sess.And("is_private=?", false) - } - - count, err := sess.Count(new(Repository)) - if err != nil { - log.Error("countRepositories: %v", err) - } - return count -} - -// CountRepositories returns number of repositories. -// Argument private only takes effect when it is false, -// set it true to count all repositories. -func CountRepositories(private bool) int64 { - return countRepositories(-1, private) -} - -// CountUserRepositories returns number of repositories user owns. -// Argument private only takes effect when it is false, -// set it true to count all repositories. -func CountUserRepositories(userID int64, private bool) int64 { - return countRepositories(userID, private) -} - -// RepoPath returns repository path by given user and repository name. -func RepoPath(userName, repoName string) string { - return filepath.Join(user_model.UserPath(userName), strings.ToLower(repoName)+".git") -} - // IncrementRepoForkNum increment repository fork number func IncrementRepoForkNum(ctx context.Context, repoID int64) error { _, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", repoID) @@ -1247,25 +633,25 @@ func DecrementRepoForkNum(ctx context.Context, repoID int64) error { } // ChangeRepositoryName changes all corresponding setting from old repository name to new one. -func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName string) (err error) { +func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, newRepoName string) (err error) { oldRepoName := repo.Name newRepoName = strings.ToLower(newRepoName) if err = IsUsableRepoName(newRepoName); err != nil { return err } - if err := repo.GetOwner(); err != nil { + if err := repo.GetOwner(db.DefaultContext); err != nil { return err } - has, err := IsRepositoryExist(repo.Owner, newRepoName) + has, err := repo_model.IsRepositoryExist(repo.Owner, newRepoName) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName} } - newRepoPath := RepoPath(repo.Owner.Name, newRepoName) + newRepoPath := repo_model.RepoPath(repo.Owner.Name, newRepoName) if err = util.Rename(repo.RepoPath(), newRepoPath); err != nil { return fmt.Errorf("rename repository directory: %v", err) } @@ -1277,7 +663,7 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s return err } if isExist { - if err = util.Rename(wikiPath, WikiPath(repo.Owner.Name, newRepoName)); err != nil { + if err = util.Rename(wikiPath, repo_model.WikiPath(repo.Owner.Name, newRepoName)); err != nil { return fmt.Errorf("rename repository wiki: %v", err) } } @@ -1295,19 +681,19 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s return committer.Commit() } -func getRepositoriesByForkID(e db.Engine, forkID int64) ([]*Repository, error) { - repos := make([]*Repository, 0, 10) +func getRepositoriesByForkID(e db.Engine, forkID int64) ([]*repo_model.Repository, error) { + repos := make([]*repo_model.Repository, 0, 10) return repos, e. Where("fork_id=?", forkID). Find(&repos) } // GetRepositoriesByForkID returns all repositories with given fork ID. -func GetRepositoriesByForkID(forkID int64) ([]*Repository, error) { +func GetRepositoriesByForkID(forkID int64) ([]*repo_model.Repository, error) { return getRepositoriesByForkID(db.GetEngine(db.DefaultContext), forkID) } -func updateRepository(e db.Engine, repo *Repository, visibilityChanged bool) (err error) { +func updateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) { repo.LowerName = strings.ToLower(repo.Name) if utf8.RuneCountInString(repo.Description) > 255 { @@ -1317,21 +703,23 @@ func updateRepository(e db.Engine, repo *Repository, visibilityChanged bool) (er repo.Website = string([]rune(repo.Website)[:255]) } + e := db.GetEngine(ctx) + if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil { return fmt.Errorf("update: %v", err) } - if err = repo.updateSize(e); err != nil { + if err = updateRepoSize(e, repo); err != nil { log.Error("Failed to update size for repository: %v", err) } if visibilityChanged { - if err = repo.getOwner(e); err != nil { + if err = repo.GetOwner(ctx); err != nil { return fmt.Errorf("getOwner: %v", err) } if repo.Owner.IsOrganization() { // Organization repository need to recalculate access table when visibility is changed. - if err = repo.recalculateTeamAccesses(e, 0); err != nil { + if err = recalculateTeamAccesses(ctx, repo, 0); err != nil { return fmt.Errorf("recalculateTeamAccesses: %v", err) } } @@ -1347,7 +735,7 @@ func updateRepository(e db.Engine, repo *Repository, visibilityChanged bool) (er } // Create/Remove git-daemon-export-ok for git-daemon... - if err := repo.CheckDaemonExportOK(db.WithEngine(db.DefaultContext, e)); err != nil { + if err := CheckDaemonExportOK(db.WithEngine(ctx, e), repo); err != nil { return err } @@ -1357,7 +745,7 @@ func updateRepository(e db.Engine, repo *Repository, visibilityChanged bool) (er } for i := range forkRepos { forkRepos[i].IsPrivate = repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate - if err = updateRepository(e, forkRepos[i], true); err != nil { + if err = updateRepository(ctx, forkRepos[i], true); err != nil { return fmt.Errorf("updateRepository[%d]: %v", forkRepos[i].ID, err) } } @@ -1367,19 +755,19 @@ func updateRepository(e db.Engine, repo *Repository, visibilityChanged bool) (er } // UpdateRepositoryCtx updates a repository with db context -func UpdateRepositoryCtx(ctx context.Context, repo *Repository, visibilityChanged bool) error { - return updateRepository(db.GetEngine(ctx), repo, visibilityChanged) +func UpdateRepositoryCtx(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) error { + return updateRepository(ctx, repo, visibilityChanged) } // UpdateRepository updates a repository -func UpdateRepository(repo *Repository, visibilityChanged bool) (err error) { +func UpdateRepository(repo *repo_model.Repository, visibilityChanged bool) (err error) { ctx, committer, err := db.TxContext() if err != nil { return err } defer committer.Close() - if err = updateRepository(db.GetEngine(ctx), repo, visibilityChanged); err != nil { + if err = updateRepository(ctx, repo, visibilityChanged); err != nil { return fmt.Errorf("updateRepository: %v", err) } @@ -1397,7 +785,7 @@ func UpdateRepositoryOwnerNames(ownerID int64, ownerName string) error { } defer committer.Close() - if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").Update(&Repository{ + if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").Update(&repo_model.Repository{ OwnerName: ownerName, }); err != nil { return err @@ -1413,7 +801,7 @@ func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error { } // UpdateRepositoryUnits updates a repository's units -func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []unit.Type) (err error) { +func UpdateRepositoryUnits(repo *repo_model.Repository, units []repo_model.RepoUnit, deleteUnitTypes []unit.Type) (err error) { ctx, committer, err := db.TxContext() if err != nil { return err @@ -1425,7 +813,7 @@ func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes [ deleteUnitTypes = append(deleteUnitTypes, u.Type) } - if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(RepoUnit)); err != nil { + if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil { return err } @@ -1454,12 +842,17 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { return err } - repo := &Repository{OwnerID: uid} + repo := &repo_model.Repository{OwnerID: uid} has, err := sess.ID(repoID).Get(repo) if err != nil { return err } else if !has { - return ErrRepoNotExist{repoID, uid, "", ""} + return repo_model.ErrRepoNotExist{ + ID: repoID, + UID: uid, + OwnerName: "", + Name: "", + } } // Delete Deploy Keys @@ -1468,15 +861,20 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { return fmt.Errorf("listDeployKeys: %v", err) } for _, dKey := range deployKeys { - if err := deleteDeployKey(sess, doer, dKey.ID); err != nil { + if err := deleteDeployKey(ctx, doer, dKey.ID); err != nil { return fmt.Errorf("deleteDeployKeys: %v", err) } } - if cnt, err := sess.ID(repoID).Delete(&Repository{}); err != nil { + if cnt, err := sess.ID(repoID).Delete(&repo_model.Repository{}); err != nil { return err } else if cnt != 1 { - return ErrRepoNotExist{repoID, uid, "", ""} + return repo_model.ErrRepoNotExist{ + ID: repoID, + UID: uid, + OwnerName: "", + Name: "", + } } if org.IsOrganization() { @@ -1487,7 +885,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { for _, t := range teams { if !t.hasRepository(sess, repoID) { continue - } else if err = t.removeRepository(sess, repo, false); err != nil { + } else if err = t.removeRepository(ctx, repo, false); err != nil { return err } } @@ -1517,18 +915,18 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { &DeletedBranch{RepoID: repoID}, &webhook.HookTask{RepoID: repoID}, &LFSLock{RepoID: repoID}, - &LanguageStat{RepoID: repoID}, + &repo_model.LanguageStat{RepoID: repoID}, &Milestone{RepoID: repoID}, - &Mirror{RepoID: repoID}, + &repo_model.Mirror{RepoID: repoID}, &Notification{RepoID: repoID}, &ProtectedBranch{RepoID: repoID}, &ProtectedTag{RepoID: repoID}, &PullRequest{BaseRepoID: repoID}, - &PushMirror{RepoID: repoID}, + &repo_model.PushMirror{RepoID: repoID}, &Release{RepoID: repoID}, - &RepoIndexerStatus{RepoID: repoID}, + &repo_model.RepoIndexerStatus{RepoID: repoID}, &RepoRedirect{RedirectRepoID: repoID}, - &RepoUnit{RepoID: repoID}, + &repo_model.RepoUnit{RepoID: repoID}, &Star{RepoID: repoID}, &Task{RepoID: repoID}, &Watch{RepoID: repoID}, @@ -1697,132 +1095,6 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { return nil } -// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. -func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) { - return getRepositoryByOwnerAndName(db.GetEngine(db.DefaultContext), ownerName, repoName) -} - -func getRepositoryByOwnerAndName(e db.Engine, ownerName, repoName string) (*Repository, error) { - var repo Repository - has, err := e.Table("repository").Select("repository.*"). - Join("INNER", "`user`", "`user`.id = repository.owner_id"). - Where("repository.lower_name = ?", strings.ToLower(repoName)). - And("`user`.lower_name = ?", strings.ToLower(ownerName)). - Get(&repo) - if err != nil { - return nil, err - } else if !has { - return nil, ErrRepoNotExist{0, 0, ownerName, repoName} - } - return &repo, nil -} - -// GetRepositoryByName returns the repository by given name under user if exists. -func GetRepositoryByName(ownerID int64, name string) (*Repository, error) { - repo := &Repository{ - OwnerID: ownerID, - LowerName: strings.ToLower(name), - } - has, err := db.GetEngine(db.DefaultContext).Get(repo) - if err != nil { - return nil, err - } else if !has { - return nil, ErrRepoNotExist{0, ownerID, "", name} - } - return repo, err -} - -func getRepositoryByID(e db.Engine, id int64) (*Repository, error) { - repo := new(Repository) - has, err := e.ID(id).Get(repo) - if err != nil { - return nil, err - } else if !has { - return nil, ErrRepoNotExist{id, 0, "", ""} - } - return repo, nil -} - -// GetRepositoryByID returns the repository by given id if exists. -func GetRepositoryByID(id int64) (*Repository, error) { - return getRepositoryByID(db.GetEngine(db.DefaultContext), id) -} - -// GetRepositoryByIDCtx returns the repository by given id if exists. -func GetRepositoryByIDCtx(ctx context.Context, id int64) (*Repository, error) { - return getRepositoryByID(db.GetEngine(ctx), id) -} - -// GetRepositoriesMapByIDs returns the repositories by given id slice. -func GetRepositoriesMapByIDs(ids []int64) (map[int64]*Repository, error) { - repos := make(map[int64]*Repository, len(ids)) - return repos, db.GetEngine(db.DefaultContext).In("id", ids).Find(&repos) -} - -// GetUserRepositories returns a list of repositories of given user. -func GetUserRepositories(opts *SearchRepoOptions) ([]*Repository, int64, error) { - if len(opts.OrderBy) == 0 { - opts.OrderBy = "updated_unix DESC" - } - - cond := builder.NewCond() - cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID}) - if !opts.Private { - cond = cond.And(builder.Eq{"is_private": false}) - } - - if opts.LowerNames != nil && len(opts.LowerNames) > 0 { - cond = cond.And(builder.In("lower_name", opts.LowerNames)) - } - - sess := db.GetEngine(db.DefaultContext) - - count, err := sess.Where(cond).Count(new(Repository)) - if err != nil { - return nil, 0, fmt.Errorf("Count: %v", err) - } - - sess = sess.Where(cond).OrderBy(opts.OrderBy.String()) - repos := make([]*Repository, 0, opts.PageSize) - return repos, count, db.SetSessionPagination(sess, opts).Find(&repos) -} - -// GetUserMirrorRepositories returns a list of mirror repositories of given user. -func GetUserMirrorRepositories(userID int64) ([]*Repository, error) { - repos := make([]*Repository, 0, 10) - return repos, db.GetEngine(db.DefaultContext). - Where("owner_id = ?", userID). - And("is_mirror = ?", true). - Find(&repos) -} - -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) -} - type repoChecker struct { querySQL, correctSQL string desc string @@ -1958,9 +1230,9 @@ func CheckRepoStats(ctx context.Context) error { } log.Trace("Updating repository count 'num_forks': %d", id) - repo, err := GetRepositoryByID(id) + repo, err := repo_model.GetRepositoryByID(id) if err != nil { - log.Error("GetRepositoryByID[%d]: %v", id, err) + log.Error("repo_model.GetRepositoryByID[%d]: %v", id, err) continue } @@ -1982,7 +1254,7 @@ func CheckRepoStats(ctx context.Context) error { } // SetArchiveRepoState sets if a repo is archived -func (repo *Repository) SetArchiveRepoState(isArchived bool) (err error) { +func SetArchiveRepoState(repo *repo_model.Repository, isArchived bool) (err error) { repo.IsArchived = isArchived _, err = db.GetEngine(db.DefaultContext).Where("id = ?", repo.ID).Cols("is_archived").NoAutoTime().Update(repo) return @@ -1996,8 +1268,8 @@ func (repo *Repository) SetArchiveRepoState(isArchived bool) (err error) { // \/ \/ // GetForkedRepo checks if given user has already forked a repository with given ID. -func GetForkedRepo(ownerID, repoID int64) *Repository { - repo := new(Repository) +func GetForkedRepo(ownerID, repoID int64) *repo_model.Repository { + repo := new(repo_model.Repository) has, _ := db.GetEngine(db.DefaultContext). Where("owner_id=? AND fork_id=?", ownerID, repoID). Get(repo) @@ -2016,40 +1288,22 @@ func HasForkedRepo(ownerID, repoID int64) bool { return has } -// CopyLFS copies LFS data from one repo to another -func CopyLFS(ctx context.Context, newRepo, oldRepo *Repository) error { - var lfsObjects []*LFSMetaObject - if err := db.GetEngine(ctx).Where("repository_id=?", oldRepo.ID).Find(&lfsObjects); err != nil { - return err - } - - for _, v := range lfsObjects { - v.ID = 0 - v.RepositoryID = newRepo.ID - if _, err := db.GetEngine(ctx).Insert(v); err != nil { - return err - } - } - - return nil -} - // GetForks returns all the forks of the repository -func (repo *Repository) GetForks(listOptions db.ListOptions) ([]*Repository, error) { +func GetForks(repo *repo_model.Repository, listOptions db.ListOptions) ([]*repo_model.Repository, error) { if listOptions.Page == 0 { - forks := make([]*Repository, 0, repo.NumForks) - return forks, db.GetEngine(db.DefaultContext).Find(&forks, &Repository{ForkID: repo.ID}) + forks := make([]*repo_model.Repository, 0, repo.NumForks) + return forks, db.GetEngine(db.DefaultContext).Find(&forks, &repo_model.Repository{ForkID: repo.ID}) } sess := db.GetPaginatedSession(&listOptions) - forks := make([]*Repository, 0, listOptions.PageSize) - return forks, sess.Find(&forks, &Repository{ForkID: repo.ID}) + forks := make([]*repo_model.Repository, 0, listOptions.PageSize) + return forks, sess.Find(&forks, &repo_model.Repository{ForkID: repo.ID}) } // GetUserFork return user forked repository from this repository, if not forked return nil -func (repo *Repository) GetUserFork(userID int64) (*Repository, error) { - var forkedRepo Repository - has, err := db.GetEngine(db.DefaultContext).Where("fork_id = ?", repo.ID).And("owner_id = ?", userID).Get(&forkedRepo) +func GetUserFork(repoID, userID int64) (*repo_model.Repository, error) { + var forkedRepo repo_model.Repository + has, err := db.GetEngine(db.DefaultContext).Where("fork_id = ?", repoID).And("owner_id = ?", userID).Get(&forkedRepo) if err != nil { return nil, err } @@ -2059,54 +1313,16 @@ func (repo *Repository) GetUserFork(userID int64) (*Repository, error) { return &forkedRepo, nil } -// GetOriginalURLHostname returns the hostname of a URL or the URL -func (repo *Repository) GetOriginalURLHostname() string { - u, err := url.Parse(repo.OriginalURL) - if err != nil { - return repo.OriginalURL - } - - return u.Host -} - -// GetTreePathLock returns LSF lock for the treePath -func (repo *Repository) GetTreePathLock(treePath string) (*LFSLock, error) { - if setting.LFS.StartServer { - locks, err := GetLFSLockByRepoID(repo.ID, 0, 0) - if err != nil { - return nil, err - } - for _, lock := range locks { - if lock.Path == treePath { - return lock, nil - } - } - } - return nil, nil -} - -func updateRepositoryCols(e db.Engine, repo *Repository, cols ...string) error { +func updateRepositoryCols(e db.Engine, repo *repo_model.Repository, cols ...string) error { _, err := e.ID(repo.ID).Cols(cols...).Update(repo) return err } // UpdateRepositoryCols updates repository's columns -func UpdateRepositoryCols(repo *Repository, cols ...string) error { +func UpdateRepositoryCols(repo *repo_model.Repository, cols ...string) error { return updateRepositoryCols(db.GetEngine(db.DefaultContext), repo, cols...) } -// GetTrustModel will get the TrustModel for the repo or the default trust model -func (repo *Repository) GetTrustModel() TrustModelType { - trustModel := repo.TrustModel - if trustModel == DefaultTrustModel { - trustModel = ToTrustModel(setting.Repository.Signing.DefaultTrustModel) - if trustModel == DefaultTrustModel { - return CollaboratorTrustModel - } - } - return trustModel -} - func updateUserStarNumbers(users []user_model.User) error { ctx, committer, err := db.TxContext() if err != nil { @@ -2147,11 +1363,11 @@ func DoctorUserStarNum() (err error) { } // IterateRepository iterate repositories -func IterateRepository(f func(repo *Repository) error) error { +func IterateRepository(f func(repo *repo_model.Repository) error) error { var start int batchSize := setting.Database.IterateBufferSize for { - repos := make([]*Repository, 0, batchSize) + repos := make([]*repo_model.Repository, 0, batchSize) if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil { return err } @@ -2169,13 +1385,13 @@ func IterateRepository(f func(repo *Repository) error) error { } // LinkedRepository returns the linked repo if any -func LinkedRepository(a *repo_model.Attachment) (*Repository, unit.Type, error) { +func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { if a.IssueID != 0 { iss, err := GetIssueByID(a.IssueID) if err != nil { return nil, unit.TypeIssues, err } - repo, err := GetRepositoryByID(iss.RepoID) + repo, err := repo_model.GetRepositoryByID(iss.RepoID) unitType := unit.TypeIssues if iss.IsPull { unitType = unit.TypePullRequests @@ -2186,7 +1402,7 @@ func LinkedRepository(a *repo_model.Attachment) (*Repository, unit.Type, error) if err != nil { return nil, unit.TypeReleases, err } - repo, err := GetRepositoryByID(rel.RepoID) + repo, err := repo_model.GetRepositoryByID(rel.RepoID) return repo, unit.TypeReleases, err } return nil, -1, nil diff --git a/models/repo/avatar.go b/models/repo/avatar.go new file mode 100644 index 0000000000..f11f868d63 --- /dev/null +++ b/models/repo/avatar.go @@ -0,0 +1,94 @@ +// 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 repo + +import ( + "fmt" + "image/png" + "io" + "net/url" + "strings" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/avatar" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" +) + +// CustomAvatarRelativePath returns repository custom avatar file path. +func (repo *Repository) CustomAvatarRelativePath() string { + return repo.Avatar +} + +// RelAvatarLink returns a relative link to the repository's avatar. +func (repo *Repository) RelAvatarLink() string { + return repo.relAvatarLink(db.GetEngine(db.DefaultContext)) +} + +// generateRandomAvatar generates a random avatar for repository. +func generateRandomAvatar(e db.Engine, repo *Repository) error { + idToString := fmt.Sprintf("%d", repo.ID) + + seed := idToString + img, err := avatar.RandomImage([]byte(seed)) + if err != nil { + return fmt.Errorf("RandomImage: %v", err) + } + + repo.Avatar = idToString + + if err := storage.SaveFrom(storage.RepoAvatars, repo.CustomAvatarRelativePath(), func(w io.Writer) error { + if err := png.Encode(w, img); err != nil { + log.Error("Encode: %v", err) + } + return err + }); err != nil { + return fmt.Errorf("Failed to create dir %s: %v", repo.CustomAvatarRelativePath(), err) + } + + log.Info("New random avatar created for repository: %d", repo.ID) + + if _, err := e.ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil { + return err + } + + return nil +} + +func (repo *Repository) relAvatarLink(e db.Engine) string { + // If no avatar - path is empty + avatarPath := repo.CustomAvatarRelativePath() + if len(avatarPath) == 0 { + switch mode := setting.RepoAvatar.Fallback; mode { + case "image": + return setting.RepoAvatar.FallbackImage + case "random": + if err := generateRandomAvatar(e, repo); err != nil { + log.Error("generateRandomAvatar: %v", err) + } + default: + // default behaviour: do not display avatar + return "" + } + } + return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar) +} + +// AvatarLink returns a link to the repository's avatar. +func (repo *Repository) AvatarLink() string { + return repo.avatarLink(db.GetEngine(db.DefaultContext)) +} + +// avatarLink returns user avatar absolute link. +func (repo *Repository) avatarLink(e db.Engine) string { + link := repo.relAvatarLink(e) + // we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL + if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") { + return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:] + } + // otherwise, return the link as it is + return link +} diff --git a/models/repo/git.go b/models/repo/git.go new file mode 100644 index 0000000000..509020565a --- /dev/null +++ b/models/repo/git.go @@ -0,0 +1,31 @@ +// 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 repo + +import "code.gitea.io/gitea/models/db" + +// MergeStyle represents the approach to merge commits into base branch. +type MergeStyle string + +const ( + // MergeStyleMerge create merge commit + MergeStyleMerge MergeStyle = "merge" + // MergeStyleRebase rebase before merging + MergeStyleRebase MergeStyle = "rebase" + // MergeStyleRebaseMerge rebase before merging with merge commit (--no-ff) + MergeStyleRebaseMerge MergeStyle = "rebase-merge" + // MergeStyleSquash squash commits into single commit before merging + MergeStyleSquash MergeStyle = "squash" + // MergeStyleManuallyMerged pr has been merged manually, just mark it as merged directly + MergeStyleManuallyMerged MergeStyle = "manually-merged" + // MergeStyleRebaseUpdate not a merge style, used to update pull head by rebase + MergeStyleRebaseUpdate MergeStyle = "rebase-update-only" +) + +// UpdateDefaultBranch updates the default branch +func UpdateDefaultBranch(repo *Repository) error { + _, err := db.GetEngine(db.DefaultContext).ID(repo.ID).Cols("default_branch").Update(repo) + return err +} diff --git a/models/repo_issue.go b/models/repo/issue.go index 32bfdc15b6..3edcc7b5a0 100644 --- a/models/repo_issue.go +++ b/models/repo/issue.go @@ -2,10 +2,14 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( + "context" + + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) @@ -45,3 +49,19 @@ func (repo *Repository) AllowOnlyContributorsToTrackTime() bool { } return u.IssuesConfig().AllowOnlyContributorsToTrackTime } + +// IsDependenciesEnabled returns if dependencies are enabled and returns the default setting if not set. +func (repo *Repository) IsDependenciesEnabled() bool { + return repo.IsDependenciesEnabledCtx(db.DefaultContext) +} + +// IsDependenciesEnabledCtx returns if dependencies are enabled and returns the default setting if not set. +func (repo *Repository) IsDependenciesEnabledCtx(ctx context.Context) bool { + var u *RepoUnit + var err error + if u, err = repo.getUnit(ctx, unit.TypeIssues); err != nil { + log.Trace("%s", err) + return setting.Service.DefaultEnableDependencies + } + return u.IssuesConfig().EnableDependencies +} diff --git a/models/repo_language_stats.go b/models/repo/language_stats.go index 79de42ce0c..3b0888b6bd 100644 --- a/models/repo_language_stats.go +++ b/models/repo/language_stats.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( "math" @@ -34,7 +34,8 @@ func init() { // LanguageStatList defines a list of language statistics type LanguageStatList []*LanguageStat -func (stats LanguageStatList) loadAttributes() { +// LoadAttributes loads attributes +func (stats LanguageStatList) LoadAttributes() { for i := range stats { stats[i].Color = enry.GetColor(stats[i].Language) } @@ -65,7 +66,7 @@ func (stats LanguageStatList) getLanguagePercentages() map[string]float32 { return langPerc } -func (repo *Repository) getLanguageStats(e db.Engine) (LanguageStatList, error) { +func getLanguageStats(e db.Engine, repo *Repository) (LanguageStatList, error) { stats := make(LanguageStatList, 0, 6) if err := e.Where("`repo_id` = ?", repo.ID).Desc("`size`").Find(&stats); err != nil { return nil, err @@ -74,13 +75,13 @@ func (repo *Repository) getLanguageStats(e db.Engine) (LanguageStatList, error) } // GetLanguageStats returns the language statistics for a repository -func (repo *Repository) GetLanguageStats() (LanguageStatList, error) { - return repo.getLanguageStats(db.GetEngine(db.DefaultContext)) +func GetLanguageStats(repo *Repository) (LanguageStatList, error) { + return getLanguageStats(db.GetEngine(db.DefaultContext), repo) } // GetTopLanguageStats returns the top language statistics for a repository -func (repo *Repository) GetTopLanguageStats(limit int) (LanguageStatList, error) { - stats, err := repo.getLanguageStats(db.GetEngine(db.DefaultContext)) +func GetTopLanguageStats(repo *Repository, limit int) (LanguageStatList, error) { + stats, err := getLanguageStats(db.GetEngine(db.DefaultContext), repo) if err != nil { return nil, err } @@ -106,12 +107,12 @@ func (repo *Repository) GetTopLanguageStats(limit int) (LanguageStatList, error) Percentage: float32(math.Round(float64(other)*10) / 10), }) } - topstats.loadAttributes() + topstats.LoadAttributes() return topstats, nil } // UpdateLanguageStats updates the language statistics for repository -func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]int64) error { +func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int64) error { ctx, committer, err := db.TxContext() if err != nil { return err @@ -119,7 +120,7 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]in defer committer.Close() sess := db.GetEngine(ctx) - oldstats, err := repo.getLanguageStats(sess) + oldstats, err := getLanguageStats(sess, repo) if err != nil { return err } @@ -175,7 +176,7 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]in } // Update indexer status - if err = repo.updateIndexerStatus(sess, RepoIndexerTypeStats, commitID); err != nil { + if err = updateIndexerStatus(sess, repo, RepoIndexerTypeStats, commitID); err != nil { return err } @@ -203,7 +204,7 @@ func CopyLanguageStat(originalRepo, destRepo *Repository) error { } // update destRepo's indexer status tmpCommitID := RepoLang[0].CommitID - if err := destRepo.updateIndexerStatus(sess, RepoIndexerTypeStats, tmpCommitID); err != nil { + if err := updateIndexerStatus(sess, destRepo, RepoIndexerTypeStats, tmpCommitID); err != nil { return err } if _, err := sess.Insert(&RepoLang); err != nil { diff --git a/models/repo/main_test.go b/models/repo/main_test.go index aa960bf132..f40a976281 100644 --- a/models/repo/main_test.go +++ b/models/repo/main_test.go @@ -15,5 +15,8 @@ func TestMain(m *testing.M) { unittest.MainTest(m, filepath.Join("..", ".."), "attachment.yml", "repo_archiver.yml", + "repository.yml", + "repo_unit.yml", + "repo_indexer_status.yml", ) } diff --git a/models/repo_mirror.go b/models/repo/mirror.go index e28d0d2517..bdb449af3a 100644 --- a/models/repo_mirror.go +++ b/models/repo/mirror.go @@ -3,9 +3,11 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( + "errors" + "fmt" "time" "code.gitea.io/gitea/models/db" @@ -15,6 +17,11 @@ import ( "xorm.io/xorm" ) +var ( + // ErrMirrorNotExist mirror does not exist error + ErrMirrorNotExist = errors.New("Mirror does not exist") +) + // RemoteMirrorer defines base methods for pull/push mirrors. type RemoteMirrorer interface { GetRepository() *Repository @@ -128,3 +135,43 @@ func InsertMirror(mirror *Mirror) error { _, err := db.GetEngine(db.DefaultContext).Insert(mirror) return err } + +// MirrorRepositoryList contains the mirror repositories +type MirrorRepositoryList []*Repository + +func (repos MirrorRepositoryList) loadAttributes(e db.Engine) error { + if len(repos) == 0 { + return nil + } + + // Load mirrors. + repoIDs := make([]int64, 0, len(repos)) + for i := range repos { + if !repos[i].IsMirror { + continue + } + + repoIDs = append(repoIDs, repos[i].ID) + } + mirrors := make([]*Mirror, 0, len(repoIDs)) + if err := e. + Where("id > 0"). + In("repo_id", repoIDs). + Find(&mirrors); err != nil { + return fmt.Errorf("find mirrors: %v", err) + } + + set := make(map[int64]*Mirror) + for i := range mirrors { + set[mirrors[i].RepoID] = mirrors[i] + } + for i := range repos { + repos[i].Mirror = set[repos[i].ID] + } + return nil +} + +// LoadAttributes loads the attributes for the given MirrorRepositoryList +func (repos MirrorRepositoryList) LoadAttributes() error { + return repos.loadAttributes(db.GetEngine(db.DefaultContext)) +} diff --git a/models/repo_pushmirror.go b/models/repo/pushmirror.go index 38a1a66947..0b62161641 100644 --- a/models/repo_pushmirror.go +++ b/models/repo/pushmirror.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( "errors" diff --git a/models/repo_pushmirror_test.go b/models/repo/pushmirror_test.go index aa4465082f..eff31fbac2 100644 --- a/models/repo_pushmirror_test.go +++ b/models/repo/pushmirror_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( "testing" diff --git a/models/repo/repo.go b/models/repo/repo.go new file mode 100644 index 0000000000..9353e813bc --- /dev/null +++ b/models/repo/repo.go @@ -0,0 +1,736 @@ +// 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 repo + +import ( + "context" + "fmt" + "html/template" + "net" + "net/url" + "path/filepath" + "strconv" + "strings" + + "code.gitea.io/gitea/models/db" + "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/markup" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" +) + +// TrustModelType defines the types of trust model for this repository +type TrustModelType int + +// kinds of TrustModel +const ( + DefaultTrustModel TrustModelType = iota // default trust model + CommitterTrustModel + CollaboratorTrustModel + CollaboratorCommitterTrustModel +) + +// String converts a TrustModelType to a string +func (t TrustModelType) String() string { + switch t { + case DefaultTrustModel: + return "default" + case CommitterTrustModel: + return "committer" + case CollaboratorTrustModel: + return "collaborator" + case CollaboratorCommitterTrustModel: + return "collaboratorcommitter" + } + return "default" +} + +// ToTrustModel converts a string to a TrustModelType +func ToTrustModel(model string) TrustModelType { + switch strings.ToLower(strings.TrimSpace(model)) { + case "default": + return DefaultTrustModel + case "collaborator": + return CollaboratorTrustModel + case "committer": + return CommitterTrustModel + case "collaboratorcommitter": + return CollaboratorCommitterTrustModel + } + return DefaultTrustModel +} + +// RepositoryStatus defines the status of repository +type RepositoryStatus int + +// all kinds of RepositoryStatus +const ( + RepositoryReady RepositoryStatus = iota // a normal repository + RepositoryBeingMigrated // repository is migrating + RepositoryPendingTransfer // repository pending in ownership transfer state + RepositoryBroken // repository is in a permanently broken state +) + +// Repository represents a git repository. +type Repository struct { + ID int64 `xorm:"pk autoincr"` + OwnerID int64 `xorm:"UNIQUE(s) index"` + OwnerName string + Owner *user_model.User `xorm:"-"` + LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` + Name string `xorm:"INDEX NOT NULL"` + Description string `xorm:"TEXT"` + Website string `xorm:"VARCHAR(2048)"` + OriginalServiceType api.GitServiceType `xorm:"index"` + OriginalURL string `xorm:"VARCHAR(2048)"` + DefaultBranch string + + NumWatches int + NumStars int + NumForks int + NumIssues int + NumClosedIssues int + NumOpenIssues int `xorm:"-"` + NumPulls int + NumClosedPulls int + NumOpenPulls int `xorm:"-"` + NumMilestones int `xorm:"NOT NULL DEFAULT 0"` + NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0"` + NumOpenMilestones int `xorm:"-"` + NumProjects int `xorm:"NOT NULL DEFAULT 0"` + NumClosedProjects int `xorm:"NOT NULL DEFAULT 0"` + NumOpenProjects int `xorm:"-"` + + IsPrivate bool `xorm:"INDEX"` + IsEmpty bool `xorm:"INDEX"` + IsArchived bool `xorm:"INDEX"` + IsMirror bool `xorm:"INDEX"` + *Mirror `xorm:"-"` + Status RepositoryStatus `xorm:"NOT NULL DEFAULT 0"` + + RenderingMetas map[string]string `xorm:"-"` + DocumentRenderingMetas map[string]string `xorm:"-"` + Units []*RepoUnit `xorm:"-"` + PrimaryLanguage *LanguageStat `xorm:"-"` + + IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"` + ForkID int64 `xorm:"INDEX"` + BaseRepo *Repository `xorm:"-"` + IsTemplate bool `xorm:"INDEX NOT NULL DEFAULT false"` + TemplateID int64 `xorm:"INDEX"` + Size int64 `xorm:"NOT NULL DEFAULT 0"` + CodeIndexerStatus *RepoIndexerStatus `xorm:"-"` + StatsIndexerStatus *RepoIndexerStatus `xorm:"-"` + IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"` + CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"` + Topics []string `xorm:"TEXT JSON"` + + TrustModel TrustModelType + + // Avatar: ID(10-20)-md5(32) - must fit into 64 symbols + Avatar string `xorm:"VARCHAR(64)"` + + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` +} + +func init() { + db.RegisterModel(new(Repository)) +} + +// SanitizedOriginalURL returns a sanitized OriginalURL +func (repo *Repository) SanitizedOriginalURL() string { + if repo.OriginalURL == "" { + return "" + } + u, err := url.Parse(repo.OriginalURL) + if err != nil { + return "" + } + u.User = nil + return u.String() +} + +// ColorFormat returns a colored string to represent this repo +func (repo *Repository) ColorFormat(s fmt.State) { + log.ColorFprintf(s, "%d:%s/%s", + log.NewColoredIDValue(repo.ID), + repo.OwnerName, + repo.Name) +} + +// IsBeingMigrated indicates that repository is being migrated +func (repo *Repository) IsBeingMigrated() bool { + return repo.Status == RepositoryBeingMigrated +} + +// IsBeingCreated indicates that repository is being migrated or forked +func (repo *Repository) IsBeingCreated() bool { + return repo.IsBeingMigrated() +} + +// IsBroken indicates that repository is broken +func (repo *Repository) IsBroken() bool { + return repo.Status == RepositoryBroken +} + +// AfterLoad is invoked from XORM after setting the values of all fields of this object. +func (repo *Repository) AfterLoad() { + // FIXME: use models migration to solve all at once. + if len(repo.DefaultBranch) == 0 { + repo.DefaultBranch = setting.Repository.DefaultBranch + } + + repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues + repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls + repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones + repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects +} + +// MustOwner always returns a valid *user_model.User object to avoid +// conceptually impossible error handling. +// It creates a fake object that contains error details +// when error occurs. +func (repo *Repository) MustOwner() *user_model.User { + return repo.mustOwner(db.DefaultContext) +} + +// FullName returns the repository full name +func (repo *Repository) FullName() string { + return repo.OwnerName + "/" + repo.Name +} + +// HTMLURL returns the repository HTML URL +func (repo *Repository) HTMLURL() string { + return setting.AppURL + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) +} + +// CommitLink make link to by commit full ID +// note: won't check whether it's an right id +func (repo *Repository) CommitLink(commitID string) (result string) { + if commitID == "" || commitID == "0000000000000000000000000000000000000000" { + result = "" + } else { + result = repo.HTMLURL() + "/commit/" + url.PathEscape(commitID) + } + return +} + +// APIURL returns the repository API URL +func (repo *Repository) APIURL() string { + return setting.AppURL + "api/v1/repos/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) +} + +// GetCommitsCountCacheKey returns cache key used for commits count caching. +func (repo *Repository) GetCommitsCountCacheKey(contextName string, isRef bool) string { + var prefix string + if isRef { + prefix = "ref" + } else { + prefix = "commit" + } + return fmt.Sprintf("commits-count-%d-%s-%s", repo.ID, prefix, contextName) +} + +// LoadUnits loads repo units into repo.Units +func (repo *Repository) LoadUnits(ctx context.Context) (err error) { + if repo.Units != nil { + return nil + } + + repo.Units, err = getUnitsByRepoID(db.GetEngine(ctx), repo.ID) + log.Trace("repo.Units: %-+v", repo.Units) + return err +} + +// UnitEnabled if this repository has the given unit enabled +func (repo *Repository) UnitEnabled(tp unit.Type) bool { + if err := repo.LoadUnits(db.DefaultContext); err != nil { + log.Warn("Error loading repository (ID: %d) units: %s", repo.ID, err.Error()) + } + for _, unit := range repo.Units { + if unit.Type == tp { + return true + } + } + return false +} + +// MustGetUnit always returns a RepoUnit object +func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit { + ru, err := repo.GetUnit(tp) + if err == nil { + return ru + } + + if tp == unit.TypeExternalWiki { + return &RepoUnit{ + Type: tp, + Config: new(ExternalWikiConfig), + } + } else if tp == unit.TypeExternalTracker { + return &RepoUnit{ + Type: tp, + Config: new(ExternalTrackerConfig), + } + } else if tp == unit.TypePullRequests { + return &RepoUnit{ + Type: tp, + Config: new(PullRequestsConfig), + } + } else if tp == unit.TypeIssues { + return &RepoUnit{ + Type: tp, + Config: new(IssuesConfig), + } + } + return &RepoUnit{ + Type: tp, + Config: new(UnitConfig), + } +} + +// GetUnit returns a RepoUnit object +func (repo *Repository) GetUnit(tp unit.Type) (*RepoUnit, error) { + return repo.getUnit(db.DefaultContext, tp) +} + +func (repo *Repository) getUnit(ctx context.Context, tp unit.Type) (*RepoUnit, error) { + if err := repo.LoadUnits(ctx); err != nil { + return nil, err + } + for _, unit := range repo.Units { + if unit.Type == tp { + return unit, nil + } + } + return nil, ErrUnitTypeNotExist{tp} +} + +// GetOwner returns the repository owner +func (repo *Repository) GetOwner(ctx context.Context) (err error) { + if repo.Owner != nil { + return nil + } + + repo.Owner, err = user_model.GetUserByIDEngine(db.GetEngine(ctx), repo.OwnerID) + return err +} + +func (repo *Repository) mustOwner(ctx context.Context) *user_model.User { + if err := repo.GetOwner(ctx); err != nil { + return &user_model.User{ + Name: "error", + FullName: err.Error(), + } + } + + return repo.Owner +} + +// ComposeMetas composes a map of metas for properly rendering issue links and external issue trackers. +func (repo *Repository) ComposeMetas() map[string]string { + if len(repo.RenderingMetas) == 0 { + metas := map[string]string{ + "user": repo.OwnerName, + "repo": repo.Name, + "repoPath": repo.RepoPath(), + "mode": "comment", + } + + unit, err := repo.GetUnit(unit.TypeExternalTracker) + if err == nil { + metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat + switch unit.ExternalTrackerConfig().ExternalTrackerStyle { + case markup.IssueNameStyleAlphanumeric: + metas["style"] = markup.IssueNameStyleAlphanumeric + default: + metas["style"] = markup.IssueNameStyleNumeric + } + } + + repo.MustOwner() + if repo.Owner.IsOrganization() { + teams := make([]string, 0, 5) + _ = db.GetEngine(db.DefaultContext).Table("team_repo"). + Join("INNER", "team", "team.id = team_repo.team_id"). + Where("team_repo.repo_id = ?", repo.ID). + Select("team.lower_name"). + OrderBy("team.lower_name"). + Find(&teams) + metas["teams"] = "," + strings.Join(teams, ",") + "," + metas["org"] = strings.ToLower(repo.OwnerName) + } + + repo.RenderingMetas = metas + } + return repo.RenderingMetas +} + +// ComposeDocumentMetas composes a map of metas for properly rendering documents +func (repo *Repository) ComposeDocumentMetas() map[string]string { + if len(repo.DocumentRenderingMetas) == 0 { + metas := map[string]string{} + for k, v := range repo.ComposeMetas() { + metas[k] = v + } + metas["mode"] = "document" + repo.DocumentRenderingMetas = metas + } + return repo.DocumentRenderingMetas +} + +// GetBaseRepo populates repo.BaseRepo for a fork repository and +// returns an error on failure (NOTE: no error is returned for +// non-fork repositories, and BaseRepo will be left untouched) +func (repo *Repository) GetBaseRepo() (err error) { + return repo.getBaseRepo(db.GetEngine(db.DefaultContext)) +} + +func (repo *Repository) getBaseRepo(e db.Engine) (err error) { + if !repo.IsFork { + return nil + } + + repo.BaseRepo, err = getRepositoryByID(e, repo.ForkID) + return err +} + +// IsGenerated returns whether _this_ repository was generated from a template +func (repo *Repository) IsGenerated() bool { + return repo.TemplateID != 0 +} + +// RepoPath returns repository path by given user and repository name. +func RepoPath(userName, repoName string) string { //revive:disable-line:exported + return filepath.Join(user_model.UserPath(userName), strings.ToLower(repoName)+".git") +} + +// RepoPath returns the repository path +func (repo *Repository) RepoPath() string { + return RepoPath(repo.OwnerName, repo.Name) +} + +// GitConfigPath returns the path to a repository's git config/ directory +func GitConfigPath(repoPath string) string { + return filepath.Join(repoPath, "config") +} + +// GitConfigPath returns the repository git config path +func (repo *Repository) GitConfigPath() string { + return GitConfigPath(repo.RepoPath()) +} + +// Link returns the repository link +func (repo *Repository) Link() string { + return setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) +} + +// ComposeCompareURL returns the repository comparison URL +func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) string { + return fmt.Sprintf("%s/%s/compare/%s...%s", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), util.PathEscapeSegments(oldCommitID), util.PathEscapeSegments(newCommitID)) +} + +// IsOwnedBy returns true when user owns this repository +func (repo *Repository) IsOwnedBy(userID int64) bool { + return repo.OwnerID == userID +} + +// CanCreateBranch returns true if repository meets the requirements for creating new branches. +func (repo *Repository) CanCreateBranch() bool { + return !repo.IsMirror +} + +// CanEnablePulls returns true if repository meets the requirements of accepting pulls. +func (repo *Repository) CanEnablePulls() bool { + return !repo.IsMirror && !repo.IsEmpty +} + +// AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled. +func (repo *Repository) AllowsPulls() bool { + return repo.CanEnablePulls() && repo.UnitEnabled(unit.TypePullRequests) +} + +// CanEnableEditor returns true if repository meets the requirements of web editor. +func (repo *Repository) CanEnableEditor() bool { + return !repo.IsMirror +} + +// DescriptionHTML does special handles to description and return HTML string. +func (repo *Repository) DescriptionHTML() template.HTML { + desc, err := markup.RenderDescriptionHTML(&markup.RenderContext{ + URLPrefix: repo.HTMLURL(), + Metas: repo.ComposeMetas(), + }, repo.Description) + if err != nil { + log.Error("Failed to render description for %s (ID: %d): %v", repo.Name, repo.ID, err) + return template.HTML(markup.Sanitize(repo.Description)) + } + return template.HTML(markup.Sanitize(string(desc))) +} + +// CloneLink represents different types of clone URLs of repository. +type CloneLink struct { + SSH string + HTTPS string + Git string +} + +// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name. +func ComposeHTTPSCloneURL(owner, repo string) string { + return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.PathEscape(owner), url.PathEscape(repo)) +} + +func (repo *Repository) cloneLink(isWiki bool) *CloneLink { + repoName := repo.Name + if isWiki { + repoName += ".wiki" + } + + sshUser := setting.RunUser + if setting.SSH.StartBuiltinServer { + sshUser = setting.SSH.BuiltinServerUser + } + + cl := new(CloneLink) + + // if we have a ipv6 literal we need to put brackets around it + // for the git cloning to work. + sshDomain := setting.SSH.Domain + ip := net.ParseIP(setting.SSH.Domain) + if ip != nil && ip.To4() == nil { + sshDomain = "[" + setting.SSH.Domain + "]" + } + + if setting.SSH.Port != 22 { + cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) + } else if setting.Repository.UseCompatSSHURI { + cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) + } else { + cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) + } + cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName) + return cl +} + +// CloneLink returns clone URLs of repository. +func (repo *Repository) CloneLink() (cl *CloneLink) { + return repo.cloneLink(false) +} + +// GetOriginalURLHostname returns the hostname of a URL or the URL +func (repo *Repository) GetOriginalURLHostname() string { + u, err := url.Parse(repo.OriginalURL) + if err != nil { + return repo.OriginalURL + } + + return u.Host +} + +// GetTrustModel will get the TrustModel for the repo or the default trust model +func (repo *Repository) GetTrustModel() TrustModelType { + trustModel := repo.TrustModel + if trustModel == DefaultTrustModel { + trustModel = ToTrustModel(setting.Repository.Signing.DefaultTrustModel) + if trustModel == DefaultTrustModel { + return CollaboratorTrustModel + } + } + return trustModel +} + +// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. +func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) { + return GetRepositoryByOwnerAndNameCtx(db.DefaultContext, ownerName, repoName) +} + +// __________ .__ __ +// \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. +// | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | +// | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ | +// |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____| +// \/ \/|__| \/ \/ + +// ErrRepoNotExist represents a "RepoNotExist" kind of error. +type ErrRepoNotExist struct { + ID int64 + UID int64 + OwnerName string + Name string +} + +// IsErrRepoNotExist checks if an error is a ErrRepoNotExist. +func IsErrRepoNotExist(err error) bool { + _, ok := err.(ErrRepoNotExist) + return ok +} + +func (err ErrRepoNotExist) Error() string { + return fmt.Sprintf("repository does not exist [id: %d, uid: %d, owner_name: %s, name: %s]", + err.ID, err.UID, err.OwnerName, err.Name) +} + +// GetRepositoryByOwnerAndNameCtx returns the repository by given owner name and repo name +func GetRepositoryByOwnerAndNameCtx(ctx context.Context, ownerName, repoName string) (*Repository, error) { + var repo Repository + has, err := db.GetEngine(ctx).Table("repository").Select("repository.*"). + Join("INNER", "`user`", "`user`.id = repository.owner_id"). + Where("repository.lower_name = ?", strings.ToLower(repoName)). + And("`user`.lower_name = ?", strings.ToLower(ownerName)). + Get(&repo) + if err != nil { + return nil, err + } else if !has { + return nil, ErrRepoNotExist{0, 0, ownerName, repoName} + } + return &repo, nil +} + +// GetRepositoryByName returns the repository by given name under user if exists. +func GetRepositoryByName(ownerID int64, name string) (*Repository, error) { + repo := &Repository{ + OwnerID: ownerID, + LowerName: strings.ToLower(name), + } + has, err := db.GetEngine(db.DefaultContext).Get(repo) + if err != nil { + return nil, err + } else if !has { + return nil, ErrRepoNotExist{0, ownerID, "", name} + } + return repo, err +} + +func getRepositoryByID(e db.Engine, id int64) (*Repository, error) { + repo := new(Repository) + has, err := e.ID(id).Get(repo) + if err != nil { + return nil, err + } else if !has { + return nil, ErrRepoNotExist{id, 0, "", ""} + } + return repo, nil +} + +// GetRepositoryByID returns the repository by given id if exists. +func GetRepositoryByID(id int64) (*Repository, error) { + return getRepositoryByID(db.GetEngine(db.DefaultContext), id) +} + +// GetRepositoryByIDCtx returns the repository by given id if exists. +func GetRepositoryByIDCtx(ctx context.Context, id int64) (*Repository, error) { + return getRepositoryByID(db.GetEngine(ctx), id) +} + +// GetRepositoriesMapByIDs returns the repositories by given id slice. +func GetRepositoriesMapByIDs(ids []int64) (map[int64]*Repository, error) { + repos := make(map[int64]*Repository, len(ids)) + return repos, db.GetEngine(db.DefaultContext).In("id", ids).Find(&repos) +} + +// IsRepositoryExistCtx returns true if the repository with given name under user has already existed. +func IsRepositoryExistCtx(ctx context.Context, u *user_model.User, repoName string) (bool, error) { + has, err := db.GetEngine(ctx).Get(&Repository{ + OwnerID: u.ID, + LowerName: strings.ToLower(repoName), + }) + if err != nil { + return false, err + } + isDir, err := util.IsDir(RepoPath(u.Name, repoName)) + return has && isDir, err +} + +// IsRepositoryExist returns true if the repository with given name under user has already existed. +func IsRepositoryExist(u *user_model.User, repoName string) (bool, error) { + return IsRepositoryExistCtx(db.DefaultContext, u, repoName) +} + +// GetTemplateRepo populates repo.TemplateRepo for a generated repository and +// returns an error on failure (NOTE: no error is returned for +// non-generated repositories, and TemplateRepo will be left untouched) +func GetTemplateRepo(repo *Repository) (*Repository, error) { + return getTemplateRepo(db.GetEngine(db.DefaultContext), repo) +} + +func getTemplateRepo(e db.Engine, repo *Repository) (*Repository, error) { + if !repo.IsGenerated() { + return nil, nil + } + + return getRepositoryByID(e, repo.TemplateID) +} + +func countRepositories(userID int64, private bool) int64 { + sess := db.GetEngine(db.DefaultContext).Where("id > 0") + + if userID > 0 { + sess.And("owner_id = ?", userID) + } + if !private { + sess.And("is_private=?", false) + } + + count, err := sess.Count(new(Repository)) + if err != nil { + log.Error("countRepositories: %v", err) + } + return count +} + +// CountRepositories returns number of repositories. +// Argument private only takes effect when it is false, +// set it true to count all repositories. +func CountRepositories(private bool) int64 { + return countRepositories(-1, private) +} + +// CountUserRepositories returns number of repositories user owns. +// Argument private only takes effect when it is false, +// set it true to count all repositories. +func CountUserRepositories(userID int64, private bool) int64 { + return countRepositories(userID, private) +} + +// GetUserMirrorRepositories returns a list of mirror repositories of given user. +func GetUserMirrorRepositories(userID int64) ([]*Repository, error) { + repos := make([]*Repository, 0, 10) + return repos, db.GetEngine(db.DefaultContext). + Where("owner_id = ?", userID). + And("is_mirror = ?", true). + Find(&repos) +} + +func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) { + return e.Count(&Repository{OwnerID: ownerID}) +} + +func getPublicRepositoryCount(e db.Engine, u *user_model.User) (int64, error) { + return e.Where("is_private = ?", false).Count(&Repository{OwnerID: u.ID}) +} + +func getPrivateRepositoryCount(e db.Engine, u *user_model.User) (int64, error) { + return e.Where("is_private = ?", true).Count(&Repository{OwnerID: u.ID}) +} + +// GetRepositoryCount returns the total number of repositories of user. +func GetRepositoryCount(ctx context.Context, ownerID int64) (int64, error) { + return getRepositoryCount(db.GetEngine(ctx), ownerID) +} + +// GetPublicRepositoryCount returns the total number of public repositories of user. +func GetPublicRepositoryCount(u *user_model.User) (int64, error) { + return getPublicRepositoryCount(db.GetEngine(db.DefaultContext), u) +} + +// GetPrivateRepositoryCount returns the total number of private repositories of user. +func GetPrivateRepositoryCount(u *user_model.User) (int64, error) { + return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u) +} diff --git a/models/repo_indexer.go b/models/repo/repo_indexer.go index e0511b325e..f442cad4d1 100644 --- a/models/repo_indexer.go +++ b/models/repo/repo_indexer.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( "fmt" @@ -13,7 +13,7 @@ import ( ) // RepoIndexerType specifies the repository indexer type -type RepoIndexerType int +type RepoIndexerType int //revive:disable-line:exported const ( // RepoIndexerTypeCode code indexer @@ -24,7 +24,7 @@ const ( // RepoIndexerStatus status of a repo's entry in the repo indexer // For now, implicitly refers to default branch -type RepoIndexerStatus struct { +type RepoIndexerStatus struct { //revive:disable-line:exported ID int64 `xorm:"pk autoincr"` RepoID int64 `xorm:"INDEX(s)"` CommitSha string `xorm:"VARCHAR(40)"` @@ -63,7 +63,7 @@ func GetUnindexedRepos(indexerType RepoIndexerType, maxRepoID int64, page, pageS } // getIndexerStatus loads repo codes indxer status -func (repo *Repository) getIndexerStatus(e db.Engine, indexerType RepoIndexerType) (*RepoIndexerStatus, error) { +func getIndexerStatus(e db.Engine, repo *Repository, indexerType RepoIndexerType) (*RepoIndexerStatus, error) { switch indexerType { case RepoIndexerTypeCode: if repo.CodeIndexerStatus != nil { @@ -91,13 +91,13 @@ func (repo *Repository) getIndexerStatus(e db.Engine, indexerType RepoIndexerTyp } // GetIndexerStatus loads repo codes indxer status -func (repo *Repository) GetIndexerStatus(indexerType RepoIndexerType) (*RepoIndexerStatus, error) { - return repo.getIndexerStatus(db.GetEngine(db.DefaultContext), indexerType) +func GetIndexerStatus(repo *Repository, indexerType RepoIndexerType) (*RepoIndexerStatus, error) { + return getIndexerStatus(db.GetEngine(db.DefaultContext), repo, indexerType) } // updateIndexerStatus updates indexer status -func (repo *Repository) updateIndexerStatus(e db.Engine, indexerType RepoIndexerType, sha string) error { - status, err := repo.getIndexerStatus(e, indexerType) +func updateIndexerStatus(e db.Engine, repo *Repository, indexerType RepoIndexerType, sha string) error { + status, err := getIndexerStatus(e, repo, indexerType) if err != nil { return fmt.Errorf("UpdateIndexerStatus: Unable to getIndexerStatus for repo: %s Error: %v", repo.FullName(), err) } @@ -120,6 +120,6 @@ func (repo *Repository) updateIndexerStatus(e db.Engine, indexerType RepoIndexer } // UpdateIndexerStatus updates indexer status -func (repo *Repository) UpdateIndexerStatus(indexerType RepoIndexerType, sha string) error { - return repo.updateIndexerStatus(db.GetEngine(db.DefaultContext), indexerType, sha) +func UpdateIndexerStatus(repo *Repository, indexerType RepoIndexerType, sha string) error { + return updateIndexerStatus(db.GetEngine(db.DefaultContext), repo, indexerType, sha) } diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go new file mode 100644 index 0000000000..6f48a22e49 --- /dev/null +++ b/models/repo/repo_test.go @@ -0,0 +1,44 @@ +// 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 repo + +import ( + "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 TestGetRepositoryCount(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + count, err1 := GetRepositoryCount(db.DefaultContext, 10) + privateCount, err2 := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)}) + publicCount, err3 := GetPublicRepositoryCount(&user_model.User{ID: int64(10)}) + assert.NoError(t, err1) + assert.NoError(t, err2) + assert.NoError(t, err3) + assert.Equal(t, int64(3), count) + assert.Equal(t, privateCount+publicCount, count) +} + +func TestGetPublicRepositoryCount(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + count, err := GetPublicRepositoryCount(&user_model.User{ID: int64(10)}) + assert.NoError(t, err) + assert.Equal(t, int64(1), count) +} + +func TestGetPrivateRepositoryCount(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + count, err := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)}) + assert.NoError(t, err) + assert.Equal(t, int64(2), count) +} diff --git a/models/repo_unit.go b/models/repo/repo_unit.go index 4dac15366b..5f6c43f02f 100644 --- a/models/repo_unit.go +++ b/models/repo/repo_unit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( "fmt" @@ -17,8 +17,23 @@ import ( "xorm.io/xorm/convert" ) +// ErrUnitTypeNotExist represents a "UnitTypeNotExist" kind of error. +type ErrUnitTypeNotExist struct { + UT unit.Type +} + +// IsErrUnitTypeNotExist checks if an error is a ErrUnitNotExist. +func IsErrUnitTypeNotExist(err error) bool { + _, ok := err.(ErrUnitTypeNotExist) + return ok +} + +func (err ErrUnitTypeNotExist) Error() string { + return fmt.Sprintf("Unit type does not exist: %s", err.UT.String()) +} + // RepoUnit describes all units of a repository -type RepoUnit struct { +type RepoUnit struct { //revive:disable-line:exported ID int64 RepoID int64 `xorm:"INDEX(s)"` Type unit.Type `xorm:"INDEX(s)"` @@ -35,7 +50,7 @@ type UnitConfig struct{} // FromDB fills up a UnitConfig from serialized format. func (cfg *UnitConfig) FromDB(bs []byte) error { - return JSONUnmarshalHandleDoubleEncode(bs, &cfg) + return json.UnmarshalHandleDoubleEncode(bs, &cfg) } // ToDB exports a UnitConfig to a serialized format. @@ -50,7 +65,7 @@ type ExternalWikiConfig struct { // FromDB fills up a ExternalWikiConfig from serialized format. func (cfg *ExternalWikiConfig) FromDB(bs []byte) error { - return JSONUnmarshalHandleDoubleEncode(bs, &cfg) + return json.UnmarshalHandleDoubleEncode(bs, &cfg) } // ToDB exports a ExternalWikiConfig to a serialized format. @@ -67,7 +82,7 @@ type ExternalTrackerConfig struct { // FromDB fills up a ExternalTrackerConfig from serialized format. func (cfg *ExternalTrackerConfig) FromDB(bs []byte) error { - return JSONUnmarshalHandleDoubleEncode(bs, &cfg) + return json.UnmarshalHandleDoubleEncode(bs, &cfg) } // ToDB exports a ExternalTrackerConfig to a serialized format. @@ -84,7 +99,7 @@ type IssuesConfig struct { // FromDB fills up a IssuesConfig from serialized format. func (cfg *IssuesConfig) FromDB(bs []byte) error { - return JSONUnmarshalHandleDoubleEncode(bs, &cfg) + return json.UnmarshalHandleDoubleEncode(bs, &cfg) } // ToDB exports a IssuesConfig to a serialized format. @@ -107,7 +122,7 @@ type PullRequestsConfig struct { // FromDB fills up a PullRequestsConfig from serialized format. func (cfg *PullRequestsConfig) FromDB(bs []byte) error { - return JSONUnmarshalHandleDoubleEncode(bs, &cfg) + return json.UnmarshalHandleDoubleEncode(bs, &cfg) } // ToDB exports a PullRequestsConfig to a serialized format. diff --git a/models/wiki.go b/models/repo/wiki.go index f80696542e..abf0155cad 100644 --- a/models/wiki.go +++ b/models/repo/wiki.go @@ -3,7 +3,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( "path/filepath" diff --git a/models/wiki_test.go b/models/repo/wiki_test.go index ae6b090db5..72f5280ce5 100644 --- a/models/wiki_test.go +++ b/models/repo/wiki_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo import ( "path/filepath" diff --git a/models/repo_activity.go b/models/repo_activity.go index d3d4c7bbd7..5bdea80b97 100644 --- a/models/repo_activity.go +++ b/models/repo_activity.go @@ -10,6 +10,7 @@ import ( "time" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -42,7 +43,7 @@ type ActivityStats struct { } // GetActivityStats return stats for repository at given time range -func GetActivityStats(repo *Repository, timeFrom time.Time, releases, issues, prs, code bool) (*ActivityStats, error) { +func GetActivityStats(repo *repo_model.Repository, timeFrom time.Time, releases, issues, prs, code bool) (*ActivityStats, error) { stats := &ActivityStats{Code: &git.CodeActivityStats{}} if releases { if err := stats.FillReleases(repo.ID, timeFrom); err != nil { @@ -79,7 +80,7 @@ func GetActivityStats(repo *Repository, timeFrom time.Time, releases, issues, pr } // GetActivityStatsTopAuthors returns top author stats for git commits for all branches -func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int) ([]*ActivityAuthorData, error) { +func GetActivityStatsTopAuthors(repo *repo_model.Repository, timeFrom time.Time, count int) ([]*ActivityAuthorData, error) { gitRepo, err := git.OpenRepository(repo.RepoPath()) if err != nil { return nil, fmt.Errorf("OpenRepository: %v", err) diff --git a/models/repo_archiver.go b/models/repo_archiver.go index 9363d09574..1ac05da043 100644 --- a/models/repo_archiver.go +++ b/models/repo_archiver.go @@ -10,14 +10,14 @@ import ( ) // LoadArchiverRepo loads repository -func LoadArchiverRepo(archiver *repo_model.RepoArchiver) (*Repository, error) { - var repo Repository +func LoadArchiverRepo(archiver *repo_model.RepoArchiver) (*repo_model.Repository, error) { + var repo repo_model.Repository has, err := db.GetEngine(db.DefaultContext).ID(archiver.RepoID).Get(&repo) if err != nil { return nil, err } if !has { - return nil, ErrRepoNotExist{ + return nil, repo_model.ErrRepoNotExist{ ID: archiver.RepoID, } } diff --git a/models/repo_avatar.go b/models/repo_avatar.go index 1d9705fe99..27af911a7e 100644 --- a/models/repo_avatar.go +++ b/models/repo_avatar.go @@ -10,59 +10,23 @@ import ( "fmt" "image/png" "io" - "net/url" "strconv" - "strings" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/avatar" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" ) -// CustomAvatarRelativePath returns repository custom avatar file path. -func (repo *Repository) CustomAvatarRelativePath() string { - return repo.Avatar -} - -// generateRandomAvatar generates a random avatar for repository. -func (repo *Repository) generateRandomAvatar(e db.Engine) error { - idToString := fmt.Sprintf("%d", repo.ID) - - seed := idToString - img, err := avatar.RandomImage([]byte(seed)) - if err != nil { - return fmt.Errorf("RandomImage: %v", err) - } - - repo.Avatar = idToString - - if err := storage.SaveFrom(storage.RepoAvatars, repo.CustomAvatarRelativePath(), func(w io.Writer) error { - if err := png.Encode(w, img); err != nil { - log.Error("Encode: %v", err) - } - return err - }); err != nil { - return fmt.Errorf("Failed to create dir %s: %v", repo.CustomAvatarRelativePath(), err) - } - - log.Info("New random avatar created for repository: %d", repo.ID) - - if _, err := e.ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil { - return err - } - - return nil -} - // RemoveRandomAvatars removes the randomly generated avatars that were created for repositories func RemoveRandomAvatars(ctx context.Context) error { return db.GetEngine(db.DefaultContext). Where("id > 0").BufferSize(setting.Database.IterateBufferSize). - Iterate(new(Repository), + Iterate(new(repo_model.Repository), func(idx int, bean interface{}) error { - repository := bean.(*Repository) + repository := bean.(*repo_model.Repository) select { case <-ctx.Done(): return db.ErrCancelledf("before random avatars removed for %s", repository.FullName()) @@ -70,55 +34,15 @@ func RemoveRandomAvatars(ctx context.Context) error { } stringifiedID := strconv.FormatInt(repository.ID, 10) if repository.Avatar == stringifiedID { - return repository.DeleteAvatar() + return DeleteRepoAvatar(repository) } return nil }) } -// RelAvatarLink returns a relative link to the repository's avatar. -func (repo *Repository) RelAvatarLink() string { - return repo.relAvatarLink(db.GetEngine(db.DefaultContext)) -} - -func (repo *Repository) relAvatarLink(e db.Engine) string { - // If no avatar - path is empty - avatarPath := repo.CustomAvatarRelativePath() - if len(avatarPath) == 0 { - switch mode := setting.RepoAvatar.Fallback; mode { - case "image": - return setting.RepoAvatar.FallbackImage - case "random": - if err := repo.generateRandomAvatar(e); err != nil { - log.Error("generateRandomAvatar: %v", err) - } - default: - // default behaviour: do not display avatar - return "" - } - } - return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar) -} - -// AvatarLink returns a link to the repository's avatar. -func (repo *Repository) AvatarLink() string { - return repo.avatarLink(db.GetEngine(db.DefaultContext)) -} - -// avatarLink returns user avatar absolute link. -func (repo *Repository) avatarLink(e db.Engine) string { - link := repo.relAvatarLink(e) - // we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL - if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") { - return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:] - } - // otherwise, return the link as it is - return link -} - -// UploadAvatar saves custom avatar for repository. +// UploadRepoAvatar saves custom avatar for repository. // FIXME: split uploads to different subdirs in case we have massive number of repos. -func (repo *Repository) UploadAvatar(data []byte) error { +func UploadRepoAvatar(repo *repo_model.Repository, data []byte) error { m, err := avatar.Prepare(data) if err != nil { return err @@ -162,8 +86,8 @@ func (repo *Repository) UploadAvatar(data []byte) error { return committer.Commit() } -// DeleteAvatar deletes the repos's custom avatar. -func (repo *Repository) DeleteAvatar() error { +// DeleteRepoAvatar deletes the repos's custom avatar. +func DeleteRepoAvatar(repo *repo_model.Repository) error { // Avatar not exists if len(repo.Avatar) == 0 { return nil diff --git a/models/repo_branch.go b/models/repo_branch.go deleted file mode 100644 index 08e8fccb59..0000000000 --- a/models/repo_branch.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2016 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 models - -// CanCreateBranch returns true if repository meets the requirements for creating new branches. -func (repo *Repository) CanCreateBranch() bool { - return !repo.IsMirror -} diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index 08682eef61..ab6a3bafbe 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -6,10 +6,12 @@ package models import ( + "context" "fmt" "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" @@ -32,11 +34,12 @@ func init() { db.RegisterModel(new(Collaboration)) } -func (repo *Repository) addCollaborator(e db.Engine, u *user_model.User) error { +func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error { collaboration := &Collaboration{ RepoID: repo.ID, UserID: u.ID, } + e := db.GetEngine(ctx) has, err := e.Get(collaboration) if err != nil { @@ -50,34 +53,34 @@ func (repo *Repository) addCollaborator(e db.Engine, u *user_model.User) error { return err } - return repo.recalculateUserAccess(e, u.ID) + return recalculateUserAccess(ctx, repo, u.ID) } // AddCollaborator adds new collaboration to a repository with default access mode. -func (repo *Repository) AddCollaborator(u *user_model.User) error { +func AddCollaborator(repo *repo_model.Repository, u *user_model.User) error { ctx, committer, err := db.TxContext() if err != nil { return err } defer committer.Close() - if err := repo.addCollaborator(db.GetEngine(ctx), u); err != nil { + if err := addCollaborator(ctx, repo, u); err != nil { return err } return committer.Commit() } -func (repo *Repository) getCollaborations(e db.Engine, listOptions db.ListOptions) ([]*Collaboration, error) { +func getCollaborations(e db.Engine, repoID int64, listOptions db.ListOptions) ([]*Collaboration, error) { if listOptions.Page == 0 { collaborations := make([]*Collaboration, 0, 8) - return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID}) + return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repoID}) } e = db.SetEnginePagination(e, &listOptions) collaborations := make([]*Collaboration, 0, listOptions.PageSize) - return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID}) + return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repoID}) } // Collaborator represents a user with collaboration details. @@ -86,8 +89,8 @@ type Collaborator struct { Collaboration *Collaboration } -func (repo *Repository) getCollaborators(e db.Engine, listOptions db.ListOptions) ([]*Collaborator, error) { - collaborations, err := repo.getCollaborations(e, listOptions) +func getCollaborators(e db.Engine, repoID int64, listOptions db.ListOptions) ([]*Collaborator, error) { + collaborations, err := getCollaborations(e, repoID, listOptions) if err != nil { return nil, fmt.Errorf("getCollaborations: %v", err) } @@ -97,7 +100,7 @@ func (repo *Repository) getCollaborators(e db.Engine, listOptions db.ListOptions user, err := user_model.GetUserByIDEngine(e, c.UserID) if err != nil { if user_model.IsErrUserNotExist(err) { - log.Warn("Inconsistent DB: User: %d is listed as collaborator of %-v but does not exist", c.UserID, repo) + log.Warn("Inconsistent DB: User: %d is listed as collaborator of %-v but does not exist", c.UserID, repoID) user = user_model.NewGhostUser() } else { return nil, err @@ -112,18 +115,18 @@ func (repo *Repository) getCollaborators(e db.Engine, listOptions db.ListOptions } // GetCollaborators returns the collaborators for a repository -func (repo *Repository) GetCollaborators(listOptions db.ListOptions) ([]*Collaborator, error) { - return repo.getCollaborators(db.GetEngine(db.DefaultContext), listOptions) +func GetCollaborators(repoID int64, listOptions db.ListOptions) ([]*Collaborator, error) { + return getCollaborators(db.GetEngine(db.DefaultContext), repoID, listOptions) } // CountCollaborators returns total number of collaborators for a repository -func (repo *Repository) CountCollaborators() (int64, error) { - return db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repo.ID).Count(&Collaboration{}) +func CountCollaborators(repoID int64) (int64, error) { + return db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repoID).Count(&Collaboration{}) } -func (repo *Repository) getCollaboration(e db.Engine, uid int64) (*Collaboration, error) { +func getCollaboration(e db.Engine, repoID, uid int64) (*Collaboration, error) { collaboration := &Collaboration{ - RepoID: repo.ID, + RepoID: repoID, UserID: uid, } has, err := e.Get(collaboration) @@ -133,16 +136,16 @@ func (repo *Repository) getCollaboration(e db.Engine, uid int64) (*Collaboration return collaboration, err } -func (repo *Repository) isCollaborator(e db.Engine, userID int64) (bool, error) { - return e.Get(&Collaboration{RepoID: repo.ID, UserID: userID}) +func isCollaborator(e db.Engine, repoID, userID int64) (bool, error) { + return e.Get(&Collaboration{RepoID: repoID, UserID: userID}) } // IsCollaborator check if a user is a collaborator of a repository -func (repo *Repository) IsCollaborator(userID int64) (bool, error) { - return repo.isCollaborator(db.GetEngine(db.DefaultContext), userID) +func IsCollaborator(repoID, userID int64) (bool, error) { + return isCollaborator(db.GetEngine(db.DefaultContext), repoID, userID) } -func (repo *Repository) changeCollaborationAccessMode(e db.Engine, uid int64, mode perm.AccessMode) error { +func changeCollaborationAccessMode(e db.Engine, repo *repo_model.Repository, uid int64, mode perm.AccessMode) error { // Discard invalid input if mode <= perm.AccessModeNone || mode > perm.AccessModeOwner { return nil @@ -177,14 +180,14 @@ func (repo *Repository) changeCollaborationAccessMode(e db.Engine, uid int64, mo } // ChangeCollaborationAccessMode sets new access mode for the collaboration. -func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode perm.AccessMode) error { +func ChangeCollaborationAccessMode(repo *repo_model.Repository, uid int64, mode perm.AccessMode) error { ctx, committer, err := db.TxContext() if err != nil { return err } defer committer.Close() - if err := repo.changeCollaborationAccessMode(db.GetEngine(ctx), uid, mode); err != nil { + if err := changeCollaborationAccessMode(db.GetEngine(ctx), repo, uid, mode); err != nil { return err } @@ -192,7 +195,7 @@ func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode perm.Acces } // DeleteCollaboration removes collaboration relation between the user and repository. -func (repo *Repository) DeleteCollaboration(uid int64) (err error) { +func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) { collaboration := &Collaboration{ RepoID: repo.ID, UserID: uid, @@ -208,7 +211,7 @@ func (repo *Repository) DeleteCollaboration(uid int64) (err error) { if has, err := sess.Delete(collaboration); err != nil || has == 0 { return err - } else if err = repo.recalculateAccesses(sess); err != nil { + } else if err = recalculateAccesses(ctx, repo); err != nil { return err } @@ -216,29 +219,29 @@ func (repo *Repository) DeleteCollaboration(uid int64) (err error) { return err } - if err = repo.reconsiderWatches(sess, uid); err != nil { + if err = reconsiderWatches(ctx, repo, uid); err != nil { return err } // Unassign a user from any issue (s)he has been assigned to in the repository - if err := repo.reconsiderIssueAssignees(sess, uid); err != nil { + if err := reconsiderRepoIssuesAssignee(ctx, repo, uid); err != nil { return err } return committer.Commit() } -func (repo *Repository) reconsiderIssueAssignees(e db.Engine, uid int64) error { - user, err := user_model.GetUserByIDEngine(e, uid) +func reconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Repository, uid int64) error { + user, err := user_model.GetUserByIDEngine(db.GetEngine(ctx), uid) if err != nil { return err } - if canAssigned, err := canBeAssigned(e, user, repo, true); err != nil || canAssigned { + if canAssigned, err := canBeAssigned(ctx, user, repo, true); err != nil || canAssigned { return err } - if _, err := e.Where(builder.Eq{"assignee_id": uid}). + if _, err := db.GetEngine(ctx).Where(builder.Eq{"assignee_id": uid}). In("issue_id", builder.Select("id").From("issue").Where(builder.Eq{"repo_id": repo.ID})). Delete(&IssueAssignees{}); err != nil { return fmt.Errorf("Could not delete assignee[%d] %v", uid, err) @@ -246,11 +249,11 @@ func (repo *Repository) reconsiderIssueAssignees(e db.Engine, uid int64) error { return nil } -func (repo *Repository) reconsiderWatches(e db.Engine, uid int64) error { - if has, err := hasAccess(e, uid, repo); err != nil || has { +func reconsiderWatches(ctx context.Context, repo *repo_model.Repository, uid int64) error { + if has, err := hasAccess(ctx, uid, repo); err != nil || has { return err } - + e := db.GetEngine(ctx) if err := watchRepo(e, uid, repo.ID, false); err != nil { return err } @@ -259,7 +262,7 @@ func (repo *Repository) reconsiderWatches(e db.Engine, uid int64) error { return removeIssueWatchersByRepoID(e, uid, repo.ID) } -func (repo *Repository) getRepoTeams(e db.Engine) (teams []*Team, err error) { +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). @@ -269,12 +272,12 @@ func (repo *Repository) getRepoTeams(e db.Engine) (teams []*Team, err error) { } // GetRepoTeams gets the list of teams that has access to the repository -func (repo *Repository) GetRepoTeams() ([]*Team, error) { - return repo.getRepoTeams(db.GetEngine(db.DefaultContext)) +func GetRepoTeams(repo *repo_model.Repository) ([]*Team, error) { + return getRepoTeams(db.GetEngine(db.DefaultContext), repo) } // IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository -func (repo *Repository) IsOwnerMemberCollaborator(userID int64) (bool, error) { +func IsOwnerMemberCollaborator(repo *repo_model.Repository, userID int64) (bool, error) { if repo.OwnerID == userID { return true, nil } diff --git a/models/repo_collaboration_test.go b/models/repo_collaboration_test.go index 94df6c27b3..8b4c712f07 100644 --- a/models/repo_collaboration_test.go +++ b/models/repo_collaboration_test.go @@ -9,6 +9,7 @@ import ( "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/unittest" user_model "code.gitea.io/gitea/models/user" @@ -19,11 +20,11 @@ func TestRepository_AddCollaborator(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(repoID, userID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) - assert.NoError(t, repo.GetOwner()) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + assert.NoError(t, repo.GetOwner(db.DefaultContext)) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}).(*user_model.User) - assert.NoError(t, repo.AddCollaborator(user)) - unittest.CheckConsistencyFor(t, &Repository{ID: repoID}, &user_model.User{ID: userID}) + assert.NoError(t, AddCollaborator(repo, user)) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) } testSuccess(1, 4) testSuccess(1, 4) @@ -33,8 +34,8 @@ func TestRepository_AddCollaborator(t *testing.T) { func TestRepository_GetCollaborators(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) - collaborators, err := repo.GetCollaborators(db.ListOptions{}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + collaborators, err := GetCollaborators(repo.ID, db.ListOptions{}) assert.NoError(t, err) expectedLen, err := db.GetEngine(db.DefaultContext).Count(&Collaboration{RepoID: repoID}) assert.NoError(t, err) @@ -54,8 +55,8 @@ func TestRepository_IsCollaborator(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID, userID int64, expected bool) { - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) - actual, err := repo.IsCollaborator(userID) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + actual, err := IsCollaborator(repo.ID, userID) assert.NoError(t, err) assert.Equal(t, expected, actual) } @@ -68,8 +69,8 @@ func TestRepository_IsCollaborator(t *testing.T) { func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) - assert.NoError(t, repo.ChangeCollaborationAccessMode(4, perm.AccessModeAdmin)) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + assert.NoError(t, ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) collaboration := unittest.AssertExistsAndLoadBean(t, &Collaboration{RepoID: repo.ID, UserID: 4}).(*Collaboration) assert.EqualValues(t, perm.AccessModeAdmin, collaboration.Mode) @@ -77,23 +78,23 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { access := unittest.AssertExistsAndLoadBean(t, &Access{UserID: 4, RepoID: repo.ID}).(*Access) assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) - assert.NoError(t, repo.ChangeCollaborationAccessMode(4, perm.AccessModeAdmin)) + assert.NoError(t, ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) - assert.NoError(t, repo.ChangeCollaborationAccessMode(unittest.NonexistentID, perm.AccessModeAdmin)) + assert.NoError(t, ChangeCollaborationAccessMode(repo, unittest.NonexistentID, perm.AccessModeAdmin)) - unittest.CheckConsistencyFor(t, &Repository{ID: repo.ID}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) } func TestRepository_DeleteCollaboration(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) - assert.NoError(t, repo.GetOwner()) - assert.NoError(t, repo.DeleteCollaboration(4)) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + assert.NoError(t, repo.GetOwner(db.DefaultContext)) + assert.NoError(t, DeleteCollaboration(repo, 4)) unittest.AssertNotExistsBean(t, &Collaboration{RepoID: repo.ID, UserID: 4}) - assert.NoError(t, repo.DeleteCollaboration(4)) + assert.NoError(t, DeleteCollaboration(repo, 4)) unittest.AssertNotExistsBean(t, &Collaboration{RepoID: repo.ID, UserID: 4}) - unittest.CheckConsistencyFor(t, &Repository{ID: repo.ID}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) } diff --git a/models/repo_generate.go b/models/repo_generate.go index cef5fa7928..6b5b8e5bc1 100644 --- a/models/repo_generate.go +++ b/models/repo_generate.go @@ -12,6 +12,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" @@ -70,7 +71,7 @@ func (gt GiteaTemplate) Globs() []glob.Glob { } // GenerateTopics generates topics from a template repository -func GenerateTopics(ctx context.Context, templateRepo, generateRepo *Repository) error { +func GenerateTopics(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { for _, topic := range templateRepo.Topics { if _, err := addTopicByNameToRepo(db.GetEngine(ctx), generateRepo.ID, topic); err != nil { return err @@ -80,7 +81,7 @@ func GenerateTopics(ctx context.Context, templateRepo, generateRepo *Repository) } // GenerateGitHooks generates git hooks from a template repository -func GenerateGitHooks(ctx context.Context, templateRepo, generateRepo *Repository) error { +func GenerateGitHooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { generateGitRepo, err := git.OpenRepository(generateRepo.RepoPath()) if err != nil { return err @@ -113,7 +114,7 @@ func GenerateGitHooks(ctx context.Context, templateRepo, generateRepo *Repositor } // GenerateWebhooks generates webhooks from a template repository -func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *Repository) error { +func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { templateWebhooks, err := webhook.ListWebhooksByOpts(&webhook.ListWebhookOptions{RepoID: templateRepo.ID}) if err != nil { return err @@ -141,7 +142,7 @@ func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *Repositor } // GenerateAvatar generates the avatar from a template repository -func GenerateAvatar(ctx context.Context, templateRepo, generateRepo *Repository) error { +func GenerateAvatar(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { generateRepo.Avatar = strings.Replace(templateRepo.Avatar, strconv.FormatInt(templateRepo.ID, 10), strconv.FormatInt(generateRepo.ID, 10), 1) if _, err := storage.Copy(storage.RepoAvatars, generateRepo.CustomAvatarRelativePath(), storage.RepoAvatars, templateRepo.CustomAvatarRelativePath()); err != nil { return err @@ -151,7 +152,7 @@ func GenerateAvatar(ctx context.Context, templateRepo, generateRepo *Repository) } // GenerateIssueLabels generates issue labels from a template repository -func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *Repository) error { +func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { templateLabels, err := getLabelsByRepoID(db.GetEngine(ctx), templateRepo.ID, "", db.ListOptions{}) if err != nil { return err diff --git a/models/repo_list.go b/models/repo_list.go index dbcf0609bd..02440bec93 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -25,7 +26,7 @@ import ( const RepositoryListDefaultPageSize = 64 // RepositoryList contains a list of repositories -type RepositoryList []*Repository +type RepositoryList []*repo_model.Repository func (repos RepositoryList) Len() int { return len(repos) @@ -40,7 +41,7 @@ func (repos RepositoryList) Swap(i, j int) { } // RepositoryListOfMap make list from values of map -func RepositoryListOfMap(repoMap map[int64]*Repository) RepositoryList { +func RepositoryListOfMap(repoMap map[int64]*repo_model.Repository) RepositoryList { return RepositoryList(valuesRepository(repoMap)) } @@ -69,14 +70,14 @@ func (repos RepositoryList) loadAttributes(e db.Engine) error { } // Load primary language. - stats := make(LanguageStatList, 0, len(repos)) + stats := make(repo_model.LanguageStatList, 0, len(repos)) if err := e. Where("`is_primary` = ? AND `language` != ?", true, "other"). In("`repo_id`", repoIDs). Find(&stats); err != nil { return fmt.Errorf("find primary languages: %v", err) } - stats.loadAttributes() + stats.LoadAttributes() for i := range repos { for _, st := range stats { if st.RepoID == repos[i].ID { @@ -94,46 +95,6 @@ func (repos RepositoryList) LoadAttributes() error { return repos.loadAttributes(db.GetEngine(db.DefaultContext)) } -// MirrorRepositoryList contains the mirror repositories -type MirrorRepositoryList []*Repository - -func (repos MirrorRepositoryList) loadAttributes(e db.Engine) error { - if len(repos) == 0 { - return nil - } - - // Load mirrors. - repoIDs := make([]int64, 0, len(repos)) - for i := range repos { - if !repos[i].IsMirror { - continue - } - - repoIDs = append(repoIDs, repos[i].ID) - } - mirrors := make([]*Mirror, 0, len(repoIDs)) - if err := e. - Where("id > 0"). - In("repo_id", repoIDs). - Find(&mirrors); err != nil { - return fmt.Errorf("find mirrors: %v", err) - } - - set := make(map[int64]*Mirror) - for i := range mirrors { - set[mirrors[i].RepoID] = mirrors[i] - } - for i := range repos { - repos[i].Mirror = set[repos[i].ID] - } - return nil -} - -// LoadAttributes loads the attributes for the given MirrorRepositoryList -func (repos MirrorRepositoryList) LoadAttributes() error { - return repos.loadAttributes(db.GetEngine(db.DefaultContext)) -} - // SearchRepoOptions holds the search options type SearchRepoOptions struct { db.ListOptions @@ -392,7 +353,7 @@ func searchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (db var err error count, err = sess. Where(cond). - Count(new(Repository)) + Count(new(repo_model.Repository)) if err != nil { return nil, 0, fmt.Errorf("Count: %v", err) } @@ -502,3 +463,31 @@ func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) { } return repoIDs, nil } + +// GetUserRepositories returns a list of repositories of given user. +func GetUserRepositories(opts *SearchRepoOptions) ([]*repo_model.Repository, int64, error) { + if len(opts.OrderBy) == 0 { + opts.OrderBy = "updated_unix DESC" + } + + cond := builder.NewCond() + cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID}) + if !opts.Private { + cond = cond.And(builder.Eq{"is_private": false}) + } + + if opts.LowerNames != nil && len(opts.LowerNames) > 0 { + cond = cond.And(builder.In("lower_name", opts.LowerNames)) + } + + sess := db.GetEngine(db.DefaultContext) + + count, err := sess.Where(cond).Count(new(repo_model.Repository)) + if err != nil { + return nil, 0, fmt.Errorf("Count: %v", err) + } + + sess = sess.Where(cond).OrderBy(opts.OrderBy.String()) + repos := make([]*repo_model.Repository, 0, opts.PageSize) + return repos, count, db.SetSessionPagination(sess, opts).Find(&repos) +} diff --git a/models/repo_permission.go b/models/repo_permission.go index 61d3d24e37..3dc8db92b8 100644 --- a/models/repo_permission.go +++ b/models/repo_permission.go @@ -5,10 +5,12 @@ package models import ( + "context" "fmt" "code.gitea.io/gitea/models/db" perm_model "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" @@ -17,7 +19,7 @@ import ( // Permission contains all the permissions related variables to a repository for a user type Permission struct { AccessMode perm_model.AccessMode - Units []*RepoUnit + Units []*repo_model.RepoUnit UnitsMode map[unit.Type]perm_model.AccessMode } @@ -142,11 +144,11 @@ func (p *Permission) ColorFormat(s fmt.State) { } // GetUserRepoPermission returns the user permissions to the repository -func GetUserRepoPermission(repo *Repository, user *user_model.User) (Permission, error) { - return getUserRepoPermission(db.GetEngine(db.DefaultContext), repo, user) +func GetUserRepoPermission(repo *repo_model.Repository, user *user_model.User) (Permission, error) { + return getUserRepoPermission(db.DefaultContext, repo, user) } -func getUserRepoPermission(e db.Engine, repo *Repository, user *user_model.User) (perm Permission, err error) { +func getUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (perm Permission, err error) { if log.IsTrace() { defer func() { if user == nil { @@ -168,26 +170,28 @@ func getUserRepoPermission(e db.Engine, repo *Repository, user *user_model.User) return } - var isCollaborator bool + e := db.GetEngine(ctx) + + var is bool if user != nil { - isCollaborator, err = repo.isCollaborator(e, user.ID) + is, err = isCollaborator(e, repo.ID, user.ID) if err != nil { return perm, err } } - if err = repo.getOwner(e); err != nil { + if err = repo.GetOwner(ctx); err != nil { return } // Prevent strangers from checking out public repo of private organization/users // Allow user if they are collaborator of a repo within a private user or a private organization but not a member of the organization itself - if !hasOrgOrUserVisible(e, repo.Owner, user) && !isCollaborator { + if !hasOrgOrUserVisible(e, repo.Owner, user) && !is { perm.AccessMode = perm_model.AccessModeNone return } - if err = repo.getUnits(e); err != nil { + if err = repo.LoadUnits(ctx); err != nil { return } @@ -211,7 +215,7 @@ func getUserRepoPermission(e db.Engine, repo *Repository, user *user_model.User) return } - if err = repo.getOwner(e); err != nil { + if err = repo.GetOwner(ctx); err != nil { return } if !repo.Owner.IsOrganization() { @@ -221,7 +225,7 @@ func getUserRepoPermission(e db.Engine, repo *Repository, user *user_model.User) perm.UnitsMode = make(map[unit.Type]perm_model.AccessMode) // Collaborators on organization - if isCollaborator { + if is { for _, u := range repo.Units { perm.UnitsMode[u.Type] = perm.AccessMode } @@ -263,7 +267,7 @@ func getUserRepoPermission(e db.Engine, repo *Repository, user *user_model.User) } // remove no permission units - perm.Units = make([]*RepoUnit, 0, len(repo.Units)) + perm.Units = make([]*repo_model.RepoUnit, 0, len(repo.Units)) for t := range perm.UnitsMode { for _, u := range repo.Units { if u.Type == t { @@ -276,18 +280,16 @@ func getUserRepoPermission(e db.Engine, repo *Repository, user *user_model.User) } // IsUserRealRepoAdmin check if this user is real repo admin -func IsUserRealRepoAdmin(repo *Repository, user *user_model.User) (bool, error) { +func IsUserRealRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bool, error) { if repo.OwnerID == user.ID { return true, nil } - sess := db.GetEngine(db.DefaultContext) - - if err := repo.getOwner(sess); err != nil { + if err := repo.GetOwner(db.DefaultContext); err != nil { return false, err } - accessMode, err := accessLevel(sess, user, repo) + accessMode, err := accessLevel(db.GetEngine(db.DefaultContext), user, repo) if err != nil { return false, err } @@ -296,11 +298,11 @@ func IsUserRealRepoAdmin(repo *Repository, user *user_model.User) (bool, error) } // IsUserRepoAdmin return true if user has admin right of a repo -func IsUserRepoAdmin(repo *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) } -func isUserRepoAdmin(e db.Engine, repo *Repository, user *user_model.User) (bool, error) { +func isUserRepoAdmin(e db.Engine, repo *repo_model.Repository, user *user_model.User) (bool, error) { if user == nil || repo == nil { return false, nil } @@ -331,62 +333,62 @@ func isUserRepoAdmin(e db.Engine, repo *Repository, user *user_model.User) (bool // AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the // user does not have access. -func AccessLevel(user *user_model.User, repo *Repository) (perm_model.AccessMode, error) { - return accessLevelUnit(db.GetEngine(db.DefaultContext), user, repo, unit.TypeCode) +func AccessLevel(user *user_model.User, repo *repo_model.Repository) (perm_model.AccessMode, error) { + return accessLevelUnit(db.DefaultContext, user, repo, unit.TypeCode) } // AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the // user does not have access. -func AccessLevelUnit(user *user_model.User, repo *Repository, unitType unit.Type) (perm_model.AccessMode, error) { - return accessLevelUnit(db.GetEngine(db.DefaultContext), user, repo, unitType) +func AccessLevelUnit(user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { + return accessLevelUnit(db.DefaultContext, user, repo, unitType) } -func accessLevelUnit(e db.Engine, user *user_model.User, repo *Repository, unitType unit.Type) (perm_model.AccessMode, error) { - perm, err := getUserRepoPermission(e, repo, user) +func accessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { + perm, err := getUserRepoPermission(ctx, repo, user) if err != nil { return perm_model.AccessModeNone, err } return perm.UnitAccessMode(unitType), nil } -func hasAccessUnit(e db.Engine, user *user_model.User, repo *Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { - mode, err := accessLevelUnit(e, user, repo, unitType) +func hasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { + mode, err := accessLevelUnit(ctx, user, repo, unitType) return testMode <= mode, err } // HasAccessUnit returns true if user has testMode to the unit of the repository -func HasAccessUnit(user *user_model.User, repo *Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { - return hasAccessUnit(db.GetEngine(db.DefaultContext), user, repo, unitType, testMode) +func HasAccessUnit(user *user_model.User, repo *repo_model.Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { + return hasAccessUnit(db.DefaultContext, user, repo, unitType, testMode) } // CanBeAssigned return true if user can be assigned to issue or pull requests in repo // Currently any write access (code, issues or pr's) is assignable, to match assignee list in user interface. // FIXME: user could send PullRequest also could be assigned??? -func CanBeAssigned(user *user_model.User, repo *Repository, isPull bool) (bool, error) { - return canBeAssigned(db.GetEngine(db.DefaultContext), user, repo, isPull) +func CanBeAssigned(user *user_model.User, repo *repo_model.Repository, isPull bool) (bool, error) { + return canBeAssigned(db.DefaultContext, user, repo, isPull) } -func canBeAssigned(e db.Engine, user *user_model.User, repo *Repository, _ bool) (bool, error) { +func canBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.Repository, _ bool) (bool, error) { if user.IsOrganization() { return false, fmt.Errorf("Organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID) } - perm, err := getUserRepoPermission(e, repo, user) + perm, err := getUserRepoPermission(ctx, repo, user) if err != nil { return false, err } return perm.CanAccessAny(perm_model.AccessModeWrite, unit.TypeCode, unit.TypeIssues, unit.TypePullRequests), nil } -func hasAccess(e db.Engine, userID int64, repo *Repository) (bool, error) { +func hasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (bool, error) { var user *user_model.User var err error if userID > 0 { - user, err = user_model.GetUserByIDEngine(e, userID) + user, err = user_model.GetUserByIDEngine(db.GetEngine(ctx), userID) if err != nil { return false, err } } - perm, err := getUserRepoPermission(e, repo, user) + perm, err := getUserRepoPermission(ctx, repo, user) if err != nil { return false, err } @@ -394,15 +396,15 @@ func hasAccess(e db.Engine, userID int64, repo *Repository) (bool, error) { } // HasAccess returns true if user has access to repo -func HasAccess(userID int64, repo *Repository) (bool, error) { - return hasAccess(db.GetEngine(db.DefaultContext), userID, repo) +func HasAccess(userID int64, repo *repo_model.Repository) (bool, error) { + return hasAccess(db.DefaultContext, userID, repo) } // FilterOutRepoIdsWithoutUnitAccess filter out repos where user has no access to repositories func FilterOutRepoIdsWithoutUnitAccess(u *user_model.User, repoIDs []int64, units ...unit.Type) ([]int64, error) { i := 0 for _, rID := range repoIDs { - repo, err := GetRepositoryByID(rID) + repo, err := repo_model.GetRepositoryByID(rID) if err != nil { return nil, err } diff --git a/models/repo_permission_test.go b/models/repo_permission_test.go index 795b5f2115..f2664d8101 100644 --- a/models/repo_permission_test.go +++ b/models/repo_permission_test.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" perm_model "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/unittest" user_model "code.gitea.io/gitea/models/user" @@ -20,8 +21,8 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // public non-organization repo - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) - assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext))) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) @@ -33,7 +34,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { } // change to collaborator - assert.NoError(t, repo.AddCollaborator(user)) + assert.NoError(t, AddCollaborator(repo, user)) perm, err = GetUserRepoPermission(repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -73,8 +74,8 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // private non-organization repo - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) - assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext))) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) @@ -86,7 +87,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, repo.AddCollaborator(user)) + assert.NoError(t, AddCollaborator(repo, user)) perm, err = GetUserRepoPermission(repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -94,7 +95,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo.ChangeCollaborationAccessMode(user.ID, perm_model.AccessModeRead)) + assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) perm, err = GetUserRepoPermission(repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -125,8 +126,8 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // public organization repo - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 32}).(*Repository) - assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext))) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32}).(*repo_model.Repository) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) @@ -138,7 +139,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, repo.AddCollaborator(user)) + assert.NoError(t, AddCollaborator(repo, user)) perm, err = GetUserRepoPermission(repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -146,7 +147,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo.ChangeCollaborationAccessMode(user.ID, perm_model.AccessModeRead)) + assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) perm, err = GetUserRepoPermission(repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -187,8 +188,8 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // private organization repo - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 24}).(*Repository) - assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext))) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}).(*repo_model.Repository) + assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) @@ -200,7 +201,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, repo.AddCollaborator(user)) + assert.NoError(t, AddCollaborator(repo, user)) perm, err = GetUserRepoPermission(repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -208,7 +209,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo.ChangeCollaborationAccessMode(user.ID, perm_model.AccessModeRead)) + assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) perm, err = GetUserRepoPermission(repo, user) assert.NoError(t, err) for _, unit := range repo.Units { diff --git a/models/repo_redirect_test.go b/models/repo_redirect_test.go index 6e5b9fc080..c6d471448e 100644 --- a/models/repo_redirect_test.go +++ b/models/repo_redirect_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -28,7 +29,7 @@ func TestNewRepoRedirect(t *testing.T) { // redirect to a completely new name assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) assert.NoError(t, newRepoRedirect(db.GetEngine(db.DefaultContext), repo.OwnerID, repo.ID, repo.Name, "newreponame")) unittest.AssertExistsAndLoadBean(t, &RepoRedirect{ @@ -47,7 +48,7 @@ func TestNewRepoRedirect2(t *testing.T) { // redirect to previously used name assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) assert.NoError(t, newRepoRedirect(db.GetEngine(db.DefaultContext), repo.OwnerID, repo.ID, repo.Name, "oldrepo1")) unittest.AssertExistsAndLoadBean(t, &RepoRedirect{ @@ -66,7 +67,7 @@ func TestNewRepoRedirect3(t *testing.T) { // redirect for a previously-unredirected repo assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) assert.NoError(t, newRepoRedirect(db.GetEngine(db.DefaultContext), repo.OwnerID, repo.ID, repo.Name, "newreponame")) unittest.AssertExistsAndLoadBean(t, &RepoRedirect{ diff --git a/models/repo_sign.go b/models/repo_sign.go index f30ba4748c..1c736a62da 100644 --- a/models/repo_sign.go +++ b/models/repo_sign.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/login" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" @@ -144,7 +145,7 @@ Loop: } // SignWikiCommit determines if we should sign the commits to this repository wiki -func (repo *Repository) SignWikiCommit(u *user_model.User) (bool, string, *git.Signature, error) { +func SignWikiCommit(repo *repo_model.Repository, u *user_model.User) (bool, string, *git.Signature, error) { rules := signingModeFromStrings(setting.Repository.Signing.Wiki) signingKey, sig := SigningKey(repo.WikiPath()) if signingKey == "" { @@ -197,7 +198,7 @@ Loop: } // SignCRUDAction determines if we should sign a CRUD commit to this repository -func (repo *Repository) SignCRUDAction(u *user_model.User, tmpBasePath, parentCommit string) (bool, string, *git.Signature, error) { +func SignCRUDAction(repo *repo_model.Repository, u *user_model.User, tmpBasePath, parentCommit string) (bool, string, *git.Signature, error) { rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions) signingKey, sig := SigningKey(repo.RepoPath()) if signingKey == "" { diff --git a/models/repo_test.go b/models/repo_test.go index e6aaedaae6..72a2977343 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -25,7 +25,7 @@ import ( func TestMetas(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := &Repository{Name: "testRepo"} + repo := &repo_model.Repository{Name: "testRepo"} repo.Owner = &user_model.User{Name: "testOwner"} repo.OwnerName = repo.Owner.Name @@ -35,15 +35,15 @@ func TestMetas(t *testing.T) { assert.Equal(t, "testRepo", metas["repo"]) assert.Equal(t, "testOwner", metas["user"]) - externalTracker := RepoUnit{ + externalTracker := repo_model.RepoUnit{ Type: unit.TypeExternalTracker, - Config: &ExternalTrackerConfig{ + Config: &repo_model.ExternalTrackerConfig{ ExternalTrackerFormat: "https://someurl.com/{user}/{repo}/{issue}", }, } testSuccess := func(expectedStyle string) { - repo.Units = []*RepoUnit{&externalTracker} + repo.Units = []*repo_model.RepoUnit{&externalTracker} repo.RenderingMetas = nil metas := repo.ComposeMetas() assert.Equal(t, expectedStyle, metas["style"]) @@ -60,7 +60,7 @@ func TestMetas(t *testing.T) { externalTracker.ExternalTrackerConfig().ExternalTrackerStyle = markup.IssueNameStyleNumeric testSuccess(markup.IssueNameStyleNumeric) - repo, err := GetRepositoryByID(3) + repo, err := repo_model.GetRepositoryByID(3) assert.NoError(t, err) metas = repo.ComposeMetas() @@ -70,40 +70,11 @@ func TestMetas(t *testing.T) { assert.Equal(t, ",owners,team1,", metas["teams"]) } -func TestGetRepositoryCount(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - count, err1 := GetRepositoryCount(db.DefaultContext, 10) - privateCount, err2 := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)}) - publicCount, err3 := GetPublicRepositoryCount(&user_model.User{ID: int64(10)}) - assert.NoError(t, err1) - assert.NoError(t, err2) - assert.NoError(t, err3) - assert.Equal(t, int64(3), count) - assert.Equal(t, privateCount+publicCount, count) -} - -func TestGetPublicRepositoryCount(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - count, err := GetPublicRepositoryCount(&user_model.User{ID: int64(10)}) - assert.NoError(t, err) - assert.Equal(t, int64(1), count) -} - -func TestGetPrivateRepositoryCount(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - count, err := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)}) - assert.NoError(t, err) - assert.Equal(t, int64(2), count) -} - func TestUpdateRepositoryVisibilityChanged(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // Get sample repo and change visibility - repo, err := GetRepositoryByID(9) + repo, err := repo_model.GetRepositoryByID(9) assert.NoError(t, err) repo.IsPrivate = true @@ -123,24 +94,24 @@ func TestGetUserFork(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // User13 has repo 11 forked from repo10 - repo, err := GetRepositoryByID(10) + repo, err := repo_model.GetRepositoryByID(10) assert.NoError(t, err) assert.NotNil(t, repo) - repo, err = repo.GetUserFork(13) + repo, err = GetUserFork(repo.ID, 13) assert.NoError(t, err) assert.NotNil(t, repo) - repo, err = GetRepositoryByID(9) + repo, err = repo_model.GetRepositoryByID(9) assert.NoError(t, err) assert.NotNil(t, repo) - repo, err = repo.GetUserFork(13) + repo, err = GetUserFork(repo.ID, 13) assert.NoError(t, err) assert.Nil(t, repo) } func TestRepoAPIURL(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL()) } @@ -152,9 +123,9 @@ func TestUploadAvatar(t *testing.T) { png.Encode(&buff, myImage) assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) - err := repo.UploadAvatar(buff.Bytes()) + err := UploadRepoAvatar(repo, buff.Bytes()) assert.NoError(t, err) assert.Equal(t, fmt.Sprintf("%d-%x", 10, md5.Sum(buff.Bytes())), repo.Avatar) } @@ -166,9 +137,9 @@ func TestUploadBigAvatar(t *testing.T) { png.Encode(&buff, myImage) assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) - err := repo.UploadAvatar(buff.Bytes()) + err := UploadRepoAvatar(repo, buff.Bytes()) assert.Error(t, err) } @@ -179,12 +150,12 @@ func TestDeleteAvatar(t *testing.T) { png.Encode(&buff, myImage) assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) - err := repo.UploadAvatar(buff.Bytes()) + err := UploadRepoAvatar(repo, buff.Bytes()) assert.NoError(t, err) - err = repo.DeleteAvatar() + err = DeleteRepoAvatar(repo) assert.NoError(t, err) assert.Equal(t, "", repo.Avatar) @@ -200,15 +171,15 @@ func TestRepoGetReviewers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // test public repo - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - reviewers, err := repo1.GetReviewers(2, 2) + reviewers, err := GetReviewers(repo1, 2, 2) assert.NoError(t, err) assert.Len(t, reviewers, 4) // test private repo - repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) - reviewers, err = repo2.GetReviewers(2, 2) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + reviewers, err = GetReviewers(repo2, 2, 2) assert.NoError(t, err) assert.Empty(t, reviewers) } @@ -216,13 +187,13 @@ func TestRepoGetReviewers(t *testing.T) { func TestRepoGetReviewerTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) - teams, err := repo2.GetReviewerTeams() + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + teams, err := GetReviewerTeams(repo2) assert.NoError(t, err) assert.Empty(t, teams) - repo3 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) - teams, err = repo3.GetReviewerTeams() + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + teams, err = GetReviewerTeams(repo3) assert.NoError(t, err) assert.Len(t, teams, 2) } @@ -232,12 +203,12 @@ func TestLinkedRepository(t *testing.T) { testCases := []struct { name string attachID int64 - expectedRepo *Repository + expectedRepo *repo_model.Repository expectedUnitType unit.Type }{ - {"LinkedIssue", 1, &Repository{ID: 1}, unit.TypeIssues}, - {"LinkedComment", 3, &Repository{ID: 1}, unit.TypePullRequests}, - {"LinkedRelease", 9, &Repository{ID: 1}, unit.TypeReleases}, + {"LinkedIssue", 1, &repo_model.Repository{ID: 1}, unit.TypeIssues}, + {"LinkedComment", 3, &repo_model.Repository{ID: 1}, unit.TypePullRequests}, + {"LinkedRelease", 9, &repo_model.Repository{ID: 1}, unit.TypeReleases}, {"Notlinked", 10, nil, -1}, } for _, tc := range testCases { diff --git a/models/repo_transfer.go b/models/repo_transfer.go index 9918a10d76..398ed0755a 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -9,6 +9,7 @@ import ( "os" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" @@ -96,7 +97,7 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool { // GetPendingRepositoryTransfer fetches the most recent and ongoing transfer // process for the repository -func GetPendingRepositoryTransfer(repo *Repository) (*RepoTransfer, error) { +func GetPendingRepositoryTransfer(repo *repo_model.Repository) (*RepoTransfer, error) { transfer := new(RepoTransfer) has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repo.ID).Get(transfer) @@ -118,7 +119,7 @@ func deleteRepositoryTransfer(e db.Engine, repoID int64) error { // CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry, // thus cancel the transfer process. -func CancelRepositoryTransfer(repo *Repository) error { +func CancelRepositoryTransfer(repo *repo_model.Repository) error { ctx, committer, err := db.TxContext() if err != nil { return err @@ -126,7 +127,7 @@ func CancelRepositoryTransfer(repo *Repository) error { defer committer.Close() sess := db.GetEngine(ctx) - repo.Status = RepositoryReady + repo.Status = repo_model.RepositoryReady if err := updateRepositoryCols(sess, repo, "status"); err != nil { return err } @@ -139,11 +140,11 @@ func CancelRepositoryTransfer(repo *Repository) error { } // TestRepositoryReadyForTransfer make sure repo is ready to transfer -func TestRepositoryReadyForTransfer(status RepositoryStatus) error { +func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error { switch status { - case RepositoryBeingMigrated: + case repo_model.RepositoryBeingMigrated: return fmt.Errorf("repo is not ready, currently migrating") - case RepositoryPendingTransfer: + case repo_model.RepositoryPendingTransfer: return ErrRepoTransferInProgress{} } return nil @@ -159,7 +160,7 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int defer committer.Close() sess := db.GetEngine(ctx) - repo, err := getRepositoryByID(sess, repoID) + repo, err := repo_model.GetRepositoryByIDCtx(ctx, repoID) if err != nil { return err } @@ -169,13 +170,13 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int return err } - repo.Status = RepositoryPendingTransfer + repo.Status = repo_model.RepositoryPendingTransfer if err := updateRepositoryCols(sess, repo, "status"); err != nil { return err } // Check if new owner has repository with same name. - if has, err := isRepositoryExist(sess, newOwner, repo.Name); err != nil { + if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { return ErrRepoAlreadyExist{newOwner.LowerName, repo.Name} @@ -202,7 +203,7 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int } // TransferOwnership transfers all corresponding repository items from old user to new one. -func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Repository) (err error) { +func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_model.Repository) (err error) { repoRenamed := false wikiRenamed := false oldOwnerName := doer.Name @@ -218,14 +219,16 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Reposit } if repoRenamed { - if err := util.Rename(RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name)); err != nil { - log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name), err) + if err := util.Rename(repo_model.RepoPath(newOwnerName, repo.Name), repo_model.RepoPath(oldOwnerName, repo.Name)); err != nil { + log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, + repo_model.RepoPath(newOwnerName, repo.Name), repo_model.RepoPath(oldOwnerName, repo.Name), err) } } if wikiRenamed { - if err := util.Rename(WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name)); err != nil { - log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name), err) + if err := util.Rename(repo_model.WikiPath(newOwnerName, repo.Name), repo_model.WikiPath(oldOwnerName, repo.Name)); err != nil { + log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, + repo_model.WikiPath(newOwnerName, repo.Name), repo_model.WikiPath(oldOwnerName, repo.Name), err) } } @@ -250,7 +253,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Reposit newOwnerName = newOwner.Name // ensure capitalisation matches // Check if new owner has repository with same name. - if has, err := isRepositoryExist(sess, newOwner, repo.Name); err != nil { + if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { return ErrRepoAlreadyExist{newOwnerName, repo.Name} @@ -271,7 +274,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Reposit } // Remove redundant collaborators. - collaborators, err := repo.getCollaborators(sess, db.ListOptions{}) + collaborators, err := getCollaborators(sess, repo.ID, db.ListOptions{}) if err != nil { return fmt.Errorf("getCollaborators: %v", err) } @@ -316,12 +319,12 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Reposit } for _, t := range teams { if t.IncludesAllRepositories { - if err := t.addRepository(sess, repo); err != nil { + if err := t.addRepository(ctx, repo); err != nil { return fmt.Errorf("addRepository: %v", err) } } } - } else if err := repo.recalculateAccesses(sess); err != nil { + } else if err := recalculateAccesses(ctx, repo); err != nil { // Organization called this in addRepository method. return fmt.Errorf("recalculateAccesses: %v", err) } @@ -378,19 +381,19 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Reposit return fmt.Errorf("Failed to create dir %s: %v", dir, err) } - if err := util.Rename(RepoPath(oldOwner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil { + if err := util.Rename(repo_model.RepoPath(oldOwner.Name, repo.Name), repo_model.RepoPath(newOwner.Name, repo.Name)); err != nil { return fmt.Errorf("rename repository directory: %v", err) } repoRenamed = true // Rename remote wiki repository to new path and delete local copy. - wikiPath := WikiPath(oldOwner.Name, repo.Name) + wikiPath := repo_model.WikiPath(oldOwner.Name, repo.Name) if isExist, err := util.IsExist(wikiPath); err != nil { log.Error("Unable to check if %s exists. Error: %v", wikiPath, err) return err } else if isExist { - if err := util.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil { + if err := util.Rename(wikiPath, repo_model.WikiPath(newOwner.Name, repo.Name)); err != nil { return fmt.Errorf("rename repository wiki: %v", err) } wikiRenamed = true @@ -399,7 +402,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Reposit if err := deleteRepositoryTransfer(sess, repo.ID); err != nil { return fmt.Errorf("deleteRepositoryTransfer: %v", err) } - repo.Status = RepositoryReady + repo.Status = repo_model.RepositoryReady if err := updateRepositoryCols(sess, repo, "status"); err != nil { return err } diff --git a/models/repo_transfer_test.go b/models/repo_transfer_test.go index 1bde5628c1..9125bb8c8d 100644 --- a/models/repo_transfer_test.go +++ b/models/repo_transfer_test.go @@ -7,6 +7,7 @@ package models import ( "testing" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -17,7 +18,7 @@ func TestRepositoryTransfer(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) transfer, err := GetPendingRepositoryTransfer(repo) assert.NoError(t, err) diff --git a/models/repo_watch.go b/models/repo_watch.go index e225c945e9..6ae478d65f 100644 --- a/models/repo_watch.go +++ b/models/repo_watch.go @@ -5,9 +5,11 @@ package models import ( + "context" "fmt" "code.gitea.io/gitea/models/db" + 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/setting" @@ -166,9 +168,9 @@ func getRepoWatchersIDs(e db.Engine, repoID int64) ([]int64, error) { Find(&ids) } -// GetWatchers returns range of users watching given repository. -func (repo *Repository) GetWatchers(opts db.ListOptions) ([]*user_model.User, error) { - sess := db.GetEngine(db.DefaultContext).Where("watch.repo_id=?", repo.ID). +// GetRepoWatchers returns range of users watching given repository. +func GetRepoWatchers(repoID int64, opts db.ListOptions) ([]*user_model.User, error) { + sess := db.GetEngine(db.DefaultContext).Where("watch.repo_id=?", repoID). Join("LEFT", "watch", "`user`.id=`watch`.user_id"). And("`watch`.mode<>?", RepoWatchModeDont) if opts.Page > 0 { @@ -182,14 +184,16 @@ func (repo *Repository) GetWatchers(opts db.ListOptions) ([]*user_model.User, er return users, sess.Find(&users) } -func notifyWatchers(e db.Engine, actions ...*Action) error { +func notifyWatchers(ctx context.Context, actions ...*Action) error { var watchers []*Watch - var repo *Repository + var repo *repo_model.Repository var err error var permCode []bool var permIssue []bool var permPR []bool + e := db.GetEngine(ctx) + for _, act := range actions { repoChanged := repo == nil || repo.ID != act.RepoID @@ -212,7 +216,7 @@ func notifyWatchers(e db.Engine, actions ...*Action) error { repo = act.Repo // check repo owner exist. - if err := act.Repo.getOwner(e); err != nil { + if err := act.Repo.GetOwner(ctx); err != nil { return fmt.Errorf("can't get repo owner: %v", err) } } else if act.Repo == nil { @@ -240,7 +244,7 @@ func notifyWatchers(e db.Engine, actions ...*Action) error { permPR[i] = false continue } - perm, err := getUserRepoPermission(e, repo, user) + perm, err := getUserRepoPermission(ctx, repo, user) if err != nil { permCode[i] = false permIssue[i] = false @@ -286,7 +290,7 @@ func notifyWatchers(e db.Engine, actions ...*Action) error { // NotifyWatchers creates batch of actions for every watcher. func NotifyWatchers(actions ...*Action) error { - return notifyWatchers(db.GetEngine(db.DefaultContext), actions...) + return notifyWatchers(db.DefaultContext, actions...) } // NotifyWatchersActions creates batch of actions for every watcher. @@ -297,7 +301,7 @@ func NotifyWatchersActions(acts []*Action) error { } defer committer.Close() for _, act := range acts { - if err := notifyWatchers(db.GetEngine(ctx), act); err != nil { + if err := notifyWatchers(ctx, act); err != nil { return err } } diff --git a/models/repo_watch_test.go b/models/repo_watch_test.go index b7efcba71a..1a60521396 100644 --- a/models/repo_watch_test.go +++ b/models/repo_watch_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" @@ -33,17 +34,17 @@ func TestWatchRepo(t *testing.T) { assert.NoError(t, WatchRepo(userID, repoID, true)) unittest.AssertExistsAndLoadBean(t, &Watch{RepoID: repoID, UserID: userID}) - unittest.CheckConsistencyFor(t, &Repository{ID: repoID}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}) assert.NoError(t, WatchRepo(userID, repoID, false)) unittest.AssertNotExistsBean(t, &Watch{RepoID: repoID, UserID: userID}) - unittest.CheckConsistencyFor(t, &Repository{ID: repoID}) + unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}) } func TestGetWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) watches, err := GetWatchers(repo.ID) assert.NoError(t, err) // One watchers are inactive, thus minus 1 @@ -60,16 +61,16 @@ func TestGetWatchers(t *testing.T) { func TestRepository_GetWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - watchers, err := repo.GetWatchers(db.ListOptions{Page: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) for _, watcher := range watchers { unittest.AssertExistsAndLoadBean(t, &Watch{UserID: watcher.ID, RepoID: repo.ID}) } - repo = unittest.AssertExistsAndLoadBean(t, &Repository{ID: 9}).(*Repository) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 9}).(*repo_model.Repository) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, 0) } @@ -114,8 +115,8 @@ func TestNotifyWatchers(t *testing.T) { func TestWatchIfAuto(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - watchers, err := repo.GetWatchers(db.ListOptions{Page: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) @@ -125,13 +126,13 @@ func TestWatchIfAuto(t *testing.T) { // Must not add watch assert.NoError(t, WatchIfAuto(8, 1, true)) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch assert.NoError(t, WatchIfAuto(10, 1, true)) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) @@ -139,31 +140,31 @@ func TestWatchIfAuto(t *testing.T) { // Must not add watch assert.NoError(t, WatchIfAuto(8, 1, true)) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch assert.NoError(t, WatchIfAuto(12, 1, false)) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should add watch assert.NoError(t, WatchIfAuto(12, 1, true)) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount+1) // Should remove watch, inhibit from adding auto assert.NoError(t, WatchRepo(12, 1, false)) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Must not add watch assert.NoError(t, WatchIfAuto(12, 1, true)) - watchers, err = repo.GetWatchers(db.ListOptions{Page: 1}) + watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) } diff --git a/models/review.go b/models/review.go index eebf796876..eeb33611ce 100644 --- a/models/review.go +++ b/models/review.go @@ -5,6 +5,7 @@ package models import ( + "context" "fmt" "strings" @@ -85,20 +86,20 @@ func init() { db.RegisterModel(new(Review)) } -func (r *Review) loadCodeComments(e db.Engine) (err error) { +func (r *Review) loadCodeComments(ctx context.Context) (err error) { if r.CodeComments != nil { return } - if err = r.loadIssue(e); err != nil { + if err = r.loadIssue(db.GetEngine(ctx)); err != nil { return } - r.CodeComments, err = fetchCodeCommentsByReview(e, r.Issue, nil, r) + r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r) return } // LoadCodeComments loads CodeComments func (r *Review) LoadCodeComments() error { - return r.loadCodeComments(db.GetEngine(db.DefaultContext)) + return r.loadCodeComments(db.DefaultContext) } func (r *Review) loadIssue(e db.Engine) (err error) { @@ -136,11 +137,12 @@ func (r *Review) LoadReviewerTeam() error { return r.loadReviewerTeam(db.GetEngine(db.DefaultContext)) } -func (r *Review) loadAttributes(e db.Engine) (err error) { +func (r *Review) loadAttributes(ctx context.Context) (err error) { + e := db.GetEngine(ctx) if err = r.loadIssue(e); err != nil { return } - if err = r.loadCodeComments(e); err != nil { + if err = r.loadCodeComments(ctx); err != nil { return } if err = r.loadReviewer(e); err != nil { @@ -154,7 +156,7 @@ func (r *Review) loadAttributes(e db.Engine) (err error) { // LoadAttributes loads all attributes except CodeComments func (r *Review) LoadAttributes() error { - return r.loadAttributes(db.GetEngine(db.DefaultContext)) + return r.loadAttributes(db.DefaultContext) } func getReviewByID(e db.Engine, id int64) (*Review, error) { @@ -235,15 +237,15 @@ type CreateReviewOptions struct { // IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals) func IsOfficialReviewer(issue *Issue, reviewers ...*user_model.User) (bool, error) { - return isOfficialReviewer(db.GetEngine(db.DefaultContext), issue, reviewers...) + return isOfficialReviewer(db.DefaultContext, issue, reviewers...) } -func isOfficialReviewer(e db.Engine, issue *Issue, reviewers ...*user_model.User) (bool, error) { - pr, err := getPullRequestByIssueID(e, issue.ID) +func isOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_model.User) (bool, error) { + pr, err := getPullRequestByIssueID(db.GetEngine(ctx), issue.ID) if err != nil { return false, err } - if err = pr.loadProtectedBranch(e); err != nil { + if err = pr.loadProtectedBranch(ctx); err != nil { return false, err } if pr.ProtectedBranch == nil { @@ -251,7 +253,7 @@ func isOfficialReviewer(e db.Engine, issue *Issue, reviewers ...*user_model.User } for _, reviewer := range reviewers { - official, err := pr.ProtectedBranch.isUserOfficialReviewer(e, reviewer) + official, err := isUserOfficialReviewer(ctx, pr.ProtectedBranch, reviewer) if official || err != nil { return official, err } @@ -262,15 +264,15 @@ func isOfficialReviewer(e db.Engine, issue *Issue, reviewers ...*user_model.User // 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) { - return isOfficialReviewerTeam(db.GetEngine(db.DefaultContext), issue, team) + return isOfficialReviewerTeam(db.DefaultContext, issue, team) } -func isOfficialReviewerTeam(e db.Engine, issue *Issue, team *Team) (bool, error) { - pr, err := getPullRequestByIssueID(e, issue.ID) +func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *Team) (bool, error) { + pr, err := getPullRequestByIssueID(db.GetEngine(ctx), issue.ID) if err != nil { return false, err } - if err = pr.loadProtectedBranch(e); err != nil { + if err = pr.loadProtectedBranch(ctx); err != nil { return false, err } if pr.ProtectedBranch == nil { @@ -385,7 +387,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co if _, err := sess.Exec("UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, doer.ID); err != nil { return nil, nil, err } - if official, err = isOfficialReviewer(sess, issue, doer); err != nil { + if official, err = isOfficialReviewer(ctx, issue, doer); err != nil { return nil, nil, err } } @@ -403,7 +405,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co return nil, nil, err } } else { - if err := review.loadCodeComments(sess); err != nil { + if err := review.loadCodeComments(ctx); err != nil { return nil, nil, err } if reviewType != ReviewTypeApprove && len(review.CodeComments) == 0 && len(strings.TrimSpace(content)) == 0 { @@ -415,7 +417,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co if _, err := sess.Exec("UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, doer.ID); err != nil { return nil, nil, err } - if official, err = isOfficialReviewer(sess, issue, doer); err != nil { + if official, err = isOfficialReviewer(ctx, issue, doer); err != nil { return nil, nil, err } } @@ -647,7 +649,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, return nil, nil } - official, err := isOfficialReviewer(sess, issue, reviewer, doer) + official, err := isOfficialReviewer(ctx, issue, reviewer, doer) if err != nil { return nil, err } else if official { @@ -705,7 +707,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen return nil, err } - official, err := isOfficialReviewer(sess, issue, reviewer) + official, err := isOfficialReviewer(ctx, issue, reviewer) if err != nil { return nil, err } else if official { @@ -756,11 +758,11 @@ func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *user_model.User) ( return nil, nil } - official, err := isOfficialReviewerTeam(sess, issue, reviewer) + official, err := isOfficialReviewerTeam(ctx, issue, reviewer) if err != nil { return nil, fmt.Errorf("isOfficialReviewerTeam(): %v", err) } else if !official { - if official, err = isOfficialReviewer(sess, issue, doer); err != nil { + if official, err = isOfficialReviewer(ctx, issue, doer); err != nil { return nil, fmt.Errorf("isOfficialReviewer(): %v", err) } } @@ -819,7 +821,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *user_model.User return nil, err } - official, err := isOfficialReviewerTeam(sess, issue, reviewer) + official, err := isOfficialReviewerTeam(ctx, issue, reviewer) if err != nil { return nil, fmt.Errorf("isOfficialReviewerTeam(): %v", err) } diff --git a/models/ssh_key_deploy.go b/models/ssh_key_deploy.go index 187af3ca9b..672974afb3 100644 --- a/models/ssh_key_deploy.go +++ b/models/ssh_key_deploy.go @@ -5,11 +5,13 @@ package models import ( + "context" "fmt" "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" @@ -221,13 +223,14 @@ func DeleteDeployKey(doer *user_model.User, id int64) error { } defer committer.Close() - if err := deleteDeployKey(db.GetEngine(ctx), doer, id); err != nil { + if err := deleteDeployKey(ctx, doer, id); err != nil { return err } return committer.Commit() } -func deleteDeployKey(sess db.Engine, doer *user_model.User, id int64) error { +func deleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error { + sess := db.GetEngine(ctx) key, err := getDeployKeyByID(sess, id) if err != nil { if IsErrDeployKeyNotExist(err) { @@ -238,9 +241,9 @@ func deleteDeployKey(sess db.Engine, doer *user_model.User, id int64) error { // Check if user has access to delete this key. if !doer.IsAdmin { - repo, err := getRepositoryByID(sess, key.RepoID) + repo, err := repo_model.GetRepositoryByIDCtx(ctx, key.RepoID) if err != nil { - return fmt.Errorf("GetRepositoryByID: %v", err) + return fmt.Errorf("repo_model.GetRepositoryByID: %v", err) } has, err := isUserRepoAdmin(sess, repo, doer) if err != nil { diff --git a/models/star.go b/models/star.go index 58bc77132d..de3207797e 100644 --- a/models/star.go +++ b/models/star.go @@ -6,6 +6,7 @@ package models import ( "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" ) @@ -75,7 +76,7 @@ func isStaring(e db.Engine, userID, repoID int64) bool { } // GetStargazers returns the users that starred the repo. -func GetStargazers(repo *Repository, opts db.ListOptions) ([]*user_model.User, error) { +func GetStargazers(repo *repo_model.Repository, opts db.ListOptions) ([]*user_model.User, error) { sess := db.GetEngine(db.DefaultContext).Where("star.repo_id = ?", repo.ID). Join("LEFT", "star", "`user`.id = star.uid") if opts.Page > 0 { diff --git a/models/star_test.go b/models/star_test.go index eef1a0c5fb..8da83661c9 100644 --- a/models/star_test.go +++ b/models/star_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -35,7 +36,7 @@ func TestIsStaring(t *testing.T) { func TestRepository_GetStargazers(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) gazers, err := GetStargazers(repo, db.ListOptions{Page: 0}) assert.NoError(t, err) if assert.Len(t, gazers, 1) { @@ -46,7 +47,7 @@ func TestRepository_GetStargazers(t *testing.T) { func TestRepository_GetStargazers2(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) gazers, err := GetStargazers(repo, db.ListOptions{Page: 0}) assert.NoError(t, err) assert.Len(t, gazers, 0) diff --git a/models/statistic.go b/models/statistic.go index 9a2a0d5c47..055f312c11 100644 --- a/models/statistic.go +++ b/models/statistic.go @@ -48,7 +48,7 @@ func GetStatistic() (stats Statistic) { stats.Counter.User = user_model.CountUsers() stats.Counter.Org = CountOrganizations() stats.Counter.PublicKey, _ = e.Count(new(PublicKey)) - stats.Counter.Repo = CountRepositories(true) + stats.Counter.Repo = repo_model.CountRepositories(true) stats.Counter.Watch, _ = e.Count(new(Watch)) stats.Counter.Star, _ = e.Count(new(Star)) stats.Counter.Action, _ = e.Count(new(Action)) @@ -95,7 +95,7 @@ func GetStatistic() (stats Statistic) { stats.Counter.Comment, _ = e.Count(new(Comment)) stats.Counter.Oauth = 0 stats.Counter.Follow, _ = e.Count(new(user_model.Follow)) - stats.Counter.Mirror, _ = e.Count(new(Mirror)) + stats.Counter.Mirror, _ = e.Count(new(repo_model.Mirror)) stats.Counter.Release, _ = e.Count(new(Release)) stats.Counter.LoginSource = login.CountSources() stats.Counter.Webhook, _ = e.Count(new(webhook.Webhook)) diff --git a/models/task.go b/models/task.go index 1999957270..64c858921c 100644 --- a/models/task.go +++ b/models/task.go @@ -8,6 +8,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/migration" @@ -23,12 +24,12 @@ import ( // Task represents a task type Task struct { ID int64 - DoerID int64 `xorm:"index"` // operator - Doer *user_model.User `xorm:"-"` - OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero - Owner *user_model.User `xorm:"-"` - RepoID int64 `xorm:"index"` - Repo *Repository `xorm:"-"` + DoerID int64 `xorm:"index"` // operator + Doer *user_model.User `xorm:"-"` + OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero + Owner *user_model.User `xorm:"-"` + RepoID int64 `xorm:"index"` + Repo *repo_model.Repository `xorm:"-"` Type structs.TaskType Status structs.TaskStatus `xorm:"index"` StartTime timeutil.TimeStamp @@ -57,12 +58,12 @@ func (task *Task) loadRepo(e db.Engine) error { if task.Repo != nil { return nil } - var repo Repository + var repo repo_model.Repository has, err := e.ID(task.RepoID).Get(&repo) if err != nil { return err } else if !has { - return ErrRepoNotExist{ + return repo_model.ErrRepoNotExist{ ID: task.RepoID, } } diff --git a/models/topic.go b/models/topic.go index 79c47e2331..2767d6c58b 100644 --- a/models/topic.go +++ b/models/topic.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" @@ -253,7 +254,7 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) { return nil, err } - if _, err := sess.ID(repoID).Cols("topics").Update(&Repository{ + if _, err := sess.ID(repoID).Cols("topics").Update(&repo_model.Repository{ Topics: topicNames, }); err != nil { return nil, err @@ -347,7 +348,7 @@ func SaveTopics(repoID int64, topicNames ...string) error { return err } - if _, err := sess.ID(repoID).Cols("topics").Update(&Repository{ + if _, err := sess.ID(repoID).Cols("topics").Update(&repo_model.Repository{ Topics: topicNames, }); err != nil { return err diff --git a/models/update.go b/models/update.go index 0898ab54c1..14333ed985 100644 --- a/models/update.go +++ b/models/update.go @@ -10,14 +10,15 @@ import ( "strings" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" ) // PushUpdateDeleteTagsContext updates a number of delete tags with context -func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []string) error { +func PushUpdateDeleteTagsContext(ctx context.Context, repo *repo_model.Repository, tags []string) error { return pushUpdateDeleteTags(db.GetEngine(ctx), repo, tags) } -func pushUpdateDeleteTags(e db.Engine, repo *Repository, tags []string) error { +func pushUpdateDeleteTags(e db.Engine, repo *repo_model.Repository, tags []string) error { if len(tags) == 0 { return nil } @@ -47,7 +48,7 @@ func pushUpdateDeleteTags(e db.Engine, repo *Repository, tags []string) error { } // PushUpdateDeleteTag must be called for any push actions to delete tag -func PushUpdateDeleteTag(repo *Repository, tagName string) error { +func PushUpdateDeleteTag(repo *repo_model.Repository, tagName string) error { rel, err := GetRelease(repo.ID, tagName) if err != nil { if IsErrReleaseNotExist(err) { @@ -72,7 +73,7 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error { } // SaveOrUpdateTag must be called for any push actions to add tag -func SaveOrUpdateTag(repo *Repository, newRel *Release) error { +func SaveOrUpdateTag(repo *repo_model.Repository, newRel *Release) error { rel, err := GetRelease(repo.ID, newRel.TagName) if err != nil && !IsErrReleaseNotExist(err) { return fmt.Errorf("GetRelease: %v", err) diff --git a/models/user.go b/models/user.go index e604c871b2..1427833e21 100644 --- a/models/user.go +++ b/models/user.go @@ -13,6 +13,7 @@ import ( _ "image/jpeg" // Needed for jpeg support "code.gitea.io/gitea/models/db" + 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/setting" @@ -151,7 +152,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { Where("watch.user_id = ?", u.ID).And("watch.mode <>?", RepoWatchModeDont).Find(&watchedRepoIDs); err != nil { return fmt.Errorf("get all watches: %v", err) } - if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(Repository)); err != nil { + if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(repo_model.Repository)); err != nil { return fmt.Errorf("decrease repository num_watches: %v", err) } // ***** END: Watch ***** @@ -161,7 +162,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { if err = e.Table("star").Cols("star.repo_id"). Where("star.uid = ?", u.ID).Find(&starredRepoIDs); err != nil { return fmt.Errorf("get all stars: %v", err) - } else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).NoAutoTime().Update(new(Repository)); err != nil { + } else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).NoAutoTime().Update(new(repo_model.Repository)); err != nil { return fmt.Errorf("decrease repository num_stars: %v", err) } // ***** END: Star ***** @@ -273,7 +274,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { } // GetStarredRepos returns the repos starred by a particular user -func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, error) { +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 { @@ -283,16 +284,16 @@ func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([] if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) - repos := make([]*Repository, 0, listOptions.PageSize) + repos := make([]*repo_model.Repository, 0, listOptions.PageSize) return repos, sess.Find(&repos) } - repos := make([]*Repository, 0, 10) + 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) ([]*Repository, int64, error) { +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<>?", RepoWatchModeDont). Join("LEFT", "watch", "`repository`.id=`watch`.repo_id") @@ -303,12 +304,12 @@ func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([] if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) - repos := make([]*Repository, 0, listOptions.PageSize) + repos := make([]*repo_model.Repository, 0, listOptions.PageSize) total, err := sess.FindAndCount(&repos) return repos, total, err } - repos := make([]*Repository, 0, 10) + repos := make([]*repo_model.Repository, 0, 10) total, err := sess.FindAndCount(&repos) return repos, total, err } |