VILLASweb-backend-go/routes/file/fileMethods.go
2019-06-05 13:12:23 +02:00

208 lines
4.3 KiB
Go

package file
import (
"fmt"
"io"
"mime/multipart"
"os"
"path/filepath"
"strconv"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/widget"
)
type File struct {
common.File
}
func (f *File) byPath(path string) error {
db := common.GetDB()
err := db.Where("Path = ?", path).Find(f).Error
if err != nil {
return fmt.Errorf("File with path=%s does not exist", path)
}
return err
}
func (f *File) byID(id uint) error {
db := common.GetDB()
err := db.Find(f, id).Error
if err != nil {
return fmt.Errorf("File with id=%v does not exist", id)
}
return nil
}
func (f *File) save() error {
// get last modify time of target file
fileinfo, err := os.Stat(f.Path)
if err != nil {
return fmt.Errorf("error stat on file: %s", err.Error())
}
f.Date = fileinfo.ModTime()
f.ImageWidth = 0
f.ImageHeight = 0
db := common.GetDB()
err = db.Create(f).Error
return err
}
func (f *File) register(fileHeader *multipart.FileHeader, objectType string, objectID uint) error {
// Obtain properties of file
f.Type = fileHeader.Header.Get("Content-Type")
f.Name = filepath.Base(fileHeader.Filename)
f.Path = filepath.Join(getFolderName(objectType, objectID), f.Name)
f.Size = uint(fileHeader.Size)
var m simulationmodel.SimulationModel
var w widget.Widget
var err error
if objectType == "model" {
// check if model exists
err = m.ByID(objectID)
if err != nil {
return err
}
} else {
// check if widget exists
err = w.ByID(uint(objectID))
if err != nil {
return err
}
}
// Save file to local disc (NOT DB!)
err = f.modifyFileOnDisc(fileHeader, true)
if err != nil {
return fmt.Errorf("File could not be saved/ modified on disk: ", err.Error())
}
// Add File object with parameters to DB
err = f.save()
if err != nil {
return err
}
// Create association to model or widget
if objectType == "model" {
err = f.addToModel(m)
if err != nil {
return err
}
} else {
err = f.addToWidget(w)
if err != nil {
return err
}
}
return nil
}
func (f *File) update(fileHeader *multipart.FileHeader) error {
err := f.modifyFileOnDisc(fileHeader, false)
if err != nil {
return err
}
db := common.GetDB()
err = db.Model(f).Update("Size", fileHeader.Size).Error
return err
}
func (f *File) modifyFileOnDisc(fileHeader *multipart.FileHeader, createFile bool) error {
//filesavepath := filepath.Join(foldername, filename)
var err error
if createFile {
// Ensure folder with name foldername exists
err = os.MkdirAll(f.Path, os.ModePerm)
} else {
// test if file exists
_, err = os.Stat(f.Path)
}
if err != nil {
return err
}
var open_options int
if createFile {
// create file it not exists, file MUST not exist
open_options = os.O_RDWR | os.O_CREATE | os.O_EXCL
} else {
open_options = os.O_RDWR
}
fileTarget, err := os.OpenFile(f.Path, open_options, 0666)
if err != nil {
return err
}
defer fileTarget.Close()
// Save file to target path
uploadedFile, err := fileHeader.Open()
if err != nil {
return err
}
defer uploadedFile.Close()
var uploadContent = make([]byte, f.Size)
for {
n, err := uploadedFile.Read(uploadContent)
if err != nil && err != io.EOF {
return err
}
if n == 0 {
break
}
_, err = fileTarget.Write(uploadContent[:n])
if err != nil {
return err
}
}
return err
}
func (f *File) download(c *gin.Context) {
//Seems this headers needed for some browsers (for example without this headers Chrome will download files as txt)
c.Header("Content-Description", "File Transfer")
c.Header("Content-Transfer-Encoding", "binary")
c.Header("Content-Disposition", "attachment; filename="+f.Name)
//c.Header("Content-Type", contentType)
c.File(f.Path)
}
func (f *File) addToModel(model simulationmodel.SimulationModel) error {
db := common.GetDB()
err := db.Model(&model).Association("Files").Append(f).Error
return err
}
func (f *File) addToWidget(widget widget.Widget) error {
db := common.GetDB()
err := db.Model(&widget).Association("Files").Append(f).Error
return err
}
func getFolderName(objectType string, objectID uint) string {
base_foldername := "files/"
foldername := base_foldername + objectType + "_" + strconv.Itoa(int(objectID)) + "/"
return foldername
}