Esempio n. 1
0
def global_keyword_start(verified_number, text, msg, text_words,
                         open_sessions):
    outbound_metadata = MessageMetadata(workflow=WORKFLOW_KEYWORD, )

    if len(text_words) > 1:
        keyword = text_words[1]
        k = Keyword.get_keyword(verified_number.domain, keyword)
        if k:
            if not contact_can_use_keyword(verified_number, k):
                return False
            process_survey_keyword_actions(verified_number, k,
                                           text[6:].strip(), msg)
        else:
            message = get_message(MSG_KEYWORD_NOT_FOUND, verified_number,
                                  (keyword, ))
            send_sms_to_verified_number(verified_number,
                                        message,
                                        metadata=outbound_metadata)
    else:
        message = get_message(MSG_START_KEYWORD_USAGE, verified_number,
                              (text_words[0], ))
        send_sms_to_verified_number(verified_number,
                                    message,
                                    metadata=outbound_metadata)
    return True
Esempio n. 2
0
    def test_opt_out_and_opt_in(self):
        self.assertEqual(PhoneBlacklist.objects.count(), 0)

        incoming('99912345678', 'join opt-test', 'GVI')
        v = PhoneNumber.get_two_way_number('99912345678')
        self.assertIsNotNone(v)

        incoming('99912345678', 'stop', 'GVI')
        self.assertEqual(PhoneBlacklist.objects.count(), 1)
        phone_number = PhoneBlacklist.objects.get(phone_number='99912345678')
        self.assertFalse(phone_number.send_sms)
        self.assertEqual(phone_number.domain, self.domain)
        self.assertIsNotNone(phone_number.last_sms_opt_out_timestamp)
        self.assertIsNone(phone_number.last_sms_opt_in_timestamp)

        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text,
                         get_message(MSG_OPTED_OUT, context=('START', )))

        incoming('99912345678', 'start', 'GVI')
        self.assertEqual(PhoneBlacklist.objects.count(), 1)
        phone_number = PhoneBlacklist.objects.get(phone_number='99912345678')
        self.assertTrue(phone_number.send_sms)
        self.assertEqual(phone_number.domain, self.domain)
        self.assertIsNotNone(phone_number.last_sms_opt_out_timestamp)
        self.assertIsNotNone(phone_number.last_sms_opt_in_timestamp)

        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, get_message(MSG_OPTED_IN,
                                               context=('STOP', )))
Esempio n. 3
0
    def test_opt_out_and_opt_in(self):
        self.assertEqual(PhoneBlacklist.objects.count(), 0)

        incoming('99912345678', 'join opt-test', 'GVI')
        v = PhoneNumber.get_two_way_number('99912345678')
        self.assertIsNotNone(v)

        incoming('99912345678', 'stop', 'GVI')
        self.assertEqual(PhoneBlacklist.objects.count(), 1)
        phone_number = PhoneBlacklist.objects.get(phone_number='99912345678')
        self.assertFalse(phone_number.send_sms)
        self.assertEqual(phone_number.domain, self.domain)
        self.assertIsNotNone(phone_number.last_sms_opt_out_timestamp)
        self.assertIsNone(phone_number.last_sms_opt_in_timestamp)

        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, get_message(MSG_OPTED_OUT, context=('START',)))

        incoming('99912345678', 'start', 'GVI')
        self.assertEqual(PhoneBlacklist.objects.count(), 1)
        phone_number = PhoneBlacklist.objects.get(phone_number='99912345678')
        self.assertTrue(phone_number.send_sms)
        self.assertEqual(phone_number.domain, self.domain)
        self.assertIsNotNone(phone_number.last_sms_opt_out_timestamp)
        self.assertIsNotNone(phone_number.last_sms_opt_in_timestamp)

        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, get_message(MSG_OPTED_IN, context=('STOP',)))
Esempio n. 4
0
def send_verification(domain, user, phone_number, logged_event):
    backend = SQLMobileBackend.load_default_by_phone_and_domain(
        SQLMobileBackend.SMS, phone_number, domain=domain)
    reply_phone = backend.reply_to_phone_number

    subevent = logged_event.create_subevent_for_single_sms(
        user.doc_type, user.get_id)

    if reply_phone:
        message = messages.get_message(
            messages.MSG_VERIFICATION_START_WITH_REPLY,
            context=(user.raw_username, reply_phone),
            domain=domain,
            language=user.get_language_code())
    else:
        message = messages.get_message(
            messages.MSG_VERIFICATION_START_WITHOUT_REPLY,
            context=(user.raw_username, ),
            domain=domain,
            language=user.get_language_code())
    send_sms(domain,
             user,
             phone_number,
             message,
             metadata=MessageMetadata(messaging_subevent_id=subevent.pk))
    subevent.completed()
Esempio n. 5
0
def send_verification(domain, user, phone_number, logged_event):
    backend = SQLMobileBackend.load_default_by_phone_and_domain(
        SQLMobileBackend.SMS,
        phone_number,
        domain=domain
    )
    reply_phone = backend.reply_to_phone_number

    subevent = logged_event.create_subevent_for_single_sms(
        user.doc_type,
        user.get_id
    )

    if reply_phone:
        message = messages.get_message(
            messages.MSG_VERIFICATION_START_WITH_REPLY,
            context=(user.raw_username, reply_phone),
            domain=domain,
            language=user.get_language_code()
        )
    else:
        message = messages.get_message(
            messages.MSG_VERIFICATION_START_WITHOUT_REPLY,
            context=(user.raw_username,),
            domain=domain,
            language=user.get_language_code()
        )
    send_sms(domain, user, phone_number, message,
        metadata=MessageMetadata(messaging_subevent_id=subevent.pk))
    subevent.completed()
Esempio n. 6
0
def process_incoming(msg):
    v = PhoneNumber.by_phone(msg.phone_number, include_pending=True)

    if v:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.location_id = get_location_id_by_verified_number(v)
        msg.save()
    elif msg.domain_scope:
        msg.domain = msg.domain_scope
        msg.save()

    can_receive_sms = PhoneBlacklist.can_receive_sms(msg.phone_number)
    opt_in_keywords, opt_out_keywords = get_opt_keywords(msg)
    domain = v.domain if v else None

    if is_opt_message(msg.text, opt_out_keywords) and can_receive_sms:
        if PhoneBlacklist.opt_out_sms(msg.phone_number, domain=domain):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT, v, context=(opt_in_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            else:
                send_sms(msg.domain, None, msg.phone_number, text, metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords) and not can_receive_sms:
        if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain):
            text = get_message(MSG_OPTED_IN, v, context=(opt_out_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    else:
        handled = False
        is_verified = v is not None and v.verified

        if msg.domain and domain_has_privilege(msg.domain, privileges.INBOUND_SMS):
            handled = load_and_call(settings.CUSTOM_SMS_HANDLERS, v, msg.text, msg)

            if not handled and is_verified and is_contact_active(v.domain, v.owner_doc_type, v.owner_id):
                handled = load_and_call(settings.SMS_HANDLERS, v, msg.text, msg)

        if not handled and not is_verified:
            handled = process_pre_registration(msg)

            if not handled:
                handled = process_sms_registration(msg)

            if not handled:
                import verify
                verify.process_verification(v, msg)

    # If the sms queue is enabled, then the billable gets created in remove_from_queue()
    if (
        not settings.SMS_QUEUE_ENABLED and
        msg.domain and
        domain_has_privilege(msg.domain, privileges.INBOUND_SMS)
    ):
        create_billable_for_sms(msg)
Esempio n. 7
0
def process_incoming(msg):
    v = PhoneNumber.by_phone(msg.phone_number, include_pending=True)

    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.location_id = get_location_id_by_verified_number(v)
        msg.save()

    if msg.domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != msg.domain_scope:
            raise DomainScopeValidationError(
                'Attempted to simulate incoming sms from phone number not ' \
                'verified with this domain'
            )

    can_receive_sms = PhoneBlacklist.can_receive_sms(msg.phone_number)
    opt_in_keywords, opt_out_keywords = get_opt_keywords(msg)
    domain = v.domain if v else None

    if is_opt_message(msg.text, opt_out_keywords) and can_receive_sms:
        if PhoneBlacklist.opt_out_sms(msg.phone_number, domain=domain):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT, v, context=(opt_in_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            else:
                send_sms(msg.domain, None, msg.phone_number, text, metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords) and not can_receive_sms:
        if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain):
            text = get_message(MSG_OPTED_IN, v, context=(opt_out_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    elif v is not None and v.verified:
        if (
            domain_has_privilege(msg.domain, privileges.INBOUND_SMS) and
            is_contact_active(v.domain, v.owner_doc_type, v.owner_id)
        ):
            for h in settings.SMS_HANDLERS:
                try:
                    handler = to_function(h)
                except:
                    notify_exception(None, message=('error loading sms handler: %s' % h))
                    continue

                try:
                    was_handled = handler(v, msg.text, msg=msg)
                except Exception, e:
                    log_sms_exception(msg)
                    was_handled = False

                if was_handled:
                    break
Esempio n. 8
0
def process_incoming(msg, delay=True):
    v = VerifiedNumber.by_phone(msg.phone_number, include_pending=True)

    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
        contact = v.owner
        if isinstance(contact, CommCareUser) and hasattr(contact, 'location_id'):
            msg.location_id = contact.location_id
        msg.save()

    if msg.domain_scope:
        # only process messages for phones known to be associated with this domain
        if v is None or v.domain != msg.domain_scope:
            raise DomainScopeValidationError(
                'Attempted to simulate incoming sms from phone number not ' \
                'verified with this domain'
            )

    can_receive_sms = PhoneNumber.can_receive_sms(msg.phone_number)
    opt_in_keywords, opt_out_keywords = get_opt_keywords(msg)
    if is_opt_message(msg.text, opt_out_keywords) and can_receive_sms:
        if PhoneNumber.opt_out_sms(msg.phone_number):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT, v, context=(opt_in_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            else:
                send_sms(msg.domain, None, msg.phone_number, text, metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords) and not can_receive_sms:
        if PhoneNumber.opt_in_sms(msg.phone_number):
            text = get_message(MSG_OPTED_IN, v, context=(opt_out_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    elif v is not None and v.verified:
        if domain_has_privilege(msg.domain, privileges.INBOUND_SMS):
            for h in settings.SMS_HANDLERS:
                try:
                    handler = to_function(h)
                except:
                    notify_exception(None, message=('error loading sms handler: %s' % h))
                    continue

                try:
                    was_handled = handler(v, msg.text, msg=msg)
                except Exception, e:
                    log_sms_exception(msg)
                    was_handled = False

                if was_handled:
                    break
Esempio n. 9
0
def process_username(username, domain):
    from corehq.apps.users.forms import (clean_mobile_worker_username,
        get_mobile_worker_max_username_length)

    max_length = get_mobile_worker_max_username_length(domain)

    return clean_mobile_worker_username(
        domain,
        username,
        name_too_long_message=get_message(MSG_USERNAME_TOO_LONG, context=(username, max_length)),
        name_exists_message=get_message(MSG_DUPLICATE_USERNAME, context=(username,))
    )
Esempio n. 10
0
def process_username(username, domain):
    from corehq.apps.users.forms import (clean_mobile_worker_username,
        get_mobile_worker_max_username_length)

    max_length = get_mobile_worker_max_username_length(domain)

    return clean_mobile_worker_username(
        domain,
        username,
        name_too_long_message=get_message(MSG_USERNAME_TOO_LONG, context=(username, max_length)),
        name_exists_message=get_message(MSG_DUPLICATE_USERNAME, context=(username,))
    )
Esempio n. 11
0
def parse_structured_sms_named_args(args, action, verified_number=None):
    """
    Returns a dictionary of {xpath: answer}
    """
    xpath_answer = {}
    for answer in args:
        answer = answer.strip()
        answer_upper = answer.upper()
        if action.named_args_separator is not None:
            # A separator is used for naming arguments; for example, the "="
            # in "register name=joe age=25"
            answer_parts = answer.partition(action.named_args_separator)
            if answer_parts[1] != action.named_args_separator:
                error_msg = get_message(MSG_EXPECTED_NAMED_ARGS_SEPARATOR,
                                        verified_number,
                                        (action.named_args_separator, ))
                raise StructuredSMSException(response_text=error_msg)
            else:
                arg_name = answer_parts[0].upper().strip()
                xpath = action.named_args.get(arg_name, None)
                if xpath is not None:
                    if xpath in xpath_answer:
                        error_msg = get_message(MSG_MULTIPLE_ANSWERS_FOUND,
                                                verified_number, (arg_name, ))
                        raise StructuredSMSException(response_text=error_msg)

                    xpath_answer[xpath] = answer_parts[2].strip()
                else:
                    # Ignore unexpected named arguments
                    pass
        else:
            # No separator is used for naming arguments
            # for example, "update a100 b34 c5"
            matches = 0
            for k, v in action.named_args.items():
                if answer_upper.startswith(k):
                    matches += 1
                    if matches > 1:
                        error_msg = get_message(MSG_MULTIPLE_QUESTIONS_MATCH,
                                                verified_number, (answer, ))
                        raise StructuredSMSException(response_text=error_msg)

                    if v in xpath_answer:
                        error_msg = get_message(MSG_MULTIPLE_ANSWERS_FOUND,
                                                verified_number, (k, ))
                        raise StructuredSMSException(response_text=error_msg)

                    xpath_answer[v] = answer[len(k):].strip()

            if matches == 0:
                # Ignore unexpected named arguments
                pass
    return xpath_answer
Esempio n. 12
0
def _handle_structured_sms(domain,
                           args,
                           contact_id,
                           session_id,
                           first_question,
                           verified_number,
                           xpath_answer=None):

    form_complete = False
    current_question = first_question
    internal_error_msg = get_message(MSG_TOUCHFORMS_DOWN, verified_number)

    used_named_args = xpath_answer is not None
    answer_num = 0
    while not form_complete:
        if current_question.is_error:
            error_msg = current_question.text_prompt or internal_error_msg
            raise StructuredSMSException(response_text=error_msg,
                                         xformsresponse=current_question)

        xpath = current_question.event._dict["binding"]
        if used_named_args and xpath in xpath_answer:
            valid, answer, error_msg = validate_answer(current_question.event,
                                                       xpath_answer[xpath],
                                                       verified_number)
            if not valid:
                raise StructuredSMSException(response_text=error_msg,
                                             xformsresponse=current_question)
        elif not used_named_args and answer_num < len(args):
            answer = args[answer_num].strip()
            valid, answer, error_msg = validate_answer(current_question.event,
                                                       answer, verified_number)
            if not valid:
                raise StructuredSMSException(response_text=error_msg,
                                             xformsresponse=current_question)
        else:
            # We're out of arguments, so try to leave each remaining question
            # blank and continue
            answer = ""
            if current_question.event._dict.get("required", False):
                error_msg = get_message(MSG_FIELD_REQUIRED, verified_number)
                raise StructuredSMSException(response_text=error_msg,
                                             xformsresponse=current_question)

        responses = get_responses(domain, session_id, answer)
        current_question = responses[-1]

        form_complete = is_form_complete(current_question)
        answer_num += 1
Esempio n. 13
0
def send_keyword_response(vn, message_id, logged_event):
    subevent = logged_event.create_subevent_for_single_sms(
        vn.owner_doc_type, vn.owner_id)
    metadata = MessageMetadata(
        workflow=WORKFLOW_KEYWORD,
        messaging_subevent_id=subevent.pk,
    )
    message = get_message(message_id, vn)
    send_sms_to_verified_number(vn, message, metadata=metadata)
    subevent.completed()
Esempio n. 14
0
def process_username(username, domain):
    """
    Loosely based on code from apps/users/forms.py:255
    """
    from corehq.apps.users.forms import validate_username

    max_len_username = 80
    if len(username) > max_len_username:
        raise forms.ValidationError(get_message(MSG_USERNAME_TOO_LONG, context=(username, max_len_username)))
    # Check if the username contains invalid characters w/ django checker
    validate_username('*****@*****.**' % username)
    username = format_username(username, domain)
    num_couch_users = len(CouchUser.view("users/by_username",
                                         key=username,
                                         reduce=False))
    if num_couch_users > 0:
        raise forms.ValidationError(get_message(MSG_DUPLICATE_USERNAME, context=(username,)))

    return username
Esempio n. 15
0
def process_username(username, domain):
    """
    Loosely based on code from apps/users/forms.py:255
    """
    from corehq.apps.users.forms import validate_username

    max_len_username = 80
    if len(username) > max_len_username:
        raise forms.ValidationError(
            get_message(MSG_USERNAME_TOO_LONG,
                        context=(username, max_len_username)))
    # Check if the username contains invalid characters w/ django checker
    validate_username('*****@*****.**' % username)
    username = format_username(username, domain)
    num_couch_users = len(
        CouchUser.view("users/by_username", key=username, reduce=False))
    if num_couch_users > 0:
        raise forms.ValidationError(
            get_message(MSG_DUPLICATE_USERNAME, context=(username, )))

    return username
Esempio n. 16
0
def process_verification(v, msg, verification_keywords=None, create_subevent_for_inbound=True):
    verification_keywords = verification_keywords or ['123']

    logged_event = MessagingEvent.get_current_verification_event(
        v.domain, v.owner_id, v.phone_number)

    if not logged_event:
        logged_event = MessagingEvent.create_verification_event(v.domain, v.owner)

    msg.domain = v.domain
    msg.couch_recipient_doc_type = v.owner_doc_type
    msg.couch_recipient = v.owner_id

    if create_subevent_for_inbound:
        subevent = logged_event.create_subevent_for_single_sms(
            v.owner_doc_type,
            v.owner_id
        )
        subevent.completed()
        msg.messaging_subevent_id = subevent.pk

    msg.save()

    if (
        not domain_has_privilege(msg.domain, privileges.INBOUND_SMS) or
        not verification_response_ok(msg.text, verification_keywords)
    ):
        return False

    v.set_two_way()
    v.set_verified()
    v.save()

    logged_event.completed()
    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type,
        v.owner_id
    )

    message = messages.get_message(
        messages.MSG_VERIFICATION_SUCCESSFUL,
        verified_number=v
    )
    send_sms_to_verified_number(v, message,
        metadata=MessageMetadata(messaging_subevent_id=subevent.pk))
    subevent.completed()
    return True
Esempio n. 17
0
def process_verification(v, msg, verification_keywords=None, create_subevent_for_inbound=True):
    verification_keywords = verification_keywords or ['123']

    logged_event = MessagingEvent.get_current_verification_event(
        v.domain, v.owner_id, v.phone_number)

    if not logged_event:
        logged_event = MessagingEvent.create_verification_event(v.domain, v.owner)

    msg.domain = v.domain
    msg.couch_recipient_doc_type = v.owner_doc_type
    msg.couch_recipient = v.owner_id

    if create_subevent_for_inbound:
        subevent = logged_event.create_subevent_for_single_sms(
            v.owner_doc_type,
            v.owner_id
        )
        subevent.completed()
        msg.messaging_subevent_id = subevent.pk

    msg.save()

    if (
        not domain_has_privilege(msg.domain, privileges.INBOUND_SMS) or
        not verification_response_ok(msg.text, verification_keywords)
    ):
        return False

    v.set_two_way()
    v.set_verified()
    v.save()

    logged_event.completed()
    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type,
        v.owner_id
    )

    message = messages.get_message(
        messages.MSG_VERIFICATION_SUCCESSFUL,
        verified_number=v
    )
    send_sms_to_verified_number(v, message,
        metadata=MessageMetadata(messaging_subevent_id=subevent.pk))
    subevent.completed()
    return True
Esempio n. 18
0
def process_verification(v, msg):
    if not v or v.verified:
        return

    logged_event = MessagingEvent.get_current_verification_event(
        v.domain, v.owner_id, v.phone_number)

    if not logged_event:
        logged_event = MessagingEvent.create_verification_event(v.domain, v.owner)

    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type,
        v.owner_id
    )
    subevent.completed()

    msg.domain = v.domain
    msg.couch_recipient_doc_type = v.owner_doc_type
    msg.couch_recipient = v.owner_id
    msg.messaging_subevent_id = subevent.pk
    msg.save()

    if (
        not domain_has_privilege(msg.domain, privileges.INBOUND_SMS) or
        not verification_response_ok(msg.text)
    ):
        return

    v.verified = True
    v.save()

    logged_event.completed()
    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type,
        v.owner_id
    )

    message = messages.get_message(
        messages.MSG_VERIFICATION_SUCCESSFUL,
        verified_number=v
    )
    send_sms_to_verified_number(v, message,
        metadata=MessageMetadata(messaging_subevent_id=subevent.pk))
    subevent.completed()
Esempio n. 19
0
def process_verification(v, msg):
    if not v or v.verified:
        return

    logged_event = MessagingEvent.get_current_verification_event(
        v.domain, v.owner_id, v.phone_number)

    if not logged_event:
        logged_event = MessagingEvent.create_verification_event(
            v.domain, v.owner)

    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type, v.owner_id)
    subevent.completed()

    msg.domain = v.domain
    msg.couch_recipient_doc_type = v.owner_doc_type
    msg.couch_recipient = v.owner_id
    msg.messaging_subevent_id = subevent.pk
    msg.save()

    if (not domain_has_privilege(msg.domain, privileges.INBOUND_SMS)
            or not verification_response_ok(msg.text)):
        return

    v.verified = True
    v.save()

    logged_event.completed()
    subevent = logged_event.create_subevent_for_single_sms(
        v.owner_doc_type, v.owner_id)

    message = messages.get_message(messages.MSG_VERIFICATION_SUCCESSFUL,
                                   verified_number=v)
    send_sms_to_verified_number(
        v,
        message,
        metadata=MessageMetadata(messaging_subevent_id=subevent.pk))
    subevent.completed()
Esempio n. 20
0
def register_sms_user(
    username, cleaned_phone_number, domain, send_welcome_sms=False, admin_alert_emails=None
):
    try:
        user_data = {}

        username = process_username(username, domain)
        password = random_password()
        new_user = CommCareUser.create(
            domain,
            username,
            password,
            created_by=None,
            created_via=USER_CHANGE_VIA_SMS,
            metadata=user_data
        )
        new_user.add_phone_number(cleaned_phone_number)
        new_user.save()

        entry = new_user.get_or_create_phone_entry(cleaned_phone_number)
        entry.set_two_way()
        entry.set_verified()
        entry.save()

        if send_welcome_sms:
            send_sms(
                domain, None, cleaned_phone_number,
                get_message(MSG_REGISTRATION_WELCOME_MOBILE_WORKER, domain=domain)
            )
        if admin_alert_emails:
            send_admin_registration_alert(domain, admin_alert_emails, new_user)
    except ValidationError as e:
        send_sms(domain, None, cleaned_phone_number, e.messages[0])
        return False
    else:
        return True
Esempio n. 21
0
def form_session_handler(verified_number, 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(verified_number.owner_id):
        if toggles.ONE_PHONE_NUMBER_MULTIPLE_CONTACTS.enabled(
                verified_number.domain):
            channel = get_channel_for_contact(verified_number.owner_id,
                                              verified_number.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 session.connection_id != verified_number.owner_id:
                    notify_error(
                        "SMS response contact does not match open session contact",
                        details={
                            "session_id": session.session_id,
                            "phone_number_id": verified_number.couch_id,
                            "message_id": msg.couch_id
                        })
                    session.mark_completed(
                        False)  # this will also release the channel
                    session.save()
                    send_sms_to_verified_number(
                        verified_number,
                        get_message(MSG_GENERIC_ERROR, verified_number))
                    return True
                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(
                verified_number.domain, verified_number.owner_id)
            if multiple:
                send_sms_to_verified_number(
                    verified_number,
                    get_message(MSG_GENERIC_ERROR, verified_number))
                return True

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

            subevent = session.related_subevent
            subevent_id = subevent.id if subevent else None

            # 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,
                messaging_subevent_id=subevent_id,
            )
            add_msg_tags(msg, inbound_metadata)
            msg.save()
            try:
                answer_next_question(verified_number, text, msg, session,
                                     subevent_id)
            except Exception:
                # Catch any touchforms errors
                log_sms_exception(msg)
                send_sms_to_verified_number(
                    verified_number,
                    get_message(MSG_TOUCHFORMS_DOWN, verified_number))
            return True
        else:
            return False
 def test_message_without_keyword(self):
     incoming('4444', '#update', 'TEST')
     self.assertEqual(self._get_last_outbound_message(), get_message(messages.MSG_UPDATE))
Esempio n. 23
0
    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

    app, module, form, error_occurred, error_code = get_app_module_form(
        domain, survey_keyword_action.app_id,
        survey_keyword_action.form_unique_id, logged_subevent)
    if error_occurred:
        error_msg = get_message(error_code, verified_number)
        clean_up_and_send_response(msg, contact, session, error_occurred,
                                   error_msg, verified_number, send_response,
                                   logged_event, logged_subevent)
        return False

    session, responses, error_occurred, error_code = start_session_for_structured_sms(
        domain, contact, verified_number, app, form, case_id, keyword,
        logged_subevent)
    if error_occurred:
        error_msg = get_message(error_code, verified_number)
        clean_up_and_send_response(msg, contact, session, error_occurred,
                                   error_msg, verified_number, send_response,
                                   logged_event, logged_subevent)
        return False
Esempio n. 24
0
def process_incoming(msg):
    v, has_domain_two_way_scope = get_inbound_phone_entry(msg)

    if v:
        if any_migrations_in_progress(v.domain):
            raise DelayProcessing()

        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.location_id = get_location_id_by_verified_number(v)
        msg.save()
    elif msg.domain_scope:
        if any_migrations_in_progress(msg.domain_scope):
            raise DelayProcessing()

        msg.domain = msg.domain_scope
        msg.save()

    opt_in_keywords, opt_out_keywords, pass_through_opt_in_keywords = get_opt_keywords(msg)
    domain = v.domain if v else None

    if is_opt_message(msg.text, opt_out_keywords):
        if PhoneBlacklist.opt_out_sms(msg.phone_number, domain=domain):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT, v, context=(opt_in_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain, msg.phone_number, text, msg.backend_id, metadata=metadata)
            else:
                send_sms(msg.domain, None, msg.phone_number, text, metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords):
        if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain):
            text = get_message(MSG_OPTED_IN, v, context=(opt_out_keywords[0],))
            if v:
                send_sms_to_verified_number(v, text)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain, msg.phone_number, text, msg.backend_id)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    else:
        if is_opt_message(msg.text, pass_through_opt_in_keywords):
            # Opt the phone number in, and then process the message normally
            PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain)

        handled = False
        is_two_way = v is not None and v.is_two_way

        if msg.domain and domain_has_privilege(msg.domain, privileges.INBOUND_SMS):
            handled = load_and_call(settings.CUSTOM_SMS_HANDLERS, v, msg.text, msg)

            if not handled and v and v.pending_verification:
                from . import verify
                handled = verify.process_verification(v, msg,
                    create_subevent_for_inbound=not has_domain_two_way_scope)

            if (
                not handled
                and (is_two_way or has_domain_two_way_scope)
                and is_contact_active(v.domain, v.owner_doc_type, v.owner_id)
            ):
                handled = load_and_call(settings.SMS_HANDLERS, v, msg.text, msg)

        if not handled and not is_two_way:
            handled = process_pre_registration(msg)

            if not handled:
                handled = process_sms_registration(msg)

    # If the sms queue is enabled, then the billable gets created in remove_from_queue()
    if (
        not settings.SMS_QUEUE_ENABLED and
        msg.domain and
        domain_has_privilege(msg.domain, privileges.INBOUND_SMS)
    ):
        create_billable_for_sms(msg)
Esempio n. 25
0
def process_incoming(msg):
    v = PhoneNumber.by_phone(msg.phone_number, include_pending=True)

    if v:
        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.location_id = get_location_id_by_verified_number(v)
        msg.save()
    elif msg.domain_scope:
        msg.domain = msg.domain_scope
        msg.save()

    can_receive_sms = PhoneBlacklist.can_receive_sms(msg.phone_number)
    opt_in_keywords, opt_out_keywords = get_opt_keywords(msg)
    domain = v.domain if v else None

    if is_opt_message(msg.text, opt_out_keywords) and can_receive_sms:
        if PhoneBlacklist.opt_out_sms(msg.phone_number, domain=domain):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT,
                               v,
                               context=(opt_in_keywords[0], ))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            else:
                send_sms(msg.domain,
                         None,
                         msg.phone_number,
                         text,
                         metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords) and not can_receive_sms:
        if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain):
            text = get_message(MSG_OPTED_IN,
                               v,
                               context=(opt_out_keywords[0], ))
            if v:
                send_sms_to_verified_number(v, text)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    else:
        handled = False
        is_verified = v is not None and v.verified

        if msg.domain and domain_has_privilege(msg.domain,
                                               privileges.INBOUND_SMS):
            handled = load_and_call(settings.CUSTOM_SMS_HANDLERS, v, msg.text,
                                    msg)

            if not handled and is_verified and is_contact_active(
                    v.domain, v.owner_doc_type, v.owner_id):
                handled = load_and_call(settings.SMS_HANDLERS, v, msg.text,
                                        msg)

        if not handled and not is_verified:
            handled = process_pre_registration(msg)

            if not handled:
                handled = process_sms_registration(msg)

            if not handled:
                import verify
                verify.process_verification(v, msg)

    # If the sms queue is enabled, then the billable gets created in remove_from_queue()
    if (not settings.SMS_QUEUE_ENABLED and msg.domain
            and domain_has_privilege(msg.domain, privileges.INBOUND_SMS)):
        create_billable_for_sms(msg)
Esempio n. 26
0
def process_incoming(msg):
    sms_load_counter("inbound", msg.domain)()
    v, has_domain_two_way_scope = get_inbound_phone_entry(msg)

    if v:
        if any_migrations_in_progress(v.domain):
            raise DelayProcessing()

        msg.couch_recipient_doc_type = v.owner_doc_type
        msg.couch_recipient = v.owner_id
        msg.domain = v.domain
        msg.location_id = get_location_id_by_verified_number(v)
        msg.save()
    elif msg.domain_scope:
        if any_migrations_in_progress(msg.domain_scope):
            raise DelayProcessing()

        msg.domain = msg.domain_scope
        msg.save()

    opt_in_keywords, opt_out_keywords, pass_through_opt_in_keywords = get_opt_keywords(
        msg)
    domain = v.domain if v else None

    if is_opt_message(msg.text, opt_out_keywords):
        if PhoneBlacklist.opt_out_sms(msg.phone_number, domain=domain):
            metadata = MessageMetadata(ignore_opt_out=True)
            text = get_message(MSG_OPTED_OUT,
                               v,
                               context=(opt_in_keywords[0], ))
            if v:
                send_sms_to_verified_number(v, text, metadata=metadata)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain,
                                      msg.phone_number,
                                      text,
                                      msg.backend_id,
                                      metadata=metadata)
            else:
                send_sms(msg.domain,
                         None,
                         msg.phone_number,
                         text,
                         metadata=metadata)
    elif is_opt_message(msg.text, opt_in_keywords):
        if PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain):
            text = get_message(MSG_OPTED_IN,
                               v,
                               context=(opt_out_keywords[0], ))
            if v:
                send_sms_to_verified_number(v, text)
            elif msg.backend_id:
                send_sms_with_backend(msg.domain, msg.phone_number, text,
                                      msg.backend_id)
            else:
                send_sms(msg.domain, None, msg.phone_number, text)
    else:
        if is_opt_message(msg.text, pass_through_opt_in_keywords):
            # Opt the phone number in, and then process the message normally
            PhoneBlacklist.opt_in_sms(msg.phone_number, domain=domain)

        handled = False
        is_two_way = v is not None and v.is_two_way

        if msg.domain and domain_has_privilege(msg.domain,
                                               privileges.INBOUND_SMS):
            if v and v.pending_verification:
                from . import verify
                handled = verify.process_verification(
                    v,
                    msg,
                    create_subevent_for_inbound=not has_domain_two_way_scope)

            if ((is_two_way or has_domain_two_way_scope) and is_contact_active(
                    v.domain, v.owner_doc_type, v.owner_id)):
                handled = load_and_call(settings.SMS_HANDLERS, v, msg.text,
                                        msg)

        if not handled and not is_two_way:
            handled = process_pre_registration(msg)

            if not handled:
                handled = process_sms_registration(msg)

    # If the sms queue is enabled, then the billable gets created in remove_from_queue()
    if (not settings.SMS_QUEUE_ENABLED and msg.domain
            and domain_has_privilege(msg.domain, privileges.INBOUND_SMS)):
        create_billable_for_sms(msg)
Esempio n. 27
0
def process_sms_registration(msg):
    """
    This method handles registration via sms.
    Returns True if a contact was registered, False if not.

    To have a case register itself, do the following:

        1) Select "Enable Case Registration Via SMS" in project settings, and fill in the
        associated Case Registration settings.

        2) Text in "join <domain>", where <domain> is the domain to join. If the sending
        number does not exist in the system, a case will be registered tied to that number.
        The "join" keyword can be any keyword in REGISTRATION_KEYWORDS. This is meant to
        support multiple translations.

    To have a mobile worker register itself, do the following:

        1) Select "Enable Mobile Worker Registration via SMS" in project settings.

        2) Text in "join <domain> worker <username>", where <domain> is the domain to join and <username> is the
        requested username.  If the username doesn't exist it will be created, otherwise the registration will error.
        If the username argument is not specified, the username will be the mobile number

        The "join" and "worker" keywords can be any keyword in REGISTRATION_KEYWORDS and
        REGISTRATION_MOBILE_WORKER_KEYWORDS, respectively. This is meant to support multiple
        translations.
    """
    registration_processed = False
    text_words = msg.text.upper().split()
    keyword1 = text_words[0] if len(text_words) > 0 else ""
    keyword2 = text_words[1].lower() if len(text_words) > 1 else ""
    keyword3 = text_words[2] if len(text_words) > 2 else ""
    keyword4 = text_words[3] if len(text_words) > 3 else ""
    cleaned_phone_number = strip_plus(msg.phone_number)
    if is_registration_text(msg.text) and keyword2 != "":
        domain = Domain.get_by_name(keyword2, strict=True)
        if domain is not None:
            if domain_has_privilege(domain, privileges.INBOUND_SMS):
                if keyword3 in REGISTRATION_MOBILE_WORKER_KEYWORDS and domain.sms_mobile_worker_registration_enabled:
                    if keyword4 != '':
                        username = keyword4
                    else:
                        username = cleaned_phone_number
                    try:
                        user_data = {}

                        invitation = SelfRegistrationInvitation.by_phone(msg.phone_number)
                        if invitation:
                            invitation.completed()
                            user_data = invitation.custom_user_data

                        username = process_username(username, domain)
                        password = random_password()
                        new_user = CommCareUser.create(domain.name, username, password, user_data=user_data)
                        new_user.add_phone_number(cleaned_phone_number)
                        new_user.save_verified_number(domain.name, cleaned_phone_number, True, None)
                        new_user.save()
                        registration_processed = True

                        if domain.enable_registration_welcome_sms_for_mobile_worker:
                            send_sms(domain.name, None, cleaned_phone_number,
                                     get_message(MSG_REGISTRATION_WELCOME_MOBILE_WORKER, domain=domain.name))
                    except ValidationError as e:
                        send_sms(domain.name, None, cleaned_phone_number, e.messages[0])

                elif domain.sms_case_registration_enabled:
                    register_sms_contact(
                        domain=domain.name,
                        case_type=domain.sms_case_registration_type,
                        case_name="unknown",
                        user_id=domain.sms_case_registration_user_id,
                        contact_phone_number=cleaned_phone_number,
                        contact_phone_number_is_verified="1",
                        owner_id=domain.sms_case_registration_owner_id,
                    )
                    registration_processed = True
                    if domain.enable_registration_welcome_sms_for_case:
                        send_sms(domain.name, None, cleaned_phone_number,
                                 get_message(MSG_REGISTRATION_WELCOME_CASE, domain=domain.name))
            msg.domain = domain.name
            msg.save()

    return registration_processed
 def test_message_with_invalid_site_code(self):
     incoming('4444', '#update location notexists', 'TEST')
     self.assertEqual(
         self._get_last_outbound_message(),
         get_message(messages.MSG_UPDATE_LOCATION_SITE_CODE_NOT_FOUND, context=['notexists'])
     )
 def test_message_with_invalid_site_code(self):
     incoming('4444', '#update location notexists', 'TEST')
     self.assertEqual(
         self._get_last_outbound_message(),
         get_message(messages.MSG_UPDATE_LOCATION_SITE_CODE_NOT_FOUND,
                     context=['notexists']))
 def test_valid_message(self):
     incoming('4444', '#update location site_code', 'TEST')
     self.assertEqual(self._get_last_outbound_message(),
                      get_message(messages.MSG_UPDATE_LOCATION_SUCCESS))
     user = CommCareUser.get(docid=self.user.get_id)
     self.assertEqual(user.location_id, self.location.get_id)
 def test_message_without_site_code(self):
     incoming('4444', '#update location', 'TEST')
     self.assertEqual(self._get_last_outbound_message(),
                      get_message(messages.MSG_UPDATE_LOCATION_SYNTAX))
 def test_with_invalid_action(self):
     incoming('4444', '#update notexists', 'TEST')
     self.assertEqual(self._get_last_outbound_message(),
                      get_message(messages.MSG_UPDATE_UNRECOGNIZED_ACTION))
 def test_message_without_keyword(self):
     incoming('4444', '#update', 'TEST')
     self.assertEqual(self._get_last_outbound_message(),
                      get_message(messages.MSG_UPDATE))
 def test_with_invalid_action(self):
     incoming('4444', '#update notexists', 'TEST')
     self.assertEqual(self._get_last_outbound_message(), get_message(messages.MSG_UPDATE_UNRECOGNIZED_ACTION))
Esempio n. 35
0
def global_keyword_unknown(verified_number, text, msg, text_words,
                           open_sessions):
    message = get_message(MSG_UNKNOWN_GLOBAL_KEYWORD, verified_number,
                          (text_words[0], ))
    send_sms_to_verified_number(verified_number, message)
    return True
 def test_message_without_site_code(self):
     incoming('4444', '#update location', 'TEST')
     self.assertEqual(self._get_last_outbound_message(), get_message(messages.MSG_UPDATE_LOCATION_SYNTAX))
Esempio n. 37
0
def process_sms_registration(msg):
    """
    This method handles registration via sms.
    Returns True if a contact was registered, False if not.

    To have a case register itself, do the following:

        1) Select "Enable Case Registration Via SMS" in project settings, and fill in the
        associated Case Registration settings.

        2) Text in "join <domain>", where <domain> is the domain to join. If the sending
        number does not exist in the system, a case will be registered tied to that number.
        The "join" keyword can be any keyword in REGISTRATION_KEYWORDS. This is meant to
        support multiple translations.

    To have a mobile worker register itself, do the following:

        1) Select "Enable Mobile Worker Registration via SMS" in project settings.

        2) Text in "join <domain> worker <username>", where <domain> is the domain to join and <username> is the
        requested username.  If the username doesn't exist it will be created, otherwise the registration will error.
        If the username argument is not specified, the username will be the mobile number

        The "join" and "worker" keywords can be any keyword in REGISTRATION_KEYWORDS and
        REGISTRATION_MOBILE_WORKER_KEYWORDS, respectively. This is meant to support multiple
        translations.
    """
    registration_processed = False
    text_words = msg.text.upper().split()
    keyword1 = text_words[0] if len(text_words) > 0 else ""
    keyword2 = text_words[1].lower() if len(text_words) > 1 else ""
    keyword3 = text_words[2] if len(text_words) > 2 else ""
    keyword4 = text_words[3] if len(text_words) > 3 else ""
    cleaned_phone_number = strip_plus(msg.phone_number)
    if is_registration_text(msg.text) and keyword2 != "":
        domain_name = keyword2

        if any_migrations_in_progress(domain_name):
            raise DelayProcessing()

        domain_obj = Domain.get_by_name(domain_name, strict=True)

        if domain_obj is not None:
            if domain_has_privilege(domain_obj, privileges.INBOUND_SMS):
                if (keyword3 in REGISTRATION_MOBILE_WORKER_KEYWORDS
                        and domain_obj.sms_mobile_worker_registration_enabled):
                    if keyword4 != '':
                        username = keyword4
                    else:
                        username = cleaned_phone_number
                    try:
                        user_data = {}

                        invitation = SelfRegistrationInvitation.by_phone(
                            msg.phone_number)
                        if invitation:
                            invitation.completed()
                            user_data = invitation.custom_user_data

                        username = process_username(username, domain_obj)
                        password = random_password()
                        new_user = CommCareUser.create(domain_obj.name,
                                                       username,
                                                       password,
                                                       user_data=user_data)
                        new_user.add_phone_number(cleaned_phone_number)
                        new_user.save()

                        entry = new_user.get_or_create_phone_entry(
                            cleaned_phone_number)
                        entry.set_two_way()
                        entry.set_verified()
                        entry.save()
                        registration_processed = True

                        if domain_obj.enable_registration_welcome_sms_for_mobile_worker:
                            send_sms(
                                domain_obj.name, None, cleaned_phone_number,
                                get_message(
                                    MSG_REGISTRATION_WELCOME_MOBILE_WORKER,
                                    domain=domain_obj.name))
                    except ValidationError as e:
                        send_sms(domain_obj.name, None, cleaned_phone_number,
                                 e.messages[0])

                elif domain_obj.sms_case_registration_enabled:
                    register_sms_contact(
                        domain=domain_obj.name,
                        case_type=domain_obj.sms_case_registration_type,
                        case_name="unknown",
                        user_id=domain_obj.sms_case_registration_user_id,
                        contact_phone_number=cleaned_phone_number,
                        contact_phone_number_is_verified="1",
                        owner_id=domain_obj.sms_case_registration_owner_id,
                    )
                    registration_processed = True
                    if domain_obj.enable_registration_welcome_sms_for_case:
                        send_sms(
                            domain_obj.name, None, cleaned_phone_number,
                            get_message(MSG_REGISTRATION_WELCOME_CASE,
                                        domain=domain_obj.name))
            msg.domain = domain_obj.name
            msg.save()

    return registration_processed
 def test_valid_message(self):
     incoming('4444', '#update location site_code', 'TEST')
     self.assertEqual(self._get_last_outbound_message(), get_message(messages.MSG_UPDATE_LOCATION_SUCCESS))
     user = CommCareUser.get(docid=self.user.get_id)
     self.assertEqual(user.location_id, self.location.get_id)
Esempio n. 39
0
def validate_answer(event, text, verified_number):
    text = text.strip()
    upper_text = text.upper()
    valid = False
    error_msg = ""
    if text == "" and event._dict.get("required", False):
        return (False, text, get_message(MSG_FIELD_REQUIRED, verified_number))

    # Validate select
    if event.datatype == "select":
        # Try to match on phrase (i.e., "Yes" or "No")
        choices = format_choices(event._dict["choices"])
        if upper_text in choices:
            text = str(choices[upper_text])
            valid = True
        else:
            try:
                answer = int(text)
                if answer >= 1 and answer <= len(event._dict["choices"]):
                    valid = True
                else:
                    error_msg = get_message(MSG_CHOICE_OUT_OF_RANGE,
                                            verified_number)
            except ValueError:
                error_msg = get_message(MSG_INVALID_CHOICE, verified_number)

    # Validate multiselect
    elif event.datatype == "multiselect":
        choices = format_choices(event._dict["choices"])
        max_index = len(event._dict["choices"])
        proposed_answers = text.split()
        final_answers = {}

        try:
            for answer in proposed_answers:
                upper_answer = answer.upper()
                if upper_answer in choices:
                    final_answers[str(choices[upper_answer])] = ""
                else:
                    int_answer = int(answer)
                    assert int_answer >= 1 and int_answer <= max_index
                    final_answers[str(int_answer)] = ""
            text = " ".join(final_answers)
            valid = True
        except Exception:
            error_msg = get_message(MSG_INVALID_CHOICE, verified_number)

    # Validate int
    elif event.datatype == "int":
        try:
            value = int(text)
            if value >= -2147483648 and value <= 2147483647:
                valid = True
            else:
                error_msg = get_message(MSG_INVALID_INT_RANGE, verified_number)
        except ValueError:
            error_msg = get_message(MSG_INVALID_INT, verified_number)

    # Validate float
    elif event.datatype == "float":
        try:
            float(text)
            valid = True
        except ValueError:
            error_msg = get_message(MSG_INVALID_FLOAT, verified_number)

    # Validate longint
    elif event.datatype == "longint":
        try:
            int(text)
            valid = True
        except ValueError:
            error_msg = get_message(MSG_INVALID_LONG, verified_number)

    # Validate date (Format: specified by Domain.sms_survey_date_format, default: YYYYMMDD)
    elif event.datatype == "date":
        domain_obj = Domain.get_by_name(verified_number.domain)
        df = get_date_format(domain_obj.sms_survey_date_format)

        if df.is_valid(text):
            try:
                text = df.parse(text).strftime('%Y-%m-%d')
                valid = True
            except (ValueError, TypeError):
                pass

        if not valid:
            error_msg = get_message(MSG_INVALID_DATE,
                                    verified_number,
                                    context=(df.human_readable_format, ))

    # Validate time (Format: HHMM, 24-hour)
    elif event.datatype == "time":
        try:
            assert len(text) == 4
            hour = int(text[0:2])
            minute = int(text[2:])
            assert hour >= 0 and hour <= 23
            assert minute >= 0 and minute <= 59
            text = "%s:%s" % (hour, str(minute).zfill(2))
            valid = True
        except Exception:
            error_msg = get_message(MSG_INVALID_TIME, verified_number)

    # Other question types pass
    else:
        valid = True

    return (valid, text, error_msg)