mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
395 lines
No EOL
9.7 KiB
Go
395 lines
No EOL
9.7 KiB
Go
package file
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
_ "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/model"
|
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/simulation"
|
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/widget"
|
|
)
|
|
|
|
//func FindAllFiles() ([]common.File, int, error) {
|
|
// db := common.GetDB()
|
|
// var files []common.File
|
|
// err := db.Find(&files).Error
|
|
// if err != nil {
|
|
// // print error message to screen
|
|
// fmt.Println(fmt.Errorf("DB Error in FindAllFiles(): %q", err).Error())
|
|
// }
|
|
// return files, len(files), err
|
|
//}
|
|
//
|
|
//func FindUserFiles(user *common.User) ([]common.File, int, error) {
|
|
// db := common.GetDB()
|
|
// var files []common.File
|
|
// err := db.Model(user).Related(&files, "Files").Error
|
|
// return files, len(files), err
|
|
//}
|
|
//
|
|
//func FindFile(userID int, fileID string) ( common.File, error) {
|
|
// var file common.File
|
|
// db := common.GetDB()
|
|
// fileID_i, _ := strconv.Atoi(fileID)
|
|
//
|
|
// err := db.First(&file, fileID_i).Error
|
|
//
|
|
// return file, err
|
|
//
|
|
//}
|
|
|
|
func FindFiles(c *gin.Context, widgetID int, modelID int, simulationID int) ([]common.File, int, error){
|
|
db := common.GetDB()
|
|
var files []common.File
|
|
var err error
|
|
|
|
if widgetID != -1 {
|
|
var w common.Widget
|
|
err = db.First(&w, widgetID).Error
|
|
if err != nil {
|
|
return files, 0, err
|
|
}
|
|
err = db.Model(&w).Related(&files, "Files").Error
|
|
if err != nil {
|
|
return files, 0, err
|
|
}
|
|
|
|
} else if modelID != -1 {
|
|
var m common.Model
|
|
err = db.First(&m, modelID).Error
|
|
if err != nil {
|
|
return files, 0, err
|
|
}
|
|
err = db.Model(&m).Related(&files, "Files").Error
|
|
if err != nil {
|
|
return files, 0, err
|
|
}
|
|
|
|
}
|
|
|
|
return files, len(files), err
|
|
}
|
|
|
|
func FindFileByPath(path string) (common.File, error) {
|
|
var file common.File
|
|
db := common.GetDB()
|
|
err := db.Where("Path = ?", path).Find(file).Error
|
|
|
|
return file, err
|
|
}
|
|
|
|
func RegisterFile(c *gin.Context, widgetID int, modelID int, simulationID int){
|
|
|
|
// Extract file from PUT request form
|
|
file_header, err := c.FormFile("file")
|
|
if err != nil {
|
|
errormsg := fmt.Sprintf("Bad request. Get form error: %s", err.Error())
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"error": errormsg,
|
|
})
|
|
return;
|
|
}
|
|
|
|
// Obtain properties of file
|
|
filetype := file_header.Header.Get("Content-Type") // TODO make sure this is properly set in file header
|
|
filename := filepath.Base(file_header.Filename)
|
|
foldername := getFolderName(simulationID, modelID, widgetID)
|
|
size := file_header.Size
|
|
|
|
// Check if simulation and widget or model exist in DB
|
|
_, err = simulation.FindSimulation(simulationID)
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
|
|
if modelID != -1 {
|
|
_, err = model.FindModel(modelID)
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
} else if widgetID != -1 {
|
|
_, err = widget.FindWidget(widgetID)
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
}
|
|
|
|
// Save file to local disc (NOT DB!)
|
|
err = modifyFileOnDisc(file_header, filename, foldername, uint(size), true)
|
|
if err != nil {
|
|
errormsg := fmt.Sprintf("Internal Server Error. Error saving file: %s", err.Error())
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": errormsg,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Add File object with parameters to DB
|
|
saveFileInDB(c, filename, foldername, filetype, uint(size), widgetID, modelID, true)
|
|
|
|
}
|
|
|
|
func UpdateFile(c *gin.Context, widgetID int, modelID int, simulationID int){
|
|
|
|
// Extract file from PUT request form
|
|
err := c.Request.ParseForm()
|
|
if err != nil {
|
|
errormsg := fmt.Sprintf("Bad request. Get form error: %s", err.Error())
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"error": errormsg,
|
|
})
|
|
return;
|
|
}
|
|
|
|
file_header, err := c.FormFile("file")
|
|
if err != nil {
|
|
errormsg := fmt.Sprintf("Bad request. Get form error: %s", err.Error())
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"error": errormsg,
|
|
})
|
|
return;
|
|
}
|
|
|
|
filename := filepath.Base(file_header.Filename)
|
|
filetype := file_header.Header.Get("Content-Type") // TODO make sure this is properly set in file header
|
|
size := file_header.Size
|
|
foldername := getFolderName(simulationID, modelID, widgetID)
|
|
|
|
err = modifyFileOnDisc(file_header, filename, foldername, uint(size), false)
|
|
if err != nil {
|
|
errormsg := fmt.Sprintf("Internal Server Error. Error saving file: %s", err.Error())
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": errormsg,
|
|
})
|
|
return
|
|
}
|
|
|
|
saveFileInDB(c, filename, foldername, filetype, uint(size), widgetID, modelID, false)
|
|
}
|
|
|
|
func ReadFile(c *gin.Context, widgetID int, modelID int, simulationID int){
|
|
|
|
//contentType := c.GetHeader("Content-Type")
|
|
|
|
//TODO currently returns first file it finds in DB
|
|
|
|
db := common.GetDB()
|
|
var fileInDB common.File
|
|
if widgetID != -1 {
|
|
// get associated Widget
|
|
var wdgt common.Widget
|
|
err := db.First(&wdgt, modelID).Error
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
err = db.Model(&wdgt).Related(&fileInDB).Error
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
|
|
} else if modelID != -1 {
|
|
|
|
// get associated Simulation Model
|
|
var model common.Model
|
|
err := db.First(&model, modelID).Error
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
err = db.Model(&model).Related(&fileInDB).Error
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
}
|
|
|
|
//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="+fileInDB.Name )
|
|
//c.Header("Content-Type", contentType)
|
|
c.File(fileInDB.Path)
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "OK.",
|
|
})
|
|
}
|
|
|
|
|
|
|
|
|
|
func DeleteFile(c *gin.Context, widgetID int, nmodelID int, simulationID int){
|
|
// TODO
|
|
}
|
|
|
|
|
|
func saveFileInDB(c *gin.Context, filename string, foldername string, filetype string, size uint, widgetID int, modelID int, createObj bool) {
|
|
|
|
filesavepath := filepath.Join(foldername, filename)
|
|
|
|
// get last modify time of target file
|
|
fileinfo, err := os.Stat(filesavepath)
|
|
if err != nil {
|
|
errormsg := fmt.Sprintf("Internal Server Error. Error stat on file: %s", err.Error())
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": errormsg,
|
|
})
|
|
return
|
|
}
|
|
modTime := fileinfo.ModTime()
|
|
|
|
// Create file object for Database
|
|
var fileObj common.File
|
|
fileObj.Size = uint(size)
|
|
fileObj.Type = filetype
|
|
fileObj.Path = filesavepath
|
|
fileObj.Date = modTime
|
|
fileObj.Name = filename
|
|
fileObj.ImageHeight = 0
|
|
fileObj.ImageWidth = 0
|
|
|
|
// Check if file shall be associated with Widget or Simulation Model
|
|
db := common.GetDB()
|
|
if widgetID != -1 {
|
|
|
|
if createObj {
|
|
// associate to Widget
|
|
var wdgt common.Widget
|
|
err := db.First(&wdgt, widgetID).Error
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
err = db.Model(&wdgt).Association("Files").Append(&fileObj).Error
|
|
} else {
|
|
// update file obj in DB
|
|
fileInDB, err := FindFileByPath(filesavepath)
|
|
if common.ProvideErrorResponse(c, err){
|
|
return
|
|
}
|
|
|
|
err = db.Model(&fileInDB).Where("Path = ?", filesavepath).Updates(map[string]interface{}{"Size": fileObj.Size, "Date": fileObj.Date, "ImageHeight": fileObj.ImageHeight, "ImageWidth": fileObj.ImageWidth}).Error
|
|
|
|
}
|
|
|
|
if common.ProvideErrorResponse(c, err) == false {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "OK.",
|
|
"fileID": fileObj.ID,
|
|
})
|
|
return
|
|
}
|
|
|
|
}
|
|
if modelID != -1 {
|
|
|
|
if createObj {
|
|
// associate to Simulation Model
|
|
db := common.GetDB()
|
|
var model common.Model
|
|
err := db.First(&model, modelID).Error
|
|
if common.ProvideErrorResponse(c, err) {
|
|
return
|
|
}
|
|
err = db.Model(&model).Association("Files").Append(&fileObj).Error
|
|
} else {
|
|
// update file obj in DB
|
|
fileInDB, err := FindFileByPath(filesavepath)
|
|
if common.ProvideErrorResponse(c, err){
|
|
return
|
|
}
|
|
|
|
err = db.Model(&fileInDB).Where("Path = ?", filesavepath).Updates(map[string]interface{}{"Size": fileObj.Size, "Date": fileObj.Date, "ImageHeight": fileObj.ImageHeight, "ImageWidth": fileObj.ImageWidth}).Error
|
|
}
|
|
|
|
if common.ProvideErrorResponse(c, err) == false {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "OK.",
|
|
"fileID": fileObj.ID,
|
|
})
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func modifyFileOnDisc(file_header *multipart.FileHeader, filename string, foldername string, size uint, createFile bool) error {
|
|
|
|
filesavepath := filepath.Join(foldername, filename)
|
|
var err error
|
|
|
|
if createFile {
|
|
// Ensure folder with name foldername exists
|
|
err = os.MkdirAll(foldername, os.ModePerm)
|
|
} else {
|
|
// test if file exists
|
|
_, err = os.Stat(filesavepath)
|
|
}
|
|
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(filesavepath, open_options, 0666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fileTarget.Close()
|
|
|
|
// Save file to target path
|
|
uploadedFile, err := file_header.Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer uploadedFile.Close()
|
|
|
|
var uploadContent = make([]byte, 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 getFolderName(simulationID int, modelID int, widgetID int) string {
|
|
base_foldername := "files/"
|
|
elementname := ""
|
|
elementid := 0
|
|
if modelID == -1{
|
|
elementname = "/widget_"
|
|
elementid = widgetID
|
|
} else {
|
|
elementname = "/model_"
|
|
elementid = modelID
|
|
}
|
|
|
|
|
|
foldername := base_foldername + "simulation_"+ strconv.Itoa(simulationID) + elementname + strconv.Itoa(elementid) + "/"
|
|
return foldername
|
|
} |