diff options
-rw-r--r-- | cmd/ponzu/options.go | 26 | ||||
-rw-r--r-- | content/item.go | 25 | ||||
-rw-r--r-- | content/post.go | 15 | ||||
-rw-r--r-- | management/editor/editor.go | 5 | ||||
-rw-r--r-- | management/manager/manager.go | 9 | ||||
-rw-r--r-- | system/admin/config/config.go | 9 | ||||
-rw-r--r-- | system/admin/handlers.go | 20 | ||||
-rw-r--r-- | system/db/content.go | 2 |
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) |