]> source.dussan.org Git - gitea.git/commitdiff
Move attachment into models/repo/ (#17650)
authorLunny Xiao <xiaolunwen@gmail.com>
Fri, 19 Nov 2021 13:39:57 +0000 (21:39 +0800)
committerGitHub <noreply@github.com>
Fri, 19 Nov 2021 13:39:57 +0000 (21:39 +0800)
* Move attachment into models/repo/

* Fix test

* Fix bug

41 files changed:
cmd/migrate_storage.go
integrations/attachment_test.go
models/attachment.go [deleted file]
models/attachment_test.go [deleted file]
models/error.go
models/issue.go
models/issue_assignees.go
models/issue_comment.go
models/issue_comment_list.go
models/issue_dependency.go
models/issue_label.go
models/issue_list.go
models/issue_lock.go
models/issue_milestone.go
models/issue_stopwatch.go
models/issue_tracked_time.go
models/issue_xref.go
models/issue_xref_test.go
models/notification.go
models/project_issue.go
models/pull.go
models/release.go
models/repo.go
models/repo/attachment.go [new file with mode: 0644]
models/repo/attachment_test.go [new file with mode: 0644]
models/repo/main_test.go [new file with mode: 0644]
models/repo_test.go
models/review.go
models/statistic.go
modules/convert/release.go
modules/doctor/dbconsistency.go
modules/doctor/storage.go
routers/api/v1/repo/release_attachment.go
routers/web/repo/attachment.go
routers/web/repo/issue.go
routers/web/repo/repo.go
services/attachment/attachment.go
services/attachment/attachment_test.go
services/migrations/gitea_uploader.go
services/release/release.go
services/release/release_test.go

index 1829ad00bada6e3d61c6c6878cc8a25b25ec875f..9f1d9057f9ccd72c0bc8b57b179a4ccea20403f4 100644 (file)
@@ -12,6 +12,7 @@ import (
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/migrations"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/storage"
@@ -79,7 +80,7 @@ var CmdMigrateStorage = cli.Command{
 }
 
 func migrateAttachments(dstStorage storage.ObjectStorage) error {
-       return models.IterateAttachment(func(attach *models.Attachment) error {
+       return repo_model.IterateAttachment(func(attach *repo_model.Attachment) error {
                _, err := storage.Copy(dstStorage, attach.RelativePath(), storage.Attachments, attach.RelativePath())
                return err
        })
index 052f27605a2c4a24fedb8004cb5e4a56b5bc8b64..481104d73f58fab3e5b533940e070e1a987b8fc3 100644 (file)
@@ -14,7 +14,7 @@ import (
        "strings"
        "testing"
 
-       "code.gitea.io/gitea/models"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/storage"
        "code.gitea.io/gitea/modules/test"
 
@@ -122,7 +122,7 @@ func TestGetAttachment(t *testing.T) {
                t.Run(tc.name, func(t *testing.T) {
                        //Write empty file to be available for response
                        if tc.createFile {
-                               _, err := storage.Attachments.Save(models.AttachmentRelativePath(tc.uuid), strings.NewReader("hello world"), -1)
+                               _, err := storage.Attachments.Save(repo_model.AttachmentRelativePath(tc.uuid), strings.NewReader("hello world"), -1)
                                assert.NoError(t, err)
                        }
                        //Actual test
diff --git a/models/attachment.go b/models/attachment.go
deleted file mode 100644 (file)
index 34edc67..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package models
-
-import (
-       "context"
-       "fmt"
-       "net/url"
-       "path"
-
-       "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/storage"
-       "code.gitea.io/gitea/modules/timeutil"
-
-       "xorm.io/xorm"
-)
-
-// Attachment represent a attachment of issue/comment/release.
-type Attachment struct {
-       ID            int64  `xorm:"pk autoincr"`
-       UUID          string `xorm:"uuid UNIQUE"`
-       RepoID        int64  `xorm:"INDEX"`           // this should not be zero
-       IssueID       int64  `xorm:"INDEX"`           // maybe zero when creating
-       ReleaseID     int64  `xorm:"INDEX"`           // maybe zero when creating
-       UploaderID    int64  `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added
-       CommentID     int64
-       Name          string
-       DownloadCount int64              `xorm:"DEFAULT 0"`
-       Size          int64              `xorm:"DEFAULT 0"`
-       CreatedUnix   timeutil.TimeStamp `xorm:"created"`
-}
-
-func init() {
-       db.RegisterModel(new(Attachment))
-}
-
-// IncreaseDownloadCount is update download count + 1
-func (a *Attachment) IncreaseDownloadCount() error {
-       // Update download count.
-       if _, err := db.GetEngine(db.DefaultContext).Exec("UPDATE `attachment` SET download_count=download_count+1 WHERE id=?", a.ID); err != nil {
-               return fmt.Errorf("increase attachment count: %v", err)
-       }
-
-       return nil
-}
-
-// AttachmentRelativePath returns the relative path
-func AttachmentRelativePath(uuid string) string {
-       return path.Join(uuid[0:1], uuid[1:2], uuid)
-}
-
-// RelativePath returns the relative path of the attachment
-func (a *Attachment) RelativePath() string {
-       return AttachmentRelativePath(a.UUID)
-}
-
-// DownloadURL returns the download url of the attached file
-func (a *Attachment) DownloadURL() string {
-       return setting.AppURL + "attachments/" + url.PathEscape(a.UUID)
-}
-
-// LinkedRepository returns the linked repo if any
-func (a *Attachment) LinkedRepository() (*Repository, unit.Type, error) {
-       if a.IssueID != 0 {
-               iss, err := GetIssueByID(a.IssueID)
-               if err != nil {
-                       return nil, unit.TypeIssues, err
-               }
-               repo, err := GetRepositoryByID(iss.RepoID)
-               unitType := unit.TypeIssues
-               if iss.IsPull {
-                       unitType = unit.TypePullRequests
-               }
-               return repo, unitType, err
-       } else if a.ReleaseID != 0 {
-               rel, err := GetReleaseByID(a.ReleaseID)
-               if err != nil {
-                       return nil, unit.TypeReleases, err
-               }
-               repo, err := GetRepositoryByID(rel.RepoID)
-               return repo, unit.TypeReleases, err
-       }
-       return nil, -1, nil
-}
-
-// GetAttachmentByID returns attachment by given id
-func GetAttachmentByID(id int64) (*Attachment, error) {
-       return getAttachmentByID(db.GetEngine(db.DefaultContext), id)
-}
-
-func getAttachmentByID(e db.Engine, id int64) (*Attachment, error) {
-       attach := &Attachment{}
-       if has, err := e.ID(id).Get(attach); err != nil {
-               return nil, err
-       } else if !has {
-               return nil, ErrAttachmentNotExist{ID: id, UUID: ""}
-       }
-       return attach, nil
-}
-
-func getAttachmentByUUID(e db.Engine, uuid string) (*Attachment, error) {
-       attach := &Attachment{}
-       has, err := e.Where("uuid=?", uuid).Get(attach)
-       if err != nil {
-               return nil, err
-       } else if !has {
-               return nil, ErrAttachmentNotExist{0, uuid}
-       }
-       return attach, nil
-}
-
-// GetAttachmentsByUUIDs returns attachment by given UUID list.
-func GetAttachmentsByUUIDs(ctx context.Context, uuids []string) ([]*Attachment, error) {
-       return getAttachmentsByUUIDs(db.GetEngine(ctx), uuids)
-}
-
-func getAttachmentsByUUIDs(e db.Engine, uuids []string) ([]*Attachment, error) {
-       if len(uuids) == 0 {
-               return []*Attachment{}, nil
-       }
-
-       // Silently drop invalid uuids.
-       attachments := make([]*Attachment, 0, len(uuids))
-       return attachments, e.In("uuid", uuids).Find(&attachments)
-}
-
-// GetAttachmentByUUID returns attachment by given UUID.
-func GetAttachmentByUUID(uuid string) (*Attachment, error) {
-       return getAttachmentByUUID(db.GetEngine(db.DefaultContext), uuid)
-}
-
-// ExistAttachmentsByUUID returns true if attachment is exist by given UUID
-func ExistAttachmentsByUUID(uuid string) (bool, error) {
-       return db.GetEngine(db.DefaultContext).Where("`uuid`=?", uuid).Exist(new(Attachment))
-}
-
-// GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName.
-func GetAttachmentByReleaseIDFileName(releaseID int64, fileName string) (*Attachment, error) {
-       return getAttachmentByReleaseIDFileName(db.GetEngine(db.DefaultContext), releaseID, fileName)
-}
-
-func getAttachmentsByIssueID(e db.Engine, issueID int64) ([]*Attachment, error) {
-       attachments := make([]*Attachment, 0, 10)
-       return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
-}
-
-// GetAttachmentsByIssueID returns all attachments of an issue.
-func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
-       return getAttachmentsByIssueID(db.GetEngine(db.DefaultContext), issueID)
-}
-
-// GetAttachmentsByCommentID returns all attachments if comment by given ID.
-func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
-       return getAttachmentsByCommentID(db.GetEngine(db.DefaultContext), commentID)
-}
-
-func getAttachmentsByCommentID(e db.Engine, commentID int64) ([]*Attachment, error) {
-       attachments := make([]*Attachment, 0, 10)
-       return attachments, e.Where("comment_id=?", commentID).Find(&attachments)
-}
-
-// getAttachmentByReleaseIDFileName return a file based on the the following infos:
-func getAttachmentByReleaseIDFileName(e db.Engine, releaseID int64, fileName string) (*Attachment, error) {
-       attach := &Attachment{ReleaseID: releaseID, Name: fileName}
-       has, err := e.Get(attach)
-       if err != nil {
-               return nil, err
-       } else if !has {
-               return nil, err
-       }
-       return attach, nil
-}
-
-// DeleteAttachment deletes the given attachment and optionally the associated file.
-func DeleteAttachment(a *Attachment, remove bool) error {
-       _, err := DeleteAttachments(db.DefaultContext, []*Attachment{a}, remove)
-       return err
-}
-
-// DeleteAttachments deletes the given attachments and optionally the associated files.
-func DeleteAttachments(ctx context.Context, attachments []*Attachment, remove bool) (int, error) {
-       if len(attachments) == 0 {
-               return 0, nil
-       }
-
-       ids := make([]int64, 0, len(attachments))
-       for _, a := range attachments {
-               ids = append(ids, a.ID)
-       }
-
-       cnt, err := db.GetEngine(ctx).In("id", ids).NoAutoCondition().Delete(attachments[0])
-       if err != nil {
-               return 0, err
-       }
-
-       if remove {
-               for i, a := range attachments {
-                       if err := storage.Attachments.Delete(a.RelativePath()); err != nil {
-                               return i, err
-                       }
-               }
-       }
-       return int(cnt), nil
-}
-
-// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
-func DeleteAttachmentsByIssue(issueID int64, remove bool) (int, error) {
-       attachments, err := GetAttachmentsByIssueID(issueID)
-       if err != nil {
-               return 0, err
-       }
-
-       return DeleteAttachments(db.DefaultContext, attachments, remove)
-}
-
-// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
-func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) {
-       attachments, err := GetAttachmentsByCommentID(commentID)
-       if err != nil {
-               return 0, err
-       }
-
-       return DeleteAttachments(db.DefaultContext, attachments, remove)
-}
-
-// UpdateAttachment updates the given attachment in database
-func UpdateAttachment(atta *Attachment) error {
-       return updateAttachment(db.GetEngine(db.DefaultContext), atta)
-}
-
-// UpdateAttachmentByUUID Updates attachment via uuid
-func UpdateAttachmentByUUID(ctx context.Context, attach *Attachment, cols ...string) error {
-       if attach.UUID == "" {
-               return fmt.Errorf("attachment uuid should be not blank")
-       }
-       _, err := db.GetEngine(ctx).Where("uuid=?", attach.UUID).Cols(cols...).Update(attach)
-       return err
-}
-
-func updateAttachment(e db.Engine, atta *Attachment) error {
-       var sess *xorm.Session
-       if atta.ID != 0 && atta.UUID == "" {
-               sess = e.ID(atta.ID)
-       } else {
-               // Use uuid only if id is not set and uuid is set
-               sess = e.Where("uuid = ?", atta.UUID)
-       }
-       _, err := sess.Cols("name", "issue_id", "release_id", "comment_id", "download_count").Update(atta)
-       return err
-}
-
-// DeleteAttachmentsByRelease deletes all attachments associated with the given release.
-func DeleteAttachmentsByRelease(releaseID int64) error {
-       _, err := db.GetEngine(db.DefaultContext).Where("release_id = ?", releaseID).Delete(&Attachment{})
-       return err
-}
-
-// IterateAttachment iterates attachments; it should not be used when Gitea is servicing users.
-func IterateAttachment(f func(attach *Attachment) error) error {
-       var start int
-       const batchSize = 100
-       for {
-               attachments := make([]*Attachment, 0, batchSize)
-               if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&attachments); err != nil {
-                       return err
-               }
-               if len(attachments) == 0 {
-                       return nil
-               }
-               start += len(attachments)
-
-               for _, attach := range attachments {
-                       if err := f(attach); err != nil {
-                               return err
-                       }
-               }
-       }
-}
-
-// CountOrphanedAttachments returns the number of bad attachments
-func CountOrphanedAttachments() (int64, error) {
-       return db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
-               Count(new(Attachment))
-}
-
-// DeleteOrphanedAttachments delete all bad attachments
-func DeleteOrphanedAttachments() error {
-       _, err := db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
-               Delete(new(Attachment))
-       return err
-}
diff --git a/models/attachment_test.go b/models/attachment_test.go
deleted file mode 100644 (file)
index 4081811..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package models
-
-import (
-       "testing"
-
-       "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/models/unittest"
-
-       "github.com/stretchr/testify/assert"
-)
-
-func TestIncreaseDownloadCount(t *testing.T) {
-       assert.NoError(t, unittest.PrepareTestDatabase())
-
-       attachment, err := GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
-       assert.NoError(t, err)
-       assert.Equal(t, int64(0), attachment.DownloadCount)
-
-       // increase download count
-       err = attachment.IncreaseDownloadCount()
-       assert.NoError(t, err)
-
-       attachment, err = GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
-       assert.NoError(t, err)
-       assert.Equal(t, int64(1), attachment.DownloadCount)
-}
-
-func TestGetByCommentOrIssueID(t *testing.T) {
-       assert.NoError(t, unittest.PrepareTestDatabase())
-
-       // count of attachments from issue ID
-       attachments, err := GetAttachmentsByIssueID(1)
-       assert.NoError(t, err)
-       assert.Len(t, attachments, 1)
-
-       attachments, err = GetAttachmentsByCommentID(1)
-       assert.NoError(t, err)
-       assert.Len(t, attachments, 2)
-}
-
-func TestDeleteAttachments(t *testing.T) {
-       assert.NoError(t, unittest.PrepareTestDatabase())
-
-       count, err := DeleteAttachmentsByIssue(4, false)
-       assert.NoError(t, err)
-       assert.Equal(t, 2, count)
-
-       count, err = DeleteAttachmentsByComment(2, false)
-       assert.NoError(t, err)
-       assert.Equal(t, 2, count)
-
-       err = DeleteAttachment(&Attachment{ID: 8}, false)
-       assert.NoError(t, err)
-
-       attachment, err := GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18")
-       assert.Error(t, err)
-       assert.True(t, IsErrAttachmentNotExist(err))
-       assert.Nil(t, attachment)
-}
-
-func TestGetAttachmentByID(t *testing.T) {
-       assert.NoError(t, unittest.PrepareTestDatabase())
-
-       attach, err := GetAttachmentByID(1)
-       assert.NoError(t, err)
-       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID)
-}
-
-func TestAttachment_DownloadURL(t *testing.T) {
-       attach := &Attachment{
-               UUID: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
-               ID:   1,
-       }
-       assert.Equal(t, "https://try.gitea.io/attachments/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.DownloadURL())
-}
-
-func TestUpdateAttachment(t *testing.T) {
-       assert.NoError(t, unittest.PrepareTestDatabase())
-
-       attach, err := GetAttachmentByID(1)
-       assert.NoError(t, err)
-       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID)
-
-       attach.Name = "new_name"
-       assert.NoError(t, UpdateAttachment(attach))
-
-       unittest.AssertExistsAndLoadBean(t, &Attachment{Name: "new_name"})
-}
-
-func TestGetAttachmentsByUUIDs(t *testing.T) {
-       assert.NoError(t, unittest.PrepareTestDatabase())
-
-       attachList, err := GetAttachmentsByUUIDs(db.DefaultContext, []string{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", "not-existing-uuid"})
-       assert.NoError(t, err)
-       assert.Len(t, attachList, 2)
-       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attachList[0].UUID)
-       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", attachList[1].UUID)
-       assert.Equal(t, int64(1), attachList[0].IssueID)
-       assert.Equal(t, int64(5), attachList[1].IssueID)
-}
-
-func TestLinkedRepository(t *testing.T) {
-       assert.NoError(t, unittest.PrepareTestDatabase())
-       testCases := []struct {
-               name             string
-               attachID         int64
-               expectedRepo     *Repository
-               expectedUnitType unit.Type
-       }{
-               {"LinkedIssue", 1, &Repository{ID: 1}, unit.TypeIssues},
-               {"LinkedComment", 3, &Repository{ID: 1}, unit.TypePullRequests},
-               {"LinkedRelease", 9, &Repository{ID: 1}, unit.TypeReleases},
-               {"Notlinked", 10, nil, -1},
-       }
-       for _, tc := range testCases {
-               t.Run(tc.name, func(t *testing.T) {
-                       attach, err := GetAttachmentByID(tc.attachID)
-                       assert.NoError(t, err)
-                       repo, unitType, err := attach.LinkedRepository()
-                       assert.NoError(t, err)
-                       if tc.expectedRepo != nil {
-                               assert.Equal(t, tc.expectedRepo.ID, repo.ID)
-                       }
-                       assert.Equal(t, tc.expectedUnitType, unitType)
-               })
-       }
-}
index 7d9b2ae65bc7eabb6f6c29a80cb2a49936cfd258..862b5633ecd9a7e60735dbf479c655dadd97f341 100644 (file)
@@ -1679,29 +1679,6 @@ func (err ErrMilestoneNotExist) Error() string {
        return fmt.Sprintf("milestone does not exist [id: %d, repo_id: %d]", err.ID, err.RepoID)
 }
 
-//    _____   __    __                .__                           __
-//   /  _  \_/  |__/  |______    ____ |  |__   _____   ____   _____/  |_
-//  /  /_\  \   __\   __\__  \ _/ ___\|  |  \ /     \_/ __ \ /    \   __\
-// /    |    \  |  |  |  / __ \\  \___|   Y  \  Y Y  \  ___/|   |  \  |
-// \____|__  /__|  |__| (____  /\___  >___|  /__|_|  /\___  >___|  /__|
-//         \/                \/     \/     \/      \/     \/     \/
-
-// ErrAttachmentNotExist represents a "AttachmentNotExist" kind of error.
-type ErrAttachmentNotExist struct {
-       ID   int64
-       UUID string
-}
-
-// IsErrAttachmentNotExist checks if an error is a ErrAttachmentNotExist.
-func IsErrAttachmentNotExist(err error) bool {
-       _, ok := err.(ErrAttachmentNotExist)
-       return ok
-}
-
-func (err ErrAttachmentNotExist) Error() string {
-       return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
-}
-
 // ___________
 // \__    ___/___ _____    _____
 //   |    |_/ __ \\__  \  /     \
@@ -1758,7 +1735,7 @@ type ErrUploadNotExist struct {
 
 // IsErrUploadNotExist checks if an error is a ErrUploadNotExist.
 func IsErrUploadNotExist(err error) bool {
-       _, ok := err.(ErrAttachmentNotExist)
+       _, ok := err.(ErrUploadNotExist)
        return ok
 }
 
index ef31f416ad3ada8523c11635889279a19e72b397..1b9d35d1e3c8f2fbeb26825f9fe74cb5cf91d6af 100644 (file)
@@ -15,6 +15,7 @@ import (
 
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/issues"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/log"
@@ -60,11 +61,11 @@ type Issue struct {
        UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
        ClosedUnix  timeutil.TimeStamp `xorm:"INDEX"`
 
-       Attachments      []*Attachment `xorm:"-"`
-       Comments         []*Comment    `xorm:"-"`
-       Reactions        ReactionList  `xorm:"-"`
-       TotalTrackedTime int64         `xorm:"-"`
-       Assignees        []*User       `xorm:"-"`
+       Attachments      []*repo_model.Attachment `xorm:"-"`
+       Comments         []*Comment               `xorm:"-"`
+       Reactions        ReactionList             `xorm:"-"`
+       TotalTrackedTime int64                    `xorm:"-"`
+       Assignees        []*User                  `xorm:"-"`
 
        // IsLocked limits commenting abilities to users on an issue
        // with write access
@@ -273,7 +274,8 @@ func (issue *Issue) loadMilestone(e db.Engine) (err error) {
        return nil
 }
 
-func (issue *Issue) loadAttributes(e db.Engine) (err error) {
+func (issue *Issue) loadAttributes(ctx context.Context) (err error) {
+       e := db.GetEngine(ctx)
        if err = issue.loadRepo(e); err != nil {
                return
        }
@@ -304,7 +306,7 @@ func (issue *Issue) loadAttributes(e db.Engine) (err error) {
        }
 
        if issue.Attachments == nil {
-               issue.Attachments, err = getAttachmentsByIssueID(e, issue.ID)
+               issue.Attachments, err = repo_model.GetAttachmentsByIssueIDCtx(ctx, issue.ID)
                if err != nil {
                        return fmt.Errorf("getAttachmentsByIssueID [%d]: %v", issue.ID, err)
                }
@@ -328,7 +330,7 @@ func (issue *Issue) loadAttributes(e db.Engine) (err error) {
 
 // LoadAttributes loads the attribute of this issue.
 func (issue *Issue) LoadAttributes() error {
-       return issue.loadAttributes(db.GetEngine(db.DefaultContext))
+       return issue.loadAttributes(db.DefaultContext)
 }
 
 // LoadMilestone load milestone of this issue.
@@ -426,12 +428,12 @@ func (issue *Issue) HasLabel(labelID int64) bool {
        return issue.hasLabel(db.GetEngine(db.DefaultContext), labelID)
 }
 
-func (issue *Issue) addLabel(e db.Engine, label *Label, doer *User) error {
-       return newIssueLabel(e, issue, label, doer)
+func (issue *Issue) addLabel(ctx context.Context, label *Label, doer *User) error {
+       return newIssueLabel(ctx, issue, label, doer)
 }
 
-func (issue *Issue) addLabels(e db.Engine, labels []*Label, doer *User) error {
-       return newIssueLabels(e, issue, labels, doer)
+func (issue *Issue) addLabels(ctx context.Context, labels []*Label, doer *User) error {
+       return newIssueLabels(ctx, issue, labels, doer)
 }
 
 func (issue *Issue) getLabels(e db.Engine) (err error) {
@@ -446,17 +448,17 @@ func (issue *Issue) getLabels(e db.Engine) (err error) {
        return nil
 }
 
-func (issue *Issue) removeLabel(e db.Engine, doer *User, label *Label) error {
-       return deleteIssueLabel(e, issue, label, doer)
+func (issue *Issue) removeLabel(ctx context.Context, doer *User, label *Label) error {
+       return deleteIssueLabel(ctx, issue, label, doer)
 }
 
-func (issue *Issue) clearLabels(e db.Engine, doer *User) (err error) {
-       if err = issue.getLabels(e); err != nil {
+func (issue *Issue) clearLabels(ctx context.Context, doer *User) (err error) {
+       if err = issue.getLabels(db.GetEngine(ctx)); err != nil {
                return fmt.Errorf("getLabels: %v", err)
        }
 
        for i := range issue.Labels {
-               if err = issue.removeLabel(e, doer, issue.Labels[i]); err != nil {
+               if err = issue.removeLabel(ctx, doer, issue.Labels[i]); err != nil {
                        return fmt.Errorf("removeLabel: %v", err)
                }
        }
@@ -487,7 +489,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
                return ErrRepoLabelNotExist{}
        }
 
-       if err = issue.clearLabels(db.GetEngine(ctx), doer); err != nil {
+       if err = issue.clearLabels(ctx, doer); err != nil {
                return err
        }
 
@@ -561,13 +563,13 @@ func (issue *Issue) ReplaceLabels(labels []*Label, doer *User) (err error) {
        toRemove = append(toRemove, issue.Labels[removeIndex:]...)
 
        if len(toAdd) > 0 {
-               if err = issue.addLabels(db.GetEngine(ctx), toAdd, doer); err != nil {
+               if err = issue.addLabels(ctx, toAdd, doer); err != nil {
                        return fmt.Errorf("addLabels: %v", err)
                }
        }
 
        for _, l := range toRemove {
-               if err = issue.removeLabel(db.GetEngine(ctx), doer, l); err != nil {
+               if err = issue.removeLabel(ctx, doer, l); err != nil {
                        return fmt.Errorf("removeLabel: %v", err)
                }
        }
@@ -596,9 +598,9 @@ func updateIssueCols(e db.Engine, issue *Issue, cols ...string) error {
        return nil
 }
 
-func (issue *Issue) changeStatus(e db.Engine, doer *User, isClosed, isMergePull bool) (*Comment, error) {
+func (issue *Issue) changeStatus(ctx context.Context, doer *User, isClosed, isMergePull bool) (*Comment, error) {
        // Reload the issue
-       currentIssue, err := getIssueByID(e, issue.ID)
+       currentIssue, err := getIssueByID(db.GetEngine(ctx), issue.ID)
        if err != nil {
                return nil, err
        }
@@ -616,10 +618,11 @@ func (issue *Issue) changeStatus(e db.Engine, doer *User, isClosed, isMergePull
        }
 
        issue.IsClosed = isClosed
-       return issue.doChangeStatus(e, doer, isMergePull)
+       return issue.doChangeStatus(ctx, doer, isMergePull)
 }
 
-func (issue *Issue) doChangeStatus(e db.Engine, doer *User, isMergePull bool) (*Comment, error) {
+func (issue *Issue) doChangeStatus(ctx context.Context, doer *User, isMergePull bool) (*Comment, error) {
+       e := db.GetEngine(ctx)
        // Check for open dependencies
        if issue.IsClosed && issue.Repo.isDependenciesEnabled(e) {
                // 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
@@ -672,7 +675,7 @@ func (issue *Issue) doChangeStatus(e db.Engine, doer *User, isMergePull bool) (*
                cmtType = CommentTypeMergePull
        }
 
-       return createComment(e, &CreateCommentOptions{
+       return createComment(ctx, &CreateCommentOptions{
                Type:  cmtType,
                Doer:  doer,
                Repo:  issue.Repo,
@@ -695,7 +698,7 @@ func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (*Comment, error) {
                return nil, err
        }
 
-       comment, err := issue.changeStatus(db.GetEngine(ctx), doer, isClosed, false)
+       comment, err := issue.changeStatus(ctx, doer, isClosed, false)
        if err != nil {
                return nil, err
        }
@@ -731,10 +734,10 @@ func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) {
                OldTitle: oldTitle,
                NewTitle: issue.Title,
        }
-       if _, err = createComment(db.GetEngine(ctx), opts); err != nil {
+       if _, err = createComment(ctx, opts); err != nil {
                return fmt.Errorf("createComment: %v", err)
        }
-       if err = issue.addCrossReferences(db.GetEngine(ctx), doer, true); err != nil {
+       if err = issue.addCrossReferences(ctx, doer, true); err != nil {
                return err
        }
 
@@ -767,7 +770,7 @@ func (issue *Issue) ChangeRef(doer *User, oldRef string) (err error) {
                OldRef: oldRefFriendly,
                NewRef: newRefFriendly,
        }
-       if _, err = createComment(db.GetEngine(ctx), opts); err != nil {
+       if _, err = createComment(ctx, opts); err != nil {
                return fmt.Errorf("createComment: %v", err)
        }
 
@@ -792,7 +795,7 @@ func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branc
                Issue:  issue,
                OldRef: branchName,
        }
-       if _, err = createComment(db.GetEngine(ctx), opts); err != nil {
+       if _, err = createComment(ctx, opts); err != nil {
                return err
        }
 
@@ -806,13 +809,13 @@ func (issue *Issue) UpdateAttachments(uuids []string) (err error) {
                return err
        }
        defer committer.Close()
-       attachments, err := getAttachmentsByUUIDs(db.GetEngine(ctx), uuids)
+       attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids)
        if err != nil {
                return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %v", uuids, err)
        }
        for i := 0; i < len(attachments); i++ {
                attachments[i].IssueID = issue.ID
-               if err := updateAttachment(db.GetEngine(ctx), attachments[i]); err != nil {
+               if err := repo_model.UpdateAttachmentCtx(ctx, attachments[i]); err != nil {
                        return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err)
                }
        }
@@ -838,7 +841,7 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
                return fmt.Errorf("SaveIssueContentHistory: %v", err)
        }
 
-       if err = issue.addCrossReferences(ctx.Engine(), doer, true); err != nil {
+       if err = issue.addCrossReferences(ctx, doer, true); err != nil {
                return fmt.Errorf("addCrossReferences: %v", err)
        }
 
@@ -908,7 +911,8 @@ type NewIssueOptions struct {
        IsPull      bool
 }
 
-func newIssue(e db.Engine, doer *User, opts NewIssueOptions) (err error) {
+func newIssue(ctx context.Context, doer *User, opts NewIssueOptions) (err error) {
+       e := db.GetEngine(ctx)
        opts.Issue.Title = strings.TrimSpace(opts.Issue.Title)
 
        if opts.Issue.MilestoneID > 0 {
@@ -949,7 +953,7 @@ func newIssue(e db.Engine, doer *User, opts NewIssueOptions) (err error) {
                        OldMilestoneID: 0,
                        MilestoneID:    opts.Issue.MilestoneID,
                }
-               if _, err = createComment(e, opts); err != nil {
+               if _, err = createComment(ctx, opts); err != nil {
                        return err
                }
        }
@@ -981,7 +985,7 @@ func newIssue(e db.Engine, doer *User, opts NewIssueOptions) (err error) {
                                continue
                        }
 
-                       if err = opts.Issue.addLabel(e, label, opts.Issue.Poster); err != nil {
+                       if err = opts.Issue.addLabel(ctx, label, opts.Issue.Poster); err != nil {
                                return fmt.Errorf("addLabel [id: %d]: %v", label.ID, err)
                        }
                }
@@ -992,7 +996,7 @@ func newIssue(e db.Engine, doer *User, opts NewIssueOptions) (err error) {
        }
 
        if len(opts.Attachments) > 0 {
-               attachments, err := getAttachmentsByUUIDs(e, opts.Attachments)
+               attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, opts.Attachments)
                if err != nil {
                        return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %v", opts.Attachments, err)
                }
@@ -1004,7 +1008,7 @@ func newIssue(e db.Engine, doer *User, opts NewIssueOptions) (err error) {
                        }
                }
        }
-       if err = opts.Issue.loadAttributes(e); err != nil {
+       if err = opts.Issue.loadAttributes(ctx); err != nil {
                return err
        }
 
@@ -1013,7 +1017,7 @@ func newIssue(e db.Engine, doer *User, opts NewIssueOptions) (err error) {
                return err
        }
 
-       return opts.Issue.addCrossReferences(e, doer, false)
+       return opts.Issue.addCrossReferences(ctx, doer, false)
 }
 
 // RecalculateIssueIndexForRepo create issue_index for repo if not exist and
@@ -1056,7 +1060,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
        }
        defer committer.Close()
 
-       if err = newIssue(db.GetEngine(ctx), issue.Poster, NewIssueOptions{
+       if err = newIssue(ctx, issue.Poster, NewIssueOptions{
                Repo:        repo,
                Issue:       issue,
                LabelIDs:    labelIDs,
@@ -1119,7 +1123,7 @@ func GetIssueWithAttrsByID(id int64) (*Issue, error) {
        if err != nil {
                return nil, err
        }
-       return issue, issue.loadAttributes(db.GetEngine(db.DefaultContext))
+       return issue, issue.loadAttributes(db.DefaultContext)
 }
 
 // GetIssueByID returns an issue by given ID.
@@ -1838,11 +1842,12 @@ func SearchIssueIDsByKeyword(kw string, repoIDs []int64, limit, start int) (int6
 // If the issue status is changed a statusChangeComment is returned
 // similarly if the title is changed the titleChanged bool is set to true
 func UpdateIssueByAPI(issue *Issue, doer *User) (statusChangeComment *Comment, titleChanged bool, err error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, false, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        if err := issue.loadRepo(sess); err != nil {
                return nil, false, fmt.Errorf("loadRepo: %v", err)
@@ -1871,23 +1876,23 @@ func UpdateIssueByAPI(issue *Issue, doer *User) (statusChangeComment *Comment, t
                        OldTitle: currentIssue.Title,
                        NewTitle: issue.Title,
                }
-               _, err := createComment(sess, opts)
+               _, err := createComment(ctx, opts)
                if err != nil {
                        return nil, false, fmt.Errorf("createComment: %v", err)
                }
        }
 
        if currentIssue.IsClosed != issue.IsClosed {
-               statusChangeComment, err = issue.doChangeStatus(sess, doer, false)
+               statusChangeComment, err = issue.doChangeStatus(ctx, doer, false)
                if err != nil {
                        return nil, false, err
                }
        }
 
-       if err := issue.addCrossReferences(sess, doer, true); err != nil {
+       if err := issue.addCrossReferences(ctx, doer, true); err != nil {
                return nil, false, err
        }
-       return statusChangeComment, titleChanged, sess.Commit()
+       return statusChangeComment, titleChanged, committer.Commit()
 }
 
 // UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it.
@@ -1897,11 +1902,12 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *Us
                return nil
        }
 
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        // Update the deadline
        if err = updateIssueCols(sess, &Issue{ID: issue.ID, DeadlineUnix: deadlineUnix}, "deadline_unix"); err != nil {
@@ -1909,11 +1915,11 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *Us
        }
 
        // Make the comment
-       if _, err = createDeadlineComment(sess, doer, issue, deadlineUnix); err != nil {
+       if _, err = createDeadlineComment(ctx, doer, issue, deadlineUnix); err != nil {
                return fmt.Errorf("createRemovedDueDateComment: %v", err)
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
 
 // DependencyInfo represents high level information about an issue which is a dependency of another issue.
@@ -2244,7 +2250,7 @@ func deleteIssuesByRepoID(sess db.Engine, repoID int64) (attachmentPaths []strin
                return
        }
 
-       var attachments []*Attachment
+       var attachments []*repo_model.Attachment
        if err = sess.In("issue_id", deleteCond).
                Find(&attachments); err != nil {
                return
@@ -2255,7 +2261,7 @@ func deleteIssuesByRepoID(sess db.Engine, repoID int64) (attachmentPaths []strin
        }
 
        if _, err = sess.In("issue_id", deleteCond).
-               Delete(&Attachment{}); err != nil {
+               Delete(&repo_model.Attachment{}); err != nil {
                return
        }
 
index 0f7ba2d7022cf988adacb958e225fdd304a095c3..996a3a8563eef984e0b2183d9ed168a0179a6158 100644 (file)
@@ -5,12 +5,11 @@
 package models
 
 import (
+       "context"
        "fmt"
 
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/util"
-
-       "xorm.io/xorm"
 )
 
 // IssueAssignees saves all issue assignees
@@ -94,26 +93,26 @@ func clearAssigneeByUserID(sess db.Engine, userID int64) (err error) {
 
 // ToggleAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it.
 func (issue *Issue) ToggleAssignee(doer *User, assigneeID int64) (removed bool, comment *Comment, err error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return false, nil, err
        }
+       defer committer.Close()
 
-       removed, comment, err = issue.toggleAssignee(sess, doer, assigneeID, false)
+       removed, comment, err = issue.toggleAssignee(ctx, doer, assigneeID, false)
        if err != nil {
                return false, nil, err
        }
 
-       if err := sess.Commit(); err != nil {
+       if err := committer.Commit(); err != nil {
                return false, nil, err
        }
 
        return removed, comment, nil
 }
 
-func (issue *Issue) toggleAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (removed bool, comment *Comment, err error) {
+func (issue *Issue) toggleAssignee(ctx context.Context, doer *User, assigneeID int64, isCreate bool) (removed bool, comment *Comment, err error) {
+       sess := db.GetEngine(ctx)
        removed, err = toggleUserAssignee(sess, issue, assigneeID)
        if err != nil {
                return false, nil, fmt.Errorf("UpdateIssueUserByAssignee: %v", err)
@@ -133,7 +132,7 @@ func (issue *Issue) toggleAssignee(sess *xorm.Session, doer *User, assigneeID in
                AssigneeID:      assigneeID,
        }
        // Comment
-       comment, err = createComment(sess, opts)
+       comment, err = createComment(ctx, opts)
        if err != nil {
                return false, nil, fmt.Errorf("createComment: %v", err)
        }
@@ -147,7 +146,7 @@ func (issue *Issue) toggleAssignee(sess *xorm.Session, doer *User, assigneeID in
 }
 
 // toggles user assignee state in database
-func toggleUserAssignee(e *xorm.Session, issue *Issue, assigneeID int64) (removed bool, err error) {
+func toggleUserAssignee(e db.Engine, issue *Issue, assigneeID int64) (removed bool, err error) {
        // Check if the user exists
        assignee, err := getUserByID(e, assigneeID)
        if err != nil {
index 1936695732158f378524bb21751bbd72f8e3507e..fccc139cd01575d8ac8459c8285a2411c3c4171b 100644 (file)
@@ -7,6 +7,7 @@
 package models
 
 import (
+       "context"
        "fmt"
        "regexp"
        "strconv"
@@ -15,6 +16,7 @@ import (
 
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/issues"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
@@ -198,8 +200,8 @@ type Comment struct {
        // Reference issue in commit message
        CommitSHA string `xorm:"VARCHAR(40)"`
 
-       Attachments []*Attachment `xorm:"-"`
-       Reactions   ReactionList  `xorm:"-"`
+       Attachments []*repo_model.Attachment `xorm:"-"`
+       Reactions   ReactionList             `xorm:"-"`
 
        // For view issue page.
        ShowRole RoleDescriptor `xorm:"-"`
@@ -300,7 +302,7 @@ func (c *Comment) AfterDelete() {
                return
        }
 
-       _, err := DeleteAttachmentsByComment(c.ID, true)
+       _, err := repo_model.DeleteAttachmentsByComment(c.ID, true)
        if err != nil {
                log.Info("Could not delete files for comment %d on issue #%d: %s", c.ID, c.IssueID, err)
        }
@@ -483,7 +485,7 @@ func (c *Comment) LoadAttachments() error {
        }
 
        var err error
-       c.Attachments, err = getAttachmentsByCommentID(db.GetEngine(db.DefaultContext), c.ID)
+       c.Attachments, err = repo_model.GetAttachmentsByCommentIDCtx(db.DefaultContext, c.ID)
        if err != nil {
                log.Error("getAttachmentsByCommentID[%d]: %v", c.ID, err)
        }
@@ -492,23 +494,24 @@ func (c *Comment) LoadAttachments() error {
 
 // UpdateAttachments update attachments by UUIDs for the comment
 func (c *Comment) UpdateAttachments(uuids []string) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
-       attachments, err := getAttachmentsByUUIDs(sess, uuids)
+       defer committer.Close()
+
+       attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids)
        if err != nil {
                return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %v", uuids, err)
        }
        for i := 0; i < len(attachments); i++ {
                attachments[i].IssueID = c.IssueID
                attachments[i].CommentID = c.ID
-               if err := updateAttachment(sess, attachments[i]); err != nil {
+               if err := repo_model.UpdateAttachmentCtx(ctx, attachments[i]); err != nil {
                        return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err)
                }
        }
-       return sess.Commit()
+       return committer.Commit()
 }
 
 // LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees
@@ -715,7 +718,8 @@ func (c *Comment) LoadPushCommits() (err error) {
        return err
 }
 
-func createComment(e db.Engine, opts *CreateCommentOptions) (_ *Comment, err error) {
+func createComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) {
+       e := db.GetEngine(ctx)
        var LabelID int64
        if opts.Label != nil {
                LabelID = opts.Label.ID
@@ -763,18 +767,19 @@ func createComment(e db.Engine, opts *CreateCommentOptions) (_ *Comment, err err
                return nil, err
        }
 
-       if err = updateCommentInfos(e, opts, comment); err != nil {
+       if err = updateCommentInfos(ctx, opts, comment); err != nil {
                return nil, err
        }
 
-       if err = comment.addCrossReferences(e, opts.Doer, false); err != nil {
+       if err = comment.addCrossReferences(ctx, opts.Doer, false); err != nil {
                return nil, err
        }
 
        return comment, nil
 }
 
-func updateCommentInfos(e db.Engine, opts *CreateCommentOptions, comment *Comment) (err error) {
+func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment *Comment) (err error) {
+       e := db.GetEngine(ctx)
        // Check comment type.
        switch opts.Type {
        case CommentTypeCode:
@@ -797,7 +802,7 @@ func updateCommentInfos(e db.Engine, opts *CreateCommentOptions, comment *Commen
                }
 
                // Check attachments
-               attachments, err := getAttachmentsByUUIDs(e, opts.Attachments)
+               attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, opts.Attachments)
                if err != nil {
                        return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %v", opts.Attachments, err)
                }
@@ -819,7 +824,7 @@ func updateCommentInfos(e db.Engine, opts *CreateCommentOptions, comment *Commen
        return updateIssueCols(e, opts.Issue, "updated_unix")
 }
 
-func createDeadlineComment(e *xorm.Session, doer *User, issue *Issue, newDeadlineUnix timeutil.TimeStamp) (*Comment, error) {
+func createDeadlineComment(ctx context.Context, doer *User, issue *Issue, newDeadlineUnix timeutil.TimeStamp) (*Comment, error) {
        var content string
        var commentType CommentType
 
@@ -837,7 +842,7 @@ func createDeadlineComment(e *xorm.Session, doer *User, issue *Issue, newDeadlin
                content = newDeadlineUnix.Format("2006-01-02") + "|" + issue.DeadlineUnix.Format("2006-01-02")
        }
 
-       if err := issue.loadRepo(e); err != nil {
+       if err := issue.loadRepo(db.GetEngine(ctx)); err != nil {
                return nil, err
        }
 
@@ -848,7 +853,7 @@ func createDeadlineComment(e *xorm.Session, doer *User, issue *Issue, newDeadlin
                Issue:   issue,
                Content: content,
        }
-       comment, err := createComment(e, opts)
+       comment, err := createComment(ctx, opts)
        if err != nil {
                return nil, err
        }
@@ -856,12 +861,12 @@ func createDeadlineComment(e *xorm.Session, doer *User, issue *Issue, newDeadlin
 }
 
 // Creates issue dependency comment
-func createIssueDependencyComment(e *xorm.Session, doer *User, issue, dependentIssue *Issue, add bool) (err error) {
+func createIssueDependencyComment(ctx context.Context, doer *User, issue, dependentIssue *Issue, add bool) (err error) {
        cType := CommentTypeAddDependency
        if !add {
                cType = CommentTypeRemoveDependency
        }
-       if err = issue.loadRepo(e); err != nil {
+       if err = issue.loadRepo(db.GetEngine(ctx)); err != nil {
                return
        }
 
@@ -873,7 +878,7 @@ func createIssueDependencyComment(e *xorm.Session, doer *User, issue, dependentI
                Issue:            issue,
                DependentIssueID: dependentIssue.ID,
        }
-       if _, err = createComment(e, opts); err != nil {
+       if _, err = createComment(ctx, opts); err != nil {
                return
        }
 
@@ -884,7 +889,7 @@ func createIssueDependencyComment(e *xorm.Session, doer *User, issue, dependentI
                Issue:            dependentIssue,
                DependentIssueID: issue.ID,
        }
-       _, err = createComment(e, opts)
+       _, err = createComment(ctx, opts)
        return
 }
 
@@ -928,18 +933,18 @@ type CreateCommentOptions struct {
 
 // CreateComment creates comment of issue or commit.
 func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err = sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, err
        }
+       defer committer.Close()
 
-       comment, err = createComment(sess, opts)
+       comment, err = createComment(ctx, opts)
        if err != nil {
                return nil, err
        }
 
-       if err = sess.Commit(); err != nil {
+       if err = committer.Commit(); err != nil {
                return nil, err
        }
 
@@ -1068,11 +1073,12 @@ func CountComments(opts *FindCommentsOptions) (int64, error) {
 
 // UpdateComment updates information of comment.
 func UpdateComment(c *Comment, doer *User) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        if _, err := sess.ID(c.ID).AllCols().Update(c); err != nil {
                return err
@@ -1080,10 +1086,10 @@ func UpdateComment(c *Comment, doer *User) error {
        if err := c.loadIssue(sess); err != nil {
                return err
        }
-       if err := c.addCrossReferences(sess, doer, true); err != nil {
+       if err := c.addCrossReferences(ctx, doer, true); err != nil {
                return err
        }
-       if err := sess.Commit(); err != nil {
+       if err := committer.Commit(); err != nil {
                return fmt.Errorf("Commit: %v", err)
        }
 
index bd1b48f8e5bf044723fe230f2cd037224e8603d2..3c587fc8f71914016e026249a3a443e8e7bf425e 100644 (file)
@@ -4,7 +4,10 @@
 
 package models
 
-import "code.gitea.io/gitea/models/db"
+import (
+       "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
+)
 
 // CommentList defines a list of comments
 type CommentList []*Comment
@@ -393,7 +396,7 @@ func (comments CommentList) loadAttachments(e db.Engine) (err error) {
                return nil
        }
 
-       attachments := make(map[int64][]*Attachment, len(comments))
+       attachments := make(map[int64][]*repo_model.Attachment, len(comments))
        commentsIDs := comments.getCommentIDs()
        left := len(commentsIDs)
        for left > 0 {
@@ -404,13 +407,13 @@ func (comments CommentList) loadAttachments(e db.Engine) (err error) {
                rows, err := e.Table("attachment").
                        Join("INNER", "comment", "comment.id = attachment.comment_id").
                        In("comment.id", commentsIDs[:limit]).
-                       Rows(new(Attachment))
+                       Rows(new(repo_model.Attachment))
                if err != nil {
                        return err
                }
 
                for rows.Next() {
-                       var attachment Attachment
+                       var attachment repo_model.Attachment
                        err = rows.Scan(&attachment)
                        if err != nil {
                                _ = rows.Close()
index f58bb3da0a61f84842a8ae743bbc1a8d80646b69..ee984fbe3eee797ea4cc4c36053f5d679921661a 100644 (file)
@@ -37,11 +37,12 @@ const (
 
 // CreateIssueDependency creates a new dependency for an issue
 func CreateIssueDependency(user *User, issue, dep *Issue) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        // Check if it aleready exists
        exists, err := issueDepExists(sess, issue.ID, dep.ID)
@@ -69,20 +70,20 @@ func CreateIssueDependency(user *User, issue, dep *Issue) error {
        }
 
        // Add comment referencing the new dependency
-       if err = createIssueDependencyComment(sess, user, issue, dep, true); err != nil {
+       if err = createIssueDependencyComment(ctx, user, issue, dep, true); err != nil {
                return err
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
 
 // RemoveIssueDependency removes a dependency from an issue
 func RemoveIssueDependency(user *User, issue, dep *Issue, depType DependencyType) (err error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err = sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
 
        var issueDepToDelete IssueDependency
 
@@ -95,7 +96,7 @@ func RemoveIssueDependency(user *User, issue, dep *Issue, depType DependencyType
                return ErrUnknownDependencyType{depType}
        }
 
-       affected, err := sess.Delete(&issueDepToDelete)
+       affected, err := db.GetEngine(ctx).Delete(&issueDepToDelete)
        if err != nil {
                return err
        }
@@ -106,10 +107,10 @@ func RemoveIssueDependency(user *User, issue, dep *Issue, depType DependencyType
        }
 
        // Add comment referencing the removed dependency
-       if err = createIssueDependencyComment(sess, user, issue, dep, false); err != nil {
+       if err = createIssueDependencyComment(ctx, user, issue, dep, false); err != nil {
                return err
        }
-       return sess.Commit()
+       return committer.Commit()
 }
 
 // Check if the dependency already exists
index 293b7140f777353994b73f5185d1c7afb3d029c6..492e2986007cdccc5cf022f370803ccda04c117e 100644 (file)
@@ -663,7 +663,8 @@ func HasIssueLabel(issueID, labelID int64) bool {
 
 // newIssueLabel this function creates a new label it does not check if the label is valid for the issue
 // YOU MUST CHECK THIS BEFORE THIS FUNCTION
-func newIssueLabel(e db.Engine, issue *Issue, label *Label, doer *User) (err error) {
+func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *User) (err error) {
+       e := db.GetEngine(ctx)
        if _, err = e.Insert(&IssueLabel{
                IssueID: issue.ID,
                LabelID: label.ID,
@@ -683,7 +684,7 @@ func newIssueLabel(e db.Engine, issue *Issue, label *Label, doer *User) (err err
                Label:   label,
                Content: "1",
        }
-       if _, err = createComment(e, opts); err != nil {
+       if _, err = createComment(ctx, opts); err != nil {
                return err
        }
 
@@ -696,11 +697,12 @@ func NewIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
                return nil
        }
 
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err = sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        if err = issue.loadRepo(sess); err != nil {
                return err
@@ -711,7 +713,7 @@ func NewIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
                return nil
        }
 
-       if err = newIssueLabel(sess, issue, label, doer); err != nil {
+       if err = newIssueLabel(ctx, issue, label, doer); err != nil {
                return err
        }
 
@@ -720,11 +722,12 @@ func NewIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
                return err
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
 
 // newIssueLabels add labels to an issue. It will check if the labels are valid for the issue
-func newIssueLabels(e db.Engine, issue *Issue, labels []*Label, doer *User) (err error) {
+func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *User) (err error) {
+       e := db.GetEngine(ctx)
        if err = issue.loadRepo(e); err != nil {
                return err
        }
@@ -735,7 +738,7 @@ func newIssueLabels(e db.Engine, issue *Issue, labels []*Label, doer *User) (err
                        continue
                }
 
-               if err = newIssueLabel(e, issue, label, doer); err != nil {
+               if err = newIssueLabel(ctx, issue, label, doer); err != nil {
                        return fmt.Errorf("newIssueLabel: %v", err)
                }
        }
@@ -751,7 +754,7 @@ func NewIssueLabels(issue *Issue, labels []*Label, doer *User) (err error) {
        }
        defer committer.Close()
 
-       if err = newIssueLabels(db.GetEngine(ctx), issue, labels, doer); err != nil {
+       if err = newIssueLabels(ctx, issue, labels, doer); err != nil {
                return err
        }
 
@@ -763,7 +766,8 @@ func NewIssueLabels(issue *Issue, labels []*Label, doer *User) (err error) {
        return committer.Commit()
 }
 
-func deleteIssueLabel(e db.Engine, issue *Issue, label *Label, doer *User) (err error) {
+func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *User) (err error) {
+       e := db.GetEngine(ctx)
        if count, err := e.Delete(&IssueLabel{
                IssueID: issue.ID,
                LabelID: label.ID,
@@ -784,7 +788,7 @@ func deleteIssueLabel(e db.Engine, issue *Issue, label *Label, doer *User) (err
                Issue: issue,
                Label: label,
        }
-       if _, err = createComment(e, opts); err != nil {
+       if _, err = createComment(ctx, opts); err != nil {
                return err
        }
 
@@ -793,22 +797,22 @@ func deleteIssueLabel(e db.Engine, issue *Issue, label *Label, doer *User) (err
 
 // DeleteIssueLabel deletes issue-label relation.
 func DeleteIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err = sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
 
-       if err = deleteIssueLabel(sess, issue, label, doer); err != nil {
+       if err = deleteIssueLabel(ctx, issue, label, doer); err != nil {
                return err
        }
 
        issue.Labels = nil
-       if err = issue.loadLabels(sess); err != nil {
+       if err = issue.loadLabels(db.GetEngine(ctx)); err != nil {
                return err
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
 
 func deleteLabelsByRepoID(sess db.Engine, repoID int64) error {
index 04dcc5842211fb714d95011672e26c3719f9d455..6eeb2a961a56e982ef2d1cebeffc189d1a22274a 100644 (file)
@@ -8,6 +8,7 @@ import (
        "fmt"
 
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
 
        "xorm.io/builder"
 )
@@ -322,7 +323,7 @@ func (issues IssueList) loadAttachments(e db.Engine) (err error) {
                return nil
        }
 
-       attachments := make(map[int64][]*Attachment, len(issues))
+       attachments := make(map[int64][]*repo_model.Attachment, len(issues))
        issuesIDs := issues.getIssueIDs()
        left := len(issuesIDs)
        for left > 0 {
@@ -333,13 +334,13 @@ func (issues IssueList) loadAttachments(e db.Engine) (err error) {
                rows, err := e.Table("attachment").
                        Join("INNER", "issue", "issue.id = attachment.issue_id").
                        In("issue.id", issuesIDs[:limit]).
-                       Rows(new(Attachment))
+                       Rows(new(repo_model.Attachment))
                if err != nil {
                        return err
                }
 
                for rows.Next() {
-                       var attachment Attachment
+                       var attachment repo_model.Attachment
                        err = rows.Scan(&attachment)
                        if err != nil {
                                if err1 := rows.Close(); err1 != nil {
index d8e3b4c0aba82c35555b6e7985bac296713501e0..d0b9c660c210da4fc12eb8968c8c59c8cab54368 100644 (file)
@@ -37,13 +37,13 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error {
                commentType = CommentTypeUnlock
        }
 
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
 
-       if err := updateIssueCols(sess, opts.Issue, "is_locked"); err != nil {
+       if err := updateIssueCols(db.GetEngine(ctx), opts.Issue, "is_locked"); err != nil {
                return err
        }
 
@@ -54,9 +54,9 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error {
                Type:    commentType,
                Content: opts.Reason,
        }
-       if _, err := createComment(sess, opt); err != nil {
+       if _, err := createComment(ctx, opt); err != nil {
                return err
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
index 3898e5b3978566d518f4d720e183fc2f2202ff82..fd5d052cbd3169d5a65950ad20ca4711ba853bc6 100644 (file)
@@ -5,6 +5,7 @@
 package models
 
 import (
+       "context"
        "fmt"
        "strings"
        "time"
@@ -15,7 +16,6 @@ import (
        "code.gitea.io/gitea/modules/timeutil"
 
        "xorm.io/builder"
-       "xorm.io/xorm"
 )
 
 // Milestone represents a milestone of repository.
@@ -263,7 +263,8 @@ func changeMilestoneStatus(e db.Engine, m *Milestone, isClosed bool) error {
        return updateRepoMilestoneNum(e, m.RepoID)
 }
 
-func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilestoneID int64) error {
+func changeMilestoneAssign(ctx context.Context, doer *User, issue *Issue, oldMilestoneID int64) error {
+       e := db.GetEngine(ctx)
        if err := updateIssueCols(e, issue, "milestone_id"); err != nil {
                return err
        }
@@ -293,7 +294,7 @@ func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilesto
                        OldMilestoneID: oldMilestoneID,
                        MilestoneID:    issue.MilestoneID,
                }
-               if _, err := createComment(e, opts); err != nil {
+               if _, err := createComment(ctx, opts); err != nil {
                        return err
                }
        }
@@ -303,17 +304,17 @@ func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilesto
 
 // ChangeMilestoneAssign changes assignment of milestone for issue.
 func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err = sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
 
-       if err = changeMilestoneAssign(sess, doer, issue, oldMilestoneID); err != nil {
+       if err = changeMilestoneAssign(ctx, doer, issue, oldMilestoneID); err != nil {
                return err
        }
 
-       if err = sess.Commit(); err != nil {
+       if err = committer.Commit(); err != nil {
                return fmt.Errorf("Commit: %v", err)
        }
        return nil
index e8f19dd738c4e4a284e3ef2ddb4fb8bcb4da7f8a..e9c38b9165be60c2804bcf1ada254ba774ea83c6 100644 (file)
@@ -5,13 +5,12 @@
 package models
 
 import (
+       "context"
        "fmt"
        "time"
 
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/timeutil"
-
-       "xorm.io/xorm"
 )
 
 // Stopwatch represents a stopwatch for time tracking.
@@ -86,18 +85,19 @@ func hasUserStopwatch(e db.Engine, userID int64) (exists bool, sw *Stopwatch, er
 
 // CreateOrStopIssueStopwatch will create or remove a stopwatch and will log it into issue's timeline.
 func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
-       if err := createOrStopIssueStopwatch(sess, user, issue); err != nil {
+       defer committer.Close()
+       if err := createOrStopIssueStopwatch(ctx, user, issue); err != nil {
                return err
        }
-       return sess.Commit()
+       return committer.Commit()
 }
 
-func createOrStopIssueStopwatch(e *xorm.Session, user *User, issue *Issue) error {
+func createOrStopIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
+       e := db.GetEngine(ctx)
        sw, exists, err := getStopwatch(e, user.ID, issue.ID)
        if err != nil {
                return err
@@ -122,7 +122,7 @@ func createOrStopIssueStopwatch(e *xorm.Session, user *User, issue *Issue) error
                        return err
                }
 
-               if _, err := createComment(e, &CreateCommentOptions{
+               if _, err := createComment(ctx, &CreateCommentOptions{
                        Doer:    user,
                        Issue:   issue,
                        Repo:    issue.Repo,
@@ -146,7 +146,7 @@ func createOrStopIssueStopwatch(e *xorm.Session, user *User, issue *Issue) error
                        if err != nil {
                                return err
                        }
-                       if err := createOrStopIssueStopwatch(e, user, issue); err != nil {
+                       if err := createOrStopIssueStopwatch(ctx, user, issue); err != nil {
                                return err
                        }
                }
@@ -157,11 +157,11 @@ func createOrStopIssueStopwatch(e *xorm.Session, user *User, issue *Issue) error
                        IssueID: issue.ID,
                }
 
-               if _, err := e.Insert(sw); err != nil {
+               if err := db.Insert(ctx, sw); err != nil {
                        return err
                }
 
-               if _, err := createComment(e, &CreateCommentOptions{
+               if _, err := createComment(ctx, &CreateCommentOptions{
                        Doer:  user,
                        Issue: issue,
                        Repo:  issue.Repo,
@@ -175,18 +175,19 @@ func createOrStopIssueStopwatch(e *xorm.Session, user *User, issue *Issue) error
 
 // CancelStopwatch removes the given stopwatch and logs it into issue's timeline.
 func CancelStopwatch(user *User, issue *Issue) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
-       if err := cancelStopwatch(sess, user, issue); err != nil {
+       defer committer.Close()
+       if err := cancelStopwatch(ctx, user, issue); err != nil {
                return err
        }
-       return sess.Commit()
+       return committer.Commit()
 }
 
-func cancelStopwatch(e *xorm.Session, user *User, issue *Issue) error {
+func cancelStopwatch(ctx context.Context, user *User, issue *Issue) error {
+       e := db.GetEngine(ctx)
        sw, exists, err := getStopwatch(e, user.ID, issue.ID)
        if err != nil {
                return err
@@ -201,7 +202,7 @@ func cancelStopwatch(e *xorm.Session, user *User, issue *Issue) error {
                        return err
                }
 
-               if _, err := createComment(e, &CreateCommentOptions{
+               if _, err := createComment(ctx, &CreateCommentOptions{
                        Doer:  user,
                        Issue: issue,
                        Repo:  issue.Repo,
index 79de8910194a5dbb0cc6390c6ba991ac52ca376c..55d585a55ccf4378fde686d5349d2cc8a1faa458 100644 (file)
@@ -154,12 +154,12 @@ func GetTrackedSeconds(opts FindTrackedTimesOptions) (int64, error) {
 
 // AddTime will add the given time (in seconds) to the issue
 func AddTime(user *User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        t, err := addTime(sess, user, issue, amount, created)
        if err != nil {
@@ -170,7 +170,7 @@ func AddTime(user *User, issue *Issue, amount int64, created time.Time) (*Tracke
                return nil, err
        }
 
-       if _, err := createComment(sess, &CreateCommentOptions{
+       if _, err := createComment(ctx, &CreateCommentOptions{
                Issue:   issue,
                Repo:    issue.Repo,
                Doer:    user,
@@ -181,7 +181,7 @@ func AddTime(user *User, issue *Issue, amount int64, created time.Time) (*Tracke
                return nil, err
        }
 
-       return t, sess.Commit()
+       return t, committer.Commit()
 }
 
 func addTime(e db.Engine, user *User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
@@ -230,12 +230,12 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*User]string, error) {
 
 // DeleteIssueUserTimes deletes times for issue
 func DeleteIssueUserTimes(issue *Issue, user *User) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        opts := FindTrackedTimesOptions{
                IssueID: issue.ID,
@@ -253,7 +253,7 @@ func DeleteIssueUserTimes(issue *Issue, user *User) error {
        if err := issue.loadRepo(sess); err != nil {
                return err
        }
-       if _, err := createComment(sess, &CreateCommentOptions{
+       if _, err := createComment(ctx, &CreateCommentOptions{
                Issue:   issue,
                Repo:    issue.Repo,
                Doer:    user,
@@ -263,17 +263,17 @@ func DeleteIssueUserTimes(issue *Issue, user *User) error {
                return err
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
 
 // DeleteTime delete a specific Time
 func DeleteTime(t *TrackedTime) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        if err := t.loadAttributes(sess); err != nil {
                return err
@@ -283,7 +283,7 @@ func DeleteTime(t *TrackedTime) error {
                return err
        }
 
-       if _, err := createComment(sess, &CreateCommentOptions{
+       if _, err := createComment(ctx, &CreateCommentOptions{
                Issue:   t.Issue,
                Repo:    t.Issue.Repo,
                Doer:    t.User,
@@ -293,7 +293,7 @@ func DeleteTime(t *TrackedTime) error {
                return err
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
 
 func deleteTimes(e db.Engine, opts FindTrackedTimesOptions) (removedTime int64, err error) {
index 4630f4d3a483847785898bf729a04470fec52db7..55483ce57bd0b1b5525ddadda2e6263fea64c36d 100644 (file)
@@ -5,6 +5,7 @@
 package models
 
 import (
+       "context"
        "fmt"
 
        "code.gitea.io/gitea/models/db"
@@ -59,7 +60,7 @@ func neuterCrossReferencesIds(e db.Engine, ids []int64) error {
 //          \/     \/            \/
 //
 
-func (issue *Issue) addCrossReferences(e db.Engine, doer *User, removeOld bool) error {
+func (issue *Issue) addCrossReferences(stdCtx context.Context, doer *User, removeOld bool) error {
        var commentType CommentType
        if issue.IsPull {
                commentType = CommentTypePullRef
@@ -72,10 +73,11 @@ func (issue *Issue) addCrossReferences(e db.Engine, doer *User, removeOld bool)
                OrigIssue: issue,
                RemoveOld: removeOld,
        }
-       return issue.createCrossReferences(e, ctx, issue.Title, issue.Content)
+       return issue.createCrossReferences(stdCtx, ctx, issue.Title, issue.Content)
 }
 
-func (issue *Issue) createCrossReferences(e db.Engine, ctx *crossReferencesContext, plaincontent, mdcontent string) error {
+func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossReferencesContext, plaincontent, mdcontent string) error {
+       e := db.GetEngine(stdCtx)
        xreflist, err := ctx.OrigIssue.getCrossReferences(e, ctx, plaincontent, mdcontent)
        if err != nil {
                return err
@@ -125,7 +127,7 @@ func (issue *Issue) createCrossReferences(e db.Engine, ctx *crossReferencesConte
                        RefAction:    xref.Action,
                        RefIsPull:    ctx.OrigIssue.IsPull,
                }
-               _, err := createComment(e, opts)
+               _, err := createComment(stdCtx, opts)
                if err != nil {
                        return err
                }
@@ -240,11 +242,11 @@ func (issue *Issue) verifyReferencedIssue(e db.Engine, ctx *crossReferencesConte
 //         \/             \/      \/     \/     \/
 //
 
-func (comment *Comment) addCrossReferences(e db.Engine, doer *User, removeOld bool) error {
+func (comment *Comment) addCrossReferences(stdCtx context.Context, doer *User, removeOld bool) error {
        if comment.Type != CommentTypeCode && comment.Type != CommentTypeComment {
                return nil
        }
-       if err := comment.loadIssue(e); err != nil {
+       if err := comment.loadIssue(db.GetEngine(stdCtx)); err != nil {
                return err
        }
        ctx := &crossReferencesContext{
@@ -254,7 +256,7 @@ func (comment *Comment) addCrossReferences(e db.Engine, doer *User, removeOld bo
                OrigComment: comment,
                RemoveOld:   removeOld,
        }
-       return comment.Issue.createCrossReferences(e, ctx, "", comment.Content)
+       return comment.Issue.createCrossReferences(stdCtx, ctx, "", comment.Content)
 }
 
 func (comment *Comment) neuterCrossReferences(e db.Engine) error {
index 551c29dcba47bb44996a2bd0ec95896af6eed628..c40e545fa89c9300662042e59f3628616425b08d 100644 (file)
@@ -140,19 +140,18 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu
                Index:    idx,
        }
 
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-
-       assert.NoError(t, sess.Begin())
-       err = newIssue(sess, d, NewIssueOptions{
+       ctx, committer, err := db.TxContext()
+       assert.NoError(t, err)
+       defer committer.Close()
+       err = newIssue(ctx, d, NewIssueOptions{
                Repo:  r,
                Issue: i,
        })
        assert.NoError(t, err)
-       i, err = getIssueByID(sess, i.ID)
+       i, err = getIssueByID(db.GetEngine(ctx), i.ID)
        assert.NoError(t, err)
-       assert.NoError(t, i.addCrossReferences(sess, d, false))
-       assert.NoError(t, sess.Commit())
+       assert.NoError(t, i.addCrossReferences(ctx, d, false))
+       assert.NoError(t, committer.Commit())
        return i
 }
 
@@ -171,12 +170,12 @@ func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *C
        i := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issue}).(*Issue)
        c := &Comment{Type: CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
 
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       assert.NoError(t, sess.Begin())
-       _, err := sess.Insert(c)
+       ctx, committer, err := db.TxContext()
+       assert.NoError(t, err)
+       defer committer.Close()
+       err = db.Insert(ctx, c)
        assert.NoError(t, err)
-       assert.NoError(t, c.addCrossReferences(sess, d, false))
-       assert.NoError(t, sess.Commit())
+       assert.NoError(t, c.addCrossReferences(ctx, d, false))
+       assert.NoError(t, committer.Commit())
        return c
 }
index 1e180736183a38025c4e1aaf10b6546e9b668340..3c252d123d3ecd0e16418b9062564fc5546c5b96 100644 (file)
@@ -5,6 +5,7 @@
 package models
 
 import (
+       "context"
        "fmt"
        "net/url"
        "strconv"
@@ -391,14 +392,15 @@ func countUnread(e db.Engine, userID int64) int64 {
 
 // LoadAttributes load Repo Issue User and Comment if not loaded
 func (n *Notification) LoadAttributes() (err error) {
-       return n.loadAttributes(db.GetEngine(db.DefaultContext))
+       return n.loadAttributes(db.DefaultContext)
 }
 
-func (n *Notification) loadAttributes(e db.Engine) (err error) {
+func (n *Notification) loadAttributes(ctx context.Context) (err error) {
+       e := db.GetEngine(ctx)
        if err = n.loadRepo(e); err != nil {
                return
        }
-       if err = n.loadIssue(e); err != nil {
+       if err = n.loadIssue(ctx); err != nil {
                return
        }
        if err = n.loadUser(e); err != nil {
@@ -420,13 +422,13 @@ func (n *Notification) loadRepo(e db.Engine) (err error) {
        return nil
 }
 
-func (n *Notification) loadIssue(e db.Engine) (err error) {
+func (n *Notification) loadIssue(ctx context.Context) (err error) {
        if n.Issue == nil && n.IssueID != 0 {
-               n.Issue, err = getIssueByID(e, n.IssueID)
+               n.Issue, err = getIssueByID(db.GetEngine(ctx), n.IssueID)
                if err != nil {
                        return fmt.Errorf("getIssueByID [%d]: %v", n.IssueID, err)
                }
-               return n.Issue.loadAttributes(e)
+               return n.Issue.loadAttributes(ctx)
        }
        return nil
 }
@@ -464,7 +466,7 @@ func (n *Notification) GetRepo() (*Repository, error) {
 
 // GetIssue returns the issue of the notification
 func (n *Notification) GetIssue() (*Issue, error) {
-       return n.Issue, n.loadIssue(db.GetEngine(db.DefaultContext))
+       return n.Issue, n.loadIssue(db.DefaultContext)
 }
 
 // HTMLURL formats a URL-string to the notification
index 4e3bc0039d2441b187c83beba0b472c9444b1d1b..75e74295b57e661a5c90ccafa3c25b2e6d9c028b 100644 (file)
@@ -5,11 +5,10 @@
 package models
 
 import (
+       "context"
        "fmt"
 
        "code.gitea.io/gitea/models/db"
-
-       "xorm.io/xorm"
 )
 
 // ProjectIssue saves relation from issue to a project
@@ -132,20 +131,21 @@ func (p *Project) NumOpenIssues() int {
 
 // ChangeProjectAssign changes the project associated with an issue
 func ChangeProjectAssign(issue *Issue, doer *User, newProjectID int64) error {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
 
-       if err := addUpdateIssueProject(sess, issue, doer, newProjectID); err != nil {
+       if err := addUpdateIssueProject(ctx, issue, doer, newProjectID); err != nil {
                return err
        }
 
-       return sess.Commit()
+       return committer.Commit()
 }
 
-func addUpdateIssueProject(e *xorm.Session, issue *Issue, doer *User, newProjectID int64) error {
+func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *User, newProjectID int64) error {
+       e := db.GetEngine(ctx)
        oldProjectID := issue.projectID(e)
 
        if _, err := e.Where("project_issue.issue_id=?", issue.ID).Delete(&ProjectIssue{}); err != nil {
@@ -157,7 +157,7 @@ func addUpdateIssueProject(e *xorm.Session, issue *Issue, doer *User, newProject
        }
 
        if oldProjectID > 0 || newProjectID > 0 {
-               if _, err := createComment(e, &CreateCommentOptions{
+               if _, err := createComment(ctx, &CreateCommentOptions{
                        Type:         CommentTypeProject,
                        Doer:         doer,
                        Repo:         issue.Repo,
index 6bcc30e901a6079d73d448b024e16580043ce3d7..3bfebee1185a1774e522ea992551131e124da3b9 100644 (file)
@@ -394,11 +394,12 @@ func (pr *PullRequest) SetMerged() (bool, error) {
 
        pr.HasMerged = true
 
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return false, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        if _, err := sess.Exec("UPDATE `issue` SET `repo_id` = `repo_id` WHERE `id` = ?", pr.IssueID); err != nil {
                return false, err
@@ -432,7 +433,7 @@ func (pr *PullRequest) SetMerged() (bool, error) {
                return false, err
        }
 
-       if _, err := pr.Issue.changeStatus(sess, pr.Merger, true, true); err != nil {
+       if _, err := pr.Issue.changeStatus(ctx, pr.Merger, true, true); err != nil {
                return false, fmt.Errorf("Issue.changeStatus: %v", err)
        }
 
@@ -441,7 +442,7 @@ func (pr *PullRequest) SetMerged() (bool, error) {
                return false, fmt.Errorf("Failed to update pr[%d]: %v", pr.ID, err)
        }
 
-       if err := sess.Commit(); err != nil {
+       if err := committer.Commit(); err != nil {
                return false, fmt.Errorf("Commit: %v", err)
        }
        return true, nil
@@ -456,13 +457,13 @@ func NewPullRequest(repo *Repository, issue *Issue, labelIDs []int64, uuids []st
 
        issue.Index = idx
 
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err = sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return err
        }
+       defer committer.Close()
 
-       if err = newIssue(sess, issue.Poster, NewIssueOptions{
+       if err = newIssue(ctx, issue.Poster, NewIssueOptions{
                Repo:        repo,
                Issue:       issue,
                LabelIDs:    labelIDs,
@@ -478,11 +479,11 @@ func NewPullRequest(repo *Repository, issue *Issue, labelIDs []int64, uuids []st
        pr.Index = issue.Index
        pr.BaseRepo = repo
        pr.IssueID = issue.ID
-       if _, err = sess.Insert(pr); err != nil {
+       if err = db.Insert(ctx, pr); err != nil {
                return fmt.Errorf("insert pull repo: %v", err)
        }
 
-       if err = sess.Commit(); err != nil {
+       if err = committer.Commit(); err != nil {
                return fmt.Errorf("Commit: %v", err)
        }
 
index f7bd67b8ca7221c0a4f88a529b18decca3675d48..69d2ceda5e183dcfa37a4a600ac3c89c2bd5027b 100644 (file)
@@ -14,6 +14,7 @@ import (
        "strings"
 
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/timeutil"
        "code.gitea.io/gitea/modules/util"
@@ -36,14 +37,14 @@ type Release struct {
        Title            string
        Sha1             string `xorm:"VARCHAR(40)"`
        NumCommits       int64
-       NumCommitsBehind int64              `xorm:"-"`
-       Note             string             `xorm:"TEXT"`
-       RenderedNote     string             `xorm:"-"`
-       IsDraft          bool               `xorm:"NOT NULL DEFAULT false"`
-       IsPrerelease     bool               `xorm:"NOT NULL DEFAULT false"`
-       IsTag            bool               `xorm:"NOT NULL DEFAULT false"`
-       Attachments      []*Attachment      `xorm:"-"`
-       CreatedUnix      timeutil.TimeStamp `xorm:"INDEX"`
+       NumCommitsBehind int64                    `xorm:"-"`
+       Note             string                   `xorm:"TEXT"`
+       RenderedNote     string                   `xorm:"-"`
+       IsDraft          bool                     `xorm:"NOT NULL DEFAULT false"`
+       IsPrerelease     bool                     `xorm:"NOT NULL DEFAULT false"`
+       IsTag            bool                     `xorm:"NOT NULL DEFAULT false"`
+       Attachments      []*repo_model.Attachment `xorm:"-"`
+       CreatedUnix      timeutil.TimeStamp       `xorm:"INDEX"`
 }
 
 func init() {
@@ -126,7 +127,7 @@ func UpdateRelease(ctx context.Context, rel *Release) error {
 // AddReleaseAttachments adds a release attachments
 func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs []string) (err error) {
        // Check attachments
-       attachments, err := getAttachmentsByUUIDs(db.GetEngine(ctx), attachmentUUIDs)
+       attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, attachmentUUIDs)
        if err != nil {
                return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %v", attachmentUUIDs, err)
        }
@@ -295,9 +296,9 @@ func getReleaseAttachments(e db.Engine, rels ...*Release) (err error) {
 
        // Sort
        sortedRels := releaseMetaSearch{ID: make([]int64, len(rels)), Rel: make([]*Release, len(rels))}
-       var attachments []*Attachment
+       var attachments []*repo_model.Attachment
        for index, element := range rels {
-               element.Attachments = []*Attachment{}
+               element.Attachments = []*repo_model.Attachment{}
                sortedRels.ID[index] = element.ID
                sortedRels.Rel[index] = element
        }
@@ -307,7 +308,7 @@ func getReleaseAttachments(e db.Engine, rels ...*Release) (err error) {
        err = e.
                Asc("release_id", "name").
                In("release_id", sortedRels.ID).
-               Find(&attachments, Attachment{})
+               Find(&attachments, repo_model.Attachment{})
        if err != nil {
                return err
        }
index 38775029262b52c7da498f048bdbb963db749a92..5921441afaafbe813b878119d79b7f6425a527c7 100644 (file)
@@ -25,6 +25,7 @@ import (
 
        admin_model "code.gitea.io/gitea/models/admin"
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/models/webhook"
        "code.gitea.io/gitea/modules/lfs"
@@ -1485,7 +1486,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
                }
        }
 
-       attachments := make([]*Attachment, 0, 20)
+       attachments := make([]*repo_model.Attachment, 0, 20)
        if err = sess.Join("INNER", "`release`", "`release`.id = `attachment`.release_id").
                Where("`release`.repo_id = ?", repoID).
                Find(&attachments); err != nil {
@@ -1620,7 +1621,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
        }
 
        // Get all attachments with both issue_id and release_id are zero
-       var newAttachments []*Attachment
+       var newAttachments []*repo_model.Attachment
        if err := sess.Where(builder.Eq{
                "repo_id":    repo.ID,
                "issue_id":   0,
@@ -1634,7 +1635,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
                newAttachmentPaths = append(newAttachmentPaths, attach.RelativePath())
        }
 
-       if _, err := sess.Where("repo_id=?", repo.ID).Delete(new(Attachment)); err != nil {
+       if _, err := sess.Where("repo_id=?", repo.ID).Delete(new(repo_model.Attachment)); err != nil {
                return err
        }
 
@@ -2191,3 +2192,27 @@ func IterateRepository(f func(repo *Repository) error) error {
                }
        }
 }
+
+// LinkedRepository returns the linked repo if any
+func LinkedRepository(a *repo_model.Attachment) (*Repository, unit.Type, error) {
+       if a.IssueID != 0 {
+               iss, err := GetIssueByID(a.IssueID)
+               if err != nil {
+                       return nil, unit.TypeIssues, err
+               }
+               repo, err := GetRepositoryByID(iss.RepoID)
+               unitType := unit.TypeIssues
+               if iss.IsPull {
+                       unitType = unit.TypePullRequests
+               }
+               return repo, unitType, err
+       } else if a.ReleaseID != 0 {
+               rel, err := GetReleaseByID(a.ReleaseID)
+               if err != nil {
+                       return nil, unit.TypeReleases, err
+               }
+               repo, err := GetRepositoryByID(rel.RepoID)
+               return repo, unit.TypeReleases, err
+       }
+       return nil, -1, nil
+}
diff --git a/models/repo/attachment.go b/models/repo/attachment.go
new file mode 100644 (file)
index 0000000..3fb331a
--- /dev/null
@@ -0,0 +1,294 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+       "context"
+       "fmt"
+       "net/url"
+       "path"
+
+       "code.gitea.io/gitea/models/db"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/storage"
+       "code.gitea.io/gitea/modules/timeutil"
+)
+
+// Attachment represent a attachment of issue/comment/release.
+type Attachment struct {
+       ID            int64  `xorm:"pk autoincr"`
+       UUID          string `xorm:"uuid UNIQUE"`
+       RepoID        int64  `xorm:"INDEX"`           // this should not be zero
+       IssueID       int64  `xorm:"INDEX"`           // maybe zero when creating
+       ReleaseID     int64  `xorm:"INDEX"`           // maybe zero when creating
+       UploaderID    int64  `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added
+       CommentID     int64
+       Name          string
+       DownloadCount int64              `xorm:"DEFAULT 0"`
+       Size          int64              `xorm:"DEFAULT 0"`
+       CreatedUnix   timeutil.TimeStamp `xorm:"created"`
+}
+
+func init() {
+       db.RegisterModel(new(Attachment))
+}
+
+// IncreaseDownloadCount is update download count + 1
+func (a *Attachment) IncreaseDownloadCount() error {
+       // Update download count.
+       if _, err := db.GetEngine(db.DefaultContext).Exec("UPDATE `attachment` SET download_count=download_count+1 WHERE id=?", a.ID); err != nil {
+               return fmt.Errorf("increase attachment count: %v", err)
+       }
+
+       return nil
+}
+
+// AttachmentRelativePath returns the relative path
+func AttachmentRelativePath(uuid string) string {
+       return path.Join(uuid[0:1], uuid[1:2], uuid)
+}
+
+// RelativePath returns the relative path of the attachment
+func (a *Attachment) RelativePath() string {
+       return AttachmentRelativePath(a.UUID)
+}
+
+// DownloadURL returns the download url of the attached file
+func (a *Attachment) DownloadURL() string {
+       return setting.AppURL + "attachments/" + url.PathEscape(a.UUID)
+}
+
+// GetAttachmentByID returns attachment by given id
+func GetAttachmentByID(id int64) (*Attachment, error) {
+       return getAttachmentByID(db.GetEngine(db.DefaultContext), id)
+}
+
+//    _____   __    __                .__                           __
+//   /  _  \_/  |__/  |______    ____ |  |__   _____   ____   _____/  |_
+//  /  /_\  \   __\   __\__  \ _/ ___\|  |  \ /     \_/ __ \ /    \   __\
+// /    |    \  |  |  |  / __ \\  \___|   Y  \  Y Y  \  ___/|   |  \  |
+// \____|__  /__|  |__| (____  /\___  >___|  /__|_|  /\___  >___|  /__|
+//         \/                \/     \/     \/      \/     \/     \/
+
+// ErrAttachmentNotExist represents a "AttachmentNotExist" kind of error.
+type ErrAttachmentNotExist struct {
+       ID   int64
+       UUID string
+}
+
+// IsErrAttachmentNotExist checks if an error is a ErrAttachmentNotExist.
+func IsErrAttachmentNotExist(err error) bool {
+       _, ok := err.(ErrAttachmentNotExist)
+       return ok
+}
+
+func (err ErrAttachmentNotExist) Error() string {
+       return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
+}
+
+func getAttachmentByID(e db.Engine, id int64) (*Attachment, error) {
+       attach := &Attachment{}
+       if has, err := e.ID(id).Get(attach); err != nil {
+               return nil, err
+       } else if !has {
+               return nil, ErrAttachmentNotExist{ID: id, UUID: ""}
+       }
+       return attach, nil
+}
+
+func getAttachmentByUUID(e db.Engine, uuid string) (*Attachment, error) {
+       attach := &Attachment{}
+       has, err := e.Where("uuid=?", uuid).Get(attach)
+       if err != nil {
+               return nil, err
+       } else if !has {
+               return nil, ErrAttachmentNotExist{0, uuid}
+       }
+       return attach, nil
+}
+
+// GetAttachmentsByUUIDs returns attachment by given UUID list.
+func GetAttachmentsByUUIDs(ctx context.Context, uuids []string) ([]*Attachment, error) {
+       return getAttachmentsByUUIDs(db.GetEngine(ctx), uuids)
+}
+
+func getAttachmentsByUUIDs(e db.Engine, uuids []string) ([]*Attachment, error) {
+       if len(uuids) == 0 {
+               return []*Attachment{}, nil
+       }
+
+       // Silently drop invalid uuids.
+       attachments := make([]*Attachment, 0, len(uuids))
+       return attachments, e.In("uuid", uuids).Find(&attachments)
+}
+
+// GetAttachmentByUUID returns attachment by given UUID.
+func GetAttachmentByUUID(uuid string) (*Attachment, error) {
+       return getAttachmentByUUID(db.GetEngine(db.DefaultContext), uuid)
+}
+
+// ExistAttachmentsByUUID returns true if attachment is exist by given UUID
+func ExistAttachmentsByUUID(uuid string) (bool, error) {
+       return db.GetEngine(db.DefaultContext).Where("`uuid`=?", uuid).Exist(new(Attachment))
+}
+
+// GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName.
+func GetAttachmentByReleaseIDFileName(releaseID int64, fileName string) (*Attachment, error) {
+       return getAttachmentByReleaseIDFileName(db.GetEngine(db.DefaultContext), releaseID, fileName)
+}
+
+// GetAttachmentsByIssueIDCtx returns all attachments of an issue.
+func GetAttachmentsByIssueIDCtx(ctx context.Context, issueID int64) ([]*Attachment, error) {
+       attachments := make([]*Attachment, 0, 10)
+       return attachments, db.GetEngine(ctx).Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
+}
+
+// GetAttachmentsByIssueID returns all attachments of an issue.
+func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
+       return GetAttachmentsByIssueIDCtx(db.DefaultContext, issueID)
+}
+
+// GetAttachmentsByCommentID returns all attachments if comment by given ID.
+func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
+       return GetAttachmentsByCommentIDCtx(db.DefaultContext, commentID)
+}
+
+// GetAttachmentsByCommentIDCtx returns all attachments if comment by given ID.
+func GetAttachmentsByCommentIDCtx(ctx context.Context, commentID int64) ([]*Attachment, error) {
+       attachments := make([]*Attachment, 0, 10)
+       return attachments, db.GetEngine(ctx).Where("comment_id=?", commentID).Find(&attachments)
+}
+
+// getAttachmentByReleaseIDFileName return a file based on the the following infos:
+func getAttachmentByReleaseIDFileName(e db.Engine, releaseID int64, fileName string) (*Attachment, error) {
+       attach := &Attachment{ReleaseID: releaseID, Name: fileName}
+       has, err := e.Get(attach)
+       if err != nil {
+               return nil, err
+       } else if !has {
+               return nil, err
+       }
+       return attach, nil
+}
+
+// DeleteAttachment deletes the given attachment and optionally the associated file.
+func DeleteAttachment(a *Attachment, remove bool) error {
+       _, err := DeleteAttachments(db.DefaultContext, []*Attachment{a}, remove)
+       return err
+}
+
+// DeleteAttachments deletes the given attachments and optionally the associated files.
+func DeleteAttachments(ctx context.Context, attachments []*Attachment, remove bool) (int, error) {
+       if len(attachments) == 0 {
+               return 0, nil
+       }
+
+       ids := make([]int64, 0, len(attachments))
+       for _, a := range attachments {
+               ids = append(ids, a.ID)
+       }
+
+       cnt, err := db.GetEngine(ctx).In("id", ids).NoAutoCondition().Delete(attachments[0])
+       if err != nil {
+               return 0, err
+       }
+
+       if remove {
+               for i, a := range attachments {
+                       if err := storage.Attachments.Delete(a.RelativePath()); err != nil {
+                               return i, err
+                       }
+               }
+       }
+       return int(cnt), nil
+}
+
+// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
+func DeleteAttachmentsByIssue(issueID int64, remove bool) (int, error) {
+       attachments, err := GetAttachmentsByIssueID(issueID)
+       if err != nil {
+               return 0, err
+       }
+
+       return DeleteAttachments(db.DefaultContext, attachments, remove)
+}
+
+// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
+func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) {
+       attachments, err := GetAttachmentsByCommentID(commentID)
+       if err != nil {
+               return 0, err
+       }
+
+       return DeleteAttachments(db.DefaultContext, attachments, remove)
+}
+
+// UpdateAttachment updates the given attachment in database
+func UpdateAttachment(atta *Attachment) error {
+       return UpdateAttachmentCtx(db.DefaultContext, atta)
+}
+
+// UpdateAttachmentByUUID Updates attachment via uuid
+func UpdateAttachmentByUUID(ctx context.Context, attach *Attachment, cols ...string) error {
+       if attach.UUID == "" {
+               return fmt.Errorf("attachment uuid should be not blank")
+       }
+       _, err := db.GetEngine(ctx).Where("uuid=?", attach.UUID).Cols(cols...).Update(attach)
+       return err
+}
+
+// UpdateAttachmentCtx updates the given attachment in database
+func UpdateAttachmentCtx(ctx context.Context, atta *Attachment) error {
+       var sess = db.GetEngine(ctx).Cols("name", "issue_id", "release_id", "comment_id", "download_count")
+       if atta.ID != 0 && atta.UUID == "" {
+               sess = sess.ID(atta.ID)
+       } else {
+               // Use uuid only if id is not set and uuid is set
+               sess = sess.Where("uuid = ?", atta.UUID)
+       }
+       _, err := sess.Update(atta)
+       return err
+}
+
+// DeleteAttachmentsByRelease deletes all attachments associated with the given release.
+func DeleteAttachmentsByRelease(releaseID int64) error {
+       _, err := db.GetEngine(db.DefaultContext).Where("release_id = ?", releaseID).Delete(&Attachment{})
+       return err
+}
+
+// IterateAttachment iterates attachments; it should not be used when Gitea is servicing users.
+func IterateAttachment(f func(attach *Attachment) error) error {
+       var start int
+       const batchSize = 100
+       for {
+               attachments := make([]*Attachment, 0, batchSize)
+               if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&attachments); err != nil {
+                       return err
+               }
+               if len(attachments) == 0 {
+                       return nil
+               }
+               start += len(attachments)
+
+               for _, attach := range attachments {
+                       if err := f(attach); err != nil {
+                               return err
+                       }
+               }
+       }
+}
+
+// CountOrphanedAttachments returns the number of bad attachments
+func CountOrphanedAttachments() (int64, error) {
+       return db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
+               Count(new(Attachment))
+}
+
+// DeleteOrphanedAttachments delete all bad attachments
+func DeleteOrphanedAttachments() error {
+       _, err := db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
+               Delete(new(Attachment))
+       return err
+}
diff --git a/models/repo/attachment_test.go b/models/repo/attachment_test.go
new file mode 100644 (file)
index 0000000..53c28d5
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+       "testing"
+
+       "code.gitea.io/gitea/models/db"
+       "code.gitea.io/gitea/models/unittest"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestIncreaseDownloadCount(t *testing.T) {
+       assert.NoError(t, unittest.PrepareTestDatabase())
+
+       attachment, err := GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
+       assert.NoError(t, err)
+       assert.Equal(t, int64(0), attachment.DownloadCount)
+
+       // increase download count
+       err = attachment.IncreaseDownloadCount()
+       assert.NoError(t, err)
+
+       attachment, err = GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
+       assert.NoError(t, err)
+       assert.Equal(t, int64(1), attachment.DownloadCount)
+}
+
+func TestGetByCommentOrIssueID(t *testing.T) {
+       assert.NoError(t, unittest.PrepareTestDatabase())
+
+       // count of attachments from issue ID
+       attachments, err := GetAttachmentsByIssueID(1)
+       assert.NoError(t, err)
+       assert.Len(t, attachments, 1)
+
+       attachments, err = GetAttachmentsByCommentID(1)
+       assert.NoError(t, err)
+       assert.Len(t, attachments, 2)
+}
+
+func TestDeleteAttachments(t *testing.T) {
+       assert.NoError(t, unittest.PrepareTestDatabase())
+
+       count, err := DeleteAttachmentsByIssue(4, false)
+       assert.NoError(t, err)
+       assert.Equal(t, 2, count)
+
+       count, err = DeleteAttachmentsByComment(2, false)
+       assert.NoError(t, err)
+       assert.Equal(t, 2, count)
+
+       err = DeleteAttachment(&Attachment{ID: 8}, false)
+       assert.NoError(t, err)
+
+       attachment, err := GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18")
+       assert.Error(t, err)
+       assert.True(t, IsErrAttachmentNotExist(err))
+       assert.Nil(t, attachment)
+}
+
+func TestGetAttachmentByID(t *testing.T) {
+       assert.NoError(t, unittest.PrepareTestDatabase())
+
+       attach, err := GetAttachmentByID(1)
+       assert.NoError(t, err)
+       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID)
+}
+
+func TestAttachment_DownloadURL(t *testing.T) {
+       attach := &Attachment{
+               UUID: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
+               ID:   1,
+       }
+       assert.Equal(t, "https://try.gitea.io/attachments/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.DownloadURL())
+}
+
+func TestUpdateAttachment(t *testing.T) {
+       assert.NoError(t, unittest.PrepareTestDatabase())
+
+       attach, err := GetAttachmentByID(1)
+       assert.NoError(t, err)
+       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID)
+
+       attach.Name = "new_name"
+       assert.NoError(t, UpdateAttachment(attach))
+
+       unittest.AssertExistsAndLoadBean(t, &Attachment{Name: "new_name"})
+}
+
+func TestGetAttachmentsByUUIDs(t *testing.T) {
+       assert.NoError(t, unittest.PrepareTestDatabase())
+
+       attachList, err := GetAttachmentsByUUIDs(db.DefaultContext, []string{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", "not-existing-uuid"})
+       assert.NoError(t, err)
+       assert.Len(t, attachList, 2)
+       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attachList[0].UUID)
+       assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", attachList[1].UUID)
+       assert.Equal(t, int64(1), attachList[0].IssueID)
+       assert.Equal(t, int64(5), attachList[1].IssueID)
+}
diff --git a/models/repo/main_test.go b/models/repo/main_test.go
new file mode 100644 (file)
index 0000000..ac62df9
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+       "path/filepath"
+       "testing"
+
+       "code.gitea.io/gitea/models/unittest"
+)
+
+func TestMain(m *testing.M) {
+       unittest.MainTest(m, filepath.Join("..", ".."),
+               "attachment.yml",
+       )
+}
index ec1bcc04879abb502737cd64ba5265672182f81e..5cc396eb76a2587495491fe11538da45861d8d78 100644 (file)
@@ -13,6 +13,7 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/models/unittest"
        "code.gitea.io/gitea/modules/markup"
@@ -224,3 +225,30 @@ func TestRepoGetReviewerTeams(t *testing.T) {
        assert.NoError(t, err)
        assert.Len(t, teams, 2)
 }
+
+func TestLinkedRepository(t *testing.T) {
+       assert.NoError(t, unittest.PrepareTestDatabase())
+       testCases := []struct {
+               name             string
+               attachID         int64
+               expectedRepo     *Repository
+               expectedUnitType unit.Type
+       }{
+               {"LinkedIssue", 1, &Repository{ID: 1}, unit.TypeIssues},
+               {"LinkedComment", 3, &Repository{ID: 1}, unit.TypePullRequests},
+               {"LinkedRelease", 9, &Repository{ID: 1}, unit.TypeReleases},
+               {"Notlinked", 10, nil, -1},
+       }
+       for _, tc := range testCases {
+               t.Run(tc.name, func(t *testing.T) {
+                       attach, err := repo_model.GetAttachmentByID(tc.attachID)
+                       assert.NoError(t, err)
+                       repo, unitType, err := LinkedRepository(attach)
+                       assert.NoError(t, err)
+                       if tc.expectedRepo != nil {
+                               assert.Equal(t, tc.expectedRepo.ID, repo.ID)
+                       }
+                       assert.Equal(t, tc.expectedUnitType, unitType)
+               })
+       }
+}
index ab275ecb264dc4e3d750a7f69f490a0fe45ab2ff..62172bac018ceb269a3944810e1205f21265443d 100644 (file)
@@ -359,11 +359,12 @@ func IsContentEmptyErr(err error) bool {
 
 // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
 func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, nil, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        official := false
 
@@ -429,7 +430,7 @@ func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, comm
                }
        }
 
-       comm, err := createComment(sess, &CreateCommentOptions{
+       comm, err := createComment(ctx, &CreateCommentOptions{
                Type:        CommentTypeReview,
                Doer:        doer,
                Content:     review.Content,
@@ -464,7 +465,7 @@ func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, comm
        }
 
        comm.Review = review
-       return review, comm, sess.Commit()
+       return review, comm, committer.Commit()
 }
 
 // GetReviewersByIssueID gets the latest review of each reviewer for a pull request
@@ -631,11 +632,12 @@ func InsertReviews(reviews []*Review) error {
 
 // AddReviewRequest add a review request from one reviewer
 func AddReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        review, err := getReviewByIssueIDAndUserID(sess, issue.ID, reviewer.ID)
        if err != nil && !IsErrReviewNotExist(err) {
@@ -667,7 +669,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
                return nil, err
        }
 
-       comment, err := createComment(sess, &CreateCommentOptions{
+       comment, err := createComment(ctx, &CreateCommentOptions{
                Type:            CommentTypeReviewRequest,
                Doer:            doer,
                Repo:            issue.Repo,
@@ -680,16 +682,17 @@ func AddReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
                return nil, err
        }
 
-       return comment, sess.Commit()
+       return comment, committer.Commit()
 }
 
 // RemoveReviewRequest remove a review request from one reviewer
 func RemoveReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        review, err := getReviewByIssueIDAndUserID(sess, issue.ID, reviewer.ID)
        if err != nil && !IsErrReviewNotExist(err) {
@@ -721,7 +724,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
                }
        }
 
-       comment, err := createComment(sess, &CreateCommentOptions{
+       comment, err := createComment(ctx, &CreateCommentOptions{
                Type:            CommentTypeReviewRequest,
                Doer:            doer,
                Repo:            issue.Repo,
@@ -733,16 +736,17 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
                return nil, err
        }
 
-       return comment, sess.Commit()
+       return comment, committer.Commit()
 }
 
 // AddTeamReviewRequest add a review request from one team
 func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment, error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        review, err := getTeamReviewerByIssueIDAndTeamID(sess, issue.ID, reviewer.ID)
        if err != nil && !IsErrReviewNotExist(err) {
@@ -779,7 +783,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment, e
                }
        }
 
-       comment, err := createComment(sess, &CreateCommentOptions{
+       comment, err := createComment(ctx, &CreateCommentOptions{
                Type:            CommentTypeReviewRequest,
                Doer:            doer,
                Repo:            issue.Repo,
@@ -792,16 +796,17 @@ func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment, e
                return nil, fmt.Errorf("createComment(): %v", err)
        }
 
-       return comment, sess.Commit()
+       return comment, committer.Commit()
 }
 
 // RemoveTeamReviewRequest remove a review request from one team
 func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment, error) {
-       sess := db.NewSession(db.DefaultContext)
-       defer sess.Close()
-       if err := sess.Begin(); err != nil {
+       ctx, committer, err := db.TxContext()
+       if err != nil {
                return nil, err
        }
+       defer committer.Close()
+       sess := db.GetEngine(ctx)
 
        review, err := getTeamReviewerByIssueIDAndTeamID(sess, issue.ID, reviewer.ID)
        if err != nil && !IsErrReviewNotExist(err) {
@@ -836,10 +841,10 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment
        }
 
        if doer == nil {
-               return nil, sess.Commit()
+               return nil, committer.Commit()
        }
 
-       comment, err := createComment(sess, &CreateCommentOptions{
+       comment, err := createComment(ctx, &CreateCommentOptions{
                Type:            CommentTypeReviewRequest,
                Doer:            doer,
                Repo:            issue.Repo,
@@ -851,7 +856,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment
                return nil, fmt.Errorf("createComment(): %v", err)
        }
 
-       return comment, sess.Commit()
+       return comment, committer.Commit()
 }
 
 // MarkConversation Add or remove Conversation mark for a code comment
index 1849497cd9b46df876b449e993f86dc37b7ea0f2..cb300c1a87f5ae5acfbdc68b24a57e6bb3716447 100644 (file)
@@ -7,6 +7,7 @@ package models
 import (
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/login"
+       repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/models/webhook"
        "code.gitea.io/gitea/modules/setting"
@@ -102,7 +103,7 @@ func GetStatistic() (stats Statistic) {
        stats.Counter.Label, _ = e.Count(new(Label))
        stats.Counter.HookTask, _ = e.Count(new(webhook.HookTask))
        stats.Counter.Team, _ = e.Count(new(Team))
-       stats.Counter.Attachment, _ = e.Count(new(Attachment))
+       stats.Counter.Attachment, _ = e.Count(new(repo_model.Attachment))
        stats.Counter.Project, _ = e.Count(new(Project))
        stats.Counter.ProjectBoard, _ = e.Count(new(ProjectBoard))
        return
index 70f0d6e76405bdcd11d2c0f4c8d2dd3637f211d6..955d3ff05fb9825cfd029f081ed0aa3506dfc302 100644 (file)
@@ -6,6 +6,7 @@ package convert
 
 import (
        "code.gitea.io/gitea/models"
+       repo_model "code.gitea.io/gitea/models/repo"
        api "code.gitea.io/gitea/modules/structs"
 )
 
@@ -35,7 +36,7 @@ func ToRelease(r *models.Release) *api.Release {
 }
 
 // ToReleaseAttachment converts models.Attachment to api.Attachment
-func ToReleaseAttachment(a *models.Attachment) *api.Attachment {
+func ToReleaseAttachment(a *repo_model.Attachment) *api.Attachment {
        return &api.Attachment{
                ID:            a.ID,
                Name:          a.Name,
index 040f73abcdb7f3d761a7544b051e54edc8292699..e5f0c5678d3093be658feae491c1683c83b9626d 100644 (file)
@@ -10,6 +10,7 @@ import (
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/migrations"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
 )
@@ -110,8 +111,8 @@ func checkDBConsistency(logger log.Logger, autofix bool) error {
                // find attachments without existing issues or releases
                {
                        Name:    "Orphaned Attachments without existing issues or releases",
-                       Counter: models.CountOrphanedAttachments,
-                       Fixer:   asFixer(models.DeleteOrphanedAttachments),
+                       Counter: repo_model.CountOrphanedAttachments,
+                       Fixer:   asFixer(repo_model.DeleteOrphanedAttachments),
                },
                // find null archived repositories
                {
index cb06d6620498ce6b13339e32d841bab485586b32..d2b7f5ee13895b9f7b10313cc9bf0bbed1a1a501 100644 (file)
@@ -5,7 +5,7 @@
 package doctor
 
 import (
-       "code.gitea.io/gitea/models"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/storage"
 )
@@ -21,7 +21,7 @@ func checkAttachmentStorageFiles(logger log.Logger, autofix bool) error {
                if err != nil {
                        return err
                }
-               exist, err := models.ExistAttachmentsByUUID(stat.Name())
+               exist, err := repo_model.ExistAttachmentsByUUID(stat.Name())
                if err != nil {
                        return err
                }
index d1533e2b5ae03d2547245d09703168915821bdca..fe82915a94d469844e5b5e8114133470110f469b 100644 (file)
@@ -8,6 +8,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/models"
+       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"
@@ -54,7 +55,7 @@ func GetReleaseAttachment(ctx *context.APIContext) {
 
        releaseID := ctx.ParamsInt64(":id")
        attachID := ctx.ParamsInt64(":asset")
-       attach, err := models.GetAttachmentByID(attachID)
+       attach, err := repo_model.GetAttachmentByID(attachID)
        if err != nil {
                ctx.Error(http.StatusInternalServerError, "GetAttachmentByID", err)
                return
@@ -241,7 +242,7 @@ func EditReleaseAttachment(ctx *context.APIContext) {
        // Check if release exists an load release
        releaseID := ctx.ParamsInt64(":id")
        attachID := ctx.ParamsInt64(":asset")
-       attach, err := models.GetAttachmentByID(attachID)
+       attach, err := repo_model.GetAttachmentByID(attachID)
        if err != nil {
                ctx.Error(http.StatusInternalServerError, "GetAttachmentByID", err)
                return
@@ -256,7 +257,7 @@ func EditReleaseAttachment(ctx *context.APIContext) {
                attach.Name = form.Name
        }
 
-       if err := models.UpdateAttachment(attach); err != nil {
+       if err := repo_model.UpdateAttachment(attach); err != nil {
                ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach)
        }
        ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach))
@@ -299,7 +300,7 @@ func DeleteReleaseAttachment(ctx *context.APIContext) {
        // Check if release exists an load release
        releaseID := ctx.ParamsInt64(":id")
        attachID := ctx.ParamsInt64(":asset")
-       attach, err := models.GetAttachmentByID(attachID)
+       attach, err := repo_model.GetAttachmentByID(attachID)
        if err != nil {
                ctx.Error(http.StatusInternalServerError, "GetAttachmentByID", err)
                return
@@ -311,7 +312,7 @@ func DeleteReleaseAttachment(ctx *context.APIContext) {
        }
        // FIXME Should prove the existence of the given repo, but results in unnecessary database requests
 
-       if err := models.DeleteAttachment(attach, true); err != nil {
+       if err := repo_model.DeleteAttachment(attach, true); err != nil {
                ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err)
                return
        }
index 3968d2765266cd1e4738bde26a28a461298bc730..303eee24d17dbbc82d5a67bf382916f1d92baf48 100644 (file)
@@ -9,6 +9,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/models"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/httpcache"
        "code.gitea.io/gitea/modules/log"
@@ -62,7 +63,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
 // DeleteAttachment response for deleting issue's attachment
 func DeleteAttachment(ctx *context.Context) {
        file := ctx.FormString("file")
-       attach, err := models.GetAttachmentByUUID(file)
+       attach, err := repo_model.GetAttachmentByUUID(file)
        if err != nil {
                ctx.Error(http.StatusBadRequest, err.Error())
                return
@@ -71,7 +72,7 @@ func DeleteAttachment(ctx *context.Context) {
                ctx.Error(http.StatusForbidden)
                return
        }
-       err = models.DeleteAttachment(attach, true)
+       err = repo_model.DeleteAttachment(attach, true)
        if err != nil {
                ctx.Error(http.StatusInternalServerError, fmt.Sprintf("DeleteAttachment: %v", err))
                return
@@ -83,9 +84,9 @@ func DeleteAttachment(ctx *context.Context) {
 
 // GetAttachment serve attachements
 func GetAttachment(ctx *context.Context) {
-       attach, err := models.GetAttachmentByUUID(ctx.Params(":uuid"))
+       attach, err := repo_model.GetAttachmentByUUID(ctx.Params(":uuid"))
        if err != nil {
-               if models.IsErrAttachmentNotExist(err) {
+               if repo_model.IsErrAttachmentNotExist(err) {
                        ctx.Error(http.StatusNotFound)
                } else {
                        ctx.ServerError("GetAttachmentByUUID", err)
@@ -93,7 +94,7 @@ func GetAttachment(ctx *context.Context) {
                return
        }
 
-       repository, unitType, err := attach.LinkedRepository()
+       repository, unitType, err := models.LinkedRepository(attach)
        if err != nil {
                ctx.ServerError("LinkedRepository", err)
                return
index 129287b96adde221c42650f68e26753f452405d7..6cc9419763cdc824b888e49b5f86fb7f5eb9fcb9 100644 (file)
@@ -18,6 +18,7 @@ import (
 
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/context"
@@ -2516,7 +2517,7 @@ func GetCommentAttachments(ctx *context.Context) {
 }
 
 func updateAttachments(item interface{}, files []string) error {
-       var attachments []*models.Attachment
+       var attachments []*repo_model.Attachment
        switch content := item.(type) {
        case *models.Issue:
                attachments = content.Attachments
@@ -2529,7 +2530,7 @@ func updateAttachments(item interface{}, files []string) error {
                if util.IsStringInSlice(attachments[i].UUID, files) {
                        continue
                }
-               if err := models.DeleteAttachment(attachments[i], true); err != nil {
+               if err := repo_model.DeleteAttachment(attachments[i], true); err != nil {
                        return err
                }
        }
@@ -2549,16 +2550,16 @@ func updateAttachments(item interface{}, files []string) error {
        }
        switch content := item.(type) {
        case *models.Issue:
-               content.Attachments, err = models.GetAttachmentsByIssueID(content.ID)
+               content.Attachments, err = repo_model.GetAttachmentsByIssueID(content.ID)
        case *models.Comment:
-               content.Attachments, err = models.GetAttachmentsByCommentID(content.ID)
+               content.Attachments, err = repo_model.GetAttachmentsByCommentID(content.ID)
        default:
                return fmt.Errorf("Unknown Type: %T", content)
        }
        return err
 }
 
-func attachmentsHTML(ctx *context.Context, attachments []*models.Attachment, content string) string {
+func attachmentsHTML(ctx *context.Context, attachments []*repo_model.Attachment, content string) string {
        attachHTML, err := ctx.HTMLString(string(tplAttachment), map[string]interface{}{
                "ctx":         ctx.Data,
                "Attachments": attachments,
index 2d6189824d7783b397b1daca26d1ea44566cad5f..e8fdb99ff4bc1aaf322599811a95bd35ce9045c2 100644 (file)
@@ -14,6 +14,7 @@ import (
 
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/context"
@@ -346,7 +347,7 @@ func RedirectDownload(ctx *context.Context) {
        curRepo := ctx.Repo.Repository
        releases, err := models.GetReleasesByRepoIDAndNames(db.DefaultContext, curRepo.ID, tagNames)
        if err != nil {
-               if models.IsErrAttachmentNotExist(err) {
+               if repo_model.IsErrAttachmentNotExist(err) {
                        ctx.Error(http.StatusNotFound)
                        return
                }
@@ -355,7 +356,7 @@ func RedirectDownload(ctx *context.Context) {
        }
        if len(releases) == 1 {
                release := releases[0]
-               att, err := models.GetAttachmentByReleaseIDFileName(release.ID, fileName)
+               att, err := repo_model.GetAttachmentByReleaseIDFileName(release.ID, fileName)
                if err != nil {
                        ctx.Error(http.StatusNotFound)
                        return
index f747ccec3ea171f8928670ad40c47ae2d73fe866..e3b65a239bb4e786c9772050d1c06018391ca6b5 100644 (file)
@@ -10,8 +10,8 @@ import (
        "fmt"
        "io"
 
-       "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/storage"
        "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
@@ -20,7 +20,7 @@ import (
 )
 
 // NewAttachment creates a new attachment object, but do not verify.
-func NewAttachment(attach *models.Attachment, file io.Reader) (*models.Attachment, error) {
+func NewAttachment(attach *repo_model.Attachment, file io.Reader) (*repo_model.Attachment, error) {
        if attach.RepoID == 0 {
                return nil, fmt.Errorf("attachment %s should belong to a repository", attach.Name)
        }
@@ -40,7 +40,7 @@ func NewAttachment(attach *models.Attachment, file io.Reader) (*models.Attachmen
 }
 
 // UploadAttachment upload new attachment into storage and update database
-func UploadAttachment(file io.Reader, actorID, repoID, releaseID int64, fileName string, allowedTypes string) (*models.Attachment, error) {
+func UploadAttachment(file io.Reader, actorID, repoID, releaseID int64, fileName string, allowedTypes string) (*repo_model.Attachment, error) {
        buf := make([]byte, 1024)
        n, _ := util.ReadAtMost(file, buf)
        buf = buf[:n]
@@ -49,7 +49,7 @@ func UploadAttachment(file io.Reader, actorID, repoID, releaseID int64, fileName
                return nil, err
        }
 
-       return NewAttachment(&models.Attachment{
+       return NewAttachment(&repo_model.Attachment{
                RepoID:     repoID,
                UploaderID: actorID,
                ReleaseID:  releaseID,
index 5bb5db11ec6653e89ae29ebb80ae7a718eed654e..a992fbf151d004ab8362ab7f878653ad11be0c8e 100644 (file)
@@ -10,6 +10,7 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
 
        "github.com/stretchr/testify/assert"
@@ -29,14 +30,14 @@ func TestUploadAttachment(t *testing.T) {
        assert.NoError(t, err)
        defer f.Close()
 
-       attach, err := NewAttachment(&models.Attachment{
+       attach, err := NewAttachment(&repo_model.Attachment{
                RepoID:     1,
                UploaderID: user.ID,
                Name:       filepath.Base(fPath),
        }, f)
        assert.NoError(t, err)
 
-       attachment, err := models.GetAttachmentByUUID(attach.UUID)
+       attachment, err := repo_model.GetAttachmentByUUID(attach.UUID)
        assert.NoError(t, err)
        assert.EqualValues(t, user.ID, attachment.UploaderID)
        assert.Equal(t, int64(0), attachment.DownloadCount)
index 0f215e05d6e38e1bc2cb2d6063bc9f2ce317190c..2394c63d76a3cd53e09c7f3e9c9015c288b864aa 100644 (file)
@@ -17,6 +17,7 @@ import (
 
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        base "code.gitea.io/gitea/modules/migration"
@@ -295,7 +296,7 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
                                        asset.Created = release.Created
                                }
                        }
-                       var attach = models.Attachment{
+                       var attach = repo_model.Attachment{
                                UUID:          gouuid.New().String(),
                                Name:          asset.Name,
                                DownloadCount: int64(*asset.DownloadCount),
index f6f456e8fa3733477d594bf567df54676ff6c7cb..30274f93efa9db0c6ea40bbd51187cea0ca90f37 100644 (file)
@@ -11,6 +11,7 @@ import (
 
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/db"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/notification"
@@ -206,7 +207,7 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea
        var deletedUUIDsMap = make(map[string]bool)
        if len(delAttachmentUUIDs) > 0 {
                // Check attachments
-               attachments, err := models.GetAttachmentsByUUIDs(ctx, delAttachmentUUIDs)
+               attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, delAttachmentUUIDs)
                if err != nil {
                        return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %v", delAttachmentUUIDs, err)
                }
@@ -217,7 +218,7 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea
                        deletedUUIDsMap[attach.UUID] = true
                }
 
-               if _, err := models.DeleteAttachments(ctx, attachments, false); err != nil {
+               if _, err := repo_model.DeleteAttachments(ctx, attachments, false); err != nil {
                        return fmt.Errorf("DeleteAttachments [uuids: %v]: %v", delAttachmentUUIDs, err)
                }
        }
@@ -228,7 +229,7 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea
                        updateAttachmentsList = append(updateAttachmentsList, k)
                }
                // Check attachments
-               attachments, err := models.GetAttachmentsByUUIDs(ctx, updateAttachmentsList)
+               attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, updateAttachmentsList)
                if err != nil {
                        return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %v", updateAttachmentsList, err)
                }
@@ -240,7 +241,7 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea
 
                for uuid, newName := range editAttachments {
                        if !deletedUUIDsMap[uuid] {
-                               if err = models.UpdateAttachmentByUUID(ctx, &models.Attachment{
+                               if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{
                                        UUID: uuid,
                                        Name: newName,
                                }, "name"); err != nil {
@@ -255,7 +256,7 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea
        }
 
        for _, uuid := range delAttachmentUUIDs {
-               if err := storage.Attachments.Delete(models.AttachmentRelativePath(uuid)); err != nil {
+               if err := storage.Attachments.Delete(repo_model.AttachmentRelativePath(uuid)); err != nil {
                        // Even delete files failed, but the attachments has been removed from database, so we
                        // should not return error but only record the error on logs.
                        // users have to delete this attachments manually or we should have a
@@ -321,7 +322,7 @@ func DeleteReleaseByID(id int64, doer *models.User, delTag bool) error {
                return fmt.Errorf("LoadAttributes: %v", err)
        }
 
-       if err := models.DeleteAttachmentsByRelease(rel.ID); err != nil {
+       if err := repo_model.DeleteAttachmentsByRelease(rel.ID); err != nil {
                return fmt.Errorf("DeleteAttachments: %v", err)
        }
 
index d720bf996b07fd815e817172c607c3e830e87cc9..92eb128f71dae91af4653e2f5280504f24ce9f3b 100644 (file)
@@ -11,6 +11,7 @@ import (
        "time"
 
        "code.gitea.io/gitea/models"
+       repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/services/attachment"
@@ -103,7 +104,7 @@ func TestRelease_Create(t *testing.T) {
                IsTag:        false,
        }, nil, ""))
 
-       attach, err := attachment.NewAttachment(&models.Attachment{
+       attach, err := attachment.NewAttachment(&repo_model.Attachment{
                RepoID:     repo.ID,
                UploaderID: user.ID,
                Name:       "test.txt",
@@ -236,7 +237,7 @@ func TestRelease_Update(t *testing.T) {
        assert.Equal(t, tagName, release.TagName)
 
        // Add new attachments
-       attach, err := attachment.NewAttachment(&models.Attachment{
+       attach, err := attachment.NewAttachment(&repo_model.Attachment{
                RepoID:     repo.ID,
                UploaderID: user.ID,
                Name:       "test.txt",