Restructure app with modules
This commit is contained in:
parent
8e94fc2781
commit
8f47c50f72
20 changed files with 396 additions and 316 deletions
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package adapters
|
||||
|
||||
import "net/http"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package adapters
|
||||
|
||||
import (
|
||||
"log"
|
168
api.go
168
api.go
|
@ -1,168 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// CopyObjectInfo is the information about an object to copy
|
||||
type CopyObjectInfo struct {
|
||||
BucketName string `json:"bucketName"`
|
||||
ObjectName string `json:"objectName"`
|
||||
SourceBucketName string `json:"sourceBucketName"`
|
||||
SourceObjectName string `json:"sourceObjectName"`
|
||||
}
|
||||
|
||||
// CreateBucketHandler creates a new bucket
|
||||
func (s *Server) CreateBucketHandler() 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"
|
||||
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
err = s.S3.MakeBucket(bucket.Name, "")
|
||||
if err != nil {
|
||||
msg := "error making bucket"
|
||||
handleHTTPError(w, msg, err, 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 {
|
||||
msg := "error encoding json"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// CreateObjectHandler allows to upload a new object
|
||||
func (s *Server) CreateObjectHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
var copy CopyObjectInfo
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(©)
|
||||
if err != nil {
|
||||
msg := "error decoding json"
|
||||
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
var copyConds = minio.NewCopyConditions()
|
||||
objectSource := fmt.Sprintf("/%s/%s", copy.SourceBucketName, copy.SourceObjectName)
|
||||
err = s.S3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds)
|
||||
if err != nil {
|
||||
msg := "error copying object"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
|
||||
err = json.NewEncoder(w).Encode(copy)
|
||||
if err != nil {
|
||||
msg := "error encoding json"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err := r.ParseMultipartForm(32 << 20)
|
||||
if err != nil {
|
||||
msg := "error parsing form"
|
||||
handleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
file, handler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
msg := "error getting form file"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = s.S3.PutObject(vars["bucketName"], handler.Filename, file, "application/octet-stream")
|
||||
if err != nil {
|
||||
msg := "error putting object"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteBucketHandler deletes a bucket
|
||||
func (s *Server) DeleteBucketHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
err := s.S3.RemoveBucket(vars["bucketName"])
|
||||
if err != nil {
|
||||
msg := "error removing bucket"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteObjectHandler deletes an object
|
||||
func (s *Server) DeleteObjectHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
err := s.S3.RemoveObject(vars["bucketName"], vars["objectName"])
|
||||
if err != nil {
|
||||
msg := "error removing object"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
}
|
||||
|
||||
// GetObjectHandler downloads an object to the client
|
||||
func (s *Server) GetObjectHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
objectName := vars["objectName"]
|
||||
|
||||
object, err := s.S3.GetObject(vars["bucketName"], objectName)
|
||||
if err != nil {
|
||||
msg := "error getting object"
|
||||
handleHTTPError(w, msg, err, 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 {
|
||||
msg := "error copying object"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
40
buckets/create-handler.go
Normal file
40
buckets/create-handler.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package buckets
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/mastertinner/s3-manager/web"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// CreateHandler creates a new bucket
|
||||
func CreateHandler(s3 *minio.Client) 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"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
err = s3.MakeBucket(bucket.Name, "")
|
||||
if err != nil {
|
||||
msg := "error making bucket"
|
||||
web.HandleHTTPError(w, msg, err, 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 {
|
||||
msg := "error encoding json"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
25
buckets/delete-handler.go
Normal file
25
buckets/delete-handler.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package buckets
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/web"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// DeleteHandler deletes a bucket
|
||||
func DeleteHandler(s3 *minio.Client) 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"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package datasources
|
||||
|
||||
import (
|
||||
"log"
|
67
main.go
67
main.go
|
@ -6,18 +6,15 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/minio/minio-go"
|
||||
"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"
|
||||
)
|
||||
|
||||
// Server is a server containing a minio client
|
||||
type Server struct {
|
||||
S3 *minio.Client
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := &Server{
|
||||
S3: NewMinioClient(),
|
||||
}
|
||||
s3 := datasources.NewMinioClient()
|
||||
|
||||
logger := log.New(os.Stdout, "request: ", log.Lshortfile)
|
||||
router := mux.NewRouter()
|
||||
|
@ -25,39 +22,63 @@ func main() {
|
|||
router.
|
||||
Methods("GET").
|
||||
Path("/").
|
||||
Handler(Adapt(IndexHandler(), Logging(logger)))
|
||||
Handler(adapters.Adapt(
|
||||
views.IndexHandler(),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
router.
|
||||
Methods("GET").
|
||||
Path("/buckets").
|
||||
Handler(Adapt(s.BucketsPageHandler(), Logging(logger)))
|
||||
Handler(adapters.Adapt(
|
||||
views.BucketsHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
router.
|
||||
Methods("GET").
|
||||
Path("/buckets/{bucketName}").
|
||||
Handler(Adapt(s.BucketPageHandler(), Logging(logger)))
|
||||
Handler(adapters.Adapt(
|
||||
views.BucketHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
|
||||
api := router.PathPrefix("/api").Subrouter()
|
||||
|
||||
buckets := api.PathPrefix("/buckets").Subrouter()
|
||||
buckets.
|
||||
br := api.PathPrefix("/buckets").Subrouter()
|
||||
br.
|
||||
Methods("POST").
|
||||
Path("").
|
||||
Handler(Adapt(s.CreateBucketHandler(), Logging(logger)))
|
||||
buckets.
|
||||
Handler(adapters.Adapt(
|
||||
buckets.CreateHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
br.
|
||||
Methods("DELETE").
|
||||
Path("/{bucketName}").
|
||||
Handler(Adapt(s.DeleteBucketHandler(), Logging(logger)))
|
||||
buckets.
|
||||
Handler(adapters.Adapt(
|
||||
buckets.DeleteHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
br.
|
||||
Methods("POST").
|
||||
Path("/{bucketName}/objects").
|
||||
Handler(Adapt(s.CreateObjectHandler(), Logging(logger)))
|
||||
buckets.
|
||||
Handler(adapters.Adapt(
|
||||
objects.CreateHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
br.
|
||||
Methods("GET").
|
||||
Path("/{bucketName}/objects/{objectName}").
|
||||
Handler(Adapt(s.GetObjectHandler(), Logging(logger)))
|
||||
buckets.
|
||||
Handler(adapters.Adapt(
|
||||
objects.GetHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
br.
|
||||
Methods("DELETE").
|
||||
Path("/{bucketName}/objects/{objectName}").
|
||||
Handler(Adapt(s.DeleteObjectHandler(), Logging(logger)))
|
||||
Handler(adapters.Adapt(
|
||||
objects.DeleteHandler(s3),
|
||||
adapters.Logging(logger),
|
||||
))
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
if len(port) == 0 {
|
||||
|
|
80
objects/create-handler.go
Normal file
80
objects/create-handler.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package objects
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/web"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// CopyObjectInfo is the information about an object to copy
|
||||
type CopyObjectInfo struct {
|
||||
BucketName string `json:"bucketName"`
|
||||
ObjectName string `json:"objectName"`
|
||||
SourceBucketName string `json:"sourceBucketName"`
|
||||
SourceObjectName string `json:"sourceObjectName"`
|
||||
}
|
||||
|
||||
// CreateHandler allows to upload a new object
|
||||
func CreateHandler(s3 *minio.Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
var copy CopyObjectInfo
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(©)
|
||||
if err != nil {
|
||||
msg := "error decoding json"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
var copyConds = minio.NewCopyConditions()
|
||||
objectSource := fmt.Sprintf("/%s/%s", copy.SourceBucketName, copy.SourceObjectName)
|
||||
err = s3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds)
|
||||
if err != nil {
|
||||
msg := "error copying object"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
|
||||
err = json.NewEncoder(w).Encode(copy)
|
||||
if err != nil {
|
||||
msg := "error encoding json"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err := r.ParseMultipartForm(32 << 20)
|
||||
if err != nil {
|
||||
msg := "error parsing form"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
file, handler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
msg := "error getting form file"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = s3.PutObject(vars["bucketName"], handler.Filename, file, "application/octet-stream")
|
||||
if err != nil {
|
||||
msg := "error putting object"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
})
|
||||
}
|
25
objects/delete-handler.go
Normal file
25
objects/delete-handler.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package objects
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/web"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// DeleteHandler deletes an object
|
||||
func DeleteHandler(s3 *minio.Client) 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"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
}
|
36
objects/get-handler.go
Normal file
36
objects/get-handler.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package objects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mastertinner/s3-manager/web"
|
||||
minio "github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// GetHandler downloads an object to the client
|
||||
func GetHandler(s3 *minio.Client) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
objectName := vars["objectName"]
|
||||
|
||||
object, err := s3.GetObject(vars["bucketName"], objectName)
|
||||
if err != nil {
|
||||
msg := "error getting object"
|
||||
web.HandleHTTPError(w, msg, err, 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 {
|
||||
msg := "error copying object"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
9
objects/with-icon.go
Normal file
9
objects/with-icon.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
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
|
||||
}
|
116
pages.go
116
pages.go
|
@ -1,116 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/minio/minio-go"
|
||||
)
|
||||
|
||||
// BucketPage defines the details page of a bucket
|
||||
type BucketPage struct {
|
||||
BucketName string
|
||||
Objects []ObjectWithIcon
|
||||
}
|
||||
|
||||
// ObjectWithIcon is a minio object with an added icon
|
||||
type ObjectWithIcon struct {
|
||||
minio.ObjectInfo
|
||||
Icon string
|
||||
}
|
||||
|
||||
// BucketPageHandler shows the details page of a bucket
|
||||
func (s *Server) BucketPageHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
bucketName := mux.Vars(r)["bucketName"]
|
||||
var objects []ObjectWithIcon
|
||||
|
||||
lp := path.Join("templates", "layout.html")
|
||||
bp := path.Join("templates", "bucket.html")
|
||||
|
||||
t, err := template.ParseFiles(lp, bp)
|
||||
if err != nil {
|
||||
msg := "error parsing templates"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
objectCh := s.S3.ListObjectsV2(bucketName, "", false, 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)}
|
||||
objects = append(objects, objectWithIcon)
|
||||
}
|
||||
|
||||
bucketPage := BucketPage{
|
||||
BucketName: bucketName,
|
||||
Objects: objects,
|
||||
}
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", bucketPage)
|
||||
if err != nil {
|
||||
msg := "error executing template"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BucketsPageHandler shows all buckets
|
||||
func (s *Server) BucketsPageHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
lp := path.Join("templates", "layout.html")
|
||||
ip := path.Join("templates", "index.html")
|
||||
|
||||
t, err := template.ParseFiles(lp, ip)
|
||||
if err != nil {
|
||||
msg := "error parsing templates"
|
||||
handleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
buckets, err := s.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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// IndexHandler forwards to "/buckets"
|
||||
func IndexHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/buckets", http.StatusPermanentRedirect)
|
||||
})
|
||||
}
|
||||
|
||||
// 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"
|
||||
}
|
60
views/bucket-handler.go
Normal file
60
views/bucket-handler.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
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
|
||||
|
||||
lp := path.Join("views", "layout.html")
|
||||
p := path.Join("views", "bucket.html")
|
||||
|
||||
t, err := template.ParseFiles(lp, p)
|
||||
if err != nil {
|
||||
msg := "error parsing templates"
|
||||
web.HandleHTTPError(w, msg, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
objectCh := s3.ListObjectsV2(bucketName, "", false, 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
|
||||
}
|
||||
})
|
||||
}
|
39
views/buckets-handler.go
Normal file
39
views/buckets-handler.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
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) {
|
||||
lp := path.Join("views", "layout.html")
|
||||
p := path.Join("views", "buckets.html")
|
||||
|
||||
t, err := template.ParseFiles(lp, 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
|
||||
}
|
||||
})
|
||||
}
|
19
views/icon.go
Normal file
19
views/icon.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
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"
|
||||
}
|
10
views/index-handler.go
Normal file
10
views/index-handler.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package views
|
||||
|
||||
import "net/http"
|
||||
|
||||
// IndexHandler forwards to "/buckets"
|
||||
func IndexHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/buckets", http.StatusPermanentRedirect)
|
||||
})
|
||||
}
|
|
@ -10,15 +10,15 @@
|
|||
<title>S3 Manager</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/css/materialize.min.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
{{ template "content" . }}
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.2.0.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/js/materialize.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('.modal').modal();
|
|
@ -1,12 +1,12 @@
|
|||
package main
|
||||
package web
|
||||
|
||||
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())
|
Loading…
Reference in a new issue