summaryrefslogtreecommitdiffstats
path: root/models/repo
diff options
context:
space:
mode:
authorJakobDev <jakobdev@gmx.de>2024-04-02 16:34:57 +0200
committerJakobDev <jakobdev@gmx.de>2024-04-08 12:51:27 +0200
commit613e5387c5933849222207c5ebb9996297cd4046 (patch)
treefcc7085edb1828be28399d2e6a594da2e4dc5ac7 /models/repo
parentMerge pull request '[PORT] gitea#29953: Fix:the rounded corners of the folded... (diff)
downloadforgejo-613e5387c5933849222207c5ebb9996297cd4046.tar.xz
forgejo-613e5387c5933849222207c5ebb9996297cd4046.zip
Count downloads for tag archives
Diffstat (limited to 'models/repo')
-rw-r--r--models/repo/archive_download_count.go87
-rw-r--r--models/repo/archive_download_count_test.go65
-rw-r--r--models/repo/archiver.go1
-rw-r--r--models/repo/release.go70
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).