Created
July 8, 2014 22:06
-
-
Save shiftregister-vg/78762c41924046641ad1 to your computer and use it in GitHub Desktop.
A Simple CMS written in Go that uses flat files as storage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h1>{{.Title}}</h1> | |
<form action="/save/{{.Title}}" method="POST"> | |
<div> | |
<textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea> | |
</div> | |
<div> | |
<input type="submit" value="Save" /> | |
</div> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h1>{{.Title}}</h1> | |
<p>[<a href="/edit/{{.Title}}">edit</a>]</p> | |
<div>{{printf "%s" .Body}}</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"flag" | |
"html/template" | |
"io/ioutil" | |
"log" | |
"net" | |
"net/http" | |
"regexp" | |
) | |
var ( | |
addr = flag.Bool("addr", false, "find open address and pring to final-port.txt") | |
templates = template.Must(template.ParseFiles("edit.html", "view.html")) | |
validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") | |
) | |
type Page struct { | |
Title string | |
Body []byte | |
} | |
func (p *Page) save() error { | |
filename := p.Title + ".txt" | |
return ioutil.WriteFile(filename, p.Body, 0600) | |
} | |
func loadPage(title string) (*Page, error) { | |
filename := title + ".txt" | |
body, err := ioutil.ReadFile(filename) | |
if err != nil { | |
return nil, err | |
} | |
return &Page{Title: title, Body: body}, nil | |
} | |
func getTitle(w http.ResponseWriter, r *http.Request) (string, error) { | |
m := validPath.FindStringSubmatch(r.URL.Path) | |
if m == nil { | |
http.NotFound(w, r) | |
return "", errors.New("Invalid Page Title") | |
} | |
return m[2], nil | |
} | |
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { | |
err := templates.ExecuteTemplate(w, tmpl+".html", p) | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
} | |
} | |
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { | |
return func(w http.ResponseWriter, r *http.Request) { | |
// Here we will extract the page title from the Request, | |
// and call the provided handler 'fn' | |
m := validPath.FindStringSubmatch(r.URL.Path) | |
if m == nil { | |
http.NotFound(w, r) | |
return | |
} | |
fn(w, r, m[2]) | |
} | |
} | |
func viewHandler(w http.ResponseWriter, r *http.Request, title string) { | |
p, err := loadPage(title) | |
if err != nil { | |
http.Redirect(w, r, "/edit/"+title, http.StatusFound) | |
return | |
} | |
renderTemplate(w, "view", p) | |
} | |
func editHandler(w http.ResponseWriter, r *http.Request, title string) { | |
p, err := loadPage(title) | |
if err != nil { | |
p = &Page{Title: title} | |
} | |
renderTemplate(w, "edit", p) | |
} | |
func saveHandler(w http.ResponseWriter, r *http.Request, title string) { | |
body := r.FormValue("body") | |
p := &Page{Title: title, Body: []byte(body)} | |
err := p.save() | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
http.Redirect(w, r, "/view/"+title, http.StatusFound) | |
} | |
func main() { | |
flag.Parse() | |
http.HandleFunc("/view/", makeHandler(viewHandler)) | |
http.HandleFunc("/edit/", makeHandler(editHandler)) | |
http.HandleFunc("/save/", makeHandler(saveHandler)) | |
if *addr { | |
l, err := net.Listen("tcp", "127.0.0.1:0") | |
if err != nil { | |
log.Fatal(err) | |
} | |
err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644) | |
if err != nil { | |
log.Fatal(err) | |
} | |
s := &http.Server{} | |
s.Serve(l) | |
return | |
} | |
log.Print("Starting server @ http://127.0.0.1:9000/") | |
http.ListenAndServe(":9000", nil) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment