diff options
author | Steve Manuel <nilslice@gmail.com> | 2016-12-14 08:40:35 -0800 |
---|---|---|
committer | Steve Manuel <nilslice@gmail.com> | 2016-12-14 08:40:35 -0800 |
commit | 6808d3bf58e19e9230e7966798a70406f6d306e0 (patch) | |
tree | 5935a919b7f5f1710895a5f7609e908d491af345 | |
parent | 8e1269385b2ea6bb8a115030a4a6f4c12fa24868 (diff) |
adding __contentIndex to map item slug to semi foreign-key, and implementing add/delete features
-rw-r--r-- | content/item.go | 6 | ||||
-rw-r--r-- | management/manager/manager.go | 10 | ||||
-rw-r--r-- | system/admin/handlers.go | 9 | ||||
-rw-r--r-- | system/db/content.go | 78 | ||||
-rw-r--r-- | system/db/init.go | 2 |
5 files changed, 96 insertions, 9 deletions
diff --git a/content/item.go b/content/item.go index e6c8243..eb79aa0 100644 --- a/content/item.go +++ b/content/item.go @@ -13,6 +13,7 @@ import ( // and it will override the slug created by Item's SetSlug with your struct's type Sluggable interface { SetSlug(string) + ItemSlug() string } // Identifiable enables a struct to have its ID set/get. Typically this is done @@ -67,6 +68,11 @@ func (i *Item) SetSlug(slug string) { i.Slug = slug } +// ItemSlug sets the item's slug for its URL +func (i *Item) ItemSlug() string { + return i.Slug +} + // ItemID gets the Item's ID field // partially implements the Identifiable interface func (i Item) ItemID() int { diff --git a/management/manager/manager.go b/management/manager/manager.go index 6083f73..989eb98 100644 --- a/management/manager/manager.go +++ b/management/manager/manager.go @@ -16,6 +16,7 @@ const managerHTML = ` <input type="hidden" name="uuid" value="{{.UUID}}"/> <input type="hidden" name="id" value="{{.ID}}"/> <input type="hidden" name="type" value="{{.Kind}}"/> + <input type="hidden" name="slug" value="{{.Slug}}"/> {{ .Editor }} </form> <script> @@ -109,6 +110,7 @@ type manager struct { ID int UUID uuid.UUID Kind string + Slug string Editor template.HTML } @@ -121,13 +123,19 @@ func Manage(e editor.Editable, typeName string) ([]byte, error) { i, ok := e.(content.Identifiable) if !ok { - return nil, fmt.Errorf("Content type %s does not implement content.Sortable.", typeName) + return nil, fmt.Errorf("Content type %s does not implement content.Identifiable.", typeName) + } + + s, ok := e.(content.Sluggable) + if !ok { + return nil, fmt.Errorf("Content type %s does not implement content.Sluggable.", typeName) } m := manager{ ID: i.ItemID(), UUID: i.UniqueID(), Kind: typeName, + Slug: s.ItemSlug(), // TODO: just added this and its implementation -- need to rebuild & test Editor: template.HTML(v), } diff --git a/system/admin/handlers.go b/system/admin/handlers.go index c91db79..7fb1692 100644 --- a/system/admin/handlers.go +++ b/system/admin/handlers.go @@ -1150,6 +1150,7 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { dec.SetAliasTag("json") err = dec.Decode(post, req.Form) if err != nil { + log.Println("Error decoding post form for content approval:", t, err) res.WriteHeader(http.StatusInternalServerError) errView, err := Error500() if err != nil { @@ -1162,6 +1163,7 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { err = hook.BeforeApprove(req) if err != nil { + log.Println("Error running BeforeApprove hook in approveContentHandler for:", t, err) res.WriteHeader(http.StatusInternalServerError) errView, err := Error500() if err != nil { @@ -1175,6 +1177,7 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { // call its Approve method err = m.Approve(req) if err != nil { + log.Println("Error running Approve method in approveContentHandler for:", t, err) res.WriteHeader(http.StatusInternalServerError) errView, err := Error500() if err != nil { @@ -1187,6 +1190,7 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { err = hook.AfterApprove(req) if err != nil { + log.Println("Error running AfterApprove hook in approveContentHandler for:", t, err) res.WriteHeader(http.StatusInternalServerError) errView, err := Error500() if err != nil { @@ -1199,6 +1203,7 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { err = hook.BeforeSave(req) if err != nil { + log.Println("Error running BeforeSave hook in approveContentHandler for:", t, err) res.WriteHeader(http.StatusInternalServerError) errView, err := Error500() if err != nil { @@ -1212,6 +1217,7 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { // Store the content in the bucket t id, err := db.SetContent(t+":-1", req.Form) if err != nil { + log.Println("Error storing content in approveContentHandler for:", t, err) res.WriteHeader(http.StatusInternalServerError) errView, err := Error500() if err != nil { @@ -1224,6 +1230,7 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { err = hook.AfterSave(req) if err != nil { + log.Println("Error running AfterSave hook in approveContentHandler for:", t, err) res.WriteHeader(http.StatusInternalServerError) errView, err := Error500() if err != nil { @@ -1567,7 +1574,7 @@ func deleteHandler(res http.ResponseWriter, req *http.Request) { return } - err = db.DeleteContent(t + ":" + id) + err = db.DeleteContent(t+":"+id, req.Form) if err != nil { log.Println(err) res.WriteHeader(http.StatusInternalServerError) diff --git a/system/db/content.go b/system/db/content.go index 19c31d7..52fc8d5 100644 --- a/system/db/content.go +++ b/system/db/content.go @@ -118,6 +118,11 @@ func insert(ns string, data url.Values) (int, error) { uid := uuid.NewV4() data.Set("uuid", uid.String()) + // if type has a specifier, add it to data for downstream processing + if specifier != "" { + data.Set("__specifier", specifier) + } + j, err := postToJSON(ns, data) if err != nil { return err @@ -128,6 +133,17 @@ func insert(ns string, data url.Values) (int, error) { return err } + // store the slug,type:id in contentIndex if public content + if specifier == "" { + ci := tx.Bucket([]byte("__contentIndex")) + k := []byte(data.Get("slug")) + v := []byte(fmt.Sprintf("%s:%d", ns, effectedID)) + err := ci.Put(k, v) + if err != nil { + return err + } + } + return nil }) if err != nil { @@ -149,12 +165,25 @@ func insert(ns string, data url.Values) (int, error) { // DeleteContent removes an item from the database. Deleting a non-existent item // will return a nil error. -func DeleteContent(target string) error { +func DeleteContent(target string, data url.Values) error { t := strings.Split(target, ":") ns, id := t[0], t[1] err := store.Update(func(tx *bolt.Tx) error { - tx.Bucket([]byte(ns)).Delete([]byte(id)) + err := tx.Bucket([]byte(ns)).Delete([]byte(id)) + if err != nil { + return err + } + + // if content has a slug, also delete it from __contentIndex + slug := data.Get("slug") + if slug != "" { + err := tx.Bucket([]byte("__contentIndex")).Delete([]byte(slug)) + if err != nil { + return err + } + } + return nil }) if err != nil { @@ -435,11 +464,22 @@ func postToJSON(ns string, data url.Values) ([]byte, error) { return nil, err } - slug, err := manager.Slug(post.(content.Identifiable)) - if err != nil { - return nil, err + // if the content has no slug, and has no specifier, create a slug, check it + // for duplicates, and add it to our values + if data.Get("slug") == "" && data.Get("__specifier") == "" { + slug, err := manager.Slug(post.(content.Identifiable)) + if err != nil { + return nil, err + } + + slug, err = checkSlugForDuplicate(slug) + if err != nil { + return nil, err + } + + post.(content.Sluggable).SetSlug(slug) + data.Set("slug", slug) } - post.(content.Sluggable).SetSlug(slug) // marshall content struct to json for db storage j, err := json.Marshal(post) @@ -449,3 +489,29 @@ func postToJSON(ns string, data url.Values) ([]byte, error) { return j, nil } + +func checkSlugForDuplicate(slug string) (string, error) { + // check for existing slug in __contentIndex + err := store.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte("__contentIndex")) + exists := true + i := 0 + for exists { + s := b.Get([]byte(slug)) + if s == nil { + exists = false + return nil + } + + i++ + slug = fmt.Sprintf("%s-%d", slug, i) + } + + return nil + }) + if err != nil { + return "", err + } + + return slug, nil +} diff --git a/system/db/init.go b/system/db/init.go index 967eed1..df993e6 100644 --- a/system/db/init.go +++ b/system/db/init.go @@ -45,7 +45,7 @@ func Init() { } // init db with other buckets as needed - buckets := []string{"__config", "__users"} + buckets := []string{"__config", "__users", "__contentIndex"} for _, name := range buckets { _, err := tx.CreateBucketIfNotExists([]byte(name)) if err != nil { |