infoalloggi-monorepo/apps/backend/storage.go

243 lines
5.3 KiB
Go
Raw Normal View History

2025-08-04 17:45:44 +02:00
package main
import (
"backend/queries"
2025-08-04 17:45:44 +02:00
"fmt"
"log"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"slices"
"time"
"github.com/labstack/echo/v4"
)
// Upload saves a file to the storage directory.
func Upload(file *multipart.FileHeader, from_admin bool) (string, error) {
log.Printf("Uploading file: %s", file.Filename)
newId, err := queries.StorageNewId()
2025-08-04 17:45:44 +02:00
if err != nil {
return "", err
2025-08-04 17:45:44 +02:00
}
2025-08-04 17:45:44 +02:00
err = Storage.Add(file, newId)
if err != nil {
return "", err
}
//if !from_admin , expires in 60 days
var expiresAt *time.Time
if !from_admin {
exp := time.Now().AddDate(0, 2, 0) // 60 days
expiresAt = &exp
} else {
expiresAt = nil
}
err = queries.StorageUpdate(newId, file.Filename, filepath.Ext(file.Filename), from_admin, expiresAt)
2025-08-04 17:45:44 +02:00
if err != nil {
return "", err
2025-08-04 17:45:44 +02:00
}
err = queries.StorageDeleteUnused()
2025-08-04 17:45:44 +02:00
if err != nil {
return "", err
2025-08-04 17:45:44 +02:00
}
return newId, nil
}
func StorageAuth(c echo.Context) error {
token := c.Request().URL.Query().Get("token")
if len(token) < 1 {
return c.String(http.StatusUnauthorized, "Unauthorized")
}
err := queries.StorageCheckToken(token)
2025-08-04 17:45:44 +02:00
if err != nil {
return err
}
err = queries.StorageCleanExpiredTokens(token)
2025-08-04 17:45:44 +02:00
if err != nil {
return err
}
return nil
}
func RemoveFromDb(ref string) error {
return queries.StorageDelete(ref)
2025-08-04 17:45:44 +02:00
}
func RemoveExpired() error {
//get all expired files
items_db, err := queries.StorageGetExpiredFiles()
2025-08-04 17:45:44 +02:00
if err != nil {
return err
2025-08-04 17:45:44 +02:00
}
2025-08-04 17:45:44 +02:00
for _, item := range items_db {
formattedName := item.Id + item.Ext
err = Storage.Delete(formattedName)
if err != nil {
return fmt.Errorf("failed to delete file %s: %w", formattedName, err)
}
err = queries.StorageDelete(item.Id)
2025-08-04 17:45:44 +02:00
if err != nil {
return err
2025-08-04 17:45:44 +02:00
}
}
return nil
}
func CheckConcruency() error {
items_db, err := queries.StorageGet_min()
2025-08-04 17:45:44 +02:00
if err != nil {
return err
}
files, err := Storage.List()
if err != nil {
return err
}
if len(items_db) != len(files) {
var founds []string
for _, item := range items_db {
formattedName := item.Id + item.Ext
found := slices.Contains(files, formattedName)
if found {
founds = append(founds, formattedName)
} else {
err := queries.StorageDelete(item.Id)
2025-08-04 17:45:44 +02:00
if err != nil {
return err
}
}
}
for _, file := range files {
found := slices.Contains(founds, file)
if !found {
fmt.Printf("File %v not found in db\n", file)
//TODO decidere se eliminarlo
}
}
}
return nil
}
func TempFolderCleaner() error {
files, err := os.ReadDir(filepath.Join(storagepath, "/tmp/"))
if err != nil {
return err
}
fmt.Println("Temp files: ", len(files))
if len(files) >= tempStorageLimit {
var oldest_Time time.Time
var oldest_File string
for _, file := range files {
file_infos, err := file.Info()
if err != nil {
return err
}
if oldest_Time.IsZero() || file_infos.ModTime().Before(oldest_Time) {
oldest_Time = file_infos.ModTime()
oldest_File = file.Name()
}
}
err = os.Remove(filepath.Join(storagepath, "/tmp/", oldest_File))
if err != nil {
return err
}
}
return nil
}
// ROUTES
func StorageRoutes(e *echo.Echo) {
e.GET("/storage/list", func(c echo.Context) error {
filenames, err := Storage.List()
if err != nil {
return c.String(http.StatusInternalServerError, err.Error())
}
return c.JSON(http.StatusOK, filenames)
})
e.GET("/storage/get/:filename", func(c echo.Context) error {
err := TempFolderCleaner()
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to clean temp folder: "+err.Error())
}
err = StorageAuth(c)
if err != nil {
return c.JSON(http.StatusUnauthorized, "Unauthorized: "+err.Error())
}
filename := c.Param("filename")
path, err := Storage.Get(filename)
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to get file: "+err.Error())
}
return c.File(path)
})
e.POST("/storage/upload", func(c echo.Context) error {
fmt.Println("Uploading file")
err := StorageAuth(c)
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to verify Auth: "+err.Error())
}
from_admin := c.QueryParam("from_admin") == "true"
file, err := c.FormFile("file")
if err != nil {
return err
}
fileId, err := Upload(file, from_admin)
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to upload file: "+err.Error())
}
return c.String(http.StatusOK, fileId)
})
e.DELETE("/storage/delete/:filename", func(c echo.Context) error {
err := StorageAuth(c)
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to verify Auth: "+err.Error())
}
filename := c.Param("filename")
err = Storage.Delete(filename)
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to remove file / file not found: "+err.Error())
}
return c.String(http.StatusOK, "File removed")
})
e.GET("/storage/remove-expired", func(c echo.Context) error {
err := RemoveExpired()
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to remove files / files not found: "+err.Error())
}
return c.String(http.StatusOK, "File removed")
})
e.GET("/storage/test", func(c echo.Context) error {
err := CheckConcruency()
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to check concruency: "+err.Error())
}
return c.String(http.StatusOK, "OK")
})
}