Home | History | Annotate | Download | only in wiki
      1 // Copyright 2010 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package main
      6 
      7 import (
      8 	"errors"
      9 	"html/template"
     10 	"io/ioutil"
     11 	"net/http"
     12 	"regexp"
     13 )
     14 
     15 type Page struct {
     16 	Title string
     17 	Body  []byte
     18 }
     19 
     20 func (p *Page) save() error {
     21 	filename := p.Title + ".txt"
     22 	return ioutil.WriteFile(filename, p.Body, 0600)
     23 }
     24 
     25 func loadPage(title string) (*Page, error) {
     26 	filename := title + ".txt"
     27 	body, err := ioutil.ReadFile(filename)
     28 	if err != nil {
     29 		return nil, err
     30 	}
     31 	return &Page{Title: title, Body: body}, nil
     32 }
     33 
     34 func viewHandler(w http.ResponseWriter, r *http.Request) {
     35 	title, err := getTitle(w, r)
     36 	if err != nil {
     37 		return
     38 	}
     39 	p, err := loadPage(title)
     40 	if err != nil {
     41 		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
     42 		return
     43 	}
     44 	renderTemplate(w, "view", p)
     45 }
     46 
     47 func editHandler(w http.ResponseWriter, r *http.Request) {
     48 	title, err := getTitle(w, r)
     49 	if err != nil {
     50 		return
     51 	}
     52 	p, err := loadPage(title)
     53 	if err != nil {
     54 		p = &Page{Title: title}
     55 	}
     56 	renderTemplate(w, "edit", p)
     57 }
     58 
     59 func saveHandler(w http.ResponseWriter, r *http.Request) {
     60 	title, err := getTitle(w, r)
     61 	if err != nil {
     62 		return
     63 	}
     64 	body := r.FormValue("body")
     65 	p := &Page{Title: title, Body: []byte(body)}
     66 	err = p.save()
     67 	if err != nil {
     68 		http.Error(w, err.Error(), http.StatusInternalServerError)
     69 		return
     70 	}
     71 	http.Redirect(w, r, "/view/"+title, http.StatusFound)
     72 }
     73 
     74 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
     75 	t, err := template.ParseFiles(tmpl + ".html")
     76 	if err != nil {
     77 		http.Error(w, err.Error(), http.StatusInternalServerError)
     78 		return
     79 	}
     80 	err = t.Execute(w, p)
     81 	if err != nil {
     82 		http.Error(w, err.Error(), http.StatusInternalServerError)
     83 	}
     84 }
     85 
     86 var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
     87 
     88 func getTitle(w http.ResponseWriter, r *http.Request) (string, error) {
     89 	m := validPath.FindStringSubmatch(r.URL.Path)
     90 	if m == nil {
     91 		http.NotFound(w, r)
     92 		return "", errors.New("Invalid Page Title")
     93 	}
     94 	return m[2], nil // The title is the second subexpression.
     95 }
     96 
     97 func main() {
     98 	http.HandleFunc("/view/", viewHandler)
     99 	http.HandleFunc("/edit/", editHandler)
    100 	http.HandleFunc("/save/", saveHandler)
    101 	http.ListenAndServe(":8080", nil)
    102 }
    103