2016-09-22 17:18:05 +01:00
|
|
|
import json
|
2016-02-17 12:57:51 +00:00
|
|
|
import logging
|
2016-06-01 15:24:19 +01:00
|
|
|
|
2021-03-10 13:55:06 +00:00
|
|
|
from requests import RequestException, request
|
|
|
|
|
|
|
|
|
|
from app.clients.sms import SmsClient, SmsClientResponseException
|
2016-02-17 12:57:51 +00:00
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2016-04-05 14:39:59 +01:00
|
|
|
|
2016-05-27 12:28:58 +01:00
|
|
|
# Firetext will send a delivery receipt with three different status codes.
|
|
|
|
|
# The `firetext_response` maps these codes to the notification statistics status and notification status.
|
|
|
|
|
# If we get a pending (status = 2) delivery receipt followed by a declined (status = 1) delivery receipt we will set
|
|
|
|
|
# the notification status to temporary-failure rather than permanent failure.
|
|
|
|
|
# See the code in the notification_dao.update_notifications_status_by_id
|
2016-04-06 14:31:33 +01:00
|
|
|
firetext_responses = {
|
2018-02-07 17:49:15 +00:00
|
|
|
'0': 'delivered',
|
|
|
|
|
'1': 'permanent-failure',
|
|
|
|
|
'2': 'pending'
|
2016-04-06 14:31:33 +01:00
|
|
|
}
|
2016-04-05 14:39:59 +01:00
|
|
|
|
2020-04-09 17:50:05 +01:00
|
|
|
firetext_codes = {
|
2020-04-21 13:30:42 +01:00
|
|
|
# code '000' means 'No errors reported'
|
2021-03-10 10:39:17 +00:00
|
|
|
'000': {'status': 'temporary-failure', 'reason': 'No error reported'},
|
2020-04-20 18:20:01 +01:00
|
|
|
'101': {'status': 'permanent-failure', 'reason': 'Unknown Subscriber'},
|
|
|
|
|
'102': {'status': 'temporary-failure', 'reason': 'Absent Subscriber'},
|
|
|
|
|
'103': {'status': 'temporary-failure', 'reason': 'Subscriber Busy'},
|
|
|
|
|
'104': {'status': 'temporary-failure', 'reason': 'No Subscriber Memory'},
|
|
|
|
|
'201': {'status': 'permanent-failure', 'reason': 'Invalid Number'},
|
|
|
|
|
'301': {'status': 'permanent-failure', 'reason': 'SMS Not Supported'},
|
|
|
|
|
'302': {'status': 'temporary-failure', 'reason': 'SMS Not Supported'},
|
|
|
|
|
'401': {'status': 'permanent-failure', 'reason': 'Message Rejected'},
|
|
|
|
|
'900': {'status': 'temporary-failure', 'reason': 'Routing Error'},
|
2020-04-09 17:50:05 +01:00
|
|
|
}
|
|
|
|
|
|
2016-04-06 14:31:33 +01:00
|
|
|
|
2020-06-01 11:45:35 +01:00
|
|
|
def get_firetext_responses(status, detailed_status_code=None):
|
|
|
|
|
detailed_status = firetext_codes[detailed_status_code]['reason'] if firetext_codes.get(
|
|
|
|
|
detailed_status_code, None
|
|
|
|
|
) else None
|
|
|
|
|
return (firetext_responses[status], detailed_status)
|
2016-03-15 14:40:42 +00:00
|
|
|
|
|
|
|
|
|
2020-06-01 11:45:35 +01:00
|
|
|
def get_message_status_and_reason_from_firetext_code(detailed_status_code):
|
|
|
|
|
return firetext_codes[detailed_status_code]['status'], firetext_codes[detailed_status_code]['reason']
|
2020-04-09 17:50:05 +01:00
|
|
|
|
|
|
|
|
|
2016-02-17 12:57:51 +00:00
|
|
|
class FiretextClient(SmsClient):
|
|
|
|
|
'''
|
|
|
|
|
FireText sms client.
|
|
|
|
|
'''
|
|
|
|
|
|
2022-03-25 13:05:23 +00:00
|
|
|
def init_app(self, *args, **kwargs):
|
|
|
|
|
super().init_app(*args, **kwargs)
|
|
|
|
|
self.api_key = self.current_app.config.get('FIRETEXT_API_KEY')
|
|
|
|
|
self.international_api_key = self.current_app.config.get('FIRETEXT_INTERNATIONAL_API_KEY')
|
|
|
|
|
self.url = self.current_app.config.get('FIRETEXT_URL')
|
2016-02-25 11:23:04 +00:00
|
|
|
|
2022-03-24 17:31:53 +00:00
|
|
|
@property
|
|
|
|
|
def name(self):
|
|
|
|
|
return 'firetext'
|
2016-02-17 12:57:51 +00:00
|
|
|
|
2022-03-25 13:26:16 +00:00
|
|
|
def try_send_sms(self, to, content, reference, international, sender):
|
2016-02-17 12:57:51 +00:00
|
|
|
data = {
|
2021-03-16 14:53:42 +00:00
|
|
|
"apiKey": self.international_api_key if international else self.api_key,
|
2022-03-25 13:26:16 +00:00
|
|
|
"from": sender,
|
2016-02-17 12:57:51 +00:00
|
|
|
"to": to.replace('+', ''),
|
2016-03-10 15:51:11 +00:00
|
|
|
"message": content,
|
|
|
|
|
"reference": reference
|
2016-02-17 12:57:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
response = request(
|
|
|
|
|
"POST",
|
2016-09-22 17:18:05 +01:00
|
|
|
self.url,
|
2017-04-04 16:05:25 +01:00
|
|
|
data=data,
|
|
|
|
|
timeout=60
|
2016-02-17 12:57:51 +00:00
|
|
|
)
|
|
|
|
|
response.raise_for_status()
|
2016-09-22 17:18:05 +01:00
|
|
|
try:
|
|
|
|
|
json.loads(response.text)
|
|
|
|
|
if response.json()['code'] != 0:
|
2022-03-29 14:18:00 +01:00
|
|
|
raise ValueError("Expected 'code' to be '0'")
|
|
|
|
|
except (ValueError, AttributeError):
|
|
|
|
|
raise SmsClientResponseException("Invalid response JSON")
|
|
|
|
|
except RequestException:
|
|
|
|
|
raise SmsClientResponseException("Request failed")
|
2022-03-25 13:05:23 +00:00
|
|
|
|
2016-02-17 12:57:51 +00:00
|
|
|
return response
|