Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add support to WhatsApp Flows #150

Merged
merged 5 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions core/handlers/msg_wpp_created.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ func handleMsgWppCreated(ctx context.Context, rt *runtime.Runtime, tx *sqlx.Tx,
}
}

// get our whatsapp flow status
if channel != nil && channel.Type() == "WAC" {
if event.Msg.InteractionType() == "flow_msg" && event.Msg.FlowMessage().FlowID != "" {
whatsAppFlow, err := models.GetActiveWhatsAppFlowFromFacebookIDAndChannel(ctx, tx, channel.ID(), event.Msg.FlowMessage().FlowID)
if err != nil {
return errors.Wrapf(err, "unable to load whatsapp flow with id: %s, for channel %d", event.Msg.FlowMessage().FlowID, channel.ID())
}

if whatsAppFlow != nil {
event.Msg.FlowMessage_.FlowMode = whatsAppFlow.Status()
}
}
}

msg, err := models.NewOutgoingFlowMsgWpp(rt, oa.Org(), channel, scene.Session(), event.Msg, event.CreatedOn())
if err != nil {
return errors.Wrapf(err, "error creating outgoing message to %s", event.Msg.URN())
Expand Down
30 changes: 29 additions & 1 deletion core/handlers/msg_wpp_created_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func TestMsgWppCreated(t *testing.T) {
nil,
"list",
"",
"",
nil,
"nil",
"",
true,
),
},
Expand All @@ -56,6 +60,10 @@ func TestMsgWppCreated(t *testing.T) {
nil,
"list",
"",
"",
nil,
"nil",
"",
true,
),
},
Expand All @@ -68,11 +76,31 @@ func TestMsgWppCreated(t *testing.T) {
nil,
"cta_url",
"http://foo.bar",
"",
nil,
"nil",
"",
true,
),
},
testdata.Bob: []flows.Action{
actions.NewSendWppMsg(handlers.NewActionUUID(), "", "", "", "Text", "footer", []flows.ListItems{}, "Menu", nil, "", "", false),
actions.NewSendWppMsg(handlers.NewActionUUID(), "", "", "", "Text", "footer", []flows.ListItems{}, "Menu", nil, "", "", "", nil, "", "", false),
},
testdata.Cathy: []flows.Action{
actions.NewSendWppMsg(
handlers.NewActionUUID(),
"text", "Hi", "", "Hi there.", "footer",
[]flows.ListItems{},
"Start WhatsApp Flow",
nil,
"flow_msg",
"",
"19472745982745",
map[string]interface{}{"uuid": testdata.Cathy.UUID, "extra": "[\"foo\", \"bar\"]"},
"WELCOME_SCREEN",
"published",
true,
),
},
},
Msgs: handlers.ContactMsgMap{
Expand Down
11 changes: 11 additions & 0 deletions core/models/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,17 @@ func newOutgoingMsgWpp(rt *runtime.Runtime, org *Org, channel *Channel, contactI
"display_text": msgWpp.CTAMessage().DisplayText_,
}
}
if msgWpp.InteractionType() == "flow_msg" {
metadata["interaction_type"] = msgWpp.InteractionType()
metadata["flow_message"] = msgWpp.FlowMessage()
metadata["flow_message"] = map[string]interface{}{
"flow_id": msgWpp.FlowMessage().FlowID,
"flow_screen": msgWpp.FlowMessage().FlowScreen,
"flow_data": msgWpp.FlowMessage().FlowData,
"flow_cta": msgWpp.FlowMessage().FlowCTA,
"flow_mode": msgWpp.FlowMessage().FlowMode,
}
}
if msgWpp.TextLanguage != "" {
metadata["text_language"] = msgWpp.TextLanguage
}
Expand Down
106 changes: 106 additions & 0 deletions core/models/whatsapp_flows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package models

import (
"context"
"database/sql"
"database/sql/driver"
"time"

"github.com/nyaruka/gocommon/uuids"
"github.com/nyaruka/goflow/assets"
"github.com/nyaruka/mailroom/utils/dbutil"
"github.com/nyaruka/null"
"github.com/pkg/errors"
)

type WhatsAppFlowID null.Int

func (i WhatsAppFlowID) MarshalJSON() ([]byte, error) {
return null.Int(i).MarshalJSON()
}

func (i *WhatsAppFlowID) UnmarshalJSON(b []byte) error {
return null.UnmarshalInt(b, (*null.Int)(i))
}

func (i WhatsAppFlowID) Value() (driver.Value, error) {
return null.Int(i).Value()
}

func (i *WhatsAppFlowID) Scan(value interface{}) error {
return null.ScanInt(value, (*null.Int)(i))
}

// WhatsAppFlow representation for WhatsApp channels
type WhatsAppFlow struct {
f struct {
ID CatalogID `json:"id"`
UUID uuids.UUID `json:"uuid"`
FacebookFlowID string `json:"facebook_flow_id"`
Category []string `json:"category"`
Status string `json:"status"`
Name string `json:"name"`
CreatedOn time.Time `json:"created_on"`
ModifiedOn time.Time `json:"modified_on"`
IsActive bool `json:"is_active"`
ChannelID ChannelID `json:"channel_id"`
OrgID OrgID `json:"org_id"`
ChannelUUID assets.ChannelUUID `json:"channel_uuid"`
}
}

func (f *WhatsAppFlow) ID() CatalogID { return f.f.ID }
func (f *WhatsAppFlow) UUID() uuids.UUID { return f.f.UUID }
func (f *WhatsAppFlow) FacebookCatalogID() string { return f.f.FacebookFlowID }
func (f *WhatsAppFlow) Category() []string { return f.f.Category }
func (f *WhatsAppFlow) Status() string { return f.f.Status }
func (f *WhatsAppFlow) Name() string { return f.f.Name }
func (f *WhatsAppFlow) CreatedOn() time.Time { return f.f.CreatedOn }
func (f *WhatsAppFlow) ModifiedOn() time.Time { return f.f.ModifiedOn }
func (f *WhatsAppFlow) IsActive() bool { return f.f.IsActive }
func (f *WhatsAppFlow) ChannelID() ChannelID { return f.f.ChannelID }
func (f *WhatsAppFlow) OrgID() OrgID { return f.f.OrgID }
func (f *WhatsAppFlow) ChannelUUID() assets.ChannelUUID { return f.f.ChannelUUID }

const getActiveWhatsAppFlowSQL = `
SELECT ROW_TO_JSON(r) FROM (SELECT
f.id as id,
f.uuid as uuid,
f.facebook_flow_id as facebook_flow_id,
f.category as category,
f.status as status,
f.name as name,
f.created_on as created_on,
f.modified_on as modified_on,
f.is_active as is_active,
f.channel_id as channel_id,
f.org_id as org_id
FROM
public.wpp_flows_whatsappflow f
WHERE
channel_id = $1 AND is_active = true AND facebook_flow_id = $2
) r;
`

// GetActiveCatalogFromChannel returns the active catalog from the given channel
func GetActiveWhatsAppFlowFromFacebookIDAndChannel(ctx context.Context, db Queryer, channelID ChannelID, facebookFlowID string) (*WhatsAppFlow, error) {
var whatsAppFlow WhatsAppFlow

rows, err := db.QueryxContext(ctx, getActiveWhatsAppFlowSQL, channelID, facebookFlowID)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, errors.Wrapf(err, "error getting active flow with id: %s, for channelID: %d", facebookFlowID, channelID)
}
defer rows.Close()

for rows.Next() {
err = dbutil.ReadJSONRow(rows, &whatsAppFlow.f)
if err != nil {
return nil, err
}
}

return &whatsAppFlow, nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ go 1.17

replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.16.2-weni

replace github.com/nyaruka/goflow => github.com/weni-ai/goflow v1.0.0
replace github.com/nyaruka/goflow => github.com/weni-ai/goflow v1.1.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPf
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
github.com/weni-ai/goflow v1.0.0 h1:19Zm8owCQWoFb+fWUxiKpWyB+KysxwJzk7ZwNolSjlo=
github.com/weni-ai/goflow v1.0.0/go.mod h1:o0xaVWP9qNcauBSlcNLa79Fm2oCPV+BDpheFRa/D40c=
github.com/weni-ai/goflow v1.1.0 h1:/UC432ghh6fkhb05Z6c/JxGWf8ej5CNVF67t9gZcIVU=
github.com/weni-ai/goflow v1.1.0/go.mod h1:o0xaVWP9qNcauBSlcNLa79Fm2oCPV+BDpheFRa/D40c=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
Loading