* Add size column to attachment Migrate attachments by calculating file sizes Signed-off-by: Jonas Franz <info@jonasfranz.software> * Calculate attachment size on creation Signed-off-by: Jonas Franz <info@jonasfranz.software> * Log error instead of returning error Signed-off-by: Jonas Franz <info@jonasfranz.software>tags/v1.21.12.1
| @@ -11,7 +11,6 @@ import ( | |||||
| "os" | "os" | ||||
| "path" | "path" | ||||
| "code.gitea.io/gitea/modules/log" | |||||
| "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" | ||||
| @@ -29,6 +28,7 @@ type Attachment struct { | |||||
| CommentID int64 | CommentID int64 | ||||
| Name string | Name string | ||||
| DownloadCount int64 `xorm:"DEFAULT 0"` | DownloadCount int64 `xorm:"DEFAULT 0"` | ||||
| Size int64 `xorm:"DEFAULT 0"` | |||||
| CreatedUnix util.TimeStamp `xorm:"created"` | CreatedUnix util.TimeStamp `xorm:"created"` | ||||
| } | } | ||||
| @@ -44,13 +44,12 @@ func (a *Attachment) IncreaseDownloadCount() error { | |||||
| // APIFormat converts models.Attachment to api.Attachment | // APIFormat converts models.Attachment to api.Attachment | ||||
| func (a *Attachment) APIFormat() *api.Attachment { | func (a *Attachment) APIFormat() *api.Attachment { | ||||
| size, _ := a.Size() | |||||
| return &api.Attachment{ | return &api.Attachment{ | ||||
| ID: a.ID, | ID: a.ID, | ||||
| Name: a.Name, | Name: a.Name, | ||||
| Created: a.CreatedUnix.AsTime(), | Created: a.CreatedUnix.AsTime(), | ||||
| DownloadCount: a.DownloadCount, | DownloadCount: a.DownloadCount, | ||||
| Size: size, | |||||
| Size: a.Size, | |||||
| UUID: a.UUID, | UUID: a.UUID, | ||||
| DownloadURL: a.DownloadURL(), | DownloadURL: a.DownloadURL(), | ||||
| } | } | ||||
| @@ -67,25 +66,6 @@ func (a *Attachment) LocalPath() string { | |||||
| return AttachmentLocalPath(a.UUID) | return AttachmentLocalPath(a.UUID) | ||||
| } | } | ||||
| // Size returns the file's size of the attachment | |||||
| func (a *Attachment) Size() (int64, error) { | |||||
| fi, err := os.Stat(a.LocalPath()) | |||||
| if err != nil { | |||||
| return 0, err | |||||
| } | |||||
| return fi.Size(), nil | |||||
| } | |||||
| // MustSize returns the result of a.Size() by ignoring errors | |||||
| func (a *Attachment) MustSize() int64 { | |||||
| size, err := a.Size() | |||||
| if err != nil { | |||||
| log.Error(4, "size: %v", err) | |||||
| return 0 | |||||
| } | |||||
| return size | |||||
| } | |||||
| // DownloadURL returns the download url of the attached file | // DownloadURL returns the download url of the attached file | ||||
| func (a *Attachment) DownloadURL() string { | func (a *Attachment) DownloadURL() string { | ||||
| return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) | return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) | ||||
| @@ -115,6 +95,13 @@ func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, | |||||
| return nil, fmt.Errorf("Copy: %v", err) | return nil, fmt.Errorf("Copy: %v", err) | ||||
| } | } | ||||
| // Update file size | |||||
| var fi os.FileInfo | |||||
| if fi, err = fw.Stat(); err != nil { | |||||
| return nil, fmt.Errorf("file size: %v", err) | |||||
| } | |||||
| attach.Size = fi.Size() | |||||
| if _, err := x.Insert(attach); err != nil { | if _, err := x.Insert(attach); err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -174,6 +174,8 @@ var migrations = []Migration{ | |||||
| NewMigration("add merge whitelist for protected branches", addProtectedBranchMergeWhitelist), | NewMigration("add merge whitelist for protected branches", addProtectedBranchMergeWhitelist), | ||||
| // v60 -> v61 | // v60 -> v61 | ||||
| NewMigration("add is_fsck_enabled column for repos", addFsckEnabledToRepo), | NewMigration("add is_fsck_enabled column for repos", addFsckEnabledToRepo), | ||||
| // v61 -> v62 | |||||
| NewMigration("add size column for attachments", addSizeToAttachment), | |||||
| } | } | ||||
| // Migrate database to current version | // Migrate database to current version | ||||
| @@ -0,0 +1,45 @@ | |||||
| // Copyright 2018 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 migrations | |||||
| import ( | |||||
| "fmt" | |||||
| "os" | |||||
| "path" | |||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "github.com/go-xorm/xorm" | |||||
| ) | |||||
| func addSizeToAttachment(x *xorm.Engine) error { | |||||
| type Attachment struct { | |||||
| ID int64 `xorm:"pk autoincr"` | |||||
| UUID string `xorm:"uuid UNIQUE"` | |||||
| Size int64 `xorm:"DEFAULT 0"` | |||||
| } | |||||
| if err := x.Sync2(new(Attachment)); err != nil { | |||||
| return fmt.Errorf("Sync2: %v", err) | |||||
| } | |||||
| attachments := make([]Attachment, 0, 100) | |||||
| if err := x.Find(&attachments); err != nil { | |||||
| return fmt.Errorf("query attachments: %v", err) | |||||
| } | |||||
| for _, attach := range attachments { | |||||
| localPath := path.Join(setting.AttachmentPath, attach.UUID[0:1], attach.UUID[1:2], attach.UUID) | |||||
| fi, err := os.Stat(localPath) | |||||
| if err != nil { | |||||
| log.Error(4, "calculate file size of attachment[UUID: %s]: %v", attach.UUID, err) | |||||
| continue | |||||
| } | |||||
| attach.Size = fi.Size() | |||||
| if _, err := x.ID(attach.ID).Cols("size").Update(attach); err != nil { | |||||
| return fmt.Errorf("update size column: %v", err) | |||||
| } | |||||
| } | |||||
| return nil | |||||
| } | |||||
| @@ -79,7 +79,7 @@ | |||||
| <li> | <li> | ||||
| <a target="_blank" rel="noopener" href="{{AppSubUrl}}/attachments/{{.UUID}}"> | <a target="_blank" rel="noopener" href="{{AppSubUrl}}/attachments/{{.UUID}}"> | ||||
| <strong><span class="ui image octicon octicon-package" title='{{.Name}}'></span> {{.Name}}</strong> | <strong><span class="ui image octicon octicon-package" title='{{.Name}}'></span> {{.Name}}</strong> | ||||
| <span class="ui text grey right">{{.MustSize | FileSize}}</span> | |||||
| <span class="ui text grey right">{{.Size | FileSize}}</span> | |||||
| </a> | </a> | ||||
| </li> | </li> | ||||
| {{end}} | {{end}} | ||||