From 06e4687cecaed41500b653e5b8685f48b8b18310 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 28 Apr 2022 13:48:48 +0200 Subject: [PATCH 1/5] more context for models (#19511) make more usage of context, to have more db transaction in one session (make diff of #9307 smaller) --- models/action.go | 2 +- models/branches.go | 34 +++++++------- models/branches_test.go | 10 ++-- models/commit_status.go | 9 ++-- models/issue.go | 20 ++++---- models/issue_label.go | 21 ++------- models/issue_label_test.go | 7 ++- models/issue_xref.go | 2 +- models/lfs_lock.go | 47 +++++++++++++------ models/organization/org.go | 2 +- models/organization/team_repo.go | 4 +- models/pull.go | 39 ++++++++++------ models/pull_list.go | 11 ++--- models/pull_test.go | 4 +- models/repo.go | 6 +-- models/repo_permission.go | 16 +++---- models/repo_permission_test.go | 48 ++++++++++---------- models/review.go | 6 +-- modules/context/repo.go | 4 +- modules/convert/convert.go | 3 +- modules/convert/issue.go | 2 +- modules/convert/pull.go | 8 ++-- modules/notification/mail/mail.go | 2 +- modules/test/context_tests.go | 2 +- routers/api/v1/api.go | 2 +- routers/api/v1/repo/branch.go | 4 +- routers/api/v1/repo/issue_comment.go | 9 ++-- routers/api/v1/repo/pull.go | 22 ++++----- routers/api/v1/repo/pull_review.go | 6 +-- routers/api/v1/repo/repo.go | 2 +- routers/private/hook_pre_receive.go | 4 +- routers/private/serv.go | 2 +- routers/web/repo/attachment.go | 2 +- routers/web/repo/branch.go | 2 +- routers/web/repo/compare.go | 4 +- routers/web/repo/http.go | 2 +- routers/web/repo/issue.go | 25 +++++----- routers/web/repo/pull.go | 22 ++++----- routers/web/repo/setting_protected_branch.go | 2 +- services/agit/agit.go | 2 +- services/asymkey/sign.go | 2 +- services/issue/assignee.go | 14 +++--- services/issue/commit.go | 3 +- services/issue/label.go | 16 +++++-- services/lfs/locks.go | 4 +- services/lfs/server.go | 2 +- services/pull/check.go | 4 +- services/pull/commit_status.go | 10 ++-- services/pull/merge.go | 6 +-- services/pull/patch.go | 2 +- services/pull/pull.go | 16 +++---- services/pull/review.go | 2 +- services/pull/temp_repo.go | 4 +- services/pull/update.go | 12 ++--- 54 files changed, 274 insertions(+), 244 deletions(-) diff --git a/models/action.go b/models/action.go index 3339d3b87af2a..5177616497514 100644 --- a/models/action.go +++ b/models/action.go @@ -508,7 +508,7 @@ func notifyWatchers(ctx context.Context, actions ...*Action) error { permPR[i] = false continue } - perm, err := getUserRepoPermission(ctx, repo, user) + perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { permCode[i] = false permIssue[i] = false diff --git a/models/branches.go b/models/branches.go index 8156fd0908277..f4ded8588fc70 100644 --- a/models/branches.go +++ b/models/branches.go @@ -337,43 +337,43 @@ 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 *repo_model.Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) { - if err = repo.GetOwner(db.DefaultContext); err != nil { +func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) { + if err = repo.GetOwner(ctx); err != nil { return fmt.Errorf("GetOwner: %v", err) } - whitelist, err := updateUserWhitelist(repo, protectBranch.WhitelistUserIDs, opts.UserIDs) + whitelist, err := updateUserWhitelist(ctx, repo, protectBranch.WhitelistUserIDs, opts.UserIDs) if err != nil { return err } protectBranch.WhitelistUserIDs = whitelist - whitelist, err = updateUserWhitelist(repo, protectBranch.MergeWhitelistUserIDs, opts.MergeUserIDs) + whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.MergeWhitelistUserIDs, opts.MergeUserIDs) if err != nil { return err } protectBranch.MergeWhitelistUserIDs = whitelist - whitelist, err = updateApprovalWhitelist(repo, protectBranch.ApprovalsWhitelistUserIDs, opts.ApprovalsUserIDs) + whitelist, err = updateApprovalWhitelist(ctx, repo, protectBranch.ApprovalsWhitelistUserIDs, opts.ApprovalsUserIDs) if err != nil { return err } protectBranch.ApprovalsWhitelistUserIDs = whitelist // if the repo is in an organization - whitelist, err = updateTeamWhitelist(repo, protectBranch.WhitelistTeamIDs, opts.TeamIDs) + whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.WhitelistTeamIDs, opts.TeamIDs) if err != nil { return err } protectBranch.WhitelistTeamIDs = whitelist - whitelist, err = updateTeamWhitelist(repo, protectBranch.MergeWhitelistTeamIDs, opts.MergeTeamIDs) + whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.MergeWhitelistTeamIDs, opts.MergeTeamIDs) if err != nil { return err } protectBranch.MergeWhitelistTeamIDs = whitelist - whitelist, err = updateTeamWhitelist(repo, protectBranch.ApprovalsWhitelistTeamIDs, opts.ApprovalsTeamIDs) + whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.ApprovalsWhitelistTeamIDs, opts.ApprovalsTeamIDs) if err != nil { return err } @@ -381,13 +381,13 @@ func UpdateProtectBranch(repo *repo_model.Repository, protectBranch *ProtectedBr // Make sure protectBranch.ID is not 0 for whitelists if protectBranch.ID == 0 { - if _, err = db.GetEngine(db.DefaultContext).Insert(protectBranch); err != nil { + if _, err = db.GetEngine(ctx).Insert(protectBranch); err != nil { return fmt.Errorf("Insert: %v", err) } return nil } - if _, err = db.GetEngine(db.DefaultContext).ID(protectBranch.ID).AllCols().Update(protectBranch); err != nil { + if _, err = db.GetEngine(ctx).ID(protectBranch.ID).AllCols().Update(protectBranch); err != nil { return fmt.Errorf("Update: %v", err) } @@ -416,7 +416,7 @@ func IsProtectedBranch(repoID int64, 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 *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { +func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { hasUsersChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist) if !hasUsersChanged { return currentWhitelist, nil @@ -424,7 +424,7 @@ func updateApprovalWhitelist(repo *repo_model.Repository, currentWhitelist, newW whitelist = make([]int64, 0, len(newWhitelist)) for _, userID := range newWhitelist { - if reader, err := IsRepoReader(repo, userID); err != nil { + if reader, err := IsRepoReader(ctx, repo, userID); err != nil { return nil, err } else if !reader { continue @@ -437,7 +437,7 @@ func updateApprovalWhitelist(repo *repo_model.Repository, currentWhitelist, newW // 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 *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { +func updateUserWhitelist(ctx context.Context, repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { hasUsersChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist) if !hasUsersChanged { return currentWhitelist, nil @@ -445,11 +445,11 @@ func updateUserWhitelist(repo *repo_model.Repository, currentWhitelist, newWhite whitelist = make([]int64, 0, len(newWhitelist)) for _, userID := range newWhitelist { - user, err := user_model.GetUserByID(userID) + user, err := user_model.GetUserByIDCtx(ctx, userID) if err != nil { return nil, fmt.Errorf("GetUserByID [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err) } - perm, err := GetUserRepoPermission(repo, user) + perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { return nil, fmt.Errorf("GetUserRepoPermission [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err) } @@ -466,13 +466,13 @@ func updateUserWhitelist(repo *repo_model.Repository, currentWhitelist, newWhite // 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 *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { +func updateTeamWhitelist(ctx context.Context, repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { hasTeamsChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist) if !hasTeamsChanged { return currentWhitelist, nil } - teams, err := organization.GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, perm.AccessModeRead) + teams, err := organization.GetTeamsWithAccessToRepo(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead) if err != nil { return nil, fmt.Errorf("GetTeamsWithAccessToRepo [org_id: %d, repo_id: %d]: %v", repo.OwnerID, repo.ID, err) } diff --git a/models/branches_test.go b/models/branches_test.go index e1a71853f20b6..0a0f125cc6e8d 100644 --- a/models/branches_test.go +++ b/models/branches_test.go @@ -7,6 +7,7 @@ package models import ( "testing" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -99,11 +100,14 @@ func TestRenameBranch(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) _isDefault := false - err := UpdateProtectBranch(repo1, &ProtectedBranch{ + ctx, committer, err := db.TxContext() + defer committer.Close() + assert.NoError(t, err) + assert.NoError(t, UpdateProtectBranch(ctx, repo1, &ProtectedBranch{ RepoID: repo1.ID, BranchName: "master", - }, WhitelistOptions{}) - assert.NoError(t, err) + }, WhitelistOptions{})) + assert.NoError(t, committer.Commit()) assert.NoError(t, RenameBranch(repo1, "master", "main", func(isDefault bool) error { _isDefault = isDefault diff --git a/models/commit_status.go b/models/commit_status.go index cd7497eed8e00..cf2143d30f4c6 100644 --- a/models/commit_status.go +++ b/models/commit_status.go @@ -232,12 +232,13 @@ type CommitStatusIndex struct { // GetLatestCommitStatus returns all statuses with a unique context for a given commit. func GetLatestCommitStatus(repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) { - return getLatestCommitStatus(db.GetEngine(db.DefaultContext), repoID, sha, listOptions) + return GetLatestCommitStatusCtx(db.DefaultContext, repoID, sha, listOptions) } -func getLatestCommitStatus(e db.Engine, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) { +// GetLatestCommitStatusCtx returns all statuses with a unique context for a given commit. +func GetLatestCommitStatusCtx(ctx context.Context, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) { ids := make([]int64, 0, 10) - sess := e.Table(&CommitStatus{}). + sess := db.GetEngine(ctx).Table(&CommitStatus{}). Where("repo_id = ?", repoID).And("sha = ?", sha). Select("max( id ) as id"). GroupBy("context_hash").OrderBy("max( id ) desc") @@ -252,7 +253,7 @@ func getLatestCommitStatus(e db.Engine, repoID int64, sha string, listOptions db if len(ids) == 0 { return statuses, count, nil } - return statuses, count, e.In("id", ids).Find(&statuses) + return statuses, count, db.GetEngine(ctx).In("id", ids).Find(&statuses) } // FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts diff --git a/models/issue.go b/models/issue.go index 8bb46bde7e294..2a41cbc28efd9 100644 --- a/models/issue.go +++ b/models/issue.go @@ -162,13 +162,9 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) { } // LoadLabels loads labels -func (issue *Issue) LoadLabels() error { - return issue.loadLabels(db.GetEngine(db.DefaultContext)) -} - -func (issue *Issue) loadLabels(e db.Engine) (err error) { +func (issue *Issue) LoadLabels(ctx context.Context) (err error) { if issue.Labels == nil { - issue.Labels, err = getLabelsByIssueID(e, issue.ID) + issue.Labels, err = getLabelsByIssueID(db.GetEngine(ctx), issue.ID) if err != nil { return fmt.Errorf("getLabelsByIssueID [%d]: %v", issue.ID, err) } @@ -313,7 +309,7 @@ func (issue *Issue) loadAttributes(ctx context.Context) (err error) { return } - if err = issue.loadLabels(e); err != nil { + if err = issue.LoadLabels(ctx); err != nil { return } @@ -493,7 +489,7 @@ func ClearIssueLabels(issue *Issue, doer *user_model.User) (err error) { return err } - perm, err := getUserRepoPermission(ctx, issue.Repo, doer) + perm, err := GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return err } @@ -539,7 +535,7 @@ func ReplaceIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (e return err } - if err = issue.loadLabels(db.GetEngine(ctx)); err != nil { + if err = issue.LoadLabels(ctx); err != nil { return err } @@ -587,7 +583,7 @@ func ReplaceIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (e } issue.Labels = nil - if err = issue.loadLabels(db.GetEngine(ctx)); err != nil { + if err = issue.LoadLabels(ctx); err != nil { return err } @@ -2341,9 +2337,9 @@ func ResolveIssueMentionsByVisibility(ctx context.Context, issue *Issue, doer *u continue } // Normal users must have read access to the referencing issue - perm, err := getUserRepoPermission(ctx, issue.Repo, user) + perm, err := GetUserRepoPermission(ctx, issue.Repo, user) if err != nil { - return nil, fmt.Errorf("getUserRepoPermission [%d]: %v", user.ID, err) + return nil, fmt.Errorf("GetUserRepoPermission [%d]: %v", user.ID, err) } if !perm.CanReadIssuesOrPulls(issue.IsPull) { continue diff --git a/models/issue_label.go b/models/issue_label.go index 25e6350bc1a66..d069153939087 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -613,7 +613,6 @@ func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error return err } defer committer.Close() - sess := db.GetEngine(ctx) if err = issue.LoadRepo(ctx); err != nil { return err @@ -629,7 +628,7 @@ func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error } issue.Labels = nil - if err = issue.loadLabels(sess); err != nil { + if err = issue.LoadLabels(ctx); err != nil { return err } @@ -670,7 +669,7 @@ func NewIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (err e } issue.Labels = nil - if err = issue.loadLabels(db.GetEngine(ctx)); err != nil { + if err = issue.LoadLabels(ctx); err != nil { return err } @@ -707,23 +706,13 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use } // DeleteIssueLabel deletes issue-label relation. -func DeleteIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error) { - ctx, committer, err := db.TxContext() - if err != nil { - return err - } - defer committer.Close() - - if err = deleteIssueLabel(ctx, issue, label, doer); err != nil { +func DeleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_model.User) error { + if err := deleteIssueLabel(ctx, issue, label, doer); err != nil { return err } issue.Labels = nil - if err = issue.loadLabels(db.GetEngine(ctx)); err != nil { - return err - } - - return committer.Commit() + return issue.LoadLabels(ctx) } func deleteLabelsByRepoID(sess db.Engine, repoID int64) error { diff --git a/models/issue_label_test.go b/models/issue_label_test.go index c9ff1a270f6b9..2dd0cf98e085c 100644 --- a/models/issue_label_test.go +++ b/models/issue_label_test.go @@ -369,7 +369,12 @@ func TestDeleteIssueLabel(t *testing.T) { } } - assert.NoError(t, DeleteIssueLabel(issue, label, doer)) + ctx, committer, err := db.TxContext() + defer committer.Close() + assert.NoError(t, err) + assert.NoError(t, DeleteIssueLabel(ctx, issue, label, doer)) + assert.NoError(t, committer.Commit()) + unittest.AssertNotExistsBean(t, &IssueLabel{IssueID: issueID, LabelID: labelID}) unittest.AssertExistsAndLoadBean(t, &Comment{ Type: CommentTypeLabel, diff --git a/models/issue_xref.go b/models/issue_xref.go index 405f1dae22704..2647f9c6560f7 100644 --- a/models/issue_xref.go +++ b/models/issue_xref.go @@ -215,7 +215,7 @@ func (issue *Issue) verifyReferencedIssue(stdCtx context.Context, ctx *crossRefe // 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(stdCtx, refIssue.Repo, ctx.Doer) + perm, err := GetUserRepoPermission(stdCtx, refIssue.Repo, ctx.Doer) if err != nil { return nil, references.XRefActionNone, err } diff --git a/models/lfs_lock.go b/models/lfs_lock.go index a77dd24e9fa6d..b5f8e4907fbf0 100644 --- a/models/lfs_lock.go +++ b/models/lfs_lock.go @@ -5,6 +5,7 @@ package models import ( + "context" "fmt" "path" "strings" @@ -42,15 +43,20 @@ func cleanPath(p string) string { // CreateLFSLock creates a new lock. func CreateLFSLock(repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) { - err := CheckLFSAccessForRepo(lock.OwnerID, repo, perm.AccessModeWrite) + dbCtx, committer, err := db.TxContext() if err != nil { return nil, err } + defer committer.Close() + + if err := CheckLFSAccessForRepo(dbCtx, lock.OwnerID, repo, perm.AccessModeWrite); err != nil { + return nil, err + } lock.Path = cleanPath(lock.Path) lock.RepoID = repo.ID - l, err := GetLFSLock(repo, lock.Path) + l, err := GetLFSLock(dbCtx, repo, lock.Path) if err == nil { return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path} } @@ -58,15 +64,18 @@ func CreateLFSLock(repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) return nil, err } - err = db.Insert(db.DefaultContext, lock) - return lock, err + if err := db.Insert(dbCtx, lock); err != nil { + return nil, err + } + + return lock, committer.Commit() } // GetLFSLock returns release by given path. -func GetLFSLock(repo *repo_model.Repository, path string) (*LFSLock, error) { +func GetLFSLock(ctx context.Context, 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) + has, err := db.GetEngine(ctx).Where("lower(path) = ?", strings.ToLower(path)).Get(rel) if err != nil { return nil, err } @@ -77,9 +86,9 @@ func GetLFSLock(repo *repo_model.Repository, path string) (*LFSLock, error) { } // GetLFSLockByID returns release by given id. -func GetLFSLockByID(id int64) (*LFSLock, error) { +func GetLFSLockByID(ctx context.Context, id int64) (*LFSLock, error) { lock := new(LFSLock) - has, err := db.GetEngine(db.DefaultContext).ID(id).Get(lock) + has, err := db.GetEngine(ctx).ID(id).Get(lock) if err != nil { return nil, err } else if !has { @@ -127,34 +136,42 @@ func CountLFSLockByRepoID(repoID int64) (int64, error) { // DeleteLFSLockByID deletes a lock by given ID. func DeleteLFSLockByID(id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) { - lock, err := GetLFSLockByID(id) + dbCtx, committer, err := db.TxContext() if err != nil { return nil, err } + defer committer.Close() - err = CheckLFSAccessForRepo(u.ID, repo, perm.AccessModeWrite) + lock, err := GetLFSLockByID(dbCtx, id) if err != nil { return nil, err } + if err := CheckLFSAccessForRepo(dbCtx, u.ID, repo, perm.AccessModeWrite); err != nil { + return nil, err + } + if !force && u.ID != lock.OwnerID { return nil, fmt.Errorf("user doesn't own lock and force flag is not set") } - _, err = db.GetEngine(db.DefaultContext).ID(id).Delete(new(LFSLock)) - return lock, err + if _, err := db.GetEngine(dbCtx).ID(id).Delete(new(LFSLock)); err != nil { + return nil, err + } + + return lock, committer.Commit() } // CheckLFSAccessForRepo check needed access mode base on action -func CheckLFSAccessForRepo(ownerID int64, repo *repo_model.Repository, mode perm.AccessMode) error { +func CheckLFSAccessForRepo(ctx context.Context, ownerID int64, repo *repo_model.Repository, mode perm.AccessMode) error { if ownerID == 0 { return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode} } - u, err := user_model.GetUserByID(ownerID) + u, err := user_model.GetUserByIDCtx(ctx, ownerID) if err != nil { return err } - perm, err := GetUserRepoPermission(repo, u) + perm, err := GetUserRepoPermission(ctx, repo, u) if err != nil { return err } diff --git a/models/organization/org.go b/models/organization/org.go index 9e71bbe80d4e3..3761335922a4a 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -683,7 +683,7 @@ func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]in // TeamsWithAccessToRepo returns all teams that have given access level to the repository. func (org *Organization) TeamsWithAccessToRepo(repoID int64, mode perm.AccessMode) ([]*Team, error) { - return GetTeamsWithAccessToRepo(org.ID, repoID, mode) + return GetTeamsWithAccessToRepo(db.DefaultContext, org.ID, repoID, mode) } // GetUserTeamIDs returns of all team IDs of the organization that user is member of. diff --git a/models/organization/team_repo.go b/models/organization/team_repo.go index 657e83aaa56fa..717d754c40b7f 100644 --- a/models/organization/team_repo.go +++ b/models/organization/team_repo.go @@ -75,9 +75,9 @@ func RemoveTeamRepo(ctx context.Context, teamID, repoID int64) error { } // GetTeamsWithAccessToRepo returns all teams in an organization that have given access level to the repository. -func GetTeamsWithAccessToRepo(orgID, repoID int64, mode perm.AccessMode) ([]*Team, error) { +func GetTeamsWithAccessToRepo(ctx context.Context, orgID, repoID int64, mode perm.AccessMode) ([]*Team, error) { teams := make([]*Team, 0, 5) - return teams, db.GetEngine(db.DefaultContext).Where("team.authorize >= ?", mode). + return teams, db.GetEngine(ctx).Where("team.authorize >= ?", mode). Join("INNER", "team_repo", "team_repo.team_id = team.id"). And("team_repo.org_id = ?", orgID). And("team_repo.repo_id = ?", repoID). diff --git a/models/pull.go b/models/pull.go index ac44ebf0bea24..e04263af9ffe7 100644 --- a/models/pull.go +++ b/models/pull.go @@ -130,7 +130,8 @@ func (pr *PullRequest) LoadAttributes() error { return pr.loadAttributes(db.GetEngine(db.DefaultContext)) } -func (pr *PullRequest) loadHeadRepo(ctx context.Context) (err error) { +// LoadHeadRepoCtx loads the head repository +func (pr *PullRequest) LoadHeadRepoCtx(ctx context.Context) (err error) { if !pr.isHeadRepoLoaded && pr.HeadRepo == nil && pr.HeadRepoID > 0 { if pr.HeadRepoID == pr.BaseRepoID { if pr.BaseRepo != nil { @@ -153,15 +154,16 @@ func (pr *PullRequest) loadHeadRepo(ctx context.Context) (err error) { // LoadHeadRepo loads the head repository func (pr *PullRequest) LoadHeadRepo() error { - return pr.loadHeadRepo(db.DefaultContext) + return pr.LoadHeadRepoCtx(db.DefaultContext) } // LoadBaseRepo loads the target repository func (pr *PullRequest) LoadBaseRepo() error { - return pr.loadBaseRepo(db.DefaultContext) + return pr.LoadBaseRepoCtx(db.DefaultContext) } -func (pr *PullRequest) loadBaseRepo(ctx context.Context) (err error) { +// LoadBaseRepoCtx loads the target repository +func (pr *PullRequest) LoadBaseRepoCtx(ctx context.Context) (err error) { if pr.BaseRepo != nil { return nil } @@ -185,15 +187,16 @@ func (pr *PullRequest) loadBaseRepo(ctx context.Context) (err error) { // LoadIssue loads issue information from database func (pr *PullRequest) LoadIssue() (err error) { - return pr.loadIssue(db.GetEngine(db.DefaultContext)) + return pr.LoadIssueCtx(db.DefaultContext) } -func (pr *PullRequest) loadIssue(e db.Engine) (err error) { +// LoadIssueCtx loads issue information from database +func (pr *PullRequest) LoadIssueCtx(ctx context.Context) (err error) { if pr.Issue != nil { return nil } - pr.Issue, err = getIssueByID(e, pr.IssueID) + pr.Issue, err = getIssueByID(db.GetEngine(ctx), pr.IssueID) if err == nil { pr.Issue.PullRequest = pr } @@ -202,10 +205,11 @@ 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.DefaultContext) + return pr.LoadProtectedBranchCtx(db.DefaultContext) } -func (pr *PullRequest) loadProtectedBranch(ctx context.Context) (err error) { +// LoadProtectedBranchCtx loads the protected branch of the base branch +func (pr *PullRequest) LoadProtectedBranchCtx(ctx context.Context) (err error) { if pr.ProtectedBranch == nil { if pr.BaseRepo == nil { if pr.BaseRepoID == 0 { @@ -392,7 +396,7 @@ func (pr *PullRequest) SetMerged() (bool, error) { } pr.Issue = nil - if err := pr.loadIssue(sess); err != nil { + if err := pr.LoadIssueCtx(ctx); err != nil { return false, err } @@ -510,6 +514,11 @@ func GetLatestPullRequestByHeadInfo(repoID int64, branch string) (*PullRequest, // GetPullRequestByIndex returns a pull request by the given index func GetPullRequestByIndex(repoID, index int64) (*PullRequest, error) { + return GetPullRequestByIndexCtx(db.DefaultContext, repoID, index) +} + +// GetPullRequestByIndexCtx returns a pull request by the given index +func GetPullRequestByIndexCtx(ctx context.Context, repoID, index int64) (*PullRequest, error) { if index < 1 { return nil, ErrPullRequestNotExist{} } @@ -518,17 +527,17 @@ func GetPullRequestByIndex(repoID, index int64) (*PullRequest, error) { Index: index, } - has, err := db.GetEngine(db.DefaultContext).Get(pr) + has, err := db.GetEngine(ctx).Get(pr) if err != nil { return nil, err } else if !has { return nil, ErrPullRequestNotExist{0, 0, 0, repoID, "", ""} } - if err = pr.LoadAttributes(); err != nil { + if err = pr.loadAttributes(db.GetEngine(ctx)); err != nil { return nil, err } - if err = pr.LoadIssue(); err != nil { + if err = pr.LoadIssueCtx(ctx); err != nil { return nil, err } @@ -547,8 +556,8 @@ func getPullRequestByID(e db.Engine, id int64) (*PullRequest, error) { } // GetPullRequestByID returns a pull request by given ID. -func GetPullRequestByID(id int64) (*PullRequest, error) { - return getPullRequestByID(db.GetEngine(db.DefaultContext), id) +func GetPullRequestByID(ctx context.Context, id int64) (*PullRequest, error) { + return getPullRequestByID(db.GetEngine(ctx), id) } // GetPullRequestByIssueIDWithNoAttributes returns pull request with no attributes loaded by given issue ID. diff --git a/models/pull_list.go b/models/pull_list.go index 9d4d42892883b..055119a1e5b6c 100644 --- a/models/pull_list.go +++ b/models/pull_list.go @@ -5,6 +5,7 @@ package models import ( + "context" "fmt" "code.gitea.io/gitea/models/db" @@ -158,13 +159,14 @@ func (prs PullRequestList) LoadAttributes() error { return prs.loadAttributes(db.GetEngine(db.DefaultContext)) } -func (prs PullRequestList) invalidateCodeComments(e db.Engine, doer *user_model.User, repo *git.Repository, branch string) error { +// InvalidateCodeComments will lookup the prs for code comments which got invalidated by change +func (prs PullRequestList) InvalidateCodeComments(ctx context.Context, doer *user_model.User, repo *git.Repository, branch string) error { if len(prs) == 0 { return nil } issueIDs := prs.getIssueIDs() var codeComments []*Comment - if err := e. + if err := db.GetEngine(ctx). Where("type = ? and invalidated = ?", CommentTypeCode, false). In("issue_id", issueIDs). Find(&codeComments); err != nil { @@ -177,8 +179,3 @@ func (prs PullRequestList) invalidateCodeComments(e db.Engine, doer *user_model. } return nil } - -// InvalidateCodeComments will lookup the prs for code comments which got invalidated by change -func (prs PullRequestList) InvalidateCodeComments(doer *user_model.User, repo *git.Repository, branch string) error { - return prs.invalidateCodeComments(db.GetEngine(db.DefaultContext), doer, repo, branch) -} diff --git a/models/pull_test.go b/models/pull_test.go index 9098b611617a6..6194ac0e2405f 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -159,12 +159,12 @@ func TestGetPullRequestByIndex(t *testing.T) { func TestGetPullRequestByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr, err := GetPullRequestByID(1) + pr, err := GetPullRequestByID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, int64(1), pr.ID) assert.Equal(t, int64(2), pr.IssueID) - _, err = GetPullRequestByID(9223372036854775807) + _, err = GetPullRequestByID(db.DefaultContext, 9223372036854775807) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } diff --git a/models/repo.go b/models/repo.go index 5073d1ceb9031..9c2fce8d3cd3e 100644 --- a/models/repo.go +++ b/models/repo.go @@ -57,9 +57,9 @@ func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *u if user.IsAdmin { return true } - perm, err := getUserRepoPermission(ctx, repo, user) + perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { - log.Error("getUserRepoPermission(): %v", err) + log.Error("GetUserRepoPermission(): %v", err) return false } @@ -198,7 +198,7 @@ func GetReviewerTeams(repo *repo_model.Repository) ([]*organization.Team, error) return nil, nil } - teams, err := organization.GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, perm.AccessModeRead) + teams, err := organization.GetTeamsWithAccessToRepo(db.DefaultContext, repo.OwnerID, repo.ID, perm.AccessModeRead) if err != nil { return nil, err } diff --git a/models/repo_permission.go b/models/repo_permission.go index 3e9ad04482d99..b4291f2362d63 100644 --- a/models/repo_permission.go +++ b/models/repo_permission.go @@ -145,11 +145,7 @@ func (p *Permission) ColorFormat(s fmt.State) { } // GetUserRepoPermission returns the user permissions to the repository -func GetUserRepoPermission(repo *repo_model.Repository, user *user_model.User) (Permission, error) { - return getUserRepoPermission(db.DefaultContext, repo, user) -} - -func getUserRepoPermission(ctx context.Context, repo *repo_model.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 { @@ -347,7 +343,7 @@ func AccessLevelUnit(user *user_model.User, repo *repo_model.Repository, unitTyp } 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) + perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { return perm_model.AccessModeNone, err } @@ -375,7 +371,7 @@ func canBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model. 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(ctx, repo, user) + perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { return false, err } @@ -391,7 +387,7 @@ func hasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) ( return false, err } } - perm, err := getUserRepoPermission(ctx, repo, user) + perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { return false, err } @@ -414,9 +410,9 @@ func GetRepoWriters(repo *repo_model.Repository) (_ []*user_model.User, err erro } // IsRepoReader returns true if user has explicit read access or higher to the repository. -func IsRepoReader(repo *repo_model.Repository, userID int64) (bool, error) { +func IsRepoReader(ctx context.Context, repo *repo_model.Repository, userID int64) (bool, error) { if repo.OwnerID == userID { return true, nil } - return db.GetEngine(db.DefaultContext).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm_model.AccessModeRead).Get(&Access{}) + return db.GetEngine(ctx).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm_model.AccessModeRead).Get(&Access{}) } diff --git a/models/repo_permission_test.go b/models/repo_permission_test.go index c103a9363f82b..7e22437f997e3 100644 --- a/models/repo_permission_test.go +++ b/models/repo_permission_test.go @@ -27,7 +27,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err := GetUserRepoPermission(repo, user) + perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -36,7 +36,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // change to collaborator assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(repo, user) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -45,7 +45,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // collaborator collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, collaborator) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, collaborator) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -54,7 +54,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, owner) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -63,7 +63,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, admin) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -80,7 +80,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) - perm, err := GetUserRepoPermission(repo, user) + perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.False(t, perm.CanRead(unit.Type)) @@ -89,7 +89,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // change to collaborator to default write access assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(repo, user) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -97,7 +97,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { } assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) - perm, err = GetUserRepoPermission(repo, user) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -106,7 +106,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, owner) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -115,7 +115,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, admin) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -132,7 +132,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - perm, err := GetUserRepoPermission(repo, user) + perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -141,7 +141,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // change to collaborator to default write access assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(repo, user) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -149,7 +149,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { } assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) - perm, err = GetUserRepoPermission(repo, user) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -158,7 +158,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // org member team owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, owner) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -167,7 +167,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // org member team tester member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, member) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, member) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -177,7 +177,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, admin) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -194,7 +194,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - perm, err := GetUserRepoPermission(repo, user) + perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.False(t, perm.CanRead(unit.Type)) @@ -203,7 +203,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // change to collaborator to default write access assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(repo, user) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -211,7 +211,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { } assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) - perm, err = GetUserRepoPermission(repo, user) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -220,7 +220,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, owner) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -231,7 +231,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team) err = organization.UpdateTeamUnits(team, nil) assert.NoError(t, err) - perm, err = GetUserRepoPermission(repo, owner) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -240,7 +240,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team tester tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, tester) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, tester) assert.NoError(t, err) assert.True(t, perm.CanWrite(unit.TypeIssues)) assert.False(t, perm.CanWrite(unit.TypeCode)) @@ -248,7 +248,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team reviewer reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, reviewer) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, reviewer) assert.NoError(t, err) assert.False(t, perm.CanRead(unit.TypeIssues)) assert.False(t, perm.CanWrite(unit.TypeCode)) @@ -256,7 +256,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(repo, admin) + perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) diff --git a/models/review.go b/models/review.go index 51818bc72220e..a9e29a10e05ca 100644 --- a/models/review.go +++ b/models/review.go @@ -238,7 +238,7 @@ func isOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo if err != nil { return false, err } - if err = pr.loadProtectedBranch(ctx); err != nil { + if err = pr.LoadProtectedBranchCtx(ctx); err != nil { return false, err } if pr.ProtectedBranch == nil { @@ -265,7 +265,7 @@ func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio if err != nil { return false, err } - if err = pr.loadProtectedBranch(ctx); err != nil { + if err = pr.LoadProtectedBranchCtx(ctx); err != nil { return false, err } if pr.ProtectedBranch == nil { @@ -891,7 +891,7 @@ func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool, return false, err } - p, err := GetUserRepoPermission(issue.Repo, doer) + p, err := GetUserRepoPermission(db.DefaultContext, issue.Repo, doer) if err != nil { return false, err } diff --git a/modules/context/repo.go b/modules/context/repo.go index 4687434455a39..a02bb7e869116 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -285,7 +285,7 @@ func RetrieveTemplateRepo(ctx *Context, repo *repo_model.Repository) { return } - perm, err := models.GetUserRepoPermission(templateRepo, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, templateRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -351,7 +351,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { return } - ctx.Repo.Permission, err = models.GetUserRepoPermission(repo, ctx.Doer) + ctx.Repo.Permission, err = models.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return diff --git a/modules/convert/convert.go b/modules/convert/convert.go index 43300f603e55a..3f565f76e087c 100644 --- a/modules/convert/convert.go +++ b/modules/convert/convert.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -74,7 +75,7 @@ func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *mod } if user != nil { - permission, err := models.GetUserRepoPermission(repo, user) + permission, err := models.GetUserRepoPermission(db.DefaultContext, repo, user) if err != nil { return nil, err } diff --git a/modules/convert/issue.go b/modules/convert/issue.go index 6cdb10f7daa6f..bf116e2283cf7 100644 --- a/modules/convert/issue.go +++ b/modules/convert/issue.go @@ -24,7 +24,7 @@ import ( // Required - Poster, Labels, // Optional - Milestone, Assignee, PullRequest func ToAPIIssue(issue *models.Issue) *api.Issue { - if err := issue.LoadLabels(); err != nil { + if err := issue.LoadLabels(db.DefaultContext); err != nil { return &api.Issue{} } if err := issue.LoadPoster(); err != nil { diff --git a/modules/convert/pull.go b/modules/convert/pull.go index 3b39e3d2c1269..6034327a9d25f 100644 --- a/modules/convert/pull.go +++ b/modules/convert/pull.go @@ -33,17 +33,17 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo } apiIssue := ToAPIIssue(pr.Issue) - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("GetRepositoryById[%d]: %v", pr.ID, err) return nil } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { log.Error("GetRepositoryById[%d]: %v", pr.ID, err) return nil } - p, err := models.GetUserRepoPermission(pr.BaseRepo, doer) + p, err := models.GetUserRepoPermission(ctx, pr.BaseRepo, doer) if err != nil { log.Error("GetUserRepoPermission[%d]: %v", pr.BaseRepoID, err) p.AccessMode = perm.AccessModeNone @@ -130,7 +130,7 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo } if pr.HeadRepo != nil && pr.Flow == models.PullRequestFlowGithub { - p, err := models.GetUserRepoPermission(pr.HeadRepo, doer) + p, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, doer) if err != nil { log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err) p.AccessMode = perm.AccessModeNone diff --git a/modules/notification/mail/mail.go b/modules/notification/mail/mail.go index 6636d18b99c06..138e438751ddf 100644 --- a/modules/notification/mail/mail.go +++ b/modules/notification/mail/mail.go @@ -169,7 +169,7 @@ func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *m log.Error("comment.Issue.LoadPullRequest: %v", err) return } - if err = comment.Issue.PullRequest.LoadBaseRepo(); err != nil { + if err = comment.Issue.PullRequest.LoadBaseRepoCtx(ctx); err != nil { log.Error("comment.Issue.PullRequest.LoadBaseRepo: %v", err) return } diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index 2c6ae2f853acb..a05b221af810d 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -60,7 +60,7 @@ func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) { ctx.Repo.Owner, err = user_model.GetUserByID(ctx.Repo.Repository.OwnerID) assert.NoError(t, err) ctx.Repo.RepoLink = ctx.Repo.Repository.Link() - ctx.Repo.Permission, err = models.GetUserRepoPermission(ctx.Repo.Repository, ctx.Doer) + ctx.Repo.Permission, err = models.GetUserRepoPermission(ctx, ctx.Repo.Repository, ctx.Doer) assert.NoError(t, err) } diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index aec2a6d7b2c42..cca0f37ba107f 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -183,7 +183,7 @@ func repoAssignment() func(ctx *context.APIContext) { repo.Owner = owner ctx.Repo.Repository = repo - ctx.Repo.Permission, err = models.GetUserRepoPermission(repo, ctx.Doer) + ctx.Repo.Permission, err = models.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) return diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index f22bed813e152..794d367b53e73 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -498,7 +498,7 @@ func CreateBranchProtection(ctx *context.APIContext) { BlockOnOutdatedBranch: form.BlockOnOutdatedBranch, } - err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ + err = models.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ UserIDs: whitelistUsers, TeamIDs: whitelistTeams, MergeUserIDs: mergeWhitelistUsers, @@ -733,7 +733,7 @@ func EditBranchProtection(ctx *context.APIContext) { } } - err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ + err = models.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ UserIDs: whitelistUsers, TeamIDs: whitelistTeams, MergeUserIDs: mergeWhitelistUsers, diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index ef91a2481c273..bc68cb396b97d 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -6,6 +6,7 @@ package repo import ( + stdCtx "context" "errors" "net/http" @@ -183,7 +184,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) { var apiComments []*api.TimelineComment for _, comment := range comments { - if comment.Type != models.CommentTypeCode && isXRefCommentAccessible(ctx.Doer, comment, issue.RepoID) { + if comment.Type != models.CommentTypeCode && isXRefCommentAccessible(ctx, ctx.Doer, comment, issue.RepoID) { comment.Issue = issue apiComments = append(apiComments, convert.ToTimelineComment(comment, ctx.Doer)) } @@ -193,16 +194,16 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) { ctx.JSON(http.StatusOK, &apiComments) } -func isXRefCommentAccessible(user *user_model.User, c *models.Comment, issueRepoID int64) bool { +func isXRefCommentAccessible(ctx stdCtx.Context, user *user_model.User, c *models.Comment, issueRepoID int64) bool { // Remove comments that the user has no permissions to see if models.CommentTypeIsRef(c.Type) && c.RefRepoID != issueRepoID && c.RefRepoID != 0 { var err error // Set RefRepo for description in template - c.RefRepo, err = repo_model.GetRepositoryByID(c.RefRepoID) + c.RefRepo, err = repo_model.GetRepositoryByIDCtx(ctx, c.RefRepoID) if err != nil { return false } - perm, err := models.GetUserRepoPermission(c.RefRepo, user) + perm, err := models.GetUserRepoPermission(ctx, c.RefRepo, user) if err != nil { return false } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 94262f81d1874..6b076eff8fad3 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -111,11 +111,11 @@ func ListPullRequests(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - if err = prs[i].LoadBaseRepo(); err != nil { + if err = prs[i].LoadBaseRepoCtx(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) return } - if err = prs[i].LoadHeadRepo(); err != nil { + if err = prs[i].LoadHeadRepoCtx(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } @@ -167,11 +167,11 @@ func GetPullRequest(ctx *context.APIContext) { return } - if err = pr.LoadBaseRepo(); err != nil { + if err = pr.LoadBaseRepoCtx(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) return } - if err = pr.LoadHeadRepo(); err != nil { + if err = pr.LoadHeadRepoCtx(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } @@ -724,7 +724,7 @@ func MergePullRequest(ctx *context.APIContext) { return } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } @@ -943,7 +943,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } // user should have permission to read baseRepo's codes and pulls, NOT headRepo's - permBase, err := models.GetUserRepoPermission(baseRepo, ctx.Doer) + permBase, err := models.GetUserRepoPermission(ctx, baseRepo, ctx.Doer) if err != nil { headGitRepo.Close() ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) @@ -962,7 +962,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } // user should have permission to read headrepo's codes - permHead, err := models.GetUserRepoPermission(headRepo, ctx.Doer) + permHead, err := models.GetUserRepoPermission(ctx, headRepo, ctx.Doer) if err != nil { headGitRepo.Close() ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) @@ -1063,18 +1063,18 @@ func UpdatePullRequest(ctx *context.APIContext) { return } - if err = pr.LoadBaseRepo(); err != nil { + if err = pr.LoadBaseRepoCtx(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) return } - if err = pr.LoadHeadRepo(); err != nil { + if err = pr.LoadHeadRepoCtx(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) return } rebase := ctx.FormString("style") == "rebase" - allowedUpdateByMerge, allowedUpdateByRebase, err := pull_service.IsUserAllowedToUpdate(pr, ctx.Doer) + allowedUpdateByMerge, allowedUpdateByRebase, err := pull_service.IsUserAllowedToUpdate(ctx, pr, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "IsUserAllowedToMerge", err) return @@ -1151,7 +1151,7 @@ func GetPullRequestCommits(ctx *context.APIContext) { return } - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { ctx.InternalServerError(err) return } diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index 3b36f28326f5b..b3ebe49bf512e 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -664,7 +664,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions reviewers := make([]*user_model.User, 0, len(opts.Reviewers)) - permDoer, err := models.GetUserRepoPermission(pr.Issue.Repo, ctx.Doer) + permDoer, err := models.GetUserRepoPermission(ctx, pr.Issue.Repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) return @@ -687,7 +687,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions return } - err = issue_service.IsValidReviewRequest(reviewer, ctx.Doer, isAdd, pr.Issue, &permDoer) + err = issue_service.IsValidReviewRequest(ctx, reviewer, ctx.Doer, isAdd, pr.Issue, &permDoer) if err != nil { if models.IsErrNotValidReviewRequest(err) { ctx.Error(http.StatusUnprocessableEntity, "NotValidReviewRequest", err) @@ -736,7 +736,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions return } - err = issue_service.IsValidTeamReviewRequest(teamReviewer, ctx.Doer, isAdd, pr.Issue) + err = issue_service.IsValidTeamReviewRequest(ctx, teamReviewer, ctx.Doer, isAdd, pr.Issue) if err != nil { if models.IsErrNotValidReviewRequest(err) { ctx.Error(http.StatusUnprocessableEntity, "NotValidReviewRequest", err) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index cec4c93d198f0..29e83521420f3 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -555,7 +555,7 @@ func GetByID(ctx *context.APIContext) { return } - perm, err := models.GetUserRepoPermission(repo, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 763fe1cf1c559..ccb6933787a1b 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -290,7 +290,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN // 6b. Merge (from UI or API) // Get the PR, user and permissions for the user in the repository - pr, err := models.GetPullRequestByID(ctx.opts.PullRequestID) + pr, err := models.GetPullRequestByID(ctx, ctx.opts.PullRequestID) if err != nil { log.Error("Unable to get PullRequest %d Error: %v", ctx.opts.PullRequestID, err) ctx.JSON(http.StatusInternalServerError, private.Response{ @@ -468,7 +468,7 @@ func (ctx *preReceiveContext) loadPusherAndPermission() bool { } ctx.user = user - userPerm, err := models.GetUserRepoPermission(ctx.Repo.Repository, user) + userPerm, err := models.GetUserRepoPermission(ctx, ctx.Repo.Repository, user) if err != nil { log.Error("Unable to get Repo permission of repo %s/%s of User %s", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err) ctx.JSON(http.StatusInternalServerError, private.Response{ diff --git a/routers/private/serv.go b/routers/private/serv.go index b0451df5d85eb..6ef0079a2be17 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -320,7 +320,7 @@ func ServCommand(ctx *context.PrivateContext) { mode = perm.AccessModeRead } - perm, err := models.GetUserRepoPermission(repo, user) + perm, err := models.GetUserRepoPermission(ctx, repo, user) if err != nil { log.Error("Unable to get permissions for %-v with key %d in %-v Error: %v", user, key.ID, repo, err) ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{ diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index be5b5812d3805..c930311f70f24 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -106,7 +106,7 @@ func GetAttachment(ctx *context.Context) { return } } else { // If we have the repository we check access - perm, err := models.GetUserRepoPermission(repository, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, repository, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err.Error()) return diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 0d139ec79c48e..732b9c9d5473a 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -279,7 +279,7 @@ func loadOneBranch(ctx *context.Context, rawBranch, defaultBranch *git.Branch, p } if repo, ok := repoIDToRepo[pr.BaseRepoID]; ok { pr.BaseRepo = repo - } else if err := pr.LoadBaseRepo(); err != nil { + } else if err := pr.LoadBaseRepoCtx(ctx); err != nil { ctx.ServerError("pr.LoadBaseRepo", err) return nil } else { diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 60c6ae0298c22..9f7bef43ef7eb 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -402,7 +402,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // Now we need to assert that the ctx.Doer has permission to read // the baseRepo's code and pulls // (NOT headRepo's) - permBase, err := models.GetUserRepoPermission(baseRepo, ctx.Doer) + permBase, err := models.GetUserRepoPermission(ctx, baseRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return nil @@ -421,7 +421,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // If we're not merging from the same repo: if !isSameRepo { // Assert ctx.Doer has permission to read headRepo's codes - permHead, err := models.GetUserRepoPermission(ci.HeadRepo, ctx.Doer) + permHead, err := models.GetUserRepoPermission(ctx, ci.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return nil diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index 1306a54369455..cc44c8e7e4fbd 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -181,7 +181,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) { } if repoExist { - p, err := models.GetUserRepoPermission(repo, ctx.Doer) + p, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index ee36216d9fdd0..8e865e448fc18 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -7,6 +7,7 @@ package repo import ( "bytes" + stdCtx "context" "errors" "fmt" "io" @@ -1052,8 +1053,8 @@ func NewIssuePost(ctx *context.Context) { } // roleDescriptor returns the Role Descriptor for a comment in/with the given repo, poster and issue -func roleDescriptor(repo *repo_model.Repository, poster *user_model.User, issue *models.Issue) (models.RoleDescriptor, error) { - perm, err := models.GetUserRepoPermission(repo, poster) +func roleDescriptor(ctx stdCtx.Context, repo *repo_model.Repository, poster *user_model.User, issue *models.Issue) (models.RoleDescriptor, error) { + perm, err := models.GetUserRepoPermission(ctx, repo, poster) if err != nil { return models.RoleDescriptorNone, err } @@ -1350,7 +1351,7 @@ func ViewIssue(ctx *context.Context) { // check if dependencies can be created across repositories ctx.Data["AllowCrossRepositoryDependencies"] = setting.Service.AllowCrossRepositoryDependencies - if issue.ShowRole, err = roleDescriptor(repo, issue.Poster, issue); err != nil { + if issue.ShowRole, err = roleDescriptor(ctx, repo, issue.Poster, issue); err != nil { ctx.ServerError("roleDescriptor", err) return } @@ -1389,7 +1390,7 @@ func ViewIssue(ctx *context.Context) { continue } - comment.ShowRole, err = roleDescriptor(repo, comment.Poster, issue) + comment.ShowRole, err = roleDescriptor(ctx, repo, comment.Poster, issue) if err != nil { ctx.ServerError("roleDescriptor", err) return @@ -1488,7 +1489,7 @@ func ViewIssue(ctx *context.Context) { continue } - c.ShowRole, err = roleDescriptor(repo, c.Poster, issue) + c.ShowRole, err = roleDescriptor(ctx, repo, c.Poster, issue) if err != nil { ctx.ServerError("roleDescriptor", err) return @@ -1526,10 +1527,10 @@ func ViewIssue(ctx *context.Context) { ctx.Data["AllowMerge"] = false if ctx.IsSigned { - if err := pull.LoadHeadRepo(); err != nil { + if err := pull.LoadHeadRepoCtx(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) } else if pull.HeadRepo != nil && pull.HeadBranch != pull.HeadRepo.DefaultBranch { - perm, err := models.GetUserRepoPermission(pull.HeadRepo, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -1545,10 +1546,10 @@ func ViewIssue(ctx *context.Context) { } } - if err := pull.LoadBaseRepo(); err != nil { + if err := pull.LoadBaseRepoCtx(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) } - perm, err := models.GetUserRepoPermission(pull.BaseRepo, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, pull.BaseRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -2038,7 +2039,7 @@ func UpdatePullReviewRequest(ctx *context.Context) { return } - err = issue_service.IsValidTeamReviewRequest(team, ctx.Doer, action == "attach", issue) + err = issue_service.IsValidTeamReviewRequest(ctx, team, ctx.Doer, action == "attach", issue) if err != nil { if models.IsErrNotValidReviewRequest(err) { log.Warn( @@ -2076,7 +2077,7 @@ func UpdatePullReviewRequest(ctx *context.Context) { return } - err = issue_service.IsValidReviewRequest(reviewer, ctx.Doer, action == "attach", issue, nil) + err = issue_service.IsValidReviewRequest(ctx, reviewer, ctx.Doer, action == "attach", issue, nil) if err != nil { if models.IsErrNotValidReviewRequest(err) { log.Warn( @@ -2919,7 +2920,7 @@ func filterXRefComments(ctx *context.Context, issue *models.Issue) error { if err != nil { return err } - perm, err := models.GetUserRepoPermission(c.RefRepo, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, c.RefRepo, ctx.Doer) if err != nil { return err } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 113e2d8421125..a03e16f39a2b3 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -70,7 +70,7 @@ func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository { return nil } - perm, err := models.GetUserRepoPermission(repo, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return nil @@ -283,7 +283,7 @@ func checkPullInfo(ctx *context.Context) *models.Issue { return nil } - if err = issue.PullRequest.LoadHeadRepo(); err != nil { + if err = issue.PullRequest.LoadHeadRepoCtx(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return nil } @@ -397,12 +397,12 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare repo := ctx.Repo.Repository pull := issue.PullRequest - if err := pull.LoadHeadRepo(); err != nil { + if err := pull.LoadHeadRepoCtx(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return nil } - if err := pull.LoadBaseRepo(); err != nil { + if err := pull.LoadBaseRepoCtx(ctx); err != nil { ctx.ServerError("LoadBaseRepo", err) return nil } @@ -499,7 +499,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare if headBranchExist { var err error - ctx.Data["UpdateAllowed"], ctx.Data["UpdateByRebaseAllowed"], err = pull_service.IsUserAllowedToUpdate(pull, ctx.Doer) + ctx.Data["UpdateAllowed"], ctx.Data["UpdateByRebaseAllowed"], err = pull_service.IsUserAllowedToUpdate(ctx, pull, ctx.Doer) if err != nil { ctx.ServerError("IsUserAllowedToUpdate", err) return nil @@ -785,16 +785,16 @@ func UpdatePullRequest(ctx *context.Context) { rebase := ctx.FormString("style") == "rebase" - if err := issue.PullRequest.LoadBaseRepo(); err != nil { + if err := issue.PullRequest.LoadBaseRepoCtx(ctx); err != nil { ctx.ServerError("LoadBaseRepo", err) return } - if err := issue.PullRequest.LoadHeadRepo(); err != nil { + if err := issue.PullRequest.LoadHeadRepoCtx(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return } - allowedUpdateByMerge, allowedUpdateByRebase, err := pull_service.IsUserAllowedToUpdate(issue.PullRequest, ctx.Doer) + allowedUpdateByMerge, allowedUpdateByRebase, err := pull_service.IsUserAllowedToUpdate(ctx, issue.PullRequest, ctx.Doer) if err != nil { ctx.ServerError("IsUserAllowedToMerge", err) return @@ -1202,14 +1202,14 @@ func CleanUpPullRequest(ctx *context.Context) { return } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) return } else if pr.HeadRepo == nil { // Forked repository has already been deleted ctx.NotFound("CleanUpPullRequest", nil) return - } else if err = pr.LoadBaseRepo(); err != nil { + } else if err = pr.LoadBaseRepoCtx(ctx); err != nil { ctx.ServerError("LoadBaseRepo", err) return } else if err = pr.HeadRepo.GetOwner(ctx); err != nil { @@ -1217,7 +1217,7 @@ func CleanUpPullRequest(ctx *context.Context) { return } - perm, err := models.GetUserRepoPermission(pr.HeadRepo, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting_protected_branch.go index a26a0a620a926..1f6e2316e7dfe 100644 --- a/routers/web/repo/setting_protected_branch.go +++ b/routers/web/repo/setting_protected_branch.go @@ -261,7 +261,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) { protectBranch.UnprotectedFilePatterns = f.UnprotectedFilePatterns protectBranch.BlockOnOutdatedBranch = f.BlockOnOutdatedBranch - err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ + err = models.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ UserIDs: whitelistUsers, TeamIDs: whitelistTeams, MergeUserIDs: mergeWhitelistUsers, diff --git a/services/agit/agit.go b/services/agit/agit.go index 5f8d16172da4a..288923618171a 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -177,7 +177,7 @@ func ProcRecive(ctx *context.PrivateContext, opts *private.HookOptions) []privat } // update exist pull request - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err) ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ "Err": fmt.Sprintf("Unable to load base repository for PR[%d] Error: %v", pr.ID, err), diff --git a/services/asymkey/sign.go b/services/asymkey/sign.go index c3f093a808105..876cb7c205b3b 100644 --- a/services/asymkey/sign.go +++ b/services/asymkey/sign.go @@ -271,7 +271,7 @@ Loop: // SignMerge determines if we should sign a PR merge commit to the base repository func SignMerge(ctx context.Context, pr *models.PullRequest, u *user_model.User, tmpBasePath, baseCommit, headCommit string) (bool, string, *git.Signature, error) { - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("Unable to get Base Repo for pull request") return false, "", nil, err } diff --git a/services/issue/assignee.go b/services/issue/assignee.go index 479c9cbb138a8..e6169b9c7e55a 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -5,6 +5,8 @@ package issue import ( + "context" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" @@ -78,7 +80,7 @@ func ReviewRequest(issue *models.Issue, doer, reviewer *user_model.User, isAdd b } // IsValidReviewRequest Check permission for ReviewRequest -func IsValidReviewRequest(reviewer, doer *user_model.User, isAdd bool, issue *models.Issue, permDoer *models.Permission) error { +func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, isAdd bool, issue *models.Issue, permDoer *models.Permission) error { if reviewer.IsOrganization() { return models.ErrNotValidReviewRequest{ Reason: "Organization can't be added as reviewer", @@ -94,14 +96,14 @@ func IsValidReviewRequest(reviewer, doer *user_model.User, isAdd bool, issue *mo } } - permReviewer, err := models.GetUserRepoPermission(issue.Repo, reviewer) + permReviewer, err := models.GetUserRepoPermission(ctx, issue.Repo, reviewer) if err != nil { return err } if permDoer == nil { permDoer = new(models.Permission) - *permDoer, err = models.GetUserRepoPermission(issue.Repo, doer) + *permDoer, err = models.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return err } @@ -168,7 +170,7 @@ func IsValidReviewRequest(reviewer, doer *user_model.User, isAdd bool, issue *mo } // IsValidTeamReviewRequest Check permission for ReviewRequest Team -func IsValidTeamReviewRequest(reviewer *organization.Team, doer *user_model.User, isAdd bool, issue *models.Issue) error { +func IsValidTeamReviewRequest(ctx context.Context, reviewer *organization.Team, doer *user_model.User, isAdd bool, issue *models.Issue) error { if doer.IsOrganization() { return models.ErrNotValidReviewRequest{ Reason: "Organization can't be doer to add reviewer", @@ -177,7 +179,7 @@ func IsValidTeamReviewRequest(reviewer *organization.Team, doer *user_model.User } } - permission, err := models.GetUserRepoPermission(issue.Repo, doer) + permission, err := models.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { log.Error("Unable to GetUserRepoPermission for %-v in %-v#%d", doer, issue.Repo, issue.Index) return err @@ -185,7 +187,7 @@ func IsValidTeamReviewRequest(reviewer *organization.Team, doer *user_model.User if isAdd { if issue.Repo.IsPrivate { - hasTeam := organization.HasTeamRepo(db.DefaultContext, reviewer.OrgID, reviewer.ID, issue.RepoID) + hasTeam := organization.HasTeamRepo(ctx, reviewer.OrgID, reviewer.ID, issue.RepoID) if !hasTeam { return models.ErrNotValidReviewRequest{ diff --git a/services/issue/commit.go b/services/issue/commit.go index 0dda5f202f4ff..b5d97e12a80f3 100644 --- a/services/issue/commit.go +++ b/services/issue/commit.go @@ -14,6 +14,7 @@ import ( "time" "code.gitea.io/gitea/models" + "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/references" @@ -130,7 +131,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm continue } - perm, err := models.GetUserRepoPermission(refRepo, doer) + perm, err := models.GetUserRepoPermission(db.DefaultContext, refRepo, doer) if err != nil { return err } diff --git a/services/issue/label.go b/services/issue/label.go index e72e1cb521cd2..62ccc0ad65594 100644 --- a/services/issue/label.go +++ b/services/issue/label.go @@ -44,11 +44,17 @@ func AddLabels(issue *models.Issue, doer *user_model.User, labels []*models.Labe // RemoveLabel removes a label from issue by given ID. func RemoveLabel(issue *models.Issue, doer *user_model.User, label *models.Label) error { - if err := issue.LoadRepo(db.DefaultContext); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { + return err + } + defer committer.Close() + + if err := issue.LoadRepo(ctx); err != nil { return err } - perm, err := models.GetUserRepoPermission(issue.Repo, doer) + perm, err := models.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return err } @@ -59,7 +65,11 @@ func RemoveLabel(issue *models.Issue, doer *user_model.User, label *models.Label return models.ErrRepoLabelNotExist{} } - if err := models.DeleteIssueLabel(issue, label, doer); err != nil { + if err := models.DeleteIssueLabel(ctx, issue, label, doer); err != nil { + return err + } + + if err := committer.Commit(); err != nil { return err } diff --git a/services/lfs/locks.go b/services/lfs/locks.go index fa51470d62626..0299452205756 100644 --- a/services/lfs/locks.go +++ b/services/lfs/locks.go @@ -88,7 +88,7 @@ func GetListLockHandler(ctx *context.Context) { }) return } - lock, err := models.GetLFSLockByID(v) + lock, err := models.GetLFSLockByID(ctx, v) if err != nil && !models.IsErrLFSLockNotExist(err) { log.Error("Unable to get lock with ID[%s]: Error: %v", v, err) } @@ -98,7 +98,7 @@ func GetListLockHandler(ctx *context.Context) { path := ctx.FormString("path") if path != "" { // Case where we request a specific id - lock, err := models.GetLFSLock(repository, path) + lock, err := models.GetLFSLock(ctx, repository, path) if err != nil && !models.IsErrLFSLockNotExist(err) { log.Error("Unable to get lock for repository %-v with path %s: Error: %v", repository, path, err) } diff --git a/services/lfs/server.go b/services/lfs/server.go index 633aa0a695275..c095bbfab4143 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -488,7 +488,7 @@ func authenticate(ctx *context.Context, repository *repo_model.Repository, autho } // ctx.IsSigned is unnecessary here, this will be checked in perm.CanAccess - perm, err := models.GetUserRepoPermission(repository, ctx.Doer) + perm, err := models.GetUserRepoPermission(ctx, repository, ctx.Doer) if err != nil { log.Error("Unable to GetUserRepoPermission for user %-v in repo %-v Error: %v", ctx.Doer, repository) return false diff --git a/services/pull/check.go b/services/pull/check.go index 29dc88e0f0c1d..f7747dfa2ac43 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -227,7 +227,7 @@ func getMergeCommit(ctx context.Context, pr *models.PullRequest) (*git.Commit, e // manuallyMerged checks if a pull request got manually merged // When a pull request got manually merged mark the pull request as merged func manuallyMerged(ctx context.Context, pr *models.PullRequest) bool { - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("PullRequest[%d].LoadBaseRepo: %v", pr.ID, err) return false } @@ -317,7 +317,7 @@ func testPR(id int64) { ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("Test PR[%d] from patch checking queue", id)) defer finished() - pr, err := models.GetPullRequestByID(id) + pr, err := models.GetPullRequestByID(ctx, id) if err != nil { log.Error("GetPullRequestByID[%d]: %v", id, err) return diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index be8df0c9b1588..143f3d50d0980 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -83,7 +83,7 @@ func IsCommitStatusContextSuccess(commitStatuses []*models.CommitStatus, require // IsPullCommitStatusPass returns if all required status checks PASS func IsPullCommitStatusPass(ctx context.Context, pr *models.PullRequest) (bool, error) { - if err := pr.LoadProtectedBranch(); err != nil { + if err := pr.LoadProtectedBranchCtx(ctx); err != nil { return false, errors.Wrap(err, "GetLatestCommitStatus") } if pr.ProtectedBranch == nil || !pr.ProtectedBranch.EnableStatusCheck { @@ -100,7 +100,7 @@ func IsPullCommitStatusPass(ctx context.Context, pr *models.PullRequest) (bool, // GetPullRequestCommitStatusState returns pull request merged commit status state func GetPullRequestCommitStatusState(ctx context.Context, pr *models.PullRequest) (structs.CommitStatusState, error) { // Ensure HeadRepo is loaded - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { return "", errors.Wrap(err, "LoadHeadRepo") } @@ -114,7 +114,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *models.PullRequest if pr.Flow == models.PullRequestFlowGithub && !headGitRepo.IsBranchExist(pr.HeadBranch) { return "", errors.New("Head branch does not exist, can not merge") } - if pr.Flow == models.PullRequestFlowAGit && !git.IsReferenceExist(headGitRepo.Ctx, headGitRepo.Path, pr.GetGitRefName()) { + if pr.Flow == models.PullRequestFlowAGit && !git.IsReferenceExist(ctx, headGitRepo.Path, pr.GetGitRefName()) { return "", errors.New("Head branch does not exist, can not merge") } @@ -128,11 +128,11 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *models.PullRequest return "", err } - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { return "", errors.Wrap(err, "LoadBaseRepo") } - commitStatuses, _, err := models.GetLatestCommitStatus(pr.BaseRepo.ID, sha, db.ListOptions{}) + commitStatuses, _, err := models.GetLatestCommitStatusCtx(ctx, pr.BaseRepo.ID, sha, db.ListOptions{}) if err != nil { return "", errors.Wrap(err, "GetLatestCommitStatus") } diff --git a/services/pull/merge.go b/services/pull/merge.go index 0c615d93c8516..7967bce6a9971 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -35,10 +35,10 @@ import ( // Caller should check PR is ready to be merged (review and status checks) // FIXME: add repoWorkingPull make sure two merges does not happen at same time. func Merge(ctx context.Context, pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (err error) { - if err = pr.LoadHeadRepo(); err != nil { + if err = pr.LoadHeadRepoCtx(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) return fmt.Errorf("LoadHeadRepo: %v", err) - } else if err = pr.LoadBaseRepo(); err != nil { + } else if err = pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) return fmt.Errorf("LoadBaseRepo: %v", err) } @@ -664,7 +664,7 @@ func IsUserAllowedToMerge(pr *models.PullRequest, p models.Permission, user *use // CheckPRReadyToMerge checks whether the PR is ready to be merged (reviews and status checks) func CheckPRReadyToMerge(ctx context.Context, pr *models.PullRequest, skipProtectedFilesCheck bool) (err error) { - if err = pr.LoadBaseRepo(); err != nil { + if err = pr.LoadBaseRepoCtx(ctx); err != nil { return fmt.Errorf("LoadBaseRepo: %v", err) } diff --git a/services/pull/patch.go b/services/pull/patch.go index f118ef33d022a..eeedcf2d382a1 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -27,7 +27,7 @@ import ( // DownloadDiffOrPatch will write the patch for the pr to the writer func DownloadDiffOrPatch(ctx context.Context, pr *models.PullRequest, w io.Writer, patch, binary bool) error { - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("Unable to load base repository ID %d for pr #%d [%d]", pr.BaseRepoID, pr.Index, pr.ID) return err } diff --git a/services/pull/pull.go b/services/pull/pull.go index f036211871322..0d10a23681e94 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -230,7 +230,7 @@ func checkForInvalidation(ctx context.Context, requests models.PullRequestList, } go func() { // FIXME: graceful: We need to tell the manager we're doing something... - err := requests.InvalidateCodeComments(doer, gitRepo, branch) + err := requests.InvalidateCodeComments(ctx, doer, gitRepo, branch) if err != nil { log.Error("PullRequestList.InvalidateCodeComments: %v", err) } @@ -341,14 +341,14 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, // checkIfPRContentChanged checks if diff to target branch has changed by push // A commit can be considered to leave the PR untouched if the patch/diff with its merge base is unchanged func checkIfPRContentChanged(ctx context.Context, pr *models.PullRequest, oldCommitID, newCommitID string) (hasChanged bool, err error) { - if err = pr.LoadHeadRepo(); err != nil { + if err = pr.LoadHeadRepoCtx(ctx); err != nil { return false, fmt.Errorf("LoadHeadRepo: %v", err) } else if pr.HeadRepo == nil { // corrupt data assumed changed return true, nil } - if err = pr.LoadBaseRepo(); err != nil { + if err = pr.LoadBaseRepoCtx(ctx); err != nil { return false, fmt.Errorf("LoadBaseRepo: %v", err) } @@ -419,13 +419,13 @@ func PushToBaseRepo(ctx context.Context, pr *models.PullRequest) (err error) { func pushToBaseRepoHelper(ctx context.Context, pr *models.PullRequest, prefixHeadBranch string) (err error) { log.Trace("PushToBaseRepo[%d]: pushing commits to base repo '%s'", pr.BaseRepoID, pr.GetGitRefName()) - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { log.Error("Unable to load head repository for PR[%d] Error: %v", pr.ID, err) return err } headRepoPath := pr.HeadRepo.RepoPath() - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err) return err } @@ -474,7 +474,7 @@ func pushToBaseRepoHelper(ctx context.Context, pr *models.PullRequest, prefixHea // UpdateRef update refs/pull/id/head directly for agit flow pull request func UpdateRef(ctx context.Context, pr *models.PullRequest) (err error) { log.Trace("UpdateRef[%d]: upgate pull request ref in base repo '%s'", pr.ID, pr.GetGitRefName()) - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err) return err } @@ -793,7 +793,7 @@ func getAllCommitStatus(gitRepo *git.Repository, pr *models.PullRequest) (status // IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head func IsHeadEqualWithBranch(ctx context.Context, pr *models.PullRequest, branchName string) (bool, error) { var err error - if err = pr.LoadBaseRepo(); err != nil { + if err = pr.LoadBaseRepoCtx(ctx); err != nil { return false, err } baseGitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, pr.BaseRepo.RepoPath()) @@ -807,7 +807,7 @@ func IsHeadEqualWithBranch(ctx context.Context, pr *models.PullRequest, branchNa return false, err } - if err = pr.LoadHeadRepo(); err != nil { + if err = pr.LoadHeadRepoCtx(ctx); err != nil { return false, err } var headGitRepo *git.Repository diff --git a/services/pull/review.go b/services/pull/review.go index e7e6f3135ba91..940fe4470d162 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -122,7 +122,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo return nil, fmt.Errorf("GetPullRequestByIssueID: %v", err) } pr := issue.PullRequest - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { return nil, fmt.Errorf("LoadHeadRepo: %v", err) } gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, pr.BaseRepo.RepoPath()) diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go index 22ef53937d8ac..f8f44ac0187bc 100644 --- a/services/pull/temp_repo.go +++ b/services/pull/temp_repo.go @@ -21,7 +21,7 @@ import ( // createTemporaryRepo creates a temporary repo with "base" for pr.BaseBranch and "tracking" for pr.HeadBranch // it also create a second base branch called "original_base" func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, error) { - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) return "", fmt.Errorf("LoadHeadRepo: %v", err) } else if pr.HeadRepo == nil { @@ -29,7 +29,7 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e return "", &repo_model.ErrRepoNotExist{ ID: pr.HeadRepoID, } - } else if err := pr.LoadBaseRepo(); err != nil { + } else if err := pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) return "", fmt.Errorf("LoadBaseRepo: %v", err) } else if pr.BaseRepo == nil { diff --git a/services/pull/update.go b/services/pull/update.go index 2ad58ecd29ac8..899bee1f19770 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -42,10 +42,10 @@ func Update(ctx context.Context, pull *models.PullRequest, doer *user_model.User return fmt.Errorf("Not support update agit flow pull request's head branch") } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) return fmt.Errorf("LoadHeadRepo: %v", err) - } else if err = pr.LoadBaseRepo(); err != nil { + } else if err = pr.LoadBaseRepoCtx(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) return fmt.Errorf("LoadBaseRepo: %v", err) } @@ -71,7 +71,7 @@ func Update(ctx context.Context, pull *models.PullRequest, doer *user_model.User } // IsUserAllowedToUpdate check if user is allowed to update PR with given permissions and branch protections -func IsUserAllowedToUpdate(pull *models.PullRequest, user *user_model.User) (mergeAllowed, rebaseAllowed bool, err error) { +func IsUserAllowedToUpdate(ctx context.Context, pull *models.PullRequest, user *user_model.User) (mergeAllowed, rebaseAllowed bool, err error) { if pull.Flow == models.PullRequestFlowAGit { return false, false, nil } @@ -79,7 +79,7 @@ func IsUserAllowedToUpdate(pull *models.PullRequest, user *user_model.User) (mer if user == nil { return false, false, nil } - headRepoPerm, err := models.GetUserRepoPermission(pull.HeadRepo, user) + headRepoPerm, err := models.GetUserRepoPermission(ctx, pull.HeadRepo, user) if err != nil { return false, false, err } @@ -122,10 +122,10 @@ func IsUserAllowedToUpdate(pull *models.PullRequest, user *user_model.User) (mer // GetDiverging determines how many commits a PR is ahead or behind the PR base branch func GetDiverging(ctx context.Context, pr *models.PullRequest) (*git.DivergeObject, error) { log.Trace("GetDiverging[%d]: compare commits", pr.ID) - if err := pr.LoadBaseRepo(); err != nil { + if err := pr.LoadBaseRepoCtx(ctx); err != nil { return nil, err } - if err := pr.LoadHeadRepo(); err != nil { + if err := pr.LoadHeadRepoCtx(ctx); err != nil { return nil, err } From 92dfbada3793fc2be23d38783d6842eac9825f58 Mon Sep 17 00:00:00 2001 From: Gusted Date: Thu, 28 Apr 2022 14:57:56 +0000 Subject: [PATCH 2/5] Better describe what `/repos/{owner}/{repo}/raw/{filepath}` returns on 200 (#19542) - Set on the description that it returns the raw file content. - Resolves #19514 --- routers/api/v1/repo/file.go | 2 +- templates/swagger/v1_json.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index ed51f6f4df2a2..d907e770ae117 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -53,7 +53,7 @@ func GetRawFile(ctx *context.APIContext) { // required: false // responses: // 200: - // description: success + // description: Returns raw file content. // "404": // "$ref": "#/responses/notFound" diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0374a53a6555c..ea03380d433b1 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -8628,7 +8628,7 @@ ], "responses": { "200": { - "description": "success" + "description": "Returns raw file content." }, "404": { "$ref": "#/responses/notFound" From 8eb1cd9264af9493e0f57a4a4c0a1f764f7cefcf Mon Sep 17 00:00:00 2001 From: qwerty287 <80460567+qwerty287@users.noreply.github.com> Date: Thu, 28 Apr 2022 17:45:33 +0200 Subject: [PATCH 3/5] Add "Allow edits from maintainer" feature (#18002) Adds a feature [like GitHub has](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) (step 7). If you create a new PR from a forked repo, you can select (and change later, but only if you are the PR creator/poster) the "Allow edits from maintainers" option. Then users with write access to the base branch get more permissions on this branch: * use the update pull request button * push directly from the command line (`git push`) * edit/delete/upload files via web UI * use related API endpoints You can't merge PRs to this branch with this enabled, you'll need "full" code write permissions. This feature has a pretty big impact on the permission system. I might forgot changing some things or didn't find security vulnerabilities. In this case, please leave a review or comment on this PR. Closes #17728 Co-authored-by: 6543 <6543@obermui.de> --- models/migrations/migrations.go | 3 ++ models/migrations/v213.go | 18 ++++++++ models/pull.go | 27 +++++++---- models/repo_permission.go | 34 ++++++++++++++ modules/context/permission.go | 10 +++++ modules/context/repo.go | 8 ++-- modules/convert/convert.go | 9 +++- modules/convert/pull.go | 2 + modules/structs/pull.go | 12 ++--- modules/structs/repo_file.go | 20 +++++++++ options/locale/locale_en-US.ini | 3 ++ routers/api/v1/api.go | 17 +++++-- routers/api/v1/repo/file.go | 10 +++-- routers/api/v1/repo/patch.go | 2 +- routers/api/v1/repo/pull.go | 12 +++++ routers/private/hook_pre_receive.go | 8 +++- routers/web/repo/compare.go | 2 + routers/web/repo/issue.go | 15 ++++--- routers/web/repo/pull.go | 45 +++++++++++++++---- routers/web/repo/view.go | 8 ++-- routers/web/web.go | 8 ++-- services/forms/repo_form.go | 24 ++++++---- services/pull/edits.go | 40 +++++++++++++++++ services/pull/update.go | 14 ++++++ templates/repo/issue/new_form.tmpl | 9 ++++ .../repo/issue/view_content/sidebar.tmpl | 16 +++++++ templates/swagger/v1_json.tmpl | 8 ++++ web_src/js/features/repo-issue.js | 33 ++++++++++++++ web_src/js/index.js | 2 + 29 files changed, 359 insertions(+), 60 deletions(-) create mode 100644 models/migrations/v213.go create mode 100644 services/pull/edits.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ba8ca85bc8d93..9e46791ec607b 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -61,6 +61,7 @@ type Version struct { // update minDBVersion accordingly var migrations = []Migration{ // Gitea 1.5.0 ends at v69 + // v70 -> v71 NewMigration("add issue_dependencies", addIssueDependencies), // v71 -> v72 @@ -380,6 +381,8 @@ var migrations = []Migration{ NewMigration("Create ForeignReference table", createForeignReferenceTable), // v212 -> v213 NewMigration("Add package tables", addPackageTables), + // v213 -> v214 + NewMigration("Add allow edits from maintainers to PullRequest table", addAllowMaintainerEdit), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v213.go b/models/migrations/v213.go new file mode 100644 index 0000000000000..b1dbf98d1ea25 --- /dev/null +++ b/models/migrations/v213.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func addAllowMaintainerEdit(x *xorm.Engine) error { + // PullRequest represents relation between pull request and repositories. + type PullRequest struct { + AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"` + } + + return x.Sync2(new(PullRequest)) +} diff --git a/models/pull.go b/models/pull.go index e04263af9ffe7..437b202d3feb4 100644 --- a/models/pull.go +++ b/models/pull.go @@ -69,15 +69,16 @@ type PullRequest struct { Issue *Issue `xorm:"-"` Index int64 - 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 - ProtectedBranch *ProtectedBranch `xorm:"-"` - MergeBase string `xorm:"VARCHAR(40)"` + 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 + ProtectedBranch *ProtectedBranch `xorm:"-"` + MergeBase string `xorm:"VARCHAR(40)"` + AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"` HasMerged bool `xorm:"INDEX"` MergedCommitID string `xorm:"VARCHAR(40)"` @@ -711,6 +712,14 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string { return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch) } +// UpdateAllowEdits update if PR can be edited from maintainers +func UpdateAllowEdits(ctx context.Context, pr *PullRequest) error { + if _, err := db.GetEngine(ctx).ID(pr.ID).Cols("allow_maintainer_edit").Update(pr); err != nil { + return err + } + return nil +} + // Mergeable returns if the pullrequest is mergeable. func (pr *PullRequest) Mergeable() bool { // If a pull request isn't mergable if it's: diff --git a/models/repo_permission.go b/models/repo_permission.go index b4291f2362d63..bc31b873f2e97 100644 --- a/models/repo_permission.go +++ b/models/repo_permission.go @@ -103,6 +103,39 @@ func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool { return p.CanWrite(unit.TypeIssues) } +// CanWriteToBranch checks if the branch is writable by the user +func (p *Permission) CanWriteToBranch(user *user_model.User, branch string) bool { + if p.CanWrite(unit.TypeCode) { + return true + } + + if len(p.Units) < 1 { + return false + } + + prs, err := GetUnmergedPullRequestsByHeadInfo(p.Units[0].RepoID, branch) + if err != nil { + return false + } + + for _, pr := range prs { + if pr.AllowMaintainerEdit { + err = pr.LoadBaseRepo() + if err != nil { + continue + } + prPerm, err := GetUserRepoPermission(db.DefaultContext, pr.BaseRepo, user) + if err != nil { + continue + } + if prPerm.CanWrite(unit.TypeCode) { + return true + } + } + } + return false +} + // ColorFormat writes a colored string for these Permissions func (p *Permission) ColorFormat(s fmt.State) { noColor := log.ColorBytes(log.Reset) @@ -160,6 +193,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use perm) }() } + // anonymous user visit private repo. // TODO: anonymous user visit public unit of private repo??? if user == nil && repo.IsPrivate { diff --git a/modules/context/permission.go b/modules/context/permission.go index 142b86faeaf5e..8dc3b3cd46ec1 100644 --- a/modules/context/permission.go +++ b/modules/context/permission.go @@ -29,6 +29,16 @@ func RequireRepoWriter(unitType unit.Type) func(ctx *Context) { } } +// CanEnableEditor checks if the user is allowed to write to the branch of the repo +func CanEnableEditor() func(ctx *Context) { + return func(ctx *Context) { + if !ctx.Repo.Permission.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) { + ctx.NotFound("CanWriteToBranch denies permission", nil) + return + } + } +} + // RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) { return func(ctx *Context) { diff --git a/modules/context/repo.go b/modules/context/repo.go index a02bb7e869116..b2c9a21f8e54f 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -78,8 +78,8 @@ type Repository struct { } // CanEnableEditor returns true if repository is editable and user has proper access level. -func (r *Repository) CanEnableEditor() bool { - return r.Permission.CanWrite(unit_model.TypeCode) && r.Repository.CanEnableEditor() && r.IsViewBranch && !r.Repository.IsArchived +func (r *Repository) CanEnableEditor(user *user_model.User) bool { + return r.IsViewBranch && r.Permission.CanWriteToBranch(user, r.BranchName) && r.Repository.CanEnableEditor() && !r.Repository.IsArchived } // CanCreateBranch returns true if repository is editable and user has proper access level. @@ -123,7 +123,7 @@ func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.Use sign, keyID, _, err := asymkey_service.SignCRUDAction(ctx, r.Repository.RepoPath(), doer, r.Repository.RepoPath(), git.BranchPrefix+r.BranchName) - canCommit := r.CanEnableEditor() && userCanPush + canCommit := r.CanEnableEditor(doer) && userCanPush if requireSigned { canCommit = canCommit && sign } @@ -139,7 +139,7 @@ func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.Use return CanCommitToBranchResults{ CanCommitToBranch: canCommit, - EditorEnabled: r.CanEnableEditor(), + EditorEnabled: r.CanEnableEditor(doer), UserCanPush: userCanPush, RequireSigned: requireSigned, WillSign: sign, diff --git a/modules/convert/convert.go b/modules/convert/convert.go index 3f565f76e087c..bd06f4dbf4bb3 100644 --- a/modules/convert/convert.go +++ b/modules/convert/convert.go @@ -41,12 +41,19 @@ func ToEmail(email *user_model.EmailAddress) *api.Email { func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *models.ProtectedBranch, user *user_model.User, isRepoAdmin bool) (*api.Branch, error) { if bp == nil { var hasPerm bool + var canPush bool var err error if user != nil { hasPerm, err = models.HasAccessUnit(user, repo, unit.TypeCode, perm.AccessModeWrite) if err != nil { return nil, err } + + perms, err := models.GetUserRepoPermission(db.DefaultContext, repo, user) + if err != nil { + return nil, err + } + canPush = perms.CanWriteToBranch(user, b.Name) } return &api.Branch{ @@ -56,7 +63,7 @@ func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *mod RequiredApprovals: 0, EnableStatusCheck: false, StatusCheckContexts: []string{}, - UserCanPush: hasPerm, + UserCanPush: canPush, UserCanMerge: hasPerm, }, nil } diff --git a/modules/convert/pull.go b/modules/convert/pull.go index 6034327a9d25f..a2f54270e4ffe 100644 --- a/modules/convert/pull.go +++ b/modules/convert/pull.go @@ -73,6 +73,8 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo Created: pr.Issue.CreatedUnix.AsTimePtr(), Updated: pr.Issue.UpdatedUnix.AsTimePtr(), + AllowMaintainerEdit: pr.AllowMaintainerEdit, + Base: &api.PRBranchInfo{ Name: pr.BaseBranch, Ref: pr.BaseBranch, diff --git a/modules/structs/pull.go b/modules/structs/pull.go index 653091b2f4321..b63b3edfd30a4 100644 --- a/modules/structs/pull.go +++ b/modules/structs/pull.go @@ -31,9 +31,10 @@ type PullRequest struct { Mergeable bool `json:"mergeable"` HasMerged bool `json:"merged"` // swagger:strfmt date-time - Merged *time.Time `json:"merged_at"` - MergedCommitID *string `json:"merge_commit_sha"` - MergedBy *User `json:"merged_by"` + Merged *time.Time `json:"merged_at"` + MergedCommitID *string `json:"merge_commit_sha"` + MergedBy *User `json:"merged_by"` + AllowMaintainerEdit bool `json:"allow_maintainer_edit"` Base *PRBranchInfo `json:"base"` Head *PRBranchInfo `json:"head"` @@ -90,6 +91,7 @@ type EditPullRequestOption struct { Labels []int64 `json:"labels"` State *string `json:"state"` // swagger:strfmt date-time - Deadline *time.Time `json:"due_date"` - RemoveDeadline *bool `json:"unset_due_date"` + Deadline *time.Time `json:"due_date"` + RemoveDeadline *bool `json:"unset_due_date"` + AllowMaintainerEdit *bool `json:"allow_maintainer_edit"` } diff --git a/modules/structs/repo_file.go b/modules/structs/repo_file.go index e2947bf7ac7b0..135e6484cd69b 100644 --- a/modules/structs/repo_file.go +++ b/modules/structs/repo_file.go @@ -30,6 +30,11 @@ type CreateFileOptions struct { Content string `json:"content"` } +// Branch returns branch name +func (o *CreateFileOptions) Branch() string { + return o.FileOptions.BranchName +} + // DeleteFileOptions options for deleting files (used for other File structs below) // Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used) type DeleteFileOptions struct { @@ -39,6 +44,11 @@ type DeleteFileOptions struct { SHA string `json:"sha" binding:"Required"` } +// Branch returns branch name +func (o *DeleteFileOptions) Branch() string { + return o.FileOptions.BranchName +} + // UpdateFileOptions options for updating files // Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used) type UpdateFileOptions struct { @@ -50,6 +60,16 @@ type UpdateFileOptions struct { FromPath string `json:"from_path" binding:"MaxSize(500)"` } +// Branch returns branch name +func (o *UpdateFileOptions) Branch() string { + return o.FileOptions.BranchName +} + +// FileOptionInterface provides a unified interface for the different file options +type FileOptionInterface interface { + Branch() string +} + // ApplyDiffPatchFileOptions options for applying a diff patch // Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used) type ApplyDiffPatchFileOptions struct { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 5ec001b6d46cb..0175c8bfc8b00 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1488,6 +1488,9 @@ pulls.desc = Enable pull requests and code reviews. pulls.new = New Pull Request pulls.view = View Pull Request pulls.compare_changes = New Pull Request +pulls.allow_edits_from_maintainers = Allow edits from maintainers +pulls.allow_edits_from_maintainers_desc = Users with write access to the base branch can also push to this branch +pulls.allow_edits_from_maintainers_err = Updating failed pulls.compare_changes_desc = Select the branch to merge into and the branch to pull from. pulls.compare_base = merge into pulls.compare_compare = pull from diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index cca0f37ba107f..782500e6c86f7 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -283,6 +283,15 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { } } +// reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin +func reqRepoBranchWriter(ctx *context.APIContext) { + options, ok := web.GetForm(ctx).(api.FileOptionInterface) + if !ok || (!ctx.Repo.CanWriteToBranch(ctx.Doer, options.Branch()) && !ctx.IsUserSiteAdmin()) { + ctx.Error(http.StatusForbidden, "reqRepoBranchWriter", "user should have a permission to write to this branch") + return + } +} + // reqRepoReader user should have specific read permission or be a repo admin or a site admin func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -1021,10 +1030,10 @@ func Routes() *web.Route { m.Get("", repo.GetContentsList) m.Get("/*", repo.GetContents) m.Group("/*", func() { - m.Post("", bind(api.CreateFileOptions{}), repo.CreateFile) - m.Put("", bind(api.UpdateFileOptions{}), repo.UpdateFile) - m.Delete("", bind(api.DeleteFileOptions{}), repo.DeleteFile) - }, reqRepoWriter(unit.TypeCode), reqToken()) + m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, repo.CreateFile) + m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, repo.UpdateFile) + m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, repo.DeleteFile) + }, reqToken()) }, reqRepoReader(unit.TypeCode)) m.Get("/signing-key.gpg", misc.SigningKey) m.Group("/topics", func() { diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index d907e770ae117..b8b72f95ebabe 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -173,8 +173,10 @@ func GetEditorconfig(ctx *context.APIContext) { } // canWriteFiles returns true if repository is editable and user has proper access level. -func canWriteFiles(r *context.Repository) bool { - return r.Permission.CanWrite(unit.TypeCode) && !r.Repository.IsMirror && !r.Repository.IsArchived +func canWriteFiles(ctx *context.APIContext, branch string) bool { + return ctx.Repo.Permission.CanWriteToBranch(ctx.Doer, branch) && + !ctx.Repo.Repository.IsMirror && + !ctx.Repo.Repository.IsArchived } // canReadFiles returns true if repository is readable and user has proper access level. @@ -376,7 +378,7 @@ func handleCreateOrUpdateFileError(ctx *context.APIContext, err error) { // Called from both CreateFile or UpdateFile to handle both func createOrUpdateFile(ctx *context.APIContext, opts *files_service.UpdateRepoFileOptions) (*api.FileResponse, error) { - if !canWriteFiles(ctx.Repo) { + if !canWriteFiles(ctx, opts.OldBranch) { return nil, models.ErrUserDoesNotHaveAccessToRepo{ UserID: ctx.Doer.ID, RepoName: ctx.Repo.Repository.LowerName, @@ -433,7 +435,7 @@ func DeleteFile(ctx *context.APIContext) { // "$ref": "#/responses/error" apiOpts := web.GetForm(ctx).(*api.DeleteFileOptions) - if !canWriteFiles(ctx.Repo) { + if !canWriteFiles(ctx, apiOpts.BranchName) { ctx.Error(http.StatusForbidden, "DeleteFile", models.ErrUserDoesNotHaveAccessToRepo{ UserID: ctx.Doer.ID, RepoName: ctx.Repo.Repository.LowerName, diff --git a/routers/api/v1/repo/patch.go b/routers/api/v1/repo/patch.go index ae64c6efe3aa3..6dbf979701fc5 100644 --- a/routers/api/v1/repo/patch.go +++ b/routers/api/v1/repo/patch.go @@ -77,7 +77,7 @@ func ApplyDiffPatch(ctx *context.APIContext) { opts.Message = "apply-patch" } - if !canWriteFiles(ctx.Repo) { + if !canWriteFiles(ctx, apiOpts.BranchName) { ctx.Error(http.StatusInternalServerError, "ApplyPatch", models.ErrUserDoesNotHaveAccessToRepo{ UserID: ctx.Doer.ID, RepoName: ctx.Repo.Repository.LowerName, diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 6b076eff8fad3..95178021838ca 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -616,6 +616,18 @@ func EditPullRequest(ctx *context.APIContext) { notification.NotifyPullRequestChangeTargetBranch(ctx.Doer, pr, form.Base) } + // update allow edits + if form.AllowMaintainerEdit != nil { + if err := pull_service.SetAllowEdits(ctx, ctx.Doer, pr, *form.AllowMaintainerEdit); err != nil { + if errors.Is(pull_service.ErrUserHasNoPermissionForAction, err) { + ctx.Error(http.StatusForbidden, "SetAllowEdits", fmt.Sprintf("SetAllowEdits: %s", err)) + return + } + ctx.ServerError("SetAllowEdits", err) + return + } + } + // Refetch from database pr, err = models.GetPullRequestByIndex(ctx.Repo.Repository.ID, pr.Index) if err != nil { diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index ccb6933787a1b..8824d9cc39841 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -45,6 +45,8 @@ type preReceiveContext struct { env []string opts *private.HookOptions + + branchName string } // CanWriteCode returns true if pusher can write code @@ -53,7 +55,7 @@ func (ctx *preReceiveContext) CanWriteCode() bool { if !ctx.loadPusherAndPermission() { return false } - ctx.canWriteCode = ctx.userPerm.CanWrite(unit.TypeCode) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite + ctx.canWriteCode = ctx.userPerm.CanWriteToBranch(ctx.user, ctx.branchName) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite ctx.checkedCanWriteCode = true } return ctx.canWriteCode @@ -134,13 +136,15 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { } func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName string) { + branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) + ctx.branchName = branchName + if !ctx.AssertCanWriteCode() { return } repo := ctx.Repo.Repository gitRepo := ctx.Repo.GitRepo - branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) if branchName == repo.DefaultBranch && newCommitID == git.EmptySHA { log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 9f7bef43ef7eb..7721507baea93 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -398,6 +398,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { } ctx.Data["HeadRepo"] = ci.HeadRepo + ctx.Data["BaseCompareRepo"] = ctx.Repo.Repository // Now we need to assert that the ctx.Doer has permission to read // the baseRepo's code and pulls @@ -436,6 +437,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { ctx.NotFound("ParseCompareInfo", nil) return nil } + ctx.Data["CanWriteToHeadRepo"] = permHead.CanWrite(unit.TypeCode) } // If we have a rootRepo and it's different from: diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 8e865e448fc18..a54ad3306bb3b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1529,7 +1529,7 @@ func ViewIssue(ctx *context.Context) { if ctx.IsSigned { if err := pull.LoadHeadRepoCtx(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) - } else if pull.HeadRepo != nil && pull.HeadBranch != pull.HeadRepo.DefaultBranch { + } else if pull.HeadRepo != nil { perm, err := models.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) @@ -1537,12 +1537,15 @@ func ViewIssue(ctx *context.Context) { } if perm.CanWrite(unit.TypeCode) { // Check if branch is not protected - if protected, err := models.IsProtectedBranch(pull.HeadRepo.ID, pull.HeadBranch); err != nil { - log.Error("IsProtectedBranch: %v", err) - } else if !protected { - canDelete = true - ctx.Data["DeleteBranchLink"] = issue.Link() + "/cleanup" + if pull.HeadBranch != pull.HeadRepo.DefaultBranch { + if protected, err := models.IsProtectedBranch(pull.HeadRepo.ID, pull.HeadBranch); err != nil { + log.Error("IsProtectedBranch: %v", err) + } else if !protected { + canDelete = true + ctx.Data["DeleteBranchLink"] = issue.Link() + "/cleanup" + } } + ctx.Data["CanWriteToHeadRepo"] = true } } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index a03e16f39a2b3..99faa5413828a 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1132,14 +1132,15 @@ func CompareAndPullRequestPost(ctx *context.Context) { Content: form.Content, } pullRequest := &models.PullRequest{ - HeadRepoID: ci.HeadRepo.ID, - BaseRepoID: repo.ID, - HeadBranch: ci.HeadBranch, - BaseBranch: ci.BaseBranch, - HeadRepo: ci.HeadRepo, - BaseRepo: repo, - MergeBase: ci.CompareInfo.MergeBase, - Type: models.PullRequestGitea, + HeadRepoID: ci.HeadRepo.ID, + BaseRepoID: repo.ID, + HeadBranch: ci.HeadBranch, + BaseBranch: ci.BaseBranch, + HeadRepo: ci.HeadRepo, + BaseRepo: repo, + MergeBase: ci.CompareInfo.MergeBase, + Type: models.PullRequestGitea, + AllowMaintainerEdit: form.AllowMaintainerEdit, } // FIXME: check error in the case two people send pull request at almost same time, give nice error prompt // instead of 500. @@ -1411,3 +1412,31 @@ func UpdatePullRequestTarget(ctx *context.Context) { "base_branch": pr.BaseBranch, }) } + +// SetAllowEdits allow edits from maintainers to PRs +func SetAllowEdits(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.UpdateAllowEditsForm) + + pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrPullRequestNotExist(err) { + ctx.NotFound("GetPullRequestByIndex", err) + } else { + ctx.ServerError("GetPullRequestByIndex", err) + } + return + } + + if err := pull_service.SetAllowEdits(ctx, ctx.Doer, pr, form.AllowMaintainerEdit); err != nil { + if errors.Is(pull_service.ErrUserHasNoPermissionForAction, err) { + ctx.Error(http.StatusForbidden) + return + } + ctx.ServerError("SetAllowEdits", err) + return + } + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "allow_maintainer_edit": pr.AllowMaintainerEdit, + }) +} diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 168927d101ae4..86fc36fad7c8c 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -579,7 +579,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["LineEscapeStatus"] = statuses } if !isLFSFile { - if ctx.Repo.CanEnableEditor() { + if ctx.Repo.CanEnableEditor(ctx.Doer) { if lfsLock != nil && lfsLock.OwnerID != ctx.Doer.ID { ctx.Data["CanEditFile"] = false ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.this_file_locked") @@ -589,7 +589,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } else if !ctx.Repo.IsViewBranch { ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch") - } else if !ctx.Repo.CanWrite(unit_model.TypeCode) { + } else if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) { ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.fork_before_edit") } } @@ -629,7 +629,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } - if ctx.Repo.CanEnableEditor() { + if ctx.Repo.CanEnableEditor(ctx.Doer) { if lfsLock != nil && lfsLock.OwnerID != ctx.Doer.ID { ctx.Data["CanDeleteFile"] = false ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.this_file_locked") @@ -639,7 +639,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } else if !ctx.Repo.IsViewBranch { ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch") - } else if !ctx.Repo.CanWrite(unit_model.TypeCode) { + } else if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) { ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_have_write_access") } } diff --git a/routers/web/web.go b/routers/web/web.go index 0de6f1372275c..22b8e7cdf3abc 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -574,6 +574,7 @@ func RegisterRoutes(m *web.Route) { reqRepoAdmin := context.RequireRepoAdmin() reqRepoCodeWriter := context.RequireRepoWriter(unit.TypeCode) + canEnableEditor := context.CanEnableEditor() reqRepoCodeReader := context.RequireRepoReader(unit.TypeCode) reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases) reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases) @@ -925,12 +926,12 @@ func RegisterRoutes(m *web.Route) { Post(bindIgnErr(forms.EditRepoFileForm{}), repo.NewDiffPatchPost) m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick). Post(bindIgnErr(forms.CherryPickForm{}), repo.CherryPickPost) - }, context.RepoRefByType(context.RepoRefBranch), repo.MustBeEditable) + }, repo.MustBeEditable) m.Group("", func() { m.Post("/upload-file", repo.UploadFileToServer) m.Post("/upload-remove", bindIgnErr(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer) - }, context.RepoRef(), repo.MustBeEditable, repo.MustBeAbleToUpload) - }, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty) + }, repo.MustBeEditable, repo.MustBeAbleToUpload) + }, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived(), repo.MustBeNotEmpty) m.Group("/branches", func() { m.Group("/_new", func() { @@ -1105,6 +1106,7 @@ func RegisterRoutes(m *web.Route) { m.Get("/commits", context.RepoRef(), repo.ViewPullCommits) m.Post("/merge", context.RepoMustNotBeArchived(), bindIgnErr(forms.MergePullRequestForm{}), repo.MergePullRequest) m.Post("/update", repo.UpdatePullRequest) + m.Post("/set_allow_maintainer_edit", bindIgnErr(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits) m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest) m.Group("/files", func() { m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.ViewPullFiles) diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 80123e9af3228..f40e99a0440a5 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -422,15 +422,16 @@ func (f *NewPackagistHookForm) Validate(req *http.Request, errs binding.Errors) // CreateIssueForm form for creating issue type CreateIssueForm struct { - Title string `binding:"Required;MaxSize(255)"` - LabelIDs string `form:"label_ids"` - AssigneeIDs string `form:"assignee_ids"` - Ref string `form:"ref"` - MilestoneID int64 - ProjectID int64 - AssigneeID int64 - Content string - Files []string + Title string `binding:"Required;MaxSize(255)"` + LabelIDs string `form:"label_ids"` + AssigneeIDs string `form:"assignee_ids"` + Ref string `form:"ref"` + MilestoneID int64 + ProjectID int64 + AssigneeID int64 + Content string + Files []string + AllowMaintainerEdit bool } // Validate validates the fields @@ -684,6 +685,11 @@ type DismissReviewForm struct { Message string } +// UpdateAllowEditsForm form for changing if PR allows edits from maintainers +type UpdateAllowEditsForm struct { + AllowMaintainerEdit bool +} + // __________ .__ // \______ \ ____ | | ____ _____ ______ ____ // | _// __ \| | _/ __ \\__ \ / ___// __ \ diff --git a/services/pull/edits.go b/services/pull/edits.go new file mode 100644 index 0000000000000..68515ec14157b --- /dev/null +++ b/services/pull/edits.go @@ -0,0 +1,40 @@ +// Copyright 2022 The Gitea Authors. +// All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package pull + +import ( + "context" + "errors" + + "code.gitea.io/gitea/models" + unit_model "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" +) + +var ErrUserHasNoPermissionForAction = errors.New("user not allowed to do this action") + +// SetAllowEdits allow edits from maintainers to PRs +func SetAllowEdits(ctx context.Context, doer *user_model.User, pr *models.PullRequest, allow bool) error { + if doer == nil || !pr.Issue.IsPoster(doer.ID) { + return ErrUserHasNoPermissionForAction + } + + if err := pr.LoadHeadRepo(); err != nil { + return err + } + + permission, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, doer) + if err != nil { + return err + } + + if !permission.CanWrite(unit_model.TypeCode) { + return ErrUserHasNoPermissionForAction + } + + pr.AllowMaintainerEdit = allow + return models.UpdateAllowEdits(ctx, pr) +} diff --git a/services/pull/update.go b/services/pull/update.go index 899bee1f19770..2d845e8504df0 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -111,11 +111,25 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *models.PullRequest, user * return false, false, nil } + baseRepoPerm, err := models.GetUserRepoPermission(ctx, pull.BaseRepo, user) + if err != nil { + return false, false, err + } + mergeAllowed, err = IsUserAllowedToMerge(pr, headRepoPerm, user) if err != nil { return false, false, err } + if pull.AllowMaintainerEdit { + mergeAllowedMaintainer, err := IsUserAllowedToMerge(pr, baseRepoPerm, user) + if err != nil { + return false, false, err + } + + mergeAllowed = mergeAllowed || mergeAllowedMaintainer + } + return mergeAllowed, rebaseAllowed, nil } diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl index 1089c82415ab8..9a4548643fb99 100644 --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -235,6 +235,15 @@ {{end}} + {{if and .PageIsComparePull (not (eq .HeadRepo.FullName .BaseCompareRepo.FullName)) .CanWriteToHeadRepo}} +
+
+
+ + +
+
+ {{end}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index e673add812a83..9e9bc670a0d7a 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -667,5 +667,21 @@ {{end}} + + {{if and .Issue.IsPull .IsIssuePoster (not .Issue.IsClosed)}} + {{if and (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) .CanWriteToHeadRepo}} +
+
+
+ + +
+
+ {{end}} + {{end}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index ea03380d433b1..d57a3a580b92f 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -14938,6 +14938,10 @@ "description": "EditPullRequestOption options when modify pull request", "type": "object", "properties": { + "allow_maintainer_edit": { + "type": "boolean", + "x-go-name": "AllowMaintainerEdit" + }, "assignee": { "type": "string", "x-go-name": "Assignee" @@ -17045,6 +17049,10 @@ "description": "PullRequest represents a pull request", "type": "object", "properties": { + "allow_maintainer_edit": { + "type": "boolean", + "x-go-name": "AllowMaintainerEdit" + }, "assignee": { "$ref": "#/definitions/User" }, diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 14b1976bbbd64..a39a704f4793a 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -288,6 +288,39 @@ export function initRepoPullRequestMergeInstruction() { }); } +export function initRepoPullRequestAllowMaintainerEdit() { + const $checkbox = $('#allow-edits-from-maintainers'); + if (!$checkbox.length) return; + + const promptTip = $checkbox.attr('data-prompt-tip'); + const promptError = $checkbox.attr('data-prompt-error'); + $checkbox.popup({content: promptTip}); + $checkbox.checkbox({ + 'onChange': () => { + const checked = $checkbox.checkbox('is checked'); + let url = $checkbox.attr('data-url'); + url += '/set_allow_maintainer_edit'; + $checkbox.checkbox('set disabled'); + $.ajax({url, type: 'POST', + data: {_csrf: csrfToken, allow_maintainer_edit: checked}, + error: () => { + $checkbox.popup({ + content: promptError, + onHidden: () => { + // the error popup should be shown only once, then we restore the popup to the default message + $checkbox.popup({content: promptTip}); + }, + }); + $checkbox.popup('show'); + }, + complete: () => { + $checkbox.checkbox('set enabled'); + }, + }); + }, + }); +} + export function initRepoIssueReferenceRepositorySearch() { $('.issue_reference_repository_search') .dropdown({ diff --git a/web_src/js/index.js b/web_src/js/index.js index f5d72aff93d4d..5b95a0d8efa88 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -36,6 +36,7 @@ import { initRepoIssueTimeTracking, initRepoIssueWipTitle, initRepoPullRequestMergeInstruction, + initRepoPullRequestAllowMaintainerEdit, initRepoPullRequestReview, } from './features/repo-issue.js'; import { @@ -158,6 +159,7 @@ $(document).ready(() => { initRepoMigrationStatusChecker(); initRepoProject(); initRepoPullRequestMergeInstruction(); + initRepoPullRequestAllowMaintainerEdit(); initRepoPullRequestReview(); initRepoRelease(); initRepoReleaseEditor(); From a51efb4c2c315db0deb4120c8f2874390c2d7e40 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 29 Apr 2022 01:39:50 +0800 Subject: [PATCH 4/5] Support `hostname:port` to pass host matcher's check #19543 (#19543) hostmatcher: split the hostname from the `hostname:port` string, use the correct hostname to do the match. --- modules/hostmatcher/hostmatcher.go | 9 +++++++-- modules/hostmatcher/hostmatcher_test.go | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/hostmatcher/hostmatcher.go b/modules/hostmatcher/hostmatcher.go index 6c5c2a74d98ca..00bbc6cb0a83f 100644 --- a/modules/hostmatcher/hostmatcher.go +++ b/modules/hostmatcher/hostmatcher.go @@ -125,13 +125,18 @@ func (hl *HostMatchList) checkIP(ip net.IP) bool { // MatchHostName checks if the host matches an allow/deny(block) list func (hl *HostMatchList) MatchHostName(host string) bool { + hostname, _, err := net.SplitHostPort(host) + if err != nil { + hostname = host + } + if hl == nil { return false } - if hl.checkPattern(host) { + if hl.checkPattern(hostname) { return true } - if ip := net.ParseIP(host); ip != nil { + if ip := net.ParseIP(hostname); ip != nil { return hl.checkIP(ip) } return false diff --git a/modules/hostmatcher/hostmatcher_test.go b/modules/hostmatcher/hostmatcher_test.go index 66030a32f1ed7..b93976df6a61e 100644 --- a/modules/hostmatcher/hostmatcher_test.go +++ b/modules/hostmatcher/hostmatcher_test.go @@ -38,6 +38,7 @@ func TestHostOrIPMatchesList(t *testing.T) { {"", net.ParseIP("10.0.1.1"), true}, {"10.0.1.1", nil, true}, + {"10.0.1.1:8080", nil, true}, {"", net.ParseIP("192.168.1.1"), true}, {"192.168.1.1", nil, true}, {"", net.ParseIP("fd00::1"), true}, @@ -48,6 +49,7 @@ func TestHostOrIPMatchesList(t *testing.T) { {"mydomain.com", net.IPv4zero, false}, {"sub.mydomain.com", net.IPv4zero, true}, + {"sub.mydomain.com:8080", net.IPv4zero, true}, {"", net.ParseIP("169.254.1.1"), true}, {"169.254.1.1", nil, true}, From 53829b84f06f4734d6abe4b3c44d18e960dd53c1 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 29 Apr 2022 00:10:15 +0000 Subject: [PATCH 5/5] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-BR.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 765776da436e2..5f5f16eac93b8 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1729,6 +1729,7 @@ activity.git_stats_deletion_n=%d exclusões search=Pesquisar search.search_repo=Pesquisar no repositório... search.fuzzy=Aproximada +search.match=Corresponde search.results=Resultados da pesquisa para "%s" em %s search.code_no_results=Nenhum código-fonte correspondente ao seu termo de pesquisa foi encontrado. search.code_search_unavailable=A pesquisa por código não está disponível no momento. Entre em contato com o administrador do site. @@ -1793,6 +1794,7 @@ settings.pulls.allow_rebase_merge_commit=Habilitar Rebasing com commits explíci settings.pulls.allow_squash_commits=Habilitar Squashing em commits via merge settings.pulls.allow_manual_merge=Habilitar Marcar PR como aplicado manualmente settings.pulls.enable_autodetect_manual_merge=Habilitar a detecção automática de merge manual (Nota: Em alguns casos especiais, podem ocorrer julgamentos errados) +settings.pulls.allow_rebase_update=Ativar atualização do branch do pull request por rebase settings.pulls.default_delete_branch_after_merge=Excluir o branch de pull request após o merge por padrão settings.packages_desc=Habilitar Registro de Pacotes de Repositório settings.projects_desc=Habilitar Projetos do Repositório @@ -2602,6 +2604,7 @@ auths.use_paged_search=Use a pesquisa paginada auths.search_page_size=Tamanho da página auths.filter=Filtro de usuário auths.admin_filter=Filtro de administrador +auths.group_attribute_list_users=Atributo do Grupo que Contém a Lista de Usuários auths.enable_ldap_groups=Habilitar grupos do LDAP auths.ms_ad_sa=Atributos de pesquisa do MS AD auths.smtp_auth=Tipo de autenticação SMTP @@ -2629,6 +2632,8 @@ auths.oauth2_profileURL=URL do perfil auths.oauth2_emailURL=URL de e-mail auths.skip_local_two_fa=Pular 2FA local auths.skip_local_two_fa_helper=Deixar desligado significa que os usuários locais com 2FA ligada ainda terão que fazer login com 2FA +auths.oauth2_tenant=Tenant +auths.oauth2_scopes=Escopos Adicionais auths.enable_auto_register=Habilitar cadastro automático auths.sspi_auto_create_users=Criar usuários automaticamente auths.sspi_auto_create_users_helper=Permitir que o método de autenticação SSPI crie automaticamente novas contas para usuários que fazem o login pela primeira vez @@ -3044,6 +3049,7 @@ maven.documentation=Para obter mais informações sobre o registro Maven, consul nuget.registry=Configurar este registro pela linha de comando: nuget.install=Para instalar o pacote usando NuGet, execute o seguinte comando: nuget.documentation=Para obter mais informações sobre o registro Nuget, consulte a documentação. +nuget.dependency.framework=Estrutura Alvo npm.registry=Configure este registro no arquivo .npmrc do seu projeto: npm.install=Para instalar o pacote usando o npm, execute o seguinte comando: npm.install2=ou adicione-o ao arquivo package.json: