pull/82/head
Henrique Dias 2016-06-21 16:35:42 +01:00
parent 72c7abe469
commit 0797fde4e3
8 changed files with 354 additions and 133 deletions

View File

@ -7,35 +7,20 @@
package hugo
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
// bindataRead reads the given file from disk. It returns an error on failure.
func bindataRead(path, name string) ([]byte, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
err = fmt.Errorf("Error reading asset %s at %s: %v", name, path, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
if clErr != nil {
return nil, err
}
return buf.Bytes(), nil
return buf, err
}
type asset struct {
@ -43,70 +28,40 @@ type asset struct {
info os.FileInfo
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
func (fi bindataFileInfo) Name() string {
return fi.name
}
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
func (fi bindataFileInfo) IsDir() bool {
return false
}
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
var _templatesEditorTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x56\x4d\x6f\xdc\x38\x0c\xbd\x07\xc8\x7f\xe0\xea\x94\x3d\x8c\x8d\xbd\x7b\xbc\x58\xec\x6e\x8b\x1e\xd2\x0e\x30\x01\x7a\xd6\x58\x9c\x58\x88\x6d\xb9\x12\x3d\xd3\x41\x90\xff\x5e\xca\xf2\x97\x32\xcd\x07\x82\xa0\xf5\xc9\x96\xc8\xc7\x47\xf2\x51\xf2\xfd\x3d\x28\xdc\xeb\x06\x41\x14\xa6\x21\x6c\x48\xc0\xc3\xc3\xe5\x45\xa6\xf4\x01\x8a\x4a\x3a\xb7\x16\xa8\x34\x19\x0b\x7e\x5f\xb2\xa5\x05\x76\x4a\xfe\xf5\x7b\x6c\x2a\xf2\xcb\x0b\xf0\x2b\x7a\x0f\xf8\x6d\x5c\x67\xb0\xba\xad\x90\x30\xa0\x01\x64\xe5\x5f\x79\x46\xf8\x9d\xa4\x45\x09\x5a\xad\x85\xd3\x84\x2b\xd2\x54\xa1\xc8\x3d\xe0\x67\x59\x23\x1b\x67\xe9\x68\x95\x67\x29\x3b\x0d\xe8\xd8\xa8\x11\x69\x6f\x6c\x0d\x35\x52\x69\x18\x65\xf3\x65\x7b\x23\x40\x16\xa4\x4d\xb3\x16\x81\x0c\xdb\xd4\x4c\x74\x78\x1f\xc9\x35\x86\xe0\xea\x67\x0c\xff\x1c\x80\xc3\xc3\x44\x9f\xa7\x37\x70\x1a\x80\x47\x5e\x71\xac\x45\x98\xbd\xe5\xb2\xd5\x92\x08\xed\xca\x34\xd5\x49\x2c\xa2\x2d\x8b\xbc\xb0\x83\x5d\x65\x8a\x3b\x27\xf2\x99\x15\xc3\x12\x32\x5f\x49\x18\x41\x0a\x48\x3e\xf8\xaf\xeb\xe0\x18\x25\xd2\x8e\xd0\xa1\x3a\x11\x1e\x6f\xef\x3a\x22\xd3\x4c\x36\x4a\x89\xfc\x1f\xa5\x60\xaf\xb1\x52\x59\x1a\x76\x17\x1e\x59\xda\x4e\x5f\x59\xca\xc4\xa3\x2a\x54\x0e\xcf\x04\xd0\xab\xe9\xd9\x9c\x47\xc5\x2d\xc3\xf8\x6d\x5f\xff\x20\xba\x95\x33\x9d\x2d\x58\x45\x4a\x92\x5c\xd5\x46\xe1\x5a\xf8\x6e\x5c\xf3\x5b\x2f\xbe\x98\x0a\xfb\x4f\x1a\x6b\xb8\x61\x8b\x10\xbd\x66\xc3\x47\xac\xb2\xe7\x93\x7a\xb1\x59\x67\xe4\x07\x93\xf7\xe9\xe1\xc0\xe9\x97\x76\xf5\x95\x9d\x9a\x95\xde\x37\x43\xd4\xd2\xde\x29\x73\x6c\x44\x9c\x41\x23\x0f\x31\xc3\x61\xfa\x11\xa7\xde\x2e\x12\x3a\xf0\xb4\x65\x7a\x2a\xb3\x84\xbd\x5c\x15\x0c\xef\x1b\xad\x73\xd8\xf6\x1e\x59\x2a\x9f\x82\x6c\x2d\x1e\x34\x1e\xcf\x41\xf0\x34\x62\x6c\x82\x49\x0c\x92\xa5\x31\xcf\x30\xd9\x51\x22\xbf\x4d\x98\xe7\xb1\xe7\x2c\xa3\x20\xe7\x0a\x7e\x74\x38\xcd\xe2\x21\x63\xaa\x9d\x8c\xc5\xab\x9b\xb6\x23\xa0\x53\xcb\xec\x5c\xb7\xab\x35\x0d\xd9\x85\xa5\xe8\xd0\x0f\x1b\x16\x6f\x91\xef\x03\x16\xb4\x2f\x33\x8f\xcb\xb0\xee\x8a\x12\x55\x57\xcd\xab\x43\x95\xd0\x39\x79\x1b\xa0\x5e\x3e\x24\x6f\x4a\x0c\xb2\x75\x70\x44\x8b\xe0\xc9\xb1\xb2\xa9\x44\x6d\xe1\x28\x4f\xc9\xeb\xce\x9d\xff\x0f\x68\x4f\xb0\x3b\xf1\xd0\x1d\xa5\x03\x27\x0f\xa8\x92\x79\xba\x37\xc6\x51\x58\x84\xa3\xa6\x12\x5a\xbe\x15\x40\x72\xdd\x0a\x6d\x8b\xae\x76\x24\x9b\x02\x93\xa9\x96\x02\x0e\xb2\xea\x38\x85\xad\xf4\x52\x5d\x54\xcf\xb5\x72\x1a\x3b\xab\x6f\x4b\x8a\x07\x33\xa4\xec\x81\x9f\xb8\x83\xae\x20\xf9\xe4\x7a\x36\xfe\x3e\x7a\x43\x33\xe6\xa2\x93\xed\xf0\x85\x0e\x4d\xad\x08\xf9\x0f\xae\x2a\xe1\x56\x8d\x09\x0e\x6b\x22\x8f\xaf\xdf\x77\x92\xcb\x82\xe3\x99\x5a\xde\x20\x96\x6d\xdf\x41\x5f\xde\x39\x88\x7a\xa5\x42\xfe\x33\x0d\x26\xf0\xb5\x94\x04\xca\xc0\xc9\x74\x2c\x14\x9e\xc5\xda\x58\xfc\xfb\x91\x50\xda\x6e\x57\x69\xc7\x74\x13\xf8\x68\xfa\x70\xae\xe4\x59\x05\x4d\x7f\x2c\x24\x32\xa8\x80\xff\xab\x64\x57\xd1\x24\x99\x4d\x70\x8e\x54\x93\x7a\xd9\x2c\x06\x78\x3c\x8d\xb3\x74\xfa\x83\xc9\x52\xff\xc3\xc3\xaf\xe3\x78\x2f\xda\xf1\x23\x00\x00\xff\xff\x32\x91\x30\x45\xbe\x09\x00\x00")
func templatesEditorTmplBytes() ([]byte, error) {
return bindataRead(
_templatesEditorTmpl,
"templates/editor.tmpl",
)
}
// templatesEditorTmpl reads file data from disk. It returns an error on failure.
func templatesEditorTmpl() (*asset, error) {
bytes, err := templatesEditorTmplBytes()
path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-hugo\\assets\\templates\\editor.tmpl"
name := "templates/editor.tmpl"
bytes, err := bindataRead(path, name)
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "templates/editor.tmpl", size: 2494, mode: os.FileMode(438), modTime: time.Unix(1466520293, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _templatesFrontmatterTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x54\xdd\x6e\xd3\x4c\x10\xbd\xaf\xd4\x77\x18\xed\x57\x7d\x02\x09\xc7\x69\x5a\x7e\x14\x1c\xdf\x54\x42\x5c\x00\x42\x22\x2f\xb0\xb1\xc7\xb0\x74\xb3\x6b\xd6\x93\x8a\x50\xf5\xdd\x19\xaf\xbd\xa9\xb1\x9d\xca\xad\x10\x77\x59\x9f\xd9\xd9\x73\xce\xcc\xc9\xed\x2d\xe4\x58\x28\x83\x20\x0a\x67\x0d\x6d\x25\x11\x3a\x01\x77\x77\xa7\x27\x8c\x39\x69\xbe\x22\x9c\x5d\xe3\xfe\x05\x9c\xdd\x48\xbd\x43\x58\xae\x60\xe6\xe1\xd3\x13\x00\x2e\x51\x05\x58\x07\xcf\xf0\x47\x5b\x30\x5b\xef\x4b\xee\x66\x37\xdf\x31\x23\xf1\x7c\x88\x48\xe7\xe4\x9e\x81\xba\x07\x40\x52\x28\xd4\x79\x85\x04\x2a\x5f\x09\xee\xd7\xd6\x7e\x92\x5b\xe4\x12\x01\xb9\x24\x19\x11\xdf\xec\xa2\xbe\x13\xa3\x69\xdd\x82\x9b\x7c\xbb\x48\x19\xfc\x52\x6a\x45\x57\xb2\x54\x24\xb5\xfa\x85\x87\x62\x45\xba\xae\x4e\x62\x2e\x6b\x2f\x54\xa5\x34\x90\x69\x59\x55\x2b\x21\x33\x52\xd6\x54\xa1\x19\xa3\x9b\x1d\x91\xbd\xc7\xf3\x5c\xa4\xff\xff\x77\x79\xf1\x36\x89\x1b\xe4\x58\x65\x8e\x1a\x09\xeb\xe2\x37\xaf\x17\x8b\x7e\x79\x12\xd7\xaf\xb6\x07\xa6\x4b\xb8\x2d\xb5\xa4\xbe\xf5\x2d\xeb\x2b\xfe\x84\x86\x82\x4d\x71\xf0\x29\x6d\x7d\x47\x5d\x61\x6f\x0e\xc6\x52\xd7\xee\xcf\xd2\x71\x83\x71\xd7\x73\x75\x13\x48\x6f\xb4\xcd\xae\x85\xb7\xdf\xff\x8c\x8e\x0d\x21\x6b\x18\x8d\x4d\x29\x28\xd4\x72\x83\x1a\x0a\xeb\x46\x8b\xa6\x8c\xc8\x77\x78\xca\x94\x26\x7a\x1f\xdc\x33\x79\xcf\xbc\x07\x7d\xeb\xda\x36\xba\xa7\xde\x34\x8e\x49\x7f\x65\xfd\xf5\x48\xf1\xa8\x45\x3a\xe1\xe9\xf7\xeb\x8f\x1f\x9a\x77\x09\x7f\x12\xf3\x90\x87\xa7\xc3\x87\xa0\xb7\xca\x9c\xd5\x5a\x80\x61\x02\x23\x84\x96\xc3\xb0\x3c\x98\xb0\xd2\x8b\x1e\x04\xad\xeb\x45\x3b\xc2\xc1\x7e\x26\x71\xe0\xf6\xc7\x6e\x1e\x11\xc6\xaf\x21\xa9\x2d\x1e\x84\x29\x53\xee\xe8\x2f\xc8\xf0\xc7\x2e\xd2\x32\x9c\xbd\xb3\x8e\xb3\x05\x62\x31\x9f\xbf\x8a\xe6\xe7\xd1\x7c\xb1\x3e\x7f\xb9\x9c\x5f\x0a\x7f\xad\x51\x1c\x58\x45\x9c\x00\xa9\x1f\xe7\x49\x12\x7b\x09\x83\x60\xfe\x03\x6d\x1d\x05\xf7\xd8\xc1\xeb\xc7\x0e\xb7\x2f\x64\xb0\xa8\xd3\xfe\x60\x92\x98\x63\x92\x3e\x3d\x64\xa3\xa9\x9f\x98\xf6\x36\xe7\x0d\x85\x81\x8e\xce\x61\xfc\xe7\xef\x00\x00\x00\xff\xff\x30\xc2\x3e\x0c\x0f\x07\x00\x00")
func templatesFrontmatterTmplBytes() ([]byte, error) {
return bindataRead(
_templatesFrontmatterTmpl,
"templates/frontmatter.tmpl",
)
fi, err := os.Stat(path)
if err != nil {
err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err)
}
a := &asset{bytes: bytes, info: fi}
return a, err
}
// templatesFrontmatterTmpl reads file data from disk. It returns an error on failure.
func templatesFrontmatterTmpl() (*asset, error) {
bytes, err := templatesFrontmatterTmplBytes()
path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-hugo\\assets\\templates\\frontmatter.tmpl"
name := "templates/frontmatter.tmpl"
bytes, err := bindataRead(path, name)
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "templates/frontmatter.tmpl", size: 1807, mode: os.FileMode(438), modTime: time.Unix(1466520317, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
fi, err := os.Stat(path)
if err != nil {
err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err)
}
a := &asset{bytes: bytes, info: fi}
return a, err
}
// Asset loads and returns the asset for the given name.

View File

@ -1,30 +0,0 @@
package files
import (
"io"
"os"
)
// CopyFile is used to copy a file
func CopyFile(old, new string) error {
// Open the file and create a new one
r, err := os.Open(old)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(new)
if err != nil {
return err
}
defer w.Close()
// Copy the content
_, err = io.Copy(w, r)
if err != nil {
return err
}
return nil
}

View File

@ -1,11 +0,0 @@
package files
import "testing"
func TestCopyFile(t *testing.T) {
err := CopyFile("test_data/file_to_copy.txt", "test_data/copied_file.txt")
if err != nil {
t.Error("Can't copy the file.")
}
}

View File

@ -1,9 +0,0 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin faucibus augue vel ex auctor molestie. Sed id lorem quis velit eleifend vestibulum. Etiam tincidunt nulla et metus dictum imperdiet. Suspendisse ac auctor risus. Donec tempus eros quis erat interdum fringilla. Duis ac tristique lorem, quis vulputate enim. In ut est elementum, dignissim tellus quis, ultrices diam. Aenean in efficitur velit, ut imperdiet felis. Suspendisse aliquet accumsan ligula, a iaculis sem luctus vel. Integer sagittis, orci viverra lacinia efficitur, eros magna sodales sapien, in tristique ante arcu ut nunc. Maecenas odio dolor, semper quis vehicula ut, malesuada sollicitudin massa. Integer dolor ligula, hendrerit convallis quam at, luctus dignissim nibh. Fusce interdum congue justo, at imperdiet lorem maximus in.
Curabitur dignissim id turpis ut eleifend. Pellentesque vehicula et purus et consectetur. Nulla facilisis vehicula nunc in imperdiet. Nam eget porta libero, vel dapibus leo. Maecenas iaculis, arcu quis vehicula sollicitudin, massa tortor mattis tortor, vitae venenatis erat neque et dui. Mauris eleifend vel urna ac interdum. Sed convallis, arcu et scelerisque suscipit, nulla urna laoreet mauris, quis aliquam dolor elit id mauris. Pellentesque ac pulvinar nibh. Duis vestibulum ligula orci, et mattis turpis facilisis mattis. Vivamus feugiat neque sed aliquet aliquet. Sed consequat augue sagittis eros imperdiet, ac lacinia erat tempor. Cras gravida mi a orci euismod feugiat. Mauris condimentum turpis id quam vulputate, et maximus dolor hendrerit.
Ut nisi urna, sollicitudin ac facilisis eu, rhoncus sed urna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla eu maximus mi, sed commodo diam. Nunc scelerisque tincidunt ipsum eget mattis. Fusce id finibus nisi, sit amet tempus tortor. Fusce accumsan lectus at dignissim volutpat. Nullam nisl nulla, rhoncus id arcu vitae, eleifend posuere libero. Aliquam dictum bibendum bibendum. Integer non mattis neque. Phasellus fermentum et ex vel vehicula.
Proin eget ligula lorem. Ut vehicula quis augue sed aliquet. Nulla viverra turpis nulla. Morbi et ipsum odio. Nulla in nisi suscipit justo blandit tristique ac vitae ipsum. Donec viverra dictum arcu. Duis est elit, ultrices a massa non, lobortis maximus eros. Nulla porttitor rhoncus lectus in finibus. Duis convallis sapien porta, fringilla orci nec, ultricies nisl. Morbi pulvinar quam in nulla rutrum euismod.
Donec et accumsan lectus, consectetur posuere nunc. Quisque et quam hendrerit, vestibulum quam eget, luctus enim. In hac habitasse platea dictumst. Nunc et est scelerisque, bibendum neque quis, ornare elit. Aliquam erat volutpat. Nulla maximus nibh vitae ex interdum, a efficitur lacus eleifend. Nam vestibulum blandit aliquet. In hac habitasse platea dictumst. Maecenas interdum quam et lorem posuere interdum. Mauris id feugiat augue. Etiam vestibulum pharetra cursus.

View File

@ -23,7 +23,7 @@ type editor struct {
}
// GET handles the GET method on editor page
func (h Hugo) GET(w http.ResponseWriter, r *http.Request, c *Config, filename string) (int, error) {
func (h Hugo) GET(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
// Check if the file exists.
if _, err := os.Stat(filename); os.IsNotExist(err) {
return http.StatusNotFound, err
@ -45,14 +45,14 @@ func (h Hugo) GET(w http.ResponseWriter, r *http.Request, c *Config, filename st
Info: &filemanager.PageInfo{
IsDir: false,
Config: &h.FileManager.Configs[0],
Name: strings.Replace(filename, c.Root, "", 1),
Name: strings.Replace(filename, h.Config.Root, "", 1),
},
}
// Create a new editor variable and set the extension
data := new(editor)
data.Mode = strings.TrimPrefix(filepath.Ext(filename), ".")
data.Name = strings.Replace(filename, c.Root, "", 1)
data.Name = strings.Replace(filename, h.Config.Root, "", 1)
data.IsPost = false
data.Mode = sanitizeMode(data.Mode)
@ -113,15 +113,18 @@ func (h Hugo) GET(w http.ResponseWriter, r *http.Request, c *Config, filename st
var code int
page.Info.Data = data
code, err = page.AddTemplate("base", filemanager.Asset, functions)
if err != nil {
return code, err
templates := []string{"frontmatter", "editor"}
for _, t := range templates {
code, err = page.AddTemplate(t, Asset, functions)
if err != nil {
return code, err
}
}
templates := []string{"listing", "actions"}
templates = []string{"actions", "base"}
for _, t := range templates {
code, err = page.AddTemplate(t, Asset, nil)
code, err = page.AddTemplate(t, filemanager.Asset, nil)
if err != nil {
return code, err
}

89
hugo.go
View File

@ -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 -pkg hugo -prefix "assets" -o binary.go assets/...
//go:generate go-bindata -debug -pkg hugo -prefix "assets" -o binary.go assets/...
// Package hugo makes the bridge between the static website generator Hugo
// and the webserver Caddy, also providing an administrative user interface.
@ -8,6 +8,9 @@ package hugo
import (
"net/http"
"os"
"path/filepath"
"strings"
"github.com/hacdias/caddy-filemanager"
"github.com/mholt/caddy/caddyhttp/httpserver"
@ -24,6 +27,90 @@ type Hugo struct {
// ServeHTTP is the main function of the whole plugin that routes every single
// request to its function.
func (h Hugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// Check if the current request if for this plugin
if httpserver.Path(r.URL.Path).Matches(h.Config.BaseURL) {
// If the url matches exactly with /{admin}/settings/, redirect
// to the page of the configuration file
if r.URL.Path == h.Config.BaseURL+"/settings/" {
var frontmatter string
if _, err := os.Stat(h.Config.Root + "config.yaml"); err == nil {
frontmatter = "yaml"
}
if _, err := os.Stat(h.Config.Root + "config.json"); err == nil {
frontmatter = "json"
}
if _, err := os.Stat(h.Config.Root + "config.toml"); err == nil {
frontmatter = "toml"
}
http.Redirect(w, r, h.Config.BaseURL+"/config."+frontmatter, http.StatusTemporaryRedirect)
return 0, nil
}
if strings.HasPrefix(r.URL.Path, h.Config.BaseURL+"/api/git/") && r.Method == http.MethodPost {
//return HandleGit(w, r, h.Config)
return 0, nil
}
if h.ShouldHandle(r) {
filename := strings.Replace(r.URL.Path, h.Config.BaseURL, h.Config.Root, 1)
switch r.Method {
case http.MethodGet:
return h.GET(w, r, filename)
case http.MethodPost:
return h.POST(w, r, filename)
default:
return h.FileManager.ServeHTTP(w, r)
}
}
return h.FileManager.ServeHTTP(w, r)
}
return h.Next.ServeHTTP(w, r)
}
var extensions = []string{
"md", "markdown", "mdown", "mmark",
"asciidoc", "adoc", "ad",
"rst",
"html", "htm",
"js",
"toml", "yaml", "json",
}
// ShouldHandle checks if this extension should be handled by this plugin
func (h Hugo) ShouldHandle(r *http.Request) bool {
// Checks if the method is get or post
if r.Method != http.MethodGet && r.Method != http.MethodPost {
return false
}
// Check if this request is for FileManager assets
if httpserver.Path(r.URL.Path).Matches(h.Config.BaseURL + filemanager.AssetsURL) {
return false
}
// If this request requires a raw file or a download, return the FileManager
query := r.URL.Query()
if val, ok := query["raw"]; ok && val[0] == "true" {
return false
}
if val, ok := query["download"]; ok && val[0] == "true" {
return false
}
// Check by file extension
extension := strings.TrimPrefix(filepath.Ext(r.URL.Path), ".")
for _, ext := range extensions {
if ext == extension {
return true
}
}
return false
}

View File

@ -14,7 +14,6 @@ import (
"regexp"
"runtime"
"github.com/hacdias/caddy-hugo/files"
"github.com/mitchellh/go-homedir"
"github.com/pivotal-golang/archiver/extractor"
)
@ -91,7 +90,7 @@ func GetPath() string {
// Copy the file
fmt.Print("Moving Hugo executable... ")
err = files.CopyFile(exetorename, hugo)
err = CopyFile(exetorename, hugo)
if err != nil {
fmt.Println(err)
os.Exit(-1)
@ -214,3 +213,27 @@ func checkSHA256() {
fmt.Println("checked!")
}
// CopyFile is used to copy a file
func CopyFile(old, new string) error {
// Open the file and create a new one
r, err := os.Open(old)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(new)
if err != nil {
return err
}
defer w.Close()
// Copy the content
_, err = io.Copy(w, r)
if err != nil {
return err
}
return nil
}

203
post.go Normal file
View File

@ -0,0 +1,203 @@
package hugo
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
"time"
"github.com/robfig/cron"
"github.com/spf13/cast"
"github.com/spf13/hugo/parser"
)
type info struct {
ContentType string
Schedule bool
Regenerate bool
Content map[string]interface{}
}
type response struct {
Message string `json:"message"`
}
// POST handles the POST method on editor page
func (h Hugo) POST(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
var data info
// Get the JSON information sent using a buffer
rawBuffer := new(bytes.Buffer)
rawBuffer.ReadFrom(r.Body)
err := json.Unmarshal(rawBuffer.Bytes(), &data)
fmt.Println(string(rawBuffer.Bytes()))
if err != nil {
return RespondJSON(w, &response{"Error decrypting json."}, http.StatusInternalServerError, err)
}
// Initializes the file content to write
var file []byte
var code int
switch data.ContentType {
case "frontmatter-only":
file, code, err = parseFrontMatterOnlyFile(data, filename)
if err != nil {
return RespondJSON(w, &response{err.Error()}, code, err)
}
case "content-only":
// The main content of the file
mainContent := data.Content["content"].(string)
mainContent = strings.TrimSpace(mainContent)
file = []byte(mainContent)
case "complete":
file, code, err = parseCompleteFile(data, filename, h.Config)
if err != nil {
return RespondJSON(w, &response{err.Error()}, code, err)
}
default:
return RespondJSON(w, &response{"Invalid content type."}, http.StatusBadRequest, nil)
}
// Write the file
err = ioutil.WriteFile(filename, file, 0666)
if err != nil {
return RespondJSON(w, &response{err.Error()}, http.StatusInternalServerError, err)
}
if data.Regenerate {
go RunHugo(h.Config, false)
}
return RespondJSON(w, nil, http.StatusOK, nil)
}
func parseFrontMatterOnlyFile(data info, filename string) ([]byte, int, error) {
frontmatter := strings.TrimPrefix(filepath.Ext(filename), ".")
var mark rune
switch frontmatter {
case "toml":
mark = rune('+')
case "json":
mark = rune('{')
case "yaml":
mark = rune('-')
default:
return []byte{}, http.StatusBadRequest, errors.New("Can't define the frontmatter.")
}
f, err := parser.InterfaceToFrontMatter(data.Content, mark)
fString := string(f)
// If it's toml or yaml, strip frontmatter identifier
if frontmatter == "toml" {
fString = strings.TrimSuffix(fString, "+++\n")
fString = strings.TrimPrefix(fString, "+++\n")
}
if frontmatter == "yaml" {
fString = strings.TrimSuffix(fString, "---\n")
fString = strings.TrimPrefix(fString, "---\n")
}
f = []byte(fString)
if err != nil {
return []byte{}, http.StatusInternalServerError, err
}
return f, http.StatusOK, nil
}
func parseCompleteFile(data info, filename string, c *Config) ([]byte, int, error) {
// The main content of the file
mainContent := data.Content["content"].(string)
mainContent = "\n\n" + strings.TrimSpace(mainContent) + "\n"
// Removes the main content from the rest of the frontmatter
delete(data.Content, "content")
if _, ok := data.Content["date"]; ok {
data.Content["date"] = data.Content["date"].(string) + ":00"
}
// Schedule the post
if data.Schedule {
t := cast.ToTime(data.Content["date"])
scheduler := cron.New()
scheduler.AddFunc(t.In(time.Now().Location()).Format("05 04 15 02 01 *"), func() {
// Set draft to false
data.Content["draft"] = false
// Converts the frontmatter in JSON
jsonFrontmatter, err := json.Marshal(data.Content)
if err != nil {
return
}
// Indents the json
frontMatterBuffer := new(bytes.Buffer)
json.Indent(frontMatterBuffer, jsonFrontmatter, "", " ")
// Generates the final file
f := new(bytes.Buffer)
f.Write(frontMatterBuffer.Bytes())
f.Write([]byte(mainContent))
file := f.Bytes()
// Write the file
if err = ioutil.WriteFile(filename, file, 0666); err != nil {
return
}
go RunHugo(c, false)
})
scheduler.Start()
}
// Converts the frontmatter in JSON
jsonFrontmatter, err := json.Marshal(data.Content)
if err != nil {
return []byte{}, http.StatusInternalServerError, err
}
// Indents the json
frontMatterBuffer := new(bytes.Buffer)
json.Indent(frontMatterBuffer, jsonFrontmatter, "", " ")
// Generates the final file
f := new(bytes.Buffer)
f.Write(frontMatterBuffer.Bytes())
f.Write([]byte(mainContent))
return f.Bytes(), http.StatusOK, nil
}
func RespondJSON(w http.ResponseWriter, message interface{}, code int, err error) (int, error) {
if message == nil {
message = map[string]string{}
}
msg, msgErr := json.Marshal(message)
if msgErr != nil {
return 500, msgErr
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
w.Write(msg)
return 0, err
}