Massive overhaul, fixing menus and changing template engine. Added /month/ and /author/ filters
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/gisle/wrouter/response"
|
"git.aiterp.net/gisle/wrouter/response"
|
||||||
|
|
||||||
@@ -24,10 +25,10 @@ func listIndex(path string, w http.ResponseWriter, req *http.Request, user *auth
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := viewmodel.PageList{}
|
vm := viewmodel.IndexList{}
|
||||||
vm.Headers, err = model.ListHeaders()
|
vm.Headers, err = model.ListHeaders()
|
||||||
vm.Categories = model.PageCategories
|
vm.Categories = model.PageCategories
|
||||||
vm.Setup(user)
|
vm.Setup(user, req.URL.Path, "Index")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Text(w, 500, err.Error())
|
response.Text(w, 500, err.Error())
|
||||||
@@ -49,7 +50,7 @@ func listFiltered(category model.PageCategory) wrouter.FunctionHandlerFunc {
|
|||||||
|
|
||||||
tagName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
|
tagName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
|
||||||
|
|
||||||
vm := viewmodel.PageList{}
|
vm := viewmodel.IndexList{}
|
||||||
|
|
||||||
if tagName != "" {
|
if tagName != "" {
|
||||||
tag, err := model.FindTag("name", tagName, "")
|
tag, err := model.FindTag("name", tagName, "")
|
||||||
@@ -66,7 +67,7 @@ func listFiltered(category model.PageCategory) wrouter.FunctionHandlerFunc {
|
|||||||
|
|
||||||
vm.Categories = model.PageCategories
|
vm.Categories = model.PageCategories
|
||||||
vm.ActiveCategory = category
|
vm.ActiveCategory = category
|
||||||
vm.Setup(user)
|
vm.Setup(user, path, category.Plural)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Text(w, 500, err.Error())
|
response.Text(w, 500, err.Error())
|
||||||
@@ -89,7 +90,7 @@ func listTagged(tagType string) wrouter.FunctionHandlerFunc {
|
|||||||
|
|
||||||
tagName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
|
tagName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
|
||||||
|
|
||||||
vm := viewmodel.PageList{}
|
vm := viewmodel.IndexList{}
|
||||||
|
|
||||||
if tagName == "" {
|
if tagName == "" {
|
||||||
return false
|
return false
|
||||||
@@ -105,7 +106,7 @@ func listTagged(tagType string) wrouter.FunctionHandlerFunc {
|
|||||||
vm.Headers, err = model.ListHeadersByTag("", tag)
|
vm.Headers, err = model.ListHeadersByTag("", tag)
|
||||||
|
|
||||||
vm.Categories = model.PageCategories
|
vm.Categories = model.PageCategories
|
||||||
vm.Setup(user)
|
vm.Setup(user, tag.Path(), tag.Name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Text(w, 500, err.Error())
|
response.Text(w, 500, err.Error())
|
||||||
@@ -118,11 +119,90 @@ func listTagged(tagType string) wrouter.FunctionHandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tagList(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
|
||||||
|
//var err error
|
||||||
|
if (req.Method != "GET" && req.Method != "POST") || len(req.URL.Path) > len(path) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
tl := viewmodel.IndexTags{}
|
||||||
|
tl.Tags, _ = model.ListTags()
|
||||||
|
tl.Setup(user, path)
|
||||||
|
|
||||||
|
view.Render(w, "tags", 200, tl)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func listAuthor(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if req.Method != "GET" || strings.LastIndex(req.URL.Path, "/") >= len(path) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
authorName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
|
||||||
|
|
||||||
|
vm := viewmodel.IndexList{}
|
||||||
|
vm.ActiveAuthor = authorName
|
||||||
|
|
||||||
|
vm.Headers, err = model.ListHeadersByAuthor(authorName)
|
||||||
|
if err != nil {
|
||||||
|
response.Text(w, 500, err.Error())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vm.Headers) > 0 {
|
||||||
|
authorName = vm.Headers[0].Author
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.Categories = model.PageCategories
|
||||||
|
vm.Setup(user, "/author/"+authorName, authorName)
|
||||||
|
|
||||||
|
view.Render(w, "index", 200, vm)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func listDate(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if req.Method != "GET" || strings.LastIndex(req.URL.Path, "/") >= len(path) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
date, err := time.Parse("2006-01", req.URL.Path[len(path):])
|
||||||
|
if err != nil {
|
||||||
|
response.Text(w, 400, "Invalid date")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
vm := viewmodel.IndexList{}
|
||||||
|
vm.ActiveDate = date.Format("January 2006")
|
||||||
|
vm.ActiveDatePath = "/month/" + date.Format("2006-01")
|
||||||
|
|
||||||
|
vm.Headers, err = model.ListHeadersByMonth(date.Year(), int(date.Month()))
|
||||||
|
if err != nil {
|
||||||
|
response.Text(w, 500, err.Error())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.Categories = model.PageCategories
|
||||||
|
vm.Setup(user, "/month/"+date.Format("2006-01"), vm.ActiveDate)
|
||||||
|
|
||||||
|
view.Render(w, "index", 200, vm)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ListController.Function("/", listIndex)
|
ListController.Function("/", listIndex)
|
||||||
|
ListController.Function("/tags/", tagList)
|
||||||
|
ListController.Function("/author/", listAuthor)
|
||||||
|
ListController.Function("/month/", listDate)
|
||||||
|
|
||||||
for _, category := range model.PageCategories {
|
for _, category := range model.PageCategories {
|
||||||
ListController.Function(fmt.Sprintf("/%s/", strings.ToLower(category.Plural)), listFiltered(category))
|
ListController.Function(category.Path, listFiltered(category))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tagType := range model.TagTypes {
|
for _, tagType := range model.TagTypes {
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ func pageCreate(path string, w http.ResponseWriter, req *http.Request, user *aut
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pc := viewmodel.PageForm{}
|
pc := viewmodel.PageCreate{}
|
||||||
pc.Setup(user)
|
pc.Setup(user)
|
||||||
pc.Operation = "Create"
|
|
||||||
|
|
||||||
// Make sure the user is logged in
|
// Make sure the user is logged in
|
||||||
if user == nil {
|
if user == nil {
|
||||||
@@ -110,7 +109,7 @@ func pageCreate(path string, w http.ResponseWriter, req *http.Request, user *aut
|
|||||||
pc.TagInput = req.Form.Get("tags")
|
pc.TagInput = req.Form.Get("tags")
|
||||||
}
|
}
|
||||||
|
|
||||||
view.Render(w, "page/create", 200, pc)
|
view.Render(w, "create", 200, pc)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -137,6 +136,28 @@ func pageView(path string, w http.ResponseWriter, req *http.Request, user *auth.
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pageSource(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.PageSource{}
|
||||||
|
pv.Page = page
|
||||||
|
pv.Setup(user)
|
||||||
|
|
||||||
|
view.Render(w, "page/source", 200, pv)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
|
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) {
|
if (req.Method != "GET" && req.Method != "POST") || strings.LastIndex(req.URL.Path, "/") > len(path) {
|
||||||
return false
|
return false
|
||||||
@@ -150,12 +171,12 @@ func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *aut
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pv := viewmodel.PageView{}
|
pv := viewmodel.PageDelete{}
|
||||||
pv.Page = page
|
pv.Page = page
|
||||||
pv.Setup(user)
|
pv.Setup(user)
|
||||||
|
|
||||||
if user == nil || user.FullID() != page.Author {
|
if user == nil || user.FullID() != page.Author {
|
||||||
view.Render(w, "message/error-access", http.StatusForbidden, path)
|
view.Render(w, "message", http.StatusForbidden, viewmodel.NewMessage(user, "Access Denied", true, "You are not allowed to delete this page."))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +185,7 @@ func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *aut
|
|||||||
|
|
||||||
// Catch sneaky shenanigans
|
// Catch sneaky shenanigans
|
||||||
if req.Form.Get("aft") != user.Session.ID {
|
if req.Form.Get("aft") != user.Session.ID {
|
||||||
view.Render(w, "message/error-forgery", http.StatusForbidden, path)
|
view.Render(w, "message", http.StatusForbidden, viewmodel.NewMessage(user, "Forgery Detected", true, "The server thinks something nasty is afoot. Try again if it is your page, and prod me on IRC if it still doesn't work."))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,12 +193,12 @@ func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *aut
|
|||||||
err := page.Delete()
|
err := page.Delete()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// It wasn't done D:
|
// It wasn't done D:
|
||||||
view.Render(w, "message/error-internal", http.StatusInternalServerError, err)
|
view.Render(w, "message", http.StatusInternalServerError, viewmodel.NewMessage(user, "Internal Server Error", true, err.Error()))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// It has been done
|
// It has been done
|
||||||
view.Render(w, "message/page-deleted", 200, pv)
|
view.Render(w, "message", 200, viewmodel.NewMessage(user, "Deletion Successful", false, "The page has been deleted."))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,12 +219,10 @@ func pageEdit(path string, w http.ResponseWriter, req *http.Request, user *auth.
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pf := viewmodel.PageForm{}
|
pf := viewmodel.PageEdit{}
|
||||||
|
pf.Page = page
|
||||||
pf.Setup(user)
|
pf.Setup(user)
|
||||||
|
|
||||||
pf.Operation = "Edit"
|
|
||||||
pf.Page = *page
|
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
pf.Error = "You are not logged in"
|
pf.Error = "You are not logged in"
|
||||||
}
|
}
|
||||||
@@ -285,5 +304,6 @@ func init() {
|
|||||||
PageController.Function("/create", pageCreate)
|
PageController.Function("/create", pageCreate)
|
||||||
PageController.Function("/edit/", pageEdit)
|
PageController.Function("/edit/", pageEdit)
|
||||||
PageController.Function("/delete/", pageDelete)
|
PageController.Function("/delete/", pageDelete)
|
||||||
|
PageController.Function("/source/", pageSource)
|
||||||
PageController.Function("/", pageView)
|
PageController.Function("/", pageView)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"git.aiterp.net/AiteRP/aitestory/view"
|
|
||||||
"git.aiterp.net/AiteRP/aitestory/viewmodel"
|
|
||||||
|
|
||||||
"git.aiterp.net/AiteRP/aitestory/model"
|
|
||||||
"git.aiterp.net/gisle/wrouter"
|
|
||||||
"git.aiterp.net/gisle/wrouter/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TagController serves and handles the tag managment pages
|
|
||||||
var TagController = wrouter.Router{}
|
|
||||||
|
|
||||||
func tagList(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
|
|
||||||
//var err error
|
|
||||||
if (req.Method != "GET" && req.Method != "POST") || len(req.URL.Path) > len(path) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
tl := viewmodel.TagList{}
|
|
||||||
tl.Tags, _ = model.ListTags()
|
|
||||||
tl.Setup(user)
|
|
||||||
|
|
||||||
view.Render(w, "tags/list", 200, tl)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
TagController.Function("/", tagList)
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.aiterp.net/AiteRP/aitestory/server"
|
import (
|
||||||
import "git.aiterp.net/AiteRP/aitestory/controllers"
|
"net/http"
|
||||||
import "git.aiterp.net/gisle/wrouter/auth"
|
|
||||||
|
"git.aiterp.net/AiteRP/aitestory/controllers"
|
||||||
|
"git.aiterp.net/AiteRP/aitestory/server"
|
||||||
|
"git.aiterp.net/AiteRP/aitestory/view"
|
||||||
|
"git.aiterp.net/AiteRP/aitestory/viewmodel"
|
||||||
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
router := &server.Main.Router
|
router := &server.Main.Router
|
||||||
@@ -10,10 +16,15 @@ func main() {
|
|||||||
auth.Register(&controllers.WikiAthenticator{})
|
auth.Register(&controllers.WikiAthenticator{})
|
||||||
router.Mount("/user", &controllers.UserController)
|
router.Mount("/user", &controllers.UserController)
|
||||||
router.Mount("/page", &controllers.PageController)
|
router.Mount("/page", &controllers.PageController)
|
||||||
router.Mount("/tags", &controllers.TagController)
|
|
||||||
router.Mount("/", &controllers.ListController)
|
router.Mount("/", &controllers.ListController)
|
||||||
|
|
||||||
router.Static("/ui/", server.Main.Config.Directories.UI)
|
router.Static("/ui/", server.Main.Config.Directories.UI)
|
||||||
|
|
||||||
|
router.Function("/", func(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
|
||||||
|
view.Render(w, "message", http.StatusNotFound, viewmodel.NewMessage(user, "404: "+req.URL.Path, true, "The server don't know what to do with that address."))
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
server.Main.Start()
|
server.Main.Start()
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -9,6 +9,7 @@ type PageCategory struct {
|
|||||||
Key string
|
Key string
|
||||||
Plural string
|
Plural string
|
||||||
Icon string
|
Icon string
|
||||||
|
Path string
|
||||||
Info string
|
Info string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,12 +23,12 @@ func (category *PageCategory) URLRoot() string {
|
|||||||
// or the database, but for now I think this list is pretty fixed
|
// or the database, but for now I think this list is pretty fixed
|
||||||
var PageCategories = []PageCategory{
|
var PageCategories = []PageCategory{
|
||||||
//{"OoC", "OoC", "O", "OoC content is for announcements, scheduling, general information, or anything that is not in-universe"},
|
//{"OoC", "OoC", "O", "OoC content is for announcements, scheduling, general information, or anything that is not in-universe"},
|
||||||
{"Info", "Info", "i", "Information relevant to RP that might be something looked for in IRC logs"},
|
{"Info", "Info", "i", "/info/", "Information relevant to RP that might be something looked for in IRC logs"},
|
||||||
{"News", "News", "N", "News stories that might be pertinent to ongoing plots"},
|
{"News", "News", "N", "/news/", "News stories that might be pertinent to ongoing plots"},
|
||||||
//{"Item", "Items", "I", "Items relevant to plots, that is more than just a document saved on a character's own omni-tool"},
|
//{"Item", "Items", "I", "Items relevant to plots, that is more than just a document saved on a character's own omni-tool"},
|
||||||
{"Document", "Documents", "D", "Data files, shadow broker dossiers, and other data that is not inside an item"},
|
{"Document", "Documents", "D", "/documents/", "Data files, shadow broker dossiers, and other data that is not inside an item"},
|
||||||
{"Background", "Background", "B", "Rumors, suspicious persons, or inter-RP occurences that may be noticed"},
|
{"Background", "Background", "B", "/background/", "Rumors, suspicious persons, or inter-RP occurences that may be noticed"},
|
||||||
{"Story", "Stories", "S", "Background stories and inter-RP character intearactions"},
|
{"Story", "Stories", "S", "/stories/", "Background stories and inter-RP character intearactions"},
|
||||||
}
|
}
|
||||||
var pageCategories []string
|
var pageCategories []string
|
||||||
|
|
||||||
|
|||||||
+73
-1
@@ -3,6 +3,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/AiteRP/aitestory/server"
|
"git.aiterp.net/AiteRP/aitestory/server"
|
||||||
@@ -34,7 +35,12 @@ func (header *Header) CategoryInfo() PageCategory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PageCategory{"Unknown", "Unknown", "?", ""}
|
return PageCategory{"Unknown", "Unknown", "?", "/", ""}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path returns the path for viewing the page
|
||||||
|
func (header *Header) Path() string {
|
||||||
|
return fmt.Sprintf("/page/%s", header.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListHeaders grabs all the general pages from
|
// ListHeaders grabs all the general pages from
|
||||||
@@ -104,6 +110,72 @@ func ListHeadersByCategory(category string) ([]Header, error) {
|
|||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListHeadersByAuthor grabs all the pages by the given author
|
||||||
|
func ListHeadersByAuthor(author string) ([]Header, error) {
|
||||||
|
const query = `
|
||||||
|
SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
|
||||||
|
FROM page
|
||||||
|
LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
|
||||||
|
LEFT JOIN tag ON (tag.id = page_tag.tag_id)
|
||||||
|
WHERE page.specific=false AND page.published=true AND page.unlisted=false AND page.author = ?
|
||||||
|
ORDER BY page.publish_date DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
db := server.Main.DB
|
||||||
|
|
||||||
|
rows, err := db.Query(query, author)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
results := make([]Header, 0, 64)
|
||||||
|
header := Header{}
|
||||||
|
for rows.Next() {
|
||||||
|
err := parseHeader(&header, rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListHeadersByMonth grabs all the pages within the given month
|
||||||
|
func ListHeadersByMonth(year int, month int) ([]Header, error) {
|
||||||
|
const query = `
|
||||||
|
SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
|
||||||
|
FROM page
|
||||||
|
LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
|
||||||
|
LEFT JOIN tag ON (tag.id = page_tag.tag_id)
|
||||||
|
WHERE page.specific=false AND page.published=true AND page.unlisted=false AND YEAR(fictional_date) = ? AND MONTH(fictional_date) = ?
|
||||||
|
ORDER BY page.publish_date DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
db := server.Main.DB
|
||||||
|
|
||||||
|
rows, err := db.Query(query, year, month)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
results := make([]Header, 0, 64)
|
||||||
|
header := Header{}
|
||||||
|
for rows.Next() {
|
||||||
|
err := parseHeader(&header, rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ListHeadersByTag lists all headers that has the tag. Leave the category empty
|
// ListHeadersByTag lists all headers that has the tag. Leave the category empty
|
||||||
// to not filter by it
|
// to not filter by it
|
||||||
func ListHeadersByTag(category string, tag *Tag) ([]Header, error) {
|
func ListHeadersByTag(category string, tag *Tag) ([]Header, error) {
|
||||||
|
|||||||
+6
-1
@@ -139,7 +139,7 @@ func (page *Page) Update() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop now if the tages haven't changed
|
// Stop now if the tages haven't changed
|
||||||
if len(page.prevTags) == len(page.Tags) {
|
if len(page.Tags) > 0 && len(page.prevTags) == len(page.Tags) {
|
||||||
change := false
|
change := false
|
||||||
|
|
||||||
for i, tag := range page.prevTags {
|
for i, tag := range page.prevTags {
|
||||||
@@ -265,6 +265,11 @@ func (page *Page) ParseForm(form url.Values) []error {
|
|||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpPath gets a path associated with a specific operation on this page.
|
||||||
|
func (page *Page) OpPath(op string) string {
|
||||||
|
return fmt.Sprintf("/page/%s/%s", op, page.ID)
|
||||||
|
}
|
||||||
|
|
||||||
// Standardize page ID generation
|
// Standardize page ID generation
|
||||||
func (page *Page) generateID() {
|
func (page *Page) generateID() {
|
||||||
page.ID = generate.FriendlyID(16)
|
page.ID = generate.FriendlyID(16)
|
||||||
|
|||||||
+17
-4
@@ -18,6 +18,15 @@ var TagTypes = []string{
|
|||||||
"Series",
|
"Series",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TagTitles are the titles to use when listing tags
|
||||||
|
var TagTitles = map[string]string{
|
||||||
|
"Location": "Locations",
|
||||||
|
"Character": "Characters",
|
||||||
|
"Event": "Plots & Events",
|
||||||
|
"Organization": "Organizations",
|
||||||
|
"Series": "Series",
|
||||||
|
}
|
||||||
|
|
||||||
// Tag describes a tag
|
// Tag describes a tag
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
ID string
|
ID string
|
||||||
@@ -121,10 +130,14 @@ func (tag *Tag) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook returns the url friendly name, which is pretty much just
|
// Path returns a path used for the tag's list page
|
||||||
// adding underscores to it.
|
func (tag Tag) Path() string {
|
||||||
func (tag Tag) Hook() string {
|
return fmt.Sprintf("/%s/%s", strings.ToLower(tag.Type), strings.Replace(tag.Name, " ", "_", -1))
|
||||||
return strings.Replace(tag.Name, " ", "_", -1)
|
}
|
||||||
|
|
||||||
|
// CSSClass gets the tag's css class, which determines its color.
|
||||||
|
func (tag Tag) CSSClass() string {
|
||||||
|
return fmt.Sprintf("ttype-%s", strings.ToLower(tag.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindTag finds a tag by ID. Leave tagtype blank to ignore it. Both key and
|
// FindTag finds a tag by ID. Leave tagtype blank to ignore it. Both key and
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
doctype 5
|
||||||
|
|
||||||
|
import mixins
|
||||||
|
|
||||||
|
html
|
||||||
|
head
|
||||||
|
block meta
|
||||||
|
meta[name="description"][content="This is a great website"]
|
||||||
|
meta[charset="UTF-8"]
|
||||||
|
meta[name="viewport"][content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=no"]
|
||||||
|
meta[name="theme-color"][content="#112233"]
|
||||||
|
meta[http-equiv="Content-Type"][content="text/html; charset=utf-8"]
|
||||||
|
|
||||||
|
block css
|
||||||
|
link[rel="stylesheet"][href="/ui/css/base.css"]
|
||||||
|
link[rel="stylesheet"][href="/ui/css/magic.css"]
|
||||||
|
link[rel="stylesheet"][href="/ui/css/theme.css"]
|
||||||
|
link[rel="stylesheet"][media="screen"][href="/ui/fonts/source-sans-pro/source-sans-pro.css"][type="text/css"]
|
||||||
|
|
||||||
|
block js
|
||||||
|
script[type="text/javascript"][src="/ui/js/background.js"]
|
||||||
|
|
||||||
|
title #{ViewTitle}
|
||||||
|
body
|
||||||
|
if ViewBackground != ""
|
||||||
|
img[id="main-background"][src="/ui/img/bg.png"]
|
||||||
|
else
|
||||||
|
img[id="main-background"][src="/ui/img/bg.png"]
|
||||||
|
|
||||||
|
div.content-wrapper
|
||||||
|
nav
|
||||||
|
block menu
|
||||||
|
if User.LoggedIn
|
||||||
|
ul
|
||||||
|
+menuitem("/user/logout", "U", "Logout")
|
||||||
|
else
|
||||||
|
ul
|
||||||
|
+menuitem("/user/login", "U", "Login")
|
||||||
|
|
||||||
|
if ViewPath != "/"
|
||||||
|
+menuitem("/", "<", "Back")
|
||||||
|
|
||||||
|
main
|
||||||
|
block main
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
$root = $
|
||||||
|
|
||||||
|
mixin menuitem($path, $icon, $text)
|
||||||
|
li
|
||||||
|
.selected ? $root.ViewPath == $path
|
||||||
|
a[href=$path]
|
||||||
|
div.mg-icon #{$icon}
|
||||||
|
div.mg-label #{$text}
|
||||||
|
|
||||||
|
mixin tagmenuitem($tag)
|
||||||
|
li
|
||||||
|
[class=$tag.CSSClass]
|
||||||
|
a[href=$tag.Path]
|
||||||
|
div.mg-icon #{$tag.Icon}
|
||||||
|
div.mg-label #{$tag.Name}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mixin formoption($name, $selected, $label, $info)
|
||||||
|
div.radio-wrapper
|
||||||
|
$id = printf("checkbox-%s", $name)
|
||||||
|
|
||||||
|
if $selected
|
||||||
|
input[id=$id][type="checkbox"][name=$name][value="true"][checked]
|
||||||
|
else
|
||||||
|
input[id=$id][type="checkbox"][name=$name][value="true"]
|
||||||
|
|
||||||
|
label[for="checkbox-unlisted"]
|
||||||
|
b #{$label}:
|
||||||
|
spamn #{$info}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
extends base/master
|
||||||
|
|
||||||
|
block append css
|
||||||
|
link[rel="stylesheet"][href="/ui/css/form.css"]
|
||||||
|
|
||||||
|
block append js
|
||||||
|
script[type="text/javascript"][src="/ui/js/form-page.js"]
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
$page = $.Page
|
||||||
|
|
||||||
|
article
|
||||||
|
h1 Create
|
||||||
|
form[action="/page/create"][method="POST"]
|
||||||
|
p.danger #{$.Error}
|
||||||
|
|
||||||
|
input.big
|
||||||
|
[placeholder="Page Name"]
|
||||||
|
[value=$page.Name]
|
||||||
|
[type="text"]
|
||||||
|
[name="name"]
|
||||||
|
textarea.tall
|
||||||
|
[placeholder="Content"]
|
||||||
|
[name="source"]
|
||||||
|
| #{$page.Source}
|
||||||
|
input
|
||||||
|
[placeholder="IC Date (e.g. 'Oct 27, 2185')"]
|
||||||
|
[name="fictionalDate"]
|
||||||
|
[type="text"]
|
||||||
|
[value=$page.FictionalDate] ? !$page.FictionalDate.IsZero
|
||||||
|
|
||||||
|
h2 Category
|
||||||
|
div.group[title="Category"]
|
||||||
|
each $category in $.Categories
|
||||||
|
div.radio-wrapper
|
||||||
|
$radioid = printf("radio-%s", $category.Key)
|
||||||
|
if $category.Key == $page.Category
|
||||||
|
input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key][checked]
|
||||||
|
else
|
||||||
|
input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key]
|
||||||
|
label[for=$radioid]
|
||||||
|
b #{$category.Key}:
|
||||||
|
span #{$category.Info}
|
||||||
|
|
||||||
|
h2 Tags
|
||||||
|
textarea
|
||||||
|
[name="tags"]
|
||||||
|
[placeholder="Location: Miner's Respite\nOrganization: Redrock Agency\nCharacter: Renala T'Iavay\nEvent: Skipping Work\nSeries: Just Another Tuesday"]
|
||||||
|
| #{$.TagInput}
|
||||||
|
|
||||||
|
h2 Options
|
||||||
|
div.group
|
||||||
|
+formoption("unlisted", $page.Unlisted, "Unlisted", "The page will not show up in any page list. Meant for omni-tool messages, quick copypastes and so on.")
|
||||||
|
+formoption("indexed", $page.Unlisted, "Indexable", "Third-party search engines (that play by the rules) are permitted to crawl this page.")
|
||||||
|
|
||||||
|
// Future options (maybe)
|
||||||
|
input[type="hidden"][name="type"][value="Markdown"]
|
||||||
|
input[type="hidden"][name="published"][value="True"]
|
||||||
|
|
||||||
|
button[type="submit"] Create
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
extends base/master
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
article
|
||||||
|
table.page-list
|
||||||
|
tbody
|
||||||
|
each $header in Headers
|
||||||
|
tr
|
||||||
|
td.pl-icon #{$header.CategoryInfo.Icon}
|
||||||
|
td.pl-content
|
||||||
|
div.plc-title
|
||||||
|
a[href=$header.Path] #{$header.Name}
|
||||||
|
div.plc-meta
|
||||||
|
div.plcm-date #{formatDate($header.PublishDate)}
|
||||||
|
if $header.Dated
|
||||||
|
div.plcm-date #{formatDate($header.FictionalDate)}
|
||||||
|
if $header.PrimaryTag
|
||||||
|
div.plcm-tag[class=$header.PrimaryTag.CSSCLass] #{$header.PrimaryTag.Name}
|
||||||
|
div.plcm-author #{formatUserID($header.Author)}
|
||||||
|
tr.spacer
|
||||||
|
td
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import base/mixins
|
||||||
|
|
||||||
|
$authorPath = printf("/author/%s", ActiveAuthor)
|
||||||
|
|
||||||
|
a[href="/"]
|
||||||
|
h1 Aite RP
|
||||||
|
|
||||||
|
ul
|
||||||
|
if User.LoggedIn
|
||||||
|
+menuitem("/page/create", "+", "Create")
|
||||||
|
|
||||||
|
ul
|
||||||
|
each $category in Categories
|
||||||
|
+menuitem($category.Path, $category.Icon, $category.Plural)
|
||||||
|
|
||||||
|
ul
|
||||||
|
if ActiveTag.ID
|
||||||
|
+menuitem(ActiveTag.Path, ActiveTag.Icon, ActiveTag.Name)
|
||||||
|
if ActiveDate
|
||||||
|
+menuitem(ActiveDatePath, "D", ActiveDate)
|
||||||
|
if ActiveAuthor
|
||||||
|
+menuitem($authorPath, "A", formatUserID(ActiveAuthor))
|
||||||
|
|
||||||
|
ul
|
||||||
|
+menuitem("/tags/", "T", "Tags")
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
extends base/master
|
||||||
|
|
||||||
|
block menu
|
||||||
|
a[href="/"]
|
||||||
|
h1 Aite RP
|
||||||
|
|
||||||
|
block main
|
||||||
|
article
|
||||||
|
h1
|
||||||
|
.danger ? $.Danger
|
||||||
|
| #{$.Title}
|
||||||
|
p #{$.Text}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
extends ../base/master
|
||||||
|
|
||||||
|
block append css
|
||||||
|
link[rel="stylesheet"][href="/ui/css/form.css"]
|
||||||
|
|
||||||
|
block append js
|
||||||
|
script[type="text/javascript"][src="/ui/js/form-page.js"]
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
$page = $.Page
|
||||||
|
|
||||||
|
article
|
||||||
|
h1.danger Delete
|
||||||
|
form[action=$page.OpPath("delete")][method="POST"]
|
||||||
|
p.danger This is irreversible, so make sure you are deleting the right page.
|
||||||
|
|
||||||
|
ul
|
||||||
|
li <b>ID:</b> #{$.Page.ID}
|
||||||
|
li <b>Name:</b> #{$.Page.Name}
|
||||||
|
li <b>Category:</b> #{$.Page.Category}
|
||||||
|
li <b>Published:</b> #{formatDateLong($.Page.PublishDate)}
|
||||||
|
ul
|
||||||
|
|
||||||
|
input[type="hidden"][name="aft"][value=$.User.SessionID]
|
||||||
|
|
||||||
|
|
||||||
|
button[type="submit"] Delete
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
extends ../base/master
|
||||||
|
|
||||||
|
|
||||||
|
block append css
|
||||||
|
link[rel="stylesheet"][href="/ui/css/form.css"]
|
||||||
|
|
||||||
|
block append js
|
||||||
|
script[type="text/javascript"][src="/ui/js/form-page.js"]
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
$page = $.Page
|
||||||
|
|
||||||
|
article
|
||||||
|
h1 Create
|
||||||
|
form[action=$page.OpPath("edit")][method="POST"]
|
||||||
|
p.danger #{$.Error}
|
||||||
|
|
||||||
|
input.big
|
||||||
|
[placeholder="Page Name"]
|
||||||
|
[value=$page.Name]
|
||||||
|
[type="text"]
|
||||||
|
[name="name"]
|
||||||
|
textarea.tall
|
||||||
|
[placeholder="Content"]
|
||||||
|
[name="source"]
|
||||||
|
| #{$page.Source}
|
||||||
|
input
|
||||||
|
[placeholder="IC Date (e.g. 'Oct 27, 2185')"]
|
||||||
|
[name="fictionalDate"]
|
||||||
|
[type="text"]
|
||||||
|
[value=$page.FictionalDate] ? !$page.FictionalDate.IsZero
|
||||||
|
|
||||||
|
h2 Category
|
||||||
|
div.group[title="Category"]
|
||||||
|
each $category in $.Categories
|
||||||
|
div.radio-wrapper
|
||||||
|
$radioid = printf("radio-%s", $category.Key)
|
||||||
|
if $category.Key == $page.Category
|
||||||
|
input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key][checked]
|
||||||
|
else
|
||||||
|
input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key]
|
||||||
|
label[for=$radioid]
|
||||||
|
b #{$category.Key}:
|
||||||
|
span #{$category.Info}
|
||||||
|
|
||||||
|
h2 Tags
|
||||||
|
textarea
|
||||||
|
[name="tags"]
|
||||||
|
[placeholder="Location: Miner's Respite\nOrganization: Redrock Agency\nCharacter: Renala T'Iavay\nEvent: Skipping Work\nSeries: Just Another Tuesday"]
|
||||||
|
| #{$.TagInput}
|
||||||
|
|
||||||
|
h2 Options
|
||||||
|
div.group
|
||||||
|
+formoption("unlisted", $page.Unlisted, "Unlisted", "The page will not show up in any page list. Meant for omni-tool messages, quick copypastes and so on.")
|
||||||
|
+formoption("indexed", $page.Indexed, "Indexable", "Third-party search engines (that play by the rules) are permitted to crawl this page.")
|
||||||
|
|
||||||
|
// Future options (maybe)
|
||||||
|
input[type="hidden"][name="type"][value="Markdown"]
|
||||||
|
input[type="hidden"][name="published"][value="True"]
|
||||||
|
|
||||||
|
button[type="submit"] Edit
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import ../base/mixins
|
||||||
|
|
||||||
|
$pagePath = printf("/page/%s", $.Page.ID)
|
||||||
|
$pageEditPath = printf("/page/edit/%s", $.Page.ID)
|
||||||
|
$pageDeletePath = printf("/page/delete/%s", $.Page.ID)
|
||||||
|
$pageSourcePath = printf("/page/source/%s", $.Page.ID)
|
||||||
|
$datePath = printf("/month/%s", $.Page.FictionalDate.UTC.Format("2006-01"))
|
||||||
|
$authorPath = printf("/author/%s", $.Page.Author)
|
||||||
|
|
||||||
|
a[href="/"]
|
||||||
|
h1 Page
|
||||||
|
|
||||||
|
if !$.HideMenu
|
||||||
|
ul
|
||||||
|
+menuitem($pagePath, "V", "View")
|
||||||
|
if $.Page.Author == $.User.ID
|
||||||
|
+menuitem($pageEditPath, "E", "Edit")
|
||||||
|
+menuitem($pageDeletePath, "X", "Delete")
|
||||||
|
else
|
||||||
|
+menuitem($pageSourcePath, "#", "Source")
|
||||||
|
|
||||||
|
ul
|
||||||
|
each $tag in $.Page.Tags
|
||||||
|
+tagmenuitem($tag)
|
||||||
|
|
||||||
|
ul
|
||||||
|
if $.Page.Dated
|
||||||
|
+menuitem($datePath, "D", formatDate($.Page.FictionalDate))
|
||||||
|
+menuitem($authorPath, "A", formatUserID($.Page.Author))
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
extends ../base/master
|
||||||
|
|
||||||
|
block append meta
|
||||||
|
if !$.Page.Indexed
|
||||||
|
meta[name="robots"][content="noindex"]
|
||||||
|
meta[name="googlebot"][content="noindex"]
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
article
|
||||||
|
code.block
|
||||||
|
#{$.Page.Source}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
extends ../base/master
|
||||||
|
|
||||||
|
block append meta
|
||||||
|
if !$.Page.Indexed
|
||||||
|
meta[name="robots"][content="noindex"]
|
||||||
|
meta[name="googlebot"][content="noindex"]
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
article.narrow
|
||||||
|
#{$.Page.Content}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
extends base/master
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
article
|
||||||
|
h1 All Tags
|
||||||
|
div.tag-list
|
||||||
|
each $key, $tags in $.Map
|
||||||
|
if $tags
|
||||||
|
div.tl-item
|
||||||
|
h2 #{$key}
|
||||||
|
ul
|
||||||
|
each $tag in $tags
|
||||||
|
li
|
||||||
|
a[class=$tag.CSSClass][href=$tag.Path] #{$tag.Name}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
extends ../base/master
|
||||||
|
|
||||||
|
block append css
|
||||||
|
link[rel="stylesheet"][href="/ui/css/form.css"]
|
||||||
|
|
||||||
|
block menu
|
||||||
|
import menu
|
||||||
|
|
||||||
|
block main
|
||||||
|
article
|
||||||
|
h1 Login
|
||||||
|
form[action="/user/login"][method="POST"]
|
||||||
|
p Use your wiki.aiterp.net account.
|
||||||
|
p.danger #{$.Error}
|
||||||
|
input
|
||||||
|
[placeholder="Username"]
|
||||||
|
[name="username"]
|
||||||
|
[type="text"]
|
||||||
|
[value=$.UserName]
|
||||||
|
[autofocus] ? $.UserName == ""
|
||||||
|
input
|
||||||
|
[placeholder="Password"]
|
||||||
|
[name="password"]
|
||||||
|
[type="password"]
|
||||||
|
[autofocus] ? $.UserName != ""
|
||||||
|
button[type="submit"] Login
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import ../base/mixins
|
||||||
|
|
||||||
|
a[href="/"]
|
||||||
|
h1 User
|
||||||
+42
-39
@@ -2,12 +2,14 @@ package view
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
|
"github.com/eknkc/amber"
|
||||||
|
|
||||||
"git.aiterp.net/AiteRP/aitestory/server"
|
"git.aiterp.net/AiteRP/aitestory/server"
|
||||||
"git.aiterp.net/gisle/wrouter/response"
|
"git.aiterp.net/gisle/wrouter/response"
|
||||||
@@ -17,52 +19,33 @@ var wd, _ = os.Getwd()
|
|||||||
var cache = make(map[string]*template.Template)
|
var cache = make(map[string]*template.Template)
|
||||||
var argsCache = make(map[string][]string)
|
var argsCache = make(map[string][]string)
|
||||||
|
|
||||||
// Register registers a template and compiles it for rendering. This should be done
|
var defaultOptions = amber.Options{PrettyPrint: true}
|
||||||
// in the beginning since an error will terminate the server
|
var defaultDirOptions = amber.DirOptions{Ext: ".amber", Recursive: true}
|
||||||
func Register(name string, base string, fragments ...string) {
|
|
||||||
rootPath := server.Main.Config.Directories.Templates
|
|
||||||
|
|
||||||
for i, fragment := range fragments {
|
|
||||||
fragments[i] = path.Join(rootPath, fragment+".tmpl")
|
|
||||||
}
|
|
||||||
|
|
||||||
args := append([]string{path.Join(rootPath, name+".tmpl"), path.Join(rootPath, base+".tmpl")}, fragments...)
|
|
||||||
tmpl, err := template.New(name).Funcs(funcMap).ParseFiles(args...)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to register %s: %s", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
argsCache[name] = args
|
|
||||||
cache[name] = tmpl
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render renders a template with the name it was registered with, and with the
|
// Render renders a template with the name it was registered with, and with the
|
||||||
// view model. The view model is expected to be the correct model from the viewmodel
|
// view model. The view model is expected to be the correct model from the viewmodel
|
||||||
// package
|
// package
|
||||||
func Render(w http.ResponseWriter, name string, status int, viewModel interface{}) {
|
func Render(w http.ResponseWriter, name string, status int, viewModel interface{}) {
|
||||||
var tmpl *template.Template
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if server.Main.Config.Server.Debug {
|
if server.Main.Config.Server.Debug {
|
||||||
tmpl, err = template.New(name).Funcs(funcMap).ParseFiles(argsCache[name]...)
|
cache, err = amber.CompileDir(server.Main.Config.Directories.Templates, defaultDirOptions, defaultOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Text(w, 500, "Failed to run template "+name+": "+err.Error())
|
log.Println(err)
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
tmpl, ok = cache[name]
|
|
||||||
if !ok {
|
|
||||||
response.Text(w, 500, "Template not found: "+name)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmpl, ok := cache[name]
|
||||||
|
if !ok {
|
||||||
|
response.Text(w, 500, "Template not found: "+name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
err = tmpl.ExecuteTemplate(w, "base", viewModel)
|
err = tmpl.Execute(w, viewModel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Template error:", err.Error())
|
log.Println("Template error:", err.Error())
|
||||||
|
response.Text(w, 500, "Template error: "+err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +60,31 @@ func Run(w io.Writer, name string, viewModel interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Register("index", "base/default")
|
var err error
|
||||||
Register("user/login", "base/default")
|
|
||||||
Register("page/create", "base/default")
|
for key, value := range funcMap {
|
||||||
Register("page/edit", "base/default")
|
if _, exists := amber.FuncMap[key]; exists {
|
||||||
Register("page/view", "base/default")
|
log.Printf("Amber already provides a function by the name: %s", key)
|
||||||
Register("page/delete", "base/default")
|
}
|
||||||
Register("tags/list", "base/default")
|
|
||||||
|
amber.FuncMap[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
cache, err = amber.CompileDir(server.Main.Config.Directories.Templates, defaultDirOptions, defaultOptions)
|
||||||
|
if err != nil {
|
||||||
|
if server.Main.Config.Server.Debug {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if server.Main.Config.Server.Debug {
|
||||||
|
fmt.Printf("Template directory: %s\n", server.Main.Config.Directories.Templates)
|
||||||
|
|
||||||
|
for key := range cache {
|
||||||
|
fmt.Printf("Template loaded: %s\n", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
{{define "base"}}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<!-- For preview and template creation only -->
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>{{ .ViewTitle }}</title>
|
|
||||||
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=no" />
|
|
||||||
<meta name="theme-color" content="#222222">
|
|
||||||
<meta name="robots" content="noindex">
|
|
||||||
<meta name="googlebot" content="noindex">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/ui/css/base.css" />
|
|
||||||
<link rel="stylesheet" href="/ui/css/magic.css" />
|
|
||||||
<link rel="stylesheet" href="/ui/css/theme.css" />
|
|
||||||
|
|
||||||
<link rel="stylesheet" media="screen" href="/ui/fonts/source-sans-pro/source-sans-pro.css" type="text/css"/>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="/ui/js/background.js"></script>
|
|
||||||
|
|
||||||
{{ block "head" . }}{{end}}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<img id="main-background" src="/ui/img/bg.png" />
|
|
||||||
|
|
||||||
<div id="content-wrapper">
|
|
||||||
<main>
|
|
||||||
{{ block "content" . }}{{end}}
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="main-menu">
|
|
||||||
{{ block "menu" . }}{{end}}
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
{{end}}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
{{ define "content" }}
|
|
||||||
<article>
|
|
||||||
<table class="page-list">
|
|
||||||
{{ range .Headers }}
|
|
||||||
<tbody>
|
|
||||||
<tr class="">
|
|
||||||
<td class="pl-icon">{{.CategoryInfo.Icon}}</td>
|
|
||||||
<td class="pl-content">
|
|
||||||
<div class="plc-title"><a href="/page/{{.ID}}">{{.Name}}</a></div>
|
|
||||||
<div class="plc-meta">
|
|
||||||
<div class="plcm-date">{{.PublishDate | formatDate}}</div>
|
|
||||||
{{ if .Dated }}
|
|
||||||
<div class="plcm-date">{{.FictionalDate | formatDate}}</div>
|
|
||||||
{{ end }}
|
|
||||||
{{ if .PrimaryTag }}
|
|
||||||
<div class="plcm-tag {{.PrimaryTag.CSSCLass}}">{{.PrimaryTag.Name}}</div>
|
|
||||||
{{ end }}
|
|
||||||
<div class="plcm-author">{{.Author | formatUserID}}</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="spacer"><td></td></tr>
|
|
||||||
{{ end }}
|
|
||||||
</table>
|
|
||||||
</article>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "menu" }}
|
|
||||||
<a href="/"><h1>Aite RP</h1></a>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
{{ range .Categories }}
|
|
||||||
<li class="{{ if eq .Key $.ActiveCategory.Key }}selected{{end}}"><a href="/{{.Plural}}/"><div class="mg-icon">{{.Icon}}</div><div class="mg-label">{{.Plural}}</div></a></li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{ if $.ActiveTag.ID }}
|
|
||||||
<ul>
|
|
||||||
<li class="selected"><a href="/{{$.ActiveTag.Type}}/{{$.ActiveTag.Hook}}"><div class="mg-icon">{{$.ActiveTag.Icon}}</div><div class="mg-label">{{$.ActiveTag.Name}}</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="/tags/"><div class="mg-icon">T</div><div class="mg-label">Tags</div></a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{ if $.User.LoggedIn }}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/page/create"><div class="mg-icon">+</div><div class="mg-label">Create</div></a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="/user/logout"><div class="mg-icon">A</div><div class="mg-label">Logout</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ else }}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/user/login"><div class="mg-icon">A</div><div class="mg-label">Login</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "head" }}
|
|
||||||
|
|
||||||
{{ end }}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{{ define "content" }}
|
|
||||||
<article>
|
|
||||||
<h1>{{$.Operation}}</h1>
|
|
||||||
<form action="/page/create", method="POST">
|
|
||||||
<p class="danger">{{$.Error}}</p>
|
|
||||||
<input class="big" placeholder="Page Name" name="name" type="text" value="{{$.Page.Name}}" />
|
|
||||||
<textarea class="tall" placeholder="Content" name="source">{{$.Page.Source}}</textarea>
|
|
||||||
<input placeholder="IC Date (e.g. 'Oct 27, 2185')" name="fictionalDate" type="text" value="{{if $.Page.FictionalDate.IsZero}}{{else}}{{$.Page.FictionalDate}}{{end}}" />
|
|
||||||
<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">{{$.TagInput}}</textarea>
|
|
||||||
<div class="group">
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- Future option -->
|
|
||||||
<input type="hidden" name="type" value="Markdown" />
|
|
||||||
<input type="hidden" name="published" value="True" />
|
|
||||||
|
|
||||||
<button type="submit">{{$.Operation}}</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 }}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{{ define "content" }}
|
|
||||||
<article class="narrow">
|
|
||||||
<h1 class="danger">Delete Page</h1>
|
|
||||||
<form action="/page/delete/{{$.Page.ID}}", method="POST">
|
|
||||||
<p class="danger">
|
|
||||||
This is an irreversible action, so make sure that this is the correct page!
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li><b>ID:</b> {{$.Page.ID}}</li>
|
|
||||||
<li><b>Name:</b> {{$.Page.Name}}</li>
|
|
||||||
<li><b>Category:</b> {{$.Page.Category}}</li>
|
|
||||||
<li><b>Published:</b> {{$.Page.PublishDate | formatDateLong}}</li>
|
|
||||||
</ul>
|
|
||||||
<input type="hidden" name="aft" value="{{$.User.SessionID}}" />
|
|
||||||
|
|
||||||
<button type="submit">Delete Page</button>
|
|
||||||
</article>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "menu" }}
|
|
||||||
<a href="/"><h1>Page</h1></a>
|
|
||||||
|
|
||||||
{{ if eq $.User.ID $.Page.Author}}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/page/edit/{{$.Page.ID}}"><div class="mg-icon">E</div><div class="mg-label">Edit</div></a></li>
|
|
||||||
<li class="selected"><a href="/page/delete/{{$.Page.ID}}"><div class="mg-icon">X</div><div class="mg-label">Delete</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="/page/{{$.Page.ID}}"><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" />
|
|
||||||
{{ end }}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{{ define "content" }}
|
|
||||||
<article>
|
|
||||||
<h1>{{$.Operation}}</h1>
|
|
||||||
<form action="/page/edit/{{$.Page.ID}}", method="POST">
|
|
||||||
<p class="danger">{{$.Error}}</p>
|
|
||||||
<input class="big" placeholder="Page Name" name="name" type="text" value="{{$.Page.Name}}" />
|
|
||||||
<textarea class="tall" placeholder="Content" name="source">{{$.Page.Source}}</textarea>
|
|
||||||
<input placeholder="IC Date (e.g. 'Oct 27, 2185')" name="fictionalDate" type="text" value="{{if $.Page.FictionalDate.IsZero}}{{else}}{{$.Page.FictionalDate}}{{end}}" />
|
|
||||||
<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">{{$.TagInput}}</textarea>
|
|
||||||
<div class="group">
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- Future option -->
|
|
||||||
<input type="hidden" name="type" value="Markdown" />
|
|
||||||
<input type="hidden" name="published" value="True" />
|
|
||||||
|
|
||||||
<button type="submit">{{$.Operation}}</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 }}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{{ define "content" }}
|
|
||||||
<article class="narrow">
|
|
||||||
{{$.Page.Content}}
|
|
||||||
</article>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "menu" }}
|
|
||||||
<a href="/"><h1>Page</h1></a>
|
|
||||||
{{ if $.Page.Dated}}
|
|
||||||
<div class="page-property">{{$.Page.FictionalDate | formatDate}}</div>
|
|
||||||
{{ else }}
|
|
||||||
<div class="page-property">{{$.Page.PublishDate | formatDate}}</div>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
{{ range $.Page.Tags }}
|
|
||||||
<li><a href="/{{.Type}}/{{.Hook}}"><div class="mg-icon">{{.Icon}}</div><div class="mg-label {{.CSSCLass}}">{{.Name}}</div></a></li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{ if eq $.User.ID $.Page.Author}}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/page/edit/{{$.Page.ID}}"><div class="mg-icon">E</div><div class="mg-label">Edit</div></a></li>
|
|
||||||
<li><a href="/page/delete/{{$.Page.ID}}"><div class="mg-icon">X</div><div class="mg-label">Delete</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="/"><div class="mg-icon"><</div><div class="mg-label">Back</div></a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{ if $.User.LoggedIn }}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/user/logout"><div class="mg-icon">A</div><div class="mg-label">Logout</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ else }}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/user/login"><div class="mg-icon">A</div><div class="mg-label">Login</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "head" }}
|
|
||||||
{{ end }}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{{ define "content" }}
|
|
||||||
<article>
|
|
||||||
<h1>All Tags</h1>
|
|
||||||
|
|
||||||
<div class="tag-list">
|
|
||||||
{{ range $tagHeader, $tags := .Map }}
|
|
||||||
<div class="tl-item">
|
|
||||||
<h2>{{ $tagHeader }}</h2>
|
|
||||||
<ul>
|
|
||||||
{{ range $tags }}
|
|
||||||
<li><a class="ttype-{{.Type | tolower }}" href="/{{.Type}}/{{.Name}}">{{ .Name }}</a></li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</article>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "menu" }}
|
|
||||||
<a href="/"><h1>Tags</h1></a>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="/"><div class="mg-icon"><</div><div class="mg-label">Back</div></a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{ if $.User.LoggedIn }}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/page/create"><div class="mg-icon">+</div><div class="mg-label">Create</div></a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="/user/logout"><div class="mg-icon">A</div><div class="mg-label">Logout</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ else }}
|
|
||||||
<ul>
|
|
||||||
<li><a href="/user/login"><div class="mg-icon">A</div><div class="mg-label">Login</div></a></li>
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "head" }}
|
|
||||||
|
|
||||||
{{ end }}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{{ define "content" }}
|
|
||||||
<article>
|
|
||||||
<h1>Login</h1>
|
|
||||||
<form action="/user/login", method="POST">
|
|
||||||
<p>Use your wiki.aiterp.net account.</p>
|
|
||||||
<p class="danger">{{$.Error}}</p>
|
|
||||||
<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>
|
|
||||||
{{ 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" />
|
|
||||||
{{ end }}
|
|
||||||
+7
-2
@@ -16,11 +16,14 @@ type Base struct {
|
|||||||
LoggedIn bool
|
LoggedIn bool
|
||||||
SessionID string
|
SessionID string
|
||||||
}
|
}
|
||||||
ViewTitle string
|
ViewBackground string
|
||||||
|
ViewPath string
|
||||||
|
ViewTitle string
|
||||||
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitBase initializes the base of the viewmodel
|
// InitBase initializes the base of the viewmodel
|
||||||
func (base *Base) setupBase(user *auth.User, viewTitle string) {
|
func (base *Base) setupBase(user *auth.User, viewTitle string, viewPath string) {
|
||||||
if user != nil {
|
if user != nil {
|
||||||
base.User.ID = user.FullID()
|
base.User.ID = user.FullID()
|
||||||
base.User.Name = user.ID
|
base.User.Name = user.ID
|
||||||
@@ -29,5 +32,7 @@ func (base *Base) setupBase(user *auth.User, viewTitle string) {
|
|||||||
base.User.SessionID = user.Session.ID
|
base.User.SessionID = user.Session.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.ViewPath = viewPath
|
||||||
|
|
||||||
base.ViewTitle = fmt.Sprintf("%s - %s", viewTitle, server.Main.Config.View.Title)
|
base.ViewTitle = fmt.Sprintf("%s - %s", viewTitle, server.Main.Config.View.Title)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package viewmodel
|
||||||
|
|
||||||
|
import "git.aiterp.net/AiteRP/aitestory/model"
|
||||||
|
|
||||||
|
// IndexBase is used for the index menu.
|
||||||
|
type IndexBase struct {
|
||||||
|
Categories []model.PageCategory
|
||||||
|
ActiveTag model.Tag
|
||||||
|
ActiveAuthor string
|
||||||
|
ActiveDate string
|
||||||
|
ActiveDatePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im *IndexBase) setupMenu() {
|
||||||
|
im.Categories = model.PageCategories
|
||||||
|
}
|
||||||
@@ -5,18 +5,18 @@ import (
|
|||||||
"git.aiterp.net/gisle/wrouter/auth"
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PageList is a view model for rendering the front page
|
// IndexList is a view model for rendering the front page
|
||||||
type PageList struct {
|
type IndexList struct {
|
||||||
Base
|
Base
|
||||||
|
IndexBase
|
||||||
Headers []model.Header
|
Headers []model.Header
|
||||||
ActiveCategory model.PageCategory
|
ActiveCategory model.PageCategory
|
||||||
Categories []model.PageCategory
|
|
||||||
ActiveTag model.Tag
|
|
||||||
FavoriteTags []model.Tag
|
FavoriteTags []model.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup sets up the page model and the base, and should
|
// Setup sets up the page model and the base, and should
|
||||||
// be run after the details have been filled in.
|
// be run after the details have been filled in.
|
||||||
func (pl *PageList) Setup(user *auth.User) {
|
func (il *IndexList) Setup(user *auth.User, viewPath string, viewTitle string) {
|
||||||
pl.setupBase(user, "Index")
|
il.setupMenu()
|
||||||
|
il.setupBase(user, viewTitle, viewPath)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package viewmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.aiterp.net/AiteRP/aitestory/model"
|
||||||
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IndexTags is a view model for rendering the tag lists.
|
||||||
|
type IndexTags struct {
|
||||||
|
Base
|
||||||
|
IndexBase
|
||||||
|
|
||||||
|
Type string
|
||||||
|
Tags []model.Tag
|
||||||
|
TagCategories []string
|
||||||
|
|
||||||
|
tagMap map[string][]model.Tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map lazy-loads the map of tags, which is only
|
||||||
|
// used when listing all of them.
|
||||||
|
func (it IndexTags) Map() map[string][]model.Tag {
|
||||||
|
// Set up the map
|
||||||
|
it.tagMap = make(map[string][]model.Tag, len(model.TagTypes))
|
||||||
|
for _, tagType := range model.TagTypes {
|
||||||
|
it.tagMap[tagType] = make([]model.Tag, 0, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Organize
|
||||||
|
for _, tag := range it.Tags {
|
||||||
|
it.tagMap[tag.Type] = append(it.tagMap[tag.Type], tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return it.tagMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup sets up the page model and the base, and should
|
||||||
|
// be run after the details have been filled in.
|
||||||
|
func (it *IndexTags) Setup(user *auth.User, viewPath string) {
|
||||||
|
title := it.Type
|
||||||
|
if it.Type != "" {
|
||||||
|
title = "All"
|
||||||
|
}
|
||||||
|
|
||||||
|
it.setupMenu()
|
||||||
|
it.setupBase(user, fmt.Sprintf("%s Tags", title), viewPath)
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package viewmodel
|
||||||
|
|
||||||
|
import "git.aiterp.net/gisle/wrouter/auth"
|
||||||
|
|
||||||
|
// Message is a simple viewmodel for the message pages
|
||||||
|
type Message struct {
|
||||||
|
Base
|
||||||
|
Title string
|
||||||
|
Text string
|
||||||
|
Danger bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMessage creates a message model
|
||||||
|
func NewMessage(user *auth.User, title string, danger bool, text string) *Message {
|
||||||
|
msg := &Message{Title: title, Text: text, Danger: danger}
|
||||||
|
msg.setupBase(user, title, "")
|
||||||
|
|
||||||
|
return msg
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package viewmodel
|
||||||
|
|
||||||
|
import "git.aiterp.net/AiteRP/aitestory/model"
|
||||||
|
|
||||||
|
// PageBase describes the basic parts of a page.
|
||||||
|
type PageBase struct {
|
||||||
|
Page *model.Page
|
||||||
|
HideMenu bool
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package viewmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.aiterp.net/AiteRP/aitestory/model"
|
||||||
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PageCreate is the view model for the page create form.
|
||||||
|
type PageCreate struct {
|
||||||
|
Base
|
||||||
|
IndexBase
|
||||||
|
|
||||||
|
Page model.Page
|
||||||
|
Error string
|
||||||
|
TagInput string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup sets the view model up.
|
||||||
|
func (pf *PageCreate) Setup(user *auth.User) {
|
||||||
|
pf.setupMenu()
|
||||||
|
pf.setupBase(user, "Create", "/page/create")
|
||||||
|
|
||||||
|
pf.Categories = model.PageCategories
|
||||||
|
|
||||||
|
pf.Page.Defaults()
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package viewmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PageDelete is the view model used to view the page's delete form.
|
||||||
|
type PageDelete struct {
|
||||||
|
Base
|
||||||
|
PageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup sets up the page view model. It should be calles last
|
||||||
|
func (pv *PageDelete) Setup(user *auth.User) {
|
||||||
|
pv.HideMenu = false
|
||||||
|
pv.setupBase(user, pv.Page.Name, fmt.Sprintf("/page/delete/%s", pv.Page.ID))
|
||||||
|
}
|
||||||
@@ -5,17 +5,19 @@ import (
|
|||||||
"git.aiterp.net/gisle/wrouter/auth"
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PageForm struct {
|
// PageEdit is the view model for the page edit form.
|
||||||
|
type PageEdit struct {
|
||||||
Base
|
Base
|
||||||
Page model.Page
|
PageBase
|
||||||
|
|
||||||
Categories []model.PageCategory
|
Categories []model.PageCategory
|
||||||
Operation string
|
|
||||||
Error string
|
Error string
|
||||||
TagInput string
|
TagInput string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pf *PageForm) Setup(user *auth.User) {
|
// Setup sets the view model up.
|
||||||
pf.setupBase(user, "Create")
|
func (pf *PageEdit) Setup(user *auth.User) {
|
||||||
|
pf.setupBase(user, "Edit", "/page/edit/"+pf.Page.ID)
|
||||||
|
|
||||||
pf.Categories = model.PageCategories
|
pf.Categories = model.PageCategories
|
||||||
pf.Page.Defaults()
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package viewmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PageSource is the view model used to view the page's source.
|
||||||
|
// It's got no extra data on its own.
|
||||||
|
type PageSource struct {
|
||||||
|
Base
|
||||||
|
PageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup sets up the page view model. It should be calles last
|
||||||
|
func (pv *PageSource) Setup(user *auth.User) {
|
||||||
|
pv.HideMenu = false
|
||||||
|
pv.setupBase(user, pv.Page.Name, fmt.Sprintf("/page/source/%s", pv.Page.ID))
|
||||||
|
}
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
package viewmodel
|
package viewmodel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.aiterp.net/AiteRP/aitestory/model"
|
"fmt"
|
||||||
|
|
||||||
"git.aiterp.net/gisle/wrouter/auth"
|
"git.aiterp.net/gisle/wrouter/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PageView is the view model used to view the page. It's got no extra
|
||||||
|
// data on its own.
|
||||||
type PageView struct {
|
type PageView struct {
|
||||||
Base
|
Base
|
||||||
Page *model.Page
|
PageBase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup sets up the page view model. It should be calles last
|
||||||
func (pv *PageView) Setup(user *auth.User) {
|
func (pv *PageView) Setup(user *auth.User) {
|
||||||
pv.setupBase(user, pv.Page.Name)
|
pv.HideMenu = false
|
||||||
|
pv.setupBase(user, pv.Page.Name, fmt.Sprintf("/page/%s", pv.Page.ID))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package viewmodel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.aiterp.net/AiteRP/aitestory/model"
|
|
||||||
"git.aiterp.net/gisle/wrouter/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TagList is a view model for rendering the tag lists.
|
|
||||||
type TagList struct {
|
|
||||||
Base
|
|
||||||
Type string
|
|
||||||
Tags []model.Tag
|
|
||||||
TagCategories []string
|
|
||||||
|
|
||||||
tagMap map[string][]model.Tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map lazy-loads the map of tags, which is only
|
|
||||||
// used when listing all of them.
|
|
||||||
func (tl TagList) Map() map[string][]model.Tag {
|
|
||||||
// Set up the map
|
|
||||||
tl.tagMap = make(map[string][]model.Tag, len(model.TagTypes))
|
|
||||||
for _, tagType := range model.TagTypes {
|
|
||||||
tl.tagMap[tagType] = make([]model.Tag, 0, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Organize
|
|
||||||
for _, tag := range tl.Tags {
|
|
||||||
tl.tagMap[tag.Type] = append(tl.tagMap[tag.Type], tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
return tl.tagMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup sets up the page model and the base, and should
|
|
||||||
// be run after the details have been filled in.
|
|
||||||
func (tl *TagList) Setup(user *auth.User) {
|
|
||||||
title := tl.Type
|
|
||||||
if tl.Type != "" {
|
|
||||||
title = "All"
|
|
||||||
}
|
|
||||||
|
|
||||||
tl.setupBase(user, fmt.Sprintf("%s Tags", title))
|
|
||||||
}
|
|
||||||
@@ -15,5 +15,5 @@ type UserLogin struct {
|
|||||||
// Setup sets up the page model and the base, and should
|
// Setup sets up the page model and the base, and should
|
||||||
// be run after the details have been filled in.
|
// be run after the details have been filled in.
|
||||||
func (ul *UserLogin) Setup(user *auth.User) {
|
func (ul *UserLogin) Setup(user *auth.User) {
|
||||||
ul.setupBase(user, "Login")
|
ul.setupBase(user, "Login", "/user/login")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user