From 59954b94d806d3e343b0fa6a17c70066b9d8fcda Mon Sep 17 00:00:00 2001 From: Derek Stevens Date: Fri, 10 Jun 2022 00:38:29 -0600 Subject: [PATCH] fix style and implement basic static file tree browsing --- archetype/config.go | 12 +++-- archetype/eureka.go | 2 +- archetype/fileManager.go | 88 ++++++++++++++++++++++++++++++++++ archetype/staticFileManager.go | 16 ------- lfo/middleware.go | 9 ++++ nirvash.go | 20 +++++++- static/delete.svg | 23 +++++++++ static/move.svg | 6 +++ static/style.css | 5 ++ templates/file_list.html | 34 +++++++++++++ templates/header.html | 2 +- 11 files changed, 193 insertions(+), 24 deletions(-) create mode 100644 archetype/fileManager.go delete mode 100644 archetype/staticFileManager.go create mode 100644 static/delete.svg create mode 100644 static/move.svg create mode 100644 templates/file_list.html diff --git a/archetype/config.go b/archetype/config.go index 425d43f..ea13c82 100644 --- a/archetype/config.go +++ b/archetype/config.go @@ -9,11 +9,13 @@ import ( ) type Config struct { - Adapter Adapter // adapter for this instance - Root string // root of the site data - StaticRoot string // root of static files for StaticFileManager - AssetRoot string // root of Nirvash dist files (CSS, images) - Plugins map[string]interface{} + Adapter Adapter // adapter for this instance + Root string // root of the site data + StaticRoot string // root of static files for StaticFileManager + StaticShowHidden bool // whether to show hidden files in the StaticFileManager + StaticShowHtml bool // whether to show html files in the StaticFileManager + AssetRoot string // root of Nirvash dist files (CSS, images) + Plugins map[string]interface{} } func GetConfigLocation() string { diff --git a/archetype/eureka.go b/archetype/eureka.go index cdcc9dd..16c9151 100644 --- a/archetype/eureka.go +++ b/archetype/eureka.go @@ -25,7 +25,7 @@ func (self *EurekaAdapter) Init(cfg *Config) { self.Root = cfg.Root self.Config = make(map[ConfigOption]string) - // TODO: read config.h and build self.Config + err = self.readCfg() if err != nil { panic("config.h is malformed!") diff --git a/archetype/fileManager.go b/archetype/fileManager.go new file mode 100644 index 0000000..69471ce --- /dev/null +++ b/archetype/fileManager.go @@ -0,0 +1,88 @@ +package archetype + +import ( + "io/ioutil" + "path/filepath" + "strings" +) + +type SimpleFileManager struct { + Root string + ShowHtml bool + ShowHidden bool +} + +type FileListing struct { + Error string + Root string + Up string + SubDirs []string + Files []string +} + +type FileManager interface { + Init(cfg *Config) error + // ListTree() FileListing + ListSubTree(root string) FileListing + // AddFile(path string, file multipart.FileHeader) error + // MkDir(path string) error + // Remove(path string) error + // Rename(old, new string) error +} + +func (self *SimpleFileManager) Init(cfg *Config) error { + self.Root = cfg.StaticRoot + self.ShowHtml = cfg.StaticShowHtml + self.ShowHidden = cfg.StaticShowHidden + return nil +} + +func (self *SimpleFileManager) ListSubTree(root string) FileListing { + list := FileListing{} + + if strings.Contains(root, "../") || strings.Contains(root, "..\\") { + list.Error = "You cannot escape!" + return list + } + + fullPath := filepath.Join(self.Root, root) + + files, err := ioutil.ReadDir(fullPath) + + if err != nil { + list.Error = err.Error() + return list + } + + list.Root = root + if !strings.HasSuffix(list.Root, "/") { + list.Root += "/" + } + if !strings.HasPrefix(list.Root, "/") { + list.Root = "/" + list.Root + } + + levels := strings.Split(root, "/") + if list.Root != "/" { + list.Up = "/" + } + if len(levels) >= 2 { + list.Up = "/" + strings.Join(levels[:len(levels)-1], "/") + } + + for _, file := range files { + if !self.ShowHidden && strings.HasPrefix(file.Name(), ".") { + continue + } + if file.IsDir() { + list.SubDirs = append(list.SubDirs, file.Name()) + } else { + if !self.ShowHtml && strings.HasSuffix(file.Name(), ".html") { + continue + } + list.Files = append(list.Files, file.Name()) + } + } + + return list +} diff --git a/archetype/staticFileManager.go b/archetype/staticFileManager.go deleted file mode 100644 index de6d1e4..0000000 --- a/archetype/staticFileManager.go +++ /dev/null @@ -1,16 +0,0 @@ -package archetype - -type StaticFileManager struct { - Root string - ShowHtml bool - ShowHidden bool -} - -type FileManager interface { - Init(cfg Config) error - ListTree() []string - ListSubTree(root string) []string - AddFile(path string, file interface{}) error - MkDir(path string) error - Remove(path string) error -} diff --git a/lfo/middleware.go b/lfo/middleware.go index 0958d4d..accbed5 100644 --- a/lfo/middleware.go +++ b/lfo/middleware.go @@ -16,6 +16,15 @@ func WithAdapter(next http.Handler, adapter core.Adapter) http.Handler { return http.HandlerFunc(handlerFunc) } +func WithFileManager(next http.Handler, fileManager core.FileManager) http.Handler { + handlerFunc := func(w http.ResponseWriter, req *http.Request) { + *req = *req.WithContext(context.WithValue(req.Context(), "file-manager", fileManager)) + next.ServeHTTP(w, req) + } + + return http.HandlerFunc(handlerFunc) +} + func EnsurePageData(next http.Handler, adapter core.Adapter) http.Handler { handlerFunc := func(w http.ResponseWriter, req *http.Request) { pageTitle := req.FormValue("title") diff --git a/nirvash.go b/nirvash.go index aa81a3d..1a5077b 100644 --- a/nirvash.go +++ b/nirvash.go @@ -27,11 +27,15 @@ func main() { cfg.Adapter.Init(cfg) + fileManager := &core.SimpleFileManager{} + fileManager.Init(cfg) + pathConcat := filepath.Join rtr := &router.Router{ StaticPaths: map[string]string{ - "/static": filepath.Join(cfg.AssetRoot, "static"), + "/static/": filepath.Join(cfg.AssetRoot, "static"), + "/files/": cfg.StaticRoot, }, } @@ -201,5 +205,19 @@ func main() { udb, "/")) + rtr.Get( + `/static-mgr/(?P.*)`, + Fortify( + Protected( + WithFileManager( + renderer.Template( + pathConcat(templateRoot, "file_list.html"), + pathConcat(templateRoot, "header.html"), + pathConcat(templateRoot, "footer.html")), + fileManager), + http.MethodGet, + udb, + "/login"))) + http.ListenAndServe(":8080", rtr) } diff --git a/static/delete.svg b/static/delete.svg new file mode 100644 index 0000000..dd1083e --- /dev/null +++ b/static/delete.svg @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/static/move.svg b/static/move.svg new file mode 100644 index 0000000..6c19612 --- /dev/null +++ b/static/move.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/static/style.css b/static/style.css index c12b84f..e29fd00 100644 --- a/static/style.css +++ b/static/style.css @@ -291,4 +291,9 @@ form input[hidden] { form input[readonly] { border: none; +} + +.edit-error { + display: block; + border-bottom: solid 2px crimson; } \ No newline at end of file diff --git a/templates/file_list.html b/templates/file_list.html new file mode 100644 index 0000000..f8089ab --- /dev/null +++ b/templates/file_list.html @@ -0,0 +1,34 @@ +{{ $slug := ((.Context).Value "params").Slug }} +{{ $fileList := ((.Context).Value "file-manager").ListSubTree $slug }} + +{{ template "header" .}} + + +{{ if ($fileList).Error }} +

File Listing Error

+ +{{($fileList).Error}} +{{ else }} +

Files: {{($fileList).Root}}

+ + + +
+
    + {{ if ($fileList).Up }} +
  • ..
  • + {{ end }} + {{ range $dir := ($fileList).SubDirs }} +
  • {{$dir}}/
  • + {{ end }} + {{ range $file := ($fileList).Files }} +
  • {{$file}}
  • + {{ end }} +
+
+ +{{ end }} + +{{ template "footer" .}} diff --git a/templates/header.html b/templates/header.html index 572df2a..84f3ef5 100644 --- a/templates/header.html +++ b/templates/header.html @@ -13,7 +13,7 @@