From 09fb036ad625ec5178319c30df47aac313fdbbe3 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Wed, 3 Apr 2019 03:25:05 +0800
Subject: [PATCH] fix upload attachments (#6481)

* fix upload attachments

* add migration for new column uploader_id on table attachment

* fix imports sequence
---
 models/attachment.go                      |  9 +++----
 models/attachment_test.go                 | 29 +++++++++++++++++++++++
 models/migrations/migrations.go           |  2 ++
 models/migrations/v83.go                  | 28 ++++++++++++++++++++++
 routers/api/v1/repo/release_attachment.go | 12 +++++-----
 routers/repo/attachment.go                |  5 +++-
 routers/routes/routes.go                  |  5 +++-
 7 files changed, 76 insertions(+), 14 deletions(-)
 create mode 100644 models/migrations/v83.go

diff --git a/models/attachment.go b/models/attachment.go
index 808bc243dc..bbb88939b1 100644
--- a/models/attachment.go
+++ b/models/attachment.go
@@ -7,7 +7,6 @@ package models
 import (
 	"fmt"
 	"io"
-	"mime/multipart"
 	"os"
 	"path"
 
@@ -25,6 +24,7 @@ type Attachment struct {
 	UUID          string `xorm:"uuid UNIQUE"`
 	IssueID       int64  `xorm:"INDEX"`
 	ReleaseID     int64  `xorm:"INDEX"`
+	UploaderID    int64  `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added
 	CommentID     int64
 	Name          string
 	DownloadCount int64          `xorm:"DEFAULT 0"`
@@ -72,11 +72,8 @@ func (a *Attachment) DownloadURL() string {
 }
 
 // NewAttachment creates a new attachment object.
-func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) {
-	attach := &Attachment{
-		UUID: gouuid.NewV4().String(),
-		Name: name,
-	}
+func NewAttachment(attach *Attachment, buf []byte, file io.Reader) (_ *Attachment, err error) {
+	attach.UUID = gouuid.NewV4().String()
 
 	localPath := attach.LocalPath()
 	if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
diff --git a/models/attachment_test.go b/models/attachment_test.go
index be4baf3055..3984425e48 100644
--- a/models/attachment_test.go
+++ b/models/attachment_test.go
@@ -5,11 +5,40 @@
 package models
 
 import (
+	"os"
+	"path/filepath"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
+func TestUploadAttachment(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+
+	var fPath = "./attachment_test.go"
+	f, err := os.Open(fPath)
+	assert.NoError(t, err)
+	defer f.Close()
+
+	var buf = make([]byte, 1024)
+	n, err := f.Read(buf)
+	assert.NoError(t, err)
+	buf = buf[:n]
+
+	attach, err := NewAttachment(&Attachment{
+		UploaderID: user.ID,
+		Name:       filepath.Base(fPath),
+	}, buf, f)
+	assert.NoError(t, err)
+
+	attachment, err := GetAttachmentByUUID(attach.UUID)
+	assert.NoError(t, err)
+	assert.EqualValues(t, user.ID, attachment.UploaderID)
+	assert.Equal(t, int64(0), attachment.DownloadCount)
+}
+
 func TestIncreaseDownloadCount(t *testing.T) {
 	assert.NoError(t, PrepareTestDatabase())
 
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index fda37f8da8..baedcbb715 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -219,6 +219,8 @@ var migrations = []Migration{
 	NewMigration("update U2F counter type", changeU2FCounterType),
 	// v82 -> v83
 	NewMigration("hot fix for wrong release sha1 on release table", fixReleaseSha1OnReleaseTable),
+	// v83 -> v84
+	NewMigration("add uploader id for table attachment", addUploaderIDForAttachment),
 }
 
 // Migrate database to current version
diff --git a/models/migrations/v83.go b/models/migrations/v83.go
new file mode 100644
index 0000000000..947645153c
--- /dev/null
+++ b/models/migrations/v83.go
@@ -0,0 +1,28 @@
+// Copyright 2019 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 (
+	"code.gitea.io/gitea/modules/util"
+
+	"github.com/go-xorm/xorm"
+)
+
+func addUploaderIDForAttachment(x *xorm.Engine) error {
+	type Attachment struct {
+		ID            int64  `xorm:"pk autoincr"`
+		UUID          string `xorm:"uuid UNIQUE"`
+		IssueID       int64  `xorm:"INDEX"`
+		ReleaseID     int64  `xorm:"INDEX"`
+		UploaderID    int64  `xorm:"INDEX DEFAULT 0"`
+		CommentID     int64
+		Name          string
+		DownloadCount int64          `xorm:"DEFAULT 0"`
+		Size          int64          `xorm:"DEFAULT 0"`
+		CreatedUnix   util.TimeStamp `xorm:"created"`
+	}
+
+	return x.Sync2(new(Attachment))
+}
diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go
index 50107dd44e..5efdd69817 100644
--- a/routers/api/v1/repo/release_attachment.go
+++ b/routers/api/v1/repo/release_attachment.go
@@ -200,16 +200,16 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
 	}
 
 	// Create a new attachment and save the file
-	attach, err := models.NewAttachment(filename, buf, file)
+	attach, err := models.NewAttachment(&models.Attachment{
+		UploaderID: ctx.User.ID,
+		Name:       filename,
+		ReleaseID:  release.ID,
+	}, buf, file)
 	if err != nil {
 		ctx.Error(500, "NewAttachment", err)
 		return
 	}
-	attach.ReleaseID = release.ID
-	if err := models.UpdateAttachment(attach); err != nil {
-		ctx.Error(500, "UpdateAttachment", err)
-		return
-	}
+
 	ctx.JSON(201, attach.APIFormat())
 }
 
diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go
index 302f5b33f7..8913e63015 100644
--- a/routers/repo/attachment.go
+++ b/routers/repo/attachment.go
@@ -60,7 +60,10 @@ func UploadAttachment(ctx *context.Context) {
 		return
 	}
 
-	attach, err := models.NewAttachment(header.Filename, buf, file)
+	attach, err := models.NewAttachment(&models.Attachment{
+		UploaderID: ctx.User.ID,
+		Name:       header.Filename,
+	}, buf, file)
 	if err != nil {
 		ctx.Error(500, fmt.Sprintf("NewAttachment: %v", err))
 		return
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 2d720b3c5c..5c6d36befa 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -480,9 +480,12 @@ func RegisterRoutes(m *macaron.Macaron) {
 				return
 			}
 		})
-		m.Post("/attachments", repo.UploadAttachment)
 	}, ignSignIn)
 
+	m.Group("", func() {
+		m.Post("/attachments", repo.UploadAttachment)
+	}, reqSignIn)
+
 	m.Group("/:username", func() {
 		m.Get("/action/:action", user.Action)
 	}, reqSignIn)