summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/ponzu/options.go26
-rw-r--r--content/item.go25
-rw-r--r--content/post.go15
-rw-r--r--management/editor/editor.go5
-rw-r--r--management/manager/manager.go9
-rw-r--r--system/admin/config/config.go9
-rw-r--r--system/admin/handlers.go20
-rw-r--r--system/db/content.go2
8 files changed, 58 insertions, 53 deletions
diff --git a/cmd/ponzu/options.go b/cmd/ponzu/options.go
index 062975b..244a759 100644
--- a/cmd/ponzu/options.go
+++ b/cmd/ponzu/options.go
@@ -80,13 +80,14 @@ type {{ .name }} struct {
Theme string ` + "`json:" + `"theme"` + "`" + `
}
-// MarshalEditor writes a buffer of html to edit a {{ .name }} and partially implements editor.Editable
+// MarshalEditor writes a buffer of html to edit a {{ .name }}
+// partially implements editor.Editable
func ({{ .initial }} *{{ .name }}) MarshalEditor() ([]byte, error) {
view, err := editor.Form({{ .initial }},
editor.Field{
- // Take careful note that the first argument to these Input-like methods
- // is the string version of each {{ .name }} struct tag, and must follow this pattern
- // for auto-decoding and -encoding reasons.
+ // Take note that the first argument to these Input-like methods
+ // is the string version of each {{ .name }} field, and must follow
+ // this pattern for auto-decoding and auto-encoding reasons.
View: editor.Input("Title", {{ .initial }}, map[string]string{
"label": "{{ .name }} Title",
"type": "text",
@@ -138,19 +139,12 @@ func init() {
Types["{{ .name }}"] = func() interface{} { return new({{ .name }}) }
}
-// SetContentID partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) SetContentID(id int) { {{ .initial }}.ID = id }
-
-// ContentID partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) ContentID() int { return {{ .initial }}.ID }
-
-// ContentName partially implements editor.Editable
+// ContentName is required to set the display name for a piece of content in the editor
+// Partially implements editor.Editable
func ({{ .initial }} *{{ .name }}) ContentName() string { return {{ .initial }}.Title }
-// SetSlug partially implements editor.Editable
-func ({{ .initial }} *{{ .name }}) SetSlug(slug string) { {{ .initial }}.Slug = slug }
-
-// Editor partially implements editor.Editable
+// Editor is a buffer of bytes for the Form function to write input views
+// partially implements editor.Editable
func ({{ .initial }} *{{ .name }}) Editor() *editor.Editor { return &{{ .initial }}.editor }
`
@@ -163,8 +157,6 @@ func newProjectInDir(path string) error {
// check if anything exists at the path, ask if it should be overwritten
if _, err := os.Stat(path); !os.IsNotExist(err) {
fmt.Println("Path exists, overwrite contents? (y/N):")
- // input := bufio.NewReader(os.Stdin)
- // answer, err := input.ReadString('\n')
var answer string
_, err := fmt.Scanf("%s\n", &answer)
diff --git a/content/item.go b/content/item.go
index f4a5489..0077dc6 100644
--- a/content/item.go
+++ b/content/item.go
@@ -18,7 +18,28 @@ func (i Item) Touch() int64 {
return i.Updated
}
-// ContentID partially implements the Sortable interface
-func (i Item) ContentID() int {
+// ItemID partially implements the Sortable interface
+func (i Item) ItemID() int {
return i.ID
}
+
+// SetSlug sets the item's slug for its URL
+func (i *Item) SetSlug(slug string) {
+ i.Slug = slug
+}
+
+// Sluggable makes a struct locatable by URL with it's own path
+// As an Item implementing Sluggable, slugs may overlap. If this is an issue,
+// make your content struct (or one which imbeds Item) implement Sluggable
+// and it will override the slug created by Item's SetSlug with your struct's
+type Sluggable interface {
+ SetSlug(string)
+}
+
+// Identifiable enables a struct to have its ID set. Typically this is done
+// to set an ID to -1 indicating it is new for DB inserts, since by default
+// a newly initialized struct would have an ID of 0, the int zero-value, and
+// BoltDB's starting key per bucket is 0, thus overwriting the first record.
+type Identifiable interface {
+ SetContentID(int)
+}
diff --git a/content/post.go b/content/post.go
index dcdfeff..b81bb5a 100644
--- a/content/post.go
+++ b/content/post.go
@@ -74,17 +74,10 @@ func init() {
Types["Post"] = func() interface{} { return new(Post) }
}
-// SetContentID partially implements editor.Editable
-func (p *Post) SetContentID(id int) { p.ID = id }
-
-// ContentID partially implements editor.Editable
-func (p *Post) ContentID() int { return p.ID }
-
-// ContentName partially implements editor.Editable
+// ContentName is required to set the display name for a piece of content in the editor
+// Partially implements editor.Editable
func (p *Post) ContentName() string { return p.Title }
-// SetSlug partially implements editor.Editable
-func (p *Post) SetSlug(slug string) { p.Slug = slug }
-
-// Editor partially implements editor.Editable
+// Editor is a buffer of bytes for the Form function to write input views
+// partially implements editor.Editable
func (p *Post) Editor() *editor.Editor { return &p.editor }
diff --git a/management/editor/editor.go b/management/editor/editor.go
index 2cfe1ea..f76197a 100644
--- a/management/editor/editor.go
+++ b/management/editor/editor.go
@@ -8,10 +8,7 @@ import (
// Editable ensures data is editable
type Editable interface {
- SetContentID(id int)
- ContentID() int
ContentName() string
- SetSlug(slug string)
Editor() *Editor
MarshalEditor() ([]byte, error)
}
@@ -20,7 +17,7 @@ type Editable interface {
type Sortable interface {
Time() int64
Touch() int64
- ContentID() int
+ ItemID() int
}
// Editor is a view containing fields to manage content
diff --git a/management/manager/manager.go b/management/manager/manager.go
index c0c5519..2830ba4 100644
--- a/management/manager/manager.go
+++ b/management/manager/manager.go
@@ -112,11 +112,16 @@ type manager struct {
func Manage(e editor.Editable, typeName string) ([]byte, error) {
v, err := e.MarshalEditor()
if err != nil {
- return nil, fmt.Errorf("Couldn't marshal editor for content %T. %s", e, err.Error())
+ return nil, fmt.Errorf("Couldn't marshal editor for content %s. %s", typeName, err.Error())
+ }
+
+ s, ok := e.(editor.Sortable)
+ if !ok {
+ return nil, fmt.Errorf("Content type %s does not implement content.Identifiable.", typeName)
}
m := manager{
- ID: e.ContentID(),
+ ID: s.ItemID(),
Kind: typeName,
Editor: template.HTML(v),
}
diff --git a/system/admin/config/config.go b/system/admin/config/config.go
index 66f767d..ba8ffb3 100644
--- a/system/admin/config/config.go
+++ b/system/admin/config/config.go
@@ -18,18 +18,9 @@ type Config struct {
CacheInvalidate []string `json:"-"`
}
-// SetContentID partially implements editor.Editable
-func (c *Config) SetContentID(id int) { c.ID = id }
-
-// ContentID partially implements editor.Editable
-func (c *Config) ContentID() int { return c.ID }
-
// ContentName partially implements editor.Editable
func (c *Config) ContentName() string { return c.Name }
-// SetSlug partially implements editor.Editable
-func (c *Config) SetSlug(slug string) { c.Slug = slug }
-
// Editor partially implements editor.Editable
func (c *Config) Editor() *editor.Editor { return &c.editor }
diff --git a/system/admin/handlers.go b/system/admin/handlers.go
index 12750e2..18faec9 100644
--- a/system/admin/handlers.go
+++ b/system/admin/handlers.go
@@ -752,10 +752,10 @@ func postsHandler(res http.ResponseWriter, req *http.Request) {
// adminPostListItem is a helper to create the li containing a post.
// p is the asserted post as an Editable, t is the Type of the post.
// specifier is passed to append a name to a namespace like _pending
-func adminPostListItem(p editor.Editable, t, status string) []byte {
- s, ok := p.(editor.Sortable)
+func adminPostListItem(e editor.Editable, typeName, status string) []byte {
+ s, ok := e.(editor.Sortable)
if !ok {
- log.Println("Content type", t, "doesn't implement editor.Sortable")
+ log.Println("Content type", typeName, "doesn't implement editor.Sortable")
post := `<li class="col s12">Error retreiving data. Your data type doesn't implement necessary interfaces.</li>`
return []byte(post)
}
@@ -766,7 +766,7 @@ func adminPostListItem(p editor.Editable, t, status string) []byte {
updatedTime := upTime.Format("01/02/06 03:04 PM")
publishTime := tsTime.Format("01/02/06")
- cid := fmt.Sprintf("%d", p.ContentID())
+ cid := fmt.Sprintf("%d", s.ItemID())
switch status {
case "public", "":
@@ -777,14 +777,14 @@ func adminPostListItem(p editor.Editable, t, status string) []byte {
post := `
<li class="col s12">
- <a href="/admin/edit?type=` + t + `&status=` + strings.TrimPrefix(status, "_") + `&id=` + cid + `">` + p.ContentName() + `</a>
+ <a href="/admin/edit?type=` + typeName + `&status=` + strings.TrimPrefix(status, "_") + `&id=` + cid + `">` + e.ContentName() + `</a>
<span class="post-detail">Updated: ` + updatedTime + `</span>
<span class="publish-date right">` + publishTime + `</span>
<form enctype="multipart/form-data" class="quick-delete-post __ponzu right" action="/admin/edit/delete" method="post">
<span>Delete</span>
<input type="hidden" name="id" value="` + cid + `" />
- <input type="hidden" name="type" value="` + t + status + `" />
+ <input type="hidden" name="type" value="` + typeName + status + `" />
</form>
</li>`
@@ -940,7 +940,13 @@ func editHandler(res http.ResponseWriter, req *http.Request) {
return
}
} else {
- post.(editor.Editable).SetContentID(-1)
+ s, ok := post.(content.Identifiable)
+ if !ok {
+ log.Println("Content type", typeName, "doesn't implement editor.Sortable")
+ return
+ }
+ s.SetContentID(-1)
+
}
m, err := manager.Manage(post.(editor.Editable), t)
diff --git a/system/db/content.go b/system/db/content.go
index cfbd4ef..b43d611 100644
--- a/system/db/content.go
+++ b/system/db/content.go
@@ -381,7 +381,7 @@ func postToJSON(ns string, data url.Values) ([]byte, error) {
if err != nil {
return nil, err
}
- post.(editor.Editable).SetSlug(slug)
+ post.(content.Sluggable).SetSlug(slug)
// marshall content struct to json for db storage
j, err := json.Marshal(post)