Browse Source

Create Page is done

master
Gisle Aune 7 years ago
parent
commit
d15e4e967e
  1. 1
      controllers/listcontroller.go
  2. 120
      controllers/pagecontroller.go
  3. 5
      formparser/parsers.go
  4. 1
      main.go
  5. 15
      model/category.go
  6. 1
      view/renderer.go
  7. 50
      view/templates/create.tmpl
  8. 12
      view/templates/login.tmpl
  9. 21
      viewmodel/pageform.go
  10. 15
      viewmodel/pageview.go

1
controllers/listcontroller.go

@ -78,7 +78,6 @@ func listFiltered(category model.PageCategory) wrouter.FunctionHandlerFunc {
}
}
// story.aiterp.net/Ruins_of_Rakhana
func init() {
ListController.Function("/", listIndex)

120
controllers/pagecontroller.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)
}

5
formparser/parsers.go

@ -3,6 +3,7 @@ package formparser
import (
"errors"
"fmt"
"log"
"time"
)
@ -24,12 +25,14 @@ func String(value string, target *string, min, max int) error {
func Select(value string, target *string, allowedValues []string, optional bool) error {
if value == "" {
if !optional {
return errors.New("not a valid option")
return errors.New("no option selected")
}
return nil
}
log.Println(value, allowedValues)
for _, allowedValue := range allowedValues {
if value == allowedValue {
*target = value

1
main.go

@ -9,6 +9,7 @@ func main() {
auth.Register(&controllers.WikiAthenticator{})
router.Mount("/user", &controllers.UserController)
router.Mount("/page", &controllers.PageController)
router.Mount("/", &controllers.ListController)
router.Static("/ui/", server.Main.Config.Directories.UI)

15
model/category.go

@ -9,6 +9,7 @@ type PageCategory struct {
Key string
Plural string
Icon string
Info string
}
// URLRoot is the "folder" used for searching within the category
@ -20,13 +21,13 @@ func (category *PageCategory) URLRoot() string {
// a limited selection of categories. I may move it to a configuration
// or the database, but for now I think this list is pretty fixed
var PageCategories = []PageCategory{
{"OoC", "OoC", "ooc"},
{"Info", "Info", "info"},
{"News", "News", "news"},
{"Item", "Items", "item"},
{"Document", "Documents", "document"},
{"Background", "Background", "background"},
{"Story", "Stories", "story"},
{"OoC", "OoC", "ooc", "OoC content is for announcements, scheduling, general information, or anything that is not in-universe"},
{"Info", "Info", "info", "Information gained during and between RP sessions"},
{"News", "News", "news", "News stories that might be pertinent to ongoing plots"},
{"Item", "Items", "item", "Items relevant to plots, that is more than just a document saved on a character's own omni-tool"},
{"Document", "Documents", "document", "Data files, shadow broker dossiers, and other data that is not inside an item"},
{"Background", "Background", "background", "Rumors, suspicious persons, or inter-RP occurences that may be noticed"},
{"Story", "Stories", "story", "Background stories and inter-RP character intearactions"},
}
var pageCategories []string

1
view/renderer.go

@ -79,4 +79,5 @@ func Run(w io.Writer, name string, viewModel interface{}) error {
func init() {
Register("index", "base/default")
Register("login", "base/default")
Register("create", "base/default")
}

50
view/templates/create.tmpl

@ -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">&lt;</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 }}

12
view/templates/login.tmpl

@ -3,8 +3,8 @@
<h1>Login</h1>
<form action="/user/login", method="POST">
<p class="red">{{$.Error}}</p>
<input placeholder="Username" name="username" type="text" />
<input placeholder="Password" name="password" type="password" />
<input placeholder="Username" name="username" type="text" value="{{$.UserName}}" {{if ne $.UserName ""}}autofocus{{end}} />
<input placeholder="Password" name="password" type="password" {{if $.UserName}}autofocus{{end}} />
<button type="submit">Submit</button>
</form>
</article>
@ -12,10 +12,12 @@
{{ define "menu" }}
<a href="/"><h1>Aite RP</h1></a>
<li><a href="/"><div class="mg-icon">&lt;</div><div class="mg-label">Back</div></a></li>
<ul>
<li><a href="/"><div class="mg-icon">&lt;</div><div class="mg-label">Back</div></a></li>
</ul>
{{ end }}
{{ define "head" }}
<link rel="stylesheet" href="/ui/css/form.css" />
{{ end }}

21
viewmodel/pageform.go

@ -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()
}

15
viewmodel/pageview.go

@ -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)
}
Loading…
Cancel
Save