Skip to content

Instantly share code, notes, and snippets.

@yezz123
Created February 15, 2022 14:43
Show Gist options
  • Save yezz123/d0f592af45eb46c28a2e45cb1e1ab2f9 to your computer and use it in GitHub Desktop.
Save yezz123/d0f592af45eb46c28a2e45cb1e1ab2f9 to your computer and use it in GitHub Desktop.
A simple way to test Twilio SMS Sender
from __future__ import unicode_literals
import logging
from django.conf import settings
from django.utils.encoding import force_text
from twilio.rest import Client
from decimal import Decimal
from pytz import timezone
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
from .models import OutgoingSMS
logger = logging.getLogger("client")
def build_callback_url(request, urlname, message):
location = reverse(urlname, kwargs={"pk": message.pk})
callback_domain = getattr(settings, "TWILIO_CALLBACK_DOMAIN", None)
if callback_domain:
url = "{}://{}{}".format(
"https" if getattr(settings, "TWILIO_CALLBACK_USE_HTTPS", False) else "http",
callback_domain,
location
)
elif request is not None:
url = request.build_absolute_uri(location)
else:
raise ValueError(
"Unable to build callback url. Configure TWILIO_CALLBACK_DOMAIN "
"or pass request object to function call"
)
return url
def send_sms(request, to_number, body, callback_urlname="sms_status_callback"):
client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN)
from_number = settings.TWILIO_PHONE_NUMBER
message = OutgoingSMS.objects.create(
from_number=from_number,
to_number=to_number,
body=body,
)
status_callback = None
if callback_urlname:
status_callback = build_callback_url(request, callback_urlname, message)
logger.debug("Sending SMS message to %s with callback url %s: %s.",
to_number, status_callback, body)
if not getattr(settings, "TWILIO_DRY_MODE", False):
sent = client.messages.create(
to=to_number,
from_=from_number,
body=body,
status_callback=status_callback
)
logger.debug("SMS message sent: %s", sent.__dict__)
message.sms_sid = sent.sid
message.account_sid = sent.account_sid
message.status = sent.status
message.to_parsed = sent.to
if sent.price:
message.price = Decimal(force_text(sent.price))
message.price_unit = sent.price_unit
# Messages returned from Twilio are in UTC
message.sent_at = sent.date_created.replace(tzinfo=timezone('UTC'))
message.save(update_fields=["sms_sid", "account_sid", "status", "to_parsed", "sent_at"])
else:
logger.info("SMS: from %s to %s: %s", from_number, to_number, body)
return message
from django.db import models
# Used in the Test
class OutgoingSMS(models.Model):
sms_sid = models.CharField(max_length=34, default="", blank=True)
account_sid = models.CharField(max_length=34, default="", blank=True)
from_number = models.CharField(max_length=30)
to_number = models.CharField(max_length=30)
to_parsed = models.CharField(max_length=30, default="", blank=True)
body = models.TextField(max_length=160, default="", blank=True)
sent_at = models.DateTimeField(null=True, blank=True)
delivered_at = models.DateTimeField(null=True, blank=True)
status = models.CharField(max_length=20, default="", blank=True)
created_at = models.DateTimeField(auto_now_add=True)
from django.test import TestCase, Client
from django.conf import settings
from datetime import datetime
from pytz import UTC
class SmsSendingTest(TestCase):
def test_send_sms(self):
result = utils.send_sms(
request=None,
to_number=settings.TWILIO_VERIFIED_NUMBER,
body='Test Message from tox'
)
self.assertTrue(isinstance(result, OutgoingSMS))
self.assertEqual(result.status, 'queued')
self.assertTrue(isinstance(result.sent_at, datetime))
self.assertEqual(result.sent_at.tzinfo, UTC)
self.assertEqual(result.created_at.tzinfo, UTC)
self.assertIsNone(result.delivered_at)
# make fake response
client = Client(
HTTP_USER_AGENT='Mozilla/5.0',
HTTP_X_TWILIO_SIGNATURE='emin'
)
response = client.post('/messaging/callback/sent/{pk}/'.format(pk=result.pk), {
'MessageStatus': 'sent',
'ApiVersion': '',
'SmsSid': '',
'SmsStatus': 'sent',
'To': settings.TWILIO_VERIFIED_NUMBER,
'From': settings.TWILIO_PHONE_NUMBER,
'MessageSid': '',
'AccountSid': settings.TWILIO_ACCOUNT_SID
})
self.assertEqual(response.status_code, 200)
self.assertEqual(response._headers['content-type'][1], 'application/xml')
# check if sms details updated
sms = OutgoingSMS.objects.get(pk=result.pk)
self.assertTrue(isinstance(sms.delivered_at, datetime))
self.assertEqual(sms.status, 'sent')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment