in api/views/phones.py [0:0]
def inbound_sms(request):
"""
Handle an inbound SMS message sent by Twilio.
The return value is TwilML Response XML that reports the error or an empty success
message.
"""
incr_if_enabled("phones_inbound_sms")
_validate_twilio_request(request)
"""
TODO: delete the message from Twilio; how to do this AFTER this request? queue?
E.g., with a django-celery task in phones.tasks:
inbound_msg_sid = request.data.get("MessageSid", None)
if inbound_msg_sid is None:
raise exceptions.ValidationError("Request missing MessageSid")
tasks._try_delete_from_twilio.delay(args=message, countdown=10)
"""
inbound_body = request.data.get("Body", None)
inbound_from = request.data.get("From", None)
inbound_to = request.data.get("To", None)
if inbound_body is None or inbound_from is None or inbound_to is None:
raise exceptions.ValidationError("Request missing From, To, Or Body.")
relay_number, real_phone = _get_phone_objects(inbound_to)
if not real_phone.user.is_active:
return response.Response(
status=200,
template_name="twiml_empty_response.xml",
)
glean_logger().log_text_received(user=real_phone.user)
_check_remaining(relay_number, "texts")
if inbound_from == real_phone.number:
prepared = False
try:
relay_number, destination_number, body = _prepare_sms_reply(
relay_number, inbound_body
)
prepared = True
except RelaySMSException as sms_exception:
_log_sms_exception("twilio", real_phone, sms_exception)
user_error_message = _get_user_error_message(real_phone, sms_exception)
twilio_client().messages.create(
from_=relay_number.number, body=user_error_message, to=real_phone.number
)
if sms_exception.status_code >= 400:
raise
if prepared:
client = twilio_client()
incr_if_enabled("phones_send_sms_reply")
success = False
try:
client.messages.create(
from_=relay_number.number, body=body, to=destination_number
)
success = True
except TwilioRestException as e:
logger.error(
"Twilio failed to send reply",
{"code": e.code, "http_status_code": e.status, "msg": e.msg},
)
if success:
relay_number.remaining_texts -= 1
relay_number.texts_forwarded += 1
relay_number.save()
return response.Response(
status=200,
template_name="twiml_empty_response.xml",
)
number_disabled = _check_disabled(relay_number, "texts")
if number_disabled:
return response.Response(
status=200,
template_name="twiml_empty_response.xml",
)
inbound_contact = _get_inbound_contact(relay_number, inbound_from)
if inbound_contact:
_check_and_update_contact(inbound_contact, "texts", relay_number)
client = twilio_client()
app = twiml_app()
incr_if_enabled("phones_outbound_sms")
body = message_body(inbound_from, inbound_body)
result = "SUCCESS"
try:
client.messages.create(
from_=relay_number.number,
body=body,
status_callback=app.sms_status_callback,
to=real_phone.number,
)
except TwilioRestException as e:
if e.code == 21610:
# User has opted out with "STOP"
# TODO: Mark RealPhone as unsubscribed?
context = {"code": e.code, "http_status_code": e.status, "msg": e.msg}
context["fxa_id"] = real_phone.user.profile.metrics_fxa_id
info_logger.info("User has blocked their Relay number", context)
result = "BLOCKED"
else:
result = "FAILED"
logger.error(
"Twilio failed to forward message",
{"code": e.code, "http_status_code": e.status, "msg": e.msg},
)
if result == "SUCCESS":
relay_number.remaining_texts -= 1
relay_number.texts_forwarded += 1
relay_number.save()
elif result == "BLOCKED":
relay_number.texts_blocked += 1
relay_number.save()
return response.Response(
status=201,
template_name="twiml_empty_response.xml",
)