blob: 067f502c6bb5ecd3e41098ac26851b270fac081f [file] [log] [blame]
Andrew Gerrand78d9a602010-04-28 12:36:39 +10001package main
2
3import (
4 "http"
5 "io/ioutil"
6 "os"
7 "regexp"
Andrew Gerrandb67b72d2011-08-18 10:38:08 +10008 "template"
Andrew Gerrand78d9a602010-04-28 12:36:39 +10009)
10
Andrew Gerrandadd4e162011-01-26 14:56:52 +100011type Page struct {
12 Title string
13 Body []byte
Andrew Gerrand78d9a602010-04-28 12:36:39 +100014}
15
Andrew Gerrandadd4e162011-01-26 14:56:52 +100016func (p *Page) save() os.Error {
17 filename := p.Title + ".txt"
18 return ioutil.WriteFile(filename, p.Body, 0600)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100019}
20
Andrew Gerrandadd4e162011-01-26 14:56:52 +100021func loadPage(title string) (*Page, os.Error) {
Andrew Gerrand78d9a602010-04-28 12:36:39 +100022 filename := title + ".txt"
23 body, err := ioutil.ReadFile(filename)
24 if err != nil {
25 return nil, err
26 }
Andrew Gerrandadd4e162011-01-26 14:56:52 +100027 return &Page{Title: title, Body: body}, nil
Andrew Gerrand78d9a602010-04-28 12:36:39 +100028}
29
Stephen Maa2332a32010-09-30 13:19:33 +100030func viewHandler(w http.ResponseWriter, r *http.Request) {
31 title, err := getTitle(w, r)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100032 if err != nil {
33 return
34 }
35 p, err := loadPage(title)
36 if err != nil {
Stephen Maa2332a32010-09-30 13:19:33 +100037 http.Redirect(w, r, "/edit/"+title, http.StatusFound)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100038 return
39 }
Stephen Maa2332a32010-09-30 13:19:33 +100040 renderTemplate(w, "view", p)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100041}
42
Stephen Maa2332a32010-09-30 13:19:33 +100043func editHandler(w http.ResponseWriter, r *http.Request) {
44 title, err := getTitle(w, r)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100045 if err != nil {
46 return
47 }
48 p, err := loadPage(title)
49 if err != nil {
Andrew Gerrandadd4e162011-01-26 14:56:52 +100050 p = &Page{Title: title}
Andrew Gerrand78d9a602010-04-28 12:36:39 +100051 }
Stephen Maa2332a32010-09-30 13:19:33 +100052 renderTemplate(w, "edit", p)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100053}
54
Stephen Maa2332a32010-09-30 13:19:33 +100055func saveHandler(w http.ResponseWriter, r *http.Request) {
56 title, err := getTitle(w, r)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100057 if err != nil {
58 return
59 }
60 body := r.FormValue("body")
Andrew Gerrandadd4e162011-01-26 14:56:52 +100061 p := &Page{Title: title, Body: []byte(body)}
Andrew Gerrand78d9a602010-04-28 12:36:39 +100062 err = p.save()
63 if err != nil {
Stephen Maa2332a32010-09-30 13:19:33 +100064 http.Error(w, err.String(), http.StatusInternalServerError)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100065 return
66 }
Stephen Maa2332a32010-09-30 13:19:33 +100067 http.Redirect(w, r, "/view/"+title, http.StatusFound)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100068}
69
Andrew Gerrandadd4e162011-01-26 14:56:52 +100070func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
Andrew Gerrandb67b72d2011-08-18 10:38:08 +100071 t, err := template.ParseFile(tmpl+".html")
Andrew Gerrand78d9a602010-04-28 12:36:39 +100072 if err != nil {
Stephen Maa2332a32010-09-30 13:19:33 +100073 http.Error(w, err.String(), http.StatusInternalServerError)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100074 return
75 }
Andrew Gerrand4896b172011-03-09 12:59:13 +110076 err = t.Execute(w, p)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100077 if err != nil {
Stephen Maa2332a32010-09-30 13:19:33 +100078 http.Error(w, err.String(), http.StatusInternalServerError)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100079 }
80}
81
82const lenPath = len("/view/")
83
84var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
85
Stephen Maa2332a32010-09-30 13:19:33 +100086func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
Andrew Gerrand78d9a602010-04-28 12:36:39 +100087 title = r.URL.Path[lenPath:]
88 if !titleValidator.MatchString(title) {
Stephen Maa2332a32010-09-30 13:19:33 +100089 http.NotFound(w, r)
Andrew Gerrand78d9a602010-04-28 12:36:39 +100090 err = os.NewError("Invalid Page Title")
91 }
92 return
93}
94
95func main() {
96 http.HandleFunc("/view/", viewHandler)
97 http.HandleFunc("/edit/", editHandler)
98 http.HandleFunc("/save/", saveHandler)
99 http.ListenAndServe(":8080", nil)
100}