You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
3.6 KiB
Go
181 lines
3.6 KiB
Go
package storage
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
|
|
"git.sp4ke.com/sp4ke/bit4sat/utils"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/segmentio/ksuid"
|
|
)
|
|
|
|
type UploadCtrl struct{}
|
|
|
|
func (ctrl UploadCtrl) New(c *gin.Context) {
|
|
uploadForm := UploadForm{}
|
|
|
|
if err := c.ShouldBindJSON(&uploadForm); err != nil {
|
|
utils.JSONErr(c, http.StatusNotAcceptable,
|
|
"could not parse form")
|
|
return
|
|
}
|
|
|
|
// Create unique id
|
|
id := ksuid.New()
|
|
up := NewUpload()
|
|
up.ID = id.String()
|
|
up.Status = UpNew
|
|
|
|
for _, file := range uploadForm.Files {
|
|
upfile := &UpFile{}
|
|
|
|
upfile.FileName, upfile.FileExt = utils.CleanFileName(file.Name)
|
|
upfile.FileSize = file.Size
|
|
upfile.FileType = file.Type
|
|
|
|
up.Files[SHA256(file.SHA256)] = upfile
|
|
}
|
|
|
|
err := up.Write()
|
|
if err != nil {
|
|
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
log.Println("new upload created")
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": http.StatusOK,
|
|
"result": gin.H{
|
|
"id": id,
|
|
},
|
|
})
|
|
}
|
|
|
|
func (ctrl UploadCtrl) Upload(c *gin.Context) {
|
|
|
|
// Check that upload ID exists
|
|
id := c.Param("id")
|
|
|
|
exists, err := IdExists(id)
|
|
if err != nil {
|
|
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
if !exists {
|
|
utils.JSONErr(c, http.StatusNotFound, "id not found")
|
|
return
|
|
}
|
|
|
|
form, err := c.MultipartForm()
|
|
if err != nil {
|
|
utils.JSONErr(c, http.StatusNotAcceptable,
|
|
fmt.Sprintf("Could not parse form: %s", err.Error()))
|
|
return
|
|
}
|
|
|
|
// Get the file's metadata from upload collection
|
|
up, err := GetByID(id)
|
|
if err != nil {
|
|
utils.JSONErrPriv(c, http.StatusNotFound, err)
|
|
return
|
|
}
|
|
|
|
log.Printf("Found matching upload %s", up.ID)
|
|
|
|
if up.Status == UpStored {
|
|
utils.JSONErr(c, http.StatusConflict, "already uploaded")
|
|
return
|
|
}
|
|
|
|
files := form.File["upload[]"]
|
|
|
|
var storedFiles []string
|
|
|
|
for _, file := range files {
|
|
log.Printf("Handling %s", file.Filename)
|
|
|
|
// Get the form's file sha256
|
|
hasher := sha256.New()
|
|
|
|
formFd, err := file.Open()
|
|
defer formFd.Close()
|
|
|
|
if err != nil {
|
|
utils.JSONErr(
|
|
c, http.StatusInternalServerError,
|
|
fmt.Sprintf("Could not read file %s", file.Filename),
|
|
)
|
|
return
|
|
}
|
|
|
|
_, err = io.Copy(hasher, formFd)
|
|
if err != nil {
|
|
utils.JSONErr(c, http.StatusInternalServerError, "")
|
|
return
|
|
}
|
|
|
|
sum256 := hex.EncodeToString(hasher.Sum(nil))
|
|
|
|
// Check sha256 same as present metadata
|
|
fileMeta, same := up.Files[SHA256(sum256)]
|
|
if !same {
|
|
utils.JSONErr(c, http.StatusConflict,
|
|
fmt.Sprintf("wrong hash for %s", file.Filename),
|
|
)
|
|
return
|
|
}
|
|
|
|
// Store file
|
|
|
|
log.Printf("Storing file %s", file.Filename)
|
|
err = storeFormFile(formFd, sum256+fileMeta.FileExt)
|
|
if err != nil {
|
|
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
|
|
removeFiles(storedFiles)
|
|
return
|
|
}
|
|
|
|
storedFiles = append(storedFiles, GetStoreDestination(sum256+fileMeta.FileExt))
|
|
|
|
log.Printf("%s stored at %s", fileMeta.FileName,
|
|
GetStoreDestination(sum256+fileMeta.FileExt))
|
|
|
|
// Setting status to stored
|
|
//log.Println("Updating upload status to stored")
|
|
//up.Status = UpStored
|
|
//err = up.TxSetState(tx, UpStored)
|
|
//if err != nil {
|
|
//utils.JSONErrPriv(c, http.StatusInternalServerError, err)
|
|
//db.RollbackTx(tx, func() {
|
|
//err := os.Remove(GetStoreDestination(up.SHA256 + up.FileExt))
|
|
//if err != nil {
|
|
//log.Println(err)
|
|
//}
|
|
//})
|
|
//return
|
|
//}
|
|
}
|
|
|
|
up.Status = UpStored
|
|
|
|
// Commit
|
|
err = up.Write()
|
|
|
|
if err != nil {
|
|
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
|
|
removeFiles(storedFiles)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": http.StatusOK,
|
|
"result": fmt.Sprintf("%d files uploaded uploaded !", len(files)),
|
|
})
|
|
|
|
}
|