@@ -3,9 +3,11 @@ package main
3
3
import (
4
4
"context"
5
5
"encoding/base64"
6
+ "encoding/json"
6
7
"flag"
7
8
"fmt"
8
9
"html/template"
10
+ "io/ioutil"
9
11
"log"
10
12
"net/http"
11
13
"os"
@@ -48,13 +50,14 @@ var (
48
50
flagDebug = flag .Bool ("debug" , false , "output debugging information" )
49
51
flagDebugDB = flag .Bool ("debugdb" , false , "output database on each request" )
50
52
flagDebugCTX = flag .Bool ("debugctx" , false , "output specific authboss related context keys on each request" )
53
+ flagAPI = flag .Bool ("api" , false , "configure the app to be an api instead of an html app" )
51
54
)
52
55
53
56
var (
54
- ab = authboss .New ()
55
- database = NewMemStorer ()
56
- templates = tpl . Must ( tpl . Load ( "views" , "views/partials" , "layout.html.tpl" , funcs ) )
57
- schemaDec = schema . NewDecoder ()
57
+ ab = authboss .New ()
58
+ database = NewMemStorer ()
59
+ schemaDec = schema . NewDecoder ( )
60
+ templates tpl. Templates = nil
58
61
)
59
62
60
63
func setupAuthboss () {
@@ -132,6 +135,10 @@ func setupAuthboss() {
132
135
func main () {
133
136
flag .Parse ()
134
137
138
+ if ! * flagAPI {
139
+ templates = tpl .Must (tpl .Load ("views" , "views/partials" , "layout.html.tpl" , funcs ))
140
+ }
141
+
135
142
// Initialize Sessions and Cookies
136
143
// Typically gorilla securecookie and sessions packages require
137
144
// highly random secret keys that are not divulged to the public.
@@ -197,26 +204,29 @@ func main() {
197
204
198
205
func dataInjector (handler http.Handler ) http.Handler {
199
206
return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
200
- data := layoutData (w , r )
207
+ data := layoutData (w , & r )
201
208
r = r .WithContext (context .WithValue (r .Context (), authboss .CTXKeyData , data ))
202
209
handler .ServeHTTP (w , r )
203
210
})
204
211
}
205
212
206
- func layoutData (w http.ResponseWriter , r * http.Request ) authboss.HTMLData {
213
+ // layoutData is passing pointers to pointers be able to edit the current pointer
214
+ // to the request. This is still safe as it still creates a new request and doesn't
215
+ // modify the old one, it just modifies what we're pointing to in our methods so
216
+ // we're able to skip returning an *http.Request everywhere
217
+ func layoutData (w http.ResponseWriter , r * * http.Request ) authboss.HTMLData {
207
218
currentUserName := ""
208
- userInter , err := ab .CurrentUser (r )
219
+ userInter , err := ab .LoadCurrentUser (r )
209
220
if userInter != nil && err == nil {
210
221
currentUserName = userInter .(* User ).Name
211
222
}
212
223
213
224
return authboss.HTMLData {
214
225
"loggedin" : userInter != nil ,
215
- "username" : "" ,
216
226
"current_user_name" : currentUserName ,
217
- "csrf_token" : nosurf .Token (r ),
218
- "flash_success" : authboss .FlashSuccess (w , r ),
219
- "flash_error" : authboss .FlashError (w , r ),
227
+ "csrf_token" : nosurf .Token (* r ),
228
+ "flash_success" : authboss .FlashSuccess (w , * r ),
229
+ "flash_error" : authboss .FlashError (w , * r ),
220
230
}
221
231
}
222
232
@@ -231,16 +241,27 @@ func newblog(w http.ResponseWriter, r *http.Request) {
231
241
var nextID = len (blogs ) + 1
232
242
233
243
func create (w http.ResponseWriter , r * http.Request ) {
234
- err := r .ParseForm ()
235
- if badRequest (w , err ) {
236
- return
237
- }
238
-
239
244
// TODO: Validation
240
245
241
246
var b Blog
242
- if badRequest (w , schemaDec .Decode (& b , r .PostForm )) {
243
- return
247
+ if * flagAPI {
248
+ byt , err := ioutil .ReadAll (r .Body )
249
+ if badRequest (w , err ) {
250
+ return
251
+ }
252
+
253
+ if badRequest (w , json .Unmarshal (byt , & b )) {
254
+ return
255
+ }
256
+ } else {
257
+ err := r .ParseForm ()
258
+ if badRequest (w , err ) {
259
+ return
260
+ }
261
+
262
+ if badRequest (w , schemaDec .Decode (& b , r .PostForm )) {
263
+ return
264
+ }
244
265
}
245
266
246
267
abuser := ab .CurrentUserP (r )
@@ -253,7 +274,12 @@ func create(w http.ResponseWriter, r *http.Request) {
253
274
254
275
blogs = append (blogs , b )
255
276
256
- http .Redirect (w , r , "/" , http .StatusFound )
277
+ if * flagAPI {
278
+ w .WriteHeader (http .StatusOK )
279
+ return
280
+ }
281
+
282
+ redirect (w , r , "/" )
257
283
}
258
284
259
285
func edit (w http.ResponseWriter , r * http.Request ) {
@@ -262,16 +288,10 @@ func edit(w http.ResponseWriter, r *http.Request) {
262
288
return
263
289
}
264
290
265
- data := layoutData (w , r ).MergeKV ("post" , blogs .Get (id ))
266
- mustRender (w , r , "edit" , data )
291
+ mustRender (w , r , "edit" , authboss.HTMLData {"post" : blogs .Get (id )})
267
292
}
268
293
269
294
func update (w http.ResponseWriter , r * http.Request ) {
270
- err := r .ParseForm ()
271
- if badRequest (w , err ) {
272
- return
273
- }
274
-
275
295
id , ok := blogID (w , r )
276
296
if ! ok {
277
297
return
@@ -280,13 +300,34 @@ func update(w http.ResponseWriter, r *http.Request) {
280
300
// TODO: Validation
281
301
282
302
var b = blogs .Get (id )
283
- if badRequest (w , schemaDec .Decode (b , r .PostForm )) {
284
- return
303
+
304
+ if * flagAPI {
305
+ byt , err := ioutil .ReadAll (r .Body )
306
+ if badRequest (w , err ) {
307
+ return
308
+ }
309
+
310
+ if badRequest (w , json .Unmarshal (byt , & b )) {
311
+ return
312
+ }
313
+ } else {
314
+ err := r .ParseForm ()
315
+ if badRequest (w , err ) {
316
+ return
317
+ }
318
+ if badRequest (w , schemaDec .Decode (b , r .PostForm )) {
319
+ return
320
+ }
285
321
}
286
322
287
323
b .Date = time .Now ()
288
324
289
- http .Redirect (w , r , "/" , http .StatusFound )
325
+ if * flagAPI {
326
+ w .WriteHeader (http .StatusOK )
327
+ return
328
+ }
329
+
330
+ redirect (w , r , "/" )
290
331
}
291
332
292
333
func destroy (w http.ResponseWriter , r * http.Request ) {
@@ -297,7 +338,12 @@ func destroy(w http.ResponseWriter, r *http.Request) {
297
338
298
339
blogs .Delete (id )
299
340
300
- http .Redirect (w , r , "/" , http .StatusFound )
341
+ if * flagAPI {
342
+ w .WriteHeader (http .StatusOK )
343
+ return
344
+ }
345
+
346
+ redirect (w , r , "/" )
301
347
}
302
348
303
349
func blogID (w http.ResponseWriter , r * http.Request ) (int , bool ) {
@@ -306,12 +352,12 @@ func blogID(w http.ResponseWriter, r *http.Request) (int, bool) {
306
352
id , err := strconv .Atoi (str )
307
353
if err != nil {
308
354
log .Println ("Error parsing blog id:" , err )
309
- http . Redirect (w , r , "/" , http . StatusFound )
355
+ redirect (w , r , "/" )
310
356
return 0 , false
311
357
}
312
358
313
359
if id <= 0 {
314
- http . Redirect (w , r , "/" , http . StatusFound )
360
+ redirect (w , r , "/" )
315
361
return 0 , false
316
362
}
317
363
@@ -333,6 +379,20 @@ func mustRender(w http.ResponseWriter, r *http.Request, name string, data authbo
333
379
current .MergeKV ("csrf_token" , nosurf .Token (r ))
334
380
current .Merge (data )
335
381
382
+ if * flagAPI {
383
+ w .Header ().Set ("Content-Type" , "application/json" )
384
+
385
+ byt , err := json .Marshal (current )
386
+ if err != nil {
387
+ w .WriteHeader (http .StatusInternalServerError )
388
+ fmt .Println ("failed to marshal json:" , err )
389
+ fmt .Fprintln (w , `{"error":"internal server error"}` )
390
+ }
391
+
392
+ w .Write (byt )
393
+ return
394
+ }
395
+
336
396
err := templates .Render (w , name , current )
337
397
if err == nil {
338
398
return
@@ -343,14 +403,32 @@ func mustRender(w http.ResponseWriter, r *http.Request, name string, data authbo
343
403
fmt .Fprintln (w , "Error occurred rendering template:" , err )
344
404
}
345
405
406
+ func redirect (w http.ResponseWriter , r * http.Request , path string ) {
407
+ if * flagAPI {
408
+ w .Header ().Set ("Content-Type" , "application/json" )
409
+ w .Header ().Set ("Location" , path )
410
+ w .WriteHeader (http .StatusFound )
411
+ fmt .Fprintf (w , `{"path": %q}` , path )
412
+ return
413
+ }
414
+
415
+ http .Redirect (w , r , path , http .StatusFound )
416
+ }
417
+
346
418
func badRequest (w http.ResponseWriter , err error ) bool {
347
419
if err == nil {
348
420
return false
349
421
}
350
422
423
+ if * flagAPI {
424
+ w .Header ().Set ("Content-Type" , "application/json" )
425
+ w .WriteHeader (http .StatusBadRequest )
426
+ fmt .Fprintln (w , `{"error":"bad request"}` , err )
427
+ return true
428
+ }
429
+
351
430
w .Header ().Set ("Content-Type" , "text/plain" )
352
431
w .WriteHeader (http .StatusBadRequest )
353
432
fmt .Fprintln (w , "Bad request:" , err )
354
-
355
433
return true
356
434
}
0 commit comments