diff --git a/caddy/filemanager/filemanager.go b/caddy/filemanager/filemanager.go index 75cbb128..791681cb 100644 --- a/caddy/filemanager/filemanager.go +++ b/caddy/filemanager/filemanager.go @@ -139,6 +139,7 @@ func parse(c *caddy.Controller) ([]*config, error) { } fm, err := New(database, User{ + Locale: "en", AllowCommands: true, AllowEdit: true, AllowNew: true, diff --git a/caddy/hugo/hugo.go b/caddy/hugo/hugo.go index 871d0fb0..21ec6887 100644 --- a/caddy/hugo/hugo.go +++ b/caddy/hugo/hugo.go @@ -108,6 +108,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) { } m, err := filemanager.New(database, filemanager.User{ + Locale: "en", AllowCommands: true, AllowEdit: true, AllowNew: true, diff --git a/filemanager.go b/filemanager.go index c0d0b512..144f986d 100644 --- a/filemanager.go +++ b/filemanager.go @@ -175,6 +175,8 @@ type Rule struct { Regexp *Regexp `json:"regexp"` } +type PluginHandler func(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) + // Regexp is a regular expression wrapper around native regexp. type Regexp struct { Raw string `json:"raw"` @@ -185,8 +187,10 @@ type Plugin struct { JavaScript string CommandEvents []string Permissions []Permission - Handler PluginHandler Options interface{} + Handlers map[string]PluginHandler `json:"-"` + BeforeAPI PluginHandler `json:"-"` + AfterAPI PluginHandler `json:"-"` } type Permission struct { @@ -194,13 +198,6 @@ type Permission struct { Value bool } -type PluginHandler interface { - // If the Plugin returns (0, nil), the executation of File Manager will procced as usual. - // Otherwise it will stop. - Before(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) - After(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) -} - func RegisterPlugin(name string, plugin Plugin) { if _, ok := plugins[name]; ok { panic(name + " plugin is already registred") diff --git a/http.go b/http.go index d33c4a8f..a6e9bf64 100644 --- a/http.go +++ b/http.go @@ -58,6 +58,30 @@ func serveHTTP(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, return apiHandler(c, w, r) } + // Checks if any plugin has an handler for this URL. + for p := range c.Plugins { + var h PluginHandler + + for path, handler := range plugins[p].Handlers { + if strings.HasPrefix(r.URL.Path, path) { + h = handler + r.URL.Path = strings.TrimPrefix(r.URL.Path, path) + break + } + } + + if h == nil { + continue + } + + valid, _ := validateAuth(c, r) + if !valid { + return http.StatusForbidden, nil + } + + return h(c, w, r) + } + // Any other request should show the index.html file. w.Header().Set("x-frame-options", "SAMEORIGIN") w.Header().Set("x-content-type", "nosniff") @@ -108,7 +132,11 @@ func apiHandler(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, } for p := range c.Plugins { - code, err := plugins[p].Handler.Before(c, w, r) + if plugins[p].BeforeAPI == nil { + continue + } + + code, err := plugins[p].BeforeAPI(c, w, r) if code != 0 || err != nil { return code, err } @@ -149,7 +177,11 @@ func apiHandler(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, } for p := range c.Plugins { - code, err := plugins[p].Handler.After(c, w, r) + if plugins[p].AfterAPI == nil { + continue + } + + code, err := plugins[p].AfterAPI(c, w, r) if code != 0 || err != nil { return code, err } diff --git a/plugins/hugo.go b/plugins/hugo.go index a19c4e41..ba35ff48 100644 --- a/plugins/hugo.go +++ b/plugins/hugo.go @@ -2,6 +2,7 @@ package plugins import ( "errors" + "io/ioutil" "log" "net/http" "os" @@ -19,13 +20,16 @@ func init() { filemanager.RegisterPlugin("hugo", filemanager.Plugin{ JavaScript: hugoJavaScript, CommandEvents: []string{"before_publish", "after_publish"}, + BeforeAPI: beforeAPI, + Handlers: map[string]filemanager.PluginHandler{ + "/preview": previewHandler, + }, Permissions: []filemanager.Permission{ { Name: "allowPublish", Value: true, }, }, - Handler: &hugo{}, }) } @@ -46,6 +50,8 @@ type Hugo struct { Args []string `name:"Hugo Arguments"` // Indicates if we should clean public before a new publish. CleanPublic bool `name:"Clean Public"` + // previewPath is the temporary path for a preview + previewPath string } // Find finds the hugo executable in the path. @@ -114,9 +120,7 @@ func (h Hugo) undraft(file string) error { return nil } -type hugo struct{} - -func (h hugo) Before(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { +func beforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { o := c.Plugins["hugo"].(*Hugo) // If we are using the 'magic url' for the settings, we should redirect the @@ -223,6 +227,32 @@ func (h hugo) Before(c *filemanager.RequestContext, w http.ResponseWriter, r *ht return http.StatusNotFound, nil } -func (h hugo) After(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { +func previewHandler(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { + h := c.Plugins["hugo"].(*Hugo) + + // Get a new temporary path if there is none. + if h.previewPath == "" { + path, err := ioutil.TempDir("", "") + if err != nil { + return http.StatusInternalServerError, err + } + + h.previewPath = path + } + + // Build the arguments to execute Hugo: change the base URL, + // build the drafts and update the destination. + args := h.Args + args = append(args, "--baseURL", c.RootURL()+"/preview/") + args = append(args, "--buildDrafts") + args = append(args, "--destination", h.previewPath) + + // Builds the preview. + if err := Run(h.Exe, args, h.Root); err != nil { + return http.StatusInternalServerError, err + } + + // Serves the temporary path with the preview. + http.FileServer(http.Dir(h.previewPath)).ServeHTTP(w, r) return 0, nil } diff --git a/plugins/hugo.js.go b/plugins/hugo.js.go index e65f2a83..9c17b4ff 100644 --- a/plugins/hugo.js.go +++ b/plugins/hugo.js.go @@ -143,14 +143,14 @@ const hugoJavaScript = `'use strict'; }, icon: 'merge_type', name: 'Hugo New' - } /* , + }, { click: function (event, data, route) { - console.log('evt') + window.open(data.store.state.baseURL + '/preview/') }, icon: 'remove_red_eye', name: 'Preview' - } */ + } ], prompts: [ {