diff options
author | JakobDev <jakobdev@gmx.de> | 2024-04-02 16:34:57 +0200 |
---|---|---|
committer | JakobDev <jakobdev@gmx.de> | 2024-04-08 12:51:27 +0200 |
commit | 613e5387c5933849222207c5ebb9996297cd4046 (patch) | |
tree | fcc7085edb1828be28399d2e6a594da2e4dc5ac7 /models/repo | |
parent | Merge pull request '[PORT] gitea#29953: Fix:the rounded corners of the folded... (diff) | |
download | forgejo-613e5387c5933849222207c5ebb9996297cd4046.tar.xz forgejo-613e5387c5933849222207c5ebb9996297cd4046.zip |
Count downloads for tag archives
Diffstat (limited to 'models/repo')
-rw-r--r-- | models/repo/archive_download_count.go | 87 | ||||
-rw-r--r-- | models/repo/archive_download_count_test.go | 65 | ||||
-rw-r--r-- | models/repo/archiver.go | 1 | ||||
-rw-r--r-- | models/repo/release.go | 70 |
4 files changed, 201 insertions, 22 deletions
diff --git a/models/repo/archive_download_count.go b/models/repo/archive_download_count.go new file mode 100644 index 0000000000..6300307a35 --- /dev/null +++ b/models/repo/archive_download_count.go @@ -0,0 +1,87 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "context" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" +) + +// RepoArchiveDownloadCount counts all archive downloads for a tag +type RepoArchiveDownloadCount struct { //nolint:revive + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"index unique(s)"` + ReleaseID int64 `xorm:"index unique(s)"` + Type git.ArchiveType `xorm:"unique(s)"` + Count int64 +} + +func init() { + db.RegisterModel(new(RepoArchiveDownloadCount)) +} + +// CountArchiveDownload adds one download the the given archive +func CountArchiveDownload(ctx context.Context, repoID, releaseID int64, tp git.ArchiveType) error { + updateCount, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).And("release_id = ?", releaseID).And("`type` = ?", tp).Incr("count").Update(new(RepoArchiveDownloadCount)) + if err != nil { + return err + } + + if updateCount != 0 { + // The count was updated, so we can exit + return nil + } + + // The archive does not esxists in the databse, so let's add it + newCounter := &RepoArchiveDownloadCount{ + RepoID: repoID, + ReleaseID: releaseID, + Type: tp, + Count: 1, + } + + _, err = db.GetEngine(ctx).Insert(newCounter) + return err +} + +// GetArchiveDownloadCount returns the download count of a tag +func GetArchiveDownloadCount(ctx context.Context, repoID, releaseID int64) (*api.TagArchiveDownloadCount, error) { + downloadCountList := make([]RepoArchiveDownloadCount, 0) + err := db.GetEngine(ctx).Where("repo_id = ?", repoID).And("release_id = ?", releaseID).Find(&downloadCountList) + if err != nil { + return nil, err + } + + tagCounter := new(api.TagArchiveDownloadCount) + + for _, singleCount := range downloadCountList { + switch singleCount.Type { + case git.ZIP: + tagCounter.Zip = singleCount.Count + case git.TARGZ: + tagCounter.TarGz = singleCount.Count + } + } + + return tagCounter, nil +} + +// GetDownloadCountForTagName returns the download count of a tag with the given name +func GetArchiveDownloadCountForTagName(ctx context.Context, repoID int64, tagName string) (*api.TagArchiveDownloadCount, error) { + release, err := GetRelease(ctx, repoID, tagName) + if err != nil { + return nil, err + } + + return GetArchiveDownloadCount(ctx, repoID, release.ID) +} + +// DeleteArchiveDownloadCountForRelease deletes the release from the repo_archive_download_count table +func DeleteArchiveDownloadCountForRelease(ctx context.Context, releaseID int64) error { + _, err := db.GetEngine(ctx).Delete(&RepoArchiveDownloadCount{ReleaseID: releaseID}) + return err +} diff --git a/models/repo/archive_download_count_test.go b/models/repo/archive_download_count_test.go new file mode 100644 index 0000000000..53bdf9a1e0 --- /dev/null +++ b/models/repo/archive_download_count_test.go @@ -0,0 +1,65 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/git" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRepoArchiveDownloadCount(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + release, err := repo_model.GetReleaseByID(db.DefaultContext, 1) + require.NoError(t, err) + + // We have no count, so it should return 0 + downloadCount, err := repo_model.GetArchiveDownloadCount(db.DefaultContext, release.RepoID, release.ID) + require.NoError(t, err) + assert.Equal(t, int64(0), downloadCount.Zip) + assert.Equal(t, int64(0), downloadCount.TarGz) + + // Set the TarGz counter to 1 + err = repo_model.CountArchiveDownload(db.DefaultContext, release.RepoID, release.ID, git.TARGZ) + require.NoError(t, err) + + downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName) + require.NoError(t, err) + assert.Equal(t, int64(0), downloadCount.Zip) + assert.Equal(t, int64(1), downloadCount.TarGz) + + // Set the TarGz counter to 2 + err = repo_model.CountArchiveDownload(db.DefaultContext, release.RepoID, release.ID, git.TARGZ) + require.NoError(t, err) + + downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName) + require.NoError(t, err) + assert.Equal(t, int64(0), downloadCount.Zip) + assert.Equal(t, int64(2), downloadCount.TarGz) + + // Set the Zip counter to 1 + err = repo_model.CountArchiveDownload(db.DefaultContext, release.RepoID, release.ID, git.ZIP) + require.NoError(t, err) + + downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName) + require.NoError(t, err) + assert.Equal(t, int64(1), downloadCount.Zip) + assert.Equal(t, int64(2), downloadCount.TarGz) + + // Delete the count + err = repo_model.DeleteArchiveDownloadCountForRelease(db.DefaultContext, release.ID) + require.NoError(t, err) + + downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName) + require.NoError(t, err) + assert.Equal(t, int64(0), downloadCount.Zip) + assert.Equal(t, int64(0), downloadCount.TarGz) +} diff --git a/models/repo/archiver.go b/models/repo/archiver.go index 14ffa1d89b..3f05fcf752 100644 --- a/models/repo/archiver.go +++ b/models/repo/archiver.go @@ -35,6 +35,7 @@ type RepoArchiver struct { //revive:disable-line:exported Status ArchiverStatus CommitID string `xorm:"VARCHAR(64) unique(s)"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"` + ReleaseID int64 `xorm:"-"` } func init() { diff --git a/models/repo/release.go b/models/repo/release.go index a9f65f6c3e..3168bdaaea 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -65,28 +65,29 @@ func (err ErrReleaseNotExist) Unwrap() error { // Release represents a release of repository. type Release struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(n)"` - Repo *Repository `xorm:"-"` - PublisherID int64 `xorm:"INDEX"` - Publisher *user_model.User `xorm:"-"` - TagName string `xorm:"INDEX UNIQUE(n)"` - OriginalAuthor string - OriginalAuthorID int64 `xorm:"index"` - LowerTagName string - Target string - TargetBehind string `xorm:"-"` // to handle non-existing or empty target - Title string - Sha1 string `xorm:"VARCHAR(64)"` - NumCommits int64 - NumCommitsBehind int64 `xorm:"-"` - Note string `xorm:"TEXT"` - RenderedNote template.HTML `xorm:"-"` - IsDraft bool `xorm:"NOT NULL DEFAULT false"` - IsPrerelease bool `xorm:"NOT NULL DEFAULT false"` - IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases - Attachments []*Attachment `xorm:"-"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(n)"` + Repo *Repository `xorm:"-"` + PublisherID int64 `xorm:"INDEX"` + Publisher *user_model.User `xorm:"-"` + TagName string `xorm:"INDEX UNIQUE(n)"` + OriginalAuthor string + OriginalAuthorID int64 `xorm:"index"` + LowerTagName string + Target string + TargetBehind string `xorm:"-"` // to handle non-existing or empty target + Title string + Sha1 string `xorm:"VARCHAR(64)"` + NumCommits int64 + NumCommitsBehind int64 `xorm:"-"` + Note string `xorm:"TEXT"` + RenderedNote template.HTML `xorm:"-"` + IsDraft bool `xorm:"NOT NULL DEFAULT false"` + IsPrerelease bool `xorm:"NOT NULL DEFAULT false"` + IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases + Attachments []*Attachment `xorm:"-"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX"` + ArchiveDownloadCount *structs.TagArchiveDownloadCount `xorm:"-"` } func init() { @@ -112,9 +113,22 @@ func (r *Release) LoadAttributes(ctx context.Context) error { } } } + + err = r.LoadArchiveDownloadCount(ctx) + if err != nil { + return err + } + return GetReleaseAttachments(ctx, r) } +// LoadArchiveDownloadCount loads the download count for the source archives +func (r *Release) LoadArchiveDownloadCount(ctx context.Context) error { + var err error + r.ArchiveDownloadCount, err = GetArchiveDownloadCount(ctx, r.RepoID, r.ID) + return err +} + // APIURL the api url for a release. release must have attributes loaded func (r *Release) APIURL() string { return r.Repo.APIURL() + "/releases/" + strconv.FormatInt(r.ID, 10) @@ -447,6 +461,18 @@ func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []s lowerTags = append(lowerTags, strings.ToLower(tag)) } + for _, tag := range tags { + release, err := GetRelease(ctx, repo.ID, tag) + if err != nil { + return fmt.Errorf("GetRelease: %w", err) + } + + err = DeleteArchiveDownloadCountForRelease(ctx, release.ID) + if err != nil { + return fmt.Errorf("DeleteTagArchiveDownloadCount: %w", err) + } + } + if _, err := db.GetEngine(ctx). Where("repo_id = ? AND is_tag = ?", repo.ID, true). In("lower_tag_name", lowerTags). |