@@ -151,6 +151,11 @@ func GetAttachmentByUUID(uuid string) (*Attachment, error) { | |||||
return getAttachmentByUUID(x, uuid) | return getAttachmentByUUID(x, uuid) | ||||
} | } | ||||
// GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName. | |||||
func GetAttachmentByReleaseIDFileName(releaseID int64, fileName string) (*Attachment, error) { | |||||
return getAttachmentByReleaseIDFileName(x, releaseID, fileName) | |||||
} | |||||
func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) { | func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) { | ||||
attachments := make([]*Attachment, 0, 10) | attachments := make([]*Attachment, 0, 10) | ||||
return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments) | return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments) | ||||
@@ -171,6 +176,18 @@ func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) | |||||
return attachments, x.Where("comment_id=?", commentID).Find(&attachments) | return attachments, x.Where("comment_id=?", commentID).Find(&attachments) | ||||
} | } | ||||
// getAttachmentByReleaseIDFileName return a file based on the the following infos: | |||||
func getAttachmentByReleaseIDFileName(e 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. | // DeleteAttachment deletes the given attachment and optionally the associated file. | ||||
func DeleteAttachment(a *Attachment, remove bool) error { | func DeleteAttachment(a *Attachment, remove bool) error { | ||||
_, err := DeleteAttachments([]*Attachment{a}, remove) | _, err := DeleteAttachments([]*Attachment{a}, remove) | ||||
@@ -14,6 +14,7 @@ import ( | |||||
"code.gitea.io/gitea/modules/process" | "code.gitea.io/gitea/modules/process" | ||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/util" | "code.gitea.io/gitea/modules/util" | ||||
api "code.gitea.io/sdk/gitea" | api "code.gitea.io/sdk/gitea" | ||||
"github.com/go-xorm/builder" | "github.com/go-xorm/builder" | ||||
) | ) | ||||
@@ -283,6 +284,15 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions, page, pageSize | |||||
return rels, err | return rels, err | ||||
} | } | ||||
// GetReleasesByRepoIDAndNames returns a list of releases of repository according repoID and tagNames. | |||||
func GetReleasesByRepoIDAndNames(repoID int64, tagNames []string) (rels []*Release, err error) { | |||||
err = x. | |||||
Desc("created_unix"). | |||||
In("tag_name", tagNames). | |||||
Find(&rels, Release{RepoID: repoID}) | |||||
return rels, err | |||||
} | |||||
// GetReleaseCountByRepoID returns the count of releases of repository | // GetReleaseCountByRepoID returns the count of releases of repository | ||||
func GetReleaseCountByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) { | func GetReleaseCountByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) { | ||||
return x.Where(opts.toConds(repoID)).Count(&Release{}) | return x.Where(opts.toConds(repoID)).Count(&Release{}) | ||||
@@ -310,6 +310,38 @@ func Action(ctx *context.Context) { | |||||
ctx.RedirectToFirst(ctx.Query("redirect_to"), ctx.Repo.RepoLink) | ctx.RedirectToFirst(ctx.Query("redirect_to"), ctx.Repo.RepoLink) | ||||
} | } | ||||
// RedirectDownload return a file based on the following infos: | |||||
func RedirectDownload(ctx *context.Context) { | |||||
var ( | |||||
vTag = ctx.Params("vTag") | |||||
fileName = ctx.Params("fileName") | |||||
) | |||||
tagNames := []string{vTag} | |||||
curRepo := ctx.Repo.Repository | |||||
releases, err := models.GetReleasesByRepoIDAndNames(curRepo.ID, tagNames) | |||||
if err != nil { | |||||
if models.IsErrAttachmentNotExist(err) { | |||||
ctx.Error(404) | |||||
return | |||||
} | |||||
ctx.ServerError("RedirectDownload", err) | |||||
return | |||||
} | |||||
if len(releases) == 1 { | |||||
release := releases[0] | |||||
att, err := models.GetAttachmentByReleaseIDFileName(release.ID, fileName) | |||||
if err != nil { | |||||
ctx.Error(404) | |||||
return | |||||
} | |||||
if att != nil { | |||||
ctx.Redirect(setting.AppSubURL + "/attachments/" + att.UUID) | |||||
return | |||||
} | |||||
} | |||||
ctx.Error(404) | |||||
} | |||||
// Download download an archive of a repository | // Download download an archive of a repository | ||||
func Download(ctx *context.Context) { | func Download(ctx *context.Context) { | ||||
var ( | var ( | ||||
@@ -475,6 +475,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
}, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader) | }, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader) | ||||
}, reqSignIn) | }, reqSignIn) | ||||
// ***** Release Attachment Download without Signin | |||||
m.Get("/:username/:reponame/releases/download/:vTag/:fileName", ignSignIn, context.RepoAssignment(), repo.MustBeNotBare, repo.RedirectDownload) | |||||
m.Group("/:username/:reponame", func() { | m.Group("/:username/:reponame", func() { | ||||
m.Group("/settings", func() { | m.Group("/settings", func() { | ||||
m.Combo("").Get(repo.Settings). | m.Combo("").Get(repo.Settings). | ||||
@@ -14,7 +14,7 @@ | |||||
{{end}} | {{end}} | ||||
</h2> | </h2> | ||||
<ul id="release-list"> | <ul id="release-list"> | ||||
{{range .Releases}} | |||||
{{range $release := .Releases}} | |||||
<li class="ui grid"> | <li class="ui grid"> | ||||
<div class="ui four wide column meta"> | <div class="ui four wide column meta"> | ||||
{{if .IsTag}} | {{if .IsTag}} | ||||
@@ -75,14 +75,14 @@ | |||||
</li> | </li> | ||||
{{end}} | {{end}} | ||||
{{if .Attachments}} | {{if .Attachments}} | ||||
{{range .Attachments}} | |||||
<li> | |||||
<a target="_blank" rel="noopener noreferrer" href="{{AppSubUrl}}/attachments/{{.UUID}}"> | |||||
<strong><span class="ui image octicon octicon-package" title='{{.Name}}'></span> {{.Name}}</strong> | |||||
<span class="ui text grey right">{{.Size | FileSize}}</span> | |||||
</a> | |||||
</li> | |||||
{{end}} | |||||
{{range $attachment := .Attachments}} | |||||
<li> | |||||
<a target="_blank" rel="noopener noreferrer" href="{{$.RepoLink}}/releases/download/{{$release.TagName}}/{{$attachment.Name}}"> | |||||
<strong><span class="ui image octicon octicon-package" title='{{$attachment.Name}}'></span> {{$attachment.Name}}</strong> | |||||
<span class="ui text grey right">{{$attachment.Size | FileSize}}</span> | |||||
</a> | |||||
</li> | |||||
{{end}} | |||||
{{end}} | {{end}} | ||||
</ul> | </ul> | ||||
</div> | </div> | ||||