github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/demos/guestbook/guestbook.go (about) 1 // Copyright 2011 Google Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 // This example only works on Managed VMs. 6 // +build !appengine 7 8 package main 9 10 import ( 11 "html/template" 12 "net/http" 13 "time" 14 15 "golang.org/x/net/context" 16 17 "google.golang.org/appengine" 18 "google.golang.org/appengine/datastore" 19 "google.golang.org/appengine/log" 20 "google.golang.org/appengine/user" 21 ) 22 23 var initTime time.Time 24 25 type Greeting struct { 26 Author string 27 Content string 28 Date time.Time 29 } 30 31 func main() { 32 http.HandleFunc("/", handleMainPage) 33 http.HandleFunc("/sign", handleSign) 34 appengine.Main() 35 } 36 37 // guestbookKey returns the key used for all guestbook entries. 38 func guestbookKey(ctx context.Context) *datastore.Key { 39 // The string "default_guestbook" here could be varied to have multiple guestbooks. 40 return datastore.NewKey(ctx, "Guestbook", "default_guestbook", 0, nil) 41 } 42 43 var tpl = template.Must(template.ParseGlob("templates/*.html")) 44 45 func handleMainPage(w http.ResponseWriter, r *http.Request) { 46 if r.Method != "GET" { 47 http.Error(w, "GET requests only", http.StatusMethodNotAllowed) 48 return 49 } 50 if r.URL.Path != "/" { 51 http.NotFound(w, r) 52 return 53 } 54 55 ctx := appengine.NewContext(r) 56 tic := time.Now() 57 q := datastore.NewQuery("Greeting").Ancestor(guestbookKey(ctx)).Order("-Date").Limit(10) 58 var gg []*Greeting 59 if _, err := q.GetAll(ctx, &gg); err != nil { 60 http.Error(w, err.Error(), http.StatusInternalServerError) 61 log.Errorf(ctx, "GetAll: %v", err) 62 return 63 } 64 log.Infof(ctx, "Datastore lookup took %s", time.Since(tic).String()) 65 log.Infof(ctx, "Rendering %d greetings", len(gg)) 66 67 var email, logout, login string 68 if u := user.Current(ctx); u != nil { 69 logout, _ = user.LogoutURL(ctx, "/") 70 email = u.Email 71 } else { 72 login, _ = user.LoginURL(ctx, "/") 73 } 74 data := struct { 75 Greetings []*Greeting 76 Login, Logout, Email string 77 }{ 78 Greetings: gg, 79 Login: login, 80 Logout: logout, 81 Email: email, 82 } 83 w.Header().Set("Content-Type", "text/html; charset=utf-8") 84 if err := tpl.ExecuteTemplate(w, "guestbook.html", data); err != nil { 85 log.Errorf(ctx, "%v", err) 86 } 87 } 88 89 func handleSign(w http.ResponseWriter, r *http.Request) { 90 if r.Method != "POST" { 91 http.Error(w, "POST requests only", http.StatusMethodNotAllowed) 92 return 93 } 94 ctx := appengine.NewContext(r) 95 g := &Greeting{ 96 Content: r.FormValue("content"), 97 Date: time.Now(), 98 } 99 if u := user.Current(ctx); u != nil { 100 g.Author = u.String() 101 } 102 key := datastore.NewIncompleteKey(ctx, "Greeting", guestbookKey(ctx)) 103 if _, err := datastore.Put(ctx, key, g); err != nil { 104 http.Error(w, err.Error(), http.StatusInternalServerError) 105 return 106 } 107 // Redirect with 303 which causes the subsequent request to use GET. 108 http.Redirect(w, r, "/", http.StatusSeeOther) 109 }