3
0

Fix encoding on save & re-encoding on fetch

This commit is contained in:
Denis Arh 2021-08-16 22:49:27 +02:00
parent 6645ac0c66
commit d1ccbc3e17
3 changed files with 87 additions and 60 deletions

View File

@ -1,6 +1,7 @@
package actionlog
import (
"strconv"
"time"
)
@ -95,13 +96,6 @@ func (m Meta) Set(key string, in interface{}, omitempty bool) {
return
}
if !omitempty {
// Nothing special,
// assign value and quit
m[key] = in
return
}
// for the rest, we need to determine what kind of
if str, is := in.(string); is {
@ -125,62 +119,64 @@ func (m Meta) Set(key string, in interface{}, omitempty bool) {
return
}
// cast to (int|uint|float)64
num := func(n interface{}) interface{} {
switch n := n.(type) {
case int:
return int64(n)
case int8:
return int64(n)
case int16:
return int64(n)
case int32:
return int64(n)
{
// properly encode big numbers
// before storing them as JSON
num := func(n interface{}) interface{} {
switch n := n.(type) {
case int:
return int64(n)
case int8:
return int64(n)
case int16:
return int64(n)
case int32:
return int64(n)
case int64:
return int64(n)
case uint:
return uint64(n)
case uintptr:
return uint64(n)
case uint8:
return uint64(n)
case uint16:
return uint64(n)
case uint32:
return uint64(n)
case uint64:
return uint64(n)
case float32:
return float64(n)
case float64:
return n
}
return n
}(in)
switch num := num.(type) {
case int64:
return n
case uint:
return uint64(n)
case uintptr:
return uint64(n)
case uint8:
return uint64(n)
case uint16:
return uint64(n)
case uint32:
return uint64(n)
if !omitempty || num > 0 {
m[key] = strconv.FormatInt(num, 10)
}
return
case uint64:
return n
case float32:
return float64(n)
if !omitempty || num > 0 {
m[key] = strconv.FormatUint(num, 10)
}
return
case float64:
return n
}
return n
}(in)
if !omitempty || num > 0 {
m[key] = in
}
switch num := num.(type) {
case nil:
case uint64:
if !omitempty || num > 0 {
m[key] = in
return
}
return
case int64:
if !omitempty || num > 0 {
m[key] = in
}
return
case float64:
if !omitempty || num > 0 {
m[key] = in
}
return
}
// for the rest (slices, etc..)
// for the rest (string, slices, etc..)
// just set the value
m[key] = in
}

View File

@ -36,10 +36,18 @@ func TestMeta_Set(t *testing.T) {
{"bool true", true, false, Meta{"t": true}},
{"bool false", false, false, Meta{"t": false}},
{"int value, omit", 1, true, Meta{"t": 1}},
{"int value, keep", 1, false, Meta{"t": 1}},
{"int value, omit", 1, true, Meta{"t": "1"}},
{"int value, keep", 1, false, Meta{"t": "1"}},
{"int empty, omit", 0, true, Meta{}},
{"int empty, keep", 0, false, Meta{"t": 0}},
{"int empty, keep", 0, false, Meta{"t": "0"}},
{"uint64 empty, omit", uint64(0), true, Meta{}},
{"uint64 empty, keep", uint64(0), false, Meta{"t": "0"}},
{"bigint", 244783268048994492, false, Meta{"t": "244783268048994492"}},
{"int64", int64(244783268048994492), false, Meta{"t": "244783268048994492"}},
{"uint64()", uint64(244783268048994492), false, Meta{"t": "244783268048994492"}},
{"int", 42, false, Meta{"t": "42"}},
{"float64", float64(42), false, Meta{"t": float64(42)}},
{"float64", float64(244783268048994492), false, Meta{"t": 2.447832680489945e+17}},
{"slice", []int{0, 1}, false, Meta{"t": []int{0, 1}}},

View File

@ -2,6 +2,8 @@ package rest
import (
"context"
"strconv"
"strings"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/filter"
@ -26,7 +28,8 @@ type (
// provide user's email
actionlogActionPayload struct {
*actionlog.Action
Actor string `json:"actor,omitempty"`
Actor string `json:"actor,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
}
actionlogPayload struct {
@ -78,6 +81,9 @@ func (ctrl Actionlog) makeFilterPayload(ctx context.Context, ee []*actionlog.Act
// Remap events to payload structs
for e := range ee {
pp[e] = &actionlogActionPayload{Action: ee[e]}
pp[e].Meta = ee[e].Meta
sanitizeMapStringInterface(pp[e].Meta)
}
err = userPreloader(
@ -115,6 +121,23 @@ func (ctrl Actionlog) makeFilterPayload(ctx context.Context, ee []*actionlog.Act
return &actionlogPayload{Filter: f, Set: pp}, nil
}
// Making sure JS can read our values
func sanitizeMapStringInterface(m map[string]interface{}) {
for k := range m {
switch v := m[k].(type) {
case float64:
if strings.HasSuffix(k, "ID") {
// make sure uint64 values on fields ending with ID
// are properly encoded as strings
m[k] = strconv.FormatUint(uint64(v), 10)
}
case map[string]interface{}:
sanitizeMapStringInterface(v)
}
}
}
// Preloader collects all ids of users, loads them and sets them back
//
// We'll be accessing the store directly since this is protected with action-log.read operation check.