Browse Source

initial commit

Stephen Searles 1 year ago
commit
b956647700

+ 307
- 0
caddyhugo.go View File

@@ -0,0 +1,307 @@
1
+package caddyhugo
2
+
3
+import (
4
+	"errors"
5
+	"fmt"
6
+	"html/template"
7
+	"io/ioutil"
8
+	"net/http"
9
+	"os"
10
+	"path"
11
+	"path/filepath"
12
+	"strings"
13
+
14
+	"github.com/mholt/caddy"
15
+	"github.com/mholt/caddy/caddyhttp/httpserver"
16
+)
17
+
18
+func init() {
19
+	plugin := CaddyHugo{}
20
+
21
+	// register a "generic" plugin, like a directive or middleware
22
+	caddy.RegisterPlugin("hugo", caddy.Plugin{
23
+		ServerType: "http",
24
+		Action:     plugin.Setup,
25
+	})
26
+
27
+	// ... there are others. See the godoc.
28
+}
29
+
30
+type CaddyHugo struct {
31
+	ServerType string
32
+
33
+	authorTmpl, adminTmpl, editTmpl *template.Template
34
+}
35
+
36
+func (c CaddyHugo) Name() string {
37
+	if c.ServerType == "" {
38
+		return "hugo"
39
+	}
40
+	return c.ServerType
41
+}
42
+
43
+func (ch CaddyHugo) Setup(c *caddy.Controller) error {
44
+
45
+	site := httpserver.GetConfig(c)
46
+
47
+	var err error
48
+
49
+	ch.authorTmpl, err = template.New("").Parse(AuthorPage)
50
+	if err != nil {
51
+		return fmt.Errorf("author template invalid: %v", err)
52
+	}
53
+
54
+	ch.adminTmpl, err = template.New("").Parse(AdminPage)
55
+	if err != nil {
56
+		return fmt.Errorf("admin template invalid: %v", err)
57
+	}
58
+
59
+	ch.editTmpl, err = template.New("").Parse(EditPage)
60
+	if err != nil {
61
+		return fmt.Errorf("edit template invalid: %v", err)
62
+	}
63
+
64
+	// add a function that wraps listeners for the HTTP server
65
+	// (it's more common for a directive to call this rather than a standalone plugin)
66
+	site.AddMiddleware(ch.Middleware(c, site))
67
+
68
+	return nil
69
+}
70
+
71
+func (ch CaddyHugo) Middleware(c *caddy.Controller, site *httpserver.SiteConfig) httpserver.Middleware {
72
+	return func(h httpserver.Handler) httpserver.Handler {
73
+		return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
74
+			if !ch.Match(r) {
75
+				return h.ServeHTTP(w, r)
76
+			}
77
+
78
+			if !ch.Auth(r) {
79
+				return http.StatusUnauthorized, errors.New("not authorized")
80
+			}
81
+
82
+			if strings.HasPrefix(r.URL.Path, "/hugo/admin") {
83
+				return ch.Admin(site).ServeHTTP(w, r)
84
+			}
85
+			if strings.HasPrefix(r.URL.Path, "/hugo/author") {
86
+				return ch.AuthorHome(site).ServeHTTP(w, r)
87
+			}
88
+			if strings.HasPrefix(r.URL.Path, "/hugo/edit/") {
89
+				return ch.Edit(c, site).ServeHTTP(w, r)
90
+			}
91
+
92
+			return http.StatusNotFound, errors.New("not found")
93
+		})
94
+	}
95
+}
96
+
97
+func (ch CaddyHugo) Auth(r *http.Request) bool {
98
+	return true
99
+}
100
+
101
+func (ch CaddyHugo) Match(r *http.Request) bool {
102
+	if r.URL.Path == "/hugo" {
103
+		return true
104
+	}
105
+
106
+	return strings.HasPrefix(r.URL.Path, "/hugo/")
107
+}
108
+
109
+func (ch CaddyHugo) BasePath() string {
110
+	return "/hugo"
111
+}
112
+
113
+func (ch CaddyHugo) Admin(site *httpserver.SiteConfig) httpserver.Handler {
114
+	return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
115
+		err := ch.adminTmpl.Execute(w, ch.TmplData(r, site))
116
+		if err != nil {
117
+			fmt.Println(err)
118
+			return http.StatusInternalServerError, err
119
+		}
120
+
121
+		return http.StatusOK, nil
122
+
123
+	})
124
+}
125
+
126
+func (ch CaddyHugo) AuthorHome(site *httpserver.SiteConfig) httpserver.Handler {
127
+	return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
128
+		err := ch.authorTmpl.Execute(w, ch.TmplData(r, site))
129
+		if err != nil {
130
+			fmt.Println(err)
131
+			return http.StatusInternalServerError, err
132
+		}
133
+
134
+		return http.StatusOK, nil
135
+	})
136
+}
137
+
138
+func (ch CaddyHugo) Edit(c *caddy.Controller, site *httpserver.SiteConfig) httpserver.Handler {
139
+	return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
140
+		if r.URL.Path == "/hugo/edit/new" {
141
+
142
+			name := r.FormValue("name")
143
+			ctype := r.FormValue("type")
144
+
145
+			if filepath.Ext(name) != ".md" {
146
+				name += ".md"
147
+			}
148
+
149
+			filename := path.Join(site.Root, "content", ctype, name)
150
+
151
+			dir := filepath.Dir(filename)
152
+			if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
153
+				err = os.MkdirAll(dir, 0755)
154
+				if err != nil {
155
+					fmt.Println(err)
156
+					return http.StatusInternalServerError, err
157
+				}
158
+			}
159
+
160
+			// create content
161
+			f, err := os.Create(filename)
162
+			if err != nil && !os.IsExist(err) {
163
+				fmt.Println(err)
164
+				return http.StatusInternalServerError, err
165
+			}
166
+
167
+			// we only needed to make the file though
168
+			err = f.Close()
169
+			if err != nil {
170
+				fmt.Println(err)
171
+				return http.StatusInternalServerError, err
172
+			}
173
+
174
+			// serve redirect
175
+			http.Redirect(w, r, filepath.Join("/hugo/edit/", filename), http.StatusFound)
176
+			return http.StatusFound, nil
177
+		}
178
+
179
+		err := ch.editTmpl.Execute(w, ch.TmplData(r, site))
180
+		if err != nil {
181
+
182
+			fmt.Println(err)
183
+			return http.StatusInternalServerError, err
184
+		}
185
+
186
+		return http.StatusOK, nil
187
+	})
188
+}
189
+
190
+func (t tmplData) Content() ([]string, error) {
191
+	var files []string
192
+
193
+	err := filepath.Walk(path.Join(t.Site.Root, "content"), func(name string, fi os.FileInfo, err error) error {
194
+		if fi.IsDir() {
195
+			return nil
196
+		}
197
+
198
+		files = append(files, name)
199
+		return nil
200
+	})
201
+
202
+	if err != nil {
203
+		fmt.Println(err)
204
+		return nil, err
205
+	}
206
+
207
+	return files, nil
208
+}
209
+
210
+func (ch CaddyHugo) TmplData(r *http.Request, site *httpserver.SiteConfig) interface{} {
211
+	return tmplData{site, r, ch}
212
+}
213
+
214
+func (t tmplData) ContentTypes() ([]string, error) {
215
+	layoutDir, err := os.Open(path.Join(t.Site.Root, "archetypes"))
216
+	if err != nil {
217
+		fmt.Println("opening layout dir", err)
218
+		return nil, err
219
+	}
220
+	defer layoutDir.Close()
221
+
222
+	names, err := layoutDir.Readdirnames(0)
223
+	if err != nil {
224
+		fmt.Println("reading dir", err)
225
+		return nil, err
226
+	}
227
+
228
+	out := []string{"default"}
229
+	for _, name := range names {
230
+		out = append(out, name[:len(name)-len(filepath.Ext(name))])
231
+	}
232
+
233
+	return out, nil
234
+}
235
+
236
+type tmplData struct {
237
+	Site *httpserver.SiteConfig
238
+	R    *http.Request
239
+	CaddyHugo
240
+}
241
+
242
+func (t tmplData) LoadContent() (string, error) {
243
+	path := t.R.URL.Path[len("/hugo/edit/"):]
244
+	f, err := os.Open(path)
245
+	if err != nil {
246
+		fmt.Println(err)
247
+		return "", err
248
+	}
249
+	out, err := ioutil.ReadAll(f)
250
+	return string(out), err
251
+}
252
+
253
+var EditPage = `<html>
254
+<head>
255
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js"></script>
256
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ext-settings_menu.js"></script>
257
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ext-keybinding_menu.js"></script>
258
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/keybinding-vim.js"></script>
259
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/mode-markdown.js"></script>
260
+<style type="text/css" media="screen">
261
+#editor { 
262
+	position: absolute;
263
+	top: 50px;
264
+	right: 0;
265
+	bottom: 0;
266
+	left: 0;
267
+}
268
+</style>
269
+
270
+<body>
271
+	<div id="editor">{{ .LoadContent }}</div>
272
+<script>
273
+    var editor = ace.edit("editor");
274
+    editor.setTheme("ace/theme/monokai");
275
+    var session = editor.getSession();
276
+    session.setMode("ace/mode/markdown");
277
+    session.on("change", function (delta) {
278
+	    console.log(delta);
279
+    })
280
+</script>
281
+</body>
282
+</html>`
283
+
284
+var AdminPage = `<html><body>not implemented</body></html>`
285
+
286
+var AuthorPage = `<html>
287
+<head>
288
+</head>
289
+<body>
290
+	<p>Create content:</p>
291
+	<form action="/hugo/edit/new" method="POST">
292
+		<label>Name: <input type="text" name="name" /></label>
293
+		<select name="type">
294
+		    {{- range .ContentTypes }}
295
+			<option value="{{ . }}">{{ . }}</option>
296
+		    {{- end }}
297
+		</select>
298
+		<input type="submit" />
299
+	</form>
300
+
301
+	<p>Edit content:</p>
302
+	<ul>{{ range .Content }}
303
+		<li><a href="/hugo/edit/{{ . }}">{{ . }}</a></li>
304
+	    {{- end }}
305
+	</ul>
306
+</body>
307
+</html>`

+ 1
- 0
readme.md View File

@@ -0,0 +1 @@
1
+author view

+ 4
- 0
testdir/caddyfile View File

@@ -0,0 +1,4 @@
1
+localhost:8080 {
2
+	hugo
3
+	errors { * }
4
+}

+ 3
- 0
testdir/testsite/archetypes/post.md View File

@@ -0,0 +1,3 @@
1
++++
2
+title = ""
3
++++

+ 3
- 0
testdir/testsite/config.toml View File

@@ -0,0 +1,3 @@
1
+baseURL = "http://example.org/"
2
+languageCode = "en-us"
3
+title = "My New Hugo Site"

+ 0
- 0
testdir/testsite/content/post/asdf.md View File


Loading…
Cancel
Save