diff --git a/internal/assets/assets.go b/assets/assets.go similarity index 76% rename from internal/assets/assets.go rename to assets/assets.go index 57b53df3..2c4744c2 100644 --- a/internal/assets/assets.go +++ b/assets/assets.go @@ -6,14 +6,14 @@ import ( "path/filepath" "strings" - "github.com/hacdias/caddy-filemanager/internal/config" + "github.com/hacdias/caddy-filemanager/config" ) // BaseURL is the url of the assets const BaseURL = "/_filemanagerinternal" -// ServeAssets provides the needed assets for the front-end -func ServeAssets(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { +// Serve provides the needed assets for the front-end +func Serve(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { // gets the filename to be used with Assets function filename := strings.Replace(r.URL.Path, c.BaseURL+BaseURL, "public", 1) file, err := Asset(filename) diff --git a/internal/assets/binary.go b/assets/binary.go similarity index 92% rename from internal/assets/binary.go rename to assets/binary.go index 45e67d7b..8e7a1e36 100644 --- a/internal/assets/binary.go +++ b/assets/binary.go @@ -268,16 +268,16 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ - ".jsbeautifyrc": Jsbeautifyrc, - "public/css/styles.css": publicCssStylesCss, - "public/js/application.js": publicJsApplicationJs, - "public/js/form2js.js": publicJsForm2jsJs, - "templates/actions.tmpl": templatesActionsTmpl, - "templates/base.tmpl": templatesBaseTmpl, - "templates/editor.tmpl": templatesEditorTmpl, + ".jsbeautifyrc": Jsbeautifyrc, + "public/css/styles.css": publicCssStylesCss, + "public/js/application.js": publicJsApplicationJs, + "public/js/form2js.js": publicJsForm2jsJs, + "templates/actions.tmpl": templatesActionsTmpl, + "templates/base.tmpl": templatesBaseTmpl, + "templates/editor.tmpl": templatesEditorTmpl, "templates/frontmatter.tmpl": templatesFrontmatterTmpl, - "templates/listing.tmpl": templatesListingTmpl, - "templates/single.tmpl": templatesSingleTmpl, + "templates/listing.tmpl": templatesListingTmpl, + "templates/single.tmpl": templatesSingleTmpl, } // AssetDir returns the file names below a certain @@ -319,6 +319,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ ".jsbeautifyrc": &bintree{Jsbeautifyrc, map[string]*bintree{}}, "public": &bintree{nil, map[string]*bintree{ @@ -327,16 +328,16 @@ var _bintree = &bintree{nil, map[string]*bintree{ }}, "js": &bintree{nil, map[string]*bintree{ "application.js": &bintree{publicJsApplicationJs, map[string]*bintree{}}, - "form2js.js": &bintree{publicJsForm2jsJs, map[string]*bintree{}}, + "form2js.js": &bintree{publicJsForm2jsJs, map[string]*bintree{}}, }}, }}, "templates": &bintree{nil, map[string]*bintree{ - "actions.tmpl": &bintree{templatesActionsTmpl, map[string]*bintree{}}, - "base.tmpl": &bintree{templatesBaseTmpl, map[string]*bintree{}}, - "editor.tmpl": &bintree{templatesEditorTmpl, map[string]*bintree{}}, + "actions.tmpl": &bintree{templatesActionsTmpl, map[string]*bintree{}}, + "base.tmpl": &bintree{templatesBaseTmpl, map[string]*bintree{}}, + "editor.tmpl": &bintree{templatesEditorTmpl, map[string]*bintree{}}, "frontmatter.tmpl": &bintree{templatesFrontmatterTmpl, map[string]*bintree{}}, - "listing.tmpl": &bintree{templatesListingTmpl, map[string]*bintree{}}, - "single.tmpl": &bintree{templatesSingleTmpl, map[string]*bintree{}}, + "listing.tmpl": &bintree{templatesListingTmpl, map[string]*bintree{}}, + "single.tmpl": &bintree{templatesSingleTmpl, map[string]*bintree{}}, }}, }} @@ -386,4 +387,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - diff --git a/assets/templates/base.tmpl b/assets/templates/base.tmpl index 3eff86fe..4f1abceb 100644 --- a/assets/templates/base.tmpl +++ b/assets/templates/base.tmpl @@ -110,5 +110,6 @@ + {{ if .Config.HugoEnabled }}{{ end }} diff --git a/internal/config/config.go b/config/config.go similarity index 100% rename from internal/config/config.go rename to config/config.go diff --git a/internal/file/editor.go b/directory/editor.go similarity index 89% rename from internal/file/editor.go rename to directory/editor.go index 89150d20..f02c95ec 100644 --- a/internal/file/editor.go +++ b/directory/editor.go @@ -1,10 +1,11 @@ -package file +package directory import ( "bytes" "path/filepath" "strings" + "github.com/hacdias/caddy-filemanager/frontmatter" "github.com/spf13/hugo/parser" ) @@ -13,7 +14,7 @@ type Editor struct { Class string Mode string Content string - FrontMatter *Content + FrontMatter *frontmatter.Content } // GetEditor gets the editor based on a FileInfo struct @@ -51,7 +52,7 @@ func (i *Info) GetEditor() (*Editor, error) { // Parses the page content and the frontmatter editor.Content = strings.TrimSpace(string(page.Content())) - editor.FrontMatter, _, err = Pretty(page.FrontMatter()) + editor.FrontMatter, _, err = frontmatter.Pretty(page.FrontMatter()) editor.Class = "complete" } else { // The editor will handle only content @@ -64,9 +65,9 @@ func (i *Info) GetEditor() (*Editor, error) { // Checks if the file already has the frontmatter rune and parses it if editor.hasFrontMatterRune(i.Raw) { - editor.FrontMatter, _, err = Pretty(i.Raw) + editor.FrontMatter, _, err = frontmatter.Pretty(i.Raw) } else { - editor.FrontMatter, _, err = Pretty(editor.appendFrontMatterRune(i.Raw, editor.Mode)) + editor.FrontMatter, _, err = frontmatter.Pretty(editor.appendFrontMatterRune(i.Raw, editor.Mode)) } // Check if there were any errors diff --git a/internal/file/file.go b/directory/file.go similarity index 98% rename from internal/file/file.go rename to directory/file.go index 2bc06876..8c352c34 100644 --- a/internal/file/file.go +++ b/directory/file.go @@ -1,4 +1,4 @@ -package file +package directory import ( "fmt" @@ -12,8 +12,8 @@ import ( "time" "github.com/dustin/go-humanize" - "github.com/hacdias/caddy-filemanager/internal/config" - p "github.com/hacdias/caddy-filemanager/internal/page" + "github.com/hacdias/caddy-filemanager/config" + p "github.com/hacdias/caddy-filemanager/page" "github.com/hacdias/caddy-filemanager/utils/errors" "github.com/mholt/caddy/caddyhttp/httpserver" ) diff --git a/internal/file/listing.go b/directory/listing.go similarity index 99% rename from internal/file/listing.go rename to directory/listing.go index d48c91ed..92aeceb5 100644 --- a/internal/file/listing.go +++ b/directory/listing.go @@ -1,4 +1,4 @@ -package file +package directory import ( "net/http" diff --git a/internal/file/update.go b/directory/update.go similarity index 97% rename from internal/file/update.go rename to directory/update.go index 3d07d70e..1df703bd 100644 --- a/internal/file/update.go +++ b/directory/update.go @@ -1,4 +1,4 @@ -package file +package directory import ( "bytes" @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/hacdias/caddy-filemanager/internal/config" + "github.com/hacdias/caddy-filemanager/config" "github.com/spf13/hugo/parser" ) diff --git a/filemanager.go b/filemanager.go index dd4168df..e5d76e4b 100644 --- a/filemanager.go +++ b/filemanager.go @@ -1,6 +1,6 @@ //go:generate go get github.com/jteeuwen/go-bindata //go:generate go install github.com/jteeuwen/go-bindata/go-bindata -//go:generate go-bindata -debug -pkg assets -prefix "assets" -o internal/assets/binary.go assets/... +//go:generate go-bindata -debug -pkg assets -prefix "assets" -o assets/binary.go assets/... // Package filemanager provides middleware for managing files in a directory // when directory path is requested instead of a specific file. Based on browse @@ -8,13 +8,19 @@ package filemanager import ( + "io" + "log" + "mime/multipart" "net/http" + "os" + "os/exec" + "path/filepath" "strings" - a "github.com/hacdias/caddy-filemanager/internal/assets" - "github.com/hacdias/caddy-filemanager/internal/config" - "github.com/hacdias/caddy-filemanager/internal/file" - "github.com/hacdias/caddy-filemanager/internal/vcs" + "github.com/hacdias/caddy-filemanager/assets" + "github.com/hacdias/caddy-filemanager/config" + "github.com/hacdias/caddy-filemanager/directory" + "github.com/hacdias/caddy-filemanager/page" "github.com/mholt/caddy/caddyhttp/httpserver" ) @@ -28,20 +34,20 @@ type FileManager struct { // ServeHTTP determines if the request is for this plugin, and if all prerequisites are met. func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { var ( - c *config.Config - fi *file.Info - code int - err error - assets bool + c *config.Config + fi *directory.Info + code int + err error + serveAssets bool ) for i := range f.Configs { if httpserver.Path(r.URL.Path).Matches(f.Configs[i].BaseURL) { c = &f.Configs[i] - assets = httpserver.Path(r.URL.Path).Matches(c.BaseURL + a.BaseURL) + serveAssets = httpserver.Path(r.URL.Path).Matches(c.BaseURL + assets.BaseURL) - if r.Method != http.MethodPost && !assets { - fi, code, err = file.GetInfo(r.URL, c) + if r.Method != http.MethodPost && !serveAssets { + fi, code, err = directory.GetInfo(r.URL, c) if err != nil { return code, err } @@ -56,8 +62,8 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err switch r.Method { case http.MethodGet: // Read and show directory or file - if assets { - return a.ServeAssets(w, r, c) + if serveAssets { + return assets.Serve(w, r, c) } if !fi.IsDir { @@ -82,7 +88,7 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err case http.MethodPost: // Upload a new file if r.Header.Get("Upload") == "true" { - return file.Upload(w, r, c) + return upload(w, r, c) } // Search and git commands if r.Header.Get("Search") == "true" { @@ -91,11 +97,11 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err // VCS commands if r.Header.Get("Command") != "" { // TODO: not implemented on frontend - vcs.Handle(w, r, c) + vcsCommand(w, r, c) } // Creates a new folder // TODO: not implemented on frontend - return file.NewDir(w, r, c) + return newDirectory(w, r, c) case http.MethodDelete: // Delete a file or a directory return fi.Delete() @@ -110,3 +116,91 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err return f.Next.ServeHTTP(w, r) } + +// upload is used to handle the upload requests to the server +func upload(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { + // Parse the multipart form in the request + err := r.ParseMultipartForm(100000) + if err != nil { + log.Println(err) + return http.StatusInternalServerError, err + } + + // For each file header in the multipart form + for _, headers := range r.MultipartForm.File { + // Handle each file + for _, header := range headers { + // Open the first file + var src multipart.File + if src, err = header.Open(); nil != err { + return http.StatusInternalServerError, err + } + + filename := strings.Replace(r.URL.Path, c.BaseURL, c.PathScope, 1) + filename = filename + header.Filename + filename = filepath.Clean(filename) + + // Create the file + var dst *os.File + if dst, err = os.Create(filename); nil != err { + if os.IsExist(err) { + return http.StatusConflict, err + } + return http.StatusInternalServerError, err + } + + // Copy the file content + if _, err = io.Copy(dst, src); nil != err { + return http.StatusInternalServerError, err + } + + defer dst.Close() + } + } + + return http.StatusOK, nil +} + +// newDirectory makes a new directory +func newDirectory(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { + path := strings.Replace(r.URL.Path, c.BaseURL, c.PathScope, 1) + path = filepath.Clean(path) + err := os.MkdirAll(path, 0755) + if err != nil { + switch { + case os.IsPermission(err): + return http.StatusForbidden, err + case os.IsExist(err): + return http.StatusConflict, err + default: + return http.StatusInternalServerError, err + } + } + return http.StatusCreated, nil +} + +// vcsCommand handles the requests for VCS related commands: git, svn and mercurial +func vcsCommand(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { + command := strings.Split(r.Header.Get("command"), " ") + + // Check if the command is for git, mercurial or svn + if command[0] != "git" && command[0] != "hg" && command[0] != "svn" { + return http.StatusForbidden, nil + } + + // Check if the program is talled is installed on the computer + if _, err := exec.LookPath(command[0]); err != nil { + return http.StatusNotImplemented, nil + } + + cmd := exec.Command(command[0], command[1:len(command)]...) + cmd.Dir = c.PathScope + output, err := cmd.CombinedOutput() + + if err != nil { + return http.StatusInternalServerError, err + } + + page := &page.Page{Info: &page.Info{Data: string(output)}} + return page.PrintAsJSON(w) +} diff --git a/internal/file/frontmatter.go b/frontmatter/frontmatter.go similarity index 99% rename from internal/file/frontmatter.go rename to frontmatter/frontmatter.go index 77f24248..6290942f 100644 --- a/internal/file/frontmatter.go +++ b/frontmatter/frontmatter.go @@ -1,4 +1,4 @@ -package file +package frontmatter import ( "bytes" diff --git a/internal/file/dir.go b/internal/file/dir.go deleted file mode 100644 index e4e1a465..00000000 --- a/internal/file/dir.go +++ /dev/null @@ -1,28 +0,0 @@ -package file - -import ( - "net/http" - "os" - "path/filepath" - "strings" - - "github.com/hacdias/caddy-filemanager/internal/config" -) - -// NewDir makes a new directory -func NewDir(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { - path := strings.Replace(r.URL.Path, c.BaseURL, c.PathScope, 1) - path = filepath.Clean(path) - err := os.MkdirAll(path, 0755) - if err != nil { - switch { - case os.IsPermission(err): - return http.StatusForbidden, err - case os.IsExist(err): - return http.StatusConflict, err - default: - return http.StatusInternalServerError, err - } - } - return http.StatusCreated, nil -} diff --git a/internal/file/upload.go b/internal/file/upload.go deleted file mode 100644 index 49b85562..00000000 --- a/internal/file/upload.go +++ /dev/null @@ -1,57 +0,0 @@ -package file - -import ( - "io" - "log" - "mime/multipart" - "net/http" - "os" - "path/filepath" - "strings" - - "github.com/hacdias/caddy-filemanager/internal/config" -) - -// Upload is used to handle the upload requests to the server -func Upload(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { - // Parse the multipart form in the request - err := r.ParseMultipartForm(100000) - if err != nil { - log.Println(err) - return http.StatusInternalServerError, err - } - - // For each file header in the multipart form - for _, headers := range r.MultipartForm.File { - // Handle each file - for _, header := range headers { - // Open the first file - var src multipart.File - if src, err = header.Open(); nil != err { - return http.StatusInternalServerError, err - } - - filename := strings.Replace(r.URL.Path, c.BaseURL, c.PathScope, 1) - filename = filename + header.Filename - filename = filepath.Clean(filename) - - // Create the file - var dst *os.File - if dst, err = os.Create(filename); nil != err { - if os.IsExist(err) { - return http.StatusConflict, err - } - return http.StatusInternalServerError, err - } - - // Copy the file content - if _, err = io.Copy(dst, src); nil != err { - return http.StatusInternalServerError, err - } - - defer dst.Close() - } - } - - return http.StatusOK, nil -} diff --git a/internal/search/search.go b/internal/search/search.go deleted file mode 100644 index 5ed85155..00000000 --- a/internal/search/search.go +++ /dev/null @@ -1 +0,0 @@ -package search diff --git a/internal/vcs/vcs.go b/internal/vcs/vcs.go deleted file mode 100644 index a549e32a..00000000 --- a/internal/vcs/vcs.go +++ /dev/null @@ -1,36 +0,0 @@ -package vcs - -import ( - "net/http" - "os/exec" - "strings" - - "github.com/hacdias/caddy-filemanager/internal/config" - "github.com/hacdias/caddy-filemanager/internal/page" -) - -// Handle handles the POST method on GIT page which is only an API. -func Handle(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { - command := strings.Split(r.Header.Get("command"), " ") - - // Check if the command is for git, mercurial or svn - if command[0] != "git" && command[0] != "hg" && command[0] != "svn" { - return http.StatusForbidden, nil - } - - // Check if the program is talled is installed on the computer - if _, err := exec.LookPath(command[0]); err != nil { - return http.StatusNotImplemented, nil - } - - cmd := exec.Command(command[0], command[1:len(command)]...) - cmd.Dir = c.PathScope - output, err := cmd.CombinedOutput() - - if err != nil { - return http.StatusInternalServerError, err - } - - page := &page.Page{Info: &page.Info{Data: string(output)}} - return page.PrintAsJSON(w) -} diff --git a/internal/page/page.go b/page/page.go similarity index 96% rename from internal/page/page.go rename to page/page.go index d7fc2605..17dfa00c 100644 --- a/internal/page/page.go +++ b/page/page.go @@ -8,8 +8,8 @@ import ( "net/http" "strings" - "github.com/hacdias/caddy-filemanager/internal/assets" - "github.com/hacdias/caddy-filemanager/internal/config" + "github.com/hacdias/caddy-filemanager/assets" + "github.com/hacdias/caddy-filemanager/config" "github.com/hacdias/caddy-filemanager/utils/variables" ) diff --git a/setup.go b/setup.go index c8371205..a7c97b1b 100644 --- a/setup.go +++ b/setup.go @@ -1,7 +1,7 @@ package filemanager import ( - "github.com/hacdias/caddy-filemanager/internal/config" + "github.com/hacdias/caddy-filemanager/config" "github.com/mholt/caddy" "github.com/mholt/caddy/caddyhttp/httpserver" )