You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
6.9 KiB
289 lines
6.9 KiB
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)
|
|
}
|