diff --git a/caddy/hugo/rice-box.go b/caddy/hugo/rice-box.go deleted file mode 100644 index f83cb99e..00000000 --- a/caddy/hugo/rice-box.go +++ /dev/null @@ -1,41 +0,0 @@ -package hugo - -import ( - "github.com/GeertJohan/go.rice/embedded" - "time" -) - -func init() { - - // define files - file2 := &embedded.EmbeddedFile{ - Filename: "hugo.js", - FileModTime: time.Unix(1501233088, 0), - Content: string("'use strict';\r\n\r\n(function () {\r\n if (window.plugins === undefined || window.plugins === null) {\r\n window.plugins = []\r\n }\r\n\r\n let regenerate = function (data, url) {\r\n url = data.api.removePrefix(url)\r\n\r\n return new Promise((resolve, reject) => {\r\n let request = new window.XMLHttpRequest()\r\n request.open('POST', `${data.store.state.baseURL}/api/hugo${url}`, true)\r\n request.setRequestHeader('Authorization', `Bearer ${data.store.state.jwt}`)\r\n request.setRequestHeader('Regenerate', 'true')\r\n\r\n request.onload = () => {\r\n if (request.status === 200) {\r\n resolve()\r\n } else {\r\n reject(request.responseText)\r\n }\r\n }\r\n\r\n request.onerror = (error) => reject(error)\r\n request.send()\r\n })\r\n }\r\n\r\n let newArchetype = function (data, url, type) {\r\n url = data.api.removePrefix(url)\r\n\r\n return new Promise((resolve, reject) => {\r\n let request = new window.XMLHttpRequest()\r\n request.open('POST', `${data.store.state.baseURL}/api/hugo${url}`, true)\r\n request.setRequestHeader('Authorization', `Bearer ${data.store.state.jwt}`)\r\n request.setRequestHeader('Archetype', encodeURIComponent(type))\r\n\r\n request.onload = () => {\r\n if (request.status === 200) {\r\n resolve(request.getResponseHeader('Location'))\r\n } else {\r\n reject(request.responseText)\r\n }\r\n }\r\n\r\n request.onerror = (error) => reject(error)\r\n request.send()\r\n })\r\n }\r\n\r\n let schedule = function (data, file, date) {\r\n file = data.api.removePrefix(file)\r\n\r\n return new Promise((resolve, reject) => {\r\n let request = new window.XMLHttpRequest()\r\n request.open('POST', `${data.store.state.baseURL}/api/hugo${file}`, true)\r\n request.setRequestHeader('Authorization', `Bearer ${data.store.state.jwt}`)\r\n request.setRequestHeader('Schedule', date)\r\n\r\n request.onload = () => {\r\n if (request.status === 200) {\r\n resolve(request.getResponseHeader('Location'))\r\n } else {\r\n reject(request.responseText)\r\n }\r\n }\r\n\r\n request.onerror = (error) => reject(error)\r\n request.send()\r\n })\r\n }\r\n\r\n window.plugins.push({\r\n name: 'hugo',\r\n credits: 'With a flavour of Hugo.',\r\n header: {\r\n visible: [\r\n {\r\n if: function (data, route) {\r\n return (data.store.state.req.kind === 'editor' &&\r\n !data.store.state.loading &&\r\n data.store.state.req.metadata !== undefined &&\r\n data.store.state.req.metadata !== null &&\r\n data.store.state.user.allowEdit &\r\n data.store.state.user.permissions.allowPublish)\r\n },\r\n click: function (event, data, route) {\r\n event.preventDefault()\r\n document.getElementById('save-button').click()\r\n // TODO: wait for save to finish?\r\n data.buttons.loading('publish')\r\n\r\n regenerate(data, route.path)\r\n .then(() => {\r\n data.buttons.done('publish')\r\n data.store.commit('showSuccess', 'Post published!')\r\n data.store.commit('setReload', true)\r\n })\r\n .catch((error) => {\r\n data.buttons.done('publish')\r\n data.store.commit('showError', error)\r\n })\r\n },\r\n id: 'publish-button',\r\n icon: 'send',\r\n name: 'Publish'\r\n }\r\n ],\r\n hidden: [\r\n {\r\n if: function (data, route) {\r\n return (data.store.state.req.kind === 'editor' &&\r\n !data.store.state.loading &&\r\n data.store.state.req.metadata !== undefined &&\r\n data.store.state.req.metadata !== null &&\r\n data.store.state.user.permissions.allowPublish)\r\n },\r\n click: function (event, data, route) {\r\n document.getElementById('save-button').click()\r\n data.store.commit('showHover', 'schedule')\r\n },\r\n id: 'schedule-button',\r\n icon: 'alarm',\r\n name: 'Schedule'\r\n }\r\n ]\r\n },\r\n sidebar: [\r\n {\r\n click: function (event, data, route) {\r\n data.router.push({ path: '/files/settings' })\r\n },\r\n icon: 'settings',\r\n name: 'Hugo Settings'\r\n },\r\n {\r\n click: function (event, data, route) {\r\n data.store.commit('showHover', 'new-archetype')\r\n },\r\n if: function (data, route) {\r\n return data.store.state.user.allowNew\r\n },\r\n icon: 'merge_type',\r\n name: 'Hugo New'\r\n } /* ,\r\n {\r\n click: function (event, data, route) {\r\n console.log('evt')\r\n },\r\n icon: 'remove_red_eye',\r\n name: 'Preview'\r\n } */\r\n ],\r\n prompts: [\r\n {\r\n name: 'new-archetype',\r\n title: 'New file',\r\n description: 'Create a new post based on an archetype. Your file will be created on content folder.',\r\n inputs: [\r\n {\r\n type: 'text',\r\n name: 'file',\r\n placeholder: 'File name'\r\n },\r\n {\r\n type: 'text',\r\n name: 'archetype',\r\n placeholder: 'Archetype'\r\n }\r\n ],\r\n ok: 'Create',\r\n submit: function (event, data, route) {\r\n event.preventDefault()\r\n\r\n let file = event.currentTarget.querySelector('[name=\"file\"]').value\r\n let type = event.currentTarget.querySelector('[name=\"archetype\"]').value\r\n if (type === '') type = 'default'\r\n\r\n data.store.commit('closeHovers')\r\n\r\n newArchetype(data, '/' + file, type)\r\n .then((url) => {\r\n data.router.push({ path: url })\r\n })\r\n .catch(error => {\r\n data.store.commit('showError', error)\r\n })\r\n }\r\n },\r\n {\r\n name: 'schedule',\r\n title: 'Schedule',\r\n description: 'Pick a date and time to schedule the publication of this post.',\r\n inputs: [\r\n {\r\n type: 'datetime-local',\r\n name: 'date',\r\n placeholder: 'Date'\r\n }\r\n ],\r\n ok: 'Schedule',\r\n submit: function (event, data, route) {\r\n event.preventDefault()\r\n data.buttons.loading('schedule')\r\n\r\n let date = event.currentTarget.querySelector('[name=\"date\"]').value\r\n if (date === '') {\r\n data.buttons.done('schedule')\r\n data.store.commit('showError', 'The date must not be empty.')\r\n return\r\n }\r\n\r\n schedule(data, route.path, date)\r\n .then(() => {\r\n data.buttons.done('schedule')\r\n data.store.commit('showSuccess', 'Post scheduled!')\r\n })\r\n .catch((error) => {\r\n data.buttons.done('schedule')\r\n data.store.commit('showError', error)\r\n })\r\n }\r\n }\r\n ]\r\n })\r\n})()\r\n"), - } - - // define dirs - dir1 := &embedded.EmbeddedDir{ - Filename: "", - DirModTime: time.Unix(1501233088, 0), - ChildFiles: []*embedded.EmbeddedFile{ - file2, // "hugo.js" - - }, - } - - // link ChildDirs - dir1.ChildDirs = []*embedded.EmbeddedDir{} - - // register embeddedBox - embedded.RegisterEmbeddedBox(`./assets/`, &embedded.EmbeddedBox{ - Name: `./assets/`, - Time: time.Unix(1501233088, 0), - Dirs: map[string]*embedded.EmbeddedDir{ - "": dir1, - }, - Files: map[string]*embedded.EmbeddedFile{ - "hugo.js": file2, - }, - }) -} diff --git a/caddy/hugo/setup.go b/caddy/hugo/setup.go index 044e086a..384967aa 100644 --- a/caddy/hugo/setup.go +++ b/caddy/hugo/setup.go @@ -3,7 +3,6 @@ package hugo import ( "crypto/md5" "encoding/hex" - "errors" "fmt" "net/http" "os" @@ -12,16 +11,12 @@ import ( "strings" "github.com/hacdias/filemanager" + "github.com/hacdias/filemanager/plugins" "github.com/hacdias/fileutils" "github.com/mholt/caddy" "github.com/mholt/caddy/caddyhttp/httpserver" ) -var ( - errHugoNotFound = errors.New("It seems that tou don't have 'hugo' on your PATH") - errUnsupportedFileType = errors.New("The type of the provided file isn't supported for this action") -) - // setup configures a new FileManager middleware instance. func setup(c *caddy.Controller) error { configs, err := parse(c) @@ -120,7 +115,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) { } // Initialize the default settings for Hugo. - hugo := &hugo{ + hugo := &plugins.Hugo{ Root: directory, Public: filepath.Join(directory, "public"), Args: []string{}, @@ -129,7 +124,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) { // Try to find the Hugo executable path. if hugo.Exe, err = exec.LookPath("hugo"); err != nil { - return nil, errHugoNotFound + return nil, plugins.ErrHugoNotFound } err = m.RegisterPlugin("hugo", hugo) diff --git a/caddy/hugo/assets/hugo.js b/plugins/assets/hugo.js similarity index 98% rename from caddy/hugo/assets/hugo.js rename to plugins/assets/hugo.js index c86a762e..2d61e0f3 100644 --- a/caddy/hugo/assets/hugo.js +++ b/plugins/assets/hugo.js @@ -80,8 +80,6 @@ if: function (data, route) { return (data.store.state.req.kind === 'editor' && !data.store.state.loading && - data.store.state.req.metadata !== undefined && - data.store.state.req.metadata !== null && data.store.state.user.allowEdit & data.store.state.user.permissions.allowPublish) }, diff --git a/caddy/hugo/hugo.go b/plugins/hugo.go similarity index 82% rename from caddy/hugo/hugo.go rename to plugins/hugo.go index a93a1539..bb21c413 100644 --- a/caddy/hugo/hugo.go +++ b/plugins/hugo.go @@ -1,6 +1,7 @@ -package hugo +package plugins import ( + "errors" "log" "net/http" "os" @@ -14,7 +15,13 @@ import ( "github.com/robfig/cron" ) -type hugo struct { +var ( + ErrHugoNotFound = errors.New("It seems that tou don't have 'hugo' on your PATH") + ErrUnsupportedFileType = errors.New("The type of the provided file isn't supported for this action") +) + +// Hugo is a hugo (https://gohugo.io) plugin. +type Hugo struct { // Website root Root string `description:"The relative or absolute path to the place where your website is located."` // Public folder @@ -25,11 +32,9 @@ type hugo struct { Args []string `description:"The arguments to run when running Hugo"` // Indicates if we should clean public before a new publish. CleanPublic bool `description:"Indicates if the public folder should be cleaned before publishing the website."` - - // TODO: admin interface to cgange options } -func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { +func (h Hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { // If we are using the 'magic url' for the settings, we should redirect the // request for the acutual path. if r.URL.Path == "/settings/" || r.URL.Path == "/settings" { @@ -49,7 +54,6 @@ func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r } r.URL.Path = "/config." + frontmatter - return 0, nil } // From here on, we only care about 'hugo' router so we can bypass @@ -78,7 +82,7 @@ func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r // If the request isn't for a markdown file, we can't // handle it. if ext != ".markdown" && ext != ".md" { - return http.StatusBadRequest, errUnsupportedFileType + return http.StatusBadRequest, ErrUnsupportedFileType } // Tries to create a new file based on this archetype. @@ -106,11 +110,11 @@ func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r } // We only run undraft command if it is a file. - if !strings.HasSuffix(filename, "/") { - args := []string{"undraft", filename} - if err := Run(h.Exe, args, h.Root); err != nil && !strings.Contains(err.Error(), "not a Draft") { + if strings.HasSuffix(filename, ".md") && strings.HasSuffix(filename, ".markdown") { + if err := h.undraft(filename); err != nil { return http.StatusInternalServerError, err } + } // Regenerates the file @@ -135,16 +139,16 @@ func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r return http.StatusNotFound, nil } -func (h hugo) AfterAPI(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { +func (h Hugo) AfterAPI(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { return 0, nil } -func (h hugo) JavaScript() string { +func (h Hugo) JavaScript() string { return rice.MustFindBox("./assets/").MustString("hugo.js") } // run runs Hugo with the define arguments. -func (h hugo) run(force bool) { +func (h Hugo) run(force bool) { // If the CleanPublic option is enabled, clean it. if h.CleanPublic { os.RemoveAll(h.Public) @@ -167,7 +171,7 @@ func (h hugo) run(force bool) { } // schedule schedules a post to be published later. -func (h hugo) schedule(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { +func (h Hugo) schedule(c *filemanager.RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { t, err := time.Parse("2006-01-02T15:04", r.Header.Get("Schedule")) path := filepath.Join(string(c.User.FileSystem), r.URL.Path) path = filepath.Clean(path) @@ -178,8 +182,7 @@ func (h hugo) schedule(c *filemanager.RequestContext, w http.ResponseWriter, r * scheduler := cron.New() scheduler.AddFunc(t.Format("05 04 15 02 01 *"), func() { - args := []string{"undraft", path} - if err := Run(h.Exe, args, h.Root); err != nil { + if err := h.undraft(path); err != nil { log.Printf(err.Error()) return } @@ -190,3 +193,12 @@ func (h hugo) schedule(c *filemanager.RequestContext, w http.ResponseWriter, r * scheduler.Start() return http.StatusOK, nil } + +func (h Hugo) undraft(file string) error { + args := []string{"undraft", file} + if err := Run(h.Exe, args, h.Root); err != nil && !strings.Contains(err.Error(), "not a Draft") { + return err + } + + return nil +} diff --git a/caddy/hugo/utils.go b/plugins/utils.go similarity index 94% rename from caddy/hugo/utils.go rename to plugins/utils.go index a8bb900b..5676cfcd 100644 --- a/caddy/hugo/utils.go +++ b/plugins/utils.go @@ -1,4 +1,4 @@ -package hugo +package plugins import ( "errors" diff --git a/rice-box.go.REMOVED.git-id b/rice-box.go.REMOVED.git-id deleted file mode 100644 index 35339201..00000000 --- a/rice-box.go.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -e50cb6a99f64eba257617c206897174ed13be0ee \ No newline at end of file