Example #1
0
def fallback_handler(v, text, msg):
    domain_obj = Domain.get_by_name(v.domain, strict=True)
    default_workflow_meta = MessageMetadata(workflow=WORKFLOW_DEFAULT, location_id=msg.location_id)
    if domain_obj.use_default_sms_response and domain_obj.default_sms_response:
        send_sms_to_verified_number(v, domain_obj.default_sms_response, metadata=default_workflow_meta)
    add_msg_tags(msg, default_workflow_meta)
    return True
Example #2
0
def fallback_handler(verified_number, text, msg):
    domain_obj = Domain.get_by_name(verified_number.domain, strict=True)

    logged_event = MessagingEvent.create_event_for_adhoc_sms(
        verified_number.domain,
        recipient=verified_number.owner,
        content_type=MessagingEvent.CONTENT_SMS,
        source=MessagingEvent.SOURCE_UNRECOGNIZED)

    inbound_subevent = logged_event.create_subevent_for_single_sms(
        verified_number.owner_doc_type, verified_number.owner_id)
    inbound_meta = MessageMetadata(workflow=WORKFLOW_DEFAULT,
                                   messaging_subevent_id=inbound_subevent.pk)
    add_msg_tags(msg, inbound_meta)

    if domain_obj.use_default_sms_response and domain_obj.default_sms_response:
        outbound_subevent = logged_event.create_subevent_for_single_sms(
            verified_number.owner_doc_type, verified_number.owner_id)
        outbound_meta = MessageMetadata(
            workflow=WORKFLOW_DEFAULT,
            location_id=msg.location_id,
            messaging_subevent_id=outbound_subevent.pk)
        send_sms_to_verified_number(verified_number,
                                    domain_obj.default_sms_response,
                                    metadata=outbound_meta)
        outbound_subevent.completed()

    inbound_subevent.completed()
    logged_event.completed()
    return True
Example #3
0
def form_session_handler(v, text, msg):
    """
    The form session handler will use the inbound text to answer the next question
    in the open SQLXformsSession for the associated contact. If no session is open,
    the handler passes. If multiple sessions are open, they are all closed and an
    error message is displayed to the user.
    """
    multiple, session = get_single_open_session_or_close_multiple(v.domain, v.owner_id)
    if multiple:
        send_sms_to_verified_number(v, get_message(MSG_MULTIPLE_SESSIONS, v))
        return True

    if session:
        # Metadata to be applied to the inbound message
        inbound_metadata = MessageMetadata(
            workflow=session.workflow,
            reminder_id=session.reminder_id,
            xforms_session_couch_id=session._id,
        )
        add_msg_tags(msg, inbound_metadata)

        try:
            answer_next_question(v, text, msg, session)
        except Exception:
            # Catch any touchforms errors
            log_sms_exception(msg)
            send_sms_to_verified_number(v, get_message(MSG_TOUCHFORMS_DOWN, v))
        return True
    else:
        return False
Example #4
0
def form_session_handler(v, text, msg):
    """
    The form session handler will use the inbound text to answer the next question
    in the open SQLXformsSession for the associated contact. If no session is open,
    the handler passes. If multiple sessions are open, they are all closed and an
    error message is displayed to the user.
    """
    multiple, session = get_single_open_session_or_close_multiple(v.domain, v.owner_id)
    if multiple:
        send_sms_to_verified_number(v, get_message(MSG_MULTIPLE_SESSIONS, v))
        return True

    if session:
        # Metadata to be applied to the inbound message
        inbound_metadata = MessageMetadata(
            workflow=session.workflow,
            reminder_id=session.reminder_id,
            xforms_session_couch_id=session._id,
        )
        add_msg_tags(msg, inbound_metadata)

        try:
            answer_next_question(v, text, msg, session)
        except Exception:
            # Catch any touchforms errors
            log_sms_exception(msg)
            send_sms_to_verified_number(v, get_message(MSG_TOUCHFORMS_DOWN, v))
        return True
    else:
        return False
Example #5
0
def forward_sms(msg, domain, verified_number, text, backend_id):
    logged_event = MessagingEvent.create_event_for_adhoc_sms(
        domain,
        recipient=verified_number.owner,
        content_type=MessagingEvent.CONTENT_SMS,
        source=MessagingEvent.SOURCE_FORWARDED)

    inbound_subevent = logged_event.create_subevent_for_single_sms(
        verified_number.owner_doc_type, verified_number.owner_id)
    inbound_meta = MessageMetadata(workflow=WORKFLOW_FORWARD,
                                   messaging_subevent_id=inbound_subevent.pk)
    add_msg_tags(msg, inbound_meta)

    outbound_subevent = logged_event.create_subevent_for_single_sms(
        verified_number.owner_doc_type, verified_number.owner_id)
    outbound_meta = MessageMetadata(workflow=WORKFLOW_FORWARD,
                                    messaging_subevent_id=outbound_subevent.pk)

    send_sms_with_backend(domain,
                          verified_number.phone_number,
                          text,
                          backend_id,
                          metadata=outbound_meta)

    outbound_subevent.completed()
    inbound_subevent.completed()
    logged_event.completed()
Example #6
0
def fallback_handler(v, text, msg):
    domain_obj = Domain.get_by_name(v.domain, strict=True)

    logged_event = MessagingEvent.create_event_for_adhoc_sms(
        v.domain, recipient=v.owner, content_type=MessagingEvent.CONTENT_SMS,
        source=MessagingEvent.SOURCE_UNRECOGNIZED)

    inbound_subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type, v.owner_id)
    inbound_meta = MessageMetadata(workflow=WORKFLOW_DEFAULT,
        messaging_subevent_id=inbound_subevent.pk)
    add_msg_tags(msg, inbound_meta)

    if domain_obj.use_default_sms_response and domain_obj.default_sms_response:
        outbound_subevent = logged_event.create_subevent_for_single_sms(
            v.owner_doc_type, v.owner_id)
        outbound_meta = MessageMetadata(workflow=WORKFLOW_DEFAULT,
            location_id=msg.location_id,
            messaging_subevent_id=outbound_subevent.pk)
        send_sms_to_verified_number(v, domain_obj.default_sms_response,
            metadata=outbound_meta)
        outbound_subevent.completed()

    inbound_subevent.completed()
    logged_event.completed()
    return True
Example #7
0
def form_session_handler(v, text, msg):
    """
    The form session handler will use the inbound text to answer the next question
    in the open SQLXformsSession for the associated contact. If no session is open,
    the handler passes. If multiple sessions are open, they are all closed and an
    error message is displayed to the user.
    """
    with critical_section_for_smsforms_sessions(v.owner_id):
        if toggles.ONE_PHONE_NUMBER_MULTIPLE_CONTACTS.enabled(v.domain):
            channel = get_channel_for_contact(v.owner_id, v.phone_number)
            running_session_info = XFormsSessionSynchronization.get_running_session_info_for_channel(
                channel)
            if running_session_info.session_id:
                session = SQLXFormsSession.by_session_id(
                    running_session_info.session_id)
                if not session.session_is_open:
                    # This should never happen. But if it does we should set the channel free
                    # and act like there was no available session
                    notify_error(
                        "The supposedly running session was not open and was released. "
                        'No known way for this to happen, so worth investigating.'
                    )
                    XFormsSessionSynchronization.clear_stale_channel_claim(
                        channel)
                    session = None
            else:
                session = None
        else:
            multiple, session = get_single_open_session_or_close_multiple(
                v.domain, v.owner_id)
            if multiple:
                send_sms_to_verified_number(
                    v, get_message(MSG_MULTIPLE_SESSIONS, v))
                return True

        if session:
            session.phone_number = v.phone_number
            session.modified_time = datetime.utcnow()
            session.save()

            # Metadata to be applied to the inbound message
            inbound_metadata = MessageMetadata(
                workflow=session.workflow,
                reminder_id=session.reminder_id,
                xforms_session_couch_id=session._id,
            )
            add_msg_tags(msg, inbound_metadata)

            try:
                answer_next_question(v, text, msg, session)
            except Exception:
                # Catch any touchforms errors
                log_sms_exception(msg)
                send_sms_to_verified_number(
                    v, get_message(MSG_TOUCHFORMS_DOWN, v))
            return True
        else:
            return False
Example #8
0
def add_keyword_metadata(msg, session):
    metadata = MessageMetadata(
        workflow=WORKFLOW_KEYWORD,
        xforms_session_couch_id=session._id if session else None,
    )

    if msg:
        add_msg_tags(msg, metadata)

    return metadata
Example #9
0
def add_keyword_metadata(msg, session):
    metadata = MessageMetadata(
        workflow=WORKFLOW_KEYWORD,
        xforms_session_couch_id=session._id if session else None,
    )

    if msg:
        add_msg_tags(msg, metadata)

    return metadata
Example #10
0
def handle_global_keywords(v, text, msg, text_words, open_sessions):
    global_keyword = text_words[0]
    global_keywords = {
        "#START": global_keyword_start,
        "#STOP": global_keyword_stop,
        "#CURRENT": global_keyword_current,
    }

    inbound_metadata = MessageMetadata(workflow=WORKFLOW_KEYWORD, )
    add_msg_tags(msg, inbound_metadata)

    fcn = global_keywords.get(global_keyword, global_keyword_unknown)
    return fcn(v, text, msg, text_words, open_sessions)
Example #11
0
def send_test_message(verified_number, text, metadata=None):
    msg = SMSLog(couch_recipient_doc_type=verified_number.owner_doc_type,
                 couch_recipient=verified_number.owner_id,
                 phone_number="+" + str(verified_number.phone_number),
                 direction=OUTGOING,
                 date=datetime.utcnow(),
                 domain=verified_number.domain,
                 text=text,
                 processed=True,
                 datetime_to_process=datetime.utcnow(),
                 queued_timestamp=datetime.utcnow())
    msg.save()
    add_msg_tags(msg, metadata)
    return True
Example #12
0
def handle_global_keywords(v, text, msg, text_words, open_sessions):
    global_keyword = text_words[0]
    global_keywords = {
        "#START": global_keyword_start,
        "#STOP": global_keyword_stop,
        "#CURRENT": global_keyword_current,
    }

    inbound_metadata = MessageMetadata(
        workflow=WORKFLOW_KEYWORD,
    )
    add_msg_tags(msg, inbound_metadata)

    fcn = global_keywords.get(global_keyword, global_keyword_unknown)
    return fcn(v, text, msg, text_words, open_sessions)
Example #13
0
def send_test_message(verified_number, text, metadata=None):
    msg = SMSLog(
        couch_recipient_doc_type=verified_number.owner_doc_type,
        couch_recipient=verified_number.owner_id,
        phone_number="+" + str(verified_number.phone_number),
        direction=OUTGOING,
        date=datetime.utcnow(),
        domain=verified_number.domain,
        text=text,
        processed=True,
        datetime_to_process=datetime.utcnow(),
        queued_timestamp=datetime.utcnow(),
    )
    msg.save()
    add_msg_tags(msg, metadata)
    return True
Example #14
0
def handle_domain_keywords(v, text, msg, text_words, sessions):
    any_session_open = len(sessions) > 0
    for survey_keyword in Keyword.get_by_domain(v.domain):
        args = split_args(text, survey_keyword)
        keyword = args[0].upper()
        if keyword == survey_keyword.keyword.upper():
            if any_session_open and not survey_keyword.override_open_sessions:
                # We don't want to override any open sessions, so just pass and
                # let the form session handler handle the message
                return False
            elif not contact_can_use_keyword(v, survey_keyword):
                # The contact type is not allowed to invoke this keyword
                return False
            else:
                inbound_metadata = MessageMetadata(workflow=WORKFLOW_KEYWORD, )
                add_msg_tags(msg, inbound_metadata)
                process_survey_keyword_actions(v, survey_keyword, text, msg)
                return True
    # No keywords matched, so pass the message onto the next handler
    return False
Example #15
0
def process_survey_keyword_actions(verified_number, survey_keyword, text, msg):
    sender = verified_number.owner
    case = None
    args = split_args(text, survey_keyword)

    logged_event = MessagingEvent.create_from_keyword(survey_keyword, sender)

    # Log a messaging subevent for the incoming message
    subevent = logged_event.create_subevent_for_single_sms(
        msg.couch_recipient_doc_type, msg.couch_recipient, completed=True)
    add_msg_tags(msg, MessageMetadata(messaging_subevent_id=subevent.pk))

    # Close any open sessions even if it's just an sms that we're
    # responding with.
    SQLXFormsSession.close_all_open_sms_sessions(verified_number.domain,
                                                 verified_number.owner_id)

    if is_commcarecase(sender):
        case = sender
        args = args[1:]
Example #16
0
def handle_domain_keywords(v, text, msg, text_words, sessions):
    any_session_open = len(sessions) > 0
    for survey_keyword in SurveyKeyword.get_all(v.domain):
        args = split_args(text, survey_keyword)
        keyword = args[0].upper()
        if keyword == survey_keyword.keyword.upper():
            if any_session_open and not survey_keyword.override_open_sessions:
                # We don't want to override any open sessions, so just pass and
                # let the form session handler handle the message
                return False
            elif not contact_can_use_keyword(v, survey_keyword):
                # The contact type is not allowed to invoke this keyword
                return False
            else:
                inbound_metadata = MessageMetadata(
                    workflow=WORKFLOW_KEYWORD,
                )
                add_msg_tags(msg, inbound_metadata)
                process_survey_keyword_actions(v, survey_keyword, text, msg)
                return True
    # No keywords matched, so pass the message onto the next handler
    return False
Example #17
0
def forward_sms(msg, domain, verified_number, text, backend_id):
    logged_event = MessagingEvent.create_event_for_adhoc_sms(
        domain, recipient=verified_number.owner,
        content_type=MessagingEvent.CONTENT_SMS,
        source=MessagingEvent.SOURCE_FORWARDED)

    inbound_subevent = logged_event.create_subevent_for_single_sms(
        verified_number.owner_doc_type, verified_number.owner_id)
    inbound_meta = MessageMetadata(workflow=WORKFLOW_FORWARD,
        messaging_subevent_id=inbound_subevent.pk)
    add_msg_tags(msg, inbound_meta)

    outbound_subevent = logged_event.create_subevent_for_single_sms(
        verified_number.owner_doc_type, verified_number.owner_id)
    outbound_meta = MessageMetadata(workflow=WORKFLOW_FORWARD,
        messaging_subevent_id=outbound_subevent.pk)

    send_sms_with_backend(domain, verified_number.phone_number, text,
        backend_id, metadata=outbound_meta)

    outbound_subevent.completed()
    inbound_subevent.completed()
    logged_event.completed()
Example #18
0
        error_occurred = True
        error_msg = get_message(MSG_TOUCHFORMS_ERROR, verified_number)

    if session is not None:
        session = XFormsSession.get(session._id)
        if session.is_open:
            session.end(False)
            session.save()

    metadata = MessageMetadata(
        workflow=WORKFLOW_KEYWORD,
        xforms_session_couch_id=session._id if session else None,
    )

    if msg:
        add_msg_tags(msg, metadata)

    if error_occurred and verified_number is not None and send_response:
        send_sms_to_verified_number(verified_number, error_msg, metadata=metadata)

    return not error_occurred

def get_question_id(xformsresponse, xpath_arg=None):
    binding = xformsresponse.event._dict.get("binding", None)
    question_id = None
    if binding:
        if xpath_arg and (binding in xpath_arg):
            question_id = xpath_arg[binding]
        else:
            question_id = binding.split("/")[-1]
    return question_id
Example #19
0
def process_survey_keyword_actions(verified_number, survey_keyword, text, msg):
    sender = verified_number.owner
    case = None
    args = split_args(text, survey_keyword)

    logged_event = MessagingEvent.create_from_keyword(survey_keyword, sender)

    # Log a messaging subevent for the incoming message
    subevent = logged_event.create_subevent_for_single_sms(
        msg.couch_recipient_doc_type,
        msg.couch_recipient,
        completed=True
    )
    add_msg_tags(msg, MessageMetadata(messaging_subevent_id=subevent.pk))

    # Close any open sessions even if it's just an sms that we're
    # responding with.
    SQLXFormsSession.close_all_open_sms_sessions(verified_number.domain,
        verified_number.owner_id)

    if is_commcarecase(sender):
        case = sender
        args = args[1:]
    elif isinstance(sender, CommCareUser):
        if keyword_uses_form_that_requires_case(survey_keyword):
            if len(args) > 1:
                external_id = args[1]
                case, matches = get_case_by_external_id(verified_number.domain,
                    external_id, sender)
                if matches == 0:
                    send_keyword_response(verified_number, MSG_CASE_NOT_FOUND, logged_event)
                    logged_event.error(MessagingEvent.ERROR_CASE_EXTERNAL_ID_NOT_FOUND)
                    return
                elif matches > 1:
                    send_keyword_response(verified_number, MSG_MULTIPLE_CASES_FOUND, logged_event)
                    logged_event.error(MessagingEvent.ERROR_MULTIPLE_CASES_WITH_EXTERNAL_ID_FOUND)
                    return
            else:
                send_keyword_response(verified_number, MSG_MISSING_EXTERNAL_ID, logged_event)
                logged_event.error(MessagingEvent.ERROR_NO_EXTERNAL_ID_GIVEN)
                return
            args = args[2:]
        else:
            args = args[1:]

    def cmp_fcn(a1, a2):
        a1_ss = (a1.action == KeywordAction.ACTION_STRUCTURED_SMS)
        a2_ss = (a2.action == KeywordAction.ACTION_STRUCTURED_SMS)
        if a1_ss and a2_ss:
            return 0
        elif a1_ss:
            return -1
        elif a2_ss:
            return 1
        else:
            return 0

    if case:
        subevent.case_id = case.case_id
        subevent.save()

    # Process structured sms actions first
    actions = sorted(survey_keyword.keywordaction_set.all(), cmp=cmp_fcn)
    for survey_keyword_action in actions:
        if survey_keyword_action.recipient == KeywordAction.RECIPIENT_SENDER:
            contact = sender
        elif survey_keyword_action.recipient == KeywordAction.RECIPIENT_OWNER:
            if is_commcarecase(sender):
                contact = get_wrapped_owner(get_owner_id(sender))
            else:
                contact = None
        elif survey_keyword_action.recipient == KeywordAction.RECIPIENT_USER_GROUP:
            try:
                contact = Group.get(survey_keyword_action.recipient_id)
                assert contact.doc_type == "Group"
                assert contact.domain == verified_number.domain
            except Exception:
                contact = None
        else:
            contact = None

        if contact is None:
            continue

        # contact can be either a user, case, group, or location
        if survey_keyword_action.action in (KeywordAction.ACTION_SMS, KeywordAction.ACTION_SMS_SURVEY):
            if isinstance(contact, Group):
                recipients = list(ScheduleInstance.expand_group(contact))
            elif isinstance(contact, SQLLocation):
                recipients = list(ScheduleInstance.expand_location_ids(contact.domain, [contact.location_id]))
            else:
                recipients = [contact]

            recipient_is_sender = survey_keyword_action.recipient == KeywordAction.RECIPIENT_SENDER

            if survey_keyword_action.action == KeywordAction.ACTION_SMS:
                content = SMSContent(message={'*': survey_keyword_action.message_content})
                content.set_context(case=case)
            elif survey_keyword_action.action == KeywordAction.ACTION_SMS_SURVEY:
                content = SMSSurveyContent(
                    form_unique_id=survey_keyword_action.form_unique_id,
                    expire_after=SQLXFormsSession.MAX_SESSION_LENGTH,
                )
                content.set_context(
                    case=case,
                    critical_section_already_acquired=recipient_is_sender,
                )
            else:
                raise ValueError("Unexpected action %s" % survey_keyword_action.action)

            for recipient in recipients:
                phone_entry = verified_number if recipient_is_sender else None
                content.send(recipient, logged_event, phone_entry=phone_entry)

        elif survey_keyword_action.action == KeywordAction.ACTION_STRUCTURED_SMS:
            res = handle_structured_sms(survey_keyword, survey_keyword_action,
                sender, verified_number, text, send_response=True, msg=msg,
                case=case, text_args=args, logged_event=logged_event)
            if not res:
                # If the structured sms processing wasn't successful, don't
                # process any of the other actions
                return
    logged_event.completed()
Example #20
0
            return 0
        elif a1_ss:
            return -1
        elif a2_ss:
            return 1
        else:
            return 0

    # Log a messaging subevent for the incoming message
    subevent = logged_event.create_subevent_for_single_sms(
        msg.couch_recipient_doc_type,
        msg.couch_recipient,
        case
    )
    subevent.completed()
    add_msg_tags(msg, MessageMetadata(messaging_subevent_id=subevent.pk))

    # Process structured sms actions first
    actions = sorted(survey_keyword.actions, cmp=cmp_fcn)
    for survey_keyword_action in actions:
        if survey_keyword_action.recipient == RECIPIENT_SENDER:
            contact = sender
        elif survey_keyword_action.recipient == RECIPIENT_OWNER:
            if sender.doc_type == "CommCareCase":
                contact = get_wrapped_owner(get_owner_id(sender))
            else:
                contact = None
        elif survey_keyword_action.recipient == RECIPIENT_USER_GROUP:
            try:
                contact = Group.get(survey_keyword_action.recipient_id)
                assert contact.doc_type == "Group"
Example #21
0
def process_survey_keyword_actions(verified_number, survey_keyword, text, msg):
    sender = verified_number.owner
    case = None
    args = split_args(text, survey_keyword)

    logged_event = MessagingEvent.create_from_keyword(survey_keyword, sender)

    # Log a messaging subevent for the incoming message
    subevent = logged_event.create_subevent_for_single_sms(
        msg.couch_recipient_doc_type,
        msg.couch_recipient
    )
    subevent.completed()
    add_msg_tags(msg, MessageMetadata(messaging_subevent_id=subevent.pk))

    # Close any open sessions even if it's just an sms that we're
    # responding with.
    SQLXFormsSession.close_all_open_sms_sessions(verified_number.domain,
        verified_number.owner_id)

    if sender.doc_type == "CommCareCase":
        case = sender
        args = args[1:]
    elif sender.doc_type == "CommCareUser":
        if keyword_uses_form_that_requires_case(survey_keyword):
            if len(args) > 1:
                external_id = args[1]
                case, matches = get_case_by_external_id(verified_number.domain,
                    external_id, sender)
                if matches == 0:
                    send_keyword_response(verified_number, MSG_CASE_NOT_FOUND, logged_event)
                    logged_event.error(MessagingEvent.ERROR_CASE_EXTERNAL_ID_NOT_FOUND)
                    return
                elif matches > 1:
                    send_keyword_response(verified_number, MSG_MULTIPLE_CASES_FOUND, logged_event)
                    logged_event.error(MessagingEvent.ERROR_MULTIPLE_CASES_WITH_EXTERNAL_ID_FOUND)
                    return
            else:
                send_keyword_response(verified_number, MSG_MISSING_EXTERNAL_ID, logged_event)
                logged_event.error(MessagingEvent.ERROR_NO_EXTERNAL_ID_GIVEN)
                return
            args = args[2:]
        else:
            args = args[1:]
    def cmp_fcn(a1, a2):
        a1_ss = (a1.action == METHOD_STRUCTURED_SMS)
        a2_ss = (a2.action == METHOD_STRUCTURED_SMS)
        if a1_ss and a2_ss:
            return 0
        elif a1_ss:
            return -1
        elif a2_ss:
            return 1
        else:
            return 0

    if case:
        subevent.case_id = case.get_id
        subevent.save()

    # Process structured sms actions first
    actions = sorted(survey_keyword.actions, cmp=cmp_fcn)
    for survey_keyword_action in actions:
        if survey_keyword_action.recipient == RECIPIENT_SENDER:
            contact = sender
        elif survey_keyword_action.recipient == RECIPIENT_OWNER:
            if sender.doc_type == "CommCareCase":
                contact = get_wrapped_owner(get_owner_id(sender))
            else:
                contact = None
        elif survey_keyword_action.recipient == RECIPIENT_USER_GROUP:
            try:
                contact = Group.get(survey_keyword_action.recipient_id)
                assert contact.doc_type == "Group"
                assert contact.domain == verified_number.domain
            except Exception:
                contact = None
        else:
            contact = None

        if contact is None:
            continue

        if survey_keyword_action.action == METHOD_SMS:
            create_immediate_reminder(contact, METHOD_SMS, 
                reminder_type=REMINDER_TYPE_KEYWORD_INITIATED,
                message=survey_keyword_action.message_content,
                case=case, logged_event=logged_event)
        elif survey_keyword_action.action == METHOD_SMS_SURVEY:
            create_immediate_reminder(contact, METHOD_SMS_SURVEY,
                reminder_type=REMINDER_TYPE_KEYWORD_INITIATED,
                form_unique_id=survey_keyword_action.form_unique_id,
                case=case, logged_event=logged_event)
        elif survey_keyword_action.action == METHOD_STRUCTURED_SMS:
            res = handle_structured_sms(survey_keyword, survey_keyword_action,
                sender, verified_number, text, send_response=True, msg=msg,
                case=case, text_args=args, logged_event=logged_event)
            if not res:
                # If the structured sms processing wasn't successful, don't
                # process any of the other actions
                return
    logged_event.completed()
Example #22
0
def handle_structured_sms(survey_keyword, survey_keyword_action, contact,
    verified_number, text, send_response=False, msg=None, case=None,
    text_args=None):

    domain = contact.domain
    contact_doc_type = contact.doc_type
    contact_id = contact._id

    if text_args is not None:
        args = text_args
    else:
        args = split_args(text, survey_keyword)
        args = args[1:]
    keyword = survey_keyword.keyword.upper()

    error_occurred = False
    error_msg = None
    session = None

    try:
        # Start the session
        app, module, form = get_form(
            survey_keyword_action.form_unique_id, include_app_module=True)

        if case:
            case_id = case._id
        elif contact_doc_type == "CommCareCase":
            case_id = contact_id
        else:
            case_id = None

        session, responses = start_session(domain, contact, app, module,
            form, case_id=case_id, yield_responses=True)
        session.workflow = WORKFLOW_KEYWORD
        session.save()
        assert len(responses) > 0, "There should be at least one response."

        first_question = responses[-1]
        if not is_form_complete(first_question):
            if survey_keyword_action.use_named_args:
                # Arguments in the sms are named
                xpath_answer = parse_structured_sms_named_args(args,
                    survey_keyword_action, verified_number)
                _handle_structured_sms(domain, args, contact_id, session,
                    first_question, verified_number, xpath_answer)
            else:
                # Arguments in the sms are not named; pass each argument to
                # each question in order
                _handle_structured_sms(domain, args, contact_id, session,
                    first_question, verified_number)

    except StructuredSMSException as sse:
        error_occurred = True
        error_msg = ""
        if sse.xformsresponse and sse.xformsresponse.event:
            xpath_arg = None
            if survey_keyword_action.use_named_args:
                xpath_arg = \
                    {v: k for k, v in survey_keyword_action.named_args.items()}
            field_name = get_question_id(sse.xformsresponse, xpath_arg)
            error_msg = get_message(MSG_FIELD_DESCRIPTOR, verified_number,
                (field_name,))
        error_msg = "%s%s" % (error_msg, sse.response_text)
    except Exception:
        notify_exception(None, message=("Could not process structured sms for"
            "contact %s, domain %s, keyword %s" % (contact_id, domain, keyword)))
        error_occurred = True
        error_msg = get_message(MSG_TOUCHFORMS_ERROR, verified_number)

    if session is not None:
        session = SQLXFormsSession.objects.get(couch_id=session._id)
        if session.is_open:
            session.end(False)
            session.save()

    metadata = MessageMetadata(
        workflow=WORKFLOW_KEYWORD,
        xforms_session_couch_id=session._id if session else None,
    )

    if msg:
        add_msg_tags(msg, metadata)

    if error_occurred and verified_number is not None and send_response:
        send_sms_to_verified_number(verified_number, error_msg, metadata=metadata)

    return not error_occurred