diff --git a/server/internal/api/v1/fs/download.go b/server/internal/api/v1/fs/download.go new file mode 100644 index 00000000..ac8d97f4 --- /dev/null +++ b/server/internal/api/v1/fs/download.go @@ -0,0 +1,75 @@ +package fs + +import ( + "archive/zip" + "io" + "path" + "strings" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/shroff/phylum/server/internal/api/auth" + "github.com/shroff/phylum/server/internal/api/serve" + "github.com/shroff/phylum/server/internal/core/fs" +) + +func handleDownloadRequest(c *gin.Context) { + resourceID, err := uuid.Parse(c.Param("id")) + if err != nil { + panic(errResourceIDInvalid) + } + + f := auth.GetFileSystem(c) + r, err := f.ResourceByID(resourceID) + prefix := path.Dir(r.Path) + + c.Writer.Header().Set("Content-Type", "application/zip") + c.Writer.Header().Set("Content-Disposition", "attachment; filename=\""+r.Name+".zip\"") + + var zip = zip.NewWriter(c.Writer) + close := c.Writer.CloseNotify() + err = r.Walk(2, func(r serve.Resource) error { + if r.FSDir() { + return nil + } + + select { + case <-close: + return nil + default: + } + + path, found := strings.CutPrefix(r.FSPath(), prefix) + if !found { + return fs.ErrResourcePathInvalid + } + out, err := zip.Create(path) + if err != nil { + return err + } + in, err := r.OpenRead(0, -1) + if err != nil { + return err + } + _, copyErr := io.Copy(out, in) + closeErr := in.Close() + + if copyErr != nil { + return copyErr + } + if closeErr != nil { + return closeErr + } + if err := zip.Flush(); err != nil { + return err + } + return nil + }) + closeErr := zip.Close() + if err != nil { + panic(err) + } + if closeErr != nil { + panic(closeErr) + } +} diff --git a/server/internal/api/v1/fs/routes.go b/server/internal/api/v1/fs/routes.go index 19843c94..ff9b8a37 100644 --- a/server/internal/api/v1/fs/routes.go +++ b/server/internal/api/v1/fs/routes.go @@ -14,6 +14,8 @@ var ( func SetupRoutes(r *gin.RouterGroup) { group := r.Group("/fs") + group.GET("/cat/:id", handleCatRequest) + group.GET("/download/:id", handleDownloadRequest) group.GET("/du/:id", handleDuRequest) group.GET("/ls/:id", handleLsRequest) group.POST("/mkdir/:id", handleMkdirRequest) @@ -21,5 +23,4 @@ func SetupRoutes(r *gin.RouterGroup) { group.POST("/cp/:id", handleCpRequest) group.DELETE("/rm/:id", handleRmRequest) group.PUT("/upload/:id", handleUploadRequest) - group.GET("/cat/:id", handleCatRequest) } diff --git a/server/internal/core/fs/open.go b/server/internal/core/fs/open.go index 0dcc6ac8..f7b650ec 100644 --- a/server/internal/core/fs/open.go +++ b/server/internal/core/fs/open.go @@ -53,21 +53,21 @@ func (r Resource) ReadDir(recursive bool) ([]serve.Resource, error) { path = c.Path } result[i] = Resource{ - f: r.f, - ID: c.ID, - ParentID: c.Parent, - Name: c.Name, - Created: c.Created.Time, - Modified: c.Modified.Time, - Deleted: nil, // Query will not return deleted results - Dir: c.Dir, - ContentSize: c.ContentSize, - ContentType: c.ContentType, - ContentSHA256: c.ContentSha256, - Permissions: string(c.Permissions), - Path: path, + f: r.f, + ID: c.ID, + ParentID: c.Parent, + Name: c.Name, + Created: c.Created.Time, + Modified: c.Modified.Time, + Deleted: nil, // Query will not return deleted results + Dir: c.Dir, + ContentSize: c.ContentSize, + ContentType: c.ContentType, + ContentSHA256: c.ContentSha256, + Permissions: string(c.Permissions), + Path: path, + UserPermissions: r.UserPermissions, // Not Needed - // UserPermissions: 0, // InheritedPermissions: "", } }