Ejemplo n.º 1
0
    def test_ussd_trigger_flow(self):
        # start a session
        callback_url = reverse('handlers.vumi_handler',
                               args=['receive', self.channel.uuid])
        ussd_code = "*111#"
        data = dict(timestamp="2016-04-18 03:54:20.570618",
                    message_id="123456",
                    from_addr="+250788383383",
                    content="None",
                    transport_type='ussd',
                    session_event="new",
                    to_addr=ussd_code)
        response = self.client.post(callback_url,
                                    json.dumps(data),
                                    content_type="application/json")
        flow = self.get_flow('ussd_trigger_flow')
        self.assertEquals(0, flow.runs.all().count())

        trigger, _ = Trigger.objects.get_or_create(
            channel=self.channel,
            keyword=ussd_code,
            flow=flow,
            created_by=self.user,
            modified_by=self.user,
            org=self.org,
            trigger_type=Trigger.TYPE_USSD_PULL)

        # now we added the trigger, let's reinitiate the session
        response = self.client.post(callback_url,
                                    json.dumps(data),
                                    content_type="application/json")

        msg = Msg.objects.all().first()
        self.assertEqual("Please enter a phone number", msg.text)

        from_addr = "+250788383383"
        data = dict(timestamp="2016-04-18 03:54:20.570618",
                    message_id="123456",
                    from_addr=from_addr,
                    content="250788123123",
                    to_addr="*113#",
                    transport_type='ussd')

        response = self.client.post(callback_url,
                                    json.dumps(data),
                                    content_type="application/json")

        self.assertEqual(response.status_code, 200)

        msg = Msg.objects.all().order_by('-created_on').first()

        # We should get the final message
        self.assertEqual("Thank you", msg.text)

        # Check the new contact was created
        new_contact = Contact.from_urn(self.org, "tel:+250788123123")
        self.assertIsNotNone(new_contact)
Ejemplo n.º 2
0
    def clean(self):
        country = self.org.get_country_code()

        # validate URN fields
        for field_key, value in self.cleaned_data.iteritems():
            if field_key.startswith('__urn__') and value:
                scheme = field_key[7:field_key.rfind('__')]

                norm_scheme, norm_path = ContactURN.normalize_urn(scheme, value, country)
                existing = Contact.from_urn(self.org, norm_scheme, norm_path)

                if existing and existing != self.instance:
                    self._errors[field_key] = _("Used by another contact")
                elif not ContactURN.validate_urn(norm_scheme, norm_path):
                    self._errors[field_key] = _("Invalid format")

        return self.cleaned_data
Ejemplo n.º 3
0
    def validate_urns(self, value):
        org = self.context['org']

        # this field isn't allowed if we are looking up by URN in the URL
        if 'urns__urn' in self.context['lookup_values']:
            raise serializers.ValidationError("Field not allowed when using URN in URL")

        # or for updates by anonymous organizations (we do allow creation of contacts with URNs)
        if org.is_anon and self.instance:
            raise serializers.ValidationError("Updating URNs not allowed for anonymous organizations")

        # if creating a contact, URNs can't belong to other contacts
        if not self.instance:
            for urn in value:
                if Contact.from_urn(org, urn):
                    raise serializers.ValidationError("URN belongs to another contact: %s" % urn)

        return value
Ejemplo n.º 4
0
    def clean(self):
        channel = self.org.get_receive_channel(TEL_SCHEME)
        country = channel.country if channel else None

        # validate URN fields
        for field_key, value in self.cleaned_data.iteritems():
            if field_key.startswith('__urn__') and value:
                scheme = field_key[7:]

                norm_scheme, norm_path = ContactURN.normalize_urn(scheme, value, country)
                existing = Contact.from_urn(self.org, norm_scheme, norm_path)

                if existing and existing != self.instance:
                    self._errors[field_key] = _("Used by another contact")
                elif not ContactURN.validate_urn(norm_scheme, norm_path):
                    self._errors[field_key] = _("Invalid format")

        return self.cleaned_data
Ejemplo n.º 5
0
    def validate_urns(self, value):
        org = self.context['org']

        # this field isn't allowed if we are looking up by URN in the URL
        if 'urns__urn' in self.context['lookup_values']:
            raise serializers.ValidationError("Field not allowed when using URN in URL")

        # or for updates by anonymous organizations (we do allow creation of contacts with URNs)
        if org.is_anon and self.instance:
            raise serializers.ValidationError("Updating URNs not allowed for anonymous organizations")

        # if creating a contact, URNs can't belong to other contacts
        if not self.instance:
            for urn in value:
                if Contact.from_urn(org, urn):
                    raise serializers.ValidationError("URN belongs to another contact: %s" % urn)

        return value
Ejemplo n.º 6
0
    def clean(self):
        channel = self.org.get_receive_channel(TEL_SCHEME)
        country = channel.country if channel else None

        # validate URN fields
        for field_key, value in self.cleaned_data.iteritems():
            if field_key.startswith('__urn__') and value:
                scheme = field_key[7:]

                norm_scheme, norm_path = ContactURN.normalize_urn(scheme, value, country)
                existing = Contact.from_urn(self.org, norm_scheme, norm_path)

                if existing and existing != self.instance:
                    self._errors[field_key] = _("Used by another contact")
                elif not ContactURN.validate_urn(norm_scheme, norm_path):
                    self._errors[field_key] = _("Invalid format")

        return self.cleaned_data
Ejemplo n.º 7
0
    def validate(self, data):
        org = self.context['org']

        # we don't allow updating of contact URNs for anon orgs - tho we do allow creation of contacts with URNs
        if org.is_anon and self.instance and data.get('urns'):
            raise serializers.ValidationError("Updating contact URNs not allowed for anonymous organizations")

        # if creating a contact, urns can't include URNs which are already taken
        if not self.instance and 'urns' in data:
            country_code = org.get_country_code()
            for urn in data['urns']:
                if Contact.from_urn(org, urn, country_code):
                    raise serializers.ValidationError("Contact URN belongs to another contact: %s" % urn)

        # if contact is blocked, they can't be added to groups
        if self.instance and (self.instance.is_blocked or self.instance.is_stopped) and data['groups']:
            raise serializers.ValidationError("Blocked or stopped contacts can't be added to groups")

        return data
Ejemplo n.º 8
0
    def validate(self, data):
        org = self.context['org']

        # we don't allow updating of contact URNs for anon orgs - tho we do allow creation of contacts with URNs
        if org.is_anon and self.instance and data.get('urns'):
            raise serializers.ValidationError("Updating contact URNs not allowed for anonymous organizations")

        # if creating a contact, urns can't include URNs which are already taken
        if not self.instance and 'urns' in data:
            country_code = org.get_country_code()
            for urn in data['urns']:
                if Contact.from_urn(org, urn, country_code):
                    raise serializers.ValidationError("Contact URN belongs to another contact: %s" % urn)

        # if contact is blocked, they can't be added to groups
        if self.instance and (self.instance.is_blocked or self.instance.is_stopped) and data['groups']:
            raise serializers.ValidationError("Blocked or stopped contacts can't be added to groups")

        return data
Ejemplo n.º 9
0
    def test_new_conversation_trigger(self):
        self.login(self.admin)
        flow = self.create_flow()
        flow2 = self.create_flow()

        # see if we list new conversation triggers on the trigger page
        create_trigger_url = reverse('triggers.trigger_create', args=[])
        response = self.client.get(create_trigger_url)
        self.assertNotContains(response, "conversation is started")

        # create a facebook channel
        fb_channel = Channel.add_facebook_channel(self.org, self.user, 'Temba', 1001, 'fb_token')

        # should now be able to create one
        response = self.client.get(create_trigger_url)
        self.assertContains(response, "conversation is started")

        # go create it
        with patch('requests.post') as mock_post:
            mock_post.return_value = MockResponse(200, '{"message": "Success"}')

            response = self.client.post(reverse('triggers.trigger_new_conversation', args=[]),
                                        data=dict(channel=fb_channel.id, flow=flow.id))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(mock_post.call_count, 1)

        # check that it is right
        trigger = Trigger.objects.get(trigger_type=Trigger.TYPE_NEW_CONVERSATION, is_active=True, is_archived=False)
        self.assertEqual(trigger.channel, fb_channel)
        self.assertEqual(trigger.flow, flow)

        # try to create another one, fails as we already have a trigger for that channel
        response = self.client.post(reverse('triggers.trigger_new_conversation', args=[]), data=dict(channel=fb_channel.id, flow=flow2.id))
        self.assertEqual(response.status_code, 200)
        self.assertFormError(response, 'form', 'channel', 'Trigger with this Channel already exists.')

        # ok, trigger a facebook event
        data = json.loads("""{
        "object": "page",
          "entry": [
            {
              "id": "620308107999975",
              "time": 1467841778778,
              "messaging": [
                {
                  "sender":{
                    "id":"1001"
                  },
                  "recipient":{
                    "id":"%s"
                  },
                  "timestamp":1458692752478,
                  "postback":{
                    "payload":"get_started"
                  }
                }
              ]
            }
          ]
        }
        """ % fb_channel.address)

        with patch('requests.get') as mock_get:
            mock_get.return_value = MockResponse(200, '{"first_name": "Ben","last_name": "Haggerty"}')

            callback_url = reverse('handlers.facebook_handler', args=[fb_channel.uuid])
            response = self.client.post(callback_url, json.dumps(data), content_type="application/json")
            self.assertEqual(response.status_code, 200)

            # should have a new flow run for Ben
            contact = Contact.from_urn(self.org, 'facebook:1001')
            self.assertTrue(contact.name, "Ben Haggerty")

            run = FlowRun.objects.get(contact=contact)
            self.assertEqual(run.flow, flow)

        # archive our trigger, should unregister our callback
        with patch('requests.post') as mock_post:
            mock_post.return_value = MockResponse(200, '{"message": "Success"}')

            Trigger.apply_action_archive(self.admin, Trigger.objects.filter(pk=trigger.pk))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(mock_post.call_count, 1)

            trigger.refresh_from_db()
            self.assertTrue(trigger.is_archived)
Ejemplo n.º 10
0
    def validate_urn(self, value):
        if self.context['org'].is_anon:
            raise serializers.ValidationError("Referencing by URN not allowed for anonymous organizations")

        self.instance = Contact.from_urn(self.context['org'], value)
        return value
Ejemplo n.º 11
0
    def test_new_conversation_trigger(self):
        self.login(self.admin)
        flow = self.create_flow()
        flow2 = self.create_flow()

        # see if we list new conversation triggers on the trigger page
        create_trigger_url = reverse('triggers.trigger_create', args=[])
        response = self.client.get(create_trigger_url)
        self.assertNotContains(response, "conversation is started")

        # create a facebook channel
        fb_channel = Channel.add_facebook_channel(self.org, self.user, 'Temba', 1001, 'fb_token')

        # should now be able to create one
        response = self.client.get(create_trigger_url)
        self.assertContains(response, "conversation is started")

        # go create it
        with patch('requests.post') as mock_post:
            mock_post.return_value = MockResponse(200, '{"message": "Success"}')

            response = self.client.post(reverse('triggers.trigger_new_conversation', args=[]),
                                        data=dict(channel=fb_channel.id, flow=flow.id))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(mock_post.call_count, 1)

        # check that it is right
        trigger = Trigger.objects.get(trigger_type=Trigger.TYPE_NEW_CONVERSATION, is_active=True, is_archived=False)
        self.assertEqual(trigger.channel, fb_channel)
        self.assertEqual(trigger.flow, flow)

        # try to create another one, fails as we already have a trigger for that channel
        response = self.client.post(reverse('triggers.trigger_new_conversation', args=[]), data=dict(channel=fb_channel.id, flow=flow2.id))
        self.assertEqual(response.status_code, 200)
        self.assertFormError(response, 'form', 'channel', 'Trigger with this Channel already exists.')

        # ok, trigger a facebook event
        data = json.loads("""{
        "object": "page",
          "entry": [
            {
              "id": "620308107999975",
              "time": 1467841778778,
              "messaging": [
                {
                  "sender":{
                    "id":"1001"
                  },
                  "recipient":{
                    "id":"%s"
                  },
                  "timestamp":1458692752478,
                  "postback":{
                    "payload":"get_started"
                  }
                }
              ]
            }
          ]
        }
        """ % fb_channel.address)

        with patch('requests.get') as mock_get:
            mock_get.return_value = MockResponse(200, '{"first_name": "Ben","last_name": "Haggerty"}')

            callback_url = reverse('handlers.facebook_handler', args=[fb_channel.uuid])
            response = self.client.post(callback_url, json.dumps(data), content_type="application/json")
            self.assertEqual(response.status_code, 200)

            # should have a new flow run for Ben
            contact = Contact.from_urn(self.org, 'facebook:1001')
            self.assertTrue(contact.name, "Ben Haggerty")

            run = FlowRun.objects.get(contact=contact)
            self.assertEqual(run.flow, flow)

        # archive our trigger, should unregister our callback
        with patch('requests.post') as mock_post:
            mock_post.return_value = MockResponse(200, '{"message": "Success"}')

            Trigger.apply_action_archive(self.admin, Trigger.objects.filter(pk=trigger.pk))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(mock_post.call_count, 1)

            trigger.refresh_from_db()
            self.assertTrue(trigger.is_archived)
Ejemplo n.º 12
0
    def validate_urn(self, value):
        if self.context['org'].is_anon:
            raise serializers.ValidationError("Referencing by URN not allowed for anonymous organizations")

        self.instance = Contact.from_urn(self.context['org'], value)
        return value