"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"
}
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
})
"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"
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
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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)
- })
- }
-}
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)
-}
-
// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
// IsErrUploadNotExist checks if an error is a ErrUploadNotExist.
func IsErrUploadNotExist(err error) bool {
- _, ok := err.(ErrAttachmentNotExist)
+ _, ok := err.(ErrUploadNotExist)
return ok
}
"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"
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
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
}
}
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)
}
// 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.
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) {
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)
}
}
return ErrRepoLabelNotExist{}
}
- if err = issue.clearLabels(db.GetEngine(ctx), doer); err != nil {
+ if err = issue.clearLabels(ctx, doer); err != nil {
return err
}
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)
}
}
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
}
}
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
cmtType = CommentTypeMergePull
}
- return createComment(e, &CreateCommentOptions{
+ return createComment(ctx, &CreateCommentOptions{
Type: cmtType,
Doer: doer,
Repo: issue.Repo,
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
}
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
}
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)
}
Issue: issue,
OldRef: branchName,
}
- if _, err = createComment(db.GetEngine(ctx), opts); err != nil {
+ if _, err = createComment(ctx, opts); err != nil {
return err
}
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)
}
}
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)
}
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 {
OldMilestoneID: 0,
MilestoneID: opts.Issue.MilestoneID,
}
- if _, err = createComment(e, opts); err != nil {
+ if _, err = createComment(ctx, opts); err != nil {
return err
}
}
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)
}
}
}
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)
}
}
}
}
- if err = opts.Issue.loadAttributes(e); err != nil {
+ if err = opts.Issue.loadAttributes(ctx); err != nil {
return err
}
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
}
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,
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.
// 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)
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.
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 {
}
// 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.
return
}
- var attachments []*Attachment
+ var attachments []*repo_model.Attachment
if err = sess.In("issue_id", deleteCond).
Find(&attachments); err != nil {
return
}
if _, err = sess.In("issue_id", deleteCond).
- Delete(&Attachment{}); err != nil {
+ Delete(&repo_model.Attachment{}); err != nil {
return
}
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
// 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)
AssigneeID: assigneeID,
}
// Comment
- comment, err = createComment(sess, opts)
+ comment, err = createComment(ctx, opts)
if err != nil {
return false, nil, fmt.Errorf("createComment: %v", err)
}
}
// 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 {
package models
import (
+ "context"
"fmt"
"regexp"
"strconv"
"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"
// 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:"-"`
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)
}
}
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)
}
// 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
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
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:
}
// 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)
}
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
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
}
Issue: issue,
Content: content,
}
- comment, err := createComment(e, opts)
+ comment, err := createComment(ctx, opts)
if err != nil {
return nil, err
}
}
// 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
}
Issue: issue,
DependentIssueID: dependentIssue.ID,
}
- if _, err = createComment(e, opts); err != nil {
+ if _, err = createComment(ctx, opts); err != nil {
return
}
Issue: dependentIssue,
DependentIssueID: issue.ID,
}
- _, err = createComment(e, opts)
+ _, err = createComment(ctx, opts)
return
}
// 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
}
// 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
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)
}
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
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 {
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()
// 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)
}
// 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
return ErrUnknownDependencyType{depType}
}
- affected, err := sess.Delete(&issueDepToDelete)
+ affected, err := db.GetEngine(ctx).Delete(&issueDepToDelete)
if err != nil {
return err
}
}
// 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
// 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,
Label: label,
Content: "1",
}
- if _, err = createComment(e, opts); err != nil {
+ if _, err = createComment(ctx, opts); err != nil {
return err
}
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
return nil
}
- if err = newIssueLabel(sess, issue, label, doer); err != nil {
+ if err = newIssueLabel(ctx, issue, label, doer); err != nil {
return err
}
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
}
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)
}
}
}
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
}
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,
Issue: issue,
Label: label,
}
- if _, err = createComment(e, opts); err != nil {
+ if _, err = createComment(ctx, opts); err != nil {
return 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 {
"fmt"
"code.gitea.io/gitea/models/db"
+ repo_model "code.gitea.io/gitea/models/repo"
"xorm.io/builder"
)
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 {
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 {
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
}
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()
}
package models
import (
+ "context"
"fmt"
"strings"
"time"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
- "xorm.io/xorm"
)
// Milestone represents a milestone of repository.
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
}
OldMilestoneID: oldMilestoneID,
MilestoneID: issue.MilestoneID,
}
- if _, err := createComment(e, opts); err != nil {
+ if _, err := createComment(ctx, opts); err != nil {
return err
}
}
// 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
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.
// 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
return err
}
- if _, err := createComment(e, &CreateCommentOptions{
+ if _, err := createComment(ctx, &CreateCommentOptions{
Doer: user,
Issue: issue,
Repo: issue.Repo,
if err != nil {
return err
}
- if err := createOrStopIssueStopwatch(e, user, issue); err != nil {
+ if err := createOrStopIssueStopwatch(ctx, user, issue); err != nil {
return err
}
}
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,
// 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
return err
}
- if _, err := createComment(e, &CreateCommentOptions{
+ if _, err := createComment(ctx, &CreateCommentOptions{
Doer: user,
Issue: issue,
Repo: issue.Repo,
// 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 {
return nil, err
}
- if _, err := createComment(sess, &CreateCommentOptions{
+ if _, err := createComment(ctx, &CreateCommentOptions{
Issue: issue,
Repo: issue.Repo,
Doer: user,
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) {
// 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,
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,
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
return err
}
- if _, err := createComment(sess, &CreateCommentOptions{
+ if _, err := createComment(ctx, &CreateCommentOptions{
Issue: t.Issue,
Repo: t.Issue.Repo,
Doer: t.User,
return err
}
- return sess.Commit()
+ return committer.Commit()
}
func deleteTimes(e db.Engine, opts FindTrackedTimesOptions) (removedTime int64, err error) {
package models
import (
+ "context"
"fmt"
"code.gitea.io/gitea/models/db"
// \/ \/ \/
//
-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
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
RefAction: xref.Action,
RefIsPull: ctx.OrigIssue.IsPull,
}
- _, err := createComment(e, opts)
+ _, err := createComment(stdCtx, opts)
if err != nil {
return err
}
// \/ \/ \/ \/ \/
//
-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{
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: 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
}
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
}
package models
import (
+ "context"
"fmt"
"net/url"
"strconv"
// 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 {
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
}
// 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
package models
import (
+ "context"
"fmt"
"code.gitea.io/gitea/models/db"
-
- "xorm.io/xorm"
)
// ProjectIssue saves relation from issue to a project
// 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 {
}
if oldProjectID > 0 || newProjectID > 0 {
- if _, err := createComment(e, &CreateCommentOptions{
+ if _, err := createComment(ctx, &CreateCommentOptions{
Type: CommentTypeProject,
Doer: doer,
Repo: issue.Repo,
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
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)
}
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
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,
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)
}
"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"
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() {
// 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)
}
// 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
}
err = e.
Asc("release_id", "name").
In("release_id", sortedRels.ID).
- Find(&attachments, Attachment{})
+ Find(&attachments, repo_model.Attachment{})
if err != nil {
return err
}
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"
}
}
- 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 {
}
// 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,
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
}
}
}
}
+
+// 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
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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",
+ )
+}
"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"
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)
+ })
+ }
+}
// 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
}
}
- comm, err := createComment(sess, &CreateCommentOptions{
+ comm, err := createComment(ctx, &CreateCommentOptions{
Type: CommentTypeReview,
Doer: doer,
Content: review.Content,
}
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
// 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) {
return nil, err
}
- comment, err := createComment(sess, &CreateCommentOptions{
+ comment, err := createComment(ctx, &CreateCommentOptions{
Type: CommentTypeReviewRequest,
Doer: doer,
Repo: issue.Repo,
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) {
}
}
- comment, err := createComment(sess, &CreateCommentOptions{
+ comment, err := createComment(ctx, &CreateCommentOptions{
Type: CommentTypeReviewRequest,
Doer: doer,
Repo: issue.Repo,
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) {
}
}
- comment, err := createComment(sess, &CreateCommentOptions{
+ comment, err := createComment(ctx, &CreateCommentOptions{
Type: CommentTypeReviewRequest,
Doer: doer,
Repo: issue.Repo,
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) {
}
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,
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
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"
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
import (
"code.gitea.io/gitea/models"
+ repo_model "code.gitea.io/gitea/models/repo"
api "code.gitea.io/gitea/modules/structs"
)
}
// 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,
"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"
)
// 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
{
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"
)
if err != nil {
return err
}
- exist, err := models.ExistAttachmentsByUUID(stat.Name())
+ exist, err := repo_model.ExistAttachmentsByUUID(stat.Name())
if err != nil {
return err
}
"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"
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
// 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
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))
// 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
}
// 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
}
"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"
// 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
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
// 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)
return
}
- repository, unitType, err := attach.LinkedRepository()
+ repository, unitType, err := models.LinkedRepository(attach)
if err != nil {
ctx.ServerError("LinkedRepository", err)
return
"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"
}
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
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
}
}
}
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,
"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"
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
}
}
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
"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"
)
// 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)
}
}
// 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]
return nil, err
}
- return NewAttachment(&models.Attachment{
+ return NewAttachment(&repo_model.Attachment{
RepoID: repoID,
UploaderID: actorID,
ReleaseID: releaseID,
"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"
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)
"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"
asset.Created = release.Created
}
}
- var attach = models.Attachment{
+ var attach = repo_model.Attachment{
UUID: gouuid.New().String(),
Name: asset.Name,
DownloadCount: int64(*asset.DownloadCount),
"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"
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)
}
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)
}
}
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)
}
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 {
}
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
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)
}
"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"
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",
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",