Exemplo n.º 1
0
    def send_message(self, flow, message, restart_participants=False, contact=None, initiate_flow=False, assert_reply=True):
        """
        Starts the flow, sends the message, returns the reply
        """
        if not contact:
            contact = self.contact

        try:
            if contact.is_test:
                Contact.set_simulation(True)

            incoming = self.create_msg(direction=INCOMING, contact=contact, text=message)

            # start the flow
            if initiate_flow:
                flow.start(groups=[], contacts=[contact], restart_participants=restart_participants, start_msg=incoming)
            else:
                flow.start(groups=[], contacts=[contact], restart_participants=restart_participants)
                self.assertTrue(flow.find_and_handle(incoming))

            # our message should have gotten a reply
            if assert_reply:
                reply = Msg.objects.get(response_to=incoming)
                self.assertEquals(contact, reply.contact)
                return reply.text

            return None

        finally:
            Contact.set_simulation(False)
Exemplo n.º 2
0
    def send_message(
        self,
        flow,
        message,
        restart_participants=False,
        contact=None,
        initiate_flow=False,
        assert_reply=True,
        assert_handle=True,
    ):
        """
        Starts the flow, sends the message, returns the reply
        """
        if not contact:
            contact = self.contact
        try:
            if contact.is_test:
                Contact.set_simulation(True)

            incoming = self.create_msg(
                direction=INCOMING, contact=contact, contact_urn=contact.get_urn(), text=message
            )

            # start the flow
            if initiate_flow:
                flow.start(
                    groups=[], contacts=[contact], restart_participants=restart_participants, start_msg=incoming
                )
            else:
                flow.start(groups=[], contacts=[contact], restart_participants=restart_participants)
                (handled, msgs) = Flow.find_and_handle(incoming)

                Msg.mark_handled(incoming)

                if assert_handle:
                    self.assertTrue(handled, "'%s' did not handle message as expected" % flow.name)
                else:
                    self.assertFalse(handled, "'%s' handled message, was supposed to ignore" % flow.name)

            # our message should have gotten a reply
            if assert_reply:
                replies = Msg.objects.filter(response_to=incoming).order_by("pk")
                self.assertGreaterEqual(len(replies), 1)

                if len(replies) == 1:
                    self.assertEqual(contact, replies.first().contact)
                    return replies.first().text

                # if it's more than one, send back a list of replies
                return [reply.text for reply in replies]

            else:
                # assert we got no reply
                replies = Msg.objects.filter(response_to=incoming).order_by("pk")
                self.assertFalse(replies)

            return None

        finally:
            Contact.set_simulation(False)
Exemplo n.º 3
0
    def test_twilio_failed_auth(self):
        def create(self, to=None, from_=None, url=None, status_callback=None):
            from twilio import TwilioRestException
            raise TwilioRestException(403, 'http://twilio.com', code=20003)

        MockTwilioClient.MockCalls.create = create

        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN", self.admin)
        self.org.save()

        # import an ivr flow
        self.import_file('call_me_maybe')
        flow = Flow.objects.filter(name='Call me maybe').first()

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        test_contact = Contact.get_test_contact(self.admin)
        Contact.set_simulation(True)
        flow.start([], [test_contact])

        log = ActionLog.objects.all().order_by('-pk').first()
        self.assertEquals(
            log.text,
            'Call ended. Could not authenticate with your Twilio account. '
            'Check your token and try again.')
Exemplo n.º 4
0
    def test_rule_first_ivr_flow(self):
        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN")
        self.org.save()

        # import an ivr flow
        self.import_file('rule-first-ivr')
        flow = Flow.objects.filter(name='Rule First IVR').first()

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        # start our flow`
        eric = self.create_contact('Eric Newcomer', number='+13603621737')
        eric.is_test = True
        eric.save()
        Contact.set_simulation(True)
        flow.start([], [eric])

        # should be using the usersettings number in test mode
        self.assertEquals('Placing test call to +1 800-555-1212', ActionLog.objects.all().first().text)

        # we should have an outbound ivr call now
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        self.assertEquals(0, call.get_duration())
        self.assertIsNotNone(call)
        self.assertEquals('CallSid', call.external_id)

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid', CallStatus='in-progress', CallDuration=20)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)
        self.assertContains(response, '<Say>Thanks for calling!</Say>')
Exemplo n.º 5
0
    def test_twilio_failed_auth(self):

        def create(self, to=None, from_=None, url=None, status_callback=None):
            from twilio import TwilioRestException
            raise TwilioRestException(403, 'http://twilio.com', code=20003)
        MockTwilioClient.MockCalls.create = create

        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN")
        self.org.save()

        # import an ivr flow
        self.import_file('call-me-maybe')
        flow = Flow.objects.filter(name='Call me maybe').first()

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        test_contact = Contact.get_test_contact(self.admin)
        Contact.set_simulation(True)
        flow.start([], [test_contact])

        log = ActionLog.objects.all().order_by('-pk').first()
        self.assertEquals(log.text, 'Call ended. Could not authenticate with your Twilio account. '
                                    'Check your token and try again.')
Exemplo n.º 6
0
 def send(self, message, contact=None):
     if not contact:
         contact = self.contact
     if contact.is_test:
         Contact.set_simulation(True)
     incoming = self.create_msg(direction=INCOMING, contact=contact, text=message)
     Flow.find_and_handle(incoming)
     return Msg.all_messages.filter(response_to=incoming).order_by('pk').first()
Exemplo n.º 7
0
    def setUp(self):

        # if we are super verbose, turn on debug for sql queries
        if self.get_verbosity() > 2:
            settings.DEBUG = True

        self.clear_cache()

        self.superuser = User.objects.create_superuser(username="******", email="*****@*****.**", password="******")

        # create different user types
        self.non_org_user = self.create_user("NonOrg")
        self.user = self.create_user("User")
        self.editor = self.create_user("Editor")
        self.admin = self.create_user("Administrator")
        self.surveyor = self.create_user("Surveyor")

        # setup admin boundaries for Rwanda
        self.country = AdminBoundary.objects.create(osm_id='171496', name='Rwanda', level=0)
        self.state1 = AdminBoundary.objects.create(osm_id='1708283', name='Kigali City', level=1, parent=self.country)
        self.state2 = AdminBoundary.objects.create(osm_id='171591', name='Eastern Province', level=1, parent=self.country)
        self.district1 = AdminBoundary.objects.create(osm_id='1711131', name='Gatsibo', level=2, parent=self.state2)
        self.district2 = AdminBoundary.objects.create(osm_id='1711163', name='Kayônza', level=2, parent=self.state2)
        self.district3 = AdminBoundary.objects.create(osm_id='3963734', name='Nyarugenge', level=2, parent=self.state1)
        self.district4 = AdminBoundary.objects.create(osm_id='1711142', name='Rwamagana', level=2, parent=self.state2)
        self.ward1 = AdminBoundary.objects.create(osm_id='171113181', name='Kageyo', level=3, parent=self.district1)
        self.ward2 = AdminBoundary.objects.create(osm_id='171116381', name='Kabare', level=3, parent=self.district2)
        self.ward3 = AdminBoundary.objects.create(osm_id='171114281', name='Bukure', level=3, parent=self.district4)

        self.org = Org.objects.create(name="Temba", timezone="Africa/Kigali", country=self.country, brand=settings.DEFAULT_BRAND,
                                      created_by=self.user, modified_by=self.user)

        self.org.initialize(topup_size=1000)

        # add users to the org
        self.user.set_org(self.org)
        self.org.viewers.add(self.user)

        self.editor.set_org(self.org)
        self.org.editors.add(self.editor)

        self.admin.set_org(self.org)
        self.org.administrators.add(self.admin)

        self.surveyor.set_org(self.org)
        self.org.surveyors.add(self.surveyor)

        self.superuser.set_org(self.org)

        # welcome topup with 1000 credits
        self.welcome_topup = self.org.topups.all()[0]

        # a single Android channel
        self.channel = Channel.create(self.org, self.user, 'RW', 'A', name="Test Channel", address="+250785551212",
                                      device="Nexus 5X", secret="12345", gcm_id="123")

        # reset our simulation to False
        Contact.set_simulation(False)
Exemplo n.º 8
0
    def setUp(self):

        # if we are super verbose, turn on debug for sql queries
        if self.get_verbosity() > 2:
            settings.DEBUG = True

        self.clear_cache()

        self.superuser = User.objects.create_superuser(username="******", email="*****@*****.**", password="******")

        # create different user types
        self.non_org_user = self.create_user("NonOrg")
        self.user = self.create_user("User")
        self.editor = self.create_user("Editor")
        self.admin = self.create_user("Administrator")
        self.surveyor = self.create_user("Surveyor")

        # setup admin boundaries for Rwanda
        self.country = AdminBoundary.objects.create(osm_id='171496', name='Rwanda', level=0)
        self.state1 = AdminBoundary.objects.create(osm_id='1708283', name='Kigali City', level=1, parent=self.country)
        self.state2 = AdminBoundary.objects.create(osm_id='171591', name='Eastern Province', level=1, parent=self.country)
        self.district1 = AdminBoundary.objects.create(osm_id='1711131', name='Gatsibo', level=2, parent=self.state2)
        self.district2 = AdminBoundary.objects.create(osm_id='1711163', name='Kayônza', level=2, parent=self.state2)
        self.district3 = AdminBoundary.objects.create(osm_id='3963734', name='Nyarugenge', level=2, parent=self.state1)
        self.district4 = AdminBoundary.objects.create(osm_id='1711142', name='Rwamagana', level=2, parent=self.state2)
        self.ward1 = AdminBoundary.objects.create(osm_id='171113181', name='Kageyo', level=3, parent=self.district1)
        self.ward2 = AdminBoundary.objects.create(osm_id='171116381', name='Kabare', level=3, parent=self.district2)
        self.ward3 = AdminBoundary.objects.create(osm_id='171114281', name='Bukure', level=3, parent=self.district4)

        self.org = Org.objects.create(name="Temba", timezone=pytz.timezone("Africa/Kigali"), country=self.country,
                                      brand=settings.DEFAULT_BRAND, created_by=self.user, modified_by=self.user)

        self.org.initialize(topup_size=1000)

        # add users to the org
        self.user.set_org(self.org)
        self.org.viewers.add(self.user)

        self.editor.set_org(self.org)
        self.org.editors.add(self.editor)

        self.admin.set_org(self.org)
        self.org.administrators.add(self.admin)

        self.surveyor.set_org(self.org)
        self.org.surveyors.add(self.surveyor)

        self.superuser.set_org(self.org)

        # welcome topup with 1000 credits
        self.welcome_topup = self.org.topups.all()[0]

        # a single Android channel
        self.channel = Channel.create(self.org, self.user, 'RW', 'A', name="Test Channel", address="+250785551212",
                                      device="Nexus 5X", secret="12345", gcm_id="123")

        # reset our simulation to False
        Contact.set_simulation(False)
Exemplo n.º 9
0
 def send(self, message, contact=None):
     if not contact:
         contact = self.contact
     if contact.is_test:
         Contact.set_simulation(True)
     incoming = self.create_msg(direction=INCOMING,
                                contact=contact,
                                text=message)
     Flow.find_and_handle(incoming)
     return Msg.all_messages.filter(
         response_to=incoming).order_by('pk').first()
Exemplo n.º 10
0
    def send(self, message, contact=None):
        if not contact:
            contact = self.contact
        if contact.is_test:
            Contact.set_simulation(True)
        incoming = self.create_msg(direction=INCOMING, contact=contact, text=message)

        # evaluate the inbound message against our triggers first
        from temba.triggers.models import Trigger
        if not Trigger.find_and_handle(incoming):
            Flow.find_and_handle(incoming)
        return Msg.objects.filter(response_to=incoming).order_by('pk').first()
Exemplo n.º 11
0
    def send(self, message, contact=None):
        if not contact:
            contact = self.contact
        if contact.is_test:
            Contact.set_simulation(True)
        incoming = self.create_msg(direction=INCOMING, contact=contact, text=message)

        # evaluate the inbound message against our triggers first
        from temba.triggers.models import Trigger
        if not Trigger.find_and_handle(incoming):
            Flow.find_and_handle(incoming)
        return Msg.objects.filter(response_to=incoming).order_by('pk').first()
Exemplo n.º 12
0
    def send_message(self,
                     flow,
                     message,
                     restart_participants=False,
                     contact=None,
                     initiate_flow=False,
                     assert_reply=True):
        """
        Starts the flow, sends the message, returns the reply
        """
        if not contact:
            contact = self.contact

        try:
            if contact.is_test:
                Contact.set_simulation(True)

            incoming = self.create_msg(direction=INCOMING,
                                       contact=contact,
                                       text=message)

            # start the flow
            if initiate_flow:
                flow.start(groups=[],
                           contacts=[contact],
                           restart_participants=restart_participants,
                           start_msg=incoming)
            else:
                flow.start(groups=[],
                           contacts=[contact],
                           restart_participants=restart_participants)
                self.assertTrue(
                    flow.find_and_handle(incoming),
                    "'%s' did not handle message as expected" % flow.name)

            # our message should have gotten a reply
            if assert_reply:
                replies = Msg.objects.filter(
                    response_to=incoming).order_by('pk')
                self.assertGreaterEqual(len(replies), 1)

                if len(replies) == 1:
                    self.assertEquals(contact, replies.first().contact)
                    return replies.first().text

                # if it's more than one, send back a list of replies
                return [reply.text for reply in replies]

            return None

        finally:
            Contact.set_simulation(False)
Exemplo n.º 13
0
    def setUp(self):
        self.clear_cache()

        self.superuser = User.objects.create_superuser(username="******", email="*****@*****.**", password="******")

        # some users not tied to our org
        self.non_org_user = self.create_user("NonOrg")
        self.non_org_manager = self.create_user("NonOrgManager")

        # our three user types inside our org
        self.user = self.create_user("User")
        self.root = self.create_user("Root")
        self.root.groups.add(Group.objects.get(name="Alpha"))

        self.admin = self.create_user("Administrator")

        # setup admin boundaries for Rwanda
        self.country = AdminBoundary.objects.create(osm_id='171496', name='Rwanda', level=0)
        state1 = AdminBoundary.objects.create(osm_id='1708283', name='Kigali City', level=1, parent=self.country)
        state2 = AdminBoundary.objects.create(osm_id='171591', name='Eastern Province', level=1, parent=self.country)
        AdminBoundary.objects.create(osm_id='1711131', name='Gatsibo', level=2, parent=state2)
        AdminBoundary.objects.create(osm_id='1711163', name='Kayonza', level=2, parent=state2)
        AdminBoundary.objects.create(osm_id='60485579', name='Kigali', level=2, parent=state1)
        AdminBoundary.objects.create(osm_id='1711142', name='Rwamagana', level=2, parent=state2)

        self.org = Org.objects.create(name="Temba", timezone="Africa/Kigali", country=self.country,
                                      created_by=self.user, modified_by=self.user)
        self.org.initialize()

        # add users to the org
        self.org.administrators.add(self.admin)
        self.admin.set_org(self.org)

        self.org.administrators.add(self.root)
        self.root.set_org(self.org)

        self.user.set_org(self.org)
        self.superuser.set_org(self.org)

        # welcome topup with 1000 credits
        self.welcome_topup = self.org.topups.all()[0]

        # a single Android channel
        self.channel = Channel.objects.create(org=self.org, name="Test Channel",
                                              address="+250785551212", country='RW', channel_type='A',
                                              secret="12345", gcm_id="123",
                                              created_by=self.user, modified_by=self.user)

        # reset our simulation to False
        Contact.set_simulation(False)
Exemplo n.º 14
0
    def setUp(self):
        self.clear_cache()

        self.superuser = User.objects.create_superuser(username="******", email="*****@*****.**", password="******")

        # create different user types
        self.non_org_user = self.create_user("NonOrg")
        self.user = self.create_user("User")
        self.editor = self.create_user("Editor")
        self.admin = self.create_user("Administrator")
        self.surveyor = self.create_user("Surveyor")

        # setup admin boundaries for Rwanda
        self.country = AdminBoundary.objects.create(osm_id='171496', name='Rwanda', level=0)
        self.state1 = AdminBoundary.objects.create(osm_id='1708283', name='Kigali City', level=1, parent=self.country)
        self.state2 = AdminBoundary.objects.create(osm_id='171591', name='Eastern Province', level=1, parent=self.country)
        self.district1 = AdminBoundary.objects.create(osm_id='1711131', name='Gatsibo', level=2, parent=self.state2)
        self.district2 = AdminBoundary.objects.create(osm_id='1711163', name='Kayonza', level=2, parent=self.state2)
        self.district3 = AdminBoundary.objects.create(osm_id='60485579', name='Kigali', level=2, parent=self.state1)
        self.district4 = AdminBoundary.objects.create(osm_id='1711142', name='Rwamagana', level=2, parent=self.state2)

        self.org = Org.objects.create(name="Temba", timezone="Africa/Kigali", country=self.country,
                                      created_by=self.user, modified_by=self.user)
        self.org.initialize()

        # add users to the org
        self.user.set_org(self.org)
        self.org.viewers.add(self.user)

        self.editor.set_org(self.org)
        self.org.editors.add(self.editor)

        self.admin.set_org(self.org)
        self.org.administrators.add(self.admin)

        self.surveyor.set_org(self.org)
        self.org.surveyors.add(self.surveyor)

        self.superuser.set_org(self.org)

        # welcome topup with 1000 credits
        self.welcome_topup = self.org.topups.all()[0]

        # a single Android channel
        self.channel = Channel.create(self.org, self.user, 'RW', 'A', name="Test Channel", address="+250785551212",
                                      secret="12345", gcm_id="123")

        # reset our simulation to False
        Contact.set_simulation(False)
Exemplo n.º 15
0
    def test_rule_first_ivr_flow(self):
        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN")
        self.org.save()

        # import an ivr flow
        self.import_file('rule-first-ivr')
        flow = Flow.objects.filter(name='Rule First IVR').first()

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        # start our flow
        eric = self.create_contact('Eric Newcomer', number='+13603621737')
        eric.is_test = True
        eric.save()
        Contact.set_simulation(True)
        flow.start([], [eric])

        # should be using the usersettings number in test mode
        self.assertEquals('Placing test call to +1 800-555-1212',
                          ActionLog.objects.all().first().text)

        # we should have an outbound ivr call now
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        self.assertEquals(0, call.get_duration())
        self.assertIsNotNone(call)
        self.assertEquals('CallSid', call.external_id)

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid',
                         CallStatus='in-progress',
                         CallDuration=20)
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)
        self.assertContains(response, '<Say>Thanks for calling!</Say>')

        # make sure a message from the person on the call goes to the
        # inbox since our flow doesn't handle text messages
        msg = self.create_msg(direction='I',
                              contact=eric,
                              text="message during phone call")
        self.assertFalse(Flow.find_and_handle(msg))
Exemplo n.º 16
0
    def send_message(self,
                     flow,
                     message,
                     restart_participants=False,
                     contact=None,
                     initiate_flow=False,
                     assert_reply=True):
        """
        Starts the flow, sends the message, returns the reply
        """
        if not contact:
            contact = self.contact

        try:
            if contact.is_test:
                Contact.set_simulation(True)

            incoming = self.create_msg(direction=INCOMING,
                                       contact=contact,
                                       text=message)

            # start the flow
            if initiate_flow:
                flow.start(groups=[],
                           contacts=[contact],
                           restart_participants=restart_participants,
                           start_msg=incoming)
            else:
                flow.start(groups=[],
                           contacts=[contact],
                           restart_participants=restart_participants)
                self.assertTrue(flow.find_and_handle(incoming))

            # our message should have gotten a reply
            if assert_reply:
                reply = Msg.objects.get(response_to=incoming)
                self.assertEquals(contact, reply.contact)
                return reply.text

            return None

        finally:
            Contact.set_simulation(False)
Exemplo n.º 17
0
    def send_message(self, flow, message, restart_participants=False, contact=None, initiate_flow=False, assert_reply=True):
        """
        Starts the flow, sends the message, returns the reply
        """
        if not contact:
            contact = self.contact

        try:
            if contact.is_test:
                Contact.set_simulation(True)

            incoming = self.create_msg(direction=INCOMING, contact=contact, text=message)

            # start the flow
            if initiate_flow:
                flow.start(groups=[], contacts=[contact], restart_participants=restart_participants, start_msg=incoming)
            else:
                flow.start(groups=[], contacts=[contact], restart_participants=restart_participants)
                self.assertTrue(flow.find_and_handle(incoming))

            # our message should have gotten a reply
            if assert_reply:
                replies = Msg.objects.filter(response_to=incoming).order_by('pk')
                self.assertGreaterEqual(len(replies), 1)

                if len(replies) == 1:
                    self.assertEquals(contact, replies.first().contact)
                    return replies.first().text

                # if it's more than one, send back a list of replies
                return [reply.text for reply in replies]

            return None

        finally:
            Contact.set_simulation(False)
Exemplo n.º 18
0
    def test_rule_first_ivr_flow(self):
        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN")
        self.org.save()

        # import an ivr flow
        flow = self.get_flow('rule-first-ivr')

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        # start our flow
        test_contact = Contact.get_test_contact(self.admin)
        Contact.set_simulation(True)
        flow.start([], [test_contact])

        # should be using the usersettings number in test mode
        self.assertEquals('Placing test call to +1 800-555-1212', ActionLog.objects.all().first().text)

        # we should have an outbound ivr call now
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        self.assertEquals(0, call.get_duration())
        self.assertIsNotNone(call)
        self.assertEquals('CallSid', call.external_id)

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid', CallStatus='in-progress', CallDuration=20)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)
        self.assertContains(response, '<Say>Thanks for calling!</Say>')

        # make sure a message from the person on the call goes to the
        # inbox since our flow doesn't handle text messages
        msg = self.create_msg(direction='I', contact=test_contact, text="message during phone call")
        self.assertFalse(Flow.find_and_handle(msg))
Exemplo n.º 19
0
    def __call__(self, request):
        Contact.set_simulation(False)

        response = self.get_response(request)
        return response
Exemplo n.º 20
0
 def process_request(self, request):
     Contact.set_simulation(False)
     return None
Exemplo n.º 21
0
    def setUp(self):
        self.maxDiff = 4096
        self.mock_server = mock_server

        # if we are super verbose, turn on debug for sql queries
        if self.get_verbosity() > 2:
            settings.DEBUG = True

        # make sure we start off without any service users
        Group.objects.get(name="Service Users").user_set.clear()

        self.clear_cache()

        self.create_anonymous_user()

        self.superuser = User.objects.create_superuser(username="******", email="*****@*****.**", password="******")

        # create different user types
        self.non_org_user = self.create_user("NonOrg")
        self.user = self.create_user("User")
        self.editor = self.create_user("Editor")
        self.admin = self.create_user("Administrator")
        self.surveyor = self.create_user("Surveyor")
        self.customer_support = self.create_user("support", ("Customer Support",))

        # setup admin boundaries for Rwanda
        self.country = AdminBoundary.create(osm_id="171496", name="Rwanda", level=0)
        self.state1 = AdminBoundary.create(osm_id="1708283", name="Kigali City", level=1, parent=self.country)
        self.state2 = AdminBoundary.create(osm_id="171591", name="Eastern Province", level=1, parent=self.country)
        self.district1 = AdminBoundary.create(osm_id="R1711131", name="Gatsibo", level=2, parent=self.state2)
        self.district2 = AdminBoundary.create(osm_id="1711163", name="Kayônza", level=2, parent=self.state2)
        self.district3 = AdminBoundary.create(osm_id="3963734", name="Nyarugenge", level=2, parent=self.state1)
        self.district4 = AdminBoundary.create(osm_id="1711142", name="Rwamagana", level=2, parent=self.state2)
        self.ward1 = AdminBoundary.create(osm_id="171113181", name="Kageyo", level=3, parent=self.district1)
        self.ward2 = AdminBoundary.create(osm_id="171116381", name="Kabare", level=3, parent=self.district2)
        self.ward3 = AdminBoundary.create(osm_id="VMN.49.1_1", name="Bukure", level=3, parent=self.district4)

        self.country.update_path()

        self.org = Org.objects.create(
            name="Temba",
            timezone=pytz.timezone("Africa/Kigali"),
            country=self.country,
            brand=settings.DEFAULT_BRAND,
            created_by=self.user,
            modified_by=self.user,
        )

        self.org.initialize(topup_size=1000)

        # add users to the org
        self.user.set_org(self.org)
        self.org.viewers.add(self.user)

        self.editor.set_org(self.org)
        self.org.editors.add(self.editor)

        self.admin.set_org(self.org)
        self.org.administrators.add(self.admin)

        self.surveyor.set_org(self.org)
        self.org.surveyors.add(self.surveyor)

        self.superuser.set_org(self.org)

        # welcome topup with 1000 credits
        self.welcome_topup = self.org.topups.all()[0]

        # a single Android channel
        self.channel = Channel.create(
            self.org,
            self.user,
            "RW",
            "A",
            name="Test Channel",
            address="+250785551212",
            device="Nexus 5X",
            secret="12345",
            gcm_id="123",
        )

        # don't cache anon user between tests
        from temba import utils

        utils._anon_user = None
        clear_flow_users()

        # reset our simulation to False
        Contact.set_simulation(False)
Exemplo n.º 22
0
    def test_ivr_options(self):

        # should be able to create an ivr flow
        self.assertTrue(self.org.supports_ivr())
        self.assertTrue(self.admin.groups.filter(name="Beta"))
        self.assertContains(self.client.get(reverse('flows.flow_create')), 'Phone Call')

        # no twilio config yet
        self.assertFalse(self.org.is_connected_to_twilio())
        self.assertIsNone(self.org.get_twilio_client())

        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN")
        self.org.save()
        self.assertTrue(self.org.is_connected_to_twilio())
        self.assertIsNotNone(self.org.get_twilio_client())

        # import an ivr flow
        self.import_file('call-me-maybe')

        # make sure our flow is there as expected
        flow = Flow.objects.filter(name='Call me maybe').first()
        self.assertEquals('callme', flow.triggers.all().first().keyword)

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        # start our flow`
        eric = self.create_contact('Eric Newcomer', number='+13603621737')
        eric.is_test = True
        eric.save()
        Contact.set_simulation(True)
        flow.start([], [eric])

        # should be using the usersettings number in test mode
        self.assertEquals('Placing test call to +1 800-555-1212', ActionLog.objects.all().first().text)

        # we should have an outbound ivr call now
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        self.assertEquals(0, call.get_duration())
        self.assertIsNotNone(call)
        self.assertEquals('CallSid', call.external_id)

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid', CallStatus='in-progress', CallDuration=20)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)
        self.assertContains(response, '<Say>Would you like me to call you? Press one for yes, two for no, or three for maybe.</Say>')

        # updated our status and duration accordingly
        call = IVRCall.objects.get(pk=call.pk)
        self.assertEquals(20, call.duration)
        self.assertEquals(IN_PROGRESS, call.status)

        # should mention our our action log that we read a message to them
        run = FlowRun.objects.all().first()
        logs = ActionLog.objects.filter(run=run).order_by('-pk')
        self.assertEquals(2, len(logs))
        self.assertEquals('Read message "Would you like me to call you? Press one for yes, two for no, or three for maybe."', logs.first().text)

        # press the number 4 (unexpected)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=4))
        self.assertContains(response, '<Say>Press one, two, or three. Thanks.</Say>')

        # now let's have them press the number 3 (for maybe)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=3))
        self.assertContains(response, '<Say>This might be crazy.</Say>')

        # twilio would then disconnect the user and notify us of a completed call
        self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), dict(CallStatus='completed'))
        self.assertEquals(COMPLETED, IVRCall.objects.get(pk=call.pk).status)

        # simulation gets flipped off by middleware, and this unhandled message doesn't flip it back on
        self.assertFalse(Contact.get_simulation())

        # test other our call status mappings with twilio
        def test_status_update(call_to_update, twilio_status, temba_status):
            call_to_update.update_status(twilio_status, 0)
            call_to_update.save()
            self.assertEquals(temba_status, IVRCall.objects.get(pk=call_to_update.pk).status)

        test_status_update(call, 'queued', QUEUED)
        test_status_update(call, 'ringing', RINGING)
        test_status_update(call, 'canceled', CANCELED)
        test_status_update(call, 'busy', BUSY)
        test_status_update(call, 'failed', FAILED)
        test_status_update(call, 'no-answer', NO_ANSWER)

        # explicitly hanging up an in progress call should remove it
        call.update_status('in-progress', 0)
        call.save()
        IVRCall.hangup_test_call(flow)
        self.assertIsNone(IVRCall.objects.filter(pk=call.pk).first())
Exemplo n.º 23
0
    def test_runs(self):
        url = reverse('api.v2.runs')

        self.assertEndpointAccess(url)

        flow1 = self.create_flow(uuid_start=0)
        flow2 = Flow.copy(flow1, self.user)

        joe_run1, = flow1.start([], [self.joe])
        frank_run1, = flow1.start([], [self.frank])
        self.create_msg(direction='I', contact=self.joe, text="it is blue").handle()
        self.create_msg(direction='I', contact=self.frank, text="Indigo").handle()

        joe_run2, = flow1.start([], [self.joe], restart_participants=True)
        frank_run2, = flow1.start([], [self.frank], restart_participants=True)
        joe_run3, = flow2.start([], [self.joe], restart_participants=True)

        # add a test contact run
        Contact.set_simulation(True)
        flow2.start([], [self.test_contact])
        Contact.set_simulation(False)

        # add a run for another org
        flow3 = self.create_flow(org=self.org2, user=self.admin2, uuid_start=10000)
        flow3.start([], [self.hans])

        # refresh runs which will have been modified by being interrupted
        joe_run1.refresh_from_db()
        joe_run2.refresh_from_db()
        frank_run1.refresh_from_db()

        # no filtering
        with self.assertNumQueries(NUM_BASE_REQUEST_QUERIES + 6):
            response = self.fetchJSON(url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json['next'], None)
        self.assertResultsById(response, [joe_run3, frank_run2, frank_run1, joe_run2, joe_run1])

        joe_run1_steps = list(joe_run1.steps.order_by('pk'))
        frank_run2_steps = list(frank_run2.steps.order_by('pk'))

        self.assertEqual(response.json['results'][1], {
            'id': frank_run2.pk,
            'flow': {'uuid': flow1.uuid, 'name': "Color Flow"},
            'contact': {'uuid': self.frank.uuid, 'name': self.frank.name},
            'responded': False,
            'steps': [
                {
                    'node': "00000000-00000000-00000000-00000001",
                    'arrived_on': format_datetime(frank_run2_steps[0].arrived_on),
                    'left_on': format_datetime(frank_run2_steps[0].left_on),
                    'text': "What is your favorite color?",
                    'value': None,
                    'category': None,
                    'type': 'actionset'
                },
                {
                    'node': "00000000-00000000-00000000-00000005",
                    'arrived_on': format_datetime(frank_run2_steps[1].arrived_on),
                    'left_on': None,
                    'text': None,
                    'value': None,
                    'category': None,
                    'type': 'ruleset'
                }
            ],
            'created_on': format_datetime(frank_run2.created_on),
            'modified_on': format_datetime(frank_run2.modified_on),
            'exited_on': None,
            'exit_type': None
        })
        self.assertEqual(response.json['results'][4], {
            'id': joe_run1.pk,
            'flow': {'uuid': flow1.uuid, 'name': "Color Flow"},
            'contact': {'uuid': self.joe.uuid, 'name': self.joe.name},
            'responded': True,
            'steps': [
                {
                    'node': "00000000-00000000-00000000-00000001",
                    'arrived_on': format_datetime(joe_run1_steps[0].arrived_on),
                    'left_on': format_datetime(joe_run1_steps[0].left_on),
                    'text': "What is your favorite color?",
                    'value': None,
                    'category': None,
                    'type': 'actionset'
                },
                {
                    'node': "00000000-00000000-00000000-00000005",
                    'arrived_on': format_datetime(joe_run1_steps[1].arrived_on),
                    'left_on': format_datetime(joe_run1_steps[1].left_on),
                    'text': 'it is blue',
                    'value': 'blue',
                    'category': "Blue",
                    'type': 'ruleset'
                },
                {
                    'node': "00000000-00000000-00000000-00000003",
                    'arrived_on': format_datetime(joe_run1_steps[2].arrived_on),
                    'left_on': format_datetime(joe_run1_steps[2].left_on),
                    'text': 'Blue is sad. :(',
                    'value': None,
                    'category': None,
                    'type': 'actionset'
                }
            ],
            'created_on': format_datetime(joe_run1.created_on),
            'modified_on': format_datetime(joe_run1.modified_on),
            'exited_on': format_datetime(joe_run1.exited_on),
            'exit_type': 'completed'
        })

        # filter by id
        response = self.fetchJSON(url, 'id=%d' % frank_run2.pk)
        self.assertResultsById(response, [frank_run2])

        # filter by flow
        response = self.fetchJSON(url, 'flow=%s' % flow1.uuid)
        self.assertResultsById(response, [frank_run2, frank_run1, joe_run2, joe_run1])

        # doesn't work if flow is inactive
        flow1.is_active = False
        flow1.save()

        response = self.fetchJSON(url, 'flow=%s' % flow1.uuid)
        self.assertResultsById(response, [])

        # restore to active
        flow1.is_active = True
        flow1.save()

        # filter by invalid flow
        response = self.fetchJSON(url, 'flow=invalid')
        self.assertResultsById(response, [])

        # filter by flow + responded
        response = self.fetchJSON(url, 'flow=%s&responded=TrUe' % flow1.uuid)
        self.assertResultsById(response, [frank_run1, joe_run1])

        # filter by contact
        response = self.fetchJSON(url, 'contact=%s' % self.joe.uuid)
        self.assertResultsById(response, [joe_run3, joe_run2, joe_run1])

        # filter by invalid contact
        response = self.fetchJSON(url, 'contact=invalid')
        self.assertResultsById(response, [])

        # filter by contact + responded
        response = self.fetchJSON(url, 'contact=%s&responded=yes' % self.joe.uuid)
        self.assertResultsById(response, [joe_run1])

        # filter by after
        response = self.fetchJSON(url, 'after=%s' % format_datetime(frank_run1.modified_on))
        self.assertResultsById(response, [joe_run3, frank_run2, frank_run1])

        # filter by before
        response = self.fetchJSON(url, 'before=%s' % format_datetime(frank_run1.modified_on))
        self.assertResultsById(response, [frank_run1, joe_run2, joe_run1])

        # filter by invalid before
        response = self.fetchJSON(url, 'before=longago')
        self.assertResultsById(response, [])

        # filter by invalid after
        response = self.fetchJSON(url, 'before=%s&after=thefuture' % format_datetime(frank_run1.modified_on))
        self.assertResultsById(response, [])

        # can't filter by both contact and flow together
        response = self.fetchJSON(url, 'contact=%s&flow=%s' % (self.joe.uuid, flow1.uuid))
        self.assertResponseError(response, None,
                                 "You may only specify one of the contact, flow parameters")
Exemplo n.º 24
0
    def test_ivr_options(self):

        # should be able to create an ivr flow
        self.assertTrue(self.org.supports_ivr())
        self.assertTrue(self.admin.groups.filter(name="Beta"))
        self.assertContains(self.client.get(reverse('flows.flow_create')),
                            'Phone Call')

        # no twilio config yet
        self.assertFalse(self.org.is_connected_to_twilio())
        self.assertIsNone(self.org.get_twilio_client())

        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN")
        self.org.save()
        self.assertTrue(self.org.is_connected_to_twilio())
        self.assertIsNotNone(self.org.get_twilio_client())

        # import an ivr flow
        self.import_file('call-me-maybe')

        # make sure our flow is there as expected
        flow = Flow.objects.filter(name='Call me maybe').first()
        self.assertEquals('callme', flow.triggers.all().first().keyword)

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        # start our flow`
        eric = self.create_contact('Eric Newcomer', number='+13603621737')
        eric.is_test = True
        eric.save()
        Contact.set_simulation(True)
        flow.start([], [eric])

        # should be using the usersettings number in test mode
        self.assertEquals('Placing test call to +1 800-555-1212',
                          ActionLog.objects.all().first().text)

        # we should have an outbound ivr call now
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        self.assertEquals(0, call.get_duration())
        self.assertIsNotNone(call)
        self.assertEquals('CallSid', call.external_id)

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid',
                         CallStatus='in-progress',
                         CallDuration=20)
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)
        self.assertContains(
            response,
            '<Say>Would you like me to call you? Press one for yes, two for no, or three for maybe.</Say>'
        )

        # updated our status and duration accordingly
        call = IVRCall.objects.get(pk=call.pk)
        self.assertEquals(20, call.duration)
        self.assertEquals(IN_PROGRESS, call.status)

        # should mention our our action log that we read a message to them
        run = FlowRun.objects.all().first()
        logs = ActionLog.objects.filter(run=run).order_by('-pk')
        self.assertEquals(2, len(logs))
        self.assertEquals(
            'Read message "Would you like me to call you? Press one for yes, two for no, or three for maybe."',
            logs.first().text)

        # press the number 4 (unexpected)
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=4))
        self.assertContains(response,
                            '<Say>Press one, two, or three. Thanks.</Say>')

        # now let's have them press the number 3 (for maybe)
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=3))
        self.assertContains(response, '<Say>This might be crazy.</Say>')

        # twilio would then disconnect the user and notify us of a completed call
        self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]),
                         dict(CallStatus='completed'))
        self.assertEquals(COMPLETED, IVRCall.objects.get(pk=call.pk).status)

        # simulation gets flipped off by middleware, and this unhandled message doesn't flip it back on
        self.assertFalse(Contact.get_simulation())

        # test other our call status mappings with twilio
        def test_status_update(call_to_update, twilio_status, temba_status):
            call_to_update.update_status(twilio_status, 0)
            call_to_update.save()
            self.assertEquals(temba_status,
                              IVRCall.objects.get(pk=call_to_update.pk).status)

        test_status_update(call, 'queued', QUEUED)
        test_status_update(call, 'ringing', RINGING)
        test_status_update(call, 'canceled', CANCELED)
        test_status_update(call, 'busy', BUSY)
        test_status_update(call, 'failed', FAILED)
        test_status_update(call, 'no-answer', NO_ANSWER)

        # explicitly hanging up an in progress call should remove it
        call.update_status('in-progress', 0)
        call.save()
        IVRCall.hangup_test_call(flow)
        self.assertIsNone(IVRCall.objects.filter(pk=call.pk).first())
Exemplo n.º 25
0
 def process_request(self, request):
     Contact.set_simulation(False)
     return None
Exemplo n.º 26
0
    def test_ivr_flow(self):
        # should be able to create an ivr flow
        self.assertTrue(self.org.supports_ivr())
        self.assertTrue(self.admin.groups.filter(name="Beta"))
        self.assertContains(self.client.get(reverse('flows.flow_create')),
                            'Phone Call')

        # no twilio config yet
        self.assertFalse(self.org.is_connected_to_twilio())
        self.assertIsNone(self.org.get_twilio_client())

        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN", self.admin)
        self.org.save()
        self.assertTrue(self.org.is_connected_to_twilio())
        self.assertIsNotNone(self.org.get_twilio_client())

        # import an ivr flow
        self.import_file('call_me_maybe')

        # make sure our flow is there as expected
        flow = Flow.objects.filter(name='Call me maybe').first()
        self.assertEquals(
            'callme',
            flow.triggers.filter(trigger_type='K').first().keyword)

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        # start our flow as a test contact
        test_contact = Contact.get_test_contact(self.admin)
        Contact.set_simulation(True)
        flow.start([], [test_contact])
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        # should be using the usersettings number in test mode
        self.assertEquals('Placing test call to +1 800-555-1212',
                          ActionLog.objects.all().first().text)

        # explicitly hanging up on a test call should remove it
        call.update_status('in-progress', 0)
        call.save()
        IVRCall.hangup_test_call(flow)
        self.assertTrue(IVRCall.objects.filter(pk=call.pk).first())

        ActionLog.objects.all().delete()
        IVRCall.objects.all().delete()

        # now pretend we are a normal caller
        eric = self.create_contact('Eric Newcomer', number='+13603621737')
        Contact.set_simulation(False)
        flow.start([], [eric], restart_participants=True)

        # we should have an outbound ivr call now
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        self.assertEquals(0, call.get_duration())
        self.assertIsNotNone(call)
        self.assertEquals('CallSid', call.external_id)

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid',
                         CallStatus='in-progress',
                         CallDuration=20)
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)

        self.assertContains(
            response,
            '<Say>Would you like me to call you? Press one for yes, two for no, or three for maybe.</Say>'
        )
        self.assertEquals(1, Msg.all_messages.filter(msg_type=IVR).count())
        self.assertEquals(1, self.org.get_credits_used())

        # make sure a message from the person on the call goes to the
        # inbox since our flow doesn't handle text messages
        msg = self.create_msg(direction='I',
                              contact=eric,
                              text="message during phone call")
        self.assertFalse(Flow.find_and_handle(msg))

        # updated our status and duration accordingly
        call = IVRCall.objects.get(pk=call.pk)
        self.assertEquals(20, call.duration)
        self.assertEquals(IN_PROGRESS, call.status)

        # don't press any numbers, but # instead
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]) + "?empty=1", dict())
        self.assertContains(response,
                            '<Say>Press one, two, or three. Thanks.</Say>')
        self.assertEquals(4, self.org.get_credits_used())

        # press the number 4 (unexpected)
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=4))

        # our inbound message should be handled
        msg = Msg.current_messages.filter(
            text='4', msg_type=IVR).order_by('-created_on').first()
        self.assertEqual('H', msg.status)

        self.assertContains(response,
                            '<Say>Press one, two, or three. Thanks.</Say>')
        self.assertEquals(6, self.org.get_credits_used())

        # two more messages, one inbound and it's response
        self.assertEquals(5, Msg.all_messages.filter(msg_type=IVR).count())

        # now let's have them press the number 3 (for maybe)
        response = self.client.post(
            reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=3))
        self.assertContains(response, '<Say>This might be crazy.</Say>')
        messages = Msg.all_messages.filter(msg_type=IVR).order_by('pk')
        self.assertEquals(7, messages.count())
        self.assertEquals(8, self.org.get_credits_used())

        for msg in messages:
            self.assertEquals(1,
                              msg.steps.all().count(),
                              msg="Message '%s' not attached to step" %
                              msg.text)

        # twilio would then disconnect the user and notify us of a completed call
        self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]),
                         dict(CallStatus='completed'))
        call = IVRCall.objects.get(pk=call.pk)
        self.assertEquals(COMPLETED, call.status)
        self.assertFalse(FlowRun.objects.filter(call=call).first().is_active)

        # simulation gets flipped off by middleware, and this unhandled message doesn't flip it back on
        self.assertFalse(Contact.get_simulation())

        # also shouldn't have any ActionLogs for non-test users
        self.assertEquals(0, ActionLog.objects.all().count())
        self.assertEquals(1, flow.get_completed_runs())

        # should still have no active runs
        self.assertEquals(0, FlowRun.objects.filter(is_active=True).count())

        # and we've exited the flow
        step = FlowStep.objects.all().order_by('-pk').first()
        self.assertTrue(step.left_on)

        # test other our call status mappings with twilio
        def test_status_update(call_to_update, twilio_status, temba_status):
            call_to_update.update_status(twilio_status, 0)
            call_to_update.save()
            self.assertEquals(temba_status,
                              IVRCall.objects.get(pk=call_to_update.pk).status)

        test_status_update(call, 'queued', QUEUED)
        test_status_update(call, 'ringing', RINGING)
        test_status_update(call, 'canceled', CANCELED)
        test_status_update(call, 'busy', BUSY)
        test_status_update(call, 'failed', FAILED)
        test_status_update(call, 'no-answer', NO_ANSWER)

        FlowStep.objects.all().delete()
        IVRCall.objects.all().delete()

        # try sending callme trigger
        from temba.msgs.models import INCOMING
        msg = self.create_msg(direction=INCOMING, contact=eric, text="callme")

        # make sure if we are started with a message we still create a normal voice run
        flow.start([], [eric], restart_participants=True, start_msg=msg)

        # we should have an outbound ivr call now, and no steps yet
        call = IVRCall.objects.filter(direction=OUTGOING).first()
        self.assertIsNotNone(call)
        self.assertEquals(0, FlowStep.objects.all().count())

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid',
                         CallStatus='in-progress',
                         CallDuration=20)
        self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]),
                         post_data)

        # should have two flow steps (the outgoing messages, and the step to handle the response)
        steps = FlowStep.objects.all().order_by('pk')

        # the first step has exactly one message which is an outgoing IVR message
        self.assertEquals(1, steps.first().messages.all().count())
        self.assertEquals(
            1,
            steps.first().messages.filter(direction=OUTGOING,
                                          msg_type=IVR).count())

        # the next step shouldn't have any messages yet since they haven't pressed anything
        self.assertEquals(0, steps[1].messages.all().count())

        # try updating our status to completed for a test contact
        Contact.set_simulation(True)
        flow.start([], [test_contact])
        call = IVRCall.objects.filter(
            direction=OUTGOING).order_by('-pk').first()
        call.update_status('completed', 30)
        call.save()
        call.refresh_from_db()

        self.assertEqual(ActionLog.objects.all().order_by('-pk').first().text,
                         'Call ended.')
        self.assertEqual(call.duration, 30)

        # now look at implied duration
        call.update_status('in-progress', None)
        call.save()
        call.refresh_from_db()
        self.assertIsNotNone(call.get_duration())
Exemplo n.º 27
0
    def __call__(self, request):
        Contact.set_simulation(False)

        response = self.get_response(request)
        return response
Exemplo n.º 28
0
    def setUp(self):
        self.clear_cache()

        self.superuser = User.objects.create_superuser(username="******",
                                                       email="*****@*****.**",
                                                       password="******")

        # some users not tied to our org
        self.non_org_user = self.create_user("NonOrg")
        self.non_org_manager = self.create_user("NonOrgManager")

        # our three user types inside our org
        self.user = self.create_user("User")
        self.root = self.create_user("Root")
        self.root.groups.add(Group.objects.get(name="Alpha"))

        self.admin = self.create_user("Administrator")

        # setup admin boundaries for Rwanda
        self.country = AdminBoundary.objects.create(osm_id='171496',
                                                    name='Rwanda',
                                                    level=0)
        state1 = AdminBoundary.objects.create(osm_id='1708283',
                                              name='Kigali City',
                                              level=1,
                                              parent=self.country)
        state2 = AdminBoundary.objects.create(osm_id='171591',
                                              name='Eastern Province',
                                              level=1,
                                              parent=self.country)
        AdminBoundary.objects.create(osm_id='1711131',
                                     name='Gatsibo',
                                     level=2,
                                     parent=state2)
        AdminBoundary.objects.create(osm_id='1711163',
                                     name='Kayonza',
                                     level=2,
                                     parent=state2)
        AdminBoundary.objects.create(osm_id='60485579',
                                     name='Kigali',
                                     level=2,
                                     parent=state1)
        AdminBoundary.objects.create(osm_id='1711142',
                                     name='Rwamagana',
                                     level=2,
                                     parent=state2)

        self.org = Org.objects.create(name="Temba",
                                      timezone="Africa/Kigali",
                                      country=self.country,
                                      created_by=self.user,
                                      modified_by=self.user)

        # add users to the org
        self.org.administrators.add(self.admin)
        self.admin.set_org(self.org)

        self.org.administrators.add(self.root)
        self.root.set_org(self.org)

        self.user.set_org(self.org)
        self.superuser.set_org(self.org)

        # welcome topup with 1000 credits
        self.welcome_topup = self.org.create_welcome_topup(self.admin)

        # a single Android channel
        self.channel = Channel.objects.create(org=self.org,
                                              name="Test Channel",
                                              address="+250785551212",
                                              country='RW',
                                              channel_type='A',
                                              secret="12345",
                                              gcm_id="123",
                                              created_by=self.user,
                                              modified_by=self.user)

        # reset our simulation to False
        Contact.set_simulation(False)
Exemplo n.º 29
0
    def test_ivr_flow(self):
        # should be able to create an ivr flow
        self.assertTrue(self.org.supports_ivr())
        self.assertTrue(self.admin.groups.filter(name="Beta"))
        self.assertContains(self.client.get(reverse('flows.flow_create')), 'Phone Call')

        # no twilio config yet
        self.assertFalse(self.org.is_connected_to_twilio())
        self.assertIsNone(self.org.get_twilio_client())

        # connect it and check our client is configured
        self.org.connect_twilio("TEST_SID", "TEST_TOKEN")
        self.org.save()
        self.assertTrue(self.org.is_connected_to_twilio())
        self.assertIsNotNone(self.org.get_twilio_client())

        # import an ivr flow
        self.import_file('call-me-maybe')

        # make sure our flow is there as expected
        flow = Flow.objects.filter(name='Call me maybe').first()
        self.assertEquals('callme', flow.triggers.filter(trigger_type='K').first().keyword)

        user_settings = self.admin.get_settings()
        user_settings.tel = '+18005551212'
        user_settings.save()

        # start our flow as a test contact
        test_contact = Contact.get_test_contact(self.admin)
        Contact.set_simulation(True)
        flow.start([], [test_contact])
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        # should be using the usersettings number in test mode
        self.assertEquals('Placing test call to +1 800-555-1212', ActionLog.objects.all().first().text)

        # explicitly hanging up on a test call should remove it
        call.update_status('in-progress', 0)
        call.save()
        IVRCall.hangup_test_call(flow)
        self.assertIsNone(IVRCall.objects.filter(pk=call.pk).first())

        ActionLog.objects.all().delete()
        IVRCall.objects.all().delete()

        # now pretend we are a normal caller
        eric = self.create_contact('Eric Newcomer', number='+13603621737')
        Contact.set_simulation(False)
        flow.start([], [eric], restart_participants=True)

        # we should have an outbound ivr call now
        call = IVRCall.objects.filter(direction=OUTGOING).first()

        self.assertEquals(0, call.get_duration())
        self.assertIsNotNone(call)
        self.assertEquals('CallSid', call.external_id)

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid', CallStatus='in-progress', CallDuration=20)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)

        self.assertContains(response, '<Say>Would you like me to call you? Press one for yes, two for no, or three for maybe.</Say>')
        self.assertEquals(1, Msg.all_messages.filter(msg_type=IVR).count())
        self.assertEquals(1, self.org.get_credits_used())

        # make sure a message from the person on the call goes to the
        # inbox since our flow doesn't handle text messages
        msg = self.create_msg(direction='I', contact=eric, text="message during phone call")
        self.assertFalse(Flow.find_and_handle(msg))

        # updated our status and duration accordingly
        call = IVRCall.objects.get(pk=call.pk)
        self.assertEquals(20, call.duration)
        self.assertEquals(IN_PROGRESS, call.status)

        # press the number 4 (unexpected)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=4))
        self.assertContains(response, '<Say>Press one, two, or three. Thanks.</Say>')
        self.assertEquals(4, self.org.get_credits_used())

        # two more messages, one inbound and it's response
        self.assertEquals(3, Msg.all_messages.filter(msg_type=IVR).count())

        # now let's have them press the number 3 (for maybe)
        response = self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), dict(Digits=3))
        self.assertContains(response, '<Say>This might be crazy.</Say>')
        messages = Msg.all_messages.filter(msg_type=IVR).order_by('pk')
        self.assertEquals(5, messages.count())
        self.assertEquals(6, self.org.get_credits_used())

        for msg in messages:
            self.assertEquals(1, msg.steps.all().count(), msg="Message '%s' not attached to step" % msg.text)

        # twilio would then disconnect the user and notify us of a completed call
        self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), dict(CallStatus='completed'))
        call = IVRCall.objects.get(pk=call.pk)
        self.assertEquals(COMPLETED, call.status)
        self.assertFalse(FlowRun.objects.filter(call=call).first().is_active)

        # simulation gets flipped off by middleware, and this unhandled message doesn't flip it back on
        self.assertFalse(Contact.get_simulation())

        # also shouldn't have any ActionLogs for non-test users
        self.assertEquals(0, ActionLog.objects.all().count())
        self.assertEquals(1, flow.get_completed_runs())

        # should still have no active runs
        self.assertEquals(0, FlowRun.objects.filter(is_active=True).count())

        # and we've exited the flow
        step = FlowStep.objects.all().order_by('-pk').first()
        self.assertTrue(step.left_on)

        # test other our call status mappings with twilio
        def test_status_update(call_to_update, twilio_status, temba_status):
            call_to_update.update_status(twilio_status, 0)
            call_to_update.save()
            self.assertEquals(temba_status, IVRCall.objects.get(pk=call_to_update.pk).status)

        test_status_update(call, 'queued', QUEUED)
        test_status_update(call, 'ringing', RINGING)
        test_status_update(call, 'canceled', CANCELED)
        test_status_update(call, 'busy', BUSY)
        test_status_update(call, 'failed', FAILED)
        test_status_update(call, 'no-answer', NO_ANSWER)

        FlowStep.objects.all().delete()
        IVRCall.objects.all().delete()

        # try sending callme trigger
        from temba.msgs.models import INCOMING
        msg = self.create_msg(direction=INCOMING, contact=eric, text="callme")

        # make sure if we are started with a message we still create a normal voice run
        flow.start([], [eric], restart_participants=True, start_msg=msg)

        # we should have an outbound ivr call now, and no steps yet
        call = IVRCall.objects.filter(direction=OUTGOING).first()
        self.assertIsNotNone(call)
        self.assertEquals(0, FlowStep.objects.all().count())

        # after a call is picked up, twilio will call back to our server
        post_data = dict(CallSid='CallSid', CallStatus='in-progress', CallDuration=20)
        self.client.post(reverse('ivr.ivrcall_handle', args=[call.pk]), post_data)

        # should have two flow steps (the outgoing messages, and the step to handle the response)
        steps = FlowStep.objects.all().order_by('pk')

        # the first step has exactly one message which is an outgoing IVR message
        self.assertEquals(1, steps.first().messages.all().count())
        self.assertEquals(1, steps.first().messages.filter(direction=OUTGOING, msg_type=IVR).count())

        # the next step shouldn't have any messages yet since they haven't pressed anything
        self.assertEquals(0, steps[1].messages.all().count())

        # try updating our status to completed for a test contact
        Contact.set_simulation(True)
        flow.start([], [test_contact])
        call = IVRCall.objects.filter(direction=OUTGOING).order_by('-pk').first()
        call.update_status('completed', 30)
        call.save()
        call.refresh_from_db()

        self.assertEqual(ActionLog.objects.all().order_by('-pk').first().text, 'Call ended.')
        self.assertEqual(call.duration, 30)

        # now look at implied duration
        call.update_status('in-progress', None)
        call.save()
        call.refresh_from_db()
        self.assertIsNotNone(call.get_duration())
Exemplo n.º 30
0
    def setUp(self):
        self.maxDiff = 4096
        self.mock_server = mock_server

        # if we are super verbose, turn on debug for sql queries
        if self.get_verbosity() > 2:
            settings.DEBUG = True

        # make sure we start off without any service users
        Group.objects.get(name="Service Users").user_set.clear()

        self.clear_cache()

        self.create_anonymous_user()

        self.superuser = User.objects.create_superuser(username="******",
                                                       email="*****@*****.**",
                                                       password="******")

        # create different user types
        self.non_org_user = self.create_user("NonOrg")
        self.user = self.create_user("User")
        self.editor = self.create_user("Editor")
        self.admin = self.create_user("Administrator")
        self.surveyor = self.create_user("Surveyor")
        self.customer_support = self.create_user("support",
                                                 ("Customer Support", ))

        # setup admin boundaries for Rwanda
        self.country = AdminBoundary.create(osm_id="171496",
                                            name="Rwanda",
                                            level=0)
        self.state1 = AdminBoundary.create(osm_id="1708283",
                                           name="Kigali City",
                                           level=1,
                                           parent=self.country)
        self.state2 = AdminBoundary.create(osm_id="171591",
                                           name="Eastern Province",
                                           level=1,
                                           parent=self.country)
        self.district1 = AdminBoundary.create(osm_id="1711131",
                                              name="Gatsibo",
                                              level=2,
                                              parent=self.state2)
        self.district2 = AdminBoundary.create(osm_id="1711163",
                                              name="Kayônza",
                                              level=2,
                                              parent=self.state2)
        self.district3 = AdminBoundary.create(osm_id="3963734",
                                              name="Nyarugenge",
                                              level=2,
                                              parent=self.state1)
        self.district4 = AdminBoundary.create(osm_id="1711142",
                                              name="Rwamagana",
                                              level=2,
                                              parent=self.state2)
        self.ward1 = AdminBoundary.create(osm_id="171113181",
                                          name="Kageyo",
                                          level=3,
                                          parent=self.district1)
        self.ward2 = AdminBoundary.create(osm_id="171116381",
                                          name="Kabare",
                                          level=3,
                                          parent=self.district2)
        self.ward3 = AdminBoundary.create(osm_id="171114281",
                                          name="Bukure",
                                          level=3,
                                          parent=self.district4)

        self.country.update_path()

        self.org = Org.objects.create(
            name="Temba",
            timezone=pytz.timezone("Africa/Kigali"),
            country=self.country,
            brand=settings.DEFAULT_BRAND,
            created_by=self.user,
            modified_by=self.user,
        )

        self.org.initialize(topup_size=1000)

        # add users to the org
        self.user.set_org(self.org)
        self.org.viewers.add(self.user)

        self.editor.set_org(self.org)
        self.org.editors.add(self.editor)

        self.admin.set_org(self.org)
        self.org.administrators.add(self.admin)

        self.surveyor.set_org(self.org)
        self.org.surveyors.add(self.surveyor)

        self.superuser.set_org(self.org)

        # welcome topup with 1000 credits
        self.welcome_topup = self.org.topups.all()[0]

        # a single Android channel
        self.channel = Channel.create(
            self.org,
            self.user,
            "RW",
            "A",
            name="Test Channel",
            address="+250785551212",
            device="Nexus 5X",
            secret="12345",
            gcm_id="123",
        )

        # don't cache anon user between tests
        from temba import utils

        utils._anon_user = None
        clear_flow_users()

        # reset our simulation to False
        Contact.set_simulation(False)