Ejemplo n.º 1
0
 def test_send_admin_registration_alert(self):
     self.domain_obj.sms_worker_registration_alert_emails = ['*****@*****.**', '*****@*****.**']
     self.domain_obj.save()
     mail.outbox = []
     incoming("+123456789", 'JOIN {} WORKER'.format(self.domain), self.backend.hq_api_id)
     self.assertEqual(len(mail.outbox), 1)
     self.assertListEqual(mail.outbox[0].recipients(), self.domain_obj.sms_worker_registration_alert_emails)
Ejemplo n.º 2
0
 def test_sms_registration_no_user(self):
     # Test with no username
     no_username_phone_number = "+99912345678"
     incoming(no_username_phone_number, 'JOIN {} WORKER'.format(self.domain), self.backend.hq_api_id)
     self.assertIsNotNone(CommCareUser.get_by_username(
         format_username(strip_plus(no_username_phone_number), self.domain)
     ))
Ejemplo n.º 3
0
    def test_incoming(self, process_sms_delay_mock, enqueue_directly_mock):
        incoming('999123', 'inbound test', self.backend.get_api_id())

        self.assertEqual(enqueue_directly_mock.call_count, 1)
        self.assertEqual(self.queued_sms_count, 1)
        self.assertEqual(self.reporting_sms_count, 0)

        queued_sms = self.get_queued_sms()
        self.assertIsNone(queued_sms.domain)
        self.assertIsNone(queued_sms.couch_recipient_doc_type)
        self.assertIsNone(queued_sms.couch_recipient)
        self.assertEqual(queued_sms.phone_number, '+999123')
        self.assertEqual(queued_sms.text, 'inbound test')
        self.assertEqual(queued_sms.processed, False)
        self.assertEqual(queued_sms.error, False)
        self.assertEqual(queued_sms.backend_api, self.backend.get_api_id())
        couch_id = queued_sms.couch_id
        self.assertIsNotNone(couch_id)
        self.assertBillableDoesNotExist(couch_id)

        process_sms(queued_sms.pk)
        self.assertEqual(self.queued_sms_count, 0)
        self.assertEqual(self.reporting_sms_count, 1)

        reporting_sms = self.get_reporting_sms()
        self.assertEqual(reporting_sms.domain, self.domain)
        self.assertEqual(reporting_sms.couch_recipient_doc_type, self.contact.doc_type)
        self.assertEqual(reporting_sms.couch_recipient, self.contact.get_id)
        self.assertEqual(reporting_sms.phone_number, '+999123')
        self.assertEqual(reporting_sms.text, 'inbound test')
        self.assertEqual(reporting_sms.processed, True)
        self.assertEqual(reporting_sms.error, False)
        self.assertEqual(reporting_sms.backend_api, self.backend.get_api_id())
        self.assertEqual(reporting_sms.couch_id, couch_id)
        self.assertBillableExists(couch_id)
    def test_other_registration_from_invite(self):
        self.domain_obj.sms_mobile_worker_registration_enabled = True
        self.domain_obj.enable_registration_welcome_sms_for_mobile_worker = True
        self.domain_obj.save()

        user_data = {'abc': 'def'}

        # Initiate Registration Workflow
        SelfRegistrationInvitation.initiate_workflow(
            self.domain,
            [SelfRegistrationUserInfo('999123', user_data)],
            app_id=self.app_id,
        )

        self.assertRegistrationInvitation(
            phone_number='999123',
            app_id=self.app_id,
            phone_type=None,
            android_only=False,
            require_email=False,
            custom_user_data=user_data,
            status=SelfRegistrationInvitation.STATUS_PENDING,
        )

        self.assertLastOutgoingSMS(
            '+999123', [_MESSAGES[MSG_MOBILE_WORKER_INVITATION_START]])

        # Choose phone type 'other'
        incoming('+999123', '2', self.backend.hq_api_id)

        self.assertRegistrationInvitation(
            phone_number='999123',
            app_id=self.app_id,
            phone_type=SelfRegistrationInvitation.PHONE_TYPE_OTHER,
            android_only=False,
            require_email=False,
            custom_user_data=user_data,
            status=SelfRegistrationInvitation.STATUS_PENDING,
        )

        self.assertLastOutgoingSMS(
            '+999123',
            [_MESSAGES[MSG_MOBILE_WORKER_JAVA_INVITATION].format(self.domain)])

        # Register over SMS
        incoming('+999123', 'JOIN {} WORKER test'.format(self.domain),
                 self.backend.hq_api_id)
        user = CommCareUser.get_by_username(
            format_username('test', self.domain))
        self.assertIsNotNone(user)
        self.assertEqual(user.user_data,
                         dict(self.default_user_data, **user_data))
        self.assertEqual(
            PhoneNumber.get_two_way_number('999123').owner_id, user.get_id)

        self.assertLastOutgoingSMS(
            '+999123', [_MESSAGES[MSG_REGISTRATION_WELCOME_MOBILE_WORKER]])

        self.assertRegistrationInvitation(
            status=SelfRegistrationInvitation.STATUS_REGISTERED, )
Ejemplo n.º 5
0
    def test_incoming(self, process_sms_delay_mock, enqueue_directly_mock):
        incoming('999123', 'inbound test', self.backend.get_api_id())

        self.assertEqual(enqueue_directly_mock.call_count, 1)
        self.assertEqual(self.queued_sms_count, 1)
        self.assertEqual(self.reporting_sms_count, 0)

        queued_sms = self.get_queued_sms()
        self.assertIsNone(queued_sms.domain)
        self.assertIsNone(queued_sms.couch_recipient_doc_type)
        self.assertIsNone(queued_sms.couch_recipient)
        self.assertEqual(queued_sms.phone_number, '+999123')
        self.assertEqual(queued_sms.text, 'inbound test')
        self.assertEqual(queued_sms.processed, False)
        self.assertEqual(queued_sms.error, False)
        self.assertEqual(queued_sms.backend_api, self.backend.get_api_id())
        couch_id = queued_sms.couch_id
        self.assertIsNotNone(couch_id)
        self.assertBillableDoesNotExist(couch_id)

        process_sms(queued_sms.pk)
        self.assertEqual(self.queued_sms_count, 0)
        self.assertEqual(self.reporting_sms_count, 1)

        reporting_sms = self.get_reporting_sms()
        self.assertEqual(reporting_sms.domain, self.domain)
        self.assertEqual(reporting_sms.couch_recipient_doc_type, self.contact.doc_type)
        self.assertEqual(reporting_sms.couch_recipient, self.contact.get_id)
        self.assertEqual(reporting_sms.phone_number, '+999123')
        self.assertEqual(reporting_sms.text, 'inbound test')
        self.assertEqual(reporting_sms.processed, True)
        self.assertEqual(reporting_sms.error, False)
        self.assertEqual(reporting_sms.backend_api, self.backend.get_api_id())
        self.assertEqual(reporting_sms.couch_id, couch_id)
        self.assertBillableExists(couch_id)
Ejemplo n.º 6
0
def message_test(request, domain, phone_number):
    if request.method == "POST":
        message = request.POST.get("message", "")
        domain_scope = None if request.couch_user.is_superuser else domain
        try:
            incoming(phone_number, message, "TEST", domain_scope=domain_scope)
        except DomainScopeValidationError:
            messages.error(
                request,
                _("Invalid phone number being simulated. You may only " \
                  "simulate SMS from verified numbers belonging to contacts " \
                  "in this domain.")
            )
        except Exception:
            notify_exception(request)
            messages.error(
                request,
                _("An error has occurred. Please try again in a few minutes " \
                  "and if the issue persists, please contact CommCareHQ " \
                  "Support.")
            )

    context = get_sms_autocomplete_context(request, domain)
    context['domain'] = domain
    context['messagelog'] = SMSLog.by_domain_dsc(domain)
    context['now'] = datetime.utcnow()
    tz = report_utils.get_timezone(request.couch_user.user_id, domain)
    context['timezone'] = tz
    context['timezone_now'] = datetime.now(tz=tz)
    context['layout_flush_content'] = True
    context['phone_number'] = phone_number
    return render(request, "sms/message_tester.html", context)
Ejemplo n.º 7
0
    def test_sms_registration_disabled(self):
        self.domain_obj.sms_mobile_worker_registration_enabled = False
        self.domain_obj.save()
        formatted_username = format_username('tester', self.domain)
        phone_number = "+9991234567"

        # Test without mobile worker registration enabled
        incoming(phone_number, 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        self.assertIsNone(CommCareUser.get_by_username(formatted_username))
Ejemplo n.º 8
0
    def test_sending_to_opted_out_number(self):
        self.assertEqual(PhoneNumber.objects.count(), 0)
        self.assertTrue(send_sms(self.domain, None, "999123456789", "hello"))

        incoming("999123456789", "stop", "GVI")
        self.assertEqual(PhoneNumber.objects.count(), 1)
        phone_number = PhoneNumber.objects.get(phone_number="999123456789")
        self.assertFalse(phone_number.send_sms)

        self.assertFalse(send_sms(self.domain, None, "999123456789", "hello"))
Ejemplo n.º 9
0
    def test_sending_to_opted_out_number(self):
        self.assertEqual(PhoneNumber.objects.count(), 0)
        self.assertTrue(send_sms(self.domain, None, "999123456789", "hello"))

        incoming("999123456789", "stop", "GVI")
        self.assertEqual(PhoneNumber.objects.count(), 1)
        phone_number = PhoneNumber.objects.get(phone_number="999123456789")
        self.assertFalse(phone_number.send_sms)

        self.assertFalse(send_sms(self.domain, None, "999123456789", "hello"))
Ejemplo n.º 10
0
    def testPartialSubmission(self):
        # Register the case
        incoming("999123", "reg pid123 1", "TEST")

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid123")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid123")
        self.assertFalse(form.partial_submission)

        case = self.get_case("pid123")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Start a modify form, and submit a partial submission with case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "2", "TEST")
        session = self.get_open_session(self.user)
        session.submit_partially_completed_forms = True
        session.include_case_updates_in_partial_submissions = True
        session.close()
        session.save()

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        self.assertFalse(session.session_is_open)
        self.assertEqual(session.submission_id, form.form_id)

        # Start a modify form, and submit a partial submission without case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "1", "TEST")
        session = self.get_open_session(self.user)
        session.submit_partially_completed_forms = True
        session.include_case_updates_in_partial_submissions = False
        session.close()
        session.save()

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        self.assertFalse(session.session_is_open)
        self.assertEqual(session.submission_id, form.form_id)
Ejemplo n.º 11
0
    def post(self, request, api_key, *args, **kwargs):
        number, text = self.get_number_and_message(request)
        if not number or not text:
            return HttpResponseBadRequest("MobileNumber or Text are missing")

        incoming(number,
                 text,
                 PushBackend.get_api_id(),
                 domain_scope=self.domain,
                 backend_id=self.backend_couch_id)
        return HttpResponse("OK")
Ejemplo n.º 12
0
    def testPartialSubmission(self):
        # Register the case
        incoming("999123", "reg pid123 1", "TEST")

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid123")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid123")
        self.assertFalse(form.partial_submission)

        case = self.get_case("pid123")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Start a modify form, and submit a partial submission with case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "2", "TEST")
        session = self.get_open_session(self.user)
        session.submit_partially_completed_forms = True
        session.include_case_updates_in_partial_submissions = True
        session.close()
        session.save()

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        self.assertFalse(session.session_is_open)
        self.assertEqual(session.submission_id, form.form_id)

        # Start a modify form, and submit a partial submission without case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "1", "TEST")
        session = self.get_open_session(self.user)
        session.submit_partially_completed_forms = True
        session.include_case_updates_in_partial_submissions = False
        session.close()
        session.save()

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        self.assertFalse(session.session_is_open)
        self.assertEqual(session.submission_id, form.form_id)
Ejemplo n.º 13
0
    def get(self, request, api_key, *args, **kwargs):
        msg = request.GET.get('msg', None)
        snr = request.GET.get('snr', None)
        # We don't have a place to put this right now, but leaving it here
        # so we remember the parameter name in case we need it later
        to = request.GET.get('to', None)

        if not msg or not snr:
            return HttpResponseBadRequest("ERROR: Missing msg or snr")

        incoming(snr, msg, SQLSMSGHBackend.get_api_id(), domain_scope=self.domain)
        return HttpResponse("")
Ejemplo n.º 14
0
    def test_sms_registration(self):
        formatted_username = format_username('tester', self.domain)
        phone_number = "+9991234567"

        incoming(phone_number, 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        self.assertIsNotNone(CommCareUser.get_by_username(formatted_username))

        # Test a duplicate registration
        prev_num_users = num_mobile_users(self.domain)
        incoming('+9991234568', 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        current_num_users = num_mobile_users(self.domain)
        self.assertEqual(prev_num_users, current_num_users)
Ejemplo n.º 15
0
    def test_other_registration_from_invite(self):
        self.domain_obj.sms_mobile_worker_registration_enabled = True
        self.domain_obj.enable_registration_welcome_sms_for_mobile_worker = True
        self.domain_obj.save()

        user_data = {'abc': 'def'}

        # Initiate Registration Workflow
        SelfRegistrationInvitation.initiate_workflow(
            self.domain,
            [SelfRegistrationUserInfo('999123', user_data)],
            app_id=self.app_id,
        )

        self.assertRegistrationInvitation(
            phone_number='999123',
            app_id=self.app_id,
            phone_type=None,
            android_only=False,
            require_email=False,
            custom_user_data=user_data,
            status=SelfRegistrationInvitation.STATUS_PENDING,
        )

        self.assertLastOutgoingSMS('+999123', [_MESSAGES[MSG_MOBILE_WORKER_INVITATION_START]])

        # Choose phone type 'other'
        incoming('+999123', '2', self.backend.hq_api_id)

        self.assertRegistrationInvitation(
            phone_number='999123',
            app_id=self.app_id,
            phone_type=SelfRegistrationInvitation.PHONE_TYPE_OTHER,
            android_only=False,
            require_email=False,
            custom_user_data=user_data,
            status=SelfRegistrationInvitation.STATUS_PENDING,
        )

        self.assertLastOutgoingSMS('+999123', [_MESSAGES[MSG_MOBILE_WORKER_JAVA_INVITATION].format(self.domain)])

        # Register over SMS
        incoming('+999123', 'JOIN {} WORKER test'.format(self.domain), self.backend.hq_api_id)
        user = CommCareUser.get_by_username(format_username('test', self.domain))
        self.assertIsNotNone(user)
        self.assertEqual(user.user_data, user_data)
        self.assertEqual(PhoneNumber.by_phone('999123').owner_id, user.get_id)

        self.assertLastOutgoingSMS('+999123', [_MESSAGES[MSG_REGISTRATION_WELCOME_MOBILE_WORKER]])

        self.assertRegistrationInvitation(
            status=SelfRegistrationInvitation.STATUS_REGISTERED,
        )
Ejemplo n.º 16
0
 def run_script(self, script):
     commands = self.parse_script(script)
     for command in commands:
         phone_number = command['phone_number']
         v = PhoneNumber.by_phone(phone_number)
         if command['direction'] == '>':
             incoming(phone_number, command['text'], v.backend_id)
         else:
             msg = self.get_last_outbound_sms(v.owner_doc_type, v.owner_id)
             self.assertEqual(msg.text, unicode(command['text']))
             self.assertEqual(strip_plus(msg.phone_number), strip_plus(phone_number))
             msg.delete()
Ejemplo n.º 17
0
    def test_opt_out_and_opt_in(self):
        self.assertEqual(PhoneNumber.objects.count(), 0)

        incoming("99912345678", "stop", "GVI")
        self.assertEqual(PhoneNumber.objects.count(), 1)
        phone_number = PhoneNumber.objects.get(phone_number="99912345678")
        self.assertFalse(phone_number.send_sms)

        incoming("99912345678", "start", "GVI")
        self.assertEqual(PhoneNumber.objects.count(), 1)
        phone_number = PhoneNumber.objects.get(phone_number="99912345678")
        self.assertTrue(phone_number.send_sms)
Ejemplo n.º 18
0
    def test_opt_out_and_opt_in(self):
        self.assertEqual(PhoneNumber.objects.count(), 0)

        incoming("99912345678", "stop", "GVI")
        self.assertEqual(PhoneNumber.objects.count(), 1)
        phone_number = PhoneNumber.objects.get(phone_number="99912345678")
        self.assertFalse(phone_number.send_sms)

        incoming("99912345678", "start", "GVI")
        self.assertEqual(PhoneNumber.objects.count(), 1)
        phone_number = PhoneNumber.objects.get(phone_number="99912345678")
        self.assertTrue(phone_number.send_sms)
Ejemplo n.º 19
0
    def post(self, request, api_key, *args, **kwargs):
        number, text = self.get_number_and_message(request)
        if not number or not text:
            return HttpResponseBadRequest("MobileNumber or Text are missing")

        incoming(
            number,
            text,
            PushBackend.get_api_id(),
            backend_id=self.backend_couch_id
        )
        return HttpResponse("OK")
Ejemplo n.º 20
0
 def run_script(self, script):
     commands = self.parse_script(script)
     for command in commands:
         phone_number = command['phone_number']
         v = PhoneNumber.get_two_way_number(phone_number)
         if command['direction'] == '>':
             incoming(phone_number, command['text'], v.backend_id)
         else:
             msg = self.get_last_outbound_sms(v.owner_doc_type, v.owner_id)
             self.assertEqual(msg.text, unicode(command['text']))
             self.assertEqual(strip_plus(msg.phone_number), strip_plus(phone_number))
             msg.delete()
Ejemplo n.º 21
0
    def testPartialSubmission(self):
        # Register the case
        incoming("999123", "reg pid123 1", "TEST")

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid123")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid123")
        self.assertFalse(form.partial_submission)

        case = self.get_case("pid123")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Start a modify form, and submit a partial submission with case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "2", "TEST")
        session = self.get_open_session(self.user)
        submit_unfinished_form(session.session_id,
                               include_case_side_effects=True)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        session = SQLXFormsSession.objects.get(pk=session.pk)
        self.assertFalse(session.is_open)
        self.assertEqual(session.submission_id, form._id)

        # Start a modify form, and submit a partial submission without case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "1", "TEST")
        session = self.get_open_session(self.user)
        submit_unfinished_form(session.session_id,
                               include_case_side_effects=False)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        session = SQLXFormsSession.objects.get(pk=session.pk)
        self.assertFalse(session.is_open)
        self.assertEqual(session.submission_id, form._id)
Ejemplo n.º 22
0
def message_test(request, domain, phone_number):
    if request.method == "POST":
        message = request.POST.get("message", "")
        incoming(phone_number, message, "TEST")
    context = get_sms_autocomplete_context(request, domain)
    context['domain'] = domain
    context['messagelog'] = SMSLog.by_domain_dsc(domain)
    context['now'] = datetime.utcnow()
    tz = report_utils.get_timezone(request.couch_user.user_id, domain)
    context['timezone'] = tz
    context['timezone_now'] = datetime.now(tz=tz)
    context['layout_flush_content'] = True
    context['phone_number'] = phone_number
    return render_to_response(request, "sms/message_tester.html", context)
Ejemplo n.º 23
0
    def testPartialSubmission(self):
        # Register the case
        incoming("999123", "reg pid123 1", "TEST")

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid123")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid123")
        self.assertFalse(form.partial_submission)

        case = self.get_case("pid123")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Start a modify form, and submit a partial submission with case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "2", "TEST")
        session = self.get_open_session(self.user)
        submit_unfinished_form(session.session_id, include_case_side_effects=True)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        session = SQLXFormsSession.objects.get(pk=session.pk)
        self.assertFalse(session.is_open)
        self.assertEqual(session.submission_id, form.form_id)

        # Start a modify form, and submit a partial submission without case side effects
        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "1", "TEST")
        session = self.get_open_session(self.user)
        submit_unfinished_form(session.session_id, include_case_side_effects=False)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "other_question", "")
        self.assertTrue(form.partial_submission)

        case = self.get_case("pid123")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        session = SQLXFormsSession.objects.get(pk=session.pk)
        self.assertFalse(session.is_open)
        self.assertEqual(session.submission_id, form.form_id)
Ejemplo n.º 24
0
    def post(self, request, api_key, *args, **kwargs):
        fromAddress = request.POST.get('fromAddress')
        toAddress = request.POST.get('toAddress')
        channel = request.POST.get('channel')
        content = request.POST.get('content')

        if channel != 'SMS':
            # We don't support any other services yet
            return HttpResponse("")

        if not fromAddress or not content:
            return HttpResponseBadRequest("ERROR: Missing fromAddress or content")

        incoming(fromAddress, content, SQLAppositBackend.get_api_id())
        return HttpResponse("")
Ejemplo n.º 25
0
def message_test(request, domain, phone_number):
    if request.method == "POST":
        message = request.POST.get("message", "")
        domain_scope = None if request.couch_user.is_superuser else domain
        incoming(phone_number, message, "TEST", domain_scope=domain_scope)

    context = get_sms_autocomplete_context(request, domain)
    context['domain'] = domain
    context['messagelog'] = SMSLog.by_domain_dsc(domain)
    context['now'] = datetime.utcnow()
    tz = report_utils.get_timezone(request.couch_user.user_id, domain)
    context['timezone'] = tz
    context['timezone_now'] = datetime.now(tz=tz)
    context['layout_flush_content'] = True
    context['phone_number'] = phone_number
    return render(request, "sms/message_tester.html", context)
Ejemplo n.º 26
0
def create_from_request(request, backend_id=None):
    """
    From an inbound request (representing an incoming message),
    create a message (log) object with the right fields populated.
    """
    sender = request.GET[InboundParams.SENDER]
    message = request.GET[InboundParams.MESSAGE]

    if len(sender) == 10:
        # add india country code
        sender = '91' + sender

    is_unicode = request.GET.get(InboundParams.DCS, "") == "8"
    if is_unicode:
        message = codecs.decode(codecs.decode(message, 'hex'), 'utf_16_be')

    backend_message_id = request.GET.get(InboundParams.MID, None)

    log = incoming(sender,
                   message,
                   SQLUnicelBackend.get_api_id(),
                   backend_message_id=backend_message_id,
                   backend_id=backend_id)

    return log
Ejemplo n.º 27
0
def message_test(request, domain, phone_number):
    if request.method == "POST":
        message = request.POST.get("message", "")
        domain_scope = None if request.couch_user.is_superuser else domain
        incoming(phone_number, message, "TEST", domain_scope=domain_scope)

    context = get_sms_autocomplete_context(request, domain)
    context["domain"] = domain
    context["messagelog"] = SMSLog.by_domain_dsc(domain)
    context["now"] = datetime.utcnow()
    tz = report_utils.get_timezone(request.couch_user.user_id, domain)
    context["timezone"] = tz
    context["timezone_now"] = datetime.now(tz=tz)
    context["layout_flush_content"] = True
    context["phone_number"] = phone_number
    return render(request, "sms/message_tester.html", context)
Ejemplo n.º 28
0
def create_from_request(request, delay=True):
    """
    From an inbound request (representing an incoming message),
    create a message (log) object with the right fields populated.
    """
    sender = request.REQUEST[InboundParams.SENDER]
    message = request.REQUEST[InboundParams.MESSAGE]
    timestamp = request.REQUEST.get(InboundParams.TIMESTAMP, "")

    if len(sender) == 10:
        # add india country code
        sender = '91' + sender

    # parse date or default to current utc time
    if timestamp:
        try:
            actual_timestamp = convert_timestamp(timestamp)
        except ValueError:
            logging.warning('could not parse unicel inbound timestamp [%s]' %
                            timestamp)
            actual_timestamp = None

    # not sure yet if this check is valid
    is_unicode = request.REQUEST.get(InboundParams.UDHI, "") == "1"
    if is_unicode:
        message = message.decode("hex").decode("utf_16_be")

    log = incoming(sender,
                   message,
                   UnicelBackend.get_api_id(),
                   timestamp=actual_timestamp,
                   delay=delay)

    return log
Ejemplo n.º 29
0
def create_from_request(request, delay=True):
    """
    From an inbound request (representing an incoming message),
    create a message (log) object with the right fields populated.
    """
    sender = request.REQUEST[InboundParams.SENDER]
    message = request.REQUEST[InboundParams.MESSAGE]
    timestamp = request.REQUEST.get(InboundParams.TIMESTAMP, "")

    if len(sender) == 10:
        # add india country code
        sender = '91' + sender

    # parse date or default to current utc time
    if timestamp:
        try:
            actual_timestamp = convert_timestamp(timestamp)
        except ValueError:
            logging.warning('could not parse unicel inbound timestamp [%s]' % timestamp)
            actual_timestamp = None

    # not sure yet if this check is valid
    is_unicode = request.REQUEST.get(InboundParams.UDHI, "") == "1"
    if is_unicode:
        message = message.decode("hex").decode("utf_16_be")

    log = incoming(sender, message, UnicelBackend.get_api_id(), timestamp=actual_timestamp, delay=delay)

    return log
Ejemplo n.º 30
0
def sms_in(request):
    """
    CommCareHQ's generic inbound sms post api, requiring an ApiUser with permission to post sms.
    The request must be a post, and must have the following post parameters:
        username - ApiUser username
        password - ApiUser password
        phone_number - phone number message was sent from
        message - text of message
    """
    backend_api = "HQ_HTTP_INBOUND"
    phone_number = request.POST.get("phone_number", None)
    message = request.POST.get("message", None)
    if phone_number is None or message is None:
        return HttpResponse("Please specify 'phone_number' and 'message' parameters.", status=400)
    else:
        incoming(phone_number, message, backend_api)
        return HttpResponse("OK")
Ejemplo n.º 31
0
    def testMultimediaSubmission(self):
        # Register the case
        incoming("999123", "reg pid123 1", "TEST")

        incoming("999123", "mod pid123", "TEST")
        incoming("999123", "1", "TEST", media_urls=['path/to/test.jpg'])
        incoming("999123", "33333333", "TEST")

        form = self.get_last_form_submission()
        self.assertEqual(list(form.attachments.keys())[0], 'test.jpg')
Ejemplo n.º 32
0
def sms_in(request):
    """
    CommCareHQ's generic inbound sms post api, requiring an ApiUser with permission to post sms.
    The request must be a post, and must have the following post parameters:
        username - ApiUser username
        password - ApiUser password
        phone_number - phone number message was sent from
        message - text of message
    """
    backend_api = "HQ_HTTP_INBOUND"
    phone_number = request.POST.get("phone_number", None)
    message = request.POST.get("message", None)
    if phone_number is None or message is None:
        return HttpResponse(
            "Please specify 'phone_number' and 'message' parameters.",
            status=400)
    else:
        incoming(phone_number, message, backend_api)
        return HttpResponse("OK")
Ejemplo n.º 33
0
    def post(self, request, api_key, *args, **kwargs):
        try:
            data = json.loads(request.body)
        except:
            return HttpResponseBadRequest(
                "Expected valid JSON as HTTP request body")

        from_number = data.get('from')
        message = data.get('message')
        message_id = data.get('messageId')

        if not from_number or not message:
            return HttpResponseBadRequest("Missing 'from' or 'message'")

        incoming(from_number,
                 message,
                 SQLAppositBackend.get_api_id(),
                 backend_message_id=message_id,
                 backend_id=self.backend_couch_id)
        return HttpResponse("")
Ejemplo n.º 34
0
    def post(self, request, api_key, *args, **kwargs):
        try:
            data = json.loads(request.body)
        except:
            return HttpResponseBadRequest("Expected valid JSON as HTTP request body")

        from_number = data.get('from')
        message = data.get('message')
        message_id = data.get('messageId')

        if not from_number or not message:
            return HttpResponseBadRequest("Missing 'from' or 'message'")

        incoming(
            from_number,
            message,
            SQLAppositBackend.get_api_id(),
            backend_message_id=message_id,
            backend_id=self.backend_couch_id
        )
        return HttpResponse("")
Ejemplo n.º 35
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',)))
Ejemplo n.º 36
0
    def test_sending_to_opted_out_number(self):
        self.assertEqual(PhoneBlacklist.objects.count(), 0)

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

        send_sms_to_verified_number(v, 'hello')
        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, 'hello')

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

        send_sms_to_verified_number(v, 'hello')
        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, 'hello')
        self.assertTrue(sms.error)
        self.assertEqual(sms.system_error_message, SMS.ERROR_PHONE_NUMBER_OPTED_OUT)

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

        send_sms_to_verified_number(v, 'hello')
        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, 'hello')
        self.assertFalse(sms.error)
        self.assertIsNone(sms.system_error_message)
Ejemplo n.º 37
0
    def test_sending_to_opted_out_number(self):
        self.assertEqual(PhoneBlacklist.objects.count(), 0)

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

        send_sms_to_verified_number(v, 'hello')
        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, 'hello')

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

        send_sms_to_verified_number(v, 'hello')
        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, 'hello')
        self.assertTrue(sms.error)
        self.assertEqual(sms.system_error_message, SMS.ERROR_PHONE_NUMBER_OPTED_OUT)

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

        send_sms_to_verified_number(v, 'hello')
        sms = self.get_last_sms('+99912345678')
        self.assertEqual(sms.direction, 'O')
        self.assertEqual(sms.text, 'hello')
        self.assertFalse(sms.error)
        self.assertIsNone(sms.system_error_message)
Ejemplo n.º 38
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', )))
Ejemplo n.º 39
0
    def get(self, request, api_key, *args, **kwargs):
        number = self.clean_value(request.GET.get("msisdn"))
        text = self.clean_value(request.GET.get("message"))
        if not number or not text:
            return HttpResponseBadRequest("MobileNumber or Text are missing")

        sms = incoming(
            number,
            text,
            StarfishBackend.get_api_id(),
            domain_scope=self.domain,
            backend_id=self.backend_couch_id,
        )
        return JsonResponse({"status": "OK", "message_id": sms.couch_id})
Ejemplo n.º 40
0
    def get(self, request, api_key, *args, **kwargs):
        number = self.clean_value(request.GET.get("msisdn"))
        text = self.clean_value(request.GET.get("message"))
        if not number or not text:
            return HttpResponseBadRequest("MobileNumber or Text are missing")

        sms = incoming(
            number,
            text,
            StarfishBackend.get_api_id(),
            domain_scope=self.domain,
            backend_id=self.backend_couch_id,
        )
        return JsonResponse({"status": "OK", "message_id": sms.couch_id})
Ejemplo n.º 41
0
    def test_multiline_message(self):
        quantities = {"fs": 100, "md": 100, "ff": 100, "pc": 100}
        message = """
            hmk
            fs 100 md 100 ff 100 pc 100
        """
        verified_number = self.user1.get_verified_number()
        msg = incoming(verified_number.phone_number, message, verified_number.backend_id)
        self.assertIsNotNone(msg)

        stock_states = StockState.objects.filter(case_id=self.facility_sp_id).values_list(
            "sql_product__code", "stock_on_hand"
        )

        for product_code, quantity in stock_states:
            self.assertEqual(quantity, quantities[product_code])
Ejemplo n.º 42
0
    def test_multiline_message(self):
        quantities = {'fs': 100, 'md': 100, 'ff': 100, 'pc': 100}
        message = """
            hmk
            fs 100 md 100 ff 100 pc 100
        """
        verified_number = get_two_way_number_for_recipient(self.user1)
        msg = incoming(verified_number.phone_number, message,
                       verified_number.backend_id)
        self.assertIsNotNone(msg)

        stock_states = StockState.objects.filter(
            case_id=self.facility_sp_id).values_list('sql_product__code',
                                                     'stock_on_hand')

        for product_code, quantity in stock_states:
            self.assertEqual(quantity, quantities[product_code])
Ejemplo n.º 43
0
def create_from_request(request):
    """
    From an inbound request (representing an incoming message),
    create a message (log) object with the right fields populated.
    """
    sender = request.GET[InboundParams.SENDER]
    message = request.GET[InboundParams.MESSAGE]

    if len(sender) == 10:
        # add india country code
        sender = '91' + sender

    is_unicode = request.GET.get(InboundParams.DCS, "") == "8"
    if is_unicode:
        message = message.decode("hex").decode("utf_16_be")

    backend_message_id = request.GET.get(InboundParams.MID, None)

    log = incoming(sender, message, SQLUnicelBackend.get_api_id(), backend_message_id=backend_message_id)

    return log
Ejemplo n.º 44
0
    def test_multiline_message(self):
        quantities = {
            'fs': 100,
            'md': 100,
            'ff': 100,
            'pc': 100
        }
        message = """
            hmk
            fs 100 md 100 ff 100 pc 100
        """
        verified_number = get_two_way_number_for_recipient(self.user1)
        msg = incoming(
            verified_number.phone_number, message, verified_number.backend_id
        )
        self.assertIsNotNone(msg)

        stock_states = StockState.objects.filter(
            case_id=self.facility_sp_id
        ).values_list('sql_product__code', 'stock_on_hand')

        for product_code, quantity in stock_states:
            self.assertEqual(quantity, quantities[product_code])
Ejemplo n.º 45
0
 def get(self, request, api_key, *args, **kwargs):
     xml = request.GET.get("xml")
     if xml is None:
         # https://classic.trumpia.com/api/inbound-push.php
         # Please note that the API server has an activity URL
         # checker in place. This URL checker will send empty HTTP
         # GETs/POSTs to see if a URL set is active. Please return a
         # status of 200OK when an empty GET/POST is received.
         return HttpResponse(status=200)
     data = parse_incoming(xml)
     phone_number = data.get("PHONENUMBER")
     text = data.get("CONTENTS")
     if not phone_number or not text:
         return HttpResponseBadRequest("PHONENUMBER or CONTENTS are missing")
     phone_number = add_nanp_prefix(phone_number)
     sms = incoming(
         phone_number,
         text,
         TrumpiaBackend.get_api_id(),
         domain_scope=self.domain,
         backend_message_id=data.get("PUSH_ID"),
         backend_id=self.backend_couch_id,
     )
     return JsonResponse({"status": "OK", "message_id": sms.couch_id})
Ejemplo n.º 46
0
    def test_sms_registration(self):
        formatted_username = format_username("tester", self.domain)

        incoming("+9991234567", "JOIN {} WORKER tester".format(self.domain), "TEST_CASE_BACKEND")
        # Test without mobile worker registration enabled
        self.assertIsNone(CommCareUser.get_by_username(formatted_username))

        # Enable mobile worker registration
        setattr(self.domain_obj, "sms_mobile_worker_registration_enabled", True)
        self.domain_obj.save()

        incoming("+9991234567", "JOIN {} WORKER tester".format(self.domain), "TEST_CASE_BACKEND")
        self.assertIsNotNone(CommCareUser.get_by_username(formatted_username))

        # Test a duplicate registration
        prev_num_users = num_mobile_users(self.domain)
        incoming("+9991234568", "JOIN {} WORKER tester".format(self.domain), "TEST_CASE_BACKEND")
        current_num_users = num_mobile_users(self.domain)
        self.assertEqual(prev_num_users, current_num_users)
Ejemplo n.º 47
0
    def test_sms_registration(self):
        formatted_username = format_username('tester', self.domain)

        # Test without mobile worker registration enabled
        incoming('+9991234567', 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        self.assertIsNone(CommCareUser.get_by_username(formatted_username))

        # Test with mobile worker registration enabled
        self.domain_obj.sms_mobile_worker_registration_enabled = True
        self.domain_obj.save()

        incoming('+9991234567', 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        self.assertIsNotNone(CommCareUser.get_by_username(formatted_username))

        # Test a duplicate registration
        prev_num_users = num_mobile_users(self.domain)
        incoming('+9991234568', 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        current_num_users = num_mobile_users(self.domain)
        self.assertEqual(prev_num_users, current_num_users)
Ejemplo n.º 48
0
    def test_sms_registration(self):
        formatted_username = format_username('tester', self.domain)

        # Test without mobile worker registration enabled
        incoming('+9991234567', 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        self.assertIsNone(CommCareUser.get_by_username(formatted_username))

        # Test with mobile worker registration enabled
        self.domain_obj.sms_mobile_worker_registration_enabled = True
        self.domain_obj.save()

        incoming('+9991234567', 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        self.assertIsNotNone(CommCareUser.get_by_username(formatted_username))

        # Test a duplicate registration
        prev_num_users = num_mobile_users(self.domain)
        incoming('+9991234568', 'JOIN {} WORKER tester'.format(self.domain), self.backend.hq_api_id)
        current_num_users = num_mobile_users(self.domain)
        self.assertEqual(prev_num_users, current_num_users)
 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))
Ejemplo n.º 52
0
    def test_all_inbound(self):
        # Mobile worker creates a case
        incoming("999123", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1234")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1234")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1234")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # now take the case away from the user
        self.update_case_owner(case, self.user3)
        case = self.get_case("pid1234")

        # then they should no longer have access
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))

        # now add access back via parent connection
        self.add_parent_access(self.user1, case)
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        form = self.get_last_form_submission()

        # Bad external id
        incoming("999123", "mod pid1235", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "mod", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        # Test validation on all fields
        incoming("999123", "Validation_Test", "TEST")
        session = self.get_open_session(self.user1)
        
        sms = self.assertLastOutboundSMSEquals(self.user1, "text")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "ab", "TEST")
        self.assertTrue(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "abc", "TEST")
        self.assertFalse(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "single select 1:a, 2:b, 3:c, 4:d.")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertTrue(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s single select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "5", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s single select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_CHOICE_OUT_OF_RANGE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2", "TEST")
        self.assertFalse(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "multi select 1:a, 2:b, 3:c, 4:d.")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_FIELD_REQUIRED))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2 x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "1 5", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "1 c", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "int")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s int" % get_message(MSG_INVALID_INT))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "50", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "float")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s float" % get_message(MSG_INVALID_FLOAT))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "21.3", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)
        
        sms = self.assertLastOutboundSMSEquals(self.user1, "long")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s long" % get_message(MSG_INVALID_LONG))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "-100", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "date")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s date" %
            get_message(MSG_INVALID_DATE, context=('YYYYMMDD',)))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "20140101", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "time")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s time" % get_message(MSG_INVALID_TIME))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2500", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s time" % get_message(MSG_INVALID_TIME))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2345", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Mobile worker creates a case via structured sms
        incoming("999123", "reg_ss pid1235 1", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your registration submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1235")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1235")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1235")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "mod_ss pid1235 b", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Bad external id
        incoming("999123", "mod_ss pid1236", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "mod_ss", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        def get_field_and_message(field_name, msg_id, additional_context=None):
            msg1 = get_message(MSG_FIELD_DESCRIPTOR, context=(field_name,))
            msg2 = get_message(msg_id, context=additional_context)
            return "%s%s" % (msg1, msg2)

        # Test validation on all fields from structured sms: positional args
        incoming("999123", "validation_test_ss_1 ab 2 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc x c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 5 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 x 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 5 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c x 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_int", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 x -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_float", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 x 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_long", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 x 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("q_date", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: positional args with custom delimiter
        incoming("999123", "validation_test_ss_2,ab,2,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,x,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,5,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 x,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 5,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,x,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_int", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,x,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_float", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,x,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_long", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,x,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("q_date", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: named args with custom delimiter
        incoming("999123", "validation_test_ss_3,arg1ab,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg2x,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg25,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 x,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 5,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg3,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg4x,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG4", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg5x,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG5", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6x,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG6", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg7x,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("ARG7", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg8x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: named args with custom delimiter and joining character
        incoming("999123", "validation_test_ss_4,arg1=ab,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=x,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=5,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 x,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 5,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=x,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG4", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=x,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG5", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=x,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG6", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=x,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("ARG7", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test leaving fields blank via structured sms
        incoming("999123", "validation_test_ss_4,arg1=abc,arg3=1 c", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", "")
        self.assertFormQuestionEquals(form, "q_float", "")
        self.assertFormQuestionEquals(form, "q_long", "")
        self.assertFormQuestionEquals(form, "q_date", "")
        self.assertFormQuestionEquals(form, "q_time", "")

        incoming("999123", "validation_test_ss_1 abc b c", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "c")
        self.assertFormQuestionEquals(form, "q_int", "")
        self.assertFormQuestionEquals(form, "q_float", "")
        self.assertFormQuestionEquals(form, "q_long", "")
        self.assertFormQuestionEquals(form, "q_date", "")
        self.assertFormQuestionEquals(form, "q_time", "")

        incoming("999123", "mod_ss_2,pid1235", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("arm", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_2,pid1235,", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("arm", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm=", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARM", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm a", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_EXPECTED_NAMED_ARGS_SEPARATOR, context=("=",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm=a,arm=b", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MULTIPLE_ANSWERS_FOUND, context=("ARM",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3 ,  pid1235  ,  arm = a", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test global keywords
        incoming("999123", "#start unknownkeyword", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_KEYWORD_NOT_FOUND, context=("UNKNOWNKEYWORD",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "#start", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_START_KEYWORD_USAGE, context=("#START",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "#unknown", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_UNKNOWN_GLOBAL_KEYWORD, context=("#UNKNOWN",)))
        self.assertNoNewSubmission(form)

        # Mobile worker creates a case
        incoming("999123", "#start reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1237")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1237")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "#start mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Bad external id
        incoming("999123", "#start mod pid1240", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "#start mod", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        # CURRENT keyword
        incoming("999123", "reg", "TEST")
        sms1 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "#CURRENT", "TEST")
        sms2 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        self.assertNotEqual(sms1.pk, sms2.pk)

        # STOP keyword
        session = self.get_open_session(self.user1)
        self.assertIsNotNone(session)
        incoming("999123", "#STOP", "TEST")
        session = self.get_open_session(self.user1)
        self.assertIsNone(session)
        self.assertNoNewSubmission(form)

        # One keyword overrides another
        incoming("999123", "reg", "TEST")
        sms1 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        self.assertNoNewSubmission(form)
        incoming("999123", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "%s Enter Study Arm 1:a, 2:b." % get_message(MSG_INVALID_CHOICE))
        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test initator filters
        case = self.get_case("pid1237")
        update_case(self.domain, case.case_id,
            case_properties={'contact_phone_number': '999124', 'contact_phone_number_is_verified': '1'})
        case = CaseAccessors(self.domain).get_case(case.case_id)

        incoming("999123", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for users")
        incoming("999123", "for_case", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Default SMS Response")

        incoming("999124", "for_case", "TEST")
        self.assertLastOutboundSMSEquals(case, "This message is for cases")
        incoming("999124", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(case, "Default SMS Response")

        # Test form over sms for case
        incoming("999124", "mod", "TEST")
        self.assertLastOutboundSMSEquals(case, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999124", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test structured sms for case
        incoming("999124", "mod_ss 2", "TEST")
        self.assertLastOutboundSMSEquals(case, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Test Auth
        incoming("999122", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, get_message(MSG_CASE_NOT_FOUND))

        # Test notifying others
        incoming("999124", "for_owner", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the case owner")

        incoming("999124", "for_group", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the group")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for the group")

        case = self.get_case("pid1237")
        self.update_case_owner(case, self.group1)
        incoming("999124", "for_owner", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the case owner")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for the case owner")

        # Test case sharing auth
        incoming("999122", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Enter Study Arm 1:a, 2:b.")
        incoming("999122", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test closing open sessions on an sms reply
        incoming("999122", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Enter Participant ID")
        incoming("999122", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for users")
        incoming("999122", "null", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Default SMS Response")
Ejemplo n.º 53
0
    def test_android_registration_from_invite(self):
        self.domain_obj.sms_mobile_worker_registration_enabled = True
        self.domain_obj.enable_registration_welcome_sms_for_mobile_worker = True
        self.domain_obj.save()

        user_data = {'abc': 'def'}

        # Initiate Registration Workflow
        SelfRegistrationInvitation.initiate_workflow(
            self.domain,
            [SelfRegistrationUserInfo('999123', user_data)],
            app_id=self.app_id,
        )

        self.assertRegistrationInvitation(
            phone_number='999123',
            app_id=self.app_id,
            phone_type=None,
            android_only=False,
            require_email=False,
            custom_user_data=user_data,
            status=SelfRegistrationInvitation.STATUS_PENDING,
        )

        self.assertLastOutgoingSMS('+999123', [_MESSAGES[MSG_MOBILE_WORKER_INVITATION_START]])

        # Choose phone type 'android'
        with patch('corehq.apps.sms.models.SelfRegistrationInvitation.odk_url') as mock_odk_url, \
                patch.object(SelfRegistrationInvitation, 'get_user_registration_url', return_value=DUMMY_REGISTRATION_URL), \
                patch.object(SelfRegistrationInvitation, 'get_app_info_url', return_value=DUMMY_APP_INFO_URL):
            mock_odk_url.__get__ = Mock(return_value=DUMMY_APP_ODK_URL)
            incoming('+999123', '1', self.backend.hq_api_id)

        self.assertRegistrationInvitation(
            phone_number='999123',
            app_id=self.app_id,
            phone_type=SelfRegistrationInvitation.PHONE_TYPE_ANDROID,
            android_only=False,
            require_email=False,
            custom_user_data=user_data,
            status=SelfRegistrationInvitation.STATUS_PENDING,
        )

        self.assertLastOutgoingSMS('+999123', [
            _MESSAGES[MSG_MOBILE_WORKER_ANDROID_INVITATION].format(DUMMY_REGISTRATION_URL),
            '[commcare app - do not delete] {}'.format(DUMMY_APP_INFO_URL),
        ])

        invite = self._get_sms_registration_invitation()
        c = Client()
        response = c.post('/a/{}/settings/users/commcare/register/{}/'.format(self.domain, invite.token), {
            'username': '******',
            'password': '******',
            'password2': 'abc',
            'email': '*****@*****.**',
        })
        self.assertEqual(response.status_code, 200)

        user = CommCareUser.get_by_username(format_username('new_user', self.domain))
        self.assertIsNotNone(user)
        self.assertEqual(user.user_data, user_data)
        self.assertEqual(user.email, '*****@*****.**')
        self.assertEqual(PhoneNumber.by_phone('999123').owner_id, user.get_id)

        self.assertRegistrationInvitation(
            status=SelfRegistrationInvitation.STATUS_REGISTERED,
        )
 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)
Ejemplo n.º 56
0
    def test_all_inbound(self):
        # Mobile worker creates a case
        incoming("999123", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1234")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1234")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1234")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # now take the case away from the user
        self.update_case_owner(case, self.user3)
        case = self.get_case("pid1234")

        # then they should no longer have access
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))

        # now add access back via parent connection
        self.add_parent_access(self.user1, case)
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        form = self.get_last_form_submission()

        # Bad external id
        incoming("999123", "mod pid1235", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "mod", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        # Test validation on all fields
        incoming("999123", "Validation_Test", "TEST")
        session = self.get_open_session(self.user1)
        
        sms = self.assertLastOutboundSMSEquals(self.user1, "text")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "ab", "TEST")
        self.assertTrue(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "abc", "TEST")
        self.assertFalse(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "single select 1:a, 2:b, 3:c, 4:d.")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertTrue(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s single select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "5", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s single select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_CHOICE_OUT_OF_RANGE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2", "TEST")
        self.assertFalse(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "multi select 1:a, 2:b, 3:c, 4:d.")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_FIELD_REQUIRED))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2 x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "1 5", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "1 c", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "int")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s int" % get_message(MSG_INVALID_INT))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "50", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "float")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s float" % get_message(MSG_INVALID_FLOAT))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "21.3", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)
        
        sms = self.assertLastOutboundSMSEquals(self.user1, "long")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s long" % get_message(MSG_INVALID_LONG))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "-100", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "date")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s date" %
            get_message(MSG_INVALID_DATE, context=('YYYYMMDD',)))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "20140101", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "time")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s time" % get_message(MSG_INVALID_TIME))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2500", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s time" % get_message(MSG_INVALID_TIME))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2345", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=int)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Mobile worker creates a case via structured sms
        incoming("999123", "reg_ss pid1235 1", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your registration submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1235")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1235")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1235")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "mod_ss pid1235 b", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Bad external id
        incoming("999123", "mod_ss pid1236", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "mod_ss", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        def get_field_and_message(field_name, msg_id, additional_context=None):
            msg1 = get_message(MSG_FIELD_DESCRIPTOR, context=(field_name,))
            msg2 = get_message(msg_id, context=additional_context)
            return "%s%s" % (msg1, msg2)

        # Test validation on all fields from structured sms: positional args
        incoming("999123", "validation_test_ss_1 ab 2 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc x c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 5 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 x 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 5 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c x 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_int", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 x -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_float", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 x 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_long", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 x 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("q_date", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=int)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: positional args with custom delimiter
        incoming("999123", "validation_test_ss_2,ab,2,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,x,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,5,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 x,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 5,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,x,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_int", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,x,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_float", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,x,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_long", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,x,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("q_date", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=int)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: named args with custom delimiter
        incoming("999123", "validation_test_ss_3,arg1ab,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg2x,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg25,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 x,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 5,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg3,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg4x,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG4", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg5x,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG5", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6x,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG6", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg7x,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("ARG7", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg8x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=int)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: named args with custom delimiter and joining character
        incoming("999123", "validation_test_ss_4,arg1=ab,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=x,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=5,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 x,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 5,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=x,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG4", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=x,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG5", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=x,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG6", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=x,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1,
            get_field_and_message("ARG7", MSG_INVALID_DATE, ('YYYYMMDD',)))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=int)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test leaving fields blank via structured sms
        incoming("999123", "validation_test_ss_4,arg1=abc,arg3=1 c", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", "")
        self.assertFormQuestionEquals(form, "q_float", "")
        self.assertFormQuestionEquals(form, "q_long", "")
        self.assertFormQuestionEquals(form, "q_date", "")
        self.assertFormQuestionEquals(form, "q_time", "")

        incoming("999123", "validation_test_ss_1 abc b c", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "c")
        self.assertFormQuestionEquals(form, "q_int", "")
        self.assertFormQuestionEquals(form, "q_float", "")
        self.assertFormQuestionEquals(form, "q_long", "")
        self.assertFormQuestionEquals(form, "q_date", "")
        self.assertFormQuestionEquals(form, "q_time", "")

        incoming("999123", "mod_ss_2,pid1235", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("arm", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_2,pid1235,", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("arm", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm=", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARM", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm a", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_EXPECTED_NAMED_ARGS_SEPARATOR, context=("=",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm=a,arm=b", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MULTIPLE_ANSWERS_FOUND, context=("ARM",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3 ,  pid1235  ,  arm = a", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test global keywords
        incoming("999123", "#start unknownkeyword", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_KEYWORD_NOT_FOUND, context=("UNKNOWNKEYWORD",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "#start", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_START_KEYWORD_USAGE, context=("#START",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "#unknown", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_UNKNOWN_GLOBAL_KEYWORD, context=("#UNKNOWN",)))
        self.assertNoNewSubmission(form)

        # Mobile worker creates a case
        incoming("999123", "#start reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1237")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1237")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "#start mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Bad external id
        incoming("999123", "#start mod pid1240", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "#start mod", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        # CURRENT keyword
        incoming("999123", "reg", "TEST")
        sms1 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "#CURRENT", "TEST")
        sms2 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        self.assertNotEqual(sms1.pk, sms2.pk)

        # STOP keyword
        session = self.get_open_session(self.user1)
        self.assertIsNotNone(session)
        incoming("999123", "#STOP", "TEST")
        session = self.get_open_session(self.user1)
        self.assertIsNone(session)
        self.assertNoNewSubmission(form)

        # One keyword overrides another
        incoming("999123", "reg", "TEST")
        sms1 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        self.assertNoNewSubmission(form)
        incoming("999123", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "%s Enter Study Arm 1:a, 2:b." % get_message(MSG_INVALID_CHOICE))
        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test initator filters
        case = self.get_case("pid1237")
        update_case(self.domain, case.case_id,
            case_properties={'contact_phone_number': '999124', 'contact_phone_number_is_verified': '1'})
        case = CaseAccessors(self.domain).get_case(case.case_id)

        incoming("999123", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for users")
        incoming("999123", "for_case", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Default SMS Response")

        incoming("999124", "for_case", "TEST")
        self.assertLastOutboundSMSEquals(case, "This message is for cases")
        incoming("999124", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(case, "Default SMS Response")

        # Test form over sms for case
        incoming("999124", "mod", "TEST")
        self.assertLastOutboundSMSEquals(case, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999124", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test structured sms for case
        incoming("999124", "mod_ss 2", "TEST")
        self.assertLastOutboundSMSEquals(case, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Test Auth
        incoming("999122", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, get_message(MSG_CASE_NOT_FOUND))

        # Test notifying others
        incoming("999124", "for_owner", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the case owner")

        incoming("999124", "for_group", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the group")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for the group")

        case = self.get_case("pid1237")
        self.update_case_owner(case, self.group1)
        incoming("999124", "for_owner", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the case owner")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for the case owner")

        # Test case sharing auth
        incoming("999122", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Enter Study Arm 1:a, 2:b.")
        incoming("999122", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test closing open sessions on an sms reply
        incoming("999122", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Enter Participant ID")
        incoming("999122", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for users")
        incoming("999122", "null", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Default SMS Response")
 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)
Ejemplo n.º 59
0
    # parse date or default to current utc time
    actual_timestamp = None
    if timestamp:
        try:
            actual_timestamp = datetime.strptime(timestamp, DATE_FORMAT)
            actual_timestamp = pytz.timezone('Asia/Kolkata').localize(actual_timestamp).astimezone(pytz.utc)
        except Exception, e:
            logging.warning('could not parse unicel inbound timestamp [%s]' % timestamp)
    
    # not sure yet if this check is valid
    is_unicode = request.REQUEST.get(InboundParams.UDHI, "") == "1"
    if is_unicode:
        message = message.decode("hex").decode("utf_16_be")

    log = incoming(sender, message, API_ID, timestamp=actual_timestamp, delay=delay)

    return log
    
def receive_phone_number():
    return _config().get('receive_phone')

def send(message, delay=True):
    """
    Send an outbound message using the Unicel API
    """
    config = _config()
    
    phone_number = clean_phone_number(message.phone_number).replace("+", "")
    # these are shared regardless of API
    params = [(OutboundParams.DESTINATION, phone_number),