From e1972b166f8388082f1d8a1a140fab845993764c Mon Sep 17 00:00:00 2001 From: t-takahashi Date: Wed, 10 Jul 2024 08:36:35 +0900 Subject: [PATCH] add download logic and test --- Dockerfile | 2 +- core/logging/request_logging.go | 4 +- core/util/object.go | 4 +- go.mod | 2 + go.sum | 2 + web/rename_controller.go | 41 ++++++++++++++ web/s3_controller.go | 96 +++++++++++++++++++++++++++++++++ web/s3_controller_test.go | 12 +++++ web/ui_controller.go | 90 ------------------------------- 9 files changed, 158 insertions(+), 95 deletions(-) create mode 100644 go.sum create mode 100644 web/rename_controller.go create mode 100644 web/s3_controller.go create mode 100644 web/s3_controller_test.go delete mode 100644 web/ui_controller.go diff --git a/Dockerfile b/Dockerfile index 72249d8..c4e490e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM golang:latest WORKDIR /app COPY go.mod . -# COPY go.sum . +COPY go.sum . RUN mkdir upload RUN go mod download COPY . . diff --git a/core/logging/request_logging.go b/core/logging/request_logging.go index b62621b..292196e 100644 --- a/core/logging/request_logging.go +++ b/core/logging/request_logging.go @@ -16,7 +16,7 @@ func LogRequest(r *http.Request) { // skip Authorization header continue } - slog.Info("[Request Header]", name, h) + slog.Debug("[Request Header]", name, h) } } @@ -26,5 +26,5 @@ func LogRequest(r *http.Request) { return } r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) - slog.Info("[Request Body]" + string(bodyBytes)) + slog.Debug("[Request Body]" + string(bodyBytes)) } diff --git a/core/util/object.go b/core/util/object.go index 1e3d770..c602d04 100644 --- a/core/util/object.go +++ b/core/util/object.go @@ -10,8 +10,8 @@ import ( "github.com/tttol/mos3/core/model" ) -func GenerateS3Objects(r *http.Request, dir string, path string) ([]model.S3Object, error) { - dirEntry, err := os.ReadDir(filepath.Join(dir, path)) +func GenerateS3Objects(r *http.Request, dir string, dirPath string) ([]model.S3Object, error) { + dirEntry, err := os.ReadDir(filepath.Join(dir, dirPath)) if err != nil { slog.Error("ReadDir error", "error", err) return nil, err diff --git a/go.mod b/go.mod index 6b1da2f..d4dd672 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/tttol/mos3 go 1.21.3 + +require github.com/go-playground/assert/v2 v2.2.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1998fd7 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= diff --git a/web/rename_controller.go b/web/rename_controller.go new file mode 100644 index 0000000..63e48a5 --- /dev/null +++ b/web/rename_controller.go @@ -0,0 +1,41 @@ +package web + +import ( + "net/http" + "os" + "path/filepath" +) + +func RenameHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + oldFilename := r.FormValue("oldFilename") + newFilename := r.FormValue("newFilename") + err := os.Rename(filepath.Join(UPLOAD_DIR, oldFilename), filepath.Join(UPLOAD_DIR, newFilename)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + http.Redirect(w, r, "/", http.StatusFound) +} + +func RenamedirHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + oldDirname := r.FormValue("oldDirname") + newDirname := r.FormValue("newDirname") + err := os.Rename(filepath.Join(UPLOAD_DIR, oldDirname), filepath.Join(UPLOAD_DIR, newDirname)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + http.Redirect(w, r, "/", http.StatusFound) +} diff --git a/web/s3_controller.go b/web/s3_controller.go new file mode 100644 index 0000000..4241034 --- /dev/null +++ b/web/s3_controller.go @@ -0,0 +1,96 @@ +package web + +import ( + "io" + "log/slog" + "net/http" + "os" + "path/filepath" + "regexp" + "text/template" + + "github.com/tttol/mos3/core/util" +) + +func S3Handler(w http.ResponseWriter, r *http.Request) { + slog.Info("S3Handler is called.") + path := r.URL.Path[len("/s3/"):] + + s3Objects, err := util.GenerateS3Objects(r, UPLOAD_DIR, GetDirPath(path)) + if err != nil { + slog.Error("GenerateS3Objects error", "error", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + var currentPath string + if path == "" { + currentPath = "/" + } else { + currentPath = path + } + + dataMap := map[string]interface{}{ + "S3Objects": s3Objects, + "Breadcrumbs": util.GenerateBreadcrumbs(path), + "CurrentPath": currentPath, + } + + tmpl, err := template.ParseFiles("static/index.html") + if err != nil { + slog.Error("template file error", "error", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if r.URL.Query().Get("action") == "dl" { + _, status, err := download(w, path) + if err != nil { + http.Error(w, err.Error(), status) + return + } + } + + slog.Info("dataMap", "dataMap", dataMap) + tmpl.Execute(w, dataMap) +} + +// It returns the number of bytes copied and the first error encountered while copying, if any. +func download(w http.ResponseWriter, path string) (n int64, httpStatus int, err error) { + slog.Info("Start downloading file", "path", path) + + file, err := os.Open(filepath.Join(UPLOAD_DIR, path)) + if err != nil { + slog.Error("File open error", "error", err) + return 0, http.StatusNotFound, err + } + defer file.Close() + + stat, err := file.Stat() + if err != nil { + slog.Error("File stat error", "error", err) + return 0, http.StatusNotFound, err + } + + w.Header().Set("Content-Disposition", "attachment; filename="+stat.Name()) + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Length", string(rune(stat.Size()))) + + writtenByteSize, err := io.Copy(w, file) + if err != nil { + slog.Error("File copy error", "error", err) + return 0, http.StatusInternalServerError, err + } + + slog.Info("Successful to dowload file", "path", path) + return writtenByteSize, http.StatusOK, nil +} + +func GetDirPath(path string) string { + re := regexp.MustCompile(`\.\w+$`) + if re.MatchString(path) { + return filepath.Dir(path) + } else { + return path + } +} diff --git a/web/s3_controller_test.go b/web/s3_controller_test.go new file mode 100644 index 0000000..5231483 --- /dev/null +++ b/web/s3_controller_test.go @@ -0,0 +1,12 @@ +package web + +import ( + "testing" + + "github.com/go-playground/assert/v2" +) + +func TestGetDirPath(t *testing.T) { + assert.Equal(t, GetDirPath("/hoge/fuga"), "/hoge/fuga") + assert.Equal(t, GetDirPath("/hoge/fuga/piyo.txt"), "/hoge/fuga") +} diff --git a/web/ui_controller.go b/web/ui_controller.go deleted file mode 100644 index cc4029e..0000000 --- a/web/ui_controller.go +++ /dev/null @@ -1,90 +0,0 @@ -package web - -import ( - "log/slog" - "net/http" - "os" - "path/filepath" - "text/template" - - "github.com/tttol/mos3/core/util" -) - -func S3Handler(w http.ResponseWriter, r *http.Request) { - slog.Info("S3Handler is called.") - path := r.URL.Path[len("/s3/"):] - if r.URL.Query().Get("action") == "dl" { - download(path) - return - } - - s3Objects, err := util.GenerateS3Objects(r, UPLOAD_DIR, path) - if err != nil { - slog.Error("GenerateS3Objects error", "error", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - var currentPath string - if path == "" { - currentPath = "/" - } else { - currentPath = path - } - - dataMap := map[string]interface{}{ - "S3Objects": s3Objects, - "Breadcrumbs": util.GenerateBreadcrumbs(path), - "CurrentPath": currentPath, - } - - tmpl, err := template.ParseFiles("static/index.html") - if err != nil { - slog.Error("template file error", "error", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - slog.Info("dataMap", "dataMap", dataMap) - tmpl.Execute(w, dataMap) -} - - - -func RenameHandler(w http.ResponseWriter, r *http.Request) { - if r.Method != "POST" { - http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) - return - } - - oldFilename := r.FormValue("oldFilename") - newFilename := r.FormValue("newFilename") - err := os.Rename(filepath.Join(UPLOAD_DIR, oldFilename), filepath.Join(UPLOAD_DIR, newFilename)) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - http.Redirect(w, r, "/", http.StatusFound) -} - -func RenamedirHandler(w http.ResponseWriter, r *http.Request) { - if r.Method != "POST" { - http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) - return - } - - oldDirname := r.FormValue("oldDirname") - newDirname := r.FormValue("newDirname") - err := os.Rename(filepath.Join(UPLOAD_DIR, oldDirname), filepath.Join(UPLOAD_DIR, newDirname)) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - http.Redirect(w, r, "/", http.StatusFound) -} - -func download(path string) { - slog.Info("Download file", "path", path) -}