Skip to content

Commit 42919cc

Browse files
Make Release Download URLs predictable (#23891)
As promised in #23817, I have this made a PR to make Release Download URLs predictable. It currently follows the schema `<repo>/releases/download/<tag>/<filename>`. this already works, but it is nowhere shown in the UI or the API. The Problem is, that it is currently possible to have multiple files with the same name (why do we even allow this) for a release. I had written some Code to check, if a Release has 2 or more files with the same Name. If yes, it uses the old `attachments/<uuid>` URlL if no it uses the new fancy URL. I had also changed `<repo>/releases/download/<tag>/<filename>` to directly serve the File instead of redirecting, so people who who use automatic update checker don't end up with the `attachments/<uuid>` URL. Fixes #10919 --------- Co-authored-by: a1012112796 <[email protected]>
1 parent e03e827 commit 42919cc

File tree

5 files changed

+60
-15
lines changed

5 files changed

+60
-15
lines changed

models/repo/attachment.go

+16-11
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,18 @@ import (
1818

1919
// Attachment represent a attachment of issue/comment/release.
2020
type Attachment struct {
21-
ID int64 `xorm:"pk autoincr"`
22-
UUID string `xorm:"uuid UNIQUE"`
23-
RepoID int64 `xorm:"INDEX"` // this should not be zero
24-
IssueID int64 `xorm:"INDEX"` // maybe zero when creating
25-
ReleaseID int64 `xorm:"INDEX"` // maybe zero when creating
26-
UploaderID int64 `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added
27-
CommentID int64
28-
Name string
29-
DownloadCount int64 `xorm:"DEFAULT 0"`
30-
Size int64 `xorm:"DEFAULT 0"`
31-
CreatedUnix timeutil.TimeStamp `xorm:"created"`
21+
ID int64 `xorm:"pk autoincr"`
22+
UUID string `xorm:"uuid UNIQUE"`
23+
RepoID int64 `xorm:"INDEX"` // this should not be zero
24+
IssueID int64 `xorm:"INDEX"` // maybe zero when creating
25+
ReleaseID int64 `xorm:"INDEX"` // maybe zero when creating
26+
UploaderID int64 `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added
27+
CommentID int64
28+
Name string
29+
DownloadCount int64 `xorm:"DEFAULT 0"`
30+
Size int64 `xorm:"DEFAULT 0"`
31+
CreatedUnix timeutil.TimeStamp `xorm:"created"`
32+
CustomDownloadURL string `xorm:"-"`
3233
}
3334

3435
func init() {
@@ -57,6 +58,10 @@ func (a *Attachment) RelativePath() string {
5758

5859
// DownloadURL returns the download url of the attached file
5960
func (a *Attachment) DownloadURL() string {
61+
if a.CustomDownloadURL != "" {
62+
return a.CustomDownloadURL
63+
}
64+
6065
return setting.AppURL + "attachments/" + url.PathEscape(a.UUID)
6166
}
6267

models/repo/release.go

+29
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package repo
77
import (
88
"context"
99
"fmt"
10+
"net/url"
1011
"sort"
1112
"strconv"
1213
"strings"
@@ -372,6 +373,34 @@ func GetReleaseAttachments(ctx context.Context, rels ...*Release) (err error) {
372373
sortedRels.Rel[currentIndex].Attachments = append(sortedRels.Rel[currentIndex].Attachments, attachment)
373374
}
374375

376+
// Makes URL's predictable
377+
for _, release := range rels {
378+
// If we have no Repo, we don't need to execute this loop
379+
if release.Repo == nil {
380+
continue
381+
}
382+
383+
// Check if there are two or more attachments with the same name
384+
hasDuplicates := false
385+
foundNames := make(map[string]bool)
386+
for _, attachment := range release.Attachments {
387+
_, found := foundNames[attachment.Name]
388+
if found {
389+
hasDuplicates = true
390+
break
391+
} else {
392+
foundNames[attachment.Name] = true
393+
}
394+
}
395+
396+
// If the names unique, use the URL with the Name instead of the UUID
397+
if !hasDuplicates {
398+
for _, attachment := range release.Attachments {
399+
attachment.CustomDownloadURL = release.Repo.HTMLURL() + "/releases/download/" + url.PathEscape(release.TagName) + "/" + url.PathEscape(attachment.Name)
400+
}
401+
}
402+
}
403+
375404
return err
376405
}
377406

routers/web/repo/attachment.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ func DeleteAttachment(ctx *context.Context) {
8686
})
8787
}
8888

89-
// GetAttachment serve attachments
90-
func GetAttachment(ctx *context.Context) {
91-
attach, err := repo_model.GetAttachmentByUUID(ctx, ctx.Params(":uuid"))
89+
// GetAttachment serve attachments with the given UUID
90+
func ServeAttachment(ctx *context.Context, uuid string) {
91+
attach, err := repo_model.GetAttachmentByUUID(ctx, uuid)
9292
if err != nil {
9393
if repo_model.IsErrAttachmentNotExist(err) {
9494
ctx.Error(http.StatusNotFound)
@@ -153,3 +153,8 @@ func GetAttachment(ctx *context.Context) {
153153
return
154154
}
155155
}
156+
157+
// GetAttachment serve attachments
158+
func GetAttachment(ctx *context.Context) {
159+
ServeAttachment(ctx, ctx.Params(":uuid"))
160+
}

routers/web/repo/release.go

+6
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
142142
return
143143
}
144144

145+
for _, release := range releases {
146+
release.Repo = ctx.Repo.Repository
147+
}
148+
145149
if err = repo_model.GetReleaseAttachments(ctx, releases...); err != nil {
146150
ctx.ServerError("GetReleaseAttachments", err)
147151
return
@@ -248,6 +252,8 @@ func SingleRelease(ctx *context.Context) {
248252
ctx.Data["Title"] = release.Title
249253
}
250254

255+
release.Repo = ctx.Repo.Repository
256+
251257
err = repo_model.GetReleaseAttachments(ctx, release)
252258
if err != nil {
253259
ctx.ServerError("GetReleaseAttachments", err)

routers/web/repo/repo.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ func RedirectDownload(ctx *context.Context) {
373373
return
374374
}
375375
if att != nil {
376-
ctx.Redirect(att.DownloadURL())
376+
ServeAttachment(ctx, att.UUID)
377377
return
378378
}
379379
}

0 commit comments

Comments
 (0)