1717package restapi
1818
1919import (
20+ "archive/zip"
21+ "bytes"
2022 "context"
2123 "encoding/base64"
2224 "fmt"
@@ -96,40 +98,51 @@ func registerObjectsHandlers(api *operations.ConsoleAPI) {
9698 prefixPath = string (decodedPrefix )
9799 }
98100 prefixElements := strings .Split (prefixPath , "/" )
101+ isFolder := false
99102 if len (prefixElements ) > 0 {
100- filename = prefixElements [len (prefixElements )- 1 ]
103+ if prefixElements [len (prefixElements )- 1 ] == "" {
104+ filename = prefixElements [len (prefixElements )- 2 ]
105+ isFolder = true
106+ } else {
107+ filename = prefixElements [len (prefixElements )- 1 ]
108+ }
101109 }
102110 if isPreview {
103111 rw .Header ().Set ("Content-Disposition" , fmt .Sprintf ("inline; filename=\" %s\" " , filename ))
104112 rw .Header ().Set ("X-Frame-Options" , "SAMEORIGIN" )
105113 rw .Header ().Set ("X-XSS-Protection" , "1" )
106114
115+ } else if isFolder {
116+ rw .Header ().Set ("Content-Disposition" , fmt .Sprintf ("attachment; filename=\" %s.zip\" " , filename ))
117+ rw .Header ().Set ("Content-Type" , "application/zip" )
107118 } else {
108119 rw .Header ().Set ("Content-Disposition" , fmt .Sprintf ("attachment; filename=\" %s\" " , filename ))
109120 rw .Header ().Set ("Content-Type" , "application/octet-stream" )
110121 }
111122
112123 // indicate object size & content type
113- stat , err := resp .(* minio.Object ).Stat ()
114- if err != nil {
115- log .Println (err )
116- } else {
117- rw .Header ().Set ("Content-Length" , fmt .Sprintf ("%d" , stat .Size ))
124+ if ! isFolder {
125+ stat , err := resp .(* minio.Object ).Stat ()
126+ if err != nil {
127+ log .Println (err )
128+ } else {
129+ rw .Header ().Set ("Content-Length" , fmt .Sprintf ("%d" , stat .Size ))
118130
119- contentType := stat .ContentType
131+ contentType := stat .ContentType
120132
121- if isPreview {
122- // In case content type was uploaded as octet-stream, we double verify content type
123- if stat .ContentType == "application/octet-stream" {
124- contentType = mimedb .TypeByExtension (filepath .Ext (filename ))
133+ if isPreview {
134+ // In case content type was uploaded as octet-stream, we double verify content type
135+ if stat .ContentType == "application/octet-stream" {
136+ contentType = mimedb .TypeByExtension (filepath .Ext (filename ))
137+ }
125138 }
126- }
127139
128- rw .Header ().Set ("Content-Type" , contentType )
140+ rw .Header ().Set ("Content-Type" , contentType )
141+ }
129142 }
130143
131144 // Copy the stream
132- _ , err = io .Copy (rw , resp )
145+ _ , err : = io .Copy (rw , resp )
133146 if err != nil {
134147 log .Println (err )
135148 }
@@ -305,6 +318,7 @@ func listBucketObjects(ctx context.Context, client MinioClient, bucketName strin
305318func getDownloadObjectResponse (session * models.Principal , params user_api.DownloadObjectParams ) (io.ReadCloser , * models.Error ) {
306319 ctx := context .Background ()
307320 var prefix string
321+ mClient , err := newMinioClient (session )
308322 if params .Prefix != "" {
309323 encodedPrefix := SanitizeEncodedPrefix (params .Prefix )
310324 decodedPrefix , err := base64 .StdEncoding .DecodeString (encodedPrefix )
@@ -313,34 +327,51 @@ func getDownloadObjectResponse(session *models.Principal, params user_api.Downlo
313327 }
314328 prefix = string (decodedPrefix )
315329 }
316- s3Client , err := newS3BucketClient (session , params .BucketName , prefix )
317- if err != nil {
318- return nil , prepareError (err )
330+ isFolder := false
331+ folders := strings .Split (prefix , "/" )
332+ if folders [len (folders )- 1 ] == "" {
333+ isFolder = true
319334 }
320- // create a mc S3Client interface implementation
321- // defining the client to be used
322- mcClient := mcClient {client : s3Client }
323- object , err := downloadObject (ctx , mcClient , params .VersionID )
335+ if isFolder {
336+ if err != nil {
337+ return nil , prepareError (err )
338+ }
339+ minioClient := minioClient {client : mClient }
340+ objects , err := listBucketObjects (ctx , minioClient , params .BucketName , prefix , true , false , false )
341+ if err != nil {
342+ return nil , prepareError (err )
343+ }
344+ w := new (bytes.Buffer )
345+ zipw := zip .NewWriter (w )
346+ var folder string
347+ if len (folders ) > 1 {
348+ folder = folders [len (folders )- 2 ]
349+ }
350+ for i := 0 ; i < len (objects ); i ++ {
351+ name := folder + objects [i ].Name [len (prefix )- 1 :]
352+ object , err := mClient .GetObject (ctx , params .BucketName , objects [i ].Name , minio.GetObjectOptions {})
353+ if err != nil {
354+ return nil , prepareError (err )
355+ }
356+ f , err := zipw .Create (name )
357+ if err != nil {
358+ return nil , prepareError (err )
359+ }
360+ buf := new (bytes.Buffer )
361+ buf .ReadFrom (object )
362+ f .Write (buf .Bytes ())
363+ }
364+ zipw .Close ()
365+ zipfile := io .NopCloser (bytes .NewReader (w .Bytes ()))
366+ return zipfile , nil
367+ }
368+ object , err := mClient .GetObject (ctx , params .BucketName , prefix , minio.GetObjectOptions {})
324369 if err != nil {
325370 return nil , prepareError (err )
326371 }
327372 return object , nil
328373}
329374
330- func downloadObject (ctx context.Context , client MCClient , versionID * string ) (io.ReadCloser , error ) {
331- // TODO: handle encrypted files
332- var reader io.ReadCloser
333- var version string
334- if versionID != nil {
335- version = * versionID
336- }
337- reader , pErr := client .get (ctx , mc.GetOptions {VersionID : version })
338- if pErr != nil {
339- return nil , pErr .Cause
340- }
341- return reader , nil
342- }
343-
344375// getDeleteObjectResponse returns whether there was an error on deletion of object
345376func getDeleteObjectResponse (session * models.Principal , params user_api.DeleteObjectParams ) * models.Error {
346377 ctx := context .Background ()
0 commit comments