Skip to content

Commit

Permalink
Add extra field to quick replies and support encoding as text using n…
Browse files Browse the repository at this point in the history
…ew line
  • Loading branch information
rowanseymour committed Feb 27, 2025
1 parent 422b569 commit d40325e
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 12 deletions.
30 changes: 29 additions & 1 deletion flows/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package flows
import (
"fmt"
"slices"
"strings"

"github.com/go-playground/validator/v10"
"github.com/nyaruka/gocommon/i18n"
Expand Down Expand Up @@ -196,7 +197,34 @@ func NewMsgTemplating(template *assets.TemplateReference, components []*Templati
}

type QuickReply struct {
Text string `json:"text"`
Text string `json:"text"`
Extra string `json:"extra,omitempty"`
}

// MarshalText marshals a quick reply into a text representation using a new line if extra is present
func (q QuickReply) MarshalText() (text []byte, err error) {
vs := []string{q.Text}
if q.Extra != "" {
vs = append(vs, q.Extra)
}
return []byte(strings.Join(vs, "\n")), nil
}

func (q *QuickReply) UnmarshalText(text []byte) error {
vs := strings.SplitN(string(text), "\n", 2)
q.Text = vs[0]
if len(vs) > 1 {
q.Extra = vs[1]
}
return nil
}

func (q QuickReply) MarshalJSON() ([]byte, error) {
// alias our type so we don't end up here again
type alias QuickReply

// we need to provide a MarshalJSON or the json package uses our MarshalText
return jsonx.Marshal((alias)(q))
}

func (q *QuickReply) UnmarshalJSON(d []byte) error {
Expand Down
48 changes: 37 additions & 11 deletions flows/msg_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package flows_test

import (
"encoding/json"
"testing"
"time"

Expand Down Expand Up @@ -262,17 +263,42 @@ func TestMsgTemplating(t *testing.T) {
}

func TestQuickReplies(t *testing.T) {
// can unmarshal from a string
qr1 := flows.QuickReply{}
jsonx.MustUnmarshal([]byte(`"Yes"`), &qr1)
assert.Equal(t, flows.QuickReply{Text: "Yes"}, qr1)
texts := []struct {
text string
expected flows.QuickReply
}{
{"", flows.QuickReply{Text: ""}},
{"Yes", flows.QuickReply{Text: "Yes"}},
{"Yes\nReally", flows.QuickReply{Text: "Yes", Extra: "Really"}},
}
for _, tc := range texts {
qr := flows.QuickReply{}
err := qr.UnmarshalText([]byte(tc.text))
require.NoError(t, err)
assert.Equal(t, tc.expected, qr)

marshaled, err := qr.MarshalText()
require.NoError(t, err)
assert.Equal(t, tc.text, string(marshaled))
}

// can unmarshal from a struct
qr2 := flows.QuickReply{}
jsonx.MustUnmarshal([]byte(`{"text": "No"}`), &qr2)
assert.Equal(t, flows.QuickReply{Text: "No"}, qr2)
jsons := []struct {
json []byte
expected flows.QuickReply
}{
{[]byte(`"Yes"`), flows.QuickReply{Text: "Yes"}},
{[]byte(`{"text": "Yes"}`), flows.QuickReply{Text: "Yes"}},
{[]byte(`{"text": "Yes", "extra": "Really"}`), flows.QuickReply{Text: "Yes", Extra: "Really"}},
}
for _, tc := range jsons {
qr := flows.QuickReply{}
err := json.Unmarshal(tc.json, &qr)
require.NoError(t, err)
assert.Equal(t, tc.expected, qr)
}

assert.Equal(t, []byte(`{"text":"Yes"}`), jsonx.MustMarshal(qr1))
assert.Equal(t, []byte(`{"text":"No"}`), jsonx.MustMarshal(qr2))
assert.Equal(t, []byte(`[{"text":"Yes"},{"text":"No"}]`), jsonx.MustMarshal([]flows.QuickReply{qr1, qr2}))
// marshaling is always as struct
assert.Equal(t, []byte(`{"text":"Yes"}`), jsonx.MustMarshal(flows.QuickReply{Text: "Yes"}))
assert.Equal(t, []byte(`{"text":"Yes","extra":"Really"}`), jsonx.MustMarshal(flows.QuickReply{Text: "Yes", Extra: "Really"}))
assert.Equal(t, []byte(`[{"text":"Yes"},{"text":"No"}]`), jsonx.MustMarshal([]flows.QuickReply{{Text: "Yes"}, {Text: "No"}}))
}

0 comments on commit d40325e

Please sign in to comment.