From 42cd60f23ff0795645d24e02ba62723364039154 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Tue, 31 Aug 2021 20:10:19 -0300 Subject: [PATCH 1/2] fix: prevent blocked contact generate log on db when send message --- backends/rapidpro/contact.go | 6 ++++-- handlers/whatsapp/whatsapp.go | 22 +++++++++++++++++++--- server.go | 14 ++++++++++---- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/backends/rapidpro/contact.go b/backends/rapidpro/contact.go index 4384436af..cfec280c5 100644 --- a/backends/rapidpro/contact.go +++ b/backends/rapidpro/contact.go @@ -84,7 +84,8 @@ SELECT c.modified_on, c.created_on, c.name, - u.id as "urn_id" + u.id as "urn_id", + c.status FROM contacts_contact AS c, contacts_contacturn AS u @@ -232,7 +233,8 @@ type DBContact struct { CreatedBy_ int `db:"created_by_id"` ModifiedBy_ int `db:"modified_by_id"` - IsNew_ bool + IsNew_ bool + Status_ string `db:"status"` } // UUID returns the UUID for this contact diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index e7a5f8c9e..e2d7824cd 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -13,6 +13,7 @@ import ( "github.com/buger/jsonparser" "github.com/nyaruka/courier" + "github.com/nyaruka/courier/backends/rapidpro" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/utils" "github.com/nyaruka/gocommon/rcache" @@ -159,8 +160,8 @@ type eventPayload struct { MimeType string `json:"mime_type" validate:"required"` Sha256 string `json:"sha256" validate:"required"` } `json:"voice"` - Contacts []struct{ - Phones []struct{ + Contacts []struct { + Phones []struct { Phone string `json:"phone"` } `json:"phones"` } `json:"contacts"` @@ -181,6 +182,21 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) } + if len(payload.Contacts) > 0 { + if contactURN, err := urns.NewWhatsAppURN(payload.Contacts[0].WaID); err == nil { + if contact, err := h.Backend().GetContact(ctx, channel, contactURN, channel.StringConfigForKey(courier.ConfigAuthToken, ""), ""); err == nil { + c, _ := json.Marshal(contact) + var dbc rapidpro.DBContact + err2 := json.Unmarshal(c, &dbc) + if err2 == nil { + if dbc.Status_ == "B" { + return nil, errors.New("blocked contact sending message") + } + } + } + } + } + // the list of events we deal with events := make([]courier.Event, 0, 2) @@ -245,7 +261,7 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h phones = append(phones, phone.Phone) } text = strings.Join(phones, ", ") - }else { + } else { // we received a message type we do not support. courier.LogRequestError(r, channel, fmt.Errorf("unsupported message type %s", msg.Type)) } diff --git a/server.go b/server.go index 9cd5661d5..5c917ff0e 100644 --- a/server.go +++ b/server.go @@ -314,15 +314,21 @@ func (s *server) channelHandleWrapper(handler ChannelHandler, handlerFunc Channe // if we received an error, write it out and report it if err != nil { - logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("url", url).WithField("request", string(request)).Error("error handling request") - writeAndLogRequestError(ctx, ww, r, channel, err) + if err.Error() != "blocked contact sending message" { + logrus.WithError(err).WithField("channel_uuid", channel.UUID()).WithField("url", url).WithField("request", string(request)).Error("error handling request") + writeAndLogRequestError(ctx, ww, r, channel, err) + } } // if we have a channel matched but no events were created we still want to log this to the channel, do so if channel != nil && len(events) == 0 { if err != nil { - logs = append(logs, NewChannelLog("Channel Error", channel, NilMsgID, r.Method, url, ww.Status(), string(request), prependHeaders(response.String(), ww.Status(), w), duration, err)) - librato.Gauge(fmt.Sprintf("courier.channel_error_%s", channel.ChannelType()), secondDuration) + if err.Error() == "blocked contact sending message" { + return + } else { + logs = append(logs, NewChannelLog("Channel Error", channel, NilMsgID, r.Method, url, ww.Status(), string(request), prependHeaders(response.String(), ww.Status(), w), duration, err)) + librato.Gauge(fmt.Sprintf("courier.channel_error_%s", channel.ChannelType()), secondDuration) + } } else { logs = append(logs, NewChannelLog("Request Ignored", channel, NilMsgID, r.Method, url, ww.Status(), string(request), prependHeaders(response.String(), ww.Status(), w), duration, err)) librato.Gauge(fmt.Sprintf("courier.channel_ignored_%s", channel.ChannelType()), secondDuration) From ae874cb9b9540c7231a7fc4c109be674ce5fccd3 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Wed, 1 Sep 2021 10:27:24 -0300 Subject: [PATCH 2/2] refactor: move check blocked contact to outside method like a middleware --- handlers/whatsapp/whatsapp.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/handlers/whatsapp/whatsapp.go b/handlers/whatsapp/whatsapp.go index e2d7824cd..480671bb8 100644 --- a/handlers/whatsapp/whatsapp.go +++ b/handlers/whatsapp/whatsapp.go @@ -63,7 +63,7 @@ func newWAHandler(channelType courier.ChannelType, name string) courier.ChannelH // Initialize is called by the engine once everything is loaded func (h *handler) Initialize(s courier.Server) error { h.SetServer(s) - s.AddHandlerRoute(h, http.MethodPost, "receive", h.receiveEvent) + s.AddHandlerRoute(h, http.MethodPost, "receive", h.checkBlockedContact) return nil } @@ -174,8 +174,9 @@ type eventPayload struct { } `json:"statuses"` } -// receiveMessage is our HTTP handler function for incoming messages -func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { +// checkBlockedContact is a handler middleware to prevent generate channel log from blocked contact messages +func (h *handler) checkBlockedContact(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { + payload := &eventPayload{} err := handlers.DecodeAndValidateJSON(payload, r) if err != nil { @@ -197,6 +198,17 @@ func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w h } } + return h.receiveEvent(ctx, channel, w, r) +} + +// receiveMessage is our HTTP handler function for incoming messages +func (h *handler) receiveEvent(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request) ([]courier.Event, error) { + payload := &eventPayload{} + err := handlers.DecodeAndValidateJSON(payload, r) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err) + } + // the list of events we deal with events := make([]courier.Event, 0, 2)