package main import ( "backend/queries" "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() if err != nil { return "", err } 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) if err != nil { return "", err } err = queries.StorageDeleteUnused() if err != nil { return "", err } 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) if err != nil { return err } err = queries.StorageCleanExpiredTokens(token) if err != nil { return err } return nil } func RemoveFromDb(ref string) error { return queries.StorageDelete(ref) } func RemoveExpired() error { //get all expired files items_db, err := queries.StorageGetExpiredFiles() if err != nil { return err } 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) if err != nil { return err } } return nil } func CheckConcruency() error { items_db, err := queries.StorageGet_min() 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) 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") }) }