|
|
package controllers
import ( "fmt" "net/http" "strings" "time"
"git.aiterp.net/gisle/wrouter/response"
"git.aiterp.net/AiteRP/aitestory/model" "git.aiterp.net/AiteRP/aitestory/viewmodel"
"git.aiterp.net/AiteRP/aitestory/view"
"git.aiterp.net/gisle/wrouter" "git.aiterp.net/gisle/wrouter/auth" )
// PageController serves page creation, viewing, editing and deleting through the website.
var PageController = wrouter.Router{}
func pageCreate(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool { if (req.Method != "GET" && req.Method != "POST") || len(req.URL.Path) > len(path) { return false }
pc := viewmodel.PageForm{} pc.Setup(user) pc.Operation = "Create"
// Make sure the user is logged in
if user == nil { // It's completely safe to eject logged-out users if they're not submitting
if req.Method == "GET" { http.Redirect(w, req, "/user/login?form=/page/create", 302) return true }
// Logged in users would probably want a chance to log in on another form, though.
pc.Error = "You are not logged in." }
// Respect the banhammer's authority
if user != nil && user.Level == "restricted" { pc.Error = "Your user account is not permitted to do this" }
// Handle submissions if nothing has complained yet
if req.Method == "POST" && pc.Error == "" { // Validate form
req.ParseForm() errs := pc.Page.ParseForm(req.Form) if len(errs) > 0 { pc.Error = "Validation failed: " + errs[0].Error() }
// Parse the tags textbox
pc.TagInput = req.Form.Get("tags") tagLines := strings.Split(pc.TagInput, "\n") for _, line := range tagLines { var tagType, tagName string
// Skip empty lines, and allow some accidental letters
if len(line) < 2 { continue }
// Parse tokens
tokens := strings.SplitN(line, ":", 2) if len(tokens) == 2 { tagType = strings.Trim(tokens[0], " \t\r") tagName = strings.Trim(tokens[1], " \t\r") } else { tagType = "*" // Permit untyped tags if it exists.
tagName = strings.Trim(tokens[0], " \t\r") }
// Grab the tag
tag, err := model.EnsureTag(tagType, tagName) if err != nil { pc.Error = "Check your tags: " + err.Error() break }
// Take a copy of it
pc.Page.Tags = append(pc.Page.Tags, *tag) }
// If everything worked out, fill in the last bits and send it off
if len(errs) == 0 && pc.Error == "" { pc.Page.Author = user.FullID() pc.Page.PublishDate = time.Now() pc.Page.EditDate = pc.Page.PublishDate.Add(-time.Hour)
err := pc.Page.Insert() if err != nil { pc.Error = "Insert failed: " + err.Error() } else { // Let us see what you have wrought upon the world
http.Redirect(w, req, "/page/"+pc.Page.ID, 302) return true } } } else { // Losing input makes the user sad, let's see to it
// that it doesn't happen.
req.ParseForm() pc.Page.ParseForm(req.Form) pc.TagInput = req.Form.Get("tags") }
view.Render(w, "page/create", 200, pc)
return true }
func pageView(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool { if req.Method != "GET" || strings.LastIndex(req.URL.Path, "/") > len(path) { return false }
page, err := model.FindPage(req.URL.Path[len(path):]) if err != nil { response.Text(w, 500, err.Error()) return true } else if page == nil { return false }
pv := viewmodel.PageView{} pv.Page = page pv.Setup(user)
view.Render(w, "page/view", 200, pv)
return true }
func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool { if (req.Method != "GET" && req.Method != "POST") || strings.LastIndex(req.URL.Path, "/") > len(path) { return false }
page, err := model.FindPage(req.URL.Path[len(path):]) if err != nil { response.Text(w, 500, err.Error()) return true } else if page == nil { return false }
pv := viewmodel.PageView{} pv.Page = page pv.Setup(user)
if user == nil || user.FullID() != page.Author { view.Render(w, "message/error-access", http.StatusForbidden, path) return true }
if req.Method == "POST" { req.ParseForm()
// Catch sneaky shenanigans
if req.Form.Get("aft") != user.Session.ID { view.Render(w, "message/error-forgery", http.StatusForbidden, path) return true }
// Thy will be done
err := page.Delete() if err != nil { // It wasn't done D:
view.Render(w, "message/error-internal", http.StatusInternalServerError, err) return true }
// It has been done
view.Render(w, "message/page-deleted", 200, pv) return true }
view.Render(w, "page/delete", 200, pv) return true }
func pageEdit(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool { if (req.Method != "GET" && req.Method != "POST") || strings.LastIndex(req.URL.Path, "/") > len(path) { return false }
page, err := model.FindPage(req.URL.Path[len(path):]) if err != nil { response.Text(w, 500, err.Error()) return true } else if page == nil { return false }
pf := viewmodel.PageForm{} pf.Setup(user)
pf.Operation = "Edit" pf.Page = *page
if user == nil { pf.Error = "You are not logged in" }
if user != nil && user.FullID() != page.Author { pf.Error = "Permission denied" }
if req.Method == "POST" { req.ParseForm()
errs := pf.Page.ParseForm(req.Form) if len(errs) > 0 { pf.Error = "Validation failed: " + errs[0].Error() }
if len(errs) == 0 && pf.Error == "" { pf.TagInput = req.Form.Get("tags") pf.Page.Tags = make([]model.Tag, 0, strings.Count(pf.TagInput, "\n")) tagLines := strings.Split(pf.TagInput, "\n") for _, line := range tagLines { var tagType, tagName string
// Skip empty lines, and allow some accidental letters
if len(line) < 2 { continue }
// Parse tokens
tokens := strings.SplitN(line, ":", 2) if len(tokens) == 2 { tagType = strings.Trim(tokens[0], " \t\r") tagName = strings.Trim(tokens[1], " \t\r") } else { tagType = "*" // Permit untyped tags if it exists.
tagName = strings.Trim(tokens[0], " \t\r") }
// Grab the tag
tag, err := model.EnsureTag(tagType, tagName) if err != nil { pf.Error = "Check your tags: " + err.Error() break }
// Take a copy of it
pf.Page.Tags = append(pf.Page.Tags, *tag) }
if pf.Error == "" { pf.Page.EditDate = time.Now()
err := pf.Page.Update() if err != nil { pf.Error = "Edit failed: " + err.Error() } else { http.Redirect(w, req, "/page/"+pf.Page.ID, 302) return true } } } } else { for _, tag := range page.Tags { line := fmt.Sprintf("%s: %s\n", tag.Type, tag.Name)
if page.PrimaryTag().ID == tag.ID { pf.TagInput = line + pf.TagInput } else { pf.TagInput += line } } }
view.Render(w, "page/edit", 200, pf) return true }
func init() { PageController.Function("/create", pageCreate) PageController.Function("/edit/", pageEdit) PageController.Function("/delete/", pageDelete) PageController.Function("/", pageView) }
|