def send_sms(domain, contact, phone_number, text, metadata=None): """ Sends an outbound SMS. Returns false if it fails. """ if phone_number is None: return False if isinstance(phone_number, int) or isinstance(phone_number, long): phone_number = str(phone_number) phone_number = clean_phone_number(phone_number) msg = SMSLog( domain=domain, phone_number=phone_number, direction=OUTGOING, date = datetime.utcnow(), backend_id=None, text = text ) if contact: msg.couch_recipient = contact._id msg.couch_recipient_doc_type = contact.doc_type add_msg_tags(msg, metadata) def onerror(): logging.exception("Problem sending SMS to %s" % phone_number) return queue_outgoing_sms(msg, onerror=onerror)
def send_sms(domain, contact, phone_number, text, metadata=None): """ Sends an outbound SMS. Returns false if it fails. """ if phone_number is None: return False if isinstance(phone_number, int) or isinstance(phone_number, long): phone_number = str(phone_number) phone_number = clean_phone_number(phone_number) msg = SMSLog(domain=domain, phone_number=phone_number, direction=OUTGOING, date=datetime.utcnow(), backend_id=None, text=text) if contact: msg.couch_recipient = contact._id msg.couch_recipient_doc_type = contact.doc_type add_msg_tags(msg, metadata) def onerror(): logging.exception("Problem sending SMS to %s" % phone_number) return queue_outgoing_sms(msg, onerror=onerror)
def send_sms(domain, contact, phone_number, text, metadata=None): """ Sends an outbound SMS. Returns false if it fails. """ if phone_number is None: return False if isinstance(phone_number, int) or isinstance(phone_number, long): phone_number = str(phone_number) phone_number = clean_phone_number(phone_number) msg = SMSLog( domain=domain, phone_number=phone_number, direction=OUTGOING, date = datetime.utcnow(), backend_id=None, location_id=get_location_id_by_contact(domain, contact), text = text ) if contact: msg.couch_recipient = contact._id msg.couch_recipient_doc_type = contact.doc_type add_msg_tags(msg, metadata) return queue_outgoing_sms(msg)
def incoming(phone_number, text, backend_api, timestamp=None, domain_scope=None, delay=True): """ entry point for incoming sms phone_number - originating phone number text - message content backend_api - backend ID of receiving sms backend timestamp - message received timestamp; defaults to now (UTC) domain_scope - if present, only messages from phone numbers that can be definitively linked to this domain will be processed; others will be dropped (useful to provide security when simulating incoming sms) """ phone_number = clean_phone_number(phone_number) v = VerifiedNumber.by_phone(phone_number, include_pending=True) if domain_scope: # only process messages for phones known to be associated with this domain if v is None or v.domain != domain_scope: raise RuntimeError("attempted to simulate incoming sms from phone number not verified with this domain") # Log message in message log msg = SMSLog( phone_number=phone_number, direction=INCOMING, date=timestamp or datetime.utcnow(), text=text, backend_api=backend_api, ) if v is not None and v.verified: msg.couch_recipient_doc_type = v.owner_doc_type msg.couch_recipient = v.owner_id msg.domain = v.domain msg.save() create_billable_for_sms(msg, backend_api, delay=delay) if v is not None and v.verified: for h in settings.SMS_HANDLERS: try: handler = to_function(h) except: logging.exception("error loading sms handler: %s" % h) continue try: was_handled = handler(v, text) except: logging.exception("unhandled error in sms handler %s for message [%s]" % (h, text)) was_handled = False if was_handled: break else: if not process_sms_registration(msg): import verify verify.process_verification(phone_number, text) return msg
def incoming(phone_number, text, backend_api, timestamp=None, domain_scope=None, delay=True): """ entry point for incoming sms phone_number - originating phone number text - message content backend_api - backend ID of receiving sms backend timestamp - message received timestamp; defaults to now (UTC) domain_scope - if present, only messages from phone numbers that can be definitively linked to this domain will be processed; others will be dropped (useful to provide security when simulating incoming sms) """ phone_number = clean_phone_number(phone_number) v = VerifiedNumber.by_phone(phone_number, include_pending=True) if domain_scope: # only process messages for phones known to be associated with this domain if v is None or v.domain != domain_scope: raise RuntimeError( 'attempted to simulate incoming sms from phone number not verified with this domain' ) # Log message in message log msg = SMSLog(phone_number=phone_number, direction=INCOMING, date=timestamp or datetime.utcnow(), text=text, backend_api=backend_api) if v is not None and v.verified: msg.couch_recipient_doc_type = v.owner_doc_type msg.couch_recipient = v.owner_id msg.domain = v.domain msg.save() create_billable_for_sms(msg, backend_api, delay=delay) if v is not None and v.verified: for h in settings.SMS_HANDLERS: try: handler = to_function(h) except: logging.exception('error loading sms handler: %s' % h) continue try: was_handled = handler(v, text) except: logging.exception( 'unhandled error in sms handler %s for message [%s]' % (h, text)) was_handled = False if was_handled: break else: if not process_sms_registration(msg): import verify verify.process_verification(phone_number, text) return msg
def incoming(phone_number, text, backend_api): phone_without_plus = str(phone_number) if phone_without_plus[0] == "+": phone_without_plus = phone_without_plus[1:] phone_with_plus = "+" + phone_without_plus # Circular Import from corehq.apps.reminders.models import SurveyKeyword v = VerifiedNumber.view("sms/verified_number_by_number", key=phone_without_plus, include_docs=True ).one() # Log message in message log msg = SMSLog( phone_number = phone_with_plus, direction = INCOMING, date = datetime.utcnow(), text = text, backend_api = backend_api ) if v is not None: msg.couch_recipient_doc_type = v.owner_doc_type msg.couch_recipient = v.owner_id msg.domain = v.domain msg.save() # Handle incoming sms if v is not None: session = XFormsSession.view("smsforms/open_sessions_by_connection", key=[v.domain, v.owner_id], include_docs=True).one() text_words = text.upper().split() # Respond to "#START <keyword>" command if len(text_words) > 0 and text_words[0] == "#START": if len(text_words) > 1: sk = SurveyKeyword.get_keyword(v.domain, text_words[1]) if sk is not None: if session is not None: session.end(False) session.save() start_session_from_keyword(sk, v) else: send_sms_to_verified_number(v, "Survey '" + text_words[1] + "' not found.") else: send_sms_to_verified_number(v, "Usage: #START <keyword>") # Respond to "#STOP" keyword elif len(text_words) > 0 and text_words[0] == "#STOP": if session is not None: session.end(False) session.save() # Respond to "#CURRENT" keyword elif len(text_words) > 0 and text_words[0] == "#CURRENT": if session is not None: resp = current_question(session.session_id) send_sms_to_verified_number(v, resp.event.text_prompt) # Respond to unknown command elif len(text_words) > 0 and text_words[0][0] == "#": send_sms_to_verified_number(v, "Unknown command '" + text_words[0] + "'") # If there's an open session, treat the inbound text as the answer to the next question elif session is not None: resp = current_question(session.session_id) event = resp.event valid = False error_msg = None # Validate select questions if event.datatype == "select": try: answer = int(text.strip()) if answer >= 1 and answer <= len(event._dict["choices"]): valid = True except Exception: pass if not valid: error_msg = "Invalid Response. " + event.text_prompt # For now, anything else passes else: valid = True if valid: responses = get_responses(msg) if len(responses) > 0: response_text = format_message_list(responses) send_sms_to_verified_number(v, response_text) else: send_sms_to_verified_number(v, error_msg) # Try to match the text against a keyword to start a survey elif len(text_words) > 0: sk = SurveyKeyword.get_keyword(v.domain, text_words[0]) if sk is not None: start_session_from_keyword(sk, v) else: #TODO: Registration via SMS pass