summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/item.go71
-rw-r--r--management/editor/editor.go6
-rw-r--r--management/editor/elements.go2
-rw-r--r--management/manager/process.go72
-rw-r--r--system/admin/handlers.go12
-rw-r--r--system/db/content.go10
6 files changed, 81 insertions, 92 deletions
diff --git a/content/item.go b/content/item.go
index eb79aa0..9ccd420 100644
--- a/content/item.go
+++ b/content/item.go
@@ -3,8 +3,13 @@ package content
import (
"fmt"
"net/http"
+ "regexp"
+ "strings"
+ "unicode"
uuid "github.com/satori/go.uuid"
+ "golang.org/x/text/transform"
+ "golang.org/x/text/unicode/norm"
)
// Sluggable makes a struct locatable by URL with it's own path
@@ -27,6 +32,12 @@ type Identifiable interface {
String() string
}
+// Sortable ensures data is sortable by time
+type Sortable interface {
+ Time() int64
+ Touch() int64
+}
+
// Hookable provides our user with an easy way to intercept or add functionality
// to the different lifecycles/events a struct may encounter. Item implements
// Hookable with no-ops so our user can override only whichever ones necessary.
@@ -136,3 +147,63 @@ func (i Item) BeforeReject(req *http.Request) error {
func (i Item) AfterReject(req *http.Request) error {
return nil
}
+
+// Slug returns a URL friendly string from the title of a post item
+func Slug(i Identifiable) (string, error) {
+ // get the name of the post item
+ name := strings.TrimSpace(i.String())
+
+ // filter out non-alphanumeric character or non-whitespace
+ slug, err := stringToSlug(name)
+ if err != nil {
+ return "", err
+ }
+
+ return slug, nil
+}
+
+func isMn(r rune) bool {
+ return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
+}
+
+// modified version of: https://www.socketloop.com/tutorials/golang-format-strings-to-seo-friendly-url-example
+func stringToSlug(s string) (string, error) {
+ src := []byte(strings.ToLower(s))
+
+ // convert all spaces to dash
+ rx := regexp.MustCompile("[[:space:]]")
+ src = rx.ReplaceAll(src, []byte("-"))
+
+ // remove all blanks such as tab
+ rx = regexp.MustCompile("[[:blank:]]")
+ src = rx.ReplaceAll(src, []byte(""))
+
+ rx = regexp.MustCompile("[!/:-@[-`{-~]")
+ src = rx.ReplaceAll(src, []byte(""))
+
+ rx = regexp.MustCompile("/[^\x20-\x7F]/")
+ src = rx.ReplaceAll(src, []byte(""))
+
+ rx = regexp.MustCompile("`&(amp;)?#?[a-z0-9]+;`i")
+ src = rx.ReplaceAll(src, []byte("-"))
+
+ rx = regexp.MustCompile("`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);`i")
+ src = rx.ReplaceAll(src, []byte("\\1"))
+
+ rx = regexp.MustCompile("`[^a-z0-9]`i")
+ src = rx.ReplaceAll(src, []byte("-"))
+
+ rx = regexp.MustCompile("`[-]+`")
+ src = rx.ReplaceAll(src, []byte("-"))
+
+ str := strings.Replace(string(src), "'", "", -1)
+ str = strings.Replace(str, `"`, "", -1)
+
+ t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
+ slug, _, err := transform.String(t, str)
+ if err != nil {
+ return "", err
+ }
+
+ return strings.TrimSpace(slug), nil
+}
diff --git a/management/editor/editor.go b/management/editor/editor.go
index 6b55a38..7194c27 100644
--- a/management/editor/editor.go
+++ b/management/editor/editor.go
@@ -13,12 +13,6 @@ type Editable interface {
MarshalEditor() ([]byte, error)
}
-// Sortable ensures data is sortable by time
-type Sortable interface {
- Time() int64
- Touch() int64
-}
-
// Mergeable allows external post content to be approved and published through
// the public-facing API
type Mergeable interface {
diff --git a/management/editor/elements.go b/management/editor/elements.go
index 4a8ae55..bb2cb3f 100644
--- a/management/editor/elements.go
+++ b/management/editor/elements.go
@@ -242,8 +242,6 @@ func Select(fieldName string, p interface{}, attrs, options map[string]string) [
// find the field value in p to determine if an option is pre-selected
fieldVal := valueFromStructField(fieldName, p)
- // may need to alloc a buffer, as we will probably loop through options
- // and append the []byte from domElement() called for each option
attrs["class"] = "browser-default"
sel := newElement("select", attrs["label"], fieldName, p, attrs)
var opts []*element
diff --git a/management/manager/process.go b/management/manager/process.go
deleted file mode 100644
index ad6da94..0000000
--- a/management/manager/process.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package manager
-
-import (
- "regexp"
- "strings"
- "unicode"
-
- "github.com/bosssauce/ponzu/content"
-
- "golang.org/x/text/transform"
- "golang.org/x/text/unicode/norm"
-)
-
-// Slug returns a URL friendly string from the title of a post item
-func Slug(i content.Identifiable) (string, error) {
- // get the name of the post item
- name := strings.TrimSpace(i.String())
-
- // filter out non-alphanumeric character or non-whitespace
- slug, err := stringToSlug(name)
- if err != nil {
- return "", err
- }
-
- return slug, nil
-}
-
-func isMn(r rune) bool {
- return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
-}
-
-// modified version of: https://www.socketloop.com/tutorials/golang-format-strings-to-seo-friendly-url-example
-func stringToSlug(s string) (string, error) {
- src := []byte(strings.ToLower(s))
-
- // convert all spaces to dash
- rx := regexp.MustCompile("[[:space:]]")
- src = rx.ReplaceAll(src, []byte("-"))
-
- // remove all blanks such as tab
- rx = regexp.MustCompile("[[:blank:]]")
- src = rx.ReplaceAll(src, []byte(""))
-
- rx = regexp.MustCompile("[!/:-@[-`{-~]")
- src = rx.ReplaceAll(src, []byte(""))
-
- rx = regexp.MustCompile("/[^\x20-\x7F]/")
- src = rx.ReplaceAll(src, []byte(""))
-
- rx = regexp.MustCompile("`&(amp;)?#?[a-z0-9]+;`i")
- src = rx.ReplaceAll(src, []byte("-"))
-
- rx = regexp.MustCompile("`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);`i")
- src = rx.ReplaceAll(src, []byte("\\1"))
-
- rx = regexp.MustCompile("`[^a-z0-9]`i")
- src = rx.ReplaceAll(src, []byte("-"))
-
- rx = regexp.MustCompile("`[-]+`")
- src = rx.ReplaceAll(src, []byte("-"))
-
- str := strings.Replace(string(src), "'", "", -1)
- str = strings.Replace(str, `"`, "", -1)
-
- t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
- slug, _, err := transform.String(t, str)
- if err != nil {
- return "", err
- }
-
- return strings.TrimSpace(slug), nil
-}
diff --git a/system/admin/handlers.go b/system/admin/handlers.go
index 1e6a26c..fed77f7 100644
--- a/system/admin/handlers.go
+++ b/system/admin/handlers.go
@@ -1048,10 +1048,10 @@ func contentsHandler(res http.ResponseWriter, req *http.Request) {
// 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(e editor.Editable, typeName, status string) []byte {
- s, ok := e.(editor.Sortable)
+ s, ok := e.(content.Sortable)
if !ok {
- 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. (editor.Sortable)</li>`
+ log.Println("Content type", typeName, "doesn't implement content.Sortable")
+ post := `<li class="col s12">Error retreiving data. Your data type doesn't implement necessary interfaces. (content.Sortable)</li>`
return []byte(post)
}
@@ -1312,12 +1312,12 @@ func editHandler(res http.ResponseWriter, req *http.Request) {
return
}
} else {
- s, ok := post.(content.Identifiable)
+ item, ok := post.(content.Identifiable)
if !ok {
- log.Println("Content type", t, "doesn't implement editor.Identifiable")
+ log.Println("Content type", t, "doesn't implement content.Identifiable")
return
}
- s.SetItemID(-1)
+ item.SetItemID(-1)
}
m, err := manager.Manage(post.(editor.Editable), t)
diff --git a/system/db/content.go b/system/db/content.go
index 87b3e69..3293ff4 100644
--- a/system/db/content.go
+++ b/system/db/content.go
@@ -11,8 +11,6 @@ import (
"strings"
"github.com/bosssauce/ponzu/content"
- "github.com/bosssauce/ponzu/management/editor"
- "github.com/bosssauce/ponzu/management/manager"
"github.com/boltdb/bolt"
"github.com/gorilla/schema"
@@ -305,7 +303,7 @@ func Query(namespace string, opts QueryOptions) (int, [][]byte) {
// correct bad input rather than return nil or error
// similar to default case for opts.Order switch below
if opts.Count < 0 {
- opts.Count = 0
+ opts.Count = -1
}
if opts.Offset < 0 {
@@ -428,7 +426,7 @@ func SortContent(namespace string) {
return
}
- posts = append(posts, post.(editor.Sortable))
+ posts = append(posts, post.(content.Sortable))
}
// sort posts
@@ -469,7 +467,7 @@ func SortContent(namespace string) {
}
-type sortableContent []editor.Sortable
+type sortableContent []content.Sortable
func (s sortableContent) Len() int {
return len(s)
@@ -502,7 +500,7 @@ func postToJSON(ns string, data url.Values) ([]byte, error) {
// 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))
+ slug, err := content.Slug(post.(content.Identifiable))
if err != nil {
return nil, err
}