0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-06-12 11:32:32 +02:00

Merge remote-tracking branch 'upstream/main' into limit-repo-size

This commit is contained in:
DmitryFrolovTri 2022-12-14 05:27:36 +00:00
commit d1368ecfb6
166 changed files with 2898 additions and 1090 deletions

View File

@ -778,6 +778,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
func getReleaseCount(id int64) (int64, error) {
return repo_model.GetReleaseCountByRepoID(
db.DefaultContext,
id,
repo_model.FindReleasesOptions{
IncludeTags: true,

View File

@ -2147,7 +2147,7 @@ ROUTER = console
;[cron.update_checker]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = false
;ENABLED = true
;RUN_AT_START = false
;ENABLE_SUCCESS_NOTICE = false
;SCHEDULE = @every 168h

View File

@ -1005,7 +1005,7 @@ Default templates for project boards:
#### Cron - Check for new Gitea versions ('cron.update_checker')
- `ENABLED`: **false**: Enable service.
- `ENABLED`: **true**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `ENABLE_SUCCESS_NOTICE`: **true**: Set to false to switch off success notices.
- `SCHEDULE`: **@every 168h**: Cron syntax for scheduling a work, e.g. `@every 168h`.

View File

@ -145,7 +145,7 @@ launched manually from command line, it can be killed by pressing `Ctrl + C`.
Gitea will search for a number of things from the _`CustomPath`_. By default this is
the `custom/` directory in the current working directory when running Gitea. It will also
look for its configuration file _`CustomConf`_ in _`CustomPath`_/conf/app.ini`, and will use the
look for its configuration file _`CustomConf`_ in `$(CustomPath)/conf/app.ini`, and will use the
current working directory as the relative base path _`AppWorkPath`_ for a number configurable
values. Finally the static files will be served from _`StaticRootPath`_ which defaults to the _`AppWorkPath`_.

6
go.mod
View File

@ -105,8 +105,8 @@ require (
gopkg.in/yaml.v3 v3.0.1
mvdan.cc/xurls/v2 v2.4.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.11
xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f
xorm.io/builder v0.3.12
xorm.io/xorm v1.3.3-0.20221209153726-f1bfc5ce9830
)
require (
@ -182,7 +182,7 @@ require (
github.com/go-openapi/strfmt v0.21.3 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-openapi/validate v0.22.0 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect

12
go.sum
View File

@ -599,8 +599,8 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@ -2379,7 +2379,7 @@ sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.11 h1:naLkJitGyYW7ZZdncsh/JW+HF4HshmvTHTyUyPwJS00=
xorm.io/builder v0.3.11/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f h1:3NvNsM4lnttTsHpk8ODHqrwN1MCEjsO3bD/rpd8A47k=
xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM=
xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.3-0.20221209153726-f1bfc5ce9830 h1:ohaHCvT7ocSDkTEa2/2z0BXfINYlHm/Z7IzN7MeXQlM=
xorm.io/xorm v1.3.3-0.20221209153726-f1bfc5ce9830/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=

View File

@ -46,7 +46,7 @@ type Engine interface {
Incr(column string, arg ...interface{}) *xorm.Session
Insert(...interface{}) (int64, error)
Iterate(interface{}, xorm.IterFunc) error
Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *xorm.Session
Join(joinOperator string, tablename, condition interface{}, args ...interface{}) *xorm.Session
SQL(interface{}, ...interface{}) *xorm.Session
Where(interface{}, ...interface{}) *xorm.Session
Asc(colNames ...string) *xorm.Session

View File

@ -25,7 +25,7 @@ func TestIterate(t *testing.T) {
return nil
})
assert.NoError(t, err)
assert.EqualValues(t, 79, repoCnt)
assert.EqualValues(t, 80, repoCnt)
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}

View File

@ -544,3 +544,9 @@
repo_id: 51
type: 2
created_unix: 946684810
-
id: 80
repo_id: 53
type: 1
created_unix: 946684810

View File

@ -1558,3 +1558,30 @@
size: 0
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false
-
id: 53
owner_id: 30
owner_name: user30
lower_name: renderer
name: renderer
is_archived: false
is_empty: false
is_private: false
num_issues: 0
num_closed_issues: 0
num_pulls: 0
num_closed_pulls: 0
num_milestones: 0
num_closed_milestones: 0
num_watches: 0
num_projects: 0
num_closed_projects: 0
status: 0
is_fork: false
fork_id: 0
is_template: false
template_id: 0
size: 0
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false

View File

@ -1102,7 +1102,7 @@
num_followers: 0
num_following: 0
num_stars: 0
num_repos: 3
num_repos: 4
num_teams: 0
num_members: 0
visibility: 0

View File

@ -102,7 +102,7 @@ func toggleIssueAssignee(ctx context.Context, issue *Issue, doer *user_model.Use
AssigneeID: assigneeID,
}
// Comment
comment, err = CreateCommentCtx(ctx, opts)
comment, err = CreateComment(ctx, opts)
if err != nil {
return false, nil, fmt.Errorf("createComment: %w", err)
}

View File

@ -779,8 +779,8 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
return err
}
// CreateCommentCtx creates comment with context
func CreateCommentCtx(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) {
// CreateComment creates comment with context
func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) {
e := db.GetEngine(ctx)
var LabelID int64
if opts.Label != nil {
@ -875,6 +875,8 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
return fmt.Errorf("update attachment [%d]: %w", attachments[i].ID, err)
}
}
comment.Attachments = attachments
case CommentTypeReopen, CommentTypeClose:
if err = repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.Issue.IsPull, true); err != nil {
return err
@ -913,7 +915,7 @@ func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Is
Issue: issue,
Content: content,
}
comment, err := CreateCommentCtx(ctx, opts)
comment, err := CreateComment(ctx, opts)
if err != nil {
return nil, err
}
@ -938,7 +940,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is
Issue: issue,
DependentIssueID: dependentIssue.ID,
}
if _, err = CreateCommentCtx(ctx, opts); err != nil {
if _, err = CreateComment(ctx, opts); err != nil {
return
}
@ -949,7 +951,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is
Issue: dependentIssue,
DependentIssueID: issue.ID,
}
_, err = CreateCommentCtx(ctx, opts)
_, err = CreateComment(ctx, opts)
return err
}
@ -991,55 +993,6 @@ type CreateCommentOptions struct {
Invalidated bool
}
// CreateComment creates comment of issue or commit.
func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
ctx, committer, err := db.TxContext(db.DefaultContext)
if err != nil {
return nil, err
}
defer committer.Close()
comment, err = CreateCommentCtx(ctx, opts)
if err != nil {
return nil, err
}
if err = committer.Commit(); err != nil {
return nil, err
}
return comment, nil
}
// CreateRefComment creates a commit reference comment to issue.
func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue *Issue, content, commitSHA string) error {
if len(commitSHA) == 0 {
return fmt.Errorf("cannot create reference with empty commit SHA")
}
// Check if same reference from same commit has already existed.
has, err := db.GetEngine(db.DefaultContext).Get(&Comment{
Type: CommentTypeCommitRef,
IssueID: issue.ID,
CommitSHA: commitSHA,
})
if err != nil {
return fmt.Errorf("check reference comment: %w", err)
} else if has {
return nil
}
_, err = CreateComment(&CreateCommentOptions{
Type: CommentTypeCommitRef,
Doer: doer,
Repo: repo,
Issue: issue,
CommitSHA: commitSHA,
Content: content,
})
return err
}
// GetCommentByID returns the comment by given ID.
func GetCommentByID(ctx context.Context, id int64) (*Comment, error) {
c := new(Comment)
@ -1315,39 +1268,6 @@ func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID
return err
}
// CreatePushPullComment create push code to pull base comment
func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) {
if pr.HasMerged || oldCommitID == "" || newCommitID == "" {
return nil, nil
}
ops := &CreateCommentOptions{
Type: CommentTypePullRequestPush,
Doer: pusher,
Repo: pr.BaseRepo,
}
var data PushActionContent
data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch)
if err != nil {
return nil, err
}
ops.Issue = pr.Issue
dataJSON, err := json.Marshal(data)
if err != nil {
return nil, err
}
ops.Content = string(dataJSON)
comment, err = CreateComment(ops)
return comment, err
}
// CreateAutoMergeComment is a internal function, only use it for CommentTypePRScheduledToAutoMerge and CommentTypePRUnScheduledToAutoMerge CommentTypes
func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullRequest, doer *user_model.User) (comment *Comment, err error) {
if typ != CommentTypePRScheduledToAutoMerge && typ != CommentTypePRUnScheduledToAutoMerge {
@ -1361,7 +1281,7 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques
return
}
comment, err = CreateCommentCtx(ctx, &CreateCommentOptions{
comment, err = CreateComment(ctx, &CreateCommentOptions{
Type: typ,
Doer: doer,
Repo: pr.BaseRepo,
@ -1370,120 +1290,6 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques
return comment, err
}
// getCommitsFromRepo get commit IDs from repo in between oldCommitID and newCommitID
// isForcePush will be true if oldCommit isn't on the branch
// Commit on baseBranch will skip
func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) {
repoPath := repo.RepoPath()
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath)
if err != nil {
return nil, false, err
}
defer closer.Close()
oldCommit, err := gitRepo.GetCommit(oldCommitID)
if err != nil {
return nil, false, err
}
if err = oldCommit.LoadBranchName(); err != nil {
return nil, false, err
}
if len(oldCommit.Branch) == 0 {
commitIDs = make([]string, 2)
commitIDs[0] = oldCommitID
commitIDs[1] = newCommitID
return commitIDs, true, err
}
newCommit, err := gitRepo.GetCommit(newCommitID)
if err != nil {
return nil, false, err
}
commits, err := newCommit.CommitsBeforeUntil(oldCommitID)
if err != nil {
return nil, false, err
}
commitIDs = make([]string, 0, len(commits))
commitChecks := make(map[string]*commitBranchCheckItem)
for _, commit := range commits {
commitChecks[commit.ID.String()] = &commitBranchCheckItem{
Commit: commit,
Checked: false,
}
}
if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil {
return
}
for i := len(commits) - 1; i >= 0; i-- {
commitID := commits[i].ID.String()
if item, ok := commitChecks[commitID]; ok && item.Checked {
commitIDs = append(commitIDs, commitID)
}
}
return commitIDs, isForcePush, err
}
type commitBranchCheckItem struct {
Commit *git.Commit
Checked bool
}
func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]*commitBranchCheckItem) error {
if startCommit.ID.String() == endCommitID {
return nil
}
checkStack := make([]string, 0, 10)
checkStack = append(checkStack, startCommit.ID.String())
for len(checkStack) > 0 {
commitID := checkStack[0]
checkStack = checkStack[1:]
item, ok := commitList[commitID]
if !ok {
continue
}
if item.Commit.ID.String() == endCommitID {
continue
}
if err := item.Commit.LoadBranchName(); err != nil {
return err
}
if item.Commit.Branch == baseBranch {
continue
}
if item.Checked {
continue
}
item.Checked = true
parentNum := item.Commit.ParentCount()
for i := 0; i < parentNum; i++ {
parentCommit, err := item.Commit.Parent(i)
if err != nil {
return err
}
checkStack = append(checkStack, parentCommit.ID.String())
}
}
return nil
}
// RemapExternalUser ExternalUserRemappable interface
func (c *Comment) RemapExternalUser(externalName string, externalID, userID int64) error {
c.OriginalAuthor = externalName

View File

@ -24,7 +24,7 @@ func TestCreateComment(t *testing.T) {
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
now := time.Now().Unix()
comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{
comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypeComment,
Doer: doer,
Repo: repo,

View File

@ -202,16 +202,12 @@ func (issue *Issue) LoadRepo(ctx context.Context) (err error) {
}
// IsTimetrackerEnabled returns true if the repo enables timetracking
func (issue *Issue) IsTimetrackerEnabled() bool {
return issue.isTimetrackerEnabled(db.DefaultContext)
}
func (issue *Issue) isTimetrackerEnabled(ctx context.Context) bool {
func (issue *Issue) IsTimetrackerEnabled(ctx context.Context) bool {
if err := issue.LoadRepo(ctx); err != nil {
log.Error(fmt.Sprintf("loadRepo: %v", err))
return false
}
return issue.Repo.IsTimetrackerEnabledCtx(ctx)
return issue.Repo.IsTimetrackerEnabled(ctx)
}
// GetPullRequest returns the issue pull request
@ -404,7 +400,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
if err = CommentList(issue.Comments).loadAttributes(ctx); err != nil {
return err
}
if issue.isTimetrackerEnabled(ctx) {
if issue.IsTimetrackerEnabled(ctx) {
if err = issue.LoadTotalTimes(ctx); err != nil {
return err
}
@ -673,7 +669,7 @@ func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User,
func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) {
// Check for open dependencies
if issue.IsClosed && issue.Repo.IsDependenciesEnabledCtx(ctx) {
if issue.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) {
// only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies
noDeps, err := IssueNoDependenciesLeft(ctx, issue)
if err != nil {
@ -725,7 +721,7 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
cmtType = CommentTypeMergePull
}
return CreateCommentCtx(ctx, &CreateCommentOptions{
return CreateComment(ctx, &CreateCommentOptions{
Type: cmtType,
Doer: doer,
Repo: issue.Repo,
@ -769,7 +765,7 @@ func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err
OldTitle: oldTitle,
NewTitle: issue.Title,
}
if _, err = CreateCommentCtx(ctx, opts); err != nil {
if _, err = CreateComment(ctx, opts); err != nil {
return fmt.Errorf("createComment: %w", err)
}
if err = issue.AddCrossReferences(ctx, doer, true); err != nil {
@ -805,7 +801,7 @@ func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err err
OldRef: oldRefFriendly,
NewRef: newRefFriendly,
}
if _, err = CreateCommentCtx(ctx, opts); err != nil {
if _, err = CreateComment(ctx, opts); err != nil {
return fmt.Errorf("createComment: %w", err)
}
@ -825,7 +821,7 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *
Issue: issue,
OldRef: branchName,
}
_, err = CreateCommentCtx(ctx, opts)
_, err = CreateComment(ctx, opts)
return err
}
@ -992,7 +988,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue
OldMilestoneID: 0,
MilestoneID: opts.Issue.MilestoneID,
}
if _, err = CreateCommentCtx(ctx, opts); err != nil {
if _, err = CreateComment(ctx, opts); err != nil {
return err
}
}
@ -2000,7 +1996,7 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment
OldTitle: currentIssue.Title,
NewTitle: issue.Title,
}
_, err := CreateCommentCtx(ctx, opts)
_, err := CreateComment(ctx, opts)
if err != nil {
return nil, false, fmt.Errorf("createComment: %w", err)
}

View File

@ -461,7 +461,7 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) {
ids := make([]int64, 0, len(issues))
for _, issue := range issues {
if issue.Repo.IsTimetrackerEnabled() {
if issue.Repo.IsTimetrackerEnabled(ctx) {
ids = append(ids, issue.ID)
}
}

View File

@ -56,7 +56,7 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error {
Type: commentType,
Content: opts.Reason,
}
if _, err := CreateCommentCtx(ctx, opt); err != nil {
if _, err := CreateComment(ctx, opt); err != nil {
return err
}

View File

@ -145,7 +145,7 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U
}
if oldProjectID > 0 || newProjectID > 0 {
if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{
if _, err := CreateComment(ctx, &CreateCommentOptions{
Type: CommentTypeProject,
Doer: doer,
Repo: issue.Repo,

View File

@ -121,7 +121,7 @@ func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossRefe
RefAction: xref.Action,
RefIsPull: ctx.OrigIssue.IsPull,
}
_, err := CreateCommentCtx(stdCtx, opts)
_, err := CreateComment(stdCtx, opts)
if err != nil {
return err
}

View File

@ -613,7 +613,7 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m
Label: label,
Content: "1",
}
if _, err = CreateCommentCtx(ctx, opts); err != nil {
if _, err = CreateComment(ctx, opts); err != nil {
return err
}
@ -714,7 +714,7 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use
Issue: issue,
Label: label,
}
if _, err = CreateCommentCtx(ctx, opts); err != nil {
if _, err = CreateComment(ctx, opts); err != nil {
return err
}

View File

@ -294,7 +294,7 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio
}
if !pr.ProtectedBranch.EnableApprovalsWhitelist {
return team.UnitAccessModeCtx(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil
return team.UnitAccessMode(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil
}
return base.Int64sContains(pr.ProtectedBranch.ApprovalsWhitelistTeamIDs, team.ID), nil
@ -436,7 +436,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co
}
}
comm, err := CreateCommentCtx(ctx, &CreateCommentOptions{
comm, err := CreateComment(ctx, &CreateCommentOptions{
Type: CommentTypeReview,
Doer: doer,
Content: review.Content,
@ -692,7 +692,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment,
return nil, err
}
comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{
comment, err := CreateComment(ctx, &CreateCommentOptions{
Type: CommentTypeReviewRequest,
Doer: doer,
Repo: issue.Repo,
@ -746,7 +746,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen
}
}
comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{
comment, err := CreateComment(ctx, &CreateCommentOptions{
Type: CommentTypeReviewRequest,
Doer: doer,
Repo: issue.Repo,
@ -804,7 +804,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_
}
}
comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{
comment, err := CreateComment(ctx, &CreateCommentOptions{
Type: CommentTypeReviewRequest,
Doer: doer,
Repo: issue.Repo,
@ -814,7 +814,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_
ReviewID: review.ID,
})
if err != nil {
return nil, fmt.Errorf("CreateCommentCtx(): %w", err)
return nil, fmt.Errorf("CreateComment(): %w", err)
}
return comment, committer.Commit()
@ -864,7 +864,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us
return nil, committer.Commit()
}
comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{
comment, err := CreateComment(ctx, &CreateCommentOptions{
Type: CommentTypeReviewRequest,
Doer: doer,
Repo: issue.Repo,
@ -873,7 +873,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us
AssigneeTeamID: reviewer.ID, // Use AssigneeTeamID as reviewer team ID
})
if err != nil {
return nil, fmt.Errorf("CreateCommentCtx(): %w", err)
return nil, fmt.Errorf("CreateComment(): %w", err)
}
return comment, committer.Commit()

View File

@ -196,7 +196,7 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
return err
}
if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{
if _, err := CreateComment(ctx, &CreateCommentOptions{
Doer: user,
Issue: issue,
Repo: issue.Repo,
@ -246,7 +246,7 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
return err
}
if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{
if _, err := CreateComment(ctx, &CreateCommentOptions{
Doer: user,
Issue: issue,
Repo: issue.Repo,
@ -287,7 +287,7 @@ func cancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) e
return err
}
if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{
if _, err := CreateComment(ctx, &CreateCommentOptions{
Doer: user,
Issue: issue,
Repo: issue.Repo,

View File

@ -172,7 +172,7 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim
return nil, err
}
if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{
if _, err := CreateComment(ctx, &CreateCommentOptions{
Issue: issue,
Repo: issue.Repo,
Doer: user,
@ -250,7 +250,7 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error {
if err := issue.LoadRepo(ctx); err != nil {
return err
}
if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{
if _, err := CreateComment(ctx, &CreateCommentOptions{
Issue: issue,
Repo: issue.Repo,
Doer: user,
@ -279,7 +279,7 @@ func DeleteTime(t *TrackedTime) error {
return err
}
if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{
if _, err := CreateComment(ctx, &CreateCommentOptions{
Issue: t.Issue,
Repo: t.Issue.Repo,
Doer: t.User,

View File

@ -30,19 +30,19 @@ func DeleteOrphanedAttachments(x *xorm.Engine) error {
}
for {
attachements := make([]Attachment, 0, limit)
attachments := make([]Attachment, 0, limit)
if err := sess.Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").
Cols("id, uuid").Limit(limit).
Asc("id").
Find(&attachements); err != nil {
Find(&attachments); err != nil {
return err
}
if len(attachements) == 0 {
if len(attachments) == 0 {
return nil
}
ids := make([]int64, 0, limit)
for _, attachment := range attachements {
for _, attachment := range attachments {
ids = append(ids, attachment.ID)
}
if len(ids) > 0 {
@ -51,13 +51,13 @@ func DeleteOrphanedAttachments(x *xorm.Engine) error {
}
}
for _, attachment := range attachements {
for _, attachment := range attachments {
uuid := attachment.UUID
if err := util.RemoveAll(filepath.Join(setting.Attachment.Path, uuid[0:1], uuid[1:2], uuid)); err != nil {
return err
}
}
if len(attachements) < limit {
if len(attachments) < limit {
return nil
}
}

View File

@ -106,7 +106,7 @@ func (org *Organization) IsOrgMember(uid int64) (bool, error) {
// CanCreateOrgRepo returns true if given user can create repo in organization
func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) {
return CanCreateOrgRepo(org.ID, uid)
return CanCreateOrgRepo(db.DefaultContext, org.ID, uid)
}
func (org *Organization) getTeam(ctx context.Context, name string) (*Team, error) {

View File

@ -73,8 +73,8 @@ func IsPublicMembership(orgID, uid int64) (bool, error) {
}
// CanCreateOrgRepo returns true if user can create repo in organization
func CanCreateOrgRepo(orgID, uid int64) (bool, error) {
return db.GetEngine(db.DefaultContext).
func CanCreateOrgRepo(ctx context.Context, orgID, uid int64) (bool, error) {
return db.GetEngine(ctx).
Where(builder.Eq{"team.can_create_org_repo": true}).
Join("INNER", "team_user", "team_user.team_id = team.id").
And("team_user.uid = ?", uid).

View File

@ -242,18 +242,12 @@ func (t *Team) LoadMembers(ctx context.Context) (err error) {
}
// UnitEnabled returns if the team has the given unit type enabled
func (t *Team) UnitEnabled(tp unit.Type) bool {
return t.UnitAccessMode(tp) > perm.AccessModeNone
func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool {
return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone
}
// UnitAccessMode returns if the team has the given unit type enabled
// it is called in templates, should not be replaced by `UnitAccessModeCtx(ctx ...)`
func (t *Team) UnitAccessMode(tp unit.Type) perm.AccessMode { // Notice: It will be used in template, don't remove it directly
return t.UnitAccessModeCtx(db.DefaultContext, tp)
}
// UnitAccessModeCtx returns if the team has the given unit type enabled
func (t *Team) UnitAccessModeCtx(ctx context.Context, tp unit.Type) perm.AccessMode {
func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode {
if err := t.getUnits(ctx); err != nil {
log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
}

View File

@ -244,7 +244,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
for _, u := range repo.Units {
var found bool
for _, team := range teams {
teamMode := team.UnitAccessModeCtx(ctx, u.Type)
teamMode := team.UnitAccessMode(ctx, u.Type)
if teamMode > perm_model.AccessModeNone {
m := perm.UnitsMode[u.Type]
if m < teamMode {

View File

@ -298,44 +298,32 @@ func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error {
return updateRepositoryProjectCount(ctx, p.RepoID)
}
// DeleteProjectByID deletes a project from a repository.
func DeleteProjectByID(id int64) error {
ctx, committer, err := db.TxContext(db.DefaultContext)
if err != nil {
return err
}
defer committer.Close()
if err := DeleteProjectByIDCtx(ctx, id); err != nil {
return err
}
return committer.Commit()
}
// DeleteProjectByIDCtx deletes a project from a repository.
func DeleteProjectByIDCtx(ctx context.Context, id int64) error {
p, err := GetProjectByID(ctx, id)
if err != nil {
if IsErrProjectNotExist(err) {
return nil
// DeleteProjectByID deletes a project from a repository. if it's not in a database
// transaction, it will start a new database transaction
func DeleteProjectByID(ctx context.Context, id int64) error {
return db.AutoTx(ctx, func(ctx context.Context) error {
p, err := GetProjectByID(ctx, id)
if err != nil {
if IsErrProjectNotExist(err) {
return nil
}
return err
}
return err
}
if err := deleteProjectIssuesByProjectID(ctx, id); err != nil {
return err
}
if err := deleteProjectIssuesByProjectID(ctx, id); err != nil {
return err
}
if err := deleteBoardByProjectID(ctx, id); err != nil {
return err
}
if err := deleteBoardByProjectID(ctx, id); err != nil {
return err
}
if _, err = db.GetEngine(ctx).ID(p.ID).Delete(new(Project)); err != nil {
return err
}
if _, err = db.GetEngine(ctx).ID(p.ID).Delete(new(Project)); err != nil {
return err
}
return updateRepositoryProjectCount(ctx, p.RepoID)
return updateRepositoryProjectCount(ctx, p.RepoID)
})
}
func DeleteProjectByRepoID(ctx context.Context, repoID int64) error {

View File

@ -99,55 +99,42 @@ func getCollaborations(ctx context.Context, repoID int64, listOptions db.ListOpt
}
// ChangeCollaborationAccessMode sets new access mode for the collaboration.
func ChangeCollaborationAccessModeCtx(ctx context.Context, repo *Repository, uid int64, mode perm.AccessMode) error {
func ChangeCollaborationAccessMode(ctx context.Context, repo *Repository, uid int64, mode perm.AccessMode) error {
// Discard invalid input
if mode <= perm.AccessModeNone || mode > perm.AccessModeOwner {
return nil
}
e := db.GetEngine(ctx)
return db.AutoTx(ctx, func(ctx context.Context) error {
e := db.GetEngine(ctx)
collaboration := &Collaboration{
RepoID: repo.ID,
UserID: uid,
}
has, err := e.Get(collaboration)
if err != nil {
return fmt.Errorf("get collaboration: %w", err)
} else if !has {
return nil
}
if collaboration.Mode == mode {
return nil
}
collaboration.Mode = mode
if _, err = e.
ID(collaboration.ID).
Cols("mode").
Update(collaboration); err != nil {
return fmt.Errorf("update collaboration: %w", err)
} else if _, err = e.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil {
return fmt.Errorf("update access table: %w", err)
}
collaboration := &Collaboration{
RepoID: repo.ID,
UserID: uid,
}
has, err := e.Get(collaboration)
if err != nil {
return fmt.Errorf("get collaboration: %w", err)
} else if !has {
return nil
}
if collaboration.Mode == mode {
return nil
}
collaboration.Mode = mode
if _, err = e.
ID(collaboration.ID).
Cols("mode").
Update(collaboration); err != nil {
return fmt.Errorf("update collaboration: %w", err)
} else if _, err = e.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil {
return fmt.Errorf("update access table: %w", err)
}
return nil
}
// ChangeCollaborationAccessMode sets new access mode for the collaboration.
func ChangeCollaborationAccessMode(repo *Repository, uid int64, mode perm.AccessMode) error {
ctx, committer, err := db.TxContext(db.DefaultContext)
if err != nil {
return err
}
defer committer.Close()
if err := ChangeCollaborationAccessModeCtx(ctx, repo, uid, mode); err != nil {
return err
}
return committer.Commit()
})
}
// IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository

View File

@ -54,7 +54,7 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin))
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin))
collaboration := unittest.AssertExistsAndLoadBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4})
assert.EqualValues(t, perm.AccessModeAdmin, collaboration.Mode)
@ -62,9 +62,9 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) {
access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: repo.ID})
assert.EqualValues(t, perm.AccessModeAdmin, access.Mode)
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin))
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin))
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, unittest.NonexistentID, perm.AccessModeAdmin))
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, unittest.NonexistentID, perm.AccessModeAdmin))
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID})
}

View File

@ -6,7 +6,6 @@ package repo
import (
"context"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -26,44 +25,34 @@ func (repo *Repository) CanEnableTimetracker() bool {
}
// IsTimetrackerEnabled returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs.
func (repo *Repository) IsTimetrackerEnabled() bool { // Notice: It will be used in template so don't remove directly
return repo.IsTimetrackerEnabledCtx(db.DefaultContext)
}
// IsTimetrackerEnabledCtx returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs.
func (repo *Repository) IsTimetrackerEnabledCtx(ctx context.Context) bool {
func (repo *Repository) IsTimetrackerEnabled(ctx context.Context) bool {
if !setting.Service.EnableTimetracking {
return false
}
var u *RepoUnit
var err error
if u, err = repo.GetUnitCtx(ctx, unit.TypeIssues); err != nil {
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
return setting.Service.DefaultEnableTimetracking
}
return u.IssuesConfig().EnableTimetracker
}
// AllowOnlyContributorsToTrackTime returns value of IssuesConfig or the default value
func (repo *Repository) AllowOnlyContributorsToTrackTime() bool {
func (repo *Repository) AllowOnlyContributorsToTrackTime(ctx context.Context) bool {
var u *RepoUnit
var err error
if u, err = repo.GetUnit(unit.TypeIssues); err != nil {
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
return setting.Service.DefaultAllowOnlyContributorsToTrackTime
}
return u.IssuesConfig().AllowOnlyContributorsToTrackTime
}
// IsDependenciesEnabled returns if dependencies are enabled and returns the default setting if not set.
func (repo *Repository) IsDependenciesEnabled() bool {
return repo.IsDependenciesEnabledCtx(db.DefaultContext)
}
// IsDependenciesEnabledCtx returns if dependencies are enabled and returns the default setting if not set.
func (repo *Repository) IsDependenciesEnabledCtx(ctx context.Context) bool {
func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool {
var u *RepoUnit
var err error
if u, err = repo.GetUnitCtx(ctx, unit.TypeIssues); err != nil {
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
log.Trace("%s", err)
return setting.Service.DefaultEnableDependencies
}

View File

@ -286,8 +286,8 @@ func GetReleasesByRepoIDAndNames(ctx context.Context, repoID int64, tagNames []s
}
// GetReleaseCountByRepoID returns the count of releases of repository
func GetReleaseCountByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) {
return db.GetEngine(db.DefaultContext).Where(opts.toConds(repoID)).Count(&Release{})
func GetReleaseCountByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) {
return db.GetEngine(ctx).Where(opts.toConds(repoID)).Count(&Release{})
}
type releaseMetaSearch struct {

View File

@ -316,12 +316,7 @@ func (repo *Repository) LoadUnits(ctx context.Context) (err error) {
}
// UnitEnabled if this repository has the given unit enabled
func (repo *Repository) UnitEnabled(tp unit.Type) (result bool) { // Notice: Don't remove this function directly, because it has been used in go template.
return repo.UnitEnabledCtx(db.DefaultContext, tp)
}
// UnitEnabled if this repository has the given unit enabled
func (repo *Repository) UnitEnabledCtx(ctx context.Context, tp unit.Type) bool {
func (repo *Repository) UnitEnabled(ctx context.Context, tp unit.Type) bool {
if err := repo.LoadUnits(ctx); err != nil {
log.Warn("Error loading repository (ID: %d) units: %s", repo.ID, err.Error())
}
@ -334,8 +329,8 @@ func (repo *Repository) UnitEnabledCtx(ctx context.Context, tp unit.Type) bool {
}
// MustGetUnit always returns a RepoUnit object
func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit {
ru, err := repo.GetUnit(tp)
func (repo *Repository) MustGetUnit(ctx context.Context, tp unit.Type) *RepoUnit {
ru, err := repo.GetUnit(ctx, tp)
if err == nil {
return ru
}
@ -368,12 +363,7 @@ func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit {
}
// GetUnit returns a RepoUnit object
func (repo *Repository) GetUnit(tp unit.Type) (*RepoUnit, error) {
return repo.GetUnitCtx(db.DefaultContext, tp)
}
// GetUnitCtx returns a RepoUnit object
func (repo *Repository) GetUnitCtx(ctx context.Context, tp unit.Type) (*RepoUnit, error) {
func (repo *Repository) GetUnit(ctx context.Context, tp unit.Type) (*RepoUnit, error) {
if err := repo.LoadUnits(ctx); err != nil {
return nil, err
}
@ -420,7 +410,7 @@ func (repo *Repository) ComposeMetas() map[string]string {
"mode": "comment",
}
unit, err := repo.GetUnit(unit.TypeExternalTracker)
unit, err := repo.GetUnit(db.DefaultContext, unit.TypeExternalTracker)
if err == nil {
metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat
switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
@ -558,7 +548,7 @@ func (repo *Repository) CanEnablePulls() bool {
// AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
func (repo *Repository) AllowsPulls() bool {
return repo.CanEnablePulls() && repo.UnitEnabled(unit.TypePullRequests)
return repo.CanEnablePulls() && repo.UnitEnabled(db.DefaultContext, unit.TypePullRequests)
}
// CanEnableEditor returns true if repository meets the requirements of web editor.

View File

@ -235,12 +235,12 @@ func TestSearchRepository(t *testing.T) {
{
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
count: 28,
count: 29,
},
{
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
count: 33,
count: 34,
},
{
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
@ -255,7 +255,7 @@ func TestSearchRepository(t *testing.T) {
{
name: "AllPublic/PublicRepositoriesOfOrganization",
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
count: 28,
count: 29,
},
{
name: "AllTemplates",

View File

@ -39,9 +39,9 @@ func init() {
}
// LoadAttributes fetches the transfer recipient from the database
func (r *RepoTransfer) LoadAttributes() error {
func (r *RepoTransfer) LoadAttributes(ctx context.Context) error {
if r.Recipient == nil {
u, err := user_model.GetUserByID(db.DefaultContext, r.RecipientID)
u, err := user_model.GetUserByID(ctx, r.RecipientID)
if err != nil {
return err
}
@ -51,7 +51,7 @@ func (r *RepoTransfer) LoadAttributes() error {
if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) {
for _, v := range r.TeamIDs {
team, err := organization.GetTeamByID(db.DefaultContext, v)
team, err := organization.GetTeamByID(ctx, v)
if err != nil {
return err
}
@ -65,7 +65,7 @@ func (r *RepoTransfer) LoadAttributes() error {
}
if r.Doer == nil {
u, err := user_model.GetUserByID(db.DefaultContext, r.DoerID)
u, err := user_model.GetUserByID(ctx, r.DoerID)
if err != nil {
return err
}
@ -80,7 +80,7 @@ func (r *RepoTransfer) LoadAttributes() error {
// For user, it checks if it's himself
// For organizations, it checks if the user is able to create repos
func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool {
if err := r.LoadAttributes(); err != nil {
if err := r.LoadAttributes(db.DefaultContext); err != nil {
log.Error("LoadAttributes: %v", err)
return false
}
@ -89,7 +89,7 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool {
return r.RecipientID == u.ID
}
allowed, err := organization.CanCreateOrgRepo(r.RecipientID, u.ID)
allowed, err := organization.CanCreateOrgRepo(db.DefaultContext, r.RecipientID, u.ID)
if err != nil {
log.Error("CanCreateOrgRepo: %v", err)
return false
@ -100,10 +100,10 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool {
// GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
// process for the repository
func GetPendingRepositoryTransfer(repo *repo_model.Repository) (*RepoTransfer, error) {
func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) (*RepoTransfer, error) {
transfer := new(RepoTransfer)
has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repo.ID).Get(transfer)
has, err := db.GetEngine(ctx).Where("repo_id = ? ", repo.ID).Get(transfer)
if err != nil {
return nil, err
}
@ -154,56 +154,48 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
// CreatePendingRepositoryTransfer transfer a repo from one owner to a new one.
// it marks the repository transfer as "pending"
func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
ctx, committer, err := db.TxContext(db.DefaultContext)
if err != nil {
return err
}
defer committer.Close()
repo, err := repo_model.GetRepositoryByID(ctx, repoID)
if err != nil {
return err
}
// Make sure repo is ready to transfer
if err := TestRepositoryReadyForTransfer(repo.Status); err != nil {
return err
}
repo.Status = repo_model.RepositoryPendingTransfer
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
return err
}
// Check if new owner has repository with same name.
if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return repo_model.ErrRepoAlreadyExist{
Uname: newOwner.LowerName,
Name: repo.Name,
func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
return db.AutoTx(ctx, func(ctx context.Context) error {
repo, err := repo_model.GetRepositoryByID(ctx, repoID)
if err != nil {
return err
}
}
transfer := &RepoTransfer{
RepoID: repo.ID,
RecipientID: newOwner.ID,
CreatedUnix: timeutil.TimeStampNow(),
UpdatedUnix: timeutil.TimeStampNow(),
DoerID: doer.ID,
TeamIDs: make([]int64, 0, len(teams)),
}
// Make sure repo is ready to transfer
if err := TestRepositoryReadyForTransfer(repo.Status); err != nil {
return err
}
for k := range teams {
transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID)
}
repo.Status = repo_model.RepositoryPendingTransfer
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
return err
}
if err := db.Insert(ctx, transfer); err != nil {
return err
}
// Check if new owner has repository with same name.
if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return repo_model.ErrRepoAlreadyExist{
Uname: newOwner.LowerName,
Name: repo.Name,
}
}
return committer.Commit()
transfer := &RepoTransfer{
RepoID: repo.ID,
RecipientID: newOwner.ID,
CreatedUnix: timeutil.TimeStampNow(),
UpdatedUnix: timeutil.TimeStampNow(),
DoerID: doer.ID,
TeamIDs: make([]int64, 0, len(teams)),
}
for k := range teams {
transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID)
}
return db.Insert(ctx, transfer)
})
}
// TransferOwnership transfers all corresponding repository items from old user to new one.

View File

@ -6,6 +6,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"
user_model "code.gitea.io/gitea/models/user"
@ -19,36 +20,36 @@ func TestRepositoryTransfer(t *testing.T) {
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
transfer, err := GetPendingRepositoryTransfer(repo)
transfer, err := GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.NoError(t, err)
assert.NotNil(t, transfer)
// Cancel transfer
assert.NoError(t, CancelRepositoryTransfer(repo))
transfer, err = GetPendingRepositoryTransfer(repo)
transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.Error(t, err)
assert.Nil(t, transfer)
assert.True(t, IsErrNoPendingTransfer(err))
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
assert.NoError(t, CreatePendingRepositoryTransfer(doer, user2, repo.ID, nil))
assert.NoError(t, CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil))
transfer, err = GetPendingRepositoryTransfer(repo)
transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.Nil(t, err)
assert.NoError(t, transfer.LoadAttributes())
assert.NoError(t, transfer.LoadAttributes(db.DefaultContext))
assert.Equal(t, "user2", transfer.Recipient.Name)
user6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// Only transfer can be started at any given time
err = CreatePendingRepositoryTransfer(doer, user6, repo.ID, nil)
err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, user6, repo.ID, nil)
assert.Error(t, err)
assert.True(t, IsErrRepoTransferInProgress(err))
// Unknown user
err = CreatePendingRepositoryTransfer(doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
assert.Error(t, err)
// Cancel transfer

View File

@ -110,7 +110,7 @@ func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
return accessMode, err
}
for _, t := range teams {
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
perm := t.UnitAccessMode(ctx, unit.TypePackages)
if accessMode < perm {
accessMode = perm
}

View File

@ -163,13 +163,13 @@ func (r *Repository) CanUseTimetracker(issue *issues_model.Issue, user *user_mod
// 1. Is timetracker enabled
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
isAssigned, _ := issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, user)
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
return r.Repository.IsTimetrackerEnabled(db.DefaultContext) && (!r.Repository.AllowOnlyContributorsToTrackTime(db.DefaultContext) ||
r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
}
// CanCreateIssueDependencies returns whether or not a user can create dependencies.
func (r *Repository) CanCreateIssueDependencies(user *user_model.User, isPull bool) bool {
return r.Repository.IsDependenciesEnabled() && r.Permission.CanWriteIssuesOrPulls(isPull)
return r.Repository.IsDependenciesEnabled(db.DefaultContext) && r.Permission.CanWriteIssuesOrPulls(isPull)
}
// GetCommitsCount returns cached commit count for current view
@ -528,12 +528,12 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
unit, err := ctx.Repo.Repository.GetUnit(unit_model.TypeExternalTracker)
unit, err := ctx.Repo.Repository.GetUnit(ctx, unit_model.TypeExternalTracker)
if err == nil {
ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL
}
ctx.Data["NumTags"], err = repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{
ctx.Data["NumTags"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{
IncludeDrafts: true,
IncludeTags: true,
HasSha1: util.OptionalBoolTrue, // only draft releases which are created with existing tags
@ -542,7 +542,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.ServerError("GetReleaseCountByRepoID", err)
return
}
ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{})
ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{})
if err != nil {
ctx.ServerError("GetReleaseCountByRepoID", err)
return
@ -723,13 +723,13 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository)
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil {
ctx.ServerError("GetPendingRepositoryTransfer", err)
return
}
if err := repoTransfer.LoadAttributes(); err != nil {
if err := repoTransfer.LoadAttributes(ctx); err != nil {
ctx.ServerError("LoadRecipient", err)
return
}

View File

@ -0,0 +1,30 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package convert
import (
repo_model "code.gitea.io/gitea/models/repo"
api "code.gitea.io/gitea/modules/structs"
)
// ToAttachment converts models.Attachment to api.Attachment
func ToAttachment(a *repo_model.Attachment) *api.Attachment {
return &api.Attachment{
ID: a.ID,
Name: a.Name,
Created: a.CreatedUnix.AsTime(),
DownloadCount: a.DownloadCount,
Size: a.Size,
UUID: a.UUID,
DownloadURL: a.DownloadURL(),
}
}
func ToAttachments(attachments []*repo_model.Attachment) []*api.Attachment {
converted := make([]*api.Attachment, 0, len(attachments))
for _, attachment := range attachments {
converted = append(converted, ToAttachment(attachment))
}
return converted
}

View File

@ -37,20 +37,21 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
}
apiIssue := &api.Issue{
ID: issue.ID,
URL: issue.APIURL(),
HTMLURL: issue.HTMLURL(),
Index: issue.Index,
Poster: ToUser(issue.Poster, nil),
Title: issue.Title,
Body: issue.Content,
Ref: issue.Ref,
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
State: issue.State(),
IsLocked: issue.IsLocked,
Comments: issue.NumComments,
Created: issue.CreatedUnix.AsTime(),
Updated: issue.UpdatedUnix.AsTime(),
ID: issue.ID,
URL: issue.APIURL(),
HTMLURL: issue.HTMLURL(),
Index: issue.Index,
Poster: ToUser(issue.Poster, nil),
Title: issue.Title,
Body: issue.Content,
Attachments: ToAttachments(issue.Attachments),
Ref: issue.Ref,
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
State: issue.State(),
IsLocked: issue.IsLocked,
Comments: issue.NumComments,
Created: issue.CreatedUnix.AsTime(),
Updated: issue.UpdatedUnix.AsTime(),
}
apiIssue.Repo = &api.RepositoryMeta{

View File

@ -16,14 +16,15 @@ import (
// ToComment converts a issues_model.Comment to the api.Comment format
func ToComment(c *issues_model.Comment) *api.Comment {
return &api.Comment{
ID: c.ID,
Poster: ToUser(c.Poster, nil),
HTMLURL: c.HTMLURL(),
IssueURL: c.IssueURL(),
PRURL: c.PRURL(),
Body: c.Content,
Created: c.CreatedUnix.AsTime(),
Updated: c.UpdatedUnix.AsTime(),
ID: c.ID,
Poster: ToUser(c.Poster, nil),
HTMLURL: c.HTMLURL(),
IssueURL: c.IssueURL(),
PRURL: c.PRURL(),
Body: c.Content,
Attachments: ToAttachments(c.Attachments),
Created: c.CreatedUnix.AsTime(),
Updated: c.UpdatedUnix.AsTime(),
}
}
@ -148,7 +149,7 @@ func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_
var err error
repo, err = repo_model.GetRepositoryByID(ctx, c.Label.RepoID)
if err != nil {
log.Error("GetRepositoryByIDCtx(%d): %v", c.Label.RepoID, err)
log.Error("GetRepositoryByID(%d): %v", c.Label.RepoID, err)
return nil
}
}

View File

@ -10,10 +10,6 @@ import (
// ToRelease convert a repo_model.Release to api.Release
func ToRelease(r *repo_model.Release) *api.Release {
assets := make([]*api.Attachment, 0)
for _, att := range r.Attachments {
assets = append(assets, ToReleaseAttachment(att))
}
return &api.Release{
ID: r.ID,
TagName: r.TagName,
@ -29,19 +25,6 @@ func ToRelease(r *repo_model.Release) *api.Release {
CreatedAt: r.CreatedUnix.AsTime(),
PublishedAt: r.CreatedUnix.AsTime(),
Publisher: ToUser(r.Publisher, nil),
Attachments: assets,
}
}
// ToReleaseAttachment converts models.Attachment to api.Attachment
func ToReleaseAttachment(a *repo_model.Attachment) *api.Attachment {
return &api.Attachment{
ID: a.ID,
Name: a.Name,
Created: a.CreatedUnix.AsTime(),
DownloadCount: a.DownloadCount,
Size: a.Size,
UUID: a.UUID,
DownloadURL: a.DownloadURL(),
Attachments: ToAttachments(r.Attachments),
}
}

View File

@ -8,7 +8,6 @@ import (
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
@ -44,7 +43,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc
hasIssues := false
var externalTracker *api.ExternalTracker
var internalTracker *api.InternalTracker
if unit, err := repo.GetUnit(unit_model.TypeIssues); err == nil {
if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err == nil {
config := unit.IssuesConfig()
hasIssues = true
internalTracker = &api.InternalTracker{
@ -52,7 +51,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc
AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
EnableIssueDependencies: config.EnableDependencies,
}
} else if unit, err := repo.GetUnit(unit_model.TypeExternalTracker); err == nil {
} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalTracker); err == nil {
config := unit.ExternalTrackerConfig()
hasIssues = true
externalTracker = &api.ExternalTracker{
@ -64,9 +63,9 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc
}
hasWiki := false
var externalWiki *api.ExternalWiki
if _, err := repo.GetUnit(unit_model.TypeWiki); err == nil {
if _, err := repo.GetUnit(ctx, unit_model.TypeWiki); err == nil {
hasWiki = true
} else if unit, err := repo.GetUnit(unit_model.TypeExternalWiki); err == nil {
} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalWiki); err == nil {
hasWiki = true
config := unit.ExternalWikiConfig()
externalWiki = &api.ExternalWiki{
@ -82,7 +81,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc
allowRebaseUpdate := false
defaultDeleteBranchAfterMerge := false
defaultMergeStyle := repo_model.MergeStyleMerge
if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil {
if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
hasPullRequests = true
ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts
@ -95,21 +94,21 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc
defaultMergeStyle = config.GetDefaultMergeStyle()
}
hasProjects := false
if _, err := repo.GetUnit(unit_model.TypeProjects); err == nil {
if _, err := repo.GetUnit(ctx, unit_model.TypeProjects); err == nil {
hasProjects = true
}
if err := repo.GetOwner(db.DefaultContext); err != nil {
if err := repo.GetOwner(ctx); err != nil {
return nil
}
numReleases, _ := repo_model.GetReleaseCountByRepoID(repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false})
numReleases, _ := repo_model.GetReleaseCountByRepoID(ctx, repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false})
mirrorInterval := ""
var mirrorUpdated time.Time
if repo.IsMirror {
var err error
repo.Mirror, err = repo_model.GetMirrorByRepoID(db.DefaultContext, repo.ID)
repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID)
if err == nil {
mirrorInterval = repo.Mirror.Interval.String()
mirrorUpdated = repo.Mirror.UpdatedUnix.AsTime()
@ -118,11 +117,11 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc
var transfer *api.RepoTransfer
if repo.Status == repo_model.RepositoryPendingTransfer {
t, err := models.GetPendingRepositoryTransfer(repo)
t, err := models.GetPendingRepositoryTransfer(ctx, repo)
if err != nil && !models.IsErrNoPendingTransfer(err) {
log.Warn("GetPendingRepositoryTransfer: %v", err)
} else {
if err := t.LoadAttributes(); err != nil {
if err := t.LoadAttributes(ctx); err != nil {
log.Warn("LoadAttributes of RepoTransfer: %v", err)
} else {
transfer = ToRepoTransfer(t)

View File

@ -305,18 +305,15 @@ func postProcess(ctx *RenderContext, procs []processor, input io.Reader, output
return err
}
res := bytes.NewBuffer(make([]byte, 0, len(rawHTML)+50))
// prepend "<html><body>"
_, _ = res.WriteString("<html><body>")
// Strip out nuls - they're always invalid
_, _ = res.Write(tagCleaner.ReplaceAll([]byte(nulCleaner.Replace(string(rawHTML))), []byte("&lt;$1")))
// close the tags
_, _ = res.WriteString("</body></html>")
// parse the HTML
node, err := html.Parse(res)
node, err := html.Parse(io.MultiReader(
// prepend "<html><body>"
strings.NewReader("<html><body>"),
// Strip out nuls - they're always invalid
bytes.NewReader(tagCleaner.ReplaceAll([]byte(nulCleaner.Replace(string(rawHTML))), []byte("&lt;$1"))),
// close the tags
strings.NewReader("</body></html>"),
))
if err != nil {
return &postProcessError{"invalid HTML", err}
}

View File

@ -314,6 +314,11 @@ func (m *webhookNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues
}
func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
if err := issue.LoadRepo(ctx); err != nil {
log.Error("LoadRepo: %v", err)
return
}
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
var err error
if issue.IsPull {

View File

@ -13,30 +13,25 @@ import (
user_model "code.gitea.io/gitea/models/user"
)
func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error {
collaboration := &repo_model.Collaboration{
RepoID: repo.ID,
UserID: u.ID,
}
func AddCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error {
return db.AutoTx(ctx, func(ctx context.Context) error {
collaboration := &repo_model.Collaboration{
RepoID: repo.ID,
UserID: u.ID,
}
has, err := db.GetByBean(ctx, collaboration)
if err != nil {
return err
} else if has {
return nil
}
collaboration.Mode = perm.AccessModeWrite
has, err := db.GetByBean(ctx, collaboration)
if err != nil {
return err
} else if has {
return nil
}
collaboration.Mode = perm.AccessModeWrite
if err = db.Insert(ctx, collaboration); err != nil {
return err
}
if err = db.Insert(ctx, collaboration); err != nil {
return err
}
return access_model.RecalculateUserAccess(ctx, repo, u.ID)
}
// AddCollaborator adds new collaboration to a repository with default access mode.
func AddCollaborator(repo *repo_model.Repository, u *user_model.User) error {
return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
return addCollaborator(ctx, repo, u)
return access_model.RecalculateUserAccess(ctx, repo, u.ID)
})
}

View File

@ -25,7 +25,7 @@ func TestRepository_AddCollaborator(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
assert.NoError(t, repo.GetOwner(db.DefaultContext))
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
assert.NoError(t, AddCollaborator(repo, user))
assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID})
}
testSuccess(1, 4)
@ -50,7 +50,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) {
}
// change to collaborator
assert.NoError(t, AddCollaborator(repo, user))
assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@ -103,7 +103,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) {
}
// change to collaborator to default write access
assert.NoError(t, AddCollaborator(repo, user))
assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@ -111,7 +111,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) {
assert.True(t, perm.CanWrite(unit.Type))
}
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead))
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead))
perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@ -155,7 +155,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) {
}
// change to collaborator to default write access
assert.NoError(t, AddCollaborator(repo, user))
assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@ -163,7 +163,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) {
assert.True(t, perm.CanWrite(unit.Type))
}
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead))
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead))
perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@ -217,7 +217,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
}
// change to collaborator to default write access
assert.NoError(t, AddCollaborator(repo, user))
assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@ -225,7 +225,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
assert.True(t, perm.CanWrite(unit.Type))
}
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead))
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead))
perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {

View File

@ -125,10 +125,10 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re
return fmt.Errorf("IsUserRepoAdmin: %w", err)
} else if !isAdmin {
// Make creator repo admin if it wasn't assigned automatically
if err = addCollaborator(ctx, repo, doer); err != nil {
return fmt.Errorf("addCollaborator: %w", err)
if err = AddCollaborator(ctx, repo, doer); err != nil {
return fmt.Errorf("AddCollaborator: %w", err)
}
if err = repo_model.ChangeCollaborationAccessModeCtx(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil {
if err = repo_model.ChangeCollaborationAccessMode(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil {
return fmt.Errorf("ChangeCollaborationAccessModeCtx: %w", err)
}
}

View File

@ -41,18 +41,19 @@ type RepositoryMeta struct {
// Issue represents an issue in a repository
// swagger:model
type Issue struct {
ID int64 `json:"id"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
Index int64 `json:"number"`
Poster *User `json:"user"`
OriginalAuthor string `json:"original_author"`
OriginalAuthorID int64 `json:"original_author_id"`
Title string `json:"title"`
Body string `json:"body"`
Ref string `json:"ref"`
Labels []*Label `json:"labels"`
Milestone *Milestone `json:"milestone"`
ID int64 `json:"id"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
Index int64 `json:"number"`
Poster *User `json:"user"`
OriginalAuthor string `json:"original_author"`
OriginalAuthorID int64 `json:"original_author_id"`
Title string `json:"title"`
Body string `json:"body"`
Ref string `json:"ref"`
Attachments []*Attachment `json:"assets"`
Labels []*Label `json:"labels"`
Milestone *Milestone `json:"milestone"`
// deprecated
Assignee *User `json:"assignee"`
Assignees []*User `json:"assignees"`

View File

@ -9,14 +9,15 @@ import (
// Comment represents a comment on a commit or issue
type Comment struct {
ID int64 `json:"id"`
HTMLURL string `json:"html_url"`
PRURL string `json:"pull_request_url"`
IssueURL string `json:"issue_url"`
Poster *User `json:"user"`
OriginalAuthor string `json:"original_author"`
OriginalAuthorID int64 `json:"original_author_id"`
Body string `json:"body"`
ID int64 `json:"id"`
HTMLURL string `json:"html_url"`
PRURL string `json:"pull_request_url"`
IssueURL string `json:"issue_url"`
Poster *User `json:"user"`
OriginalAuthor string `json:"original_author"`
OriginalAuthorID int64 `json:"original_author_id"`
Body string `json:"body"`
Attachments []*Attachment `json:"assets"`
// swagger:strfmt date-time
Created time.Time `json:"created_at"`
// swagger:strfmt date-time

View File

@ -7,7 +7,6 @@ import (
goctx "context"
"fmt"
"net/http"
"reflect"
"strings"
"code.gitea.io/gitea/modules/context"
@ -18,16 +17,9 @@ import (
)
// Bind binding an obj to a handler
func Bind(obj interface{}) http.HandlerFunc {
tp := reflect.TypeOf(obj)
if tp.Kind() == reflect.Ptr {
tp = tp.Elem()
}
if tp.Kind() != reflect.Struct {
panic("Only structs are allowed to bind")
}
func Bind[T any](obj T) http.HandlerFunc {
return Wrap(func(ctx *context.Context) {
theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly
theObj := new(T) // create a new form obj for every request but not use obj directly
binding.Bind(ctx.Req, theObj)
SetForm(ctx, theObj)
middleware.AssignForm(theObj, ctx.Data)

10
options/license/Symlinks Normal file
View File

@ -0,0 +1,10 @@
My "symlinks" utility pre-dates the "open source licensing"
fad by a number of years. Just to clarify, this is 100%
freeware, written entirely by myself. The intent is to use
it to detect missing/obsolete symlink targets on an installed
distro, before creating the "gold" (or "final") release discs.
Use and distribute and modify as you (or anyone
else) sees fit. There have no formal restrictions or
requirements whatsoever regarding distribution of either
binaries or source code, whether modified or original.

View File

@ -67,7 +67,6 @@ import (
gocontext "context"
"fmt"
"net/http"
"reflect"
"strings"
"code.gitea.io/gitea/models/organization"
@ -567,14 +566,17 @@ func mustNotBeArchived(ctx *context.APIContext) {
}
}
// bind binding an obj to a func(ctx *context.APIContext)
func bind(obj interface{}) http.HandlerFunc {
tp := reflect.TypeOf(obj)
for tp.Kind() == reflect.Ptr {
tp = tp.Elem()
func mustEnableAttachments(ctx *context.APIContext) {
if !setting.Attachment.Enabled {
ctx.NotFound()
return
}
}
// bind binding an obj to a func(ctx *context.APIContext)
func bind[T any](obj T) http.HandlerFunc {
return web.Wrap(func(ctx *context.APIContext) {
theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly
theObj := new(T) // create a new form obj for every request but not use obj directly
errs := binding.Bind(ctx.Req, theObj)
if len(errs) > 0 {
ctx.Error(http.StatusUnprocessableEntity, "validationError", fmt.Sprintf("%s: %s", errs[0].FieldNames, errs[0].Error()))
@ -892,6 +894,15 @@ func Routes(ctx gocontext.Context) *web.Route {
Get(repo.GetIssueCommentReactions).
Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueCommentReaction).
Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueCommentReaction)
m.Group("/assets", func() {
m.Combo("").
Get(repo.ListIssueCommentAttachments).
Post(reqToken(), mustNotBeArchived, repo.CreateIssueCommentAttachment)
m.Combo("/{asset}").
Get(repo.GetIssueCommentAttachment).
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment).
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueCommentAttachment)
}, mustEnableAttachments)
})
})
m.Group("/{index}", func() {
@ -935,6 +946,15 @@ func Routes(ctx gocontext.Context) *web.Route {
Get(repo.GetIssueReactions).
Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueReaction).
Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueReaction)
m.Group("/assets", func() {
m.Combo("").
Get(repo.ListIssueAttachments).
Post(reqToken(), mustNotBeArchived, repo.CreateIssueAttachment)
m.Combo("/{asset}").
Get(repo.GetIssueAttachment).
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueAttachment)
}, mustEnableAttachments)
})
}, mustEnableIssuesOrPulls)
m.Group("/labels", func() {

View File

@ -174,13 +174,13 @@ func AddCollaborator(ctx *context.APIContext) {
return
}
if err := repo_module.AddCollaborator(ctx.Repo.Repository, collaborator); err != nil {
if err := repo_module.AddCollaborator(ctx, ctx.Repo.Repository, collaborator); err != nil {
ctx.Error(http.StatusInternalServerError, "AddCollaborator", err)
return
}
if form.Permission != nil {
if err := repo_model.ChangeCollaborationAccessMode(ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil {
if err := repo_model.ChangeCollaborationAccessMode(ctx, ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil {
ctx.Error(http.StatusInternalServerError, "ChangeCollaborationAccessMode", err)
return
}

View File

@ -0,0 +1,372 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"net/http"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/attachment"
issue_service "code.gitea.io/gitea/services/issue"
)
// GetIssueAttachment gets a single attachment of the issue
func GetIssueAttachment(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueGetIssueAttachment
// ---
// summary: Get an issue attachment
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to get
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/Attachment"
// "404":
// "$ref": "#/responses/error"
issue := getIssueFromContext(ctx)
if issue == nil {
return
}
attach := getIssueAttachmentSafeRead(ctx, issue)
if attach == nil {
return
}
ctx.JSON(http.StatusOK, convert.ToAttachment(attach))
}
// ListIssueAttachments lists all attachments of the issue
func ListIssueAttachments(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/assets issue issueListIssueAttachments
// ---
// summary: List issue's attachments
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/AttachmentList"
// "404":
// "$ref": "#/responses/error"
issue := getIssueFromContext(ctx)
if issue == nil {
return
}
if err := issue.LoadAttributes(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue).Attachments)
}
// CreateIssueAttachment creates an attachment and saves the given file
func CreateIssueAttachment(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/assets issue issueCreateIssueAttachment
// ---
// summary: Create an issue attachment
// produces:
// - application/json
// consumes:
// - multipart/form-data
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
// - name: name
// in: query
// description: name of the attachment
// type: string
// required: false
// - name: attachment
// in: formData
// description: attachment to upload
// type: file
// required: true
// responses:
// "201":
// "$ref": "#/responses/Attachment"
// "400":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/error"
issue := getIssueFromContext(ctx)
if issue == nil {
return
}
if !canUserWriteIssueAttachment(ctx, issue) {
return
}
// Get uploaded file from request
file, header, err := ctx.Req.FormFile("attachment")
if err != nil {
ctx.Error(http.StatusInternalServerError, "FormFile", err)
return
}
defer file.Close()
filename := header.Filename
if query := ctx.FormString("name"); query != "" {
filename = query
}
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
IssueID: issue.ID,
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
return
}
issue.Attachments = append(issue.Attachments, attachment)
if err := issue_service.ChangeContent(issue, ctx.Doer, issue.Content); err != nil {
ctx.Error(http.StatusInternalServerError, "ChangeContent", err)
return
}
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
}
// EditIssueAttachment updates the given attachment
func EditIssueAttachment(ctx *context.APIContext) {
// swagger:operation PATCH /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueEditIssueAttachment
// ---
// summary: Edit an issue attachment
// produces:
// - application/json
// consumes:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to edit
// type: integer
// format: int64
// required: true
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/EditAttachmentOptions"
// responses:
// "201":
// "$ref": "#/responses/Attachment"
// "404":
// "$ref": "#/responses/error"
attachment := getIssueAttachmentSafeWrite(ctx)
if attachment == nil {
return
}
// do changes to attachment. only meaningful change is name.
form := web.GetForm(ctx).(*api.EditAttachmentOptions)
if form.Name != "" {
attachment.Name = form.Name
}
if err := repo_model.UpdateAttachment(ctx, attachment); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", err)
}
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
}
// DeleteIssueAttachment delete a given attachment
func DeleteIssueAttachment(ctx *context.APIContext) {
// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueDeleteIssueAttachment
// ---
// summary: Delete an issue attachment
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to delete
// type: integer
// format: int64
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/error"
attachment := getIssueAttachmentSafeWrite(ctx)
if attachment == nil {
return
}
if err := repo_model.DeleteAttachment(attachment, true); err != nil {
ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err)
return
}
ctx.Status(http.StatusNoContent)
}
func getIssueFromContext(ctx *context.APIContext) *issues_model.Issue {
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64("index"))
if err != nil {
ctx.NotFoundOrServerError("GetIssueByIndex", issues_model.IsErrIssueNotExist, err)
return nil
}
issue.Repo = ctx.Repo.Repository
return issue
}
func getIssueAttachmentSafeWrite(ctx *context.APIContext) *repo_model.Attachment {
issue := getIssueFromContext(ctx)
if issue == nil {
return nil
}
if !canUserWriteIssueAttachment(ctx, issue) {
return nil
}
return getIssueAttachmentSafeRead(ctx, issue)
}
func getIssueAttachmentSafeRead(ctx *context.APIContext, issue *issues_model.Issue) *repo_model.Attachment {
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset"))
if err != nil {
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
return nil
}
if !attachmentBelongsToRepoOrIssue(ctx, attachment, issue) {
return nil
}
return attachment
}
func canUserWriteIssueAttachment(ctx *context.APIContext, issue *issues_model.Issue) bool {
canEditIssue := ctx.IsSigned && (ctx.Doer.ID == issue.PosterID || ctx.IsUserRepoAdmin() || ctx.IsUserSiteAdmin()) && ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
if !canEditIssue {
ctx.Error(http.StatusForbidden, "", "user should have permission to write issue")
return false
}
return true
}
func attachmentBelongsToRepoOrIssue(ctx *context.APIContext, attachment *repo_model.Attachment, issue *issues_model.Issue) bool {
if attachment.RepoID != ctx.Repo.Repository.ID {
log.Debug("Requested attachment[%d] does not belong to repo[%-v].", attachment.ID, ctx.Repo.Repository)
ctx.NotFound("no such attachment in repo")
return false
}
if attachment.IssueID == 0 {
log.Debug("Requested attachment[%d] is not in an issue.", attachment.ID)
ctx.NotFound("no such attachment in issue")
return false
} else if issue != nil && attachment.IssueID != issue.ID {
log.Debug("Requested attachment[%d] does not belong to issue[%d, #%d].", attachment.ID, issue.ID, issue.Index)
ctx.NotFound("no such attachment in issue")
return false
}
return true
}

View File

@ -18,7 +18,7 @@ import (
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
comment_service "code.gitea.io/gitea/services/comments"
issue_service "code.gitea.io/gitea/services/issue"
)
// ListIssueComments list all the comments of an issue
@ -95,6 +95,11 @@ func ListIssueComments(ctx *context.APIContext) {
return
}
if err := issues_model.CommentList(comments).LoadAttachments(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
return
}
apiComments := make([]*api.Comment, len(comments))
for i, comment := range comments {
comment.Issue = issue
@ -294,6 +299,10 @@ func ListRepoIssueComments(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "LoadPosters", err)
return
}
if err := issues_model.CommentList(comments).LoadAttachments(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
return
}
if _, err := issues_model.CommentList(comments).Issues().LoadRepositories(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadRepositories", err)
return
@ -353,7 +362,7 @@ func CreateIssueComment(ctx *context.APIContext) {
return
}
comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil)
comment, err := issue_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil)
if err != nil {
ctx.Error(http.StatusInternalServerError, "CreateIssueComment", err)
return
@ -547,7 +556,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
oldContent := comment.Content
comment.Content = form.Body
if err := comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil {
if err := issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateComment", err)
return
}
@ -646,7 +655,7 @@ func deleteIssueComment(ctx *context.APIContext) {
return
}
if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
ctx.Error(http.StatusInternalServerError, "DeleteCommentByID", err)
return
}

View File

@ -0,0 +1,383 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"net/http"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/attachment"
issue_service "code.gitea.io/gitea/services/issue"
)
// GetIssueCommentAttachment gets a single attachment of the comment
func GetIssueCommentAttachment(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueGetIssueCommentAttachment
// ---
// summary: Get a comment attachment
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment
// type: integer
// format: int64
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to get
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/Attachment"
// "404":
// "$ref": "#/responses/error"
comment := getIssueCommentSafe(ctx)
if comment == nil {
return
}
attachment := getIssueCommentAttachmentSafeRead(ctx, comment)
if attachment == nil {
return
}
if attachment.CommentID != comment.ID {
log.Debug("User requested attachment[%d] is not in comment[%d].", attachment.ID, comment.ID)
ctx.NotFound("attachment not in comment")
return
}
ctx.JSON(http.StatusOK, convert.ToAttachment(attachment))
}
// ListIssueCommentAttachments lists all attachments of the comment
func ListIssueCommentAttachments(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/assets issue issueListIssueCommentAttachments
// ---
// summary: List comment's attachments
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/AttachmentList"
// "404":
// "$ref": "#/responses/error"
comment := getIssueCommentSafe(ctx)
if comment == nil {
return
}
if err := comment.LoadAttachments(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
return
}
ctx.JSON(http.StatusOK, convert.ToAttachments(comment.Attachments))
}
// CreateIssueCommentAttachment creates an attachment and saves the given file
func CreateIssueCommentAttachment(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/issues/comments/{id}/assets issue issueCreateIssueCommentAttachment
// ---
// summary: Create a comment attachment
// produces:
// - application/json
// consumes:
// - multipart/form-data
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment
// type: integer
// format: int64
// required: true
// - name: name
// in: query
// description: name of the attachment
// type: string
// required: false
// - name: attachment
// in: formData
// description: attachment to upload
// type: file
// required: true
// responses:
// "201":
// "$ref": "#/responses/Attachment"
// "400":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/error"
// Check if comment exists and load comment
comment := getIssueCommentSafe(ctx)
if comment == nil {
return
}
if !canUserWriteIssueCommentAttachment(ctx, comment) {
return
}
// Get uploaded file from request
file, header, err := ctx.Req.FormFile("attachment")
if err != nil {
ctx.Error(http.StatusInternalServerError, "FormFile", err)
return
}
defer file.Close()
filename := header.Filename
if query := ctx.FormString("name"); query != "" {
filename = query
}
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
IssueID: comment.IssueID,
CommentID: comment.ID,
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
return
}
if err := comment.LoadAttachments(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
return
}
if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, comment.Content); err != nil {
ctx.ServerError("UpdateComment", err)
return
}
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
}
// EditIssueCommentAttachment updates the given attachment
func EditIssueCommentAttachment(ctx *context.APIContext) {
// swagger:operation PATCH /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueEditIssueCommentAttachment
// ---
// summary: Edit a comment attachment
// produces:
// - application/json
// consumes:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment
// type: integer
// format: int64
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to edit
// type: integer
// format: int64
// required: true
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/EditAttachmentOptions"
// responses:
// "201":
// "$ref": "#/responses/Attachment"
// "404":
// "$ref": "#/responses/error"
attach := getIssueCommentAttachmentSafeWrite(ctx)
if attach == nil {
return
}
form := web.GetForm(ctx).(*api.EditAttachmentOptions)
if form.Name != "" {
attach.Name = form.Name
}
if err := repo_model.UpdateAttachment(ctx, attach); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach)
}
ctx.JSON(http.StatusCreated, convert.ToAttachment(attach))
}
// DeleteIssueCommentAttachment delete a given attachment
func DeleteIssueCommentAttachment(ctx *context.APIContext) {
// swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueDeleteIssueCommentAttachment
// ---
// summary: Delete a comment attachment
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment
// type: integer
// format: int64
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to delete
// type: integer
// format: int64
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/error"
attach := getIssueCommentAttachmentSafeWrite(ctx)
if attach == nil {
return
}
if err := repo_model.DeleteAttachment(attach, true); err != nil {
ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err)
return
}
ctx.Status(http.StatusNoContent)
}
func getIssueCommentSafe(ctx *context.APIContext) *issues_model.Comment {
comment, err := issues_model.GetCommentByID(ctx, ctx.ParamsInt64("id"))
if err != nil {
ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err)
return nil
}
if err := comment.LoadIssue(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err)
return nil
}
if comment.Issue == nil || comment.Issue.RepoID != ctx.Repo.Repository.ID {
ctx.Error(http.StatusNotFound, "", "no matching issue comment found")
return nil
}
comment.Issue.Repo = ctx.Repo.Repository
return comment
}
func getIssueCommentAttachmentSafeWrite(ctx *context.APIContext) *repo_model.Attachment {
comment := getIssueCommentSafe(ctx)
if comment == nil {
return nil
}
if !canUserWriteIssueCommentAttachment(ctx, comment) {
return nil
}
return getIssueCommentAttachmentSafeRead(ctx, comment)
}
func canUserWriteIssueCommentAttachment(ctx *context.APIContext, comment *issues_model.Comment) bool {
canEditComment := ctx.IsSigned && (ctx.Doer.ID == comment.PosterID || ctx.IsUserRepoAdmin() || ctx.IsUserSiteAdmin()) && ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)
if !canEditComment {
ctx.Error(http.StatusForbidden, "", "user should have permission to edit comment")
return false
}
return true
}
func getIssueCommentAttachmentSafeRead(ctx *context.APIContext, comment *issues_model.Comment) *repo_model.Attachment {
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset"))
if err != nil {
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
return nil
}
if !attachmentBelongsToRepoOrComment(ctx, attachment, comment) {
return nil
}
return attachment
}
func attachmentBelongsToRepoOrComment(ctx *context.APIContext, attachment *repo_model.Attachment, comment *issues_model.Comment) bool {
if attachment.RepoID != ctx.Repo.Repository.ID {
log.Debug("Requested attachment[%d] does not belong to repo[%-v].", attachment.ID, ctx.Repo.Repository)
ctx.NotFound("no such attachment in repo")
return false
}
if attachment.IssueID == 0 || attachment.CommentID == 0 {
log.Debug("Requested attachment[%d] is not in a comment.", attachment.ID)
ctx.NotFound("no such attachment in comment")
return false
}
if comment != nil && attachment.CommentID != comment.ID {
log.Debug("Requested attachment[%d] does not belong to comment[%d].", attachment.ID, comment.ID)
ctx.NotFound("no such attachment in comment")
return false
}
return true
}

View File

@ -71,7 +71,7 @@ func ListTrackedTimes(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
if !ctx.Repo.Repository.IsTimetrackerEnabled() {
if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
ctx.NotFound("Timetracker is disabled")
return
}
@ -190,7 +190,7 @@ func AddTime(ctx *context.APIContext) {
}
if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) {
if !ctx.Repo.Repository.IsTimetrackerEnabled() {
if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
ctx.Error(http.StatusBadRequest, "", "time tracking disabled")
return
}
@ -271,7 +271,7 @@ func ResetIssueTime(ctx *context.APIContext) {
}
if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) {
if !ctx.Repo.Repository.IsTimetrackerEnabled() {
if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"})
return
}
@ -342,7 +342,7 @@ func DeleteTime(ctx *context.APIContext) {
}
if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) {
if !ctx.Repo.Repository.IsTimetrackerEnabled() {
if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"})
return
}
@ -410,7 +410,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) {
// "403":
// "$ref": "#/responses/forbidden"
if !ctx.Repo.Repository.IsTimetrackerEnabled() {
if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
ctx.Error(http.StatusBadRequest, "", "time tracking disabled")
return
}
@ -498,7 +498,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) {
// "403":
// "$ref": "#/responses/forbidden"
if !ctx.Repo.Repository.IsTimetrackerEnabled() {
if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
ctx.Error(http.StatusBadRequest, "", "time tracking disabled")
return
}

View File

@ -68,7 +68,7 @@ func GetReleaseAttachment(ctx *context.APIContext) {
return
}
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests
ctx.JSON(http.StatusOK, convert.ToReleaseAttachment(attach))
ctx.JSON(http.StatusOK, convert.ToAttachment(attach))
}
// ListReleaseAttachments lists all attachments of the release
@ -194,7 +194,12 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
}
// Create a new attachment and save the file
attach, err := attachment.UploadAttachment(file, ctx.Doer.ID, release.RepoID, releaseID, filename, setting.Repository.Release.AllowedTypes)
attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: release.RepoID,
ReleaseID: releaseID,
})
if err != nil {
if upload.IsErrFileTypeForbidden(err) {
ctx.Error(http.StatusBadRequest, "DetectContentType", err)
@ -204,7 +209,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
return
}
ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach))
ctx.JSON(http.StatusCreated, convert.ToAttachment(attach))
}
// EditReleaseAttachment updates the given attachment
@ -274,7 +279,7 @@ func EditReleaseAttachment(ctx *context.APIContext) {
if err := repo_model.UpdateAttachment(ctx, attach); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach)
}
ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach))
ctx.JSON(http.StatusCreated, convert.ToAttachment(attach))
}
// DeleteReleaseAttachment delete a given attachment

View File

@ -736,7 +736,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
var units []repo_model.RepoUnit
var deleteUnitTypes []unit_model.Type
currHasIssues := repo.UnitEnabledCtx(ctx, unit_model.TypeIssues)
currHasIssues := repo.UnitEnabled(ctx, unit_model.TypeIssues)
newHasIssues := currHasIssues
if opts.HasIssues != nil {
newHasIssues = *opts.HasIssues
@ -776,7 +776,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime,
EnableDependencies: opts.InternalTracker.EnableIssueDependencies,
}
} else if unit, err := repo.GetUnit(unit_model.TypeIssues); err != nil {
} else if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err != nil {
// Unit type doesn't exist so we make a new config file with default values
config = &repo_model.IssuesConfig{
EnableTimetracker: true,
@ -803,7 +803,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
}
}
currHasWiki := repo.UnitEnabledCtx(ctx, unit_model.TypeWiki)
currHasWiki := repo.UnitEnabled(ctx, unit_model.TypeWiki)
newHasWiki := currHasWiki
if opts.HasWiki != nil {
newHasWiki = *opts.HasWiki
@ -843,7 +843,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
}
}
currHasPullRequests := repo.UnitEnabledCtx(ctx, unit_model.TypePullRequests)
currHasPullRequests := repo.UnitEnabled(ctx, unit_model.TypePullRequests)
newHasPullRequests := currHasPullRequests
if opts.HasPullRequests != nil {
newHasPullRequests = *opts.HasPullRequests
@ -853,7 +853,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
// We do allow setting individual PR settings through the API, so
// we get the config settings and then set them
// if those settings were provided in the opts.
unit, err := repo.GetUnit(unit_model.TypePullRequests)
unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests)
var config *repo_model.PullRequestsConfig
if err != nil {
// Unit type doesn't exist so we make a new config file with default values

View File

@ -105,7 +105,7 @@ func Transfer(ctx *context.APIContext) {
oldFullname := ctx.Repo.Repository.FullName()
if err := repo_service.StartRepositoryTransfer(ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil {
if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil {
if models.IsErrRepoTransferInProgress(err) {
ctx.Error(http.StatusConflict, "StartRepositoryTransfer", err)
return
@ -207,7 +207,7 @@ func RejectTransfer(ctx *context.APIContext) {
}
func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository)
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil {
if models.IsErrNoPendingTransfer(err) {
ctx.NotFound()
@ -216,7 +216,7 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {
return err
}
if err := repoTransfer.LoadAttributes(); err != nil {
if err := repoTransfer.LoadAttributes(ctx); err != nil {
return err
}
@ -226,7 +226,7 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {
}
if accept {
return repo_service.TransferOwnership(repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams)
return repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams)
}
return models.CancelRepositoryTransfer(ctx.Repo.Repository)

View File

@ -6,7 +6,6 @@ package private
import (
"net/http"
"reflect"
"strings"
"code.gitea.io/gitea/modules/context"
@ -39,13 +38,9 @@ func CheckInternalToken(next http.Handler) http.Handler {
}
// bind binding an obj to a handler
func bind(obj interface{}) http.HandlerFunc {
tp := reflect.TypeOf(obj)
for tp.Kind() == reflect.Ptr {
tp = tp.Elem()
}
func bind[T any](obj T) http.HandlerFunc {
return web.Wrap(func(ctx *context.PrivateContext) {
theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly
theObj := new(T) // create a new form obj for every request but not use obj directly
binding.Bind(ctx.Req, theObj)
web.SetForm(ctx, theObj)
})

View File

@ -382,7 +382,7 @@ func ServCommand(ctx *context.PrivateContext) {
if results.IsWiki {
// Ensure the wiki is enabled before we allow access to it
if _, err := repo.GetUnit(unit.TypeWiki); err != nil {
if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil {
if repo_model.IsErrUnitTypeNotExist(err) {
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
Results: results,

View File

@ -68,6 +68,10 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions,
orderBy = "`user`.updated_unix ASC"
case "reversealphabetically":
orderBy = "`user`.name DESC"
case "lastlogin":
orderBy = "`user`.last_login_unix ASC"
case "reverselastlogin":
orderBy = "`user`.last_login_unix DESC"
case UserSearchDefaultSortType: // "alphabetically"
default:
orderBy = "`user`.name ASC"

View File

@ -44,7 +44,11 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
}
defer file.Close()
attach, err := attachment.UploadAttachment(file, ctx.Doer.ID, repoID, 0, header.Filename, allowedTypes)
attach, err := attachment.UploadAttachment(file, allowedTypes, &repo_model.Attachment{
Name: header.Filename,
UploaderID: ctx.Doer.ID,
RepoID: repoID,
})
if err != nil {
if upload.IsErrFileTypeForbidden(err) {
ctx.Error(http.StatusBadRequest, err.Error())
@ -82,7 +86,7 @@ func DeleteAttachment(ctx *context.Context) {
})
}
// GetAttachment serve attachements
// GetAttachment serve attachments
func GetAttachment(ctx *context.Context) {
attach, err := repo_model.GetAttachmentByUUID(ctx, ctx.Params(":uuid"))
if err != nil {

View File

@ -177,7 +177,7 @@ func CherryPickPost(ctx *context.Context) {
}
}
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
} else {
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName))

View File

@ -577,7 +577,7 @@ func PrepareCompareDiff(
if (headCommitID == ci.CompareInfo.MergeBase && !ci.DirectComparison) ||
headCommitID == ci.CompareInfo.BaseCommitID {
ctx.Data["IsNothingToCompare"] = true
if unit, err := repo.GetUnit(unit.TypePullRequests); err == nil {
if unit, err := repo.GetUnit(ctx, unit.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
if !config.AutodetectManualMerge {

View File

@ -328,7 +328,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
}
}
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
} else {
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
@ -514,7 +514,7 @@ func DeleteFilePost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
} else {
treePath := path.Dir(ctx.Repo.TreePath)
@ -717,7 +717,7 @@ func UploadFilePost(ctx *context.Context) {
return
}
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
} else {
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))

View File

@ -258,7 +258,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
if isWiki {
// Ensure the wiki is enabled before we allow access to it
if _, err := repo.GetUnit(unit.TypeWiki); err != nil {
if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil {
if repo_model.IsErrUnitTypeNotExist(err) {
ctx.PlainText(http.StatusForbidden, "repository wiki is disabled")
return

View File

@ -47,7 +47,6 @@ import (
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
comment_service "code.gitea.io/gitea/services/comments"
"code.gitea.io/gitea/services/forms"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"
@ -114,7 +113,7 @@ func MustEnableIssues(ctx *context.Context) {
return
}
unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker)
unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker)
if err == nil {
ctx.Redirect(unit.ExternalTrackerConfig().ExternalTrackerURL)
return
@ -1174,7 +1173,7 @@ func getBranchData(ctx *context.Context, issue *issues_model.Issue) {
func ViewIssue(ctx *context.Context) {
if ctx.Params(":type") == "issues" {
// If issue was requested we check if repo has external tracker and redirect
extIssueUnit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker)
extIssueUnit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker)
if err == nil && extIssueUnit != nil {
if extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == markup.IssueNameStyleNumeric || extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == "" {
metas := ctx.Repo.Repository.ComposeMetas()
@ -1375,7 +1374,7 @@ func ViewIssue(ctx *context.Context) {
comment *issues_model.Comment
participants = make([]*user_model.User, 1, 10)
)
if ctx.Repo.Repository.IsTimetrackerEnabled() {
if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
if ctx.IsSigned {
// Deal with the stopwatch
ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx.Doer.ID, issue.ID)
@ -1636,7 +1635,7 @@ func ViewIssue(ctx *context.Context) {
}
}
prUnit, err := repo.GetUnit(unit.TypePullRequests)
prUnit, err := repo.GetUnit(ctx, unit.TypePullRequests)
if err != nil {
ctx.ServerError("GetUnit", err)
return
@ -2709,7 +2708,7 @@ func NewComment(ctx *context.Context) {
return
}
comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments)
comment, err := issue_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments)
if err != nil {
ctx.ServerError("CreateIssueComment", err)
return
@ -2749,7 +2748,7 @@ func UpdateCommentContent(ctx *context.Context) {
})
return
}
if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil {
if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil {
ctx.ServerError("UpdateComment", err)
return
}
@ -2805,7 +2804,7 @@ func DeleteComment(ctx *context.Context) {
return
}
if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
ctx.ServerError("DeleteComment", err)
return
}
@ -3050,7 +3049,7 @@ func GetIssueAttachments(ctx *context.Context) {
issue := GetActionIssue(ctx)
attachments := make([]*api.Attachment, len(issue.Attachments))
for i := 0; i < len(issue.Attachments); i++ {
attachments[i] = convert.ToReleaseAttachment(issue.Attachments[i])
attachments[i] = convert.ToAttachment(issue.Attachments[i])
}
ctx.JSON(http.StatusOK, attachments)
}
@ -3069,7 +3068,7 @@ func GetCommentAttachments(ctx *context.Context) {
return
}
for i := 0; i < len(comment.Attachments); i++ {
attachments = append(attachments, convert.ToReleaseAttachment(comment.Attachments[i]))
attachments = append(attachments, convert.ToAttachment(comment.Attachments[i]))
}
}
ctx.JSON(http.StatusOK, attachments)

View File

@ -73,7 +73,7 @@ func Milestones(ctx *context.Context) {
ctx.ServerError("GetMilestones", err)
return
}
if ctx.Repo.Repository.IsTimetrackerEnabled() {
if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
if err := miles.LoadTotalTrackedTimes(); err != nil {
ctx.ServerError("LoadTotalTrackedTimes", err)
return

View File

@ -108,7 +108,7 @@ func NewDiffPatchPost(ctx *context.Context) {
}
}
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
} else {
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))

View File

@ -196,7 +196,7 @@ func DeleteProject(ctx *context.Context) {
return
}
if err := project_model.DeleteProjectByID(p.ID); err != nil {
if err := project_model.DeleteProjectByID(ctx, p.ID); err != nil {
ctx.Flash.Error("DeleteProjectByID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.projects.deletion_success"))

View File

@ -135,7 +135,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
return
}
count, err := repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, opts)
count, err := repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, opts)
if err != nil {
ctx.ServerError("GetReleaseCountByRepoID", err)
return

View File

@ -315,12 +315,12 @@ func Action(ctx *context.Context) {
}
func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error {
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository)
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil {
return err
}
if err := repoTransfer.LoadAttributes(); err != nil {
if err := repoTransfer.LoadAttributes(ctx); err != nil {
return err
}
@ -334,7 +334,7 @@ func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error {
ctx.Repo.GitRepo = nil
}
if err := repo_service.TransferOwnership(repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil {
if err := repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil {
return err
}
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success"))

View File

@ -412,6 +412,15 @@ func SettingsPost(ctx *context.Context) {
repoChanged = true
}
if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() {
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
Type: unit_model.TypeCode,
})
} else if !unit_model.TypeCode.UnitGlobalDisabled() {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode)
}
if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
if !validation.IsValidExternalURL(form.ExternalWikiURL) {
ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
@ -704,7 +713,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Repo.GitRepo = nil
}
if err := repo_service.StartRepositoryTransfer(ctx.Doer, newOwner, repo, nil); err != nil {
if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil {
if repo_model.IsErrRepoAlreadyExist(err) {
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
} else if models.IsErrRepoTransferInProgress(err) {
@ -726,7 +735,7 @@ func SettingsPost(ctx *context.Context) {
return
}
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository)
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
if err != nil {
if models.IsErrNoPendingTransfer(err) {
ctx.Flash.Error("repo.settings.transfer_abort_invalid")
@ -738,7 +747,7 @@ func SettingsPost(ctx *context.Context) {
return
}
if err := repoTransfer.LoadAttributes(); err != nil {
if err := repoTransfer.LoadAttributes(ctx); err != nil {
ctx.ServerError("LoadRecipient", err)
return
}
@ -944,7 +953,7 @@ func CollaborationPost(ctx *context.Context) {
}
}
if err = repo_module.AddCollaborator(ctx.Repo.Repository, u); err != nil {
if err = repo_module.AddCollaborator(ctx, ctx.Repo.Repository, u); err != nil {
ctx.ServerError("AddCollaborator", err)
return
}
@ -960,6 +969,7 @@ func CollaborationPost(ctx *context.Context) {
// ChangeCollaborationAccessMode response for changing access of a collaboration
func ChangeCollaborationAccessMode(ctx *context.Context) {
if err := repo_model.ChangeCollaborationAccessMode(
ctx,
ctx.Repo.Repository,
ctx.FormInt64("uid"),
perm.AccessMode(ctx.FormInt("mode"))); err != nil {

View File

@ -59,7 +59,7 @@ func MustEnableWiki(ctx *context.Context) {
return
}
unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalWiki)
unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalWiki)
if err == nil {
ctx.Redirect(unit.ExternalWikiConfig().ExternalWikiURL)
return

View File

@ -231,7 +231,7 @@ func Milestones(ctx *context.Context) {
return
}
if milestones[i].Repo.IsTimetrackerEnabled() {
if milestones[i].Repo.IsTimetrackerEnabled(ctx) {
err := milestones[i].LoadTotalTrackedTime()
if err != nil {
ctx.ServerError("LoadTotalTrackedTime", err)

View File

@ -26,7 +26,7 @@ func TestArchivedIssues(t *testing.T) {
// Assume: User 30 has access to two Repos with Issues, one of the Repos being archived.
repos, _, _ := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{Actor: ctx.Doer})
assert.Len(t, repos, 2)
assert.Len(t, repos, 3)
IsArchived := make(map[int64]bool)
NumIssues := make(map[int64]int)
for _, repo := range repos {

View File

@ -234,8 +234,6 @@ func RegisterRoutes(m *web.Route) {
ignExploreSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView})
ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})
reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true})
bindIgnErr := web.Bind
validation.AddBindingRules()
linkAccountEnabled := func(ctx *context.Context) {
@ -356,32 +354,32 @@ func RegisterRoutes(m *web.Route) {
// ***** START: User *****
m.Group("/user", func() {
m.Get("/login", auth.SignIn)
m.Post("/login", bindIgnErr(forms.SignInForm{}), auth.SignInPost)
m.Post("/login", web.Bind(forms.SignInForm{}), auth.SignInPost)
m.Group("", func() {
m.Combo("/login/openid").
Get(auth.SignInOpenID).
Post(bindIgnErr(forms.SignInOpenIDForm{}), auth.SignInOpenIDPost)
Post(web.Bind(forms.SignInOpenIDForm{}), auth.SignInOpenIDPost)
}, openIDSignInEnabled)
m.Group("/openid", func() {
m.Combo("/connect").
Get(auth.ConnectOpenID).
Post(bindIgnErr(forms.ConnectOpenIDForm{}), auth.ConnectOpenIDPost)
Post(web.Bind(forms.ConnectOpenIDForm{}), auth.ConnectOpenIDPost)
m.Group("/register", func() {
m.Combo("").
Get(auth.RegisterOpenID, openIDSignUpEnabled).
Post(bindIgnErr(forms.SignUpOpenIDForm{}), auth.RegisterOpenIDPost)
Post(web.Bind(forms.SignUpOpenIDForm{}), auth.RegisterOpenIDPost)
}, openIDSignUpEnabled)
}, openIDSignInEnabled)
m.Get("/sign_up", auth.SignUp)
m.Post("/sign_up", bindIgnErr(forms.RegisterForm{}), auth.SignUpPost)
m.Post("/sign_up", web.Bind(forms.RegisterForm{}), auth.SignUpPost)
m.Get("/link_account", linkAccountEnabled, auth.LinkAccount)
m.Post("/link_account_signin", linkAccountEnabled, bindIgnErr(forms.SignInForm{}), auth.LinkAccountPostSignIn)
m.Post("/link_account_signup", linkAccountEnabled, bindIgnErr(forms.RegisterForm{}), auth.LinkAccountPostRegister)
m.Post("/link_account_signin", linkAccountEnabled, web.Bind(forms.SignInForm{}), auth.LinkAccountPostSignIn)
m.Post("/link_account_signup", linkAccountEnabled, web.Bind(forms.RegisterForm{}), auth.LinkAccountPostRegister)
m.Group("/two_factor", func() {
m.Get("", auth.TwoFactor)
m.Post("", bindIgnErr(forms.TwoFactorAuthForm{}), auth.TwoFactorPost)
m.Post("", web.Bind(forms.TwoFactorAuthForm{}), auth.TwoFactorPost)
m.Get("/scratch", auth.TwoFactorScratch)
m.Post("/scratch", bindIgnErr(forms.TwoFactorScratchAuthForm{}), auth.TwoFactorScratchPost)
m.Post("/scratch", web.Bind(forms.TwoFactorScratchAuthForm{}), auth.TwoFactorScratchPost)
})
m.Group("/webauthn", func() {
m.Get("", auth.WebAuthn)
@ -393,34 +391,34 @@ func RegisterRoutes(m *web.Route) {
m.Any("/user/events", routing.MarkLongPolling, events.Events)
m.Group("/login/oauth", func() {
m.Get("/authorize", bindIgnErr(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
m.Post("/grant", bindIgnErr(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth)
m.Get("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
m.Post("/grant", web.Bind(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth)
// TODO manage redirection
m.Post("/authorize", bindIgnErr(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
}, ignSignInAndCsrf, reqSignIn)
m.Get("/login/oauth/userinfo", ignSignInAndCsrf, auth.InfoOAuth)
m.Post("/login/oauth/access_token", CorsHandler(), bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
m.Post("/login/oauth/access_token", CorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
m.Get("/login/oauth/keys", ignSignInAndCsrf, auth.OIDCKeys)
m.Post("/login/oauth/introspect", CorsHandler(), bindIgnErr(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
m.Post("/login/oauth/introspect", CorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
m.Group("/user/settings", func() {
m.Get("", user_setting.Profile)
m.Post("", bindIgnErr(forms.UpdateProfileForm{}), user_setting.ProfilePost)
m.Post("", web.Bind(forms.UpdateProfileForm{}), user_setting.ProfilePost)
m.Get("/change_password", auth.MustChangePassword)
m.Post("/change_password", bindIgnErr(forms.MustChangePasswordForm{}), auth.MustChangePasswordPost)
m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), user_setting.AvatarPost)
m.Post("/change_password", web.Bind(forms.MustChangePasswordForm{}), auth.MustChangePasswordPost)
m.Post("/avatar", web.Bind(forms.AvatarForm{}), user_setting.AvatarPost)
m.Post("/avatar/delete", user_setting.DeleteAvatar)
m.Group("/account", func() {
m.Combo("").Get(user_setting.Account).Post(bindIgnErr(forms.ChangePasswordForm{}), user_setting.AccountPost)
m.Post("/email", bindIgnErr(forms.AddEmailForm{}), user_setting.EmailPost)
m.Combo("").Get(user_setting.Account).Post(web.Bind(forms.ChangePasswordForm{}), user_setting.AccountPost)
m.Post("/email", web.Bind(forms.AddEmailForm{}), user_setting.EmailPost)
m.Post("/email/delete", user_setting.DeleteEmail)
m.Post("/delete", user_setting.DeleteAccount)
})
m.Group("/appearance", func() {
m.Get("", user_setting.Appearance)
m.Post("/language", bindIgnErr(forms.UpdateLanguageForm{}), user_setting.UpdateUserLang)
m.Post("/language", web.Bind(forms.UpdateLanguageForm{}), user_setting.UpdateUserLang)
m.Post("/hidden_comments", user_setting.UpdateUserHiddenComments)
m.Post("/theme", bindIgnErr(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost)
m.Post("/theme", web.Bind(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost)
})
m.Group("/security", func() {
m.Get("", security.Security)
@ -428,15 +426,15 @@ func RegisterRoutes(m *web.Route) {
m.Post("/regenerate_scratch", security.RegenerateScratchTwoFactor)
m.Post("/disable", security.DisableTwoFactor)
m.Get("/enroll", security.EnrollTwoFactor)
m.Post("/enroll", bindIgnErr(forms.TwoFactorAuthForm{}), security.EnrollTwoFactorPost)
m.Post("/enroll", web.Bind(forms.TwoFactorAuthForm{}), security.EnrollTwoFactorPost)
})
m.Group("/webauthn", func() {
m.Post("/request_register", bindIgnErr(forms.WebauthnRegistrationForm{}), security.WebAuthnRegister)
m.Post("/request_register", web.Bind(forms.WebauthnRegistrationForm{}), security.WebAuthnRegister)
m.Post("/register", security.WebauthnRegisterPost)
m.Post("/delete", bindIgnErr(forms.WebauthnDeleteForm{}), security.WebauthnDelete)
m.Post("/delete", web.Bind(forms.WebauthnDeleteForm{}), security.WebauthnDelete)
})
m.Group("/openid", func() {
m.Post("", bindIgnErr(forms.AddOpenIDForm{}), security.OpenIDPost)
m.Post("", web.Bind(forms.AddOpenIDForm{}), security.OpenIDPost)
m.Post("/delete", security.DeleteOpenID)
m.Post("/toggle_visibility", security.ToggleOpenIDVisibility)
}, openIDSignInEnabled)
@ -444,28 +442,28 @@ func RegisterRoutes(m *web.Route) {
})
m.Group("/applications/oauth2", func() {
m.Get("/{id}", user_setting.OAuth2ApplicationShow)
m.Post("/{id}", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit)
m.Post("/{id}", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit)
m.Post("/{id}/regenerate_secret", user_setting.OAuthApplicationsRegenerateSecret)
m.Post("", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost)
m.Post("", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost)
m.Post("/{id}/delete", user_setting.DeleteOAuth2Application)
m.Post("/{id}/revoke/{grantId}", user_setting.RevokeOAuth2Grant)
})
m.Combo("/applications").Get(user_setting.Applications).
Post(bindIgnErr(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost)
Post(web.Bind(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost)
m.Post("/applications/delete", user_setting.DeleteApplication)
m.Combo("/keys").Get(user_setting.Keys).
Post(bindIgnErr(forms.AddKeyForm{}), user_setting.KeysPost)
Post(web.Bind(forms.AddKeyForm{}), user_setting.KeysPost)
m.Post("/keys/delete", user_setting.DeleteKey)
m.Group("/packages", func() {
m.Get("", user_setting.Packages)
m.Group("/rules", func() {
m.Group("/add", func() {
m.Get("", user_setting.PackagesRuleAdd)
m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleAddPost)
m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleAddPost)
})
m.Group("/{id}", func() {
m.Get("", user_setting.PackagesRuleEdit)
m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleEditPost)
m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleEditPost)
m.Get("/preview", user_setting.PackagesRulePreview)
})
})
@ -507,7 +505,7 @@ func RegisterRoutes(m *web.Route) {
// ***** START: Admin *****
m.Group("/admin", func() {
m.Get("", adminReq, admin.Dashboard)
m.Post("", adminReq, bindIgnErr(forms.AdminDashboardForm{}), admin.DashboardPost)
m.Post("", adminReq, web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost)
m.Group("/config", func() {
m.Get("", admin.Config)
@ -532,10 +530,10 @@ func RegisterRoutes(m *web.Route) {
m.Group("/users", func() {
m.Get("", admin.Users)
m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(forms.AdminCreateUserForm{}), admin.NewUserPost)
m.Combo("/{userid}").Get(admin.EditUser).Post(bindIgnErr(forms.AdminEditUserForm{}), admin.EditUserPost)
m.Combo("/new").Get(admin.NewUser).Post(web.Bind(forms.AdminCreateUserForm{}), admin.NewUserPost)
m.Combo("/{userid}").Get(admin.EditUser).Post(web.Bind(forms.AdminEditUserForm{}), admin.EditUserPost)
m.Post("/{userid}/delete", admin.DeleteUser)
m.Post("/{userid}/avatar", bindIgnErr(forms.AvatarForm{}), admin.AvatarPost)
m.Post("/{userid}/avatar", web.Bind(forms.AvatarForm{}), admin.AvatarPost)
m.Post("/{userid}/avatar/delete", admin.DeleteAvatar)
})
@ -566,39 +564,39 @@ func RegisterRoutes(m *web.Route) {
m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/packagist/{id}", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
}, webhooksEnabled)
m.Group("/{configType:default-hooks|system-hooks}", func() {
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/packagist/new", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
})
m.Group("/auths", func() {
m.Get("", admin.Authentications)
m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(forms.AuthenticationForm{}), admin.NewAuthSourcePost)
m.Combo("/new").Get(admin.NewAuthSource).Post(web.Bind(forms.AuthenticationForm{}), admin.NewAuthSourcePost)
m.Combo("/{authid}").Get(admin.EditAuthSource).
Post(bindIgnErr(forms.AuthenticationForm{}), admin.EditAuthSourcePost)
Post(web.Bind(forms.AuthenticationForm{}), admin.EditAuthSourcePost)
m.Post("/{authid}/delete", admin.DeleteAuthSource)
})
@ -610,9 +608,9 @@ func RegisterRoutes(m *web.Route) {
m.Group("/applications", func() {
m.Get("", admin.Applications)
m.Post("/oauth2", bindIgnErr(forms.EditOAuth2ApplicationForm{}), admin.ApplicationsPost)
m.Post("/oauth2", web.Bind(forms.EditOAuth2ApplicationForm{}), admin.ApplicationsPost)
m.Group("/oauth2/{id}", func() {
m.Combo("").Get(admin.EditApplication).Post(bindIgnErr(forms.EditOAuth2ApplicationForm{}), admin.EditApplicationPost)
m.Combo("").Get(admin.EditApplication).Post(web.Bind(forms.EditOAuth2ApplicationForm{}), admin.EditApplicationPost)
m.Post("/regenerate_secret", admin.ApplicationsRegenerateSecret)
m.Post("/delete", admin.DeleteApplication)
})
@ -657,7 +655,6 @@ func RegisterRoutes(m *web.Route) {
reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases)
reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases)
reqRepoWikiWriter := context.RequireRepoWriter(unit.TypeWiki)
reqRepoIssueWriter := context.RequireRepoWriter(unit.TypeIssues)
reqRepoIssueReader := context.RequireRepoReader(unit.TypeIssues)
reqRepoPullsReader := context.RequireRepoReader(unit.TypePullRequests)
reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(unit.TypeIssues, unit.TypePullRequests)
@ -683,7 +680,7 @@ func RegisterRoutes(m *web.Route) {
m.Group("/org", func() {
m.Group("", func() {
m.Get("/create", org.Create)
m.Post("/create", bindIgnErr(forms.CreateOrgForm{}), org.CreatePost)
m.Post("/create", web.Bind(forms.CreateOrgForm{}), org.CreatePost)
})
m.Group("/invite/{token}", func() {
@ -713,22 +710,22 @@ func RegisterRoutes(m *web.Route) {
m.Group("/{org}", func() {
m.Get("/teams/new", org.NewTeam)
m.Post("/teams/new", bindIgnErr(forms.CreateTeamForm{}), org.NewTeamPost)
m.Post("/teams/new", web.Bind(forms.CreateTeamForm{}), org.NewTeamPost)
m.Get("/teams/-/search", org.SearchTeam)
m.Get("/teams/{team}/edit", org.EditTeam)
m.Post("/teams/{team}/edit", bindIgnErr(forms.CreateTeamForm{}), org.EditTeamPost)
m.Post("/teams/{team}/edit", web.Bind(forms.CreateTeamForm{}), org.EditTeamPost)
m.Post("/teams/{team}/delete", org.DeleteTeam)
m.Group("/settings", func() {
m.Combo("").Get(org.Settings).
Post(bindIgnErr(forms.UpdateOrgSettingForm{}), org.SettingsPost)
m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), org.SettingsAvatar)
Post(web.Bind(forms.UpdateOrgSettingForm{}), org.SettingsPost)
m.Post("/avatar", web.Bind(forms.AvatarForm{}), org.SettingsAvatar)
m.Post("/avatar/delete", org.SettingsDeleteAvatar)
m.Group("/applications", func() {
m.Get("", org.Applications)
m.Post("/oauth2", bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuthApplicationsPost)
m.Post("/oauth2", web.Bind(forms.EditOAuth2ApplicationForm{}), org.OAuthApplicationsPost)
m.Group("/oauth2/{id}", func() {
m.Combo("").Get(org.OAuth2ApplicationShow).Post(bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuth2ApplicationEdit)
m.Combo("").Get(org.OAuth2ApplicationShow).Post(web.Bind(forms.EditOAuth2ApplicationForm{}), org.OAuth2ApplicationEdit)
m.Post("/regenerate_secret", org.OAuthApplicationsRegenerateSecret)
m.Post("/delete", org.DeleteOAuth2Application)
})
@ -743,38 +740,38 @@ func RegisterRoutes(m *web.Route) {
m.Get("", org.Webhooks)
m.Post("/delete", org.DeleteWebhook)
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Group("/{id}", func() {
m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
}, webhooksEnabled)
m.Group("/labels", func() {
m.Get("", org.RetrieveLabels, org.Labels)
m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), org.NewLabel)
m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), org.UpdateLabel)
m.Post("/new", web.Bind(forms.CreateLabelForm{}), org.NewLabel)
m.Post("/edit", web.Bind(forms.CreateLabelForm{}), org.UpdateLabel)
m.Post("/delete", org.DeleteLabel)
m.Post("/initialize", bindIgnErr(forms.InitializeLabelsForm{}), org.InitializeLabels)
m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), org.InitializeLabels)
})
m.Route("/delete", "GET,POST", org.SettingsDelete)
@ -784,11 +781,11 @@ func RegisterRoutes(m *web.Route) {
m.Group("/rules", func() {
m.Group("/add", func() {
m.Get("", org.PackagesRuleAdd)
m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), org.PackagesRuleAddPost)
m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), org.PackagesRuleAddPost)
})
m.Group("/{id}", func() {
m.Get("", org.PackagesRuleEdit)
m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), org.PackagesRuleEditPost)
m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), org.PackagesRuleEditPost)
m.Get("/preview", org.PackagesRulePreview)
})
})
@ -804,12 +801,12 @@ func RegisterRoutes(m *web.Route) {
// ***** START: Repository *****
m.Group("/repo", func() {
m.Get("/create", repo.Create)
m.Post("/create", bindIgnErr(forms.CreateRepoForm{}), repo.CreatePost)
m.Post("/create", web.Bind(forms.CreateRepoForm{}), repo.CreatePost)
m.Get("/migrate", repo.Migrate)
m.Post("/migrate", bindIgnErr(forms.MigrateRepoForm{}), repo.MigratePost)
m.Post("/migrate", web.Bind(forms.MigrateRepoForm{}), repo.MigratePost)
m.Group("/fork", func() {
m.Combo("/{repoid}").Get(repo.Fork).
Post(bindIgnErr(forms.CreateRepoForm{}), repo.ForkPost)
Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
}, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader)
m.Get("/search", repo.SearchRepo)
}, reqSignIn)
@ -826,7 +823,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("/files/{fileid}", user.DownloadPackageFile)
m.Group("/settings", func() {
m.Get("", user.PackageSettings)
m.Post("", bindIgnErr(forms.PackageSettingForm{}), user.PackageSettingsPost)
m.Post("", web.Bind(forms.PackageSettingForm{}), user.PackageSettingsPost)
}, reqPackageAccess(perm.AccessModeWrite))
})
})
@ -842,9 +839,9 @@ func RegisterRoutes(m *web.Route) {
m.Group("/settings", func() {
m.Group("", func() {
m.Combo("").Get(repo.Settings).
Post(bindIgnErr(forms.RepoSettingForm{}), repo.SettingsPost)
Post(web.Bind(forms.RepoSettingForm{}), repo.SettingsPost)
}, repo.SettingsCtxData)
m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), repo.SettingsAvatar)
m.Post("/avatar", web.Bind(forms.AvatarForm{}), repo.SettingsAvatar)
m.Post("/avatar/delete", repo.SettingsDeleteAvatar)
m.Group("/collaboration", func() {
@ -860,16 +857,16 @@ func RegisterRoutes(m *web.Route) {
m.Group("/branches", func() {
m.Combo("").Get(repo.ProtectedBranch).Post(repo.ProtectedBranchPost)
m.Combo("/*").Get(repo.SettingsProtectedBranch).
Post(bindIgnErr(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost)
Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost)
}, repo.MustBeNotEmpty)
m.Post("/rename_branch", bindIgnErr(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo.RenameBranchPost)
m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo.RenameBranchPost)
m.Group("/tags", func() {
m.Get("", repo.Tags)
m.Post("", bindIgnErr(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.NewProtectedTagPost)
m.Post("", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.NewProtectedTagPost)
m.Post("/delete", context.RepoMustNotBeArchived(), repo.DeleteProtectedTagPost)
m.Get("/{id}", repo.EditProtectedTag)
m.Post("/{id}", bindIgnErr(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.EditProtectedTagPost)
m.Post("/{id}", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.EditProtectedTagPost)
})
m.Group("/hooks/git", func() {
@ -882,38 +879,38 @@ func RegisterRoutes(m *web.Route) {
m.Get("", repo.Webhooks)
m.Post("/delete", repo.DeleteWebhook)
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/packagist/new", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
m.Group("/{id}", func() {
m.Get("", repo.WebHooksEdit)
m.Post("/test", repo.TestWebhook)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/packagist/{id}", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
}, webhooksEnabled)
m.Group("/keys", func() {
m.Combo("").Get(repo.DeployKeys).
Post(bindIgnErr(forms.AddKeyForm{}), repo.DeployKeysPost)
Post(web.Bind(forms.AddKeyForm{}), repo.DeployKeysPost)
m.Post("/delete", repo.DeleteDeployKey)
})
@ -952,7 +949,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("/compare", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists, ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists).
Get(ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
m.Group("/{type:issues|pulls}", func() {
m.Group("/{index}", func() {
m.Get("/info", repo.GetIssueInfo)
@ -965,7 +962,7 @@ func RegisterRoutes(m *web.Route) {
m.Group("/issues", func() {
m.Group("/new", func() {
m.Combo("").Get(context.RepoRef(), repo.NewIssue).
Post(bindIgnErr(forms.CreateIssueForm{}), repo.NewIssuePost)
Post(web.Bind(forms.CreateIssueForm{}), repo.NewIssuePost)
m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate)
})
m.Get("/search", repo.ListIssues)
@ -976,7 +973,7 @@ func RegisterRoutes(m *web.Route) {
m.Group("/{index}", func() {
m.Post("/title", repo.UpdateIssueTitle)
m.Post("/content", repo.UpdateIssueContent)
m.Post("/deadline", bindIgnErr(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline)
m.Post("/deadline", web.Bind(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline)
m.Post("/watch", repo.IssueWatch)
m.Post("/ref", repo.UpdateIssueRef)
m.Post("/viewed-files", repo.UpdateViewedFiles)
@ -984,18 +981,18 @@ func RegisterRoutes(m *web.Route) {
m.Post("/add", repo.AddDependency)
m.Post("/delete", repo.RemoveDependency)
})
m.Combo("/comments").Post(repo.MustAllowUserComment, bindIgnErr(forms.CreateCommentForm{}), repo.NewComment)
m.Combo("/comments").Post(repo.MustAllowUserComment, web.Bind(forms.CreateCommentForm{}), repo.NewComment)
m.Group("/times", func() {
m.Post("/add", bindIgnErr(forms.AddTimeManuallyForm{}), repo.AddTimeManually)
m.Post("/add", web.Bind(forms.AddTimeManuallyForm{}), repo.AddTimeManually)
m.Post("/{timeid}/delete", repo.DeleteTime)
m.Group("/stopwatch", func() {
m.Post("/toggle", repo.IssueStopwatch)
m.Post("/cancel", repo.CancelStopwatch)
})
})
m.Post("/reactions/{action}", bindIgnErr(forms.ReactionForm{}), repo.ChangeIssueReaction)
m.Post("/lock", reqRepoIssueWriter, bindIgnErr(forms.IssueLockForm{}), repo.LockIssue)
m.Post("/unlock", reqRepoIssueWriter, repo.UnlockIssue)
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeIssueReaction)
m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue)
m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue)
m.Post("/delete", reqRepoAdmin, repo.DeleteIssue)
}, context.RepoMustNotBeArchived())
m.Group("/{index}", func() {
@ -1011,7 +1008,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject)
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest)
m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(forms.DismissReviewForm{}), repo.DismissReview)
m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation)
m.Post("/attachments", repo.UploadIssueAttachment)
@ -1020,23 +1017,23 @@ func RegisterRoutes(m *web.Route) {
m.Group("/comments/{id}", func() {
m.Post("", repo.UpdateCommentContent)
m.Post("/delete", repo.DeleteComment)
m.Post("/reactions/{action}", bindIgnErr(forms.ReactionForm{}), repo.ChangeCommentReaction)
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommentReaction)
}, context.RepoMustNotBeArchived())
m.Group("/comments/{id}", func() {
m.Get("/attachments", repo.GetCommentAttachments)
})
m.Post("/markdown", bindIgnErr(structs.MarkdownOption{}), misc.Markdown)
m.Post("/markdown", web.Bind(structs.MarkdownOption{}), misc.Markdown)
m.Group("/labels", func() {
m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/new", web.Bind(forms.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", web.Bind(forms.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/delete", repo.DeleteLabel)
m.Post("/initialize", bindIgnErr(forms.InitializeLabelsForm{}), repo.InitializeLabels)
m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), repo.InitializeLabels)
}, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
m.Group("/milestones", func() {
m.Combo("/new").Get(repo.NewMilestone).
Post(bindIgnErr(forms.CreateMilestoneForm{}), repo.NewMilestonePost)
Post(web.Bind(forms.CreateMilestoneForm{}), repo.NewMilestonePost)
m.Get("/{id}/edit", repo.EditMilestone)
m.Post("/{id}/edit", bindIgnErr(forms.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Post("/{id}/edit", web.Bind(forms.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Post("/{id}/{action}", repo.ChangeMilestoneStatus)
m.Post("/delete", repo.DeleteMilestone)
}, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
@ -1047,23 +1044,23 @@ func RegisterRoutes(m *web.Route) {
m.Group("", func() {
m.Group("", func() {
m.Combo("/_edit/*").Get(repo.EditFile).
Post(bindIgnErr(forms.EditRepoFileForm{}), repo.EditFilePost)
Post(web.Bind(forms.EditRepoFileForm{}), repo.EditFilePost)
m.Combo("/_new/*").Get(repo.NewFile).
Post(bindIgnErr(forms.EditRepoFileForm{}), repo.NewFilePost)
m.Post("/_preview/*", bindIgnErr(forms.EditPreviewDiffForm{}), repo.DiffPreviewPost)
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewFilePost)
m.Post("/_preview/*", web.Bind(forms.EditPreviewDiffForm{}), repo.DiffPreviewPost)
m.Combo("/_delete/*").Get(repo.DeleteFile).
Post(bindIgnErr(forms.DeleteRepoFileForm{}), repo.DeleteFilePost)
Post(web.Bind(forms.DeleteRepoFileForm{}), repo.DeleteFilePost)
m.Combo("/_upload/*", repo.MustBeAbleToUpload).
Get(repo.UploadFile).
Post(bindIgnErr(forms.UploadRepoFileForm{}), repo.UploadFilePost)
Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost)
m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch).
Post(bindIgnErr(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick).
Post(bindIgnErr(forms.CherryPickForm{}), repo.CherryPickPost)
Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
}, repo.MustBeEditable)
m.Group("", func() {
m.Post("/upload-file", repo.UploadFileToServer)
m.Post("/upload-remove", bindIgnErr(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
}, repo.MustBeEditable, repo.MustBeAbleToUpload)
}, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived(), repo.MustBeNotEmpty)
@ -1072,7 +1069,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch)
m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch)
m.Post("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.CreateBranch)
}, bindIgnErr(forms.NewBranchForm{}))
}, web.Bind(forms.NewBranchForm{}))
m.Post("/delete", repo.DeleteBranchPost)
m.Post("/restore", repo.RestoreBranchPost)
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
@ -1090,7 +1087,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("/releases/attachments/{uuid}", repo.GetAttachment, repo.MustBeNotEmpty, reqRepoReleaseReader)
m.Group("/releases", func() {
m.Get("/new", repo.NewRelease)
m.Post("/new", bindIgnErr(forms.NewReleaseForm{}), repo.NewReleasePost)
m.Post("/new", web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost)
m.Post("/delete", repo.DeleteRelease)
m.Post("/attachments", repo.UploadReleaseAttachment)
m.Post("/attachments/remove", repo.DeleteAttachment)
@ -1099,7 +1096,7 @@ func RegisterRoutes(m *web.Route) {
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
m.Group("/releases", func() {
m.Get("/edit/*", repo.EditRelease)
m.Post("/edit/*", bindIgnErr(forms.EditReleaseForm{}), repo.EditReleasePost)
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, func(ctx *context.Context) {
var err error
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
@ -1148,17 +1145,17 @@ func RegisterRoutes(m *web.Route) {
m.Get("/{id}", repo.ViewProject)
m.Group("", func() {
m.Get("/new", repo.NewProject)
m.Post("/new", bindIgnErr(forms.CreateProjectForm{}), repo.NewProjectPost)
m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost)
m.Group("/{id}", func() {
m.Post("", bindIgnErr(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
m.Post("/delete", repo.DeleteProject)
m.Get("/edit", repo.EditProject)
m.Post("/edit", bindIgnErr(forms.CreateProjectForm{}), repo.EditProjectPost)
m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost)
m.Post("/{action:open|close}", repo.ChangeProjectStatus)
m.Group("/{boardID}", func() {
m.Put("", bindIgnErr(forms.EditProjectBoardForm{}), repo.EditProjectBoard)
m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard)
m.Delete("", repo.DeleteProjectBoard)
m.Post("/default", repo.SetDefaultProjectBoard)
@ -1174,14 +1171,14 @@ func RegisterRoutes(m *web.Route) {
Post(context.RepoMustNotBeArchived(),
reqSignIn,
reqRepoWikiWriter,
bindIgnErr(forms.NewWikiForm{}),
web.Bind(forms.NewWikiForm{}),
repo.WikiPost)
m.Combo("/*").
Get(repo.Wiki).
Post(context.RepoMustNotBeArchived(),
reqSignIn,
reqRepoWikiWriter,
bindIgnErr(forms.NewWikiForm{}),
web.Bind(forms.NewWikiForm{}),
repo.WikiPost)
m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff)
@ -1239,17 +1236,17 @@ func RegisterRoutes(m *web.Route) {
m.Get(".diff", repo.DownloadPullDiff)
m.Get(".patch", repo.DownloadPullPatch)
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
m.Post("/merge", context.RepoMustNotBeArchived(), bindIgnErr(forms.MergePullRequestForm{}), repo.MergePullRequest)
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest)
m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)
m.Post("/update", repo.UpdatePullRequest)
m.Post("/set_allow_maintainer_edit", bindIgnErr(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits)
m.Post("/set_allow_maintainer_edit", web.Bind(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)
m.Group("/reviews", func() {
m.Get("/new_comment", repo.RenderNewCodeCommentForm)
m.Post("/comments", bindIgnErr(forms.CodeCommentForm{}), repo.CreateCodeComment)
m.Post("/submit", bindIgnErr(forms.SubmitReviewForm{}), repo.SubmitReview)
m.Post("/comments", web.Bind(forms.CodeCommentForm{}), repo.CreateCodeComment)
m.Post("/submit", web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview)
}, context.RepoMustNotBeArchived())
})
}, repo.MustAllowPulls)

View File

@ -206,7 +206,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
if err != nil {
return nil, fmt.Errorf("Failed to load pull issue. Error: %w", err)
}
comment, err := issues_model.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i])
comment, err := pull_service.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i])
if err == nil && comment != nil {
notification.NotifyPullRequestPushCommits(ctx, pusher, pr, comment)
}

View File

@ -39,19 +39,14 @@ func NewAttachment(attach *repo_model.Attachment, file io.Reader) (*repo_model.A
}
// UploadAttachment upload new attachment into storage and update database
func UploadAttachment(file io.Reader, actorID, repoID, releaseID int64, fileName, allowedTypes string) (*repo_model.Attachment, error) {
func UploadAttachment(file io.Reader, allowedTypes string, opts *repo_model.Attachment) (*repo_model.Attachment, error) {
buf := make([]byte, 1024)
n, _ := util.ReadAtMost(file, buf)
buf = buf[:n]
if err := upload.Verify(buf, fileName, allowedTypes); err != nil {
if err := upload.Verify(buf, opts.Name, allowedTypes); err != nil {
return nil, err
}
return NewAttachment(&repo_model.Attachment{
RepoID: repoID,
UploaderID: actorID,
ReleaseID: releaseID,
Name: fileName,
}, io.MultiReader(bytes.NewReader(buf), file))
return NewAttachment(opts, io.MultiReader(bytes.NewReader(buf), file))
}

View File

@ -136,6 +136,7 @@ type RepoSettingForm struct {
RepoSizeLimit int64
// Advanced settings
EnableCode bool
EnableWiki bool
EnableExternalWiki bool
ExternalWikiURL string

View File

@ -1,10 +1,11 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package comments
package issue
import (
"context"
"fmt"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
@ -14,9 +15,58 @@ import (
"code.gitea.io/gitea/modules/timeutil"
)
// CreateComment creates comment of issue or commit.
func CreateComment(opts *issues_model.CreateCommentOptions) (comment *issues_model.Comment, err error) {
ctx, committer, err := db.TxContext(db.DefaultContext)
if err != nil {
return nil, err
}
defer committer.Close()
comment, err = issues_model.CreateComment(ctx, opts)
if err != nil {
return nil, err
}
if err = committer.Commit(); err != nil {
return nil, err
}
return comment, nil
}
// CreateRefComment creates a commit reference comment to issue.
func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content, commitSHA string) error {
if len(commitSHA) == 0 {
return fmt.Errorf("cannot create reference with empty commit SHA")
}
// Check if same reference from same commit has already existed.
has, err := db.GetEngine(db.DefaultContext).Get(&issues_model.Comment{
Type: issues_model.CommentTypeCommitRef,
IssueID: issue.ID,
CommitSHA: commitSHA,
})
if err != nil {
return fmt.Errorf("check reference comment: %w", err)
} else if has {
return nil
}
_, err = CreateComment(&issues_model.CreateCommentOptions{
Type: issues_model.CommentTypeCommitRef,
Doer: doer,
Repo: repo,
Issue: issue,
CommitSHA: commitSHA,
Content: content,
})
return err
}
// CreateIssueComment creates a plain issue comment.
func CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content string, attachments []string) (*issues_model.Comment, error) {
comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{
comment, err := CreateComment(&issues_model.CreateCommentOptions{
Type: issues_model.CommentTypeComment,
Doer: doer,
Repo: repo,

View File

@ -158,7 +158,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm
}
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, html.EscapeString(repo.Link()), html.EscapeString(url.PathEscape(c.Sha1)), html.EscapeString(strings.SplitN(c.Message, "\n", 2)[0]))
if err = issues_model.CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil {
if err = CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil {
return err
}

View File

@ -54,7 +54,7 @@ func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *is
OldMilestoneID: oldMilestoneID,
MilestoneID: issue.MilestoneID,
}
if _, err := issues_model.CreateCommentCtx(ctx, opts); err != nil {
if _, err := issues_model.CreateComment(ctx, opts); err != nil {
return err
}
}

View File

@ -236,7 +236,7 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool {
return false
}
if unit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests); err == nil {
if unit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
if !config.AutodetectManualMerge {
return false

162
services/pull/comment.go Normal file
View File

@ -0,0 +1,162 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package pull
import (
"context"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
issue_service "code.gitea.io/gitea/services/issue"
)
type commitBranchCheckItem struct {
Commit *git.Commit
Checked bool
}
func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]*commitBranchCheckItem) error {
if startCommit.ID.String() == endCommitID {
return nil
}
checkStack := make([]string, 0, 10)
checkStack = append(checkStack, startCommit.ID.String())
for len(checkStack) > 0 {
commitID := checkStack[0]
checkStack = checkStack[1:]
item, ok := commitList[commitID]
if !ok {
continue
}
if item.Commit.ID.String() == endCommitID {
continue
}
if err := item.Commit.LoadBranchName(); err != nil {
return err
}
if item.Commit.Branch == baseBranch {
continue
}
if item.Checked {
continue
}
item.Checked = true
parentNum := item.Commit.ParentCount()
for i := 0; i < parentNum; i++ {
parentCommit, err := item.Commit.Parent(i)
if err != nil {
return err
}
checkStack = append(checkStack, parentCommit.ID.String())
}
}
return nil
}
// getCommitIDsFromRepo get commit IDs from repo in between oldCommitID and newCommitID
// isForcePush will be true if oldCommit isn't on the branch
// Commit on baseBranch will skip
func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) {
repoPath := repo.RepoPath()
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath)
if err != nil {
return nil, false, err
}
defer closer.Close()
oldCommit, err := gitRepo.GetCommit(oldCommitID)
if err != nil {
return nil, false, err
}
if err = oldCommit.LoadBranchName(); err != nil {
return nil, false, err
}
if len(oldCommit.Branch) == 0 {
commitIDs = make([]string, 2)
commitIDs[0] = oldCommitID
commitIDs[1] = newCommitID
return commitIDs, true, err
}
newCommit, err := gitRepo.GetCommit(newCommitID)
if err != nil {
return nil, false, err
}
commits, err := newCommit.CommitsBeforeUntil(oldCommitID)
if err != nil {
return nil, false, err
}
commitIDs = make([]string, 0, len(commits))
commitChecks := make(map[string]*commitBranchCheckItem)
for _, commit := range commits {
commitChecks[commit.ID.String()] = &commitBranchCheckItem{
Commit: commit,
Checked: false,
}
}
if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil {
return
}
for i := len(commits) - 1; i >= 0; i-- {
commitID := commits[i].ID.String()
if item, ok := commitChecks[commitID]; ok && item.Checked {
commitIDs = append(commitIDs, commitID)
}
}
return commitIDs, isForcePush, err
}
// CreatePushPullComment create push code to pull base comment
func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *issues_model.PullRequest, oldCommitID, newCommitID string) (comment *issues_model.Comment, err error) {
if pr.HasMerged || oldCommitID == "" || newCommitID == "" {
return nil, nil
}
ops := &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypePullRequestPush,
Doer: pusher,
Repo: pr.BaseRepo,
}
var data issues_model.PushActionContent
data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch)
if err != nil {
return nil, err
}
ops.Issue = pr.Issue
dataJSON, err := json.Marshal(data)
if err != nil {
return nil, err
}
ops.Content = string(dataJSON)
comment, err = issue_service.CreateComment(ops)
return comment, err
}

View File

@ -54,7 +54,7 @@ func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr
return "", err
}
isExternalTracker := pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker)
isExternalTracker := pr.BaseRepo.UnitEnabled(ctx, unit.TypeExternalTracker)
issueReference := "#"
if isExternalTracker {
issueReference = "!"
@ -145,11 +145,11 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID))
// Removing an auto merge pull and ignore if not exist
if err := pull_model.DeleteScheduledAutoMerge(db.DefaultContext, pr.ID); err != nil && !db.IsErrNotExist(err) {
if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) {
return err
}
prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests)
prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests)
if err != nil {
log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err)
return err
@ -828,7 +828,7 @@ func MergedManually(pr *issues_model.PullRequest, doer *user_model.User, baseGit
defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID))
if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
prUnit, err := pr.BaseRepo.GetUnitCtx(ctx, unit.TypePullRequests)
prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests)
if err != nil {
return err
}

View File

@ -354,7 +354,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
}
// 5. Now get the pull request configuration to check if we need to ignore whitespace
prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests)
prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests)
if err != nil {
return false, err
}

View File

@ -123,7 +123,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, pull *issu
Content: string(dataJSON),
}
_, _ = issues_model.CreateComment(ops)
_, _ = issue_service.CreateComment(ops)
}
return nil
@ -222,7 +222,7 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer
OldRef: oldBranch,
NewRef: targetBranch,
}
if _, err = issues_model.CreateComment(options); err != nil {
if _, err = issue_service.CreateComment(options); err != nil {
return fmt.Errorf("CreateChangeTargetBranchComment: %w", err)
}
@ -317,7 +317,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
}
AddToTaskQueue(pr)
comment, err := issues_model.CreatePushPullComment(ctx, doer, pr, oldCommitID, newCommitID)
comment, err := CreatePushPullComment(ctx, doer, pr, oldCommitID, newCommitID)
if err == nil && comment != nil {
notification.NotifyPullRequestPushCommits(ctx, doer, pr, comment)
}

View File

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
issue_service "code.gitea.io/gitea/services/issue"
)
// CreateCodeComment creates a comment on the code line
@ -202,7 +203,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo
return nil, err
}
}
return issues_model.CreateComment(&issues_model.CreateCommentOptions{
return issue_service.CreateComment(&issues_model.CreateCommentOptions{
Type: issues_model.CommentTypeCode,
Doer: doer,
Repo: repo,
@ -322,7 +323,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
return
}
comment, err = issues_model.CreateComment(&issues_model.CreateCommentOptions{
comment, err = issue_service.CreateComment(&issues_model.CreateCommentOptions{
Doer: doer,
Content: message,
Type: issues_model.CommentTypeDismissReview,

View File

@ -106,7 +106,7 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest,
// can't do rebase on protected branch because need force push
if pr.ProtectedBranch == nil {
prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests)
prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests)
if err != nil {
log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err)
return false, false, err

View File

@ -21,6 +21,7 @@ import (
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)
func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) {
@ -218,7 +219,10 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod
}
for _, attach := range attachments {
if attach.ReleaseID != rel.ID {
return errors.New("delete attachement of release permission denied")
return util.SilentWrap{
Message: "delete attachment of release permission denied",
Err: util.ErrPermissionDenied,
}
}
deletedUUIDs.Add(attach.UUID)
}
@ -240,7 +244,10 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod
}
for _, attach := range attachments {
if attach.ReleaseID != rel.ID {
return errors.New("update attachement of release permission denied")
return util.SilentWrap{
Message: "update attachment of release permission denied",
Err: util.ErrPermissionDenied,
}
}
}

View File

@ -58,7 +58,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod
func PushCreateRepo(authUser, owner *user_model.User, repoName string) (*repo_model.Repository, error) {
if !authUser.IsAdmin {
if owner.IsOrganization() {
if ok, err := organization.CanCreateOrgRepo(owner.ID, authUser.ID); err != nil {
if ok, err := organization.CanCreateOrgRepo(db.DefaultContext, owner.ID, authUser.ID); err != nil {
return nil, err
} else if !ok {
return nil, fmt.Errorf("cannot push-create repository for org")

View File

@ -4,6 +4,7 @@
package repository
import (
"context"
"fmt"
"code.gitea.io/gitea/models"
@ -24,8 +25,8 @@ import (
var repoWorkingPool = sync.NewExclusivePool()
// TransferOwnership transfers all corresponding setting from old user to new one.
func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
if err := repo.GetOwner(db.DefaultContext); err != nil {
func TransferOwnership(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
if err := repo.GetOwner(ctx); err != nil {
return err
}
for _, team := range teams {
@ -43,18 +44,18 @@ func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Reposit
}
repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
newRepo, err := repo_model.GetRepositoryByID(db.DefaultContext, repo.ID)
newRepo, err := repo_model.GetRepositoryByID(ctx, repo.ID)
if err != nil {
return err
}
for _, team := range teams {
if err := models.AddRepository(db.DefaultContext, team, newRepo); err != nil {
if err := models.AddRepository(ctx, team, newRepo); err != nil {
return err
}
}
notification.NotifyTransferRepository(db.DefaultContext, doer, repo, oldOwner.Name)
notification.NotifyTransferRepository(ctx, doer, repo, oldOwner.Name)
return nil
}
@ -84,49 +85,49 @@ func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, ne
// StartRepositoryTransfer transfer a repo from one owner to a new one.
// it make repository into pending transfer state, if doer can not create repo for new owner.
func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
if err := models.TestRepositoryReadyForTransfer(repo.Status); err != nil {
return err
}
// Admin is always allowed to transfer || user transfer repo back to his account
if doer.IsAdmin || doer.ID == newOwner.ID {
return TransferOwnership(doer, newOwner, repo, teams)
return TransferOwnership(ctx, doer, newOwner, repo, teams)
}
// If new owner is an org and user can create repos he can transfer directly too
if newOwner.IsOrganization() {
allowed, err := organization.CanCreateOrgRepo(newOwner.ID, doer.ID)
allowed, err := organization.CanCreateOrgRepo(ctx, newOwner.ID, doer.ID)
if err != nil {
return err
}
if allowed {
return TransferOwnership(doer, newOwner, repo, teams)
return TransferOwnership(ctx, doer, newOwner, repo, teams)
}
}
// In case the new owner would not have sufficient access to the repo, give access rights for read
hasAccess, err := access_model.HasAccess(db.DefaultContext, newOwner.ID, repo)
hasAccess, err := access_model.HasAccess(ctx, newOwner.ID, repo)
if err != nil {
return err
}
if !hasAccess {
if err := repo_module.AddCollaborator(repo, newOwner); err != nil {
if err := repo_module.AddCollaborator(ctx, repo, newOwner); err != nil {
return err
}
if err := repo_model.ChangeCollaborationAccessMode(repo, newOwner.ID, perm.AccessModeRead); err != nil {
if err := repo_model.ChangeCollaborationAccessMode(ctx, repo, newOwner.ID, perm.AccessModeRead); err != nil {
return err
}
}
// Make repo as pending for transfer
repo.Status = repo_model.RepositoryPendingTransfer
if err := models.CreatePendingRepositoryTransfer(doer, newOwner, repo.ID, teams); err != nil {
if err := models.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams); err != nil {
return err
}
// notify users who are able to accept / reject transfer
notification.NotifyRepoPendingTransfer(db.DefaultContext, doer, newOwner, repo)
notification.NotifyRepoPendingTransfer(ctx, doer, newOwner, repo)
return nil
}

View File

@ -37,7 +37,7 @@ func TestTransferOwnership(t *testing.T) {
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
assert.NoError(t, TransferOwnership(doer, doer, repo, nil))
assert.NoError(t, TransferOwnership(db.DefaultContext, doer, doer, repo, nil))
transferredRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
assert.EqualValues(t, 2, transferredRepo.OwnerID)
@ -70,7 +70,7 @@ func TestStartRepositoryTransferSetPermission(t *testing.T) {
assert.NoError(t, err)
assert.False(t, hasAccess)
assert.NoError(t, StartRepositoryTransfer(doer, recipient, repo, nil))
assert.NoError(t, StartRepositoryTransfer(db.DefaultContext, doer, recipient, repo, nil))
hasAccess, err = access_model.HasAccess(db.DefaultContext, recipient.ID, repo)
assert.NoError(t, err)

View File

@ -1,5 +1,5 @@
name: gitea
summary: Gitea - A painless self-hosted Git service
summary: Gitea - A painless self-hosted Git service
description: |
The goal of this project is to make the easiest, fastest, and most painless
way of setting up a self-hosted Git service. With Go, this can be done with
@ -39,7 +39,6 @@ apps:
command: usr/bin/sqlite3
parts:
gitea:
plugin: make
source: .

View File

@ -6,12 +6,12 @@
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
<div class="menu">
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More