Skip to content

Added URL mapping for Release attachments like on github.com #1707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions models/attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
gouuid "github.com/satori/go.uuid"

"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)

// Attachment represent a attachment of issue/comment/release.
Expand Down Expand Up @@ -58,6 +59,15 @@ func (a *Attachment) IncreaseDownloadCount() error {
return nil
}

// FileSize is returning the file datasize
func (a *Attachment) FileSize() (string, error) {
stats, err := os.Stat(AttachmentLocalPath(a.UUID))
if err != nil {
return "error", fmt.Errorf("AttachmentFileSize: %v", err)
}
return util.FormatFileSize(stats.Size()), nil
}

// AttachmentLocalPath returns where attachment is stored in local file
// system based on given UUID.
func AttachmentLocalPath(uuid string) string {
Expand Down Expand Up @@ -126,6 +136,11 @@ func GetAttachmentByUUID(uuid string) (*Attachment, error) {
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) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
Expand All @@ -142,6 +157,18 @@ func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
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.
func DeleteAttachment(a *Attachment, remove bool) error {
_, err := DeleteAttachments([]*Attachment{a}, remove)
Expand Down
38 changes: 38 additions & 0 deletions models/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ package models

import (
"fmt"
"path"
"sort"
"strings"
"time"

"code.gitea.io/git"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"

api "code.gitea.io/sdk/gitea"
"github.com/go-xorm/xorm"
)
Expand Down Expand Up @@ -73,6 +76,41 @@ func (r *Release) loadAttributes(e Engine) error {
return nil
}

// buildArchivePath construct the correct archive path for the release
func buildArchivePath(r *Release, isZip bool) string {
repoPath := setting.RepoRootPath
repo := &Repository{ID: r.RepoID}
_, err := x.Get(repo)
if err != nil {
return "buildArchivePath -> Unknow Repository"
}
user := r.Publisher
var subPath, typ, ext string
if isZip {
subPath = "archives"
typ = "zip"
ext = ".zip"
} else {
subPath = "archives"
typ = "targz"
ext = ".tar.gz"
}
result := path.Join(repoPath, user.LowerName, repo.Name+".git", subPath, typ, r.Sha1[0:10]) + ext
return result
}

// GetReleaseZIPFileSize returns the ZIP file size
func (r *Release) GetReleaseZIPFileSize() string {
archivePath := buildArchivePath(r, true)
return util.FormatFileSize(util.GetFileSize(archivePath))
}

// GetReleaseTARFileSize returns the TAR file size
func (r *Release) GetReleaseTARFileSize() string {
archivePath := buildArchivePath(r, false)
return util.FormatFileSize(util.GetFileSize(archivePath))
}

// LoadAttributes load repo and publisher attributes for a release
func (r *Release) LoadAttributes() error {
return r.loadAttributes(x)
Expand Down
52 changes: 52 additions & 0 deletions modules/util/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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 util

import (
"fmt"
"os"
)

// FormatFileSizeToMB formats the filesize
func FormatFileSize(bytes int64) string {
var result float64
var format string
var measure string
if bytes < 10240 { // bytes
result = float64(bytes) / float64(1048)
measure = "Bytes"
} else if bytes < 1048576 { // kbytes
result = float64(bytes) / float64(102400)
measure = "KB"
} else if bytes < 1048576000 { // mbytes
result = float64(bytes) / float64(1048576)
measure = "MB"
} else if bytes < 1048576000000 { // gbytes
result = float64(bytes) / float64(1048576000)
measure = "GB"
} else if bytes < 1048576000000000 { // tbytes
result = float64(bytes) / float64(1048576000000)
measure = "TB"
}

if result < 0.01 {
format = "%.2f"
result = 0.01
} else if result < 0.1 {
format = "%.2f"
} else {
format = "%.1f"
}
return fmt.Sprintf(format, result) + " " + measure
}

// GetFileSize returns file size
func GetFileSize(path string) int64 {
stats, err := os.Stat(path)
if err != nil {
return -1
}
return stats.Size()
}
31 changes: 31 additions & 0 deletions routers/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,37 @@ func Action(ctx *context.Context) {
ctx.Redirect(redirectTo)
}

// 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.Handle(500, "RedirectDownload: Failed to get attachment", err)
return
}
if len(releases) == 1 {
release := releases[0]
att, err := models.GetAttachmentByReleaseIDFileName(release.ID, fileName)
if err != nil {
ctx.Handle(404, "RedirectDownload -> Attachment not found", err)
return
}
if att != nil {
ctx.Redirect(setting.AppSubURL + "/attachments/" + att.UUID)
}
}
ctx.Handle(404, "RedirectDownload -> Attachment not found", err)
}

// Download download an archive of a repository
func Download(ctx *context.Context) {
var (
Expand Down
10 changes: 10 additions & 0 deletions routers/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,16 @@ func RegisterRoutes(m *macaron.Macaron) {
Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost)
}, reqSignIn)

// ***** Release Attachment Download without Sigin
m.Get("/:username/:reponame/releases/download/:vTag/:fileName", ignSignIn, context.RepoAssignment(), repo.RedirectDownload)
/*
m.Group("/:username/:reponame", func() {
m.Group("/releases", func() {
m.Get("/download/:vTag/:fileName", repo.RedirectDownload)
}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef())
}, ignSignIn)
*/

m.Group("/:username/:reponame", func() {
m.Group("/settings", func() {
m.Combo("").Get(repo.Settings).
Expand Down
29 changes: 18 additions & 11 deletions templates/repo/release/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
{{end}}
</h2>
<ul id="release-list">
{{range .Releases}}
{{range $release := .Releases}}
<li class="ui grid">
<div class="ui four wide column meta">
{{if .PublisherID}}
Expand Down Expand Up @@ -53,21 +53,28 @@
<div class="download">
<h2>{{$.i18n.Tr "repo.release.downloads"}}</h2>
<ul class="list">
{{$tagname := .TagName}}
{{if .Attachments}}
{{range $attachment := .Attachments}}
<li>
<a target="_blank" rel="noopener" href="{{$.RepoLink}}/releases/download/{{$tagname}}/{{$attachment.Name}}">
<span class="ui image octicon octicon-desktop-download" title='{{$attachment.Name}}'></span> {{$attachment.Name}}
<a target="_blank" href="{{$.RepoLink}}/releases/download/{{$tagname}}/{{$attachment.Name}}" class="ui right"><span class="ui image octicon octicon-file-binary" title='{{$attachment.Name}}'></span>{{$attachment.FileSize}}</a>
</a>
</li>
{{end}}
{{end}}
<li>
<a href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="octicon octicon-file-zip"></i> {{$.i18n.Tr "repo.release.source_code"}} (ZIP)</a>
</li>
<li>
<a href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="octicon octicon-file-zip"></i> {{$.i18n.Tr "repo.release.source_code"}} (TAR.GZ)</a>
<a href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="octicon octicon-file-zip"></i> {{$.i18n.Tr "repo.release.source_code"}} (ZIP)
<a target="_blank" href="{{$.RepoLink}}/archive/{{.TagName}}.zip" class="ui right"><span class="ui image octicon octicon-file-binary"></span>{{$release.GetReleaseZIPFileSize}}</a>
</a>
</li>
{{if .Attachments}}
{{range .Attachments}}
<li>
<a target="_blank" rel="noopener" href="{{AppSubUrl}}/attachments/{{.UUID}}">
<span class="ui image octicon octicon-desktop-download" title='{{.Name}}'></span> {{.Name}}
<a href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="octicon octicon-file-zip"></i> {{$.i18n.Tr "repo.release.source_code"}} (TAR.GZ)
<a target="_blank" href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz" class="ui right"><span class="ui image octicon octicon-file-binary"></span>{{$release.GetReleaseTARFileSize}}</a>
</a>
</li>
{{end}}
{{end}}

</ul>
</div>
{{else}}
Expand Down