def make_twilio_request(method, uri, **kwargs): """ Make a request to Twilio. Throws an error """ headers = kwargs.get("headers", {}) headers["User-Agent"] = "twilio-python/%s" % twilio.__version__ if method == "POST" and "Content-Type" not in headers: headers["Content-Type"] = "application/x-www-form-urlencoded" kwargs["headers"] = headers if "Accept" not in headers: headers["Accept"] = "application/json" uri = uri + ".json" resp = make_request(method, uri, **kwargs) if not resp.ok: try: error = json.loads(resp.content) message = "%s: %s" % (error["code"], error["message"]) except: message = resp.content raise TwilioRestException(resp.status_code, resp.url, message) return resp
def create_instance(self, body): """ Create an InstanceResource via a POST to the List Resource :param dict body: Dictoionary of POST data """ resp, instance = self.request("POST", self.uri, data=body) if resp.status_code != 201: raise TwilioRestException(resp.status, self.uri, "Resource not created") return self.load_instance(instance)
def twilioSMS_unloggedSender(request, recipient, body, sender=settings.TWILIO_CALLER_ID, callBack=None): """Sends an SMS message without logging it. :param request: The HTTP Request object :param recipient: The destination mobile phone number. :param body: The body of the message to be sent. The length of this MUST NOT be greater than 160 characters. An exception is raised if it is. :param sender: The "sender" of the SMS message. Note that this value MUST be a DoctorCom phone number (one that we own through our Twilio account). If it isn't, then urllib will raise an exception since Twilio will come back with HTTP status 400. :param callBack: The url to have Twilio call back to with the SMS delivery status. Default None. """ if (len(body) > 160): # fragment? raise Exception('Message is too long: "%s"' % (body,)) sms_resp = None try: # d = { # 'From': sender, # 'To': recipient, # 'Body': body, # 'Method': 'POST', # 'StatusCallback': callBack or '', # } # auth, uri = client.auth, client.account_uri # resp = make_twilio_request('POST', uri + '/SMS/Messages', auth=auth, data=d) # sms_resp = json.loads(resp.content) # 2010-04-01 version sms_resp = client.sms.messages.create(body=body, to=recipient, from_=sender, status_callback=callBack) except TwilioRestException as re: msg = re.msg # json.loads(re.msg) if (re.status == 400): logger.warn('%s: got HTTP400 from Twilio: %s' % (str(request.session.session_key), msg)) else: logger.error('%s: Got HTTP from Twilio: %s' % (str(request.session.session_key), msg)) # An error occurred, re-raise the exception raise TwilioRestException(re.status, re.uri, msg, re.code or 0) return sms_resp
def test_deactivate(self): # make our channel of the twilio ilk self.org.connect_twilio("TEST_SID", "TEST_TOKEN", self.admin) twilio_channel = self.org.channels.all().first() twilio_channel.channel_type = "T" twilio_channel.save() # mock an authentication failure during the release process with self.settings(IS_PROD=True): with patch("temba.tests.twilio.MockTwilioClient.MockPhoneNumbers.update") as mock_numbers: mock_numbers.side_effect = TwilioRestException( 401, "http://twilio", msg="Authentication Failure", code=20003 ) # releasing shouldn't blow up on auth failures twilio_channel.release() twilio_channel.refresh_from_db() self.assertFalse(twilio_channel.is_active)
def test_claim(self): self.login(self.admin) claim_twilio = reverse("channels.types.twilio.claim") # remove any existing channels self.org.channels.update(is_active=False) # make sure twilio is on the claim page response = self.client.get(reverse("channels.channel_claim")) self.assertContains(response, "Twilio") response = self.client.get(claim_twilio) self.assertEqual(response.status_code, 302) response = self.client.get(claim_twilio, follow=True) self.assertEqual(response.request["PATH_INFO"], reverse("orgs.org_twilio_connect")) # attach a Twilio accont to the org self.org.config = {ACCOUNT_SID: "account-sid", ACCOUNT_TOKEN: "account-token"} self.org.save() # hit the claim page, should now have a claim twilio link response = self.client.get(reverse("channels.channel_claim")) self.assertContains(response, claim_twilio) response = self.client.get(claim_twilio) self.assertIn("account_trial", response.context) self.assertFalse(response.context["account_trial"]) with patch("temba.orgs.models.Org.get_twilio_client") as mock_get_twilio_client: mock_get_twilio_client.return_value = None response = self.client.get(claim_twilio) self.assertRedirects(response, reverse("orgs.org_twilio_connect")) mock_get_twilio_client.side_effect = TwilioRestException( 401, "http://twilio", msg="Authentication Failure", code=20003 ) response = self.client.get(claim_twilio) self.assertRedirects(response, reverse("orgs.org_twilio_connect")) with patch("temba.tests.twilio.MockTwilioClient.MockAccounts.get") as mock_get: mock_get.return_value = MockTwilioClient.MockAccount("Trial") response = self.client.get(claim_twilio) self.assertIn("account_trial", response.context) self.assertTrue(response.context["account_trial"]) with patch("temba.tests.twilio.MockTwilioClient.MockPhoneNumbers.search") as mock_search: search_url = reverse("channels.channel_search_numbers") # try making empty request response = self.client.post(search_url, {}) self.assertEqual(response.json(), []) # try searching for US number mock_search.return_value = [MockTwilioClient.MockPhoneNumber("+12062345678")] response = self.client.post(search_url, {"country": "US", "area_code": "206"}) self.assertEqual(response.json(), ["+1 206-234-5678", "+1 206-234-5678"]) # try searching without area code response = self.client.post(search_url, {"country": "US", "area_code": ""}) self.assertEqual(response.json(), ["+1 206-234-5678", "+1 206-234-5678"]) mock_search.return_value = [] response = self.client.post(search_url, {"country": "US", "area_code": ""}) self.assertEqual( response.json()["error"], "Sorry, no numbers found, please enter another area code and try again." ) # try searching for non-US number mock_search.return_value = [MockTwilioClient.MockPhoneNumber("+442812345678")] response = self.client.post(search_url, {"country": "GB", "area_code": "028"}) self.assertEqual(response.json(), ["+44 28 1234 5678", "+44 28 1234 5678"]) mock_search.return_value = [] response = self.client.post(search_url, {"country": "GB", "area_code": ""}) self.assertEqual( response.json()["error"], "Sorry, no numbers found, please enter another pattern and try again." ) with patch("temba.tests.twilio.MockTwilioClient.MockPhoneNumbers.list") as mock_numbers: mock_numbers.return_value = [MockTwilioClient.MockPhoneNumber("+12062345678")] with patch("temba.tests.twilio.MockTwilioClient.MockShortCodes.list") as mock_short_codes: mock_short_codes.return_value = [] response = self.client.get(claim_twilio) self.assertContains(response, "206-234-5678") # claim it response = self.client.post(claim_twilio, dict(country="US", phone_number="12062345678")) self.assertRedirects(response, reverse("public.public_welcome") + "?success") # make sure it is actually connected channel = Channel.objects.get(channel_type="T", org=self.org) self.assertEqual( channel.role, Channel.ROLE_CALL + Channel.ROLE_ANSWER + Channel.ROLE_SEND + Channel.ROLE_RECEIVE ) channel_config = channel.config self.assertEqual(channel_config[Channel.CONFIG_ACCOUNT_SID], "account-sid") self.assertEqual(channel_config[Channel.CONFIG_AUTH_TOKEN], "account-token") self.assertTrue(channel_config[Channel.CONFIG_APPLICATION_SID]) self.assertTrue(channel_config[Channel.CONFIG_NUMBER_SID]) # voice only number with patch("temba.tests.twilio.MockTwilioClient.MockPhoneNumbers.list") as mock_numbers: mock_numbers.return_value = [MockTwilioClient.MockPhoneNumber("+554139087835")] with patch("temba.tests.twilio.MockTwilioClient.MockShortCodes.list") as mock_short_codes: mock_short_codes.return_value = [] Channel.objects.all().delete() response = self.client.get(claim_twilio) self.assertContains(response, "+55 41 3908-7835") # claim it response = self.client.post(claim_twilio, dict(country="BR", phone_number="554139087835")) self.assertRedirects(response, reverse("public.public_welcome") + "?success") # make sure it is actually connected channel = Channel.objects.get(channel_type="T", org=self.org) self.assertEqual(channel.role, Channel.ROLE_CALL + Channel.ROLE_ANSWER) with patch("temba.tests.twilio.MockTwilioClient.MockPhoneNumbers.list") as mock_numbers: mock_numbers.return_value = [MockTwilioClient.MockPhoneNumber("+4545335500")] with patch("temba.tests.twilio.MockTwilioClient.MockShortCodes.list") as mock_short_codes: mock_short_codes.return_value = [] Channel.objects.all().delete() response = self.client.get(claim_twilio) self.assertContains(response, "45 33 55 00") self.assertEqual(mock_numbers.call_args_list[0][1], {"page_size": 1000}) # claim it response = self.client.post(claim_twilio, dict(country="DK", phone_number="4545335500")) self.assertRedirects(response, reverse("public.public_welcome") + "?success") # make sure it is actually connected Channel.objects.get(channel_type="T", org=self.org) with patch("temba.tests.twilio.MockTwilioClient.MockPhoneNumbers.list") as mock_numbers: mock_numbers.return_value = [] with patch("temba.tests.twilio.MockTwilioClient.MockShortCodes.list") as mock_short_codes: mock_short_codes.return_value = [MockTwilioClient.MockShortCode("8080")] Channel.objects.all().delete() self.org.timezone = "America/New_York" self.org.save() response = self.client.get(claim_twilio) self.assertContains(response, "8080") self.assertContains(response, 'class="country">US') # we look up the country from the timezone # claim it response = self.client.post(claim_twilio, dict(country="US", phone_number="8080")) self.assertRedirects(response, reverse("public.public_welcome") + "?success") self.assertEqual(mock_numbers.call_args_list[0][1], {"page_size": 1000}) # make sure it is actually connected Channel.objects.get(channel_type="T", org=self.org) twilio_channel = self.org.channels.all().first() # make channel support both sms and voice to check we clear both applications twilio_channel.role = Channel.ROLE_SEND + Channel.ROLE_RECEIVE + Channel.ROLE_ANSWER + Channel.ROLE_CALL twilio_channel.save() self.assertEqual("T", twilio_channel.channel_type) with self.settings(IS_PROD=True): with patch("temba.tests.twilio.MockTwilioClient.MockPhoneNumbers.update") as mock_numbers: # our twilio channel removal should fail on bad auth mock_numbers.side_effect = TwilioRestException( 401, "http://twilio", msg="Authentication Failure", code=20003 ) self.client.post(reverse("channels.channel_delete", args=[twilio_channel.pk])) self.assertIsNotNone(self.org.channels.all().first()) # or other arbitrary twilio errors mock_numbers.side_effect = TwilioRestException(400, "http://twilio", msg="Twilio Error", code=123) self.client.post(reverse("channels.channel_delete", args=[twilio_channel.pk])) self.assertIsNotNone(self.org.channels.all().first()) # now lets be successful mock_numbers.side_effect = None self.client.post(reverse("channels.channel_delete", args=[twilio_channel.pk])) self.assertIsNone(self.org.channels.filter(is_active=True).first()) self.assertEqual( mock_numbers.call_args_list[-1][1], dict(voice_application_sid="", sms_application_sid="") )
def side_effect(): from twilio import TwilioRestException raise TwilioRestException('Test exception')
def create(self, to=None, from_=None, url=None, status_callback=None): from twilio import TwilioRestException raise TwilioRestException(403, 'http://twilio.com', code=20003)
def test_claim(self): self.login(self.admin) claim_twilio = reverse('channels.claim_twilio') # remove any existing channels self.org.channels.update(is_active=False, org=None) # make sure twilio is on the claim page response = self.client.get(reverse('channels.channel_claim')) self.assertContains(response, "Twilio") response = self.client.get(claim_twilio) self.assertEqual(response.status_code, 302) response = self.client.get(claim_twilio, follow=True) self.assertEqual(response.request['PATH_INFO'], reverse('orgs.org_twilio_connect')) # attach a Twilio accont to the org self.org.config = json.dumps({ ACCOUNT_SID: 'account-sid', ACCOUNT_TOKEN: 'account-token' }) self.org.save() # hit the claim page, should now have a claim twilio link response = self.client.get(reverse('channels.channel_claim')) self.assertContains(response, claim_twilio) response = self.client.get(claim_twilio) self.assertIn('account_trial', response.context) self.assertFalse(response.context['account_trial']) with patch('temba.orgs.models.Org.get_twilio_client' ) as mock_get_twilio_client: mock_get_twilio_client.return_value = None response = self.client.get(claim_twilio) self.assertRedirects(response, reverse('orgs.org_twilio_connect')) mock_get_twilio_client.side_effect = TwilioRestException( 401, 'http://twilio', msg='Authentication Failure', code=20003) response = self.client.get(claim_twilio) self.assertRedirects(response, reverse('orgs.org_twilio_connect')) with patch( 'temba.tests.MockTwilioClient.MockAccounts.get') as mock_get: mock_get.return_value = MockTwilioClient.MockAccount('Trial') response = self.client.get(claim_twilio) self.assertIn('account_trial', response.context) self.assertTrue(response.context['account_trial']) with patch('temba.tests.MockTwilioClient.MockPhoneNumbers.search' ) as mock_search: search_url = reverse('channels.channel_search_numbers') # try making empty request response = self.client.post(search_url, {}) self.assertEqual(response.json(), []) # try searching for US number mock_search.return_value = [ MockTwilioClient.MockPhoneNumber('+12062345678') ] response = self.client.post(search_url, { 'country': 'US', 'area_code': '206' }) self.assertEqual(response.json(), ['+1 206-234-5678', '+1 206-234-5678']) # try searching without area code response = self.client.post(search_url, { 'country': 'US', 'area_code': '' }) self.assertEqual(response.json(), ['+1 206-234-5678', '+1 206-234-5678']) mock_search.return_value = [] response = self.client.post(search_url, { 'country': 'US', 'area_code': '' }) self.assertEqual( json.loads(response.content)['error'], "Sorry, no numbers found, please enter another area code and try again." ) # try searching for non-US number mock_search.return_value = [ MockTwilioClient.MockPhoneNumber('+442812345678') ] response = self.client.post(search_url, { 'country': 'GB', 'area_code': '028' }) self.assertEqual(response.json(), ['+44 28 1234 5678', '+44 28 1234 5678']) mock_search.return_value = [] response = self.client.post(search_url, { 'country': 'GB', 'area_code': '' }) self.assertEqual( json.loads(response.content)['error'], "Sorry, no numbers found, please enter another pattern and try again." ) with patch('temba.tests.MockTwilioClient.MockPhoneNumbers.list' ) as mock_numbers: mock_numbers.return_value = [ MockTwilioClient.MockPhoneNumber('+12062345678') ] with patch('temba.tests.MockTwilioClient.MockShortCodes.list' ) as mock_short_codes: mock_short_codes.return_value = [] response = self.client.get(claim_twilio) self.assertContains(response, '206-234-5678') # claim it response = self.client.post( claim_twilio, dict(country='US', phone_number='12062345678')) self.assertRedirects( response, reverse('public.public_welcome') + "?success") # make sure it is actually connected channel = Channel.objects.get(channel_type='T', org=self.org) self.assertEqual( channel.role, Channel.ROLE_CALL + Channel.ROLE_ANSWER + Channel.ROLE_SEND + Channel.ROLE_RECEIVE) channel_config = channel.config_json() self.assertEqual(channel_config[Channel.CONFIG_ACCOUNT_SID], 'account-sid') self.assertEqual(channel_config[Channel.CONFIG_AUTH_TOKEN], 'account-token') self.assertTrue(channel_config[Channel.CONFIG_APPLICATION_SID]) self.assertTrue(channel_config[Channel.CONFIG_NUMBER_SID]) # voice only number with patch('temba.tests.MockTwilioClient.MockPhoneNumbers.list' ) as mock_numbers: mock_numbers.return_value = [ MockTwilioClient.MockPhoneNumber('+554139087835') ] with patch('temba.tests.MockTwilioClient.MockShortCodes.list' ) as mock_short_codes: mock_short_codes.return_value = [] Channel.objects.all().delete() response = self.client.get(claim_twilio) self.assertContains(response, '+55 41 3908-7835') # claim it response = self.client.post( claim_twilio, dict(country='BR', phone_number='554139087835')) self.assertRedirects( response, reverse('public.public_welcome') + "?success") # make sure it is actually connected channel = Channel.objects.get(channel_type='T', org=self.org) self.assertEqual(channel.role, Channel.ROLE_CALL + Channel.ROLE_ANSWER) with patch('temba.tests.MockTwilioClient.MockPhoneNumbers.list' ) as mock_numbers: mock_numbers.return_value = [ MockTwilioClient.MockPhoneNumber('+4545335500') ] with patch('temba.tests.MockTwilioClient.MockShortCodes.list' ) as mock_short_codes: mock_short_codes.return_value = [] Channel.objects.all().delete() response = self.client.get(claim_twilio) self.assertContains(response, '45 33 55 00') # claim it response = self.client.post( claim_twilio, dict(country='DK', phone_number='4545335500')) self.assertRedirects( response, reverse('public.public_welcome') + "?success") # make sure it is actually connected Channel.objects.get(channel_type='T', org=self.org) with patch('temba.tests.MockTwilioClient.MockPhoneNumbers.list' ) as mock_numbers: mock_numbers.return_value = [] with patch('temba.tests.MockTwilioClient.MockShortCodes.list' ) as mock_short_codes: mock_short_codes.return_value = [ MockTwilioClient.MockShortCode('8080') ] Channel.objects.all().delete() self.org.timezone = 'America/New_York' self.org.save() response = self.client.get(claim_twilio) self.assertContains(response, '8080') self.assertContains( response, 'class="country">US' ) # we look up the country from the timezone # claim it response = self.client.post( claim_twilio, dict(country='US', phone_number='8080')) self.assertRedirects( response, reverse('public.public_welcome') + "?success") # make sure it is actually connected Channel.objects.get(channel_type='T', org=self.org) twilio_channel = self.org.channels.all().first() # make channel support both sms and voice to check we clear both applications twilio_channel.role = Channel.ROLE_SEND + Channel.ROLE_RECEIVE + Channel.ROLE_ANSWER + Channel.ROLE_CALL twilio_channel.save() self.assertEqual('T', twilio_channel.channel_type) with self.settings(IS_PROD=True): with patch('temba.tests.MockTwilioClient.MockPhoneNumbers.update' ) as mock_numbers: # our twilio channel removal should fail on bad auth mock_numbers.side_effect = TwilioRestException( 401, 'http://twilio', msg='Authentication Failure', code=20003) self.client.post( reverse('channels.channel_delete', args=[twilio_channel.pk])) self.assertIsNotNone(self.org.channels.all().first()) # or other arbitrary twilio errors mock_numbers.side_effect = TwilioRestException( 400, 'http://twilio', msg='Twilio Error', code=123) self.client.post( reverse('channels.channel_delete', args=[twilio_channel.pk])) self.assertIsNotNone(self.org.channels.all().first()) # now lets be successful mock_numbers.side_effect = None self.client.post( reverse('channels.channel_delete', args=[twilio_channel.pk])) self.assertIsNone(self.org.channels.all().first()) self.assertEqual( mock_numbers.call_args_list[-1][1], dict(voice_application_sid='', sms_application_sid=''))
def test_claim(self): self.login(self.admin) claim_twilio_ms = reverse('channels.claim_twilio_messaging_service') # remove any existing channels self.org.channels.all().delete() # make sure twilio is on the claim page response = self.client.get(reverse('channels.channel_claim')) self.assertContains(response, "Twilio") response = self.client.get(claim_twilio_ms) self.assertEqual(response.status_code, 302) response = self.client.get(claim_twilio_ms, follow=True) self.assertEqual(response.request['PATH_INFO'], reverse('orgs.org_twilio_connect')) twilio_config = dict() twilio_config[ACCOUNT_SID] = 'account-sid' twilio_config[ACCOUNT_TOKEN] = 'account-token' twilio_config[APPLICATION_SID] = 'TwilioTestSid' self.org.config = json.dumps(twilio_config) self.org.save() response = self.client.get(reverse('channels.channel_claim')) self.assertContains(response, claim_twilio_ms) response = self.client.get(claim_twilio_ms) self.assertTrue('account_trial' in response.context) self.assertFalse(response.context['account_trial']) with patch('temba.orgs.models.Org.get_twilio_client' ) as mock_get_twilio_client: mock_get_twilio_client.return_value = None response = self.client.get(claim_twilio_ms) self.assertRedirects(response, reverse('orgs.org_twilio_connect')) mock_get_twilio_client.side_effect = TwilioRestException( 401, 'http://twilio', msg='Authentication Failure', code=20003) response = self.client.get(claim_twilio_ms) self.assertRedirects(response, reverse('orgs.org_twilio_connect')) with patch( 'temba.tests.MockTwilioClient.MockAccounts.get') as mock_get: mock_get.return_value = MockTwilioClient.MockAccount('Trial') response = self.client.get(claim_twilio_ms) self.assertTrue('account_trial' in response.context) self.assertTrue(response.context['account_trial']) response = self.client.get(claim_twilio_ms) self.assertEqual(response.context['form'].fields['country'].choices, list(TWILIO_SUPPORTED_COUNTRIES)) self.assertContains(response, "icon-channel-twilio") response = self.client.post(claim_twilio_ms, dict()) self.assertTrue(response.context['form'].errors) response = self.client.post( claim_twilio_ms, dict(country='US', messaging_service_sid='MSG-SERVICE-SID')) channel = self.org.channels.get() self.assertRedirects( response, reverse('channels.channel_configuration', args=[channel.pk])) self.assertEqual(channel.channel_type, "TMS") channel_config = channel.config_json() self.assertEqual(channel_config['messaging_service_sid'], 'MSG-SERVICE-SID') self.assertTrue(channel_config['account_sid']) self.assertTrue(channel_config['auth_token'])
def make_twilio_request(method, uri, **kwargs): """ Make a request to Twilio. Throws an error :return: a requests-like HTTP response :rtype: :class:`RequestsResponse` :raises TwilioRestException: if the response is a 400 or 500-level response. """ headers = kwargs.get("headers", {}) user_agent = "twilio-python/%s (Python %s)" % ( twilio.__version__, platform.python_version(), ) headers["User-Agent"] = user_agent headers["Accept-Charset"] = "utf-8" if method == "POST" and "Content-Type" not in headers: headers["Content-Type"] = "application/x-www-form-urlencoded" kwargs["headers"] = headers if "Accept" not in headers: headers["Accept"] = "application/json" uri += ".json" resp = make_request(method, uri, **kwargs) if not resp.ok: try: error = json.loads(resp.content) code = error["code"] message = "%s: %s" % (code, error["message"]) except: code = None message = resp.content def red(msg): return u("\033[31m\033[49m%s\033[0m") % msg def white(msg): return u("\033[37m\033[49m%s\033[0m") % msg def blue(msg): return u("\033[34m\033[49m%s\033[0m") % msg def orange(msg): return u("\033[33m\033[49m%s\033[0m") % msg def teal(msg): return u("\033[36m\033[49m%s\033[0m") % msg # If it makes sense to print a human readable error message, try to do # it. The one problem is that someone might catch this error and try to # display the message from it to an end user. if hasattr(sys.stderr, 'isatty') and sys.stderr.isatty(): msg = red("\nHTTP Error. ") msg += white("Your request was:\n\n") msg += teal("%s %s" % (method, uri)) msg += white("\n\nTwilio returned the following information:") msg += blue("\n\n" + str(message) + "\n") if code: msg += white("\nMore information may be available here:\n\n") msg += blue("https://www.twilio.com/docs/errors/%s" % code) msg += "\n\n" else: msg = message raise TwilioRestException(resp.status_code, resp.url, msg, code) return resp
def test_claim(self): self.login(self.admin) claim_twilio_ms = reverse("channels.types.twilio_messaging_service.claim") # remove any existing channels self.org.channels.all().delete() # make sure twilio is on the claim page response = self.client.get(reverse("channels.channel_claim")) self.assertContains(response, "Twilio") response = self.client.get(claim_twilio_ms) self.assertEqual(response.status_code, 302) response = self.client.get(claim_twilio_ms, follow=True) self.assertEqual(response.request["PATH_INFO"], reverse("orgs.org_twilio_connect")) twilio_config = dict() twilio_config[ACCOUNT_SID] = "account-sid" twilio_config[ACCOUNT_TOKEN] = "account-token" twilio_config[APPLICATION_SID] = "TwilioTestSid" self.org.config = twilio_config self.org.save() response = self.client.get(reverse("channels.channel_claim")) self.assertContains(response, claim_twilio_ms) response = self.client.get(claim_twilio_ms) self.assertIn("account_trial", response.context) self.assertFalse(response.context["account_trial"]) with patch("temba.orgs.models.Org.get_twilio_client") as mock_get_twilio_client: mock_get_twilio_client.return_value = None response = self.client.get(claim_twilio_ms) self.assertRedirects(response, reverse("orgs.org_twilio_connect")) mock_get_twilio_client.side_effect = TwilioRestException( 401, "http://twilio", msg="Authentication Failure", code=20003 ) response = self.client.get(claim_twilio_ms) self.assertRedirects(response, reverse("orgs.org_twilio_connect")) with patch("temba.tests.twilio.MockTwilioClient.MockAccounts.get") as mock_get: mock_get.return_value = MockTwilioClient.MockAccount("Trial") response = self.client.get(claim_twilio_ms) self.assertIn("account_trial", response.context) self.assertTrue(response.context["account_trial"]) response = self.client.get(claim_twilio_ms) self.assertEqual(response.context["form"].fields["country"].choices, list(TWILIO_SUPPORTED_COUNTRIES)) self.assertContains(response, "icon-channel-twilio") response = self.client.post(claim_twilio_ms, dict()) self.assertTrue(response.context["form"].errors) response = self.client.post(claim_twilio_ms, dict(country="US", messaging_service_sid="MSG-SERVICE-SID")) channel = self.org.channels.get() self.assertRedirects(response, reverse("channels.channel_configuration", args=[channel.uuid])) self.assertEqual(channel.channel_type, "TMS") channel_config = channel.config self.assertEqual(channel_config["messaging_service_sid"], "MSG-SERVICE-SID") self.assertTrue(channel_config["account_sid"]) self.assertTrue(channel_config["auth_token"]) response = self.client.get(reverse("channels.channel_configuration", args=[channel.uuid])) self.assertContains(response, reverse("courier.tms", args=[channel.uuid, "receive"]))