package storage import ( "crypto/sha256" "encoding/hex" "fmt" "io" "log" "net/http" "os" "git.sp4ke.com/sp4ke/bit4sat/db" "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() tx, err := db.DB.Sql.Beginx() if err != nil { utils.JSONErrPriv(c, http.StatusInternalServerError, err) return } for _, file := range uploadForm.Files { up := &Upload{} up.ID = id.String() log.Println(file.Name) up.FileName, up.FileExt = utils.CleanFileName(file.Name) up.FileSize = file.Size up.FileType = file.Type up.SHA256 = file.SHA256 up.Status = UpNew err := up.TxWrite(tx) if err != nil { utils.JSONErrPriv(c, http.StatusInternalServerError, err) db.RollbackTx(tx, nil) return } } err = tx.Commit() 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 } files := form.File["upload[]"] tx, err := db.DB.Sql.Beginx() if err != nil { utils.JSONErrPriv(c, http.StatusInternalServerError, err) return } for _, file := range files { log.Printf("Handling %s", file.Filename) // Get the file's 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), ) db.RollbackTx(tx, nil) return } _, err = io.Copy(hasher, formFd) if err != nil { utils.JSONErr(c, http.StatusInternalServerError, "") db.RollbackTx(tx, nil) return } sum256 := hex.EncodeToString(hasher.Sum(nil)) // Get the file's metadata from upload table up, err := GetByHashID(sum256, id) if err != nil { utils.JSONErrPriv(c, http.StatusNotFound, err) db.RollbackTx(tx, nil) return } log.Printf("Found received file's %s metadata in local database\n", up.FileName) //log.Println(up) // Store file if up.Status == UpStored { utils.JSONErr(c, http.StatusConflict, fmt.Sprintf("%s already uploaded", up.FileName)) return } // // log.Println("Storing file") err = StoreFormFile(formFd, up.SHA256+up.FileExt) if err != nil { utils.JSONErrPriv(c, http.StatusInternalServerError, err) db.RollbackTx(tx, nil) return } log.Printf("%s stored at %s", up.FileName, GetStoreDestination(up.SHA256+up.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 } } err = tx.Commit() if err != nil { utils.JSONErrPriv(c, http.StatusInternalServerError, err) return } c.JSON(http.StatusOK, gin.H{ "status": http.StatusOK, "result": fmt.Sprintf("%d files uploaded uploaded !", len(files)), }) }