Remove unneeded packages
This commit is contained in:
parent
42dc5a3dec
commit
4672fc2e1c
24 changed files with 254 additions and 294 deletions
80
bucket-view.go
Normal file
80
bucket-view.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// BucketViewHandler shows the details page of a bucket
|
||||
func BucketViewHandler(s3 S3Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
bucketName := mux.Vars(r)["bucketName"]
|
||||
var objs []ObjectWithIcon
|
||||
|
||||
l := path.Join("templates", "layout.html.tmpl")
|
||||
p := path.Join("templates", "bucket.html.tmpl")
|
||||
|
||||
t, err := template.ParseFiles(l, p)
|
||||
if err != nil {
|
||||
msg := "error parsing templates"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
objectCh := s3.ListObjectsV2(bucketName, "", true, doneCh)
|
||||
for object := range objectCh {
|
||||
if object.Err != nil {
|
||||
msg := "error listing objects"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
objectWithIcon := ObjectWithIcon{object, icon(object.Key)}
|
||||
objs = append(objs, objectWithIcon)
|
||||
}
|
||||
|
||||
bucketPage := BucketPage{
|
||||
BucketName: bucketName,
|
||||
Objects: objs,
|
||||
}
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", bucketPage)
|
||||
if err != nil {
|
||||
msg := "error executing template"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// icon returns an icon for a file type
|
||||
func icon(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"
|
||||
}
|
36
buckets-view.go
Normal file
36
buckets-view.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
// BucketsViewHandler shows all buckets
|
||||
func BucketsViewHandler(s3 S3Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
l := path.Join("templates", "layout.html.tmpl")
|
||||
p := path.Join("templates", "buckets.html.tmpl")
|
||||
|
||||
t, err := template.ParseFiles(l, p)
|
||||
if err != nil {
|
||||
msg := "error parsing templates"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
buckets, err := s3.ListBuckets()
|
||||
if err != nil {
|
||||
msg := "error listing buckets"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", buckets)
|
||||
if err != nil {
|
||||
msg := "error executing template"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,30 +1,28 @@
|
|||
package buckets
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/mastertinner/s3-manager/datasources"
|
||||
"github.com/mastertinner/s3-manager/utils"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// CreateHandler creates a new bucket
|
||||
func CreateHandler(s3 datasources.S3Client) http.Handler {
|
||||
// CreateBucketHandler creates a new bucket
|
||||
func CreateBucketHandler(s3 S3Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var bucket minio.BucketInfo
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&bucket)
|
||||
if err != nil {
|
||||
msg := "error decoding json"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
err = s3.MakeBucket(bucket.Name, "")
|
||||
if err != nil {
|
||||
msg := "error making bucket"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -34,7 +32,7 @@ func CreateHandler(s3 datasources.S3Client) http.Handler {
|
|||
err = json.NewEncoder(w).Encode(bucket)
|
||||
if err != nil {
|
||||
msg := "error encoding json"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
|
@ -1,4 +1,4 @@
|
|||
package buckets_test
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -7,45 +7,38 @@ import (
|
|||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mastertinner/s3-manager/buckets"
|
||||
"github.com/mastertinner/s3-manager/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateHandler(t *testing.T) {
|
||||
func TestCreateBucketHandler(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
s3Client *mock.S3Client
|
||||
tests := map[string]struct {
|
||||
s3Client S3Client
|
||||
body string
|
||||
expectedStatusCode int
|
||||
expectedBody string
|
||||
}{
|
||||
{
|
||||
description: "success",
|
||||
s3Client: &mock.S3Client{},
|
||||
"success": {
|
||||
s3Client: &S3ClientMock{},
|
||||
body: "{\"name\":\"myBucket\"}",
|
||||
expectedStatusCode: http.StatusCreated,
|
||||
expectedBody: "{\"name\":\"myBucket\",\"creationDate\":\"0001-01-01T00:00:00Z\"}\n",
|
||||
},
|
||||
{
|
||||
description: "empty request",
|
||||
s3Client: &mock.S3Client{},
|
||||
"empty request": {
|
||||
s3Client: &S3ClientMock{},
|
||||
body: "",
|
||||
expectedStatusCode: http.StatusUnprocessableEntity,
|
||||
expectedBody: "error decoding json\n",
|
||||
},
|
||||
{
|
||||
description: "malformed request",
|
||||
s3Client: &mock.S3Client{},
|
||||
"malformed request": {
|
||||
s3Client: &S3ClientMock{},
|
||||
body: "}",
|
||||
expectedStatusCode: http.StatusUnprocessableEntity,
|
||||
expectedBody: "error decoding json\n",
|
||||
},
|
||||
{
|
||||
description: "s3 error",
|
||||
s3Client: &mock.S3Client{
|
||||
"s3 error": {
|
||||
s3Client: &S3ClientMock{
|
||||
Err: errors.New("internal S3 error"),
|
||||
},
|
||||
body: "{\"name\":\"myBucket\"}",
|
||||
|
@ -59,11 +52,11 @@ func TestCreateHandler(t *testing.T) {
|
|||
assert.NoError(err)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := buckets.CreateHandler(tc.s3Client)
|
||||
handler := CreateBucketHandler(tc.s3Client)
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(tc.expectedStatusCode, rr.Code, tc.description)
|
||||
assert.Equal(tc.expectedBody, rr.Body.String(), tc.description)
|
||||
assert.Equal(tc.expectedStatusCode, rr.Code)
|
||||
assert.Equal(tc.expectedBody, rr.Body.String())
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package objects
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -6,8 +6,6 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/datasources"
|
||||
"github.com/mastertinner/s3-manager/utils"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
|
@ -19,8 +17,8 @@ type CopyObjectInfo struct {
|
|||
SourceObjectName string `json:"sourceObjectName"`
|
||||
}
|
||||
|
||||
// CreateHandler allows to upload a new object
|
||||
func CreateHandler(s3 datasources.S3Client) http.Handler {
|
||||
// CreateObjectHandler allows to upload a new object
|
||||
func CreateObjectHandler(s3 S3Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
@ -30,7 +28,7 @@ func CreateHandler(s3 datasources.S3Client) http.Handler {
|
|||
err := json.NewDecoder(r.Body).Decode(©)
|
||||
if err != nil {
|
||||
msg := "error decoding json"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -39,7 +37,7 @@ func CreateHandler(s3 datasources.S3Client) http.Handler {
|
|||
err = s3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds)
|
||||
if err != nil {
|
||||
msg := "error copying object"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -49,21 +47,21 @@ func CreateHandler(s3 datasources.S3Client) http.Handler {
|
|||
err = json.NewEncoder(w).Encode(copy)
|
||||
if err != nil {
|
||||
msg := "error encoding json"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err := r.ParseMultipartForm(32 << 20)
|
||||
if err != nil {
|
||||
msg := "error parsing form"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
file, handler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
msg := "error getting form file"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
@ -71,7 +69,7 @@ func CreateHandler(s3 datasources.S3Client) http.Handler {
|
|||
_, err = s3.PutObject(vars["bucketName"], handler.Filename, file, "application/octet-stream")
|
||||
if err != nil {
|
||||
msg := "error putting object"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -1,22 +1,20 @@
|
|||
package buckets
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/datasources"
|
||||
"github.com/mastertinner/s3-manager/utils"
|
||||
)
|
||||
|
||||
// DeleteHandler deletes a bucket
|
||||
func DeleteHandler(s3 datasources.S3Client) http.Handler {
|
||||
// DeleteBucketHandler deletes a bucket
|
||||
func DeleteBucketHandler(s3 S3Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
err := s3.RemoveBucket(vars["bucketName"])
|
||||
if err != nil {
|
||||
msg := "error removing bucket"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package buckets_test
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -6,29 +6,24 @@ import (
|
|||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mastertinner/s3-manager/buckets"
|
||||
"github.com/mastertinner/s3-manager/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeleteHandler(t *testing.T) {
|
||||
func TestDeleteBucketHandler(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
s3Client *mock.S3Client
|
||||
tests := map[string]struct {
|
||||
s3Client S3Client
|
||||
expectedStatusCode int
|
||||
expectedBody string
|
||||
}{
|
||||
{
|
||||
description: "success",
|
||||
s3Client: &mock.S3Client{},
|
||||
"success": {
|
||||
s3Client: &S3ClientMock{},
|
||||
expectedStatusCode: http.StatusNoContent,
|
||||
expectedBody: "",
|
||||
},
|
||||
{
|
||||
description: "s3 error",
|
||||
s3Client: &mock.S3Client{
|
||||
"s3 error": {
|
||||
s3Client: &S3ClientMock{
|
||||
Err: errors.New("internal S3 error"),
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
|
@ -41,11 +36,11 @@ func TestDeleteHandler(t *testing.T) {
|
|||
assert.NoError(err)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := buckets.DeleteHandler(tc.s3Client)
|
||||
handler := DeleteBucketHandler(tc.s3Client)
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(tc.expectedStatusCode, rr.Code, tc.description)
|
||||
assert.Equal(tc.expectedBody, rr.Body.String(), tc.description)
|
||||
assert.Equal(tc.expectedStatusCode, rr.Code)
|
||||
assert.Equal(tc.expectedBody, rr.Body.String())
|
||||
}
|
||||
}
|
|
@ -1,22 +1,20 @@
|
|||
package objects
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/datasources"
|
||||
"github.com/mastertinner/s3-manager/utils"
|
||||
)
|
||||
|
||||
// DeleteHandler deletes an object
|
||||
func DeleteHandler(s3 datasources.S3Client) http.Handler {
|
||||
// DeleteObjectHandler deletes an object
|
||||
func DeleteObjectHandler(s3 S3Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
err := s3.RemoveObject(vars["bucketName"], vars["objectName"])
|
||||
if err != nil {
|
||||
msg := "error removing object"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package objects_test
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -6,29 +6,24 @@ import (
|
|||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mastertinner/s3-manager/mock"
|
||||
"github.com/mastertinner/s3-manager/objects"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeleteHandler(t *testing.T) {
|
||||
func TestDeleteObjectHandler(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
s3Client *mock.S3Client
|
||||
tests := map[string]struct {
|
||||
s3Client S3Client
|
||||
expectedStatusCode int
|
||||
expectedBody string
|
||||
}{
|
||||
{
|
||||
description: "success",
|
||||
s3Client: &mock.S3Client{},
|
||||
"success": {
|
||||
s3Client: &S3ClientMock{},
|
||||
expectedStatusCode: http.StatusNoContent,
|
||||
expectedBody: "",
|
||||
},
|
||||
{
|
||||
description: "s3 error",
|
||||
s3Client: &mock.S3Client{
|
||||
"s3 error": {
|
||||
s3Client: &S3ClientMock{
|
||||
Err: errors.New("internal S3 error"),
|
||||
},
|
||||
expectedStatusCode: http.StatusInternalServerError,
|
||||
|
@ -41,11 +36,11 @@ func TestDeleteHandler(t *testing.T) {
|
|||
assert.NoError(err)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := objects.DeleteHandler(tc.s3Client)
|
||||
handler := DeleteObjectHandler(tc.s3Client)
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(tc.expectedStatusCode, rr.Code, tc.description)
|
||||
assert.Equal(tc.expectedBody, rr.Body.String(), tc.description)
|
||||
assert.Equal(tc.expectedStatusCode, rr.Code)
|
||||
assert.Equal(tc.expectedBody, rr.Body.String())
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package objects
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -6,12 +6,10 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/datasources"
|
||||
"github.com/mastertinner/s3-manager/utils"
|
||||
)
|
||||
|
||||
// GetHandler downloads an object to the client
|
||||
func GetHandler(s3 datasources.S3Client) http.Handler {
|
||||
// GetObjectHandler downloads an object to the client
|
||||
func GetObjectHandler(s3 S3Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
objectName := vars["objectName"]
|
||||
|
@ -19,7 +17,7 @@ func GetHandler(s3 datasources.S3Client) http.Handler {
|
|||
object, err := s3.GetObject(vars["bucketName"], objectName)
|
||||
if err != nil {
|
||||
msg := "error getting object"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -29,7 +27,7 @@ func GetHandler(s3 datasources.S3Client) http.Handler {
|
|||
_, err = io.Copy(w, object)
|
||||
if err != nil {
|
||||
msg := "error copying object"
|
||||
utils.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
|
@ -1,12 +1,12 @@
|
|||
package utils
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HandleHTTPError handles HTTP errors
|
||||
func HandleHTTPError(w http.ResponseWriter, msg string, err error, statusCode int) {
|
||||
// handleHTTPError handles HTTP errors
|
||||
func handleHTTPError(w http.ResponseWriter, msg string, err error, statusCode int) {
|
||||
http.Error(w, msg, statusCode)
|
||||
if err != nil {
|
||||
log.Println(msg+":", err.Error())
|
|
@ -1,9 +1,9 @@
|
|||
package views
|
||||
package main
|
||||
|
||||
import "net/http"
|
||||
|
||||
// IndexHandler forwards to "/buckets"
|
||||
func IndexHandler() http.Handler {
|
||||
func IndexViewHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/buckets", http.StatusPermanentRedirect)
|
||||
})
|
41
main.go
41
main.go
|
@ -6,15 +6,12 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/adapters"
|
||||
"github.com/mastertinner/s3-manager/buckets"
|
||||
"github.com/mastertinner/s3-manager/datasources"
|
||||
"github.com/mastertinner/s3-manager/objects"
|
||||
"github.com/mastertinner/s3-manager/views"
|
||||
"github.com/mastertinner/adapters"
|
||||
"github.com/mastertinner/adapters/logging"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s3 := datasources.NewMinioClient()
|
||||
s3 := NewMinioClient()
|
||||
logger := log.New(os.Stdout, "", log.Ldate|log.Ltime)
|
||||
router := mux.NewRouter()
|
||||
|
||||
|
@ -22,22 +19,22 @@ func main() {
|
|||
Methods("GET").
|
||||
Path("/").
|
||||
Handler(adapters.Adapt(
|
||||
views.IndexHandler(),
|
||||
adapters.Logging(logger),
|
||||
IndexViewHandler(),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
router.
|
||||
Methods("GET").
|
||||
Path("/buckets").
|
||||
Handler(adapters.Adapt(
|
||||
views.BucketsHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
BucketsViewHandler(s3),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
router.
|
||||
Methods("GET").
|
||||
Path("/buckets/{bucketName}").
|
||||
Handler(adapters.Adapt(
|
||||
views.BucketHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
BucketViewHandler(s3),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
|
||||
api := router.PathPrefix("/api").Subrouter()
|
||||
|
@ -47,36 +44,36 @@ func main() {
|
|||
Methods("POST").
|
||||
Path("").
|
||||
Handler(adapters.Adapt(
|
||||
buckets.CreateHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
CreateBucketHandler(s3),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
br.
|
||||
Methods("DELETE").
|
||||
Path("/{bucketName}").
|
||||
Handler(adapters.Adapt(
|
||||
buckets.DeleteHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
DeleteBucketHandler(s3),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
br.
|
||||
Methods("POST").
|
||||
Path("/{bucketName}/objects").
|
||||
Handler(adapters.Adapt(
|
||||
objects.CreateHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
CreateObjectHandler(s3),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
br.
|
||||
Methods("GET").
|
||||
Path("/{bucketName}/objects/{objectName}").
|
||||
Handler(adapters.Adapt(
|
||||
objects.GetHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
GetObjectHandler(s3),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
br.
|
||||
Methods("DELETE").
|
||||
Path("/{bucketName}/objects/{objectName}").
|
||||
Handler(adapters.Adapt(
|
||||
objects.DeleteHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
DeleteObjectHandler(s3),
|
||||
logging.Handler(logger),
|
||||
))
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package datasources
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
|
@ -1,46 +0,0 @@
|
|||
package mock
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
type S3Client struct {
|
||||
Buckets []minio.BucketInfo
|
||||
ObjectInfos []minio.ObjectInfo
|
||||
Objects []minio.Object
|
||||
Err error
|
||||
}
|
||||
|
||||
func (s S3Client) CopyObject(string, string, string, minio.CopyConditions) error {
|
||||
return s.Err
|
||||
}
|
||||
|
||||
func (s S3Client) GetObject(string, string) (*minio.Object, error) {
|
||||
return &s.Objects[0], s.Err
|
||||
}
|
||||
|
||||
func (s S3Client) ListBuckets() ([]minio.BucketInfo, error) {
|
||||
return s.Buckets, s.Err
|
||||
}
|
||||
|
||||
func (s S3Client) ListObjectsV2(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo {
|
||||
return make(<-chan minio.ObjectInfo)
|
||||
}
|
||||
|
||||
func (s S3Client) MakeBucket(string, string) error {
|
||||
return s.Err
|
||||
}
|
||||
|
||||
func (s S3Client) PutObject(string, string, io.Reader, string) (int64, error) {
|
||||
return 0, s.Err
|
||||
}
|
||||
|
||||
func (s S3Client) RemoveBucket(string) error {
|
||||
return s.Err
|
||||
}
|
||||
|
||||
func (s S3Client) RemoveObject(string, string) error {
|
||||
return s.Err
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package objects
|
||||
|
||||
import minio "github.com/minio/minio-go"
|
||||
|
||||
// WithIcon is a minio object with an added icon
|
||||
type WithIcon struct {
|
||||
minio.ObjectInfo
|
||||
Icon string
|
||||
}
|
47
s3-client-mock.go
Normal file
47
s3-client-mock.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// S3ClientMock is a mocked S3 client
|
||||
type S3ClientMock struct {
|
||||
Buckets []minio.BucketInfo
|
||||
ObjectInfos []minio.ObjectInfo
|
||||
Objects []minio.Object
|
||||
Err error
|
||||
}
|
||||
|
||||
func (s S3ClientMock) CopyObject(string, string, string, minio.CopyConditions) error {
|
||||
return s.Err
|
||||
}
|
||||
|
||||
func (s S3ClientMock) GetObject(string, string) (*minio.Object, error) {
|
||||
return &s.Objects[0], s.Err
|
||||
}
|
||||
|
||||
func (s S3ClientMock) ListBuckets() ([]minio.BucketInfo, error) {
|
||||
return s.Buckets, s.Err
|
||||
}
|
||||
|
||||
func (s S3ClientMock) ListObjectsV2(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo {
|
||||
return make(<-chan minio.ObjectInfo)
|
||||
}
|
||||
|
||||
func (s S3ClientMock) MakeBucket(string, string) error {
|
||||
return s.Err
|
||||
}
|
||||
|
||||
func (s S3ClientMock) PutObject(string, string, io.Reader, string) (int64, error) {
|
||||
return 0, s.Err
|
||||
}
|
||||
|
||||
func (s S3ClientMock) RemoveBucket(string) error {
|
||||
return s.Err
|
||||
}
|
||||
|
||||
func (s S3ClientMock) RemoveObject(string, string) error {
|
||||
return s.Err
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package datasources
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
|
@ -1,60 +0,0 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/objects"
|
||||
"github.com/mastertinner/s3-manager/web"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// BucketPage defines the details page of a bucket
|
||||
type BucketPage struct {
|
||||
BucketName string
|
||||
Objects []objects.WithIcon
|
||||
}
|
||||
|
||||
// BucketHandler shows the details page of a bucket
|
||||
func BucketHandler(s3 *minio.Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
bucketName := mux.Vars(r)["bucketName"]
|
||||
var objs []objects.WithIcon
|
||||
|
||||
l := path.Join("views", "layout.html")
|
||||
p := path.Join("views", "bucket.html")
|
||||
|
||||
t, err := template.ParseFiles(l, p)
|
||||
if err != nil {
|
||||
msg := "error parsing templates"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
objectCh := s3.ListObjectsV2(bucketName, "", true, doneCh)
|
||||
for object := range objectCh {
|
||||
if object.Err != nil {
|
||||
msg := "error listing objects"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
objectWithIcon := objects.WithIcon{object, icon(object.Key)}
|
||||
objs = append(objs, objectWithIcon)
|
||||
}
|
||||
|
||||
bucketPage := BucketPage{
|
||||
BucketName: bucketName,
|
||||
Objects: objs,
|
||||
}
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", bucketPage)
|
||||
if err != nil {
|
||||
msg := "error executing template"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/mastertinner/s3-manager/web"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// BucketsHandler shows all buckets
|
||||
func BucketsHandler(s3 *minio.Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
l := path.Join("views", "layout.html")
|
||||
p := path.Join("views", "buckets.html")
|
||||
|
||||
t, err := template.ParseFiles(l, p)
|
||||
if err != nil {
|
||||
msg := "error parsing templates"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
buckets, err := s3.ListBuckets()
|
||||
if err != nil {
|
||||
msg := "error listing buckets"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", buckets)
|
||||
if err != nil {
|
||||
msg := "error executing template"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package views
|
||||
|
||||
import "path"
|
||||
|
||||
// icon returns an icon for a file type
|
||||
func icon(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"
|
||||
}
|
Loading…
Reference in a new issue