Gisle Aune
7 years ago
10 changed files with 227 additions and 14 deletions
-
1controllers/listcontroller.go
-
120controllers/pagecontroller.go
-
5formparser/parsers.go
-
1main.go
-
15model/category.go
-
1view/renderer.go
-
50view/templates/create.tmpl
-
10view/templates/login.tmpl
-
21viewmodel/pageform.go
-
15viewmodel/pageview.go
@ -0,0 +1,120 @@ |
|||
package controllers |
|||
|
|||
import ( |
|||
"net/http" |
|||
"strings" |
|||
"time" |
|||
|
|||
"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 |
|||
} |
|||
} |
|||
} |
|||
|
|||
view.Render(w, "create", 200, pc) |
|||
|
|||
return true |
|||
} |
|||
|
|||
func pageView(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 |
|||
} |
|||
|
|||
return true |
|||
} |
|||
|
|||
func init() { |
|||
PageController.Function("/create", pageCreate) |
|||
PageController.Function("/", pageView) |
|||
} |
@ -0,0 +1,50 @@ |
|||
{{ define "content" }} |
|||
<article> |
|||
<h1>Create</h1> |
|||
<form action="/page/create", method="POST"> |
|||
<p class="red">{{$.Error}}</p> |
|||
<input class="big" placeholder="Page Name" name="name" type="text" value="{{$.Page.Name}}" autofocus /> |
|||
<textarea class="tall" placeholder="Content" name="source">{{$.Page.Source}}</textarea> |
|||
<input placeholder="IC Date" name="fictionalDate" type="text" value="{{if $.Page.FictionalDate.IsZero}}{{else}}{{$.Page.FictionalDate}}{{end}}" autofocus /> |
|||
<div class="group"> |
|||
{{ range $.Categories }} |
|||
<div class="radio-wrapper"> |
|||
<input name="category" type="radio" name="category" value="{{.Key}}" {{if eq $.Page.Category .Key}}checked{{end}}><b> {{.Key}}</b>: {{.Info}}</input> |
|||
</div> |
|||
{{ end }} |
|||
</div> |
|||
<textarea name="tags" placeholder="Tags, e.g. 'Location: Miner's Respite'. One per line, topmost is primary tag"></textarea> |
|||
<div class="group"> |
|||
<div class="radio-wrapper"> |
|||
<input type="checkbox" name="dated" value="true" {{if $.Page.Dated}}checked{{end}}><b> Dated</b>: The IC date is shown on the page list. It will still be used for sorting if this option is disabled.</input> |
|||
</div> |
|||
<div class="radio-wrapper"> |
|||
<input type="checkbox" name="unlisted" value="true" {{if $.Page.Unlisted}}checked{{end}}><b> Unlisted</b>: This page will not show up on page lists, but anyone with a link can view it.</input> |
|||
</div> |
|||
<div class="radio-wrapper"> |
|||
<input type="checkbox" name="specific" value="true" {{if $.Page.Specific}}checked{{end}}><b> Specific</b>: This page will only show up on page lists when one of its tags is searched for.</input> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Future option --> |
|||
<input type="hidden" name="type" value="Markdown" /> |
|||
<input type="hidden" name="published" value="True" /> |
|||
|
|||
<button type="submit">Submit</button> |
|||
|
|||
</form> |
|||
</article> |
|||
{{ end }} |
|||
|
|||
{{ define "menu" }} |
|||
<a href="/"><h1>Aite RP</h1></a> |
|||
|
|||
<ul> |
|||
<li><a href="/"><div class="mg-icon"><</div><div class="mg-label">Back</div></a></li> |
|||
</ul> |
|||
{{ end }} |
|||
|
|||
{{ define "head" }} |
|||
<link rel="stylesheet" href="/ui/css/form.css" /> |
|||
<script type="text/javascript" src="/ui/js/form-page.js"></script> |
|||
{{ end }} |
@ -0,0 +1,21 @@ |
|||
package viewmodel |
|||
|
|||
import ( |
|||
"git.aiterp.net/AiteRP/aitestory/model" |
|||
"git.aiterp.net/gisle/wrouter/auth" |
|||
) |
|||
|
|||
type PageForm struct { |
|||
Base |
|||
Page model.Page |
|||
Categories []model.PageCategory |
|||
Operation string |
|||
Error string |
|||
TagInput string |
|||
} |
|||
|
|||
func (pf *PageForm) Setup(user *auth.User) { |
|||
pf.setupBase(user, "Create") |
|||
pf.Categories = model.PageCategories |
|||
pf.Page.Defaults() |
|||
} |
@ -0,0 +1,15 @@ |
|||
package viewmodel |
|||
|
|||
import ( |
|||
"git.aiterp.net/AiteRP/aitestory/model" |
|||
"git.aiterp.net/gisle/wrouter/auth" |
|||
) |
|||
|
|||
type PageView struct { |
|||
Base |
|||
Page model.Page |
|||
} |
|||
|
|||
func (pv *PageView) Setup(user *auth.User) { |
|||
pv.setupBase(user, pv.Page.Name) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue