From 7855e07a966931e0cebe600930fd5e5c9fe68b4b Mon Sep 17 00:00:00 2001 From: Lena Fuhrimann <6780471+cloudlena@users.noreply.github.com> Date: Wed, 21 Dec 2016 00:32:40 +0100 Subject: [PATCH] Allow bucket creation --- .cfignore | 1 + .gitignore | 1 + api-handlers.go | 76 +++++++++++++++++++++++ handlers.go => page-handlers.go | 49 ++++++++++++--- routes.go | 20 +++++- templates/bucket.html | 107 ++++++++++++++++++++++++++------ templates/index.html | 72 ++++++++++++++------- templates/layout.html | 16 ++--- 8 files changed, 281 insertions(+), 61 deletions(-) create mode 100644 api-handlers.go rename handlers.go => page-handlers.go (54%) diff --git a/.cfignore b/.cfignore index 4b19c34..d3d449e 100644 --- a/.cfignore +++ b/.cfignore @@ -1,2 +1,3 @@ vendor +s3manager README.md diff --git a/.gitignore b/.gitignore index 79ccbc4..6af0b65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ vendor +s3manager glide.lock diff --git a/api-handlers.go b/api-handlers.go new file mode 100644 index 0000000..adbe629 --- /dev/null +++ b/api-handlers.go @@ -0,0 +1,76 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + + "github.com/gorilla/mux" + "github.com/minio/minio-go" +) + +// createBucketHandler creates a new bucket +func createBucketHandler(w http.ResponseWriter, r *http.Request) { + var bucket minio.BucketInfo + body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576)) + if err != nil { + panic(err) + } + if err = r.Body.Close(); err != nil { + panic(err) + } + err = json.Unmarshal(body, &bucket) + if err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + return + } + + err = minioClient.MakeBucket(bucket.Name, "") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(bucket) + if err != nil { + panic(err) + } +} + +// getObjectHandler downloads an object to the client +func getObjectHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + objectName := vars["objectName"] + + object, err := minioClient.GetObject(vars["bucketName"], objectName) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", objectName)) + w.Header().Set("Content-Type", "application/octet-stream") + + _, err = io.Copy(w, object) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } +} + +// deleteObjectHandler deletes an object +func deleteObjectHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + err := minioClient.RemoveObject(vars["bucketName"], vars["objectName"]) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) +} diff --git a/handlers.go b/page-handlers.go similarity index 54% rename from handlers.go rename to page-handlers.go index eff4f84..07ce000 100644 --- a/handlers.go +++ b/page-handlers.go @@ -6,11 +6,22 @@ import ( "net/http" "path" - "strings" - + "github.com/gorilla/mux" minio "github.com/minio/minio-go" ) +// ObjectWithIcon is a minio object with an added icon +type ObjectWithIcon struct { + minio.ObjectInfo + Icon string +} + +// BucketPage defines the details page of a bucket +type BucketPage struct { + BucketName string + Objects []ObjectWithIcon +} + // indexPageHandler forwards to "/buckets" func indexPageHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/buckets", http.StatusPermanentRedirect) @@ -37,10 +48,10 @@ func bucketsPageHandler(w http.ResponseWriter, r *http.Request) { } } -// bucketHandler handles the main page +// bucketHandler shows the details page of a bucket func bucketPageHandler(w http.ResponseWriter, r *http.Request) { - bucket := strings.Split(r.URL.Path, "/")[2] - var objects []minio.ObjectInfo + bucketName := mux.Vars(r)["bucketName"] + var objects []ObjectWithIcon lp := path.Join("templates", "layout.html") bp := path.Join("templates", "bucket.html") @@ -50,20 +61,40 @@ func bucketPageHandler(w http.ResponseWriter, r *http.Request) { panic(err) } - // Create a done channel to control 'ListObjectsV2' go routine. doneCh := make(chan struct{}) - objectCh := minioClient.ListObjectsV2(bucket, "", false, doneCh) + objectCh := minioClient.ListObjectsV2(bucketName, "", false, doneCh) for object := range objectCh { if object.Err != nil { fmt.Println(object.Err) return } - objects = append(objects, object) + objectWithIcon := ObjectWithIcon{object, getIcon(object.Key)} + objects = append(objects, objectWithIcon) } - err = t.ExecuteTemplate(w, "layout", objects) + bucketPage := BucketPage{ + BucketName: bucketName, + Objects: objects, + } + + err = t.ExecuteTemplate(w, "layout", bucketPage) if err != nil { panic(err) } } + +func getIcon(fileName string) string { + e := path.Ext(fileName) + + switch e { + case ".tgz": + return "archive" + case ".png", ".jpg", ".gif", ".svg": + return "photo" + case ".mp3": + return "music_note" + } + + return "insert_drive_file" +} diff --git a/routes.go b/routes.go index 66f401a..5aaec9e 100644 --- a/routes.go +++ b/routes.go @@ -29,7 +29,25 @@ var routes = Routes{ Route{ "Load Bucket Page", "GET", - "/buckets/{bucketID}", + "/buckets/{bucketName}", bucketPageHandler, }, + Route{ + "Create Bucket", + "POST", + "/api/buckets", + createBucketHandler, + }, + Route{ + "Download Object", + "GET", + "/api/buckets/{bucketName}/objects/{objectName}", + getObjectHandler, + }, + Route{ + "Delete Object", + "DELETE", + "/api/buckets/{bucketName}/objects/{objectName}", + deleteObjectHandler, + }, } diff --git a/templates/bucket.html b/templates/bucket.html index 3d7a699..dd5526b 100644 --- a/templates/bucket.html +++ b/templates/bucket.html @@ -1,25 +1,94 @@ {{ define "content" }} - + - - - - - - - - +
+
-
- {{ range $object := . }} - - - - - - +
KeySizeOwnerLast Modified
{{ $object.Key }}{{ $object.Size }} bytes{{ $object.Owner }}{{ $object.LastModified }}
+ + + + + + + + + + + + + + {{ range $object := .Objects }} + + + + + + + + + {{ end }} + + +
KeySizeOwnerLast ModifiedActions
{{ $object.Icon }}{{ $object.Key }}{{ $object.Size }} bytes{{ $object.Owner }}{{ $object.LastModified }} + + + Actions arrow_drop_down + + + + +
+ + {{ if not .Objects }} +

Oh noes... No objects in {{ .BucketName }} yet...

{{ end }} - +

- + + + +
+ + add + +
+ + + + {{ end }} diff --git a/templates/index.html b/templates/index.html index 54a11be..97ba035 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,27 +1,37 @@ {{ define "content" }} -
-
+ - {{ range $bucket := . }} - -
-
- + + {{ end }} diff --git a/templates/layout.html b/templates/layout.html index 77d34fd..75bedf3 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -14,20 +14,16 @@ - -
-
- {{ template "content" . }} -
-
+ {{ template "content" . }} +