Skip to content

Commit 8b45aff

Browse files
authored
Merge pull request #474 from tutorcruncher/fix-carrier-failed-webhook-status
Fix carrier failed webhook status
2 parents 65dc570 + ae0cf8f commit 8b45aff

File tree

5 files changed

+104
-4
lines changed

5 files changed

+104
-4
lines changed

src/schemas/webhooks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from enum import Enum
55
from pydantic import BaseModel, validator
66
from pydantic.validators import str_validator
7-
from typing import List
7+
from typing import List, Optional
88

99
from src.schemas.messages import MessageStatus
1010

@@ -98,7 +98,7 @@ class MessageBirdWebHook(BaseWebhook):
9898
status: MessageBirdMessageStatus
9999
message_id: IDStr
100100
error_code: str = None
101-
price_amount: float
101+
price_amount: Optional[float] = None
102102

103103
def extra_json(self, sort_keys=False):
104104
return json.dumps({'error_code': self.error_code} if self.error_code else {}, sort_keys=sort_keys)

src/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = '1.0.34'
1+
VERSION = '1.0.35'

src/views/webhooks.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import hashlib
33
import hmac
44
import json
5+
import logging
56
from fastapi import APIRouter, Form, Header
67
from foxglove import glove
78
from foxglove.exceptions import HttpBadRequest, HttpForbidden, HttpUnprocessableEntity
@@ -15,6 +16,8 @@
1516

1617
app = APIRouter(route_class=KeepBodyAPIRoute)
1718

19+
logger = logging.getLogger('views.webhooks')
20+
1821

1922
@app.post('/test/')
2023
async def test_webhook_view(m: MandrillSingleWebhook):
@@ -56,6 +59,16 @@ async def messagebird_webhook_view(request: Request):
5659
event = MessageBirdWebHook(**request.query_params)
5760
except ValidationError as e:
5861
raise HttpUnprocessableEntity(e.args[0])
62+
if event.error_code is not None:
63+
if event.error_code == '104':
64+
logger.error(
65+
'[webhooks][mesagebird] carrier rejected error',
66+
extra={'id': event.message_id, 'datetime': event.ts, 'status': event.status},
67+
)
68+
else:
69+
# Will change this to a warning in the future
70+
logger.error('[webhooks][mesagebird] delivery failed with status: %s', event.status)
71+
5972
method = SendMethod.sms_messagebird
6073
if (test := request.query_params.get('test')) and test.lower() == 'true':
6174
method = SendMethod.sms_test

src/worker/webhooks.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,12 @@ async def update_message_status(ctx, send_method: SendMethod, m: BaseWebhook, lo
9898
values=Values(message_id=message_id, status=m.status, ts=m.ts, extra=m.extra_json()),
9999
),
100100
]
101-
if isinstance(m, MessageBirdWebHook):
101+
if isinstance(m, MessageBirdWebHook) and m.price_amount is not None:
102102
cost = m.price_amount
103103
qs.append(
104104
glove.pg.execute_b('update messages set cost=:cost where id=:message_id', cost=cost, message_id=message_id)
105105
)
106+
106107
await asyncio.gather(*qs)
107108

108109
return UpdateStatus.added

tests/test_sms.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,92 @@ def test_messagebird_webhook_sms_pricing(cli, sync_db: SyncDb, dummy_server, wor
263263
assert msg['cost'] == 0.07
264264

265265

266+
def test_messagebird_webhook_carrier_failed(cli, sync_db: SyncDb, dummy_server, worker, loop):
267+
data = {
268+
'uid': str(uuid4()),
269+
'company_code': 'webhook-test',
270+
'method': 'sms-messagebird',
271+
'main_template': 'this is a message',
272+
'recipients': [{'first_name': 'John', 'last_name': 'Doe', 'user_link': 4321, 'number': '07801234567'}],
273+
}
274+
275+
r = cli.post('/send/sms/', json=data, headers={'Authorization': 'testing-key'})
276+
assert r.status_code == 201, r.text
277+
assert worker.test_run() == 1
278+
279+
msg = sync_db.fetchrow_b('select * from messages join message_groups g on g.id = messages.id')
280+
assert msg['status'] == 'send'
281+
assert msg['to_first_name'] == 'John'
282+
assert msg['to_last_name'] == 'Doe'
283+
assert msg['to_user_link'] == '4321'
284+
assert msg['to_address'] == '+44 7801 234567'
285+
assert msg['from_name'] == 'Morpheus'
286+
assert msg['body'] == 'this is a message'
287+
assert msg['cost'] is None
288+
assert len(msg['tags']) == 1 # just group_id
289+
290+
url_args = {
291+
'id': msg['external_id'],
292+
'reference': 'morpheus',
293+
'recipient': '447801234567',
294+
'status': 'delivery_failed',
295+
'statusDatetime': '2032-06-06T12:00:00',
296+
'statusReason': 'carrier+rejected',
297+
'statusErrorCode': 104,
298+
}
299+
300+
r = cli.get(f'/webhook/messagebird/?{urlencode(url_args)}')
301+
assert r.status_code == 200, r.text
302+
assert worker.test_run() == 2
303+
304+
msg = sync_db.fetchrow_b('select * from messages')
305+
assert msg['status'] == 'delivery_failed'
306+
assert msg['cost'] is None
307+
308+
309+
def test_messagebird_webhook_other_delivery_failed(cli, sync_db: SyncDb, dummy_server, worker, loop):
310+
data = {
311+
'uid': str(uuid4()),
312+
'company_code': 'webhook-test',
313+
'method': 'sms-messagebird',
314+
'main_template': 'this is a message',
315+
'recipients': [{'first_name': 'John', 'last_name': 'Doe', 'user_link': 4321, 'number': '07801234567'}],
316+
}
317+
318+
r = cli.post('/send/sms/', json=data, headers={'Authorization': 'testing-key'})
319+
assert r.status_code == 201, r.text
320+
assert worker.test_run() == 1
321+
322+
msg = sync_db.fetchrow_b('select * from messages join message_groups g on g.id = messages.id')
323+
assert msg['status'] == 'send'
324+
assert msg['to_first_name'] == 'John'
325+
assert msg['to_last_name'] == 'Doe'
326+
assert msg['to_user_link'] == '4321'
327+
assert msg['to_address'] == '+44 7801 234567'
328+
assert msg['from_name'] == 'Morpheus'
329+
assert msg['body'] == 'this is a message'
330+
assert msg['cost'] is None
331+
assert len(msg['tags']) == 1 # just group_id
332+
333+
url_args = {
334+
'id': msg['external_id'],
335+
'reference': 'morpheus',
336+
'recipient': '447801234567',
337+
'status': 'delivery_failed',
338+
'statusDatetime': '2032-06-06T12:00:00',
339+
'statusReason': 'unknown+subscriber',
340+
'statusErrorCode': 27,
341+
}
342+
343+
r = cli.get(f'/webhook/messagebird/?{urlencode(url_args)}')
344+
assert r.status_code == 200, r.text
345+
assert worker.test_run() == 2
346+
347+
msg = sync_db.fetchrow_b('select * from messages')
348+
assert msg['status'] == 'delivery_failed'
349+
assert msg['cost'] is None
350+
351+
266352
def test_failed_render(cli, tmpdir, sync_db: SyncDb, worker, loop):
267353
data = {
268354
'uid': str(uuid4()),

0 commit comments

Comments
 (0)