diff --git a/frontend/src/network/network.ts b/frontend/src/network/network.ts
index 355f694..a7dac4c 100644
--- a/frontend/src/network/network.ts
+++ b/frontend/src/network/network.ts
@@ -529,6 +529,10 @@ class Network {
};
}
}
+
+ getFileDownloadLink(fileId: number): string {
+ return `${this.apiBaseUrl}/files/download/${fileId}`;
+ }
}
export const network = new Network();
diff --git a/frontend/src/pages/resource_details_page.tsx b/frontend/src/pages/resource_details_page.tsx
index da26a48..604beeb 100644
--- a/frontend/src/pages/resource_details_page.tsx
+++ b/frontend/src/pages/resource_details_page.tsx
@@ -147,7 +147,10 @@ function FileTile({file}: { file: RFile }) {
{file.description}
-
diff --git a/server/api/file.go b/server/api/file.go
index 7f93a3e..16342e9 100644
--- a/server/api/file.go
+++ b/server/api/file.go
@@ -6,6 +6,7 @@ import (
"nysoure/server/model"
"nysoure/server/service"
"strconv"
+ "strings"
)
func AddFileRoutes(router fiber.Router) {
@@ -19,6 +20,7 @@ func AddFileRoutes(router fiber.Router) {
fileGroup.Get("/:id", getFile)
fileGroup.Put("/:id", updateFile)
fileGroup.Delete("/:id", deleteFile)
+ fileGroup.Get("/download/:id", downloadFile)
}
}
@@ -200,3 +202,20 @@ func deleteFile(c fiber.Ctx) error {
Message: "File deleted successfully",
})
}
+
+func downloadFile(c fiber.Ctx) error {
+ idStr, err := strconv.ParseUint(c.Params("id"), 10, 32)
+ if err != nil {
+ return model.NewRequestError("Invalid file ID")
+ }
+ id := uint(idStr)
+ s, filename, err := service.DownloadFile(id)
+ if err != nil {
+ return err
+ }
+ if strings.HasPrefix(s, "http") {
+ return c.Redirect().Status(fiber.StatusFound).To(s)
+ }
+ c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
+ return c.SendFile(s)
+}
diff --git a/server/dao/file.go b/server/dao/file.go
index f694325..c88a1b9 100644
--- a/server/dao/file.go
+++ b/server/dao/file.go
@@ -85,7 +85,7 @@ func CreateFile(filename string, description string, resourceID uint, storageID
func GetFile(id uint) (*model.File, error) {
f := &model.File{}
- if err := db.Where("id = ?", id).First(f).Error; err != nil {
+ if err := db.Preload("Storage").Where("id = ?", id).First(f).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, model.NewNotFoundError("file not found")
}
diff --git a/server/service/file.go b/server/service/file.go
index 8688eff..0307eb5 100644
--- a/server/service/file.go
+++ b/server/service/file.go
@@ -346,3 +346,28 @@ func GetFile(fid uint) (*model.FileView, error) {
return file.ToView(), nil
}
+
+func DownloadFile(fid uint) (string, string, error) {
+ file, err := dao.GetFile(fid)
+ if err != nil {
+ log.Error("failed to get file: ", err)
+ return "", "", model.NewNotFoundError("file not found")
+ }
+
+ if file.StorageID == nil {
+ if file.RedirectUrl != "" {
+ return file.RedirectUrl, file.Filename, nil
+ }
+ return "", "", model.NewRequestError("file is not available")
+ }
+
+ iStorage := storage.NewStorage(file.Storage)
+ if iStorage == nil {
+ log.Error("failed to find storage: ", err)
+ return "", "", model.NewInternalServerError("failed to find storage")
+ }
+
+ path, err := iStorage.Download(file.StorageKey)
+
+ return path, file.Filename, err
+}