Simplify Static Generators Code; progresses on #108

Former-commit-id: 7f4552b70980f39204e5a5517a1c1f3602304569 [formerly 0c9cdc2a1e988d378f8a068b9a6b53eb41144f2f] [formerly e221c08add31a6837c8695c413b2c55d31806f16 [formerly 7ee721a9e3]]
Former-commit-id: de2ff86dbc24a8f77260539d656201daf9dfebe5 [formerly 3d0eb1e810bbce97a7bf430abf0d0c7a3833ce2a]
Former-commit-id: 6f22d477a1105c7b84cbe70dda1afb0d364e47c5
pull/726/head
Henrique Dias 2017-08-10 15:04:07 +01:00
parent 97f31310c6
commit 25a86a9382
3 changed files with 53 additions and 82 deletions

View File

@ -121,15 +121,6 @@ type FileManager struct {
Commands map[string][]string Commands map[string][]string
} }
type StaticGen interface {
SettingsPath() string
Hook(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error)
Preview(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error)
Publish(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error)
Schedule(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error)
}
// Command is a command function. // Command is a command function.
type Command func(r *http.Request, m *FileManager, u *User) error type Command func(r *http.Request, m *FileManager, u *User) error
@ -357,6 +348,8 @@ func (m *FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
} }
// EnableStaticGen attaches a static generator to the current File Manager
// instance.
func (m *FileManager) EnableStaticGen(data StaticGen) error { func (m *FileManager) EnableStaticGen(data StaticGen) error {
if reflect.TypeOf(data).Kind() != reflect.Ptr { if reflect.TypeOf(data).Kind() != reflect.Ptr {
return errors.New("data should be a pointer to interface, not interface") return errors.New("data should be a pointer to interface, not interface")

View File

@ -5,13 +5,16 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/hacdias/fileutils" "github.com/hacdias/fileutils"
"github.com/robfig/cron"
) )
// sanitizeURL sanitizes the URL to prevent path transversal // sanitizeURL sanitizes the URL to prevent path transversal
@ -231,10 +234,45 @@ func resourcePublishSchedule(c *RequestContext, w http.ResponseWriter, r *http.R
} }
if publish == "true" { if publish == "true" {
return c.StaticGen.Publish(c, w, r) return resourcePublish(c, w, r)
} }
return c.StaticGen.Schedule(c, w, r) t, err := time.Parse("2006-01-02T15:04", schedule)
if err != nil {
return http.StatusInternalServerError, err
}
scheduler := cron.New()
scheduler.AddFunc(t.Format("05 04 15 02 01 *"), func() {
_, err := resourcePublish(c, w, r)
if err != nil {
log.Print(err)
}
})
scheduler.Start()
return http.StatusOK, nil
}
func resourcePublish(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) {
path := filepath.Join(string(c.User.FileSystem), r.URL.Path)
// Before save command handler.
if err := c.Runner("before_publish", path); err != nil {
return http.StatusInternalServerError, err
}
code, err := c.StaticGen.Publish(c, w, r)
if err != nil {
return code, err
}
// Executed the before publish command.
if err := c.Runner("before_publish", path); err != nil {
return http.StatusInternalServerError, err
}
return code, nil
} }
// resourcePatchHandler is the entry point for resource handler. // resourcePatchHandler is the entry point for resource handler.

View File

@ -9,17 +9,23 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/hacdias/varutils" "github.com/hacdias/varutils"
"github.com/robfig/cron"
) )
var ( var (
// ErrUnsupportedFileType ... errUnsupportedFileType = errors.New("The type of the provided file isn't supported for this action")
ErrUnsupportedFileType = errors.New("The type of the provided file isn't supported for this action")
) )
// StaticGen is a static website generator.
type StaticGen interface {
SettingsPath() string
Hook(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error)
Preview(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error)
Publish(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error)
}
// Hugo is the Hugo static website generator. // Hugo is the Hugo static website generator.
type Hugo struct { type Hugo struct {
// Website root // Website root
@ -89,7 +95,7 @@ func (h Hugo) Hook(c *RequestContext, w http.ResponseWriter, r *http.Request) (i
// If the request isn't for a markdown file, we can't // If the request isn't for a markdown file, we can't
// handle it. // handle it.
if ext != ".markdown" && ext != ".md" { if ext != ".markdown" && ext != ".md" {
return http.StatusBadRequest, ErrUnsupportedFileType return http.StatusBadRequest, errUnsupportedFileType
} }
// Tries to create a new file based on this archetype. // Tries to create a new file based on this archetype.
@ -107,11 +113,6 @@ func (h Hugo) Hook(c *RequestContext, w http.ResponseWriter, r *http.Request) (i
func (h Hugo) Publish(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { func (h Hugo) Publish(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) {
filename := filepath.Join(string(c.User.FileSystem), r.URL.Path) filename := filepath.Join(string(c.User.FileSystem), r.URL.Path)
// Before save command handler.
if err := c.Runner("before_publish", filename); err != nil {
return http.StatusInternalServerError, err
}
// We only run undraft command if it is a file. // We only run undraft command if it is a file.
if strings.HasSuffix(filename, ".md") && strings.HasSuffix(filename, ".markdown") { if strings.HasSuffix(filename, ".md") && strings.HasSuffix(filename, ".markdown") {
if err := h.undraft(filename); err != nil { if err := h.undraft(filename); err != nil {
@ -122,37 +123,9 @@ func (h Hugo) Publish(c *RequestContext, w http.ResponseWriter, r *http.Request)
// Regenerates the file // Regenerates the file
h.run(false) h.run(false)
// Executed the before publish command.
if err := c.Runner("before_publish", filename); err != nil {
return http.StatusInternalServerError, err
}
return 0, nil return 0, nil
} }
// Schedule schedules a post.
func (h Hugo) Schedule(c *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)
if err != nil {
return http.StatusInternalServerError, err
}
scheduler := cron.New()
scheduler.AddFunc(t.Format("05 04 15 02 01 *"), func() {
if err := h.undraft(path); err != nil {
log.Printf(err.Error())
}
h.run(false)
})
scheduler.Start()
return http.StatusOK, nil
}
// Preview handles the preview path. // Preview handles the preview path.
func (h *Hugo) Preview(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { func (h *Hugo) Preview(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) {
// Get a new temporary path if there is none. // Get a new temporary path if there is none.
@ -252,11 +225,6 @@ func (j Jekyll) Hook(c *RequestContext, w http.ResponseWriter, r *http.Request)
func (j Jekyll) Publish(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { func (j Jekyll) Publish(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) {
filename := filepath.Join(string(c.User.FileSystem), r.URL.Path) filename := filepath.Join(string(c.User.FileSystem), r.URL.Path)
// Before save command handler.
if err := c.Runner("before_publish", filename); err != nil {
return http.StatusInternalServerError, err
}
// We only run undraft command if it is a file. // We only run undraft command if it is a file.
if err := j.undraft(filename); err != nil { if err := j.undraft(filename); err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
@ -265,37 +233,9 @@ func (j Jekyll) Publish(c *RequestContext, w http.ResponseWriter, r *http.Reques
// Regenerates the file // Regenerates the file
j.run() j.run()
// Executed the before publish command.
if err := c.Runner("before_publish", filename); err != nil {
return http.StatusInternalServerError, err
}
return 0, nil return 0, nil
} }
// Schedule schedules a post.
func (j Jekyll) Schedule(c *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)
if err != nil {
return http.StatusInternalServerError, err
}
scheduler := cron.New()
scheduler.AddFunc(t.Format("05 04 15 02 01 *"), func() {
if err := j.undraft(path); err != nil {
log.Printf(err.Error())
}
j.run()
})
scheduler.Start()
return http.StatusOK, nil
}
// Preview handles the preview path. // Preview handles the preview path.
func (j *Jekyll) Preview(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) { func (j *Jekyll) Preview(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) {
// Get a new temporary path if there is none. // Get a new temporary path if there is none.