forked from filebrowser/filebrowser
/
hugo.go
135 lines (110 loc) · 3.49 KB
/
hugo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//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 assets -o assets/assets.go templates/ assets/css/ assets/js/ assets/fonts/
package hugo
import (
"mime"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/hacdias/caddy-hugo/assets"
"github.com/hacdias/caddy-hugo/browse"
"github.com/hacdias/caddy-hugo/config"
"github.com/hacdias/caddy-hugo/editor"
"github.com/hacdias/caddy-hugo/utils"
"github.com/mholt/caddy/caddy/setup"
"github.com/mholt/caddy/middleware"
)
// Setup configures the middleware
func Setup(c *setup.Controller) (middleware.Middleware, error) {
config, _ := config.ParseHugo(c)
utils.Run(config)
return func(next middleware.Handler) middleware.Handler {
return &CaddyHugo{Next: next, Config: config}
}, nil
}
// CaddyHugo main type
type CaddyHugo struct {
Next middleware.Handler
Config *config.Config
}
func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// Only handle /admin path
if middleware.Path(r.URL.Path).Matches("/admin") {
var err error
var page string
code := 404
// If the length of the components string is less than one, the variable
// page will always be "admin"
if len(utils.ParseComponents(r)) > 1 {
page = utils.ParseComponents(r)[1]
} else {
page = utils.ParseComponents(r)[0]
}
// If the page isn't "assets" neither "edit", it should always put a
// trailing slash in the path
if page != "assets" && page != "edit" {
if r.URL.Path[len(r.URL.Path)-1] != '/' {
http.Redirect(w, r, r.URL.Path+"/", http.StatusTemporaryRedirect)
return 0, nil
}
}
// If the current page is only "/admin/", redirect to "/admin/browse/content/"
if r.URL.Path == "/admin/" {
http.Redirect(w, r, "/admin/browse/content/", http.StatusTemporaryRedirect)
return 0, nil
}
// If the url matches exactly with /admin/settings/ serve that page
// page variable isn't used here to avoid people using URLs like
// "/admin/settings/something".
if r.URL.Path == "/admin/settings/" {
var frontmatter string
if _, err := os.Stat(h.Config.Path + "config.yaml"); err == nil {
frontmatter = "yaml"
}
if _, err := os.Stat(h.Config.Path + "config.json"); err == nil {
frontmatter = "json"
}
if _, err := os.Stat(h.Config.Path + "config.toml"); err == nil {
frontmatter = "toml"
}
http.Redirect(w, r, "/admin/edit/config."+frontmatter, http.StatusTemporaryRedirect)
return 0, nil
}
// Serve the static assets
if page == "assets" {
return serveAssets(w, r)
}
// Browse page
if page == "browse" {
code, err = browse.ServeHTTP(w, r, h.Config)
}
// Edit page
if page == "edit" {
code, err = editor.ServeHTTP(w, r, h.Config)
}
// Whenever the header "X-Refenerate" is true, the website should be
// regenerated. Used in edit and settings, for example.
if r.Header.Get("X-Regenerate") == "true" {
utils.Run(h.Config)
}
return code, err
}
return h.Next.ServeHTTP(w, r)
}
func serveAssets(w http.ResponseWriter, r *http.Request) (int, error) {
filename := strings.Replace(r.URL.Path, "/admin/", "", 1)
file, err := assets.Asset(filename)
if err != nil {
return 404, nil
}
// Get the file extension ant its mime type
extension := filepath.Ext(filename)
mime := mime.TypeByExtension(extension)
// Write the header with the Content-Type and write the file
// content to the buffer
w.Header().Set("Content-Type", mime)
w.Write(file)
return 200, nil
}