//PageCreate handles /admin/new_page route func PageCreate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { data["Title"] = "New page" data["Active"] = "pages" data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("pages/form").Execute(w, data) } else if r.Method == "POST" { page := &models.Page{ Name: r.PostFormValue("name"), Content: r.PostFormValue("content"), Published: shared.Atob(r.PostFormValue("published")), } if err := page.Insert(); err != nil { session.AddFlash(err.Error()) session.Save(r, w) http.Redirect(w, r, "/admin/new_page", 303) return } http.Redirect(w, r, "/admin/pages", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//ArchiveShow handles GET /archives/:year-:month route func ArchiveShow(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) data := shared.DefaultData(r) if r.Method == "GET" { param := r.URL.Path[len("/archives/"):] ym := strings.Split(param, "-") if len(ym) != 2 { w.WriteHeader(400) tmpl.Lookup("errors/400").Execute(w, nil) return } year, _ := strconv.Atoi(ym[0]) month, _ := strconv.Atoi(ym[1]) list, err := models.GetPostsByArchive(year, month) if err != nil { w.WriteHeader(500) tmpl.Lookup("errors/500").Execute(w, nil) return } data["Title"] = fmt.Sprintf("%s %s %d", "Archives for", time.Month(month).String(), year) data["List"] = list data["Active"] = fmt.Sprintf("archives/%d-%02d", year, month) tmpl.Lookup("archives/show").Execute(w, data) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//TagCreate handles /admin/new_tag route func TagCreate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { data["Title"] = "New tag" data["Active"] = "tags" data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("tags/form").Execute(w, data) } else if r.Method == "POST" { tag := &models.Tag{ Name: r.PostFormValue("name"), } if err := tag.Insert(); err != nil { session.AddFlash(err.Error()) session.Save(r, w) http.Redirect(w, r, "/admin/new_tag", 303) return } http.Redirect(w, r, "/admin/tags", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//PageDelete handles /admin/delete_page route func PageDelete(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) if r.Method == "POST" { page, err := models.GetPage(r.PostFormValue("id")) if err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, shared.ErrorData(err)) } if err := page.Delete(); err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(500) tmpl.Lookup("errors/500").Execute(w, shared.ErrorData(err)) return } http.Redirect(w, r, "/admin/pages", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//Home handles GET / route func Home(w http.ResponseWriter, r *http.Request) { tmpl, data := shared.Template(r), shared.DefaultData(r) if r.RequestURI != "/" { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, nil) return } data["Title"] = "Welcome to blog boilerplate" data["Active"] = "home" tmpl.Lookup("home/show").Execute(w, data) }
//PostUpdate handles /admin/edit_post/:id route func PostUpdate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { id := r.URL.Path[len("/admin/edit_post/"):] post, err := models.GetPost(id) if err != nil { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, shared.ErrorData(err)) return } tags, err := models.GetTags() if err != nil { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, nil) return } data["Title"] = "Edit post" data["Active"] = "posts" data["Post"] = post data["Tags"] = tags data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("posts/form").Execute(w, data) } else if r.Method == "POST" { r.ParseForm() post := &models.Post{ ID: shared.Atoi64(r.PostFormValue("id")), Name: r.PostFormValue("name"), Content: r.PostFormValue("content"), Published: shared.Atob(r.PostFormValue("published")), Tags: r.Form["tags"], //PostFormValue returns only first value } if err := post.Update(); err != nil { session.AddFlash(err.Error()) session.Save(r, w) http.Redirect(w, r, r.RequestURI, 303) return } http.Redirect(w, r, "/admin/posts", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//SignUp handles /signup route func SignUp(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { data["Title"] = "Sign up" data["Active"] = "signup" data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("auth/signup").Execute(w, data) } else if r.Method == "POST" { user := &models.User{ Email: r.PostFormValue("email"), Password: r.PostFormValue("password"), } //check existence userDB, _ := models.GetUserByEmail(user.Email) if userDB.ID != 0 { session.AddFlash("User exists") session.Save(r, w) http.Redirect(w, r, "/signup", 303) return } //create user err := user.HashPassword() if err != nil { session.AddFlash("Error whilst registering user.") session.Save(r, w) log.Printf("ERROR: can't register user: %v", err) http.Redirect(w, r, "/signup", 303) return } if err := user.Insert(); err != nil { session.AddFlash("Error whilst registering user.") session.Save(r, w) log.Printf("ERROR: can't register user: %v", err) http.Redirect(w, r, "/signup", 303) return } session.Values["user_id"] = user.ID session.Save(r, w) http.Redirect(w, r, "/", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//UserUpdate handles /admin/edit_user/:id route func UserUpdate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { id := r.URL.Path[len("/admin/edit_user/"):] user, err := models.GetUser(id) if err != nil { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, shared.ErrorData(err)) return } data["Title"] = "Edit user" data["Active"] = "users" data["User"] = user data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("users/form").Execute(w, data) } else if r.Method == "POST" { user := &models.User{ ID: shared.Atoi64(r.PostFormValue("id")), Name: r.PostFormValue("name"), Email: r.PostFormValue("email"), Password: r.PostFormValue("password"), } if err := user.HashPassword(); err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(500) tmpl.Lookup("errors/500").Execute(w, shared.ErrorData(err)) return } if err := user.Update(); err != nil { session.AddFlash(err.Error()) session.Save(r, w) http.Redirect(w, r, r.RequestURI, 303) return } http.Redirect(w, r, "/admin/users", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//RssXML handles GET /rss route func RssXML(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) if r.Method == "GET" { now := time.Now() domain := shared.GetConfig().Domain feed := &feeds.Feed{ Title: "Blog boilerplate", Link: &feeds.Link{Href: domain}, Description: "Basic blog boilerplate in Go", Author: &feeds.Author{Name: "Blog Author"}, Created: now, Copyright: fmt.Sprintf("© %s", "Blog"), } feed.Items = make([]*feeds.Item, 0) posts, err := models.GetPublishedPosts() if err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(500) tmpl.Lookup("errors/500").Execute(w, shared.ErrorData(err)) return } for i := range posts { feed.Items = append(feed.Items, &feeds.Item{ Id: fmt.Sprintf("%s/posts/%d", domain, posts[i].ID), Title: posts[i].Name, Link: &feeds.Link{Href: fmt.Sprintf("%s/posts/%d", domain, posts[i].ID)}, Description: string(posts[i].Excerpt()), Author: &feeds.Author{Name: posts[i].Author.Name}, Created: now, }) } rss, err := feed.ToRss() if err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(500) tmpl.Lookup("errors/500").Execute(w, shared.ErrorData(err)) return } fmt.Fprintln(w, rss) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//CommentReply handles /admin/new_comment route func CommentReply(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { user := context.Get(r, "user").(*models.User) parentID := shared.Atoi64(r.FormValue("parent_id")) parent, _ := models.GetComment(parentID) comment := &models.Comment{ PostID: parent.PostID, ParentID: null.NewInt(parentID, parentID > 0), AuthorName: user.Name, } data["Title"] = "Reply" data["Active"] = "comments" data["Comment"] = comment data["Flash"] = session.Flashes("comments") session.Save(r, w) tmpl.Lookup("comments/form").Execute(w, data) } else if r.Method == "POST" { parentID := shared.Atoi64(r.PostFormValue("parent_id")) comment := &models.Comment{ PostID: shared.Atoi64(r.PostFormValue("post_id")), ParentID: null.NewInt(parentID, parentID > 0), AuthorName: r.PostFormValue("author_name"), Content: r.PostFormValue("content"), Published: shared.Atob(r.PostFormValue("published")), } if err := comment.Insert(); err != nil { session.AddFlash(err.Error(), "comments") session.Save(r, w) http.Redirect(w, r, r.RequestURI, 303) return } http.Redirect(w, r, "/admin/comments", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//SignIn handles /signin route func SignIn(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { data["Title"] = "Sign in" data["Active"] = "signin" data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("auth/signin").Execute(w, data) } else if r.Method == "POST" { user := &models.User{ Email: r.PostFormValue("email"), Password: r.PostFormValue("password"), } //check existence userDB, _ := models.GetUserByEmail(user.Email) if userDB.ID == 0 { log.Printf("ERROR: Login failed, IP: %s, Email: %s\n", r.RemoteAddr, user.Email) session.AddFlash("Email or password incorrect") session.Save(r, w) http.Redirect(w, r, "/signin", 303) return } //create user if err := userDB.ComparePassword(user.Password); err != nil { log.Printf("ERROR: Login failed, IP: %s, Email: %s\n", r.RemoteAddr, user.Email) session.AddFlash("Email or password incorrect") session.Save(r, w) http.Redirect(w, r, "/signin", 303) return } session.Values["user_id"] = userDB.ID session.Save(r, w) http.Redirect(w, r, "/", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//PostCreate handles /admin/new_post route func PostCreate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { tags, err := models.GetTags() if err != nil { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, nil) return } data["Title"] = "New post" data["Active"] = "posts" data["Tags"] = tags data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("posts/form").Execute(w, data) } else if r.Method == "POST" { r.ParseForm() post := &models.Post{ Name: r.PostFormValue("name"), Content: r.PostFormValue("content"), Published: shared.Atob(r.PostFormValue("published")), Tags: r.Form["tags"], //PostFormValue returns only first value } if user := context.Get(r, "user"); user != nil { post.UserID = null.NewInt(user.(*models.User).ID, user.(*models.User).ID > 0) } if err := post.Insert(); err != nil { session.AddFlash(err.Error()) session.Save(r, w) http.Redirect(w, r, "/admin/new_post", 303) return } http.Redirect(w, r, "/admin/posts", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//CommentUpdate handles /admin/edit_comment/:id route func CommentUpdate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { id := r.URL.Path[len("/admin/edit_comment/"):] comment, err := models.GetComment(id) if err != nil { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, shared.ErrorData(err)) return } data["Title"] = "Edit comment" data["Active"] = "comments" data["Comment"] = comment data["Flash"] = session.Flashes("comments") session.Save(r, w) tmpl.Lookup("comments/form").Execute(w, data) } else if r.Method == "POST" { r.ParseForm() comment := &models.Comment{ ID: shared.Atoi64(r.PostFormValue("id")), Content: r.PostFormValue("content"), Published: shared.Atob(r.PostFormValue("published")), } if err := comment.Update(); err != nil { session.AddFlash(err.Error(), "comments") session.Save(r, w) http.Redirect(w, r, r.RequestURI, 303) return } http.Redirect(w, r, "/admin/comments", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//PageUpdate handles /admin/edit_page/:id route func PageUpdate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { id := r.URL.Path[len("/admin/edit_page/"):] page, err := models.GetPage(id) if err != nil { w.WriteHeader(400) tmpl.Lookup("errors/400").Execute(w, shared.ErrorData(err)) return } data["Title"] = "Edit page" data["Active"] = "pages" data["Page"] = page data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("pages/form").Execute(w, data) } else if r.Method == "POST" { page := &models.Page{ ID: shared.Atoi64(r.PostFormValue("id")), Name: r.PostFormValue("name"), Content: r.PostFormValue("content"), Published: shared.Atob(r.PostFormValue("published")), } if err := page.Update(); err != nil { session.AddFlash(err.Error()) session.Save(r, w) http.Redirect(w, r, r.RequestURI, 303) return } http.Redirect(w, r, "/admin/pages", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//Search handles POST /search route func Search(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) data := shared.DefaultData(r) if r.Method == "POST" { query := r.PostFormValue("query") //full text search by name & description. Btw you can extend search to multi-table scenario with rankings, etc //fts index and SearchPosts assume language is english posts, _ := models.SearchPosts(query) data["Title"] = fmt.Sprintf("%s %q", "Search results for", query) data["Posts"] = posts tmpl.Lookup("search/results").Execute(w, data) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//UserCreate handles /admin/new_user route func UserCreate(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { data["Title"] = "New user" data["Active"] = "users" data["Flash"] = session.Flashes() session.Save(r, w) tmpl.Lookup("users/form").Execute(w, data) } else if r.Method == "POST" { user := &models.User{ Name: r.PostFormValue("name"), Email: r.PostFormValue("email"), Password: r.PostFormValue("password"), } if err := user.HashPassword(); err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(500) tmpl.Lookup("errors/500").Execute(w, shared.ErrorData(err)) return } if err := user.Insert(); err != nil { session.AddFlash(err.Error()) session.Save(r, w) http.Redirect(w, r, "/admin/new_user", 303) return } http.Redirect(w, r, "/admin/users", 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//PostShow handles GET /posts/:id route func PostShow(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) session := shared.Session(r) data := shared.DefaultData(r) if r.Method == "GET" { id := r.URL.Path[len("/posts/"):] post, err := models.GetPost(id) if err != nil || !post.Published { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, nil) return } data["Post"] = post data["Title"] = post.Name data["Active"] = fmt.Sprintf("posts/%s", id) data["OauthName"] = session.Values["oauth_name"] //Facebook open graph meta tags data["Ogheadprefix"] = "og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#" data["Ogtitle"] = post.Name data["Ogurl"] = fmt.Sprintf("http://%s/posts/%d", r.Host, post.ID) data["Ogtype"] = "article" data["Ogdescription"] = post.Excerpt() if img := post.GetImage(); len(img) > 0 { data["Ogimage"] = fmt.Sprintf("http://%s%s", r.Host, img) } //flashes data["Flash"] = session.Flashes("comments") session.Save(r, w) tmpl.Lookup("posts/show").Execute(w, data) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//PageIndex handles GET /admin/pages route func PageIndex(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) data := shared.DefaultData(r) if r.Method == "GET" { list, err := models.GetPages() if err != nil { w.WriteHeader(500) tmpl.Lookup("errors/500").Execute(w, shared.ErrorData(err)) return } data["Title"] = "Pages" data["Active"] = "pages" data["List"] = list tmpl.Lookup("pages/index").Execute(w, data) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//CommentCreate handles /new_comment route func CommentCreate(w http.ResponseWriter, r *http.Request) { session := shared.Session(r) tmpl := shared.Template(r) if r.Method == "POST" { if _, ok := session.Values["oauth_name"]; !ok { err := fmt.Errorf("You are not authorized to post comments.") log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) return } comment := &models.Comment{ PostID: shared.Atoi64(r.PostFormValue("post_id")), AuthorName: session.Values["oauth_name"].(string), Content: r.PostFormValue("content"), Published: false, //comments are published by admin via dashboard } if err := comment.Insert(); err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(400) tmpl.Lookup("errors/400").Execute(w, shared.ErrorData(err)) return } session.AddFlash("Thank you! Your comment will be visible after approval.", "comments") session.Save(r, w) http.Redirect(w, r, fmt.Sprintf("/posts/%d#comments", comment.PostID), 303) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//PageShow handles /pages/:id route func PageShow(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) data := shared.DefaultData(r) if r.Method == "GET" { id := r.URL.Path[len("/pages/"):] page, err := models.GetPage(id) if err != nil || !page.Published { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, nil) return } data["Page"] = page data["Title"] = page.Name data["Active"] = fmt.Sprintf("pages/%s", id) tmpl.Lookup("pages/show").Execute(w, data) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//TagShow handles GET /tags/:name route func TagShow(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) data := shared.DefaultData(r) if r.Method == "GET" { name := r.URL.Path[len("/tags/"):] tag, err := models.GetTag(name) if err != nil { w.WriteHeader(404) tmpl.Lookup("errors/404").Execute(w, nil) return } data["Tag"] = tag data["Title"] = tag.Name data["Active"] = fmt.Sprintf("tags/%s", name) tmpl.Lookup("tags/show").Execute(w, data) } else { err := fmt.Errorf("Method %q not allowed", r.Method) log.Printf("ERROR: %s\n", err) w.WriteHeader(405) tmpl.Lookup("errors/405").Execute(w, shared.ErrorData(err)) } }
//Dashboard handles GET /admin route func Dashboard(w http.ResponseWriter, r *http.Request) { tmpl := shared.Template(r) data := shared.DefaultData(r) data["Title"] = "Dashboard" tmpl.Lookup("dashboard/show").Execute(w, data) }