diff options
Diffstat (limited to 'system')
-rw-r--r-- | system/addon/addon.go | 47 | ||||
-rw-r--r-- | system/addon/manager.go | 34 | ||||
-rw-r--r-- | system/admin/handlers.go | 13 | ||||
-rw-r--r-- | system/db/addon.go | 53 |
4 files changed, 100 insertions, 47 deletions
diff --git a/system/addon/addon.go b/system/addon/addon.go index a423d07..833ce23 100644 --- a/system/addon/addon.go +++ b/system/addon/addon.go @@ -8,6 +8,7 @@ import ( "github.com/ponzu-cms/ponzu/system/db" "github.com/ponzu-cms/ponzu/system/item" + "github.com/tidwall/sjson" ) var ( @@ -65,8 +66,7 @@ func Register(m Meta, fn func() interface{}) Addon { // register sets up the system to use the Addon by: // 1. Validating the Addon struct -// 2. Checking that the Addon parent type was added to Types (via its New()) -// 3. Saving it to the __addons bucket in DB with id/key = addon_reverse_dns +// 2. Saving it to the __addons bucket in DB with id/key = addon_reverse_dns func register(a Addon) error { if a.PonzuAddonName == "" { return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonName") @@ -118,7 +118,12 @@ func register(a Addon) error { // db.SetAddon is like SetContent, but rather than the key being an int64 ID, // we need it to be a string based on the addon_reverse_dns - err = db.SetAddon(vals) + kind, ok := Types[a.PonzuAddonReverseDNS] + if !ok { + return fmt.Errorf("Error: no addon to set with id: %s", a.PonzuAddonReverseDNS) + } + + err = db.SetAddon(vals, kind()) if err != nil { return err } @@ -163,9 +168,41 @@ func setStatus(key, status string) error { return err } - a.Set("addon_status", status) + a, err = sjson.SetBytes(a, "addon_status", status) + if err != nil { + return err + } + + kind, ok := Types[key] + if !ok { + return fmt.Errorf("Error: no addon to set with id: %s", key) + } + + // convert json => map[string]interface{} => url.Values + var kv map[string]interface{} + err = json.Unmarshal(a, kv) + if err != nil { + return err + } + + var vals url.Values + for k, v := range kv { + switch v.(type) { + case []string: + s := v.([]string) + for i := range s { + if i == 0 { + vals.Set(k, s[i]) + } + + vals.Add(k, s[i]) + } + default: + vals.Set(k, fmt.Sprintf("%v", v)) + } + } - err = db.SetAddon(a) + err = db.SetAddon(vals, kind()) if err != nil { return err } diff --git a/system/addon/manager.go b/system/addon/manager.go index acd779a..eb8b44c 100644 --- a/system/addon/manager.go +++ b/system/addon/manager.go @@ -2,12 +2,14 @@ package addon import ( "bytes" + "encoding/json" "fmt" "html/template" "net/url" "github.com/gorilla/schema" "github.com/ponzu-cms/ponzu/management/editor" + "github.com/tidwall/gjson" ) const defaultInput = `<input type="hidden" name="%s" value="%s"/>` @@ -31,18 +33,42 @@ type manager struct { } // Manage ... -func Manage(data url.Values, reverseDNS string) ([]byte, error) { +func Manage(data []byte, reverseDNS string) ([]byte, error) { a, ok := Types[reverseDNS] if !ok { return nil, fmt.Errorf("Addon has not been added to addon.Types map") } + // convert json => map[string]interface{} => url.Values + var kv map[string]interface{} + err := json.Unmarshal(data, kv) + if err != nil { + return nil, err + } + + var vals url.Values + for k, v := range kv { + switch v.(type) { + case []string: + s := v.([]string) + for i := range s { + if i == 0 { + vals.Set(k, s[i]) + } + + vals.Add(k, s[i]) + } + default: + vals.Set(k, fmt.Sprintf("%v", v)) + } + } + at := a() dec := schema.NewDecoder() dec.IgnoreUnknownKeys(true) dec.SetAliasTag("json") - err := dec.Decode(at, data) + err = dec.Decode(at, vals) if err != nil { return nil, err } @@ -68,7 +94,7 @@ func Manage(data url.Values, reverseDNS string) ([]byte, error) { } for _, f := range fields { - input := fmt.Sprintf(defaultInput, f, data.Get(f)) + input := fmt.Sprintf(defaultInput, f, gjson.GetBytes(data, f).String()) _, err := inputs.WriteString(input) if err != nil { return nil, fmt.Errorf("Failed to write input for addon view: %s", f) @@ -78,7 +104,7 @@ func Manage(data url.Values, reverseDNS string) ([]byte, error) { m := manager{ DefaultInputs: template.HTML(inputs.Bytes()), Editor: template.HTML(v), - AddonName: data.Get("addon_name"), + AddonName: gjson.GetBytes(data, "addon_name").String(), } // execute html template into buffer for func return val diff --git a/system/admin/handlers.go b/system/admin/handlers.go index 71f88c2..02d9d92 100644 --- a/system/admin/handlers.go +++ b/system/admin/handlers.go @@ -8,7 +8,6 @@ import ( "fmt" "log" "net/http" - "net/url" "strconv" "strings" "time" @@ -26,6 +25,7 @@ import ( "github.com/gorilla/schema" emailer "github.com/nilslice/email" "github.com/nilslice/jwt" + "github.com/tidwall/gjson" ) func adminHandler(res http.ResponseWriter, req *http.Request) { @@ -2228,7 +2228,7 @@ func addonHandler(res http.ResponseWriter, req *http.Request) { } } - err = db.SetAddon(req.Form) + err = db.SetAddon(req.Form, at()) if err != nil { log.Println("Error saving addon:", name, err) res.WriteHeader(http.StatusInternalServerError) @@ -2256,10 +2256,13 @@ func addonHandler(res http.ResponseWriter, req *http.Request) { } } -func adminAddonListItem(data url.Values) []byte { +func adminAddonListItem(data []byte) []byte { + id := gjson.GetBytes(data, "addon_reverse_dns").String() + status := gjson.GetBytes(data, "addon_status").String() + name := gjson.GetBytes(data, "addon_name").String() + var action string var buttonClass string - status := data.Get("addon_status") if status != addon.StatusEnabled { action = "Enable" buttonClass = "green" @@ -2268,8 +2271,6 @@ func adminAddonListItem(data url.Values) []byte { buttonClass = "red" } - id := data.Get("addon_reverse_dns") - name := data.Get("addon_name") a := ` <li class="col s12"> <a href="/admin/addon?id=` + id + `" alt="Configure '` + name + `'">` + name + `</a> diff --git a/system/db/addon.go b/system/db/addon.go index c77ccf0..4b3e20c 100644 --- a/system/db/addon.go +++ b/system/db/addon.go @@ -7,7 +7,10 @@ import ( "log" "net/url" + "encoding/json" + "github.com/boltdb/bolt" + "github.com/gorilla/schema" ) var ( @@ -16,8 +19,8 @@ var ( ) // Addon looks for an addon by its addon_reverse_dns as the key and returns -// the url.Values representation of an addon -func Addon(key string) (url.Values, error) { +// the []byte as json representation of an addon +func Addon(key string) ([]byte, error) { buf := &bytes.Buffer{} err := store.View(func(tx *bolt.Tx) error { @@ -40,25 +43,21 @@ func Addon(key string) (url.Values, error) { return nil, err } - data, err := url.ParseQuery(buf.String()) - if err != nil { - return nil, err - } - - return data, nil + return buf.Bytes(), nil } // SetAddon stores the values of an addon into the __addons bucket with a the -// addon_reverse_dns field used as the key -func SetAddon(data url.Values) error { - // we don't know the structure of the addon type from a addon developer, so - // encoding to json before it's stored in the db is difficult. Instead, we - // can just encode the url.Values to a query string using the Encode() method. - // The downside is that we will have to parse the values out of the query - // string when loading it from the db - v := data.Encode() +// `addon_reverse_dns` field used as the key. `kind` is the interface{} type for +// the provided addon (as in the result of calling addon.Types[id]) +func SetAddon(data url.Values, kind interface{}) error { + dec := schema.NewDecoder() + dec.IgnoreUnknownKeys(true) + dec.SetAliasTag("json") + err := dec.Decode(kind, data) - err := store.Update(func(tx *bolt.Tx) error { + v, err := json.Marshal(kind) + + err = store.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("__addons")) k := data.Get("addon_reverse_dns") if k == "" { @@ -66,7 +65,7 @@ func SetAddon(data url.Values) error { return fmt.Errorf(`Addon "%s" has no identifier to use as key.`, name) } - err := b.Put([]byte(k), []byte(v)) + err := b.Put([]byte(k), v) if err != nil { return err } @@ -80,25 +79,15 @@ func SetAddon(data url.Values) error { return nil } -// AddonAll returns all registered addons as a []url.Values -func AddonAll() []url.Values { - var all []url.Values - buf := &bytes.Buffer{} +// AddonAll returns all registered addons as a [][]byte +func AddonAll() [][]byte { + var all [][]byte err := store.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("__addons")) err := b.ForEach(func(k, v []byte) error { - _, err := buf.Write(v) - if err != nil { - return err - } - - data, err := url.ParseQuery(buf.String()) - if err != nil { - return err - } + all = append(all, v) - all = append(all, data) return nil }) if err != nil { |