コード例 #1
0
ファイル: perf_tests.py プロジェクト: xuanhan863/rapidpro
    def setUp(self):
        self.clear_cache()

        self.user = self.create_user("tito")
        self.admin = self.create_user("Administrator")
        self.org = Org.objects.create(name="Nyaruka Ltd.", timezone="Africa/Kigali",
                                      created_by=self.user, modified_by=self.user)
        self.org.administrators.add(self.admin)
        self.admin.set_org(self.org)
        self.org.administrators.add(self.user)
        self.user.set_org(self.org)

        self.tel_mtn = Channel.objects.create(org=self.org, name="MTN", channel_type="A", role="SR",
                                              address="+250780000000", secret="12345", gcm_id="123",
                                              created_by=self.user, modified_by=self.user)
        self.tel_tigo = Channel.objects.create(org=self.org, name="Tigo", channel_type="A", role="SR",
                                               address="+250720000000", secret="23456", gcm_id="234",
                                               created_by=self.user, modified_by=self.user)
        self.tel_bulk = Channel.objects.create(org=self.org, name="Nexmo", channel_type="NX", role="S",
                                               parent=self.tel_tigo, secret="34567",
                                               created_by=self.user, modified_by=self.user)
        self.twitter = Channel.objects.create(org=self.org, name="Twitter", channel_type="TT", role="SR",
                                              created_by=self.user, modified_by=self.user)

        # for generating tuples of scheme, path and channel
        generate_tel_mtn = lambda num: (TEL_SCHEME, "+25078%07d" % (num + 1), self.tel_mtn)
        generate_tel_tigo = lambda num: (TEL_SCHEME, "+25072%07d" % (num + 1), self.tel_tigo)
        generate_twitter = lambda num: (TWITTER_SCHEME, "tweep_%d" % (num + 1), self.twitter)
        self.urn_generators = (generate_tel_mtn, generate_tel_tigo, generate_twitter)

        self.field_nick = ContactField.get_or_create(self.org, 'nick', 'Nickname', show_in_table=True, value_type=TEXT)
        self.field_age = ContactField.get_or_create(self.org, 'age', 'Age', show_in_table=True, value_type=DECIMAL)
コード例 #2
0
ファイル: perf_tests.py プロジェクト: joeynimu/rapidpro
    def setUp(self):
        self.clear_cache()

        self.user = self.create_user("tito")
        self.admin = self.create_user("Administrator")
        self.org = Org.objects.create(name="Nyaruka Ltd.", timezone="Africa/Kigali",
                                      created_by=self.user, modified_by=self.user)
        self.org.initialize()

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

        self.tel_mtn = Channel.objects.create(org=self.org, name="MTN", channel_type="A", role="SR",
                                              address="+250780000000", secret="12345", gcm_id="123",
                                              created_by=self.user, modified_by=self.user)
        self.tel_tigo = Channel.objects.create(org=self.org, name="Tigo", channel_type="A", role="SR",
                                               address="+250720000000", secret="23456", gcm_id="234",
                                               created_by=self.user, modified_by=self.user)
        self.tel_bulk = Channel.objects.create(org=self.org, name="Nexmo", channel_type="NX", role="S",
                                               parent=self.tel_tigo, secret="34567",
                                               created_by=self.user, modified_by=self.user)
        self.twitter = Channel.objects.create(org=self.org, name="Twitter", channel_type="TT", role="SR",
                                              created_by=self.user, modified_by=self.user)

        # for generating tuples of scheme, path and channel
        generate_tel_mtn = lambda num: (TEL_SCHEME, "+25078%07d" % (num + 1), self.tel_mtn)
        generate_tel_tigo = lambda num: (TEL_SCHEME, "+25072%07d" % (num + 1), self.tel_tigo)
        generate_twitter = lambda num: (TWITTER_SCHEME, "tweep_%d" % (num + 1), self.twitter)
        self.urn_generators = (generate_tel_mtn, generate_tel_tigo, generate_twitter)

        self.field_nick = ContactField.get_or_create(self.org, 'nick', 'Nickname', show_in_table=True, value_type=TEXT)
        self.field_age = ContactField.get_or_create(self.org, 'age', 'Age', show_in_table=True, value_type=DECIMAL)
コード例 #3
0
ファイル: perf_tests.py プロジェクト: Ilhasoft/rapidpro
    def setUp(self):
        self.clear_cache()

        self.user = self.create_user("tito")
        self.admin = self.create_user("Administrator")
        self.org = Org.objects.create(name="Nyaruka Ltd.", timezone="Africa/Kigali",
                                      created_by=self.user, modified_by=self.user)
        self.org.initialize()

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

        self.tel_mtn = Channel.create(self.org, self.user, 'RW', 'A', name="MTN", address="+250780000000",
                                      secret="12345", gcm_id="123")
        self.tel_tigo = Channel.create(self.org, self.user, 'RW', 'A', name="Tigo", address="+250720000000",
                                       secret="23456", gcm_id="234")
        self.tel_bulk = Channel.create(self.org, self.user, 'RW', 'NX', name="Nexmo", parent=self.tel_tigo)
        self.twitter = Channel.create(self.org, self.user, None, 'TT', name="Twitter", address="billy_bob")

        # for generating tuples of scheme, path and channel
        def generate_tel_mtn(num):
            return TEL_SCHEME, "+25078%07d" % (num + 1), self.tel_mtn

        def generate_tel_tigo(num):
            return TEL_SCHEME, "+25072%07d" % (num + 1), self.tel_tigo

        def generate_twitter(num):
            return TWITTER_SCHEME, "tweep_%d" % (num + 1), self.twitter

        self.urn_generators = (generate_tel_mtn, generate_tel_tigo, generate_twitter)

        self.field_nick = ContactField.get_or_create(self.org, self.admin, 'nick', 'Nickname', show_in_table=True, value_type=Value.TYPE_TEXT)
        self.field_age = ContactField.get_or_create(self.org, self.admin, 'age', 'Age', show_in_table=True, value_type=Value.TYPE_DECIMAL)
コード例 #4
0
ファイル: test_v2.py プロジェクト: JediKoder/rapidpro
    def test_campaign_events(self):
        url = reverse('api.v2.campaign_events')

        self.assertEndpointAccess(url)

        flow = self.create_flow()
        reporters = self.create_group("Reporters", [self.joe, self.frank])
        registration = ContactField.get_or_create(self.org, self.admin, 'registration', "Registration")

        campaign1 = Campaign.create(self.org, self.admin, "Reminders", reporters)
        event1 = CampaignEvent.create_message_event(self.org, self.admin, campaign1, registration,
                                                    1, CampaignEvent.UNIT_DAYS, "Don't forget to brush your teeth")

        campaign2 = Campaign.create(self.org, self.admin, "Notifications", reporters)
        event2 = CampaignEvent.create_flow_event(self.org, self.admin, campaign2, registration,
                                                 6, CampaignEvent.UNIT_HOURS, flow, delivery_hour=12)

        # create event for another org
        joined = ContactField.get_or_create(self.org2, self.admin2, 'joined', "Joined On")
        spammers = ContactGroup.get_or_create(self.org2, self.admin2, "Spammers")
        spam = Campaign.create(self.org2, self.admin2, "Cool stuff", spammers)
        CampaignEvent.create_flow_event(self.org2, self.admin2, spam, joined,
                                        6, CampaignEvent.UNIT_HOURS, flow, delivery_hour=12)

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

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json['next'], None)
        self.assertResultsByUUID(response, [event2, event1])
        self.assertEqual(response.json['results'][0], {
            'uuid': event2.uuid,
            'campaign': {'uuid': campaign2.uuid, 'name': "Notifications"},
            'relative_to': {'key': "registration", 'label': "Registration"},
            'offset': 6,
            'unit': 'hours',
            'delivery_hour': 12,
            'flow': {'uuid': flow.uuid, 'name': "Color Flow"},
            'message': None,
            'created_on': format_datetime(event2.created_on)
        })

        # filter by UUID
        response = self.fetchJSON(url, 'uuid=%s' % event1.uuid)
        self.assertResultsByUUID(response, [event1])

        # filter by campaign name
        response = self.fetchJSON(url, 'campaign=Reminders')
        self.assertResultsByUUID(response, [event1])

        # filter by campaign UUID
        response = self.fetchJSON(url, 'campaign=%s' % campaign1.uuid)
        self.assertResultsByUUID(response, [event1])

        # filter by invalid campaign
        response = self.fetchJSON(url, 'campaign=invalid')
        self.assertResultsByUUID(response, [])
コード例 #5
0
    def test_field_results(self):
        (c1, c2, c3, c4) = (self.create_contact("Contact1", '0788111111'),
                            self.create_contact("Contact2", '0788222222'),
                            self.create_contact("Contact3", '0788333333'),
                            self.create_contact("Contact4", '0788444444'))

        # create a gender field that uses strings
        gender = ContactField.get_or_create(self.org, 'gender', label="Gender", value_type=TEXT)

        c1.set_field('gender', "Male")
        c2.set_field('gender', "Female")
        c3.set_field('gender', "Female")

        result = Value.get_value_summary(contact_field=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset']) # this is two as we have the default contact created by our unit tests
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Female", 2)
        self.assertResult(result, 1, "Male", 1)

        # create an born field that uses decimals
        born = ContactField.get_or_create(self.org, 'born', label="Born", value_type=DECIMAL)
        c1.set_field('born', 1977)
        c2.set_field('born', 1990)
        c3.set_field('born', 1977)

        result = Value.get_value_summary(contact_field=born)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "1977", 2)
        self.assertResult(result, 1, "1990", 1)

        # ok, state field!
        state = ContactField.get_or_create(self.org, 'state', label="State", value_type=STATE)
        c1.set_field('state', "Kigali City")
        c2.set_field('state', "Kigali City")

        result = Value.get_value_summary(contact_field=state)[0]
        self.assertEquals(1, len(result['categories']))
        self.assertEquals(2, result['set'])
        self.assertEquals(3, result['unset'])
        self.assertResult(result, 0, "1708283", 2)

        reg_date = ContactField.get_or_create(self.org, 'reg_date', label="Registration Date", value_type=DATETIME)
        now = timezone.now()

        c1.set_field('reg_date', now.replace(hour=9))
        c2.set_field('reg_date', now.replace(hour=4))
        c3.set_field('reg_date', now - timedelta(days=1))
        result = Value.get_value_summary(contact_field=reg_date)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertResult(result, 0, (now - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0), 1)
        self.assertResult(result, 1, now.replace(hour=0, minute=0, second=0, microsecond=0), 2)
コード例 #6
0
ファイル: tests.py プロジェクト: qoda/rapidpro
    def test_dst_scheduling(self):
        # set our timezone to something that honors DST
        eastern = pytz.timezone("US/Eastern")
        self.org.timezone = eastern
        self.org.save()

        # create our campaign and event
        campaign = Campaign.create(self.org, self.admin, "Planting Reminders", self.farmers)
        event = CampaignEvent.create_flow_event(
            self.org, self.admin, campaign, relative_to=self.planting_date, offset=2, unit="D", flow=self.reminder_flow
        )

        # set the time to something pre-dst (fall back on November 4th at 2am to 1am)
        self.farmer1.set_field(self.user, "planting_date", "03-11-2029 12:30:00")
        EventFire.update_campaign_events(campaign)

        # try changing our field type to something non-date, should throw
        with self.assertRaises(ValueError):
            ContactField.get_or_create(self.org, self.admin, "planting_date", value_type=Value.TYPE_TEXT)

        # we should be scheduled to go off on the 5th at 12:30:10 Eastern
        fire = EventFire.objects.get()
        self.assertEqual(5, fire.scheduled.day)
        self.assertEqual(11, fire.scheduled.month)
        self.assertEqual(2029, fire.scheduled.year)
        self.assertEqual(12, fire.scheduled.astimezone(eastern).hour)

        # assert our offsets are different (we crossed DST)
        self.assertNotEqual(fire.scheduled.utcoffset(), self.farmer1.get_field_value(self.planting_date).utcoffset())

        # the number of hours between these two events should be 49 (two days 1 hour)
        delta = fire.scheduled - self.farmer1.get_field_value(self.planting_date)
        self.assertEqual(delta.days, 2)
        self.assertEqual(delta.seconds, 3600)

        # spring forward case, this will go across a DST jump forward scenario
        self.farmer1.set_field(self.user, "planting_date", "10-03-2029 02:30:00")
        EventFire.update_campaign_events(campaign)

        fire = EventFire.objects.get()
        self.assertEqual(12, fire.scheduled.day)
        self.assertEqual(3, fire.scheduled.month)
        self.assertEqual(2029, fire.scheduled.year)
        self.assertEqual(2, fire.scheduled.astimezone(eastern).hour)

        # assert our offsets changed (we crossed DST)
        self.assertNotEqual(fire.scheduled.utcoffset(), self.farmer1.get_field_value(self.planting_date).utcoffset())

        # delta should be 47 hours exactly
        delta = fire.scheduled - self.farmer1.get_field_value(self.planting_date)
        self.assertEqual(delta.days, 1)
        self.assertEqual(delta.seconds, 82800)

        # release our campaign event
        event.release()

        # should be able to change our field type now
        ContactField.get_or_create(self.org, self.admin, "planting_date", value_type=Value.TYPE_TEXT)
コード例 #7
0
ファイル: views.py プロジェクト: xuanhan863/rapidpro
        def form_valid(self, form):
            try:
                cleaned_data = form.cleaned_data
                org = self.request.user.get_org()

                for key in cleaned_data:
                    if key.startswith('field_'):
                        idx = key[6:]
                        label = cleaned_data["label_%s" % idx]
                        field = cleaned_data[key]
                        show_in_table = cleaned_data["show_%s" % idx]
                        value_type = cleaned_data['type_%s' % idx]

                        if field == '__new_field':
                            if label:
                                analytics.track(self.request.user.username,
                                                'temba.contactfield_created')
                                key = ContactField.make_key(label)
                                ContactField.get_or_create(
                                    org,
                                    key,
                                    label,
                                    show_in_table=show_in_table,
                                    value_type=value_type)
                        else:
                            if label:
                                ContactField.get_or_create(
                                    org,
                                    field.key,
                                    label,
                                    show_in_table=show_in_table,
                                    value_type=value_type)
                            else:
                                ContactField.hide_field(org, field.key)

                if 'HTTP_X_PJAX' not in self.request.META:
                    return HttpResponseRedirect(self.get_success_url())
                else:  # pragma: no cover
                    return self.render_to_response(
                        self.get_context_data(
                            form=form,
                            success_url=self.get_success_url(),
                            success_script=getattr(self, 'success_script',
                                                   None)))

            except IntegrityError as e:  # pragma: no cover
                message = str(e).capitalize()
                errors = self.form._errors.setdefault(
                    forms.forms.NON_FIELD_ERRORS, forms.util.ErrorList())
                errors.append(message)
                return self.render_to_response(
                    self.get_context_data(form=form))
コード例 #8
0
def update_field_locally(user, contact, key, value, label=None):
    field = ContactField.get_or_create(contact.org, user, key, label=label)

    field_uuid = str(field.uuid)
    if contact.fields is None:
        contact.fields = {}

    if not value:
        value = None
        if field_uuid in contact.fields:
            del contact.fields[field_uuid]

    else:
        field_dict = contact.serialize_field(field, value)

        if contact.fields.get(field_uuid) != field_dict:
            contact.fields[field_uuid] = field_dict

    # update our JSONB on our contact
    with connection.cursor() as cursor:
        if value is None:
            # delete the field
            cursor.execute("UPDATE contacts_contact SET fields = fields - %s WHERE id = %s", [field_uuid, contact.id])
        else:
            # update the field
            cursor.execute(
                "UPDATE contacts_contact SET fields = COALESCE(fields,'{}'::jsonb) || %s::jsonb WHERE id = %s",
                [json.dumps({field_uuid: contact.fields[field_uuid]}), contact.id],
            )
コード例 #9
0
    def setUp(self):
        super(ScheduleTest, self).setUp()

        self.farmer1 = self.create_contact("Rob Jasper", "+250788111111")
        self.farmer2 = self.create_contact("Mike Gordon", "+250788222222")

        self.nonfarmer = self.create_contact("Trey Anastasio", "+250788333333")
        self.farmers = self.create_group("Farmers",
                                         [self.farmer1, self.farmer2])

        self.reminder_flow = self.create_flow()
        self.reminder2_flow = self.create_flow()

        # create a voice flow to make sure they work too, not a proper voice flow but
        # sufficient for assuring these flow types show up where they should
        self.voice_flow = self.create_flow()
        self.voice_flow.name = 'IVR flow'
        self.voice_flow.flow_type = 'V'
        self.voice_flow.save()

        # create a contact field for our planting date
        self.planting_date = ContactField.get_or_create(
            self.org, 'planting_date', "Planting Date")

        self.admin.groups.add(Group.objects.get(name="Beta"))
コード例 #10
0
    def setUp(self):
        super().setUp()

        self.farmer1 = self.create_contact("Rob Jasper", "+250788111111")
        self.farmer2 = self.create_contact("Mike Gordon",
                                           "+250788222222",
                                           language="spa")

        self.nonfarmer = self.create_contact("Trey Anastasio", "+250788333333")
        self.farmers = self.create_group("Farmers",
                                         [self.farmer1, self.farmer2])

        self.reminder_flow = self.create_flow(name="Reminder Flow")
        self.reminder2_flow = self.create_flow(name="Planting Reminder")

        # create a voice flow to make sure they work too, not a proper voice flow but
        # sufficient for assuring these flow types show up where they should
        self.voice_flow = self.create_flow(name="IVR flow", flow_type="V")

        # create a contact field for our planting date
        self.planting_date = ContactField.get_or_create(
            self.org,
            self.admin,
            "planting_date",
            "Planting Date",
            value_type=Value.TYPE_DATETIME)
コード例 #11
0
ファイル: tests.py プロジェクト: mxabierto/rapidpro
    def setUp(self):
        super().setUp()

        self.planting_date = ContactField.get_or_create(
            self.org, self.admin, "planting_date", "Planting Date", value_type=Value.TYPE_DATETIME
        )
        self.contact = self.create_contact("Ben Haggerty", number="+12065552020")
        self.contact.set_field(self.admin, "planting_date", "2018-06-23T13:48:12.123456Z")

        # create a campaign with a message event 1 day after planting date
        self.farmers = self.create_group("Farmers", [self.contact])
        self.campaign = Campaign.create(self.org, self.admin, "Planting Reminders", self.farmers)

        self.event = CampaignEvent.create_message_event(
            self.org,
            self.admin,
            self.campaign,
            relative_to=self.planting_date,
            offset=1,
            unit="D",
            message={
                "eng": "Hi @(upper(contact.name)) don't forget to plant on @(format_date(contact.planting_date))"
            },
            base_language="eng",
        )
コード例 #12
0
    def save(self):
        """
        Update our contact
        """
        name = self.validated_data.get('name')
        fields = self.validated_data.get('fields')
        language = self.validated_data.get('language')

        # treat empty names as None
        if not name:
            name = None

        changed = []

        if self.instance:
            if self.parsed_urns is not None:
                self.instance.update_urns(self.user, self.parsed_urns)

            # update our name and language
            if name != self.instance.name:
                self.instance.name = name
                changed.append('name')
        else:
            self.instance = Contact.get_or_create_by_urns(self.org, self.user, name, urns=self.parsed_urns,
                                                          language=language, force_urn_update=True)

        # Contact.get_or_create doesn't nullify language so do that here
        if 'language' in self.validated_data and language is None:
            self.instance.language = language.lower() if language else None
            self.instance.save()

        # save our contact if it changed
        if changed:
            self.instance.save(update_fields=changed)

        # update our fields
        if fields is not None:
            for key, value in fields.items():
                existing_by_key = ContactField.objects.filter(org=self.org, key__iexact=key, is_active=True).first()
                if existing_by_key:
                    self.instance.set_field(self.user, existing_by_key.key, value)
                    continue
                elif self.new_fields and key in self.new_fields:
                    new_field = ContactField.get_or_create(org=self.org, user=self.user,
                                                           key=regex.sub('[^A-Za-z0-9]+', '_', key).lower(),
                                                           label=key)
                    self.instance.set_field(self.user, new_field.key, value)

                # TODO as above, need to get users to stop updating via label
                existing_by_label = ContactField.get_by_label(self.org, key)
                if existing_by_label:
                    self.instance.set_field(self.user, existing_by_label.key, value)

        # update our contact's groups
        if self.group_objs is not None:
            self.instance.update_static_groups(self.user, self.group_objs)

        return self.instance
コード例 #13
0
    def save(self):
        label = self.validated_data.get('label')
        value_type = self.validated_data.get('value_type')

        if self.instance:
            key = self.instance.key
        else:
            key = ContactField.make_key(label)

        return ContactField.get_or_create(self.context['org'], self.context['user'], key, label, value_type=value_type)
コード例 #14
0
ファイル: serializers.py プロジェクト: cybort/rapidpro
    def save(self):
        key = self.validated_data.get('key')
        label = self.validated_data.get('label')
        value_type = self.validated_data.get('value_type')

        return ContactField.get_or_create(self.org,
                                          self.user,
                                          key,
                                          label,
                                          value_type=value_type)
コード例 #15
0
ファイル: serializers.py プロジェクト: teehamaral/rapidpro
    def save(self):
        label = self.validated_data.get("label")
        value_type = self.validated_data.get("value_type")

        if self.instance:
            key = self.instance.key
        else:
            key = ContactField.make_key(label)

        return ContactField.get_or_create(self.context["org"], self.context["user"], key, label, value_type=value_type)
コード例 #16
0
    def save(self):
        label = self.validated_data.get('label')
        value_type = self.validated_data.get('value_type')

        if self.instance:
            key = self.instance.key
        else:
            key = ContactField.make_key(label)

        return ContactField.get_or_create(self.context['org'], self.context['user'], key, label, value_type=value_type)
コード例 #17
0
    def save(self):
        key = self.validated_data.get("key")
        label = self.validated_data.get("label")
        value_type = self.validated_data.get("value_type")

        return ContactField.get_or_create(self.org,
                                          self.user,
                                          key,
                                          label,
                                          value_type=value_type)
コード例 #18
0
    def save(self):
        label = self.validated_data.get("label")
        value_type = self.validated_data.get("value_type")

        if self.instance:
            key = self.instance.key
        else:
            key = ContactField.make_key(label)

        return ContactField.get_or_create(self.context["org"], self.context["user"], key, label, value_type=value_type)
コード例 #19
0
def update_field_locally(user, contact, key, value, label=None):
    org = contact.org
    field = ContactField.get_or_create(contact.org, user, key, label=label)

    field_uuid = str(field.uuid)
    if contact.fields is None:
        contact.fields = {}

    if not value:
        value = None
        if field_uuid in contact.fields:
            del contact.fields[field_uuid]

    else:
        field_dict = serialize_field_value(contact, field, value)

        if contact.fields.get(field_uuid) != field_dict:
            contact.fields[field_uuid] = field_dict

    # update our JSONB on our contact
    with connection.cursor() as cursor:
        if value is None:
            # delete the field
            cursor.execute(
                "UPDATE contacts_contact SET fields = fields - %s WHERE id = %s",
                [field_uuid, contact.id])
        else:
            # update the field
            cursor.execute(
                "UPDATE contacts_contact SET fields = COALESCE(fields,'{}'::jsonb) || %s::jsonb WHERE id = %s",
                [
                    json.dumps({field_uuid: contact.fields[field_uuid]}),
                    contact.id
                ],
            )

    # very simplified version of mailroom's campaign event scheduling
    events = CampaignEvent.objects.filter(
        relative_to=field, campaign__group__in=contact.user_groups.all())
    for event in events:
        EventFire.objects.filter(contact=contact, event=event).delete()
        date_value = parse_datetime(org, value)
        if date_value:
            scheduled = date_value + timedelta(
                **{event_units[event.unit]: event.offset})
            if scheduled > timezone.now():
                EventFire.objects.create(contact=contact,
                                         event=event,
                                         scheduled=scheduled)
コード例 #20
0
ファイル: views.py プロジェクト: austiine04/rapidpro
        def form_valid(self, form):
            try:
                cleaned_data = form.cleaned_data
                org = self.request.user.get_org()

                for key in cleaned_data:
                    if key.startswith('field_'):
                        idx = key[6:]
                        label = cleaned_data["label_%s" % idx]
                        field = cleaned_data[key]
                        show_in_table = cleaned_data["show_%s" % idx]
                        value_type = cleaned_data['type_%s' % idx]

                        if field == '__new_field':
                            if label:
                                analytics.track(self.request.user.username, 'temba.contactfield_created')
                                key = ContactField.make_key(label)
                                ContactField.get_or_create(org, key, label, show_in_table=show_in_table, value_type=value_type)
                        else:
                            if label:
                                ContactField.get_or_create(org, field.key, label, show_in_table=show_in_table, value_type=value_type)
                            else:
                                ContactField.hide_field(org, field.key)

                if 'HTTP_X_PJAX' not in self.request.META:
                    return HttpResponseRedirect(self.get_success_url())
                else:  # pragma: no cover
                    return self.render_to_response(self.get_context_data(form=form,
                                                                         success_url=self.get_success_url(),
                                                                         success_script=getattr(self, 'success_script', None)))

            except IntegrityError as e:  # pragma: no cover
                message = str(e).capitalize()
                errors = self.form._errors.setdefault(forms.forms.NON_FIELD_ERRORS, forms.utils.ErrorList())
                errors.append(message)
                return self.render_to_response(self.get_context_data(form=form))
コード例 #21
0
ファイル: serializers.py プロジェクト: unicef-zambia/rapidpro
    def restore_object(self, attrs, instance=None):
        """
        Update our contact field
        """
        if instance:  # pragma: no cover
            raise ValidationError("Invalid operation")

        org = self.user.get_org()
        key = attrs.get('key', None)
        label = attrs.get('label')
        value_type = attrs.get('value_type')

        if not key:
            key = ContactField.make_key(label)

        return ContactField.get_or_create(org, key, label, value_type=value_type)
コード例 #22
0
ファイル: serializers.py プロジェクト: AxisOfEval/rapidpro
    def restore_object(self, attrs, instance=None):
        """
        Update our contact field
        """
        if instance:  # pragma: no cover
            raise ValidationError("Invalid operation")

        org = self.user.get_org()
        key = attrs.get('key', None)
        label = attrs.get('label')
        value_type = attrs.get('value_type')

        if not key:
            key = ContactField.make_key(label)

        return ContactField.get_or_create(org, key, label, value_type=value_type)
コード例 #23
0
ファイル: tasks.py プロジェクト: mxabierto/rapidpro
def create_event(event_spec, notification, campaign):
    org = notification.org_dest
    user = notification.created_by

    relative_to = ContactField.get_or_create(
        org,
        user,
        key=event_spec["relative_to"]["key"],
        label=event_spec["relative_to"]["label"],
        value_type="D",
    )
    # create our message flow for message events
    if event_spec["event_type"] == CampaignEvent.TYPE_MESSAGE:
        message = event_spec["message"]
        base_language = event_spec.get("base_language")
        if not isinstance(message, dict):
            try:
                message = json.loads(message)
            except ValueError:
                # if it's not a language dict, turn it into one
                message = dict(base=message)
                base_language = "base"
        event = CampaignEvent.create_message_event(
            org,
            user,
            campaign,
            relative_to,
            event_spec["offset"],
            event_spec["unit"],
            message,
            event_spec["delivery_hour"],
            base_language=base_language,
        )
        event.update_flow_name()
    else:
        flow = Flow.objects.filter(org=org, is_active=True, name=event_spec["flow"]["name"]).last()
        if flow:
            CampaignEvent.create_flow_event(
                org,
                user,
                campaign,
                relative_to,
                event_spec["offset"],
                event_spec["unit"],
                flow,
                event_spec["delivery_hour"],
            )
コード例 #24
0
ファイル: tests.py プロジェクト: ewheeler/rapidpro
    def setUp(self):
        super(CampaignTest, self).setUp()

        self.farmer1 = self.create_contact("Rob Jasper", "+250788111111")
        self.farmer2 = self.create_contact("Mike Gordon", "+250788222222")

        self.nonfarmer = self.create_contact("Trey Anastasio", "+250788333333")
        self.farmers = self.create_group("Farmers", [self.farmer1, self.farmer2])

        self.reminder_flow = self.create_flow()
        self.reminder2_flow = self.create_flow()

        # create a voice flow to make sure they work too, not a proper voice flow but
        # sufficient for assuring these flow types show up where they should
        self.voice_flow = self.create_flow()
        self.voice_flow.name = 'IVR flow'
        self.voice_flow.flow_type = 'V'
        self.voice_flow.save()

        # create a contact field for our planting date
        self.planting_date = ContactField.get_or_create(self.org, self.admin, 'planting_date', "Planting Date")
コード例 #25
0
ファイル: actions.py プロジェクト: teamgeocart/rapidpro
    def get_label(cls, org, field, label=None):
        from temba.flows.models import get_flow_user

        # make sure this field exists
        if field == "name":
            label = "Contact Name"
        elif field == "first_name":
            label = "First Name"
        elif field == "tel_e164":
            label = "Phone Number"
        elif field in ContactURN.CONTEXT_KEYS_TO_SCHEME.keys():
            label = str(ContactURN.CONTEXT_KEYS_TO_LABEL[field])
        else:
            contact_field = ContactField.user_fields.filter(org=org, key=field).first()

            if not contact_field:
                contact_field = ContactField.get_or_create(org, get_flow_user(org), field, label)

            label = contact_field.label

        return label
コード例 #26
0
    def test_fields(self):
        url = reverse('api.v2.fields')

        self.assertEndpointAccess(url)

        ContactField.get_or_create(self.org, self.admin, 'nick_name',
                                   "Nick Name")
        ContactField.get_or_create(self.org,
                                   self.admin,
                                   'registered',
                                   "Registered On",
                                   value_type=Value.TYPE_DATETIME)
        ContactField.get_or_create(self.org2, self.admin2, 'not_ours',
                                   "Something Else")

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

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json['next'], None)
        self.assertEqual(response.json['results'], [{
            'key': 'registered',
            'label': "Registered On",
            'value_type': "datetime"
        }, {
            'key': 'nick_name',
            'label': "Nick Name",
            'value_type': "text"
        }])

        # filter by key
        response = self.fetchJSON(url, 'key=nick_name')
        self.assertEqual(response.json['results'], [{
            'key': 'nick_name',
            'label': "Nick Name",
            'value_type': "text"
        }])
コード例 #27
0
ファイル: test_v2.py プロジェクト: churcho/rapidpro
    def test_fields(self):
        url = reverse('api.v2.fields')

        self.assertEndpointAccess(url)

        ContactField.get_or_create(self.org, self.admin, 'nick_name', "Nick Name")
        ContactField.get_or_create(self.org, self.admin, 'registered', "Registered On", value_type=Value.TYPE_DATETIME)
        ContactField.get_or_create(self.org2, self.admin2, 'not_ours', "Something Else")

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

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json['next'], None)
        self.assertEqual(response.json['results'], [
            {'key': 'registered', 'label': "Registered On", 'value_type': "datetime"},
            {'key': 'nick_name', 'label': "Nick Name", 'value_type': "text"}
        ])

        # filter by key
        response = self.fetchJSON(url, 'key=nick_name')
        self.assertEqual(response.json['results'], [{'key': 'nick_name', 'label': "Nick Name", 'value_type': "text"}])
コード例 #28
0
    def import_campaigns(cls, exported_json, org, user, same_site=False):
        """
        Import campaigns from our export file
        """
        from temba.orgs.models import EARLIEST_IMPORT_VERSION

        if Flow.is_before_version(
                exported_json.get("version", "0"),
                EARLIEST_IMPORT_VERSION):  # pragma: needs cover
            raise ValueError(
                _("Unknown version (%s)" % exported_json.get("version", 0)))

        if "campaigns" in exported_json:
            for campaign_spec in exported_json["campaigns"]:
                name = campaign_spec["name"]
                campaign = None
                group = None

                # first check if we have the objects by id
                if same_site:
                    group = ContactGroup.user_groups.filter(
                        uuid=campaign_spec["group"]["uuid"], org=org).first()
                    if group:  # pragma: needs cover
                        group.name = campaign_spec["group"]["name"]
                        group.save()

                    campaign = Campaign.objects.filter(
                        org=org, uuid=campaign_spec["uuid"]).first()
                    if campaign:  # pragma: needs cover
                        campaign.name = Campaign.get_unique_name(
                            org, name, ignore=campaign)
                        campaign.save()

                # fall back to lookups by name
                if not group:
                    group = ContactGroup.get_user_group(
                        org, campaign_spec["group"]["name"])

                if not campaign:
                    campaign = Campaign.objects.filter(org=org,
                                                       name=name).first()

                # all else fails, create the objects from scratch
                if not group:
                    group = ContactGroup.create_static(
                        org, user, campaign_spec["group"]["name"])

                if not campaign:
                    campaign_name = Campaign.get_unique_name(org, name)
                    campaign = Campaign.create(org, user, campaign_name, group)
                else:
                    campaign.group = group
                    campaign.save()

                # release all of our events, we'll recreate these
                for event in campaign.events.all():
                    event.release()

                # fill our campaign with events
                for event_spec in campaign_spec["events"]:
                    relative_to = ContactField.get_or_create(
                        org,
                        user,
                        key=event_spec["relative_to"]["key"],
                        label=event_spec["relative_to"]["label"],
                        value_type="D",
                    )

                    # create our message flow for message events
                    if event_spec["event_type"] == CampaignEvent.TYPE_MESSAGE:

                        message = event_spec["message"]
                        base_language = event_spec.get("base_language")

                        if not isinstance(message, dict):
                            try:
                                message = json.loads(message)
                            except ValueError:
                                # if it's not a language dict, turn it into one
                                message = dict(base=message)
                                base_language = "base"

                        event = CampaignEvent.create_message_event(
                            org,
                            user,
                            campaign,
                            relative_to,
                            event_spec["offset"],
                            event_spec["unit"],
                            message,
                            event_spec["delivery_hour"],
                            base_language=base_language,
                        )
                        event.update_flow_name()
                    else:
                        flow = Flow.objects.filter(
                            org=org,
                            is_active=True,
                            uuid=event_spec["flow"]["uuid"]).first()
                        if flow:
                            CampaignEvent.create_flow_event(
                                org,
                                user,
                                campaign,
                                relative_to,
                                event_spec["offset"],
                                event_spec["unit"],
                                flow,
                                event_spec["delivery_hour"],
                            )

                # update our scheduled events for this campaign
                EventFire.update_campaign_events(campaign)
コード例 #29
0
    def import_campaigns(cls, exported_json, org, user, same_site=False):
        """
        Import campaigns from our export file
        """
        from temba.orgs.models import EARLIEST_IMPORT_VERSION
        if Flow.is_before_version(
                exported_json.get('version', "0"),
                EARLIEST_IMPORT_VERSION):  # pragma: needs cover
            raise ValueError(
                _("Unknown version (%s)" % exported_json.get('version', 0)))

        if 'campaigns' in exported_json:
            for campaign_spec in exported_json['campaigns']:
                name = campaign_spec['name']
                campaign = None
                group = None

                # first check if we have the objects by id
                if same_site:
                    group = ContactGroup.user_groups.filter(
                        uuid=campaign_spec['group']['uuid'], org=org).first()
                    if group:  # pragma: needs cover
                        group.name = campaign_spec['group']['name']
                        group.save()

                    campaign = Campaign.objects.filter(
                        org=org, uuid=campaign_spec['uuid']).first()
                    if campaign:  # pragma: needs cover
                        campaign.name = Campaign.get_unique_name(
                            org, name, ignore=campaign)
                        campaign.save()

                # fall back to lookups by name
                if not group:
                    group = ContactGroup.get_user_group(
                        org, campaign_spec['group']['name'])

                if not campaign:
                    campaign = Campaign.objects.filter(org=org,
                                                       name=name).first()

                # all else fails, create the objects from scratch
                if not group:
                    group = ContactGroup.create_static(
                        org, user, campaign_spec['group']['name'])

                if not campaign:
                    campaign_name = Campaign.get_unique_name(org, name)
                    campaign = Campaign.create(org, user, campaign_name, group)
                else:
                    campaign.group = group
                    campaign.save()

                # we want to nuke old single message flows
                for event in campaign.events.all():
                    if event.flow.flow_type == Flow.MESSAGE:
                        event.flow.release()

                # and all of the events, we'll recreate these
                campaign.events.all().delete()

                # fill our campaign with events
                for event_spec in campaign_spec['events']:
                    relative_to = ContactField.get_or_create(
                        org,
                        user,
                        key=event_spec['relative_to']['key'],
                        label=event_spec['relative_to']['label'])

                    # create our message flow for message events
                    if event_spec['event_type'] == CampaignEvent.TYPE_MESSAGE:

                        message = event_spec['message']
                        base_language = event_spec.get('base_language')

                        if not isinstance(message, dict):
                            try:
                                message = json.loads(message)
                            except ValueError:
                                # if it's not a language dict, turn it into one
                                message = dict(base=message)
                                base_language = 'base'

                        event = CampaignEvent.create_message_event(
                            org,
                            user,
                            campaign,
                            relative_to,
                            event_spec['offset'],
                            event_spec['unit'],
                            message,
                            event_spec['delivery_hour'],
                            base_language=base_language)
                        event.update_flow_name()
                    else:
                        flow = Flow.objects.filter(
                            org=org,
                            is_active=True,
                            uuid=event_spec['flow']['uuid']).first()
                        if flow:
                            CampaignEvent.create_flow_event(
                                org, user, campaign, relative_to,
                                event_spec['offset'], event_spec['unit'], flow,
                                event_spec['delivery_hour'])

                # update our scheduled events for this campaign
                EventFire.update_campaign_events(campaign)
コード例 #30
0
ファイル: models.py プロジェクト: mbanje/rapidpro
    def import_campaigns(cls, exported_json, org, user, same_site=False):
        """
        Import campaigns from our export file
        """
        from temba.orgs.models import EARLIEST_IMPORT_VERSION

        if exported_json.get("version", 0) < EARLIEST_IMPORT_VERSION:
            raise ValueError(_("Unknown version (%s)" % exported_json.get("version", 0)))

        if "campaigns" in exported_json:
            for campaign_spec in exported_json["campaigns"]:
                name = campaign_spec["name"]
                campaign = None
                group = None

                # first check if we have the objects by id
                if same_site:
                    group = ContactGroup.user_groups.filter(
                        id=campaign_spec["group"]["id"], org=org, is_active=True
                    ).first()
                    if group:
                        group.name = campaign_spec["group"]["name"]
                        group.save()

                    campaign = Campaign.objects.filter(org=org, id=campaign_spec["id"]).first()
                    if campaign:
                        campaign.name = Campaign.get_unique_name(org, name, ignore=campaign)
                        campaign.save()

                # fall back to lookups by name
                if not group:
                    group = ContactGroup.user_groups.filter(name=campaign_spec["group"]["name"], org=org).first()

                if not campaign:
                    campaign = Campaign.objects.filter(org=org, name=name).first()

                # all else fails, create the objects from scratch
                if not group:
                    group = ContactGroup.create(org, user, campaign_spec["group"]["name"])

                if not campaign:
                    campaign_name = Campaign.get_unique_name(org, name)
                    campaign = Campaign.create(org, user, campaign_name, group)
                else:
                    campaign.group = group
                    campaign.save()

                # we want to nuke old single message flows
                for event in campaign.events.all():
                    if event.flow.flow_type == Flow.MESSAGE:
                        event.flow.delete()

                # and all of the events, we'll recreate these
                campaign.events.all().delete()

                # fill our campaign with events
                for event_spec in campaign_spec["events"]:
                    relative_to = ContactField.get_or_create(
                        org, key=event_spec["relative_to"]["key"], label=event_spec["relative_to"]["label"]
                    )

                    # create our message flow for message events
                    if event_spec["event_type"] == MESSAGE_EVENT:
                        event = CampaignEvent.create_message_event(
                            org,
                            user,
                            campaign,
                            relative_to,
                            event_spec["offset"],
                            event_spec["unit"],
                            event_spec["message"],
                            event_spec["delivery_hour"],
                        )
                        event.update_flow_name()
                    else:
                        flow = Flow.objects.filter(org=org, id=event_spec["flow"]["id"]).first()
                        if flow:
                            CampaignEvent.create_flow_event(
                                org,
                                user,
                                campaign,
                                relative_to,
                                event_spec["offset"],
                                event_spec["unit"],
                                flow,
                                event_spec["delivery_hour"],
                            )

                # update our scheduled events for this campaign
                EventFire.update_campaign_events(campaign)
コード例 #31
0
ファイル: serializers.py プロジェクト: teehamaral/rapidpro
    def save(self):
        """
        Update our contact
        """
        name = self.validated_data.get("name")
        fields = self.validated_data.get("fields")
        language = self.validated_data.get("language")

        # treat empty names as None
        if not name:
            name = None

        changed = []

        if self.instance:
            if self.parsed_urns is not None:
                self.instance.update_urns(self.user, self.parsed_urns)

            # update our name and language
            if name != self.instance.name:
                self.instance.name = name
                changed.append("name")
        else:
            self.instance = Contact.get_or_create_by_urns(
                self.org, self.user, name, urns=self.parsed_urns, language=language, force_urn_update=True
            )

        # Contact.get_or_create doesn't nullify language so do that here
        if "language" in self.validated_data and language is None:
            self.instance.language = language.lower() if language else None
            changed.append("language")

        # save our contact if it changed
        if changed:
            self.instance.save(update_fields=changed, handle_update=True)

        # update our fields
        if fields is not None:
            for key, value in fields.items():
                existing_by_key = ContactField.user_fields.filter(
                    org=self.org, key__iexact=key, is_active=True
                ).first()
                if existing_by_key:
                    self.instance.set_field(self.user, existing_by_key.key, value)
                    continue
                elif self.new_fields and key in self.new_fields:
                    new_field = ContactField.get_or_create(
                        org=self.org, user=self.user, key=regex.sub("[^A-Za-z0-9]+", "_", key).lower(), label=key
                    )
                    self.instance.set_field(self.user, new_field.key, value)

                # TODO as above, need to get users to stop updating via label
                existing_by_label = ContactField.get_by_label(self.org, key)
                if existing_by_label:
                    self.instance.set_field(self.user, existing_by_label.key, value)

        # update our contact's groups
        if self.group_objs is not None:
            self.instance.update_static_groups(self.user, self.group_objs)

        return self.instance
コード例 #32
0
ファイル: serializers.py プロジェクト: AxisOfEval/rapidpro
    def restore_object(self, attrs, instance=None):
        """
        Create or update our campaign
        """
        if instance: # pragma: no cover
            raise ValidationError("Invalid operation")

        org = self.user.get_org()

        # parse our arguments
        message = attrs.get('message', None)
        flow = attrs.get('flow', None)

        if not message and not flow:
            raise ValidationError("Must specify either a flow or a message for the event")

        if message and flow:
            raise ValidationError("You cannot set both a flow and a message on an event, it must be only one")

        campaign_id = attrs.get('campaign', None)
        event_id = attrs.get('event', None)

        if not campaign_id and not event_id:
            raise ValidationError("You must specify either a campaign to create a new event, or an event to update")

        offset = attrs.get('offset')
        unit = attrs.get('unit')
        delivery_hour = attrs.get('delivery_hour')
        relative_to = attrs.get('relative_to')

        # load our contact field
        existing_field = ContactField.objects.filter(label=relative_to, org=org, is_active=True)

        if not existing_field:
            relative_to_field = ContactField.get_or_create(org, ContactField.make_key(relative_to), relative_to)
        else:
            relative_to_field = existing_field[0]

        if 'event' in attrs:
            event = CampaignEvent.objects.get(pk=attrs['event'], is_active=True, campaign__org=org)

            # we are being set to a flow
            if 'flow' in attrs:
                flow = Flow.objects.get(pk=attrs['flow'], is_active=True, org=org)
                event.flow = flow
                event.event_type = FLOW_EVENT
                event.message = None

            # we are being set to a message
            else:
                event.message = attrs['message']

                # if we aren't currently a message event, we need to create our hidden message flow
                if event.event_type != MESSAGE_EVENT:
                    event.flow = Flow.create_single_message(org, self.user, event.message)
                    event.event_type = MESSAGE_EVENT

                # otherwise, we can just update that flow
                else:
                    # set our single message on our flow
                    event.flow.update_single_message_flow(message=attrs['message'])

            # update our other attributes
            event.offset = offset
            event.unit = unit
            event.delivery_hour = delivery_hour
            event.relative_to = relative_to_field
            event.save()
            event.update_flow_name()

        else:
            campaign = Campaign.objects.get(pk=attrs['campaign'], is_active=True, org=org)
            event_type = MESSAGE_EVENT

            if 'flow' in attrs:
                flow = Flow.objects.get(pk=attrs['flow'], is_active=True, org=org)
                event_type = FLOW_EVENT
            else:
                flow = Flow.create_single_message(org, self.user, message)

            event = CampaignEvent.objects.create(campaign=campaign, relative_to=relative_to_field, offset=offset,
                                                 unit=unit, event_type=event_type, flow=flow, message=message,
                                                 created_by=self.user, modified_by=self.user)
            event.update_flow_name()

        return event
コード例 #33
0
ファイル: tests.py プロジェクト: songea/rapidpro
    def test_category_results(self):
        self.setup_color_gender_flow()

        # create a state field:
        # assign c1 and c2 to Kigali
        ContactField.get_or_create(self.org,
                                   self.admin,
                                   'state',
                                   label="State",
                                   value_type=Value.TYPE_STATE)
        ContactField.get_or_create(self.org,
                                   self.admin,
                                   'district',
                                   label="District",
                                   value_type=Value.TYPE_DISTRICT)

        self.c1.set_field(self.user, 'state', "Kigali City")
        self.c1.set_field(self.user, 'district', "Nyarugenge")
        self.c2.set_field(self.user, 'state', "Kigali City")
        self.c2.set_field(self.user, 'district', "Nyarugenge")

        self.run_color_gender_flow(self.c1, "red", "male", "16")
        self.run_color_gender_flow(self.c2, "blue", "female", "19")
        self.run_color_gender_flow(self.c3, "green", "male", "75")
        self.run_color_gender_flow(self.c4, "maroon", "female", "50")

        # create a group of the women
        ladies = self.create_group("Ladies", [self.c2, self.c4])

        # get our rulesets
        color = RuleSet.objects.get(flow=self.flow, label="Color")
        gender = RuleSet.objects.get(flow=self.flow, label="Gender")
        age = RuleSet.objects.get(flow=self.flow, label="Age")

        # fetch our results through the view
        self.login(self.admin)
        response = self.client.get(
            reverse('flows.ruleset_results', args=[color.pk]))
        response = response.json()

        categories = response['results'][0]['categories']
        self.assertEqual('Red', categories[0]['label'])
        self.assertEqual('Blue', categories[1]['label'])
        self.assertEqual('Green', categories[2]['label'])

        self.assertEqual(2, categories[0]['count'])
        self.assertEqual(1, categories[1]['count'])
        self.assertEqual(1, categories[2]['count'])

        # categories should be in the same order as our rules, should have correct counts
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Red", 2)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 1)

        # check our age category as well
        result = Value.get_value_summary(ruleset=age)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Child", 1)
        self.assertResult(result, 1, "Adult", 2)
        self.assertResult(result, 2, "Senior", 1)

        # and our gender categories
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Male", 2)
        self.assertResult(result, 1, "Female", 2)

        # now filter the results and only get responses by men
        result = Value.get_value_summary(
            ruleset=color,
            filters=[dict(ruleset=gender.pk, categories=["Male"])])[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 1)

        # what about men that are adults?
        result = Value.get_value_summary(ruleset=color,
                                         filters=[
                                             dict(ruleset=gender.pk,
                                                  categories=["Male"]),
                                             dict(ruleset=age.pk,
                                                  categories=["Adult"])
                                         ])[0]
        self.assertResult(result, 0, "Red", 0)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # union of all genders
        result = Value.get_value_summary(
            ruleset=color,
            filters=[
                dict(ruleset=gender.pk, categories=["Male", "Female"]),
                dict(ruleset=age.pk, categories=["Adult"])
            ])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # just women adults by group
        result = Value.get_value_summary(ruleset=color,
                                         filters=[
                                             dict(groups=[ladies.pk]),
                                             dict(ruleset=age.pk,
                                                  categories="Adult")
                                         ])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # remove one of the women from the group
        ladies.update_contacts(self.user, [self.c2], False)

        # get a new summary
        result = Value.get_value_summary(ruleset=color,
                                         filters=[
                                             dict(groups=[ladies.pk]),
                                             dict(ruleset=age.pk,
                                                  categories="Adult")
                                         ])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # ok, back in she goes
        ladies.update_contacts(self.user, [self.c2], True)

        # do another run for contact 1
        self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # totals should reflect the new value, not the old
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 2)
        self.assertResult(result, 2, "Green", 1)

        # what if we do a partial run?
        self.send_message(self.flow,
                          "red",
                          contact=self.c1,
                          restart_participants=True)

        # should change our male/female breakdown since c1 now no longer has a gender
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertResult(result, 0, "Male", 1)
        self.assertResult(result, 1, "Female", 2)

        # back to a full flow
        self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # ok, now segment by gender
        result = Value.get_value_summary(ruleset=color,
                                         filters=[],
                                         segment=dict(
                                             ruleset=gender.pk,
                                             categories=["Male", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # segment by gender again, but use the contact field to do so
        result = Value.get_value_summary(ruleset=color,
                                         filters=[],
                                         segment=dict(
                                             contact_field="Gender",
                                             values=["MALE", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # add in a filter at the same time
        result = Value.get_value_summary(
            ruleset=color,
            filters=[dict(ruleset=color.pk, categories=["Blue"])],
            segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))

        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 0)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 0)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # ok, try segmenting by location instead
        result = Value.get_value_summary(ruleset=color,
                                         segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 0)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # updating state location leads to updated data
        self.c2.set_field(self.user, 'state', "Eastern Province")
        result = Value.get_value_summary(ruleset=color,
                                         segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 1)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 1)
        self.assertResult(kigali_result, 2, "Green", 0)

        # segment by district instead
        result = Value.get_value_summary(ruleset=color,
                                         segment=dict(parent="1708283",
                                                      location="District"))

        # only on district in kigali
        self.assertEquals(1, len(result))
        kigali_result = result[0]
        self.assertEquals('3963734', kigali_result['boundary'])
        self.assertEquals('Nyarugenge', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # do a sanity check on our choropleth view
        self.login(self.admin)
        response = self.client.get(
            reverse('flows.ruleset_choropleth', args=[color.pk]) +
            "?_format=json&boundary=" + self.org.country.osm_id)

        # response should be valid json
        response = response.json()

        # should have breaks
        self.assertTrue('breaks' in response)

        # should have two categories, Blue and Others
        self.assertEquals(2, len(response['categories']))
        self.assertEquals("Blue", response['categories'][0])
        self.assertEquals("Others", response['categories'][1])

        # assert our kigali result
        kigali_result = response['scores']['1708283']
        self.assertEquals(1, kigali_result['score'])
        self.assertEquals("Kigali City", kigali_result['name'])
        self.assertEquals("Blue", kigali_result['results'][0]['label'])
        self.assertEquals("Others", kigali_result['results'][1]['label'])

        self.assertEquals(1, kigali_result['results'][0]['count'])
        self.assertEquals(0, kigali_result['results'][1]['count'])

        self.assertEquals(100, kigali_result['results'][0]['percentage'])
        self.assertEquals(0, kigali_result['results'][1]['percentage'])

        with patch('temba.values.models.Value.get_value_summary') as mock:
            mock.return_value = []

            response = self.client.get(
                reverse('flows.ruleset_choropleth', args=[color.pk]) +
                "?_format=json&boundary=" + self.org.country.osm_id)

            # response should be valid json
            response = response.json()

            # should have two categories, Blue and Others
            self.assertEquals(2, len(response['categories']))
            self.assertEquals("", response['categories'][0])
            self.assertEquals("", response['categories'][1])

            # all counts and percentage are 0
            self.assertEquals(0, response['totals']['count'])
            self.assertEquals(0, response['totals']['results'][0]['count'])
            self.assertEquals(0,
                              response['totals']['results'][0]['percentage'])
            self.assertEquals(0, response['totals']['results'][1]['count'])
            self.assertEquals(0,
                              response['totals']['results'][1]['percentage'])

            # and empty string labels
            self.assertEquals("", response['totals']['results'][0]['label'])
            self.assertEquals("", response['totals']['results'][1]['label'])

        # also check our analytics view
        response = self.client.get(reverse('flows.ruleset_analytics'))

        # make sure we have only one flow in it
        flows = json.loads(response.context['flows'])
        self.assertEquals(1, len(flows))
        self.assertEquals(3, len(flows[0]['rules']))
コード例 #34
0
def has_whatsapp_timestamp_contactfield(org):
    return ContactField.get_or_create(org,
                                      user=org.administrators.first(),
                                      key=HAS_WHATSAPP_TIMESTAMP_KEY,
                                      value_type=Value.TYPE_DATETIME)
コード例 #35
0
ファイル: models.py プロジェクト: tybritten/rapidpro
    def import_campaigns(cls,
                         org,
                         user,
                         campaign_defs,
                         same_site=False) -> List:
        """
        Import campaigns from a list of exported campaigns
        """

        imported = []

        for campaign_def in campaign_defs:
            name = campaign_def[Campaign.EXPORT_NAME]
            campaign = None
            group = None

            # first check if we have the objects by UUID
            if same_site:
                group = ContactGroup.user_groups.filter(
                    uuid=campaign_def[Campaign.EXPORT_GROUP]["uuid"],
                    org=org).first()
                if group:  # pragma: needs cover
                    group.name = campaign_def[Campaign.EXPORT_GROUP]["name"]
                    group.save()

                campaign = Campaign.objects.filter(
                    org=org, uuid=campaign_def[Campaign.EXPORT_UUID]).first()
                if campaign:  # pragma: needs cover
                    campaign.name = Campaign.get_unique_name(org,
                                                             name,
                                                             ignore=campaign)
                    campaign.save()

            # fall back to lookups by name
            if not group:
                group = ContactGroup.get_user_group_by_name(
                    org, campaign_def[Campaign.EXPORT_GROUP]["name"])

            if not campaign:
                campaign = Campaign.objects.filter(org=org, name=name).first()

            # all else fails, create the objects from scratch
            if not group:
                group = ContactGroup.create_static(
                    org, user, campaign_def[Campaign.EXPORT_GROUP]["name"])

            if not campaign:
                campaign_name = Campaign.get_unique_name(org, name)
                campaign = Campaign.create(org, user, campaign_name, group)
            else:
                campaign.group = group
                campaign.save()

            # deactivate all of our events, we'll recreate these
            for event in campaign.events.all():
                event.release()

            # fill our campaign with events
            for event_spec in campaign_def[Campaign.EXPORT_EVENTS]:
                field_key = event_spec["relative_to"]["key"]

                if field_key == "created_on":
                    relative_to = ContactField.system_fields.filter(
                        org=org, key=field_key).first()
                else:
                    relative_to = ContactField.get_or_create(
                        org,
                        user,
                        key=field_key,
                        label=event_spec["relative_to"]["label"],
                        value_type="D")

                start_mode = event_spec.get("start_mode",
                                            CampaignEvent.MODE_INTERRUPT)

                # create our message flow for message events
                if event_spec["event_type"] == CampaignEvent.TYPE_MESSAGE:

                    message = event_spec["message"]
                    base_language = event_spec.get("base_language")

                    if not isinstance(message, dict):
                        try:
                            message = json.loads(message)
                        except ValueError:
                            # if it's not a language dict, turn it into one
                            message = dict(base=message)
                            base_language = "base"

                    event = CampaignEvent.create_message_event(
                        org,
                        user,
                        campaign,
                        relative_to,
                        event_spec["offset"],
                        event_spec["unit"],
                        message,
                        event_spec["delivery_hour"],
                        base_language=base_language,
                        start_mode=start_mode,
                    )
                    event.update_flow_name()
                else:
                    flow = Flow.objects.filter(
                        org=org,
                        is_active=True,
                        is_system=False,
                        uuid=event_spec["flow"]["uuid"]).first()
                    if flow:
                        CampaignEvent.create_flow_event(
                            org,
                            user,
                            campaign,
                            relative_to,
                            event_spec["offset"],
                            event_spec["unit"],
                            flow,
                            event_spec["delivery_hour"],
                            start_mode=start_mode,
                        )

            imported.append(campaign)

        return imported
コード例 #36
0
ファイル: serializers.py プロジェクト: unicef-zambia/rapidpro
    def restore_object(self, attrs, instance=None):
        """
        Create or update our campaign
        """
        if instance: # pragma: no cover
            raise ValidationError("Invalid operation")

        org = self.user.get_org()

        # parse our arguments
        message = attrs.get('message', None)
        flow = attrs.get('flow', None)

        if not message and not flow:
            raise ValidationError("Must specify either a flow or a message for the event")

        if message and flow:
            raise ValidationError("You cannot set both a flow and a message on an event, it must be only one")

        campaign_id = attrs.get('campaign', None)
        event_id = attrs.get('event', None)

        if not campaign_id and not event_id:
            raise ValidationError("You must specify either a campaign to create a new event, or an event to update")

        offset = attrs.get('offset')
        unit = attrs.get('unit')
        delivery_hour = attrs.get('delivery_hour')
        relative_to = attrs.get('relative_to')

        # load our contact field
        existing_field = ContactField.objects.filter(label=relative_to, org=org, is_active=True)

        if not existing_field:
            relative_to_field = ContactField.get_or_create(org, ContactField.make_key(relative_to), relative_to)
        else:
            relative_to_field = existing_field[0]

        if 'event' in attrs:
            event = CampaignEvent.objects.get(pk=attrs['event'], is_active=True, campaign__org=org)

            # we are being set to a flow
            if 'flow' in attrs:
                flow = Flow.objects.get(pk=attrs['flow'], is_active=True, org=org)
                event.flow = flow
                event.event_type = FLOW_EVENT
                event.message = None

            # we are being set to a message
            else:
                event.message = attrs['message']

                # if we aren't currently a message event, we need to create our hidden message flow
                if event.event_type != MESSAGE_EVENT:
                    event.flow = CampaignEvent.create_single_message_flow(org, self.user, event.message)
                    event.event_type = MESSAGE_EVENT

                # otherwise, we can just update that flow
                else:
                    # set our single message on our flow
                    event.flow.update_single_message_flow(message=attrs['message'])

            # update our other attributes
            event.offset = offset
            event.unit = unit
            event.delivery_hour = delivery_hour
            event.relative_to = relative_to_field
            event.save()
            event.update_flow_name()

        else:
            campaign = Campaign.objects.get(pk=attrs['campaign'], is_active=True, org=org)
            event_type = MESSAGE_EVENT

            if 'flow' in attrs:
                flow = Flow.objects.get(pk=attrs['flow'], is_active=True, org=org)
                event_type = FLOW_EVENT
            else:
                flow = CampaignEvent.create_single_message_flow(org, self.user, message)

            event = CampaignEvent.objects.create(campaign=campaign, relative_to=relative_to_field, offset=offset,
                                                 unit=unit, event_type=event_type, flow=flow, message=message,
                                                 created_by=self.user, modified_by=self.user)
            event.update_flow_name()

        return event
コード例 #37
0
ファイル: models.py プロジェクト: ewheeler/rapidpro
    def import_campaigns(cls, exported_json, org, user, same_site=False):
        """
        Import campaigns from our export file
        """
        from temba.orgs.models import EARLIEST_IMPORT_VERSION
        if exported_json.get('version', 0) < EARLIEST_IMPORT_VERSION:
            raise ValueError(_("Unknown version (%s)" % exported_json.get('version', 0)))

        if 'campaigns' in exported_json:
            for campaign_spec in exported_json['campaigns']:
                name = campaign_spec['name']
                campaign = None
                group = None

                # first check if we have the objects by id
                if same_site:
                    group = ContactGroup.user_groups.filter(uuid=campaign_spec['group']['uuid'], org=org).first()
                    if group:
                        group.name = campaign_spec['group']['name']
                        group.save()

                    campaign = Campaign.objects.filter(org=org, uuid=campaign_spec['uuid']).first()
                    if campaign:
                        campaign.name = Campaign.get_unique_name(org, name, ignore=campaign)
                        campaign.save()

                # fall back to lookups by name
                if not group:
                    group = ContactGroup.get_user_group(org, campaign_spec['group']['name'])

                if not campaign:
                    campaign = Campaign.objects.filter(org=org, name=name).first()

                # all else fails, create the objects from scratch
                if not group:
                    group = ContactGroup.create_static(org, user, campaign_spec['group']['name'])

                if not campaign:
                    campaign_name = Campaign.get_unique_name(org, name)
                    campaign = Campaign.create(org, user, campaign_name, group)
                else:
                    campaign.group = group
                    campaign.save()

                # we want to nuke old single message flows
                for event in campaign.events.all():
                    if event.flow.flow_type == Flow.MESSAGE:
                        event.flow.release()

                # and all of the events, we'll recreate these
                campaign.events.all().delete()

                # fill our campaign with events
                for event_spec in campaign_spec['events']:
                    relative_to = ContactField.get_or_create(org, user,
                                                             key=event_spec['relative_to']['key'],
                                                             label=event_spec['relative_to']['label'])

                    # create our message flow for message events
                    if event_spec['event_type'] == CampaignEvent.TYPE_MESSAGE:
                        event = CampaignEvent.create_message_event(org, user, campaign, relative_to,
                                                                   event_spec['offset'],
                                                                   event_spec['unit'],
                                                                   event_spec['message'],
                                                                   event_spec['delivery_hour'])
                        event.update_flow_name()
                    else:
                        flow = Flow.objects.filter(org=org, is_active=True, uuid=event_spec['flow']['uuid']).first()
                        if flow:
                            CampaignEvent.create_flow_event(org, user, campaign, relative_to,
                                                            event_spec['offset'],
                                                            event_spec['unit'],
                                                            flow,
                                                            event_spec['delivery_hour'])

                # update our scheduled events for this campaign
                EventFire.update_campaign_events(campaign)
コード例 #38
0
ファイル: serializers.py プロジェクト: teehamaral/rapidpro
    def save(self):
        key = self.validated_data.get("key")
        label = self.validated_data.get("label")
        value_type = self.validated_data.get("value_type")

        return ContactField.get_or_create(self.org, self.user, key, label, value_type=value_type)
コード例 #39
0
    def import_campaigns(cls, exported_json, org, user, site=None):
        """
        Import campaigns from our export file
        """
        from temba.orgs.models import EARLIEST_IMPORT_VERSION
        if exported_json.get('version', 0) < EARLIEST_IMPORT_VERSION:
            raise ValueError(
                _("Unknown version (%s)" % exported_json.get('version', 0)))

        if 'campaigns' in exported_json:
            for campaign_spec in exported_json['campaigns']:
                name = campaign_spec['name']
                campaign = None
                group = None

                # first check if we have the objects by id
                if site and site == exported_json.get('site', None):
                    group = ContactGroup.user_groups.filter(
                        id=campaign_spec['group']['id'],
                        org=org,
                        is_active=True).first()
                    if group:
                        group.name = campaign_spec['group']['name']
                        group.save()

                    campaign = Campaign.objects.filter(
                        org=org, id=campaign_spec['id']).first()
                    if campaign:
                        campaign.name = Campaign.get_unique_name(
                            name, org, ignore=campaign)
                        campaign.save()

                # fall back to lookups by name
                if not group:
                    group = ContactGroup.user_groups.filter(
                        name=campaign_spec['group']['name'], org=org).first()

                if not campaign:
                    campaign = Campaign.objects.filter(org=org,
                                                       name=name).first()

                # all else fails, create the objects from scratch
                if not group:
                    group = ContactGroup.create(org, user,
                                                campaign_spec['group']['name'])

                if not campaign:
                    campaign = Campaign.objects.create(
                        name=Campaign.get_unique_name(name, org),
                        org=org,
                        group=group,
                        created_by=user,
                        modified_by=user)
                else:
                    campaign.group = group
                    campaign.save()

                # we want to nuke old single message flows
                for event in campaign.events.all():
                    if event.flow.flow_type == Flow.MESSAGE:
                        event.flow.delete()

                # and all of the events, we'll recreate these
                campaign.events.all().delete()

                # fill our campaign with events
                for event_spec in campaign_spec['events']:
                    relative_to = ContactField.get_or_create(
                        org,
                        key=event_spec['relative_to']['key'],
                        label=event_spec['relative_to']['label'])

                    # create our message flow for message events
                    if event_spec['event_type'] == MESSAGE_EVENT:
                        flow = Flow.create_single_message(
                            org, user, event_spec['message'])
                    else:
                        flow = Flow.objects.filter(
                            org=org, id=event_spec['flow']['id']).first()

                    if flow:
                        event = campaign.events.create(
                            created_by=user,
                            modified_by=user,
                            offset=event_spec['offset'],
                            unit=event_spec['unit'],
                            event_type=event_spec['event_type'],
                            delivery_hour=event_spec['delivery_hour'],
                            message=event_spec['message'],
                            flow=flow,
                            relative_to=relative_to)
                        event.update_flow_name()

                # update our scheduled events for this campaign
                EventFire.update_campaign_events(campaign)
コード例 #40
0
ファイル: models.py プロジェクト: teehamaral/rapidpro
    def import_campaigns(cls, exported_json, org, user, same_site=False):
        """
        Import campaigns from our export file
        """
        from temba.orgs.models import EARLIEST_IMPORT_VERSION

        if Flow.is_before_version(exported_json.get("version", "0"), EARLIEST_IMPORT_VERSION):  # pragma: needs cover
            raise ValueError(_("Unknown version (%s)" % exported_json.get("version", 0)))

        if "campaigns" in exported_json:
            for campaign_spec in exported_json["campaigns"]:
                name = campaign_spec["name"]
                campaign = None
                group = None

                # first check if we have the objects by id
                if same_site:
                    group = ContactGroup.user_groups.filter(uuid=campaign_spec["group"]["uuid"], org=org).first()
                    if group:  # pragma: needs cover
                        group.name = campaign_spec["group"]["name"]
                        group.save()

                    campaign = Campaign.objects.filter(org=org, uuid=campaign_spec["uuid"]).first()
                    if campaign:  # pragma: needs cover
                        campaign.name = Campaign.get_unique_name(org, name, ignore=campaign)
                        campaign.save()

                # fall back to lookups by name
                if not group:
                    group = ContactGroup.get_user_group(org, campaign_spec["group"]["name"])

                if not campaign:
                    campaign = Campaign.objects.filter(org=org, name=name).first()

                # all else fails, create the objects from scratch
                if not group:
                    group = ContactGroup.create_static(org, user, campaign_spec["group"]["name"])

                if not campaign:
                    campaign_name = Campaign.get_unique_name(org, name)
                    campaign = Campaign.create(org, user, campaign_name, group)
                else:
                    campaign.group = group
                    campaign.save()

                # deactivate all of our events, we'll recreate these
                for event in campaign.events.all():
                    event.release()

                # fill our campaign with events
                for event_spec in campaign_spec["events"]:
                    field_key = event_spec["relative_to"]["key"]

                    if field_key == "created_on":
                        relative_to = ContactField.system_fields.filter(org=org, key=field_key).first()
                    else:
                        relative_to = ContactField.get_or_create(
                            org, user, key=field_key, label=event_spec["relative_to"]["label"], value_type="D"
                        )

                    start_mode = event_spec.get("start_mode", CampaignEvent.MODE_INTERRUPT)

                    # create our message flow for message events
                    if event_spec["event_type"] == CampaignEvent.TYPE_MESSAGE:

                        message = event_spec["message"]
                        base_language = event_spec.get("base_language")

                        if not isinstance(message, dict):
                            try:
                                message = json.loads(message)
                            except ValueError:
                                # if it's not a language dict, turn it into one
                                message = dict(base=message)
                                base_language = "base"

                        event = CampaignEvent.create_message_event(
                            org,
                            user,
                            campaign,
                            relative_to,
                            event_spec["offset"],
                            event_spec["unit"],
                            message,
                            event_spec["delivery_hour"],
                            base_language=base_language,
                            start_mode=start_mode,
                        )
                        event.update_flow_name()
                    else:
                        flow = Flow.objects.filter(
                            org=org, is_active=True, is_system=False, uuid=event_spec["flow"]["uuid"]
                        ).first()
                        if flow:
                            CampaignEvent.create_flow_event(
                                org,
                                user,
                                campaign,
                                relative_to,
                                event_spec["offset"],
                                event_spec["unit"],
                                flow,
                                event_spec["delivery_hour"],
                                start_mode=start_mode,
                            )

                # update our scheduled events for this campaign
                EventFire.update_campaign_events(campaign)
コード例 #41
0
ファイル: tests.py プロジェクト: austiine04/rapidpro
    def test_category_results(self):
        self.setup_color_gender_flow()

        # create a state field:
        # assign c1 and c2 to Kigali
        state = ContactField.get_or_create(self.org, 'state', label="State", value_type=STATE)
        district = ContactField.get_or_create(self.org, 'district', label="District", value_type=DISTRICT)
        self.c1.set_field('state', "Kigali City")
        self.c1.set_field('district', "Kigali")
        self.c2.set_field('state', "Kigali City")
        self.c2.set_field('district', "Kigali")

        self.run_color_gender_flow(self.c1, "red", "male", "16")
        self.run_color_gender_flow(self.c2, "blue", "female", "19")
        self.run_color_gender_flow(self.c3, "green", "male", "75")
        self.run_color_gender_flow(self.c4, "maroon", "female", "50")

        # create a group of the women
        ladies = self.create_group("Ladies", [self.c2, self.c4])

        # get our rulesets
        color = RuleSet.objects.get(flow=self.flow, label="Color")
        gender = RuleSet.objects.get(flow=self.flow, label="Gender")
        age = RuleSet.objects.get(flow=self.flow, label="Age")

        # categories should be in the same order as our rules, should have correct counts
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Red", 2)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 1)

        # check our age category as well
        result = Value.get_value_summary(ruleset=age)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Child", 1)
        self.assertResult(result, 1, "Adult", 2)
        self.assertResult(result, 2, "Senior", 1)

        # and our gender categories
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Male", 2)
        self.assertResult(result, 1, "Female", 2)

        # now filter the results and only get responses by men
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"])])[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 1)

        # what about men that are adults?
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]
        self.assertResult(result, 0, "Red", 0)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # union of all genders
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male", "Female"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # just women adults by group
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # remove one of the women from the group
        ladies.update_contacts([self.c2], False)

        # get a new summary
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # ok, back in she goes
        ladies.update_contacts([self.c2], True)

        # do another run for contact 1
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # totals should reflect the new value, not the old
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 2)
        self.assertResult(result, 2, "Green", 1)

        # what if we do a partial run?
        self.send_message(self.flow, "red", contact=self.c1, restart_participants=True)

        # should change our male/female breakdown since c1 now no longer has a gender
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertResult(result, 0, "Male", 1)
        self.assertResult(result, 1, "Female", 2)

        # back to a full flow
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # ok, now segment by gender
        result = Value.get_value_summary(ruleset=color, filters=[], segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # segment by gender again, but use the contact field to do so
        result = Value.get_value_summary(ruleset=color, filters=[], segment=dict(contact_field="Gender", values=["MALE", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # add in a filter at the same time
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=color.pk, categories=["Blue"])],
                                         segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))

        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 0)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 0)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # ok, try segmenting by location instead
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 0)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # updating state location leads to updated data
        self.c2.set_field('state', "Eastern Province")
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 1)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 1)
        self.assertResult(kigali_result, 2, "Green", 0)

        # segment by district instead
        result = Value.get_value_summary(ruleset=color, segment=dict(parent="1708283", location="District"))

        # only on district in kigali
        self.assertEquals(1, len(result))
        kigali_result = result[0]
        self.assertEquals('60485579', kigali_result['boundary'])
        self.assertEquals('Kigali', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # do a sanity check on our choropleth view
        self.login(self.admin)
        response = self.client.get(reverse('flows.ruleset_choropleth', args=[color.pk]) +
                                   "?_format=json&boundary=" + self.org.country.osm_id)

        # response should be valid json
        response = json.loads(response.content)

        # should have breaks
        self.assertTrue('breaks' in response)

        # should have two categories, Blue and Others
        self.assertEquals(2, len(response['categories']))
        self.assertEquals("Blue", response['categories'][0])
        self.assertEquals("Others", response['categories'][1])

        # assert our kigali result
        kigali_result = response['scores']['1708283']
        self.assertEquals(1, kigali_result['score'])
        self.assertEquals("Kigali City", kigali_result['name'])
        self.assertEquals("Blue", kigali_result['results'][0]['label'])
        self.assertEquals("Others", kigali_result['results'][1]['label'])

        self.assertEquals(1, kigali_result['results'][0]['count'])
        self.assertEquals(0, kigali_result['results'][1]['count'])

        self.assertEquals(100, kigali_result['results'][0]['percentage'])
        self.assertEquals(0, kigali_result['results'][1]['percentage'])

        with patch('temba.values.models.Value.get_value_summary') as mock:
            mock.return_value = []

            response = self.client.get(reverse('flows.ruleset_choropleth', args=[color.pk]) +
                                   "?_format=json&boundary=" + self.org.country.osm_id)

            # response should be valid json
            response = json.loads(response.content)

            # should have two categories, Blue and Others
            self.assertEquals(2, len(response['categories']))
            self.assertEquals("", response['categories'][0])
            self.assertEquals("", response['categories'][1])

            # all counts and percentage are 0
            self.assertEquals(0, response['totals']['count'])
            self.assertEquals(0, response['totals']['results'][0]['count'])
            self.assertEquals(0, response['totals']['results'][0]['percentage'])
            self.assertEquals(0, response['totals']['results'][1]['count'])
            self.assertEquals(0, response['totals']['results'][1]['percentage'])

            # and empty string labels
            self.assertEquals("", response['totals']['results'][0]['label'])
            self.assertEquals("", response['totals']['results'][1]['label'])

        # also check our analytics view
        response = self.client.get(reverse('flows.ruleset_analytics'))

        # make sure we have only one flow in it
        flows = json.loads(response.context['flows'])
        self.assertEquals(1, len(flows))
        self.assertEquals(3, len(flows[0]['rules']))
コード例 #42
0
ファイル: tests.py プロジェクト: songea/rapidpro
    def test_field_results(self):
        c1 = self.create_contact("Contact1", '0788111111')
        c2 = self.create_contact("Contact2", '0788222222')
        c3 = self.create_contact("Contact3", '0788333333')
        self.create_contact("Contact4", '0788444444')

        # create a gender field that uses strings
        gender = ContactField.get_or_create(self.org,
                                            self.admin,
                                            'gender',
                                            label="Gender",
                                            value_type=Value.TYPE_TEXT)

        c1.set_field(self.user, 'gender', "Male")
        c2.set_field(self.user, 'gender', "Female")
        c3.set_field(self.user, 'gender', "Female")

        result = Value.get_value_summary(contact_field=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(
            2, result['unset']
        )  # this is two as we have the default contact created by our unit tests
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Female", 2)
        self.assertResult(result, 1, "Male", 1)

        # create an born field that uses decimals
        born = ContactField.get_or_create(self.org,
                                          self.admin,
                                          'born',
                                          label="Born",
                                          value_type=Value.TYPE_DECIMAL)
        c1.set_field(self.user, 'born', 1977)
        c2.set_field(self.user, 'born', 1990)
        c3.set_field(self.user, 'born', 1977)

        result = Value.get_value_summary(contact_field=born)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "1977", 2)
        self.assertResult(result, 1, "1990", 1)

        # ok, state field!
        state = ContactField.get_or_create(self.org,
                                           self.admin,
                                           'state',
                                           label="State",
                                           value_type=Value.TYPE_STATE)
        c1.set_field(self.user, 'state', "Kigali City")
        c2.set_field(self.user, 'state', "Kigali City")

        result = Value.get_value_summary(contact_field=state)[0]
        self.assertEquals(1, len(result['categories']))
        self.assertEquals(2, result['set'])
        self.assertEquals(3, result['unset'])
        self.assertResult(result, 0, "1708283", 2)

        reg_date = ContactField.get_or_create(self.org,
                                              self.admin,
                                              'reg_date',
                                              label="Registration Date",
                                              value_type=Value.TYPE_DATETIME)
        now = timezone.now()

        c1.set_field(self.user, 'reg_date', now.replace(hour=9))
        c2.set_field(self.user, 'reg_date', now.replace(hour=4))
        c3.set_field(self.user, 'reg_date', now - timedelta(days=1))
        result = Value.get_value_summary(contact_field=reg_date)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertResult(
            result, 0, now.replace(hour=0, minute=0, second=0, microsecond=0),
            2)
        self.assertResult(result, 1,
                          (now - timedelta(days=1)).replace(hour=0,
                                                            minute=0,
                                                            second=0,
                                                            microsecond=0), 1)

        # make sure categories returned are sorted by count, not name
        c2.set_field(self.user, 'gender', "Male")
        result = Value.get_value_summary(contact_field=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(
            2, result['unset']
        )  # this is two as we have the default contact created by our unit tests
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Male", 2)
        self.assertResult(result, 1, "Female", 1)

        # check the modified date is tracked for fields
        original_value = Value.objects.get(contact=c1, contact_field=gender)
        c1.set_field(self.user, 'gender', 'unknown')
        new_value = Value.objects.get(contact=c1, contact_field=gender)
        self.assertTrue(new_value.modified_on > original_value.modified_on)
        self.assertNotEqual(new_value.string_value,
                            original_value.string_value)
コード例 #43
0
    def test_scheduling(self):
        campaign = Campaign.create(self.org, self.admin, "Planting Reminders", self.farmers)

        self.assertEquals("Planting Reminders", unicode(campaign))

        # create a reminder for our first planting event
        planting_reminder = CampaignEvent.create_flow_event(self.org, self.admin, campaign, relative_to=self.planting_date,
                                                            offset=0, unit='D', flow=self.reminder_flow, delivery_hour=17)

        self.assertEquals("Planting Date == 0 -> Color Flow", unicode(planting_reminder))

        # schedule our reminders
        EventFire.update_campaign_events(campaign)

        # we should haven't any event fires created, since neither of our farmers have a planting date
        self.assertEquals(0, EventFire.objects.all().count())

        # ok, set a planting date on one of our contacts
        self.farmer1.set_field('planting_date', "05-10-2020 12:30:10")

        # update our campaign events
        EventFire.update_campaign_events(campaign)

        # should have one event now
        fire = EventFire.objects.get()
        self.assertEquals(5, fire.scheduled.day)
        self.assertEquals(10, fire.scheduled.month)
        self.assertEquals(2020, fire.scheduled.year)

        # account for timezone difference, our org is in UTC+2
        self.assertEquals(17 - 2, fire.scheduled.hour)

        self.assertEquals(self.farmer1, fire.contact)
        self.assertEquals(planting_reminder, fire.event)

        self.assertIsNone(fire.fired)

        # change the date of our date
        self.farmer1.set_field('planting_date', "06-10-2020 12:30:10")

        EventFire.update_campaign_events_for_contact(campaign, self.farmer1)
        fire = EventFire.objects.get()
        self.assertEquals(6, fire.scheduled.day)
        self.assertEquals(10, fire.scheduled.month)
        self.assertEquals(2020, fire.scheduled.year)
        self.assertEquals(self.farmer1, fire.contact)
        self.assertEquals(planting_reminder, fire.event)

        # set it to something invalid
        self.farmer1.set_field('planting_date', "what?")
        EventFire.update_campaign_events_for_contact(campaign, self.farmer1)
        self.assertFalse(EventFire.objects.all())

        # now something valid again
        self.farmer1.set_field('planting_date', "07-10-2020 12:30:10")

        EventFire.update_campaign_events_for_contact(campaign, self.farmer1)
        fire = EventFire.objects.get()
        self.assertEquals(7, fire.scheduled.day)
        self.assertEquals(10, fire.scheduled.month)
        self.assertEquals(2020, fire.scheduled.year)
        self.assertEquals(self.farmer1, fire.contact)
        self.assertEquals(planting_reminder, fire.event)

        # create another reminder
        planting_reminder2 = CampaignEvent.create_flow_event(self.org, self.admin, campaign, relative_to=self.planting_date,
                                                             offset=1, unit='D', flow=self.reminder2_flow)

        self.assertEquals(1, planting_reminder2.abs_offset())

        # update the campaign
        EventFire.update_campaign_events(campaign)

        # should have two events now, ordered by date
        events = EventFire.objects.all()

        self.assertEquals(planting_reminder, events[0].event)
        self.assertEquals(7, events[0].scheduled.day)

        self.assertEquals(planting_reminder2, events[1].event)
        self.assertEquals(8, events[1].scheduled.day)

        # mark one of the events as inactive
        planting_reminder2.is_active = False
        planting_reminder2.save()

        # update the campaign
        EventFire.update_campaign_events(campaign)

        # back to only one event
        event = EventFire.objects.get()
        self.assertEquals(planting_reminder, event.event)
        self.assertEquals(7, event.scheduled.day)

        # update our date
        self.farmer1.set_field('planting_date', '09-10-2020 12:30')

        # should have updated
        event = EventFire.objects.get()
        self.assertEquals(planting_reminder, event.event)
        self.assertEquals(9, event.scheduled.day)

        # let's remove our contact field
        ContactField.hide_field(self.org, 'planting_date')

        # shouldn't have anything scheduled
        self.assertFalse(EventFire.objects.all())

        # add it back in
        ContactField.get_or_create(self.org, 'planting_date', "planting Date")

        # should be back!
        event = EventFire.objects.get()
        self.assertEquals(planting_reminder, event.event)
        self.assertEquals(9, event.scheduled.day)

        # change our fire date to sometimein the past so it gets triggered
        event.scheduled = timezone.now() - timedelta(hours=1)
        event.save()

        # schedule our events to fire
        check_campaigns_task()

        # should have one flow run now
        run = FlowRun.objects.get()
        self.assertEquals(event.contact, run.contact)
コード例 #44
0
ファイル: perf_tests.py プロジェクト: tsotetsi/textily-web
    def setUp(self):
        self.clear_cache()

        self.user = self.create_user("tito")
        self.admin = self.create_user("Administrator")
        self.org = Org.objects.create(name="Nyaruka Ltd.",
                                      timezone="Africa/Kigali",
                                      created_by=self.user,
                                      modified_by=self.user)
        self.org.initialize()

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

        self.tel_mtn = Channel.create(self.org,
                                      self.user,
                                      'RW',
                                      'A',
                                      name="MTN",
                                      address="+250780000000",
                                      secret="12345",
                                      gcm_id="123")
        self.tel_tigo = Channel.create(self.org,
                                       self.user,
                                       'RW',
                                       'A',
                                       name="Tigo",
                                       address="+250720000000",
                                       secret="23456",
                                       gcm_id="234")
        self.tel_bulk = Channel.create(self.org,
                                       self.user,
                                       'RW',
                                       'NX',
                                       name="Nexmo",
                                       parent=self.tel_tigo)
        self.twitter = Channel.create(self.org,
                                      self.user,
                                      None,
                                      'TT',
                                      name="Twitter",
                                      address="billy_bob")

        # for generating tuples of scheme, path and channel
        def generate_tel_mtn(num):
            return TEL_SCHEME, "+25078%07d" % (num + 1), self.tel_mtn

        def generate_tel_tigo(num):
            return TEL_SCHEME, "+25072%07d" % (num + 1), self.tel_tigo

        def generate_twitter(num):
            return TWITTER_SCHEME, "tweep_%d" % (num + 1), self.twitter

        self.urn_generators = (generate_tel_mtn, generate_tel_tigo,
                               generate_twitter)

        self.field_nick = ContactField.get_or_create(
            self.org,
            self.admin,
            'nick',
            'Nickname',
            show_in_table=True,
            value_type=Value.TYPE_TEXT)
        self.field_age = ContactField.get_or_create(
            self.org,
            self.admin,
            'age',
            'Age',
            show_in_table=True,
            value_type=Value.TYPE_DECIMAL)
コード例 #45
0
ファイル: tests.py プロジェクト: xuanhan863/rapidpro
    def test_category_results(self):
        self.setup_color_gender_flow()

        # create a state field:
        # assign c1 and c2 to Kigali
        state = ContactField.get_or_create(self.org, 'state', label="State", value_type=STATE)
        district = ContactField.get_or_create(self.org, 'district', label="District", value_type=DISTRICT)
        self.c1.set_field('state', "Kigali City")
        self.c1.set_field('district', "Kigali")
        self.c2.set_field('state', "Kigali City")
        self.c2.set_field('district', "Kigali")

        self.run_color_gender_flow(self.c1, "red", "male", "16")
        self.run_color_gender_flow(self.c2, "blue", "female", "19")
        self.run_color_gender_flow(self.c3, "green", "male", "75")
        self.run_color_gender_flow(self.c4, "maroon", "female", "50")

        # create a group of the women
        ladies = self.create_group("Ladies", [self.c2, self.c4])

        # get our rulesets
        color = RuleSet.objects.get(flow=self.flow, label="Color")
        gender = RuleSet.objects.get(flow=self.flow, label="Gender")
        age = RuleSet.objects.get(flow=self.flow, label="Age")

        # categories should be in the same order as our rules, should have correct counts
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Red", 2)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 1)

        # check our age category as well
        result = Value.get_value_summary(ruleset=age)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Child", 1)
        self.assertResult(result, 1, "Adult", 2)
        self.assertResult(result, 2, "Senior", 1)

        # and our gender categories
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Male", 2)
        self.assertResult(result, 1, "Female", 2)

        # now filter the results and only get responses by men
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"])])[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 1)

        # what about men that are adults?
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]
        self.assertResult(result, 0, "Red", 0)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # union of all genders
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male", "Female"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # just women adults by group
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # remove one of the women from the group
        ladies.update_contacts([self.c2], False)

        # get a new summary
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # ok, back in she goes
        ladies.update_contacts([self.c2], True)

        # do another run for contact 1
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # totals should reflect the new value, not the old
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 2)
        self.assertResult(result, 2, "Green", 1)

        # what if we do a partial run?
        self.send_message(self.flow, "red", contact=self.c1, restart_participants=True)

        # should change our male/female breakdown since c1 now no longer has a gender
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertResult(result, 0, "Male", 1)
        self.assertResult(result, 1, "Female", 2)

        # back to a full flow
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # ok, now segment by gender
        result = Value.get_value_summary(ruleset=color, filters=[], segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # add in a filter at the same time
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=color.pk, categories=["Blue"])],
                                         segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))

        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 0)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 0)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # ok, try segmenting by location instead
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 0)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # updating state location leads to updated data
        self.c2.set_field('state', "Eastern Province")
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 1)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 1)
        self.assertResult(kigali_result, 2, "Green", 0)

        # segment by district instead
        result = Value.get_value_summary(ruleset=color, segment=dict(parent="1708283", location="District"))

        # only on district in kigali
        self.assertEquals(1, len(result))
        kigali_result = result[0]
        self.assertEquals('60485579', kigali_result['boundary'])
        self.assertEquals('Kigali', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)
コード例 #46
0
ファイル: tests.py プロジェクト: AbrahamKiggundu/rapidpro
    def test_scheduling(self):
        campaign = Campaign.objects.create(name="Planting Reminders", group=self.farmers, org=self.org,
                                           created_by=self.admin, modified_by=self.admin)

        self.assertEquals("Planting Reminders", unicode(campaign))

        # create a reminder for our first planting event
        planting_reminder = CampaignEvent.objects.create(campaign=campaign, relative_to=self.planting_date, offset=0,
                                                         flow=self.reminder_flow, delivery_hour=17,
                                                         created_by=self.admin, modified_by=self.admin)

        self.assertEquals("Planting Date == 0 -> Color Flow", unicode(planting_reminder))

        # schedule our reminders
        EventFire.update_campaign_events(campaign)

        # we should haven't any event fires created, since neither of our farmers have a planting date
        self.assertEquals(0, EventFire.objects.all().count())

        # ok, set a planting date on one of our contacts
        self.farmer1.set_field('planting_date', "05-10-2020 12:30:10")

        # update our campaign events
        EventFire.update_campaign_events(campaign)

        # should have one event now
        fire = EventFire.objects.get()
        self.assertEquals(5, fire.scheduled.day)
        self.assertEquals(10, fire.scheduled.month)
        self.assertEquals(2020, fire.scheduled.year)

        # account for timezone difference, our org is in UTC+2
        self.assertEquals(17 - 2, fire.scheduled.hour)

        self.assertEquals(self.farmer1, fire.contact)
        self.assertEquals(planting_reminder, fire.event)

        self.assertIsNone(fire.fired)

        # change the date of our date
        self.farmer1.set_field('planting_date', "06-10-2020 12:30:10")

        EventFire.update_campaign_events_for_contact(campaign, self.farmer1)
        fire = EventFire.objects.get()
        self.assertEquals(6, fire.scheduled.day)
        self.assertEquals(10, fire.scheduled.month)
        self.assertEquals(2020, fire.scheduled.year)
        self.assertEquals(self.farmer1, fire.contact)
        self.assertEquals(planting_reminder, fire.event)

        # set it to something invalid
        self.farmer1.set_field('planting_date', "what?")
        EventFire.update_campaign_events_for_contact(campaign, self.farmer1)
        self.assertFalse(EventFire.objects.all())

        # now something valid again
        self.farmer1.set_field('planting_date', "07-10-2020 12:30:10")

        EventFire.update_campaign_events_for_contact(campaign, self.farmer1)
        fire = EventFire.objects.get()
        self.assertEquals(7, fire.scheduled.day)
        self.assertEquals(10, fire.scheduled.month)
        self.assertEquals(2020, fire.scheduled.year)
        self.assertEquals(self.farmer1, fire.contact)
        self.assertEquals(planting_reminder, fire.event)

        # create another reminder
        planting_reminder2 = CampaignEvent.objects.create(campaign=campaign, relative_to=self.planting_date, offset=1,
                                                          flow=self.reminder2_flow,
                                                          created_by=self.admin, modified_by=self.admin)

        self.assertEquals(1, planting_reminder2.abs_offset())

        # update the campaign
        EventFire.update_campaign_events(campaign)

        # should have two events now, ordered by date
        events = EventFire.objects.all()

        self.assertEquals(planting_reminder, events[0].event)
        self.assertEquals(7, events[0].scheduled.day)

        self.assertEquals(planting_reminder2, events[1].event)
        self.assertEquals(8, events[1].scheduled.day)

        # mark one of the events as inactive
        planting_reminder2.is_active = False
        planting_reminder2.save()

        # update the campaign
        EventFire.update_campaign_events(campaign)

        # back to only one event
        event = EventFire.objects.get()
        self.assertEquals(planting_reminder, event.event)
        self.assertEquals(7, event.scheduled.day)

        # update our date
        self.farmer1.set_field('planting_date', '09-10-2020 12:30')

        # should have updated
        event = EventFire.objects.get()
        self.assertEquals(planting_reminder, event.event)
        self.assertEquals(9, event.scheduled.day)

        # let's remove our contact field
        ContactField.hide_field(self.org, 'planting_date')

        # shouldn't have anything scheduled
        self.assertFalse(EventFire.objects.all())

        # add it back in
        ContactField.get_or_create(self.org, 'planting_date', "planting Date")

        # should be back!
        event = EventFire.objects.get()
        self.assertEquals(planting_reminder, event.event)
        self.assertEquals(9, event.scheduled.day)

        # try firing the event
        event.fire()

        # should have one flow run now
        run = FlowRun.objects.get()
        self.assertEquals(event.contact, run.contact)
コード例 #47
0
ファイル: tests.py プロジェクト: CliffordOwino/rapidpro
    def test_field_results(self):
        c1 = self.create_contact("Contact1", '0788111111')
        c2 = self.create_contact("Contact2", '0788222222')
        c3 = self.create_contact("Contact3", '0788333333')
        self.create_contact("Contact4", '0788444444')

        # create a gender field that uses strings
        gender = ContactField.get_or_create(self.org, self.admin, 'gender', label="Gender", value_type=Value.TYPE_TEXT)

        c1.set_field(self.user, 'gender', "Male")
        c2.set_field(self.user, 'gender', "Female")
        c3.set_field(self.user, 'gender', "Female")

        result = Value.get_value_summary(contact_field=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])  # this is two as we have the default contact created by our unit tests
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Female", 2)
        self.assertResult(result, 1, "Male", 1)

        # create an born field that uses decimals
        born = ContactField.get_or_create(self.org, self.admin, 'born', label="Born", value_type=Value.TYPE_DECIMAL)
        c1.set_field(self.user, 'born', 1977)
        c2.set_field(self.user, 'born', 1990)
        c3.set_field(self.user, 'born', 1977)

        result = Value.get_value_summary(contact_field=born)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "1977", 2)
        self.assertResult(result, 1, "1990", 1)

        # ok, state field!
        state = ContactField.get_or_create(self.org, self.admin, 'state', label="State", value_type=Value.TYPE_STATE)
        c1.set_field(self.user, 'state', "Kigali City")
        c2.set_field(self.user, 'state', "Kigali City")

        result = Value.get_value_summary(contact_field=state)[0]
        self.assertEquals(1, len(result['categories']))
        self.assertEquals(2, result['set'])
        self.assertEquals(3, result['unset'])
        self.assertResult(result, 0, "1708283", 2)

        reg_date = ContactField.get_or_create(self.org, self.admin, 'reg_date', label="Registration Date", value_type=Value.TYPE_DATETIME)
        now = timezone.now()

        c1.set_field(self.user, 'reg_date', now.replace(hour=9))
        c2.set_field(self.user, 'reg_date', now.replace(hour=4))
        c3.set_field(self.user, 'reg_date', now - timedelta(days=1))
        result = Value.get_value_summary(contact_field=reg_date)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertResult(result, 0, now.replace(hour=0, minute=0, second=0, microsecond=0), 2)
        self.assertResult(result, 1, (now - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0), 1)

        # make sure categories returned are sorted by count, not name
        c2.set_field(self.user, 'gender', "Male")
        result = Value.get_value_summary(contact_field=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])  # this is two as we have the default contact created by our unit tests
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Male", 2)
        self.assertResult(result, 1, "Female", 1)

        # check the modified date is tracked for fields
        original_value = Value.objects.get(contact=c1, contact_field=gender)
        c1.set_field(self.user, 'gender', 'unknown')
        new_value = Value.objects.get(contact=c1, contact_field=gender)
        self.assertTrue(new_value.modified_on > original_value.modified_on)
        self.assertNotEqual(new_value.string_value, original_value.string_value)