Exemplo n.º 1
0
    def create_contact(self,
                       name=None,
                       number=None,
                       twitter=None,
                       twitterid=None,
                       urn=None,
                       **kwargs):
        """
        Create a contact in the master test org
        """
        urns = []
        if number:
            urns.append(URN.from_tel(number))
        if twitter:
            urns.append(URN.from_twitter(twitter))
        if twitterid:
            urns.append(URN.from_twitterid(twitterid))
        if urn:
            urns.append(urn)

        if not name and not urns:  # pragma: no cover
            raise ValueError("Need a name or URN to create a contact")

        kwargs["name"] = name
        kwargs["urns"] = urns

        if "org" not in kwargs:
            kwargs["org"] = self.org
        if "user" not in kwargs:
            kwargs["user"] = self.user

        return Contact.get_or_create_by_urns(**kwargs)
Exemplo n.º 2
0
    def create_contact(self,
                       name=None,
                       number=None,
                       twitter=None,
                       urn=None,
                       is_test=False,
                       **kwargs):
        """
        Create a contact in the master test org
        """
        urns = []
        if number:
            urns.append(URN.from_tel(number))
        if twitter:
            urns.append(URN.from_twitter(twitter))
        if urn:
            urns.append(urn)

        if not name and not urns:  # pragma: no cover
            raise ValueError("Need a name or URN to create a contact")

        kwargs['name'] = name
        kwargs['urns'] = urns
        kwargs['is_test'] = is_test

        if 'org' not in kwargs:
            kwargs['org'] = self.org
        if 'user' not in kwargs:
            kwargs['user'] = self.user

        return Contact.get_or_create(**kwargs)
Exemplo n.º 3
0
    def create_contact(self,
                       name=None,
                       number=None,
                       twitter=None,
                       urn=None,
                       fields=None,
                       **kwargs):
        """
        Create a contact in the master test org
        """

        org = kwargs.pop("org", None) or self.org
        user = kwargs.pop("user", None) or self.user

        urns = []
        if number:
            urns.append(URN.from_tel(number))
        if twitter:
            urns.append(URN.from_twitter(twitter))
        if urn:
            urns.append(urn)

        assert name or urns, "contact should have a name or a contact"

        kwargs["name"] = name
        kwargs["urns"] = urns

        contact = Contact.get_or_create_by_urns(org, user, **kwargs)

        if fields:
            update_fields_locally(user, contact, fields)

        return contact
Exemplo n.º 4
0
    def create_contact(self, name=None, number=None, twitter=None, urn=None, is_test=False, **kwargs):
        """
        Create a contact in the master test org
        """
        urns = []
        if number:
            urns.append(URN.from_tel(number))
        if twitter:
            urns.append(URN.from_twitter(twitter))
        if urn:
            urns.append(urn)

        if not name and not urns:  # pragma: no cover
            raise ValueError("Need a name or URN to create a contact")

        kwargs['name'] = name
        kwargs['urns'] = urns
        kwargs['is_test'] = is_test

        if 'org' not in kwargs:
            kwargs['org'] = self.org
        if 'user' not in kwargs:
            kwargs['user'] = self.user

        return Contact.get_or_create(**kwargs)
Exemplo n.º 5
0
    def create_contact(self, name=None, number=None, twitter=None, twitterid=None, urn=None, is_test=False, **kwargs):
        """
        Create a contact in the master test org
        """
        urns = []
        if number:
            urns.append(URN.from_tel(number))
        if twitter:
            urns.append(URN.from_twitter(twitter))
        if twitterid:
            urns.append(URN.from_twitterid(twitterid))
        if urn:
            urns.append(urn)

        if not name and not urns:  # pragma: no cover
            raise ValueError("Need a name or URN to create a contact")

        kwargs["name"] = name
        kwargs["urns"] = urns
        kwargs["is_test"] = is_test

        if "org" not in kwargs:
            kwargs["org"] = self.org
        if "user" not in kwargs:
            kwargs["user"] = self.user

        return Contact.get_or_create_by_urns(**kwargs)
Exemplo n.º 6
0
    def send(self, channel, msg, text):
        twitter = TembaTwython.from_channel(channel)
        start = time.time()

        try:
            urn = getattr(msg, "urn", URN.from_twitter(msg.urn_path))
            (scheme, path, query, display) = URN.to_parts(urn)

            # this is a legacy URN (no display), the path is our screen name
            if scheme == TWITTER_SCHEME:
                dm = twitter.send_direct_message(screen_name=path, text=text)
                external_id = dm["id"]

            # this is a new twitterid URN, our path is our user id
            else:
                metadata = msg.metadata if hasattr(msg, "metadata") else {}
                quick_replies = metadata.get("quick_replies", [])
                formatted_replies = [dict(label=item[: self.quick_reply_text_size]) for item in quick_replies]

                if quick_replies:
                    params = {
                        "event": {
                            "type": "message_create",
                            "message_create": {
                                "target": {"recipient_id": path},
                                "message_data": {
                                    "text": text,
                                    "quick_reply": {"type": "options", "options": formatted_replies},
                                },
                            },
                        }
                    }
                    dm = twitter.post("direct_messages/events/new", params=params)
                    external_id = dm["event"]["id"]
                else:
                    dm = twitter.send_direct_message(user_id=path, text=text)
                    external_id = dm["id"]

        except Exception as e:
            error_code = getattr(e, "error_code", 400)
            fatal = False

            if error_code == 404:  # handle doesn't exist
                fatal = True
            elif error_code == 403:
                for err in self.FATAL_403S:
                    if str(e).find(err) >= 0:
                        fatal = True
                        break

            # if message can never be sent, stop them contact
            if fatal:
                contact = Contact.objects.get(id=msg.contact)
                contact.stop(contact.modified_by)

            raise SendException(str(e), events=twitter.events, fatal=fatal, start=start)

        Channel.success(channel, msg, WIRED, start, events=twitter.events, external_id=external_id)
Exemplo n.º 7
0
    def test_resolve(self, mock_lookup_user):
        self.joe = self.create_contact("joe", twitter="therealjoe")

        urn = self.joe.get_urns()[0]

        # test no return value, should cause joe to be stopped
        mock_lookup_user.return_value = []
        resolve_twitter_ids()

        self.joe.refresh_from_db()
        urn.refresh_from_db()
        self.assertTrue(self.joe.is_stopped)
        self.assertIsNone(urn.display)
        self.assertEqual("twitter:therealjoe", urn.identity)
        self.assertEqual("therealjoe", urn.path)

        self.joe.unstop(self.admin)

        # test a real return value
        mock_lookup_user.return_value = [dict(screen_name="TheRealJoe", id="123456")]
        resolve_twitter_ids()

        urn.refresh_from_db()
        self.assertIsNone(urn.contact)

        new_urn = self.joe.get_urns()[0]
        self.assertEqual("twitterid:123456", new_urn.identity)
        self.assertEqual("123456", new_urn.path)
        self.assertEqual("therealjoe", new_urn.display)
        self.assertEqual("twitterid:123456#therealjoe", new_urn.urn)

        old_fred = self.create_contact("old fred", urn=URN.from_twitter("fred"))
        new_fred = self.create_contact("new fred", urn=URN.from_twitterid("12345", screen_name="fred"))

        mock_lookup_user.return_value = [dict(screen_name="fred", id="12345")]
        resolve_twitter_ids()

        # new fred shouldn't have any URNs anymore as he really is old_fred
        self.assertEqual(0, len(new_fred.urns.all()))

        # old fred should be unchanged
        self.assertEqual("twitterid:12345", old_fred.urns.all()[0].identity)

        self.jane = self.create_contact("jane", twitter="jane10")
        mock_lookup_user.side_effect = Exception(
            "Twitter API returned a 404 (Not Found), No user matches for specified terms."
        )
        resolve_twitter_ids()

        self.jane.refresh_from_db()
        self.assertTrue(self.jane.is_stopped)

        self.sarah = self.create_contact("sarah", twitter="sarah20")
        mock_lookup_user.side_effect = Exception("Unable to reach API")
        resolve_twitter_ids()

        self.sarah.refresh_from_db()
        self.assertFalse(self.sarah.is_stopped)
Exemplo n.º 8
0
    def test_resolve(self, mock_lookup_user):
        self.joe = self.create_contact("joe", twitter="therealjoe")

        urn = self.joe.get_urns()[0]

        # test no return value, should cause joe to be stopped
        mock_lookup_user.return_value = []
        resolve_twitter_ids()

        self.joe.refresh_from_db()
        urn.refresh_from_db()
        self.assertTrue(self.joe.is_stopped)
        self.assertIsNone(urn.display)
        self.assertEqual("twitter:therealjoe", urn.identity)
        self.assertEqual("therealjoe", urn.path)

        self.joe.unstop(self.admin)

        # test a real return value
        mock_lookup_user.return_value = [dict(screen_name="TheRealJoe", id="123456")]
        resolve_twitter_ids()

        urn.refresh_from_db()
        self.assertIsNone(urn.contact)

        new_urn = self.joe.get_urns()[0]
        self.assertEqual("twitterid:123456", new_urn.identity)
        self.assertEqual("123456", new_urn.path)
        self.assertEqual("therealjoe", new_urn.display)
        self.assertEqual("twitterid:123456#therealjoe", new_urn.urn)

        old_fred = self.create_contact("old fred", urn=URN.from_twitter("fred"))
        new_fred = self.create_contact("new fred", urn=URN.from_twitterid("12345", screen_name="fred"))

        mock_lookup_user.return_value = [dict(screen_name="fred", id="12345")]
        resolve_twitter_ids()

        # new fred shouldn't have any URNs anymore as he really is old_fred
        self.assertEqual(0, len(new_fred.urns.all()))

        # old fred should be unchanged
        self.assertEqual("twitterid:12345", old_fred.urns.all()[0].identity)

        self.jane = self.create_contact("jane", twitter="jane10")
        mock_lookup_user.side_effect = Exception(
            "Twitter API returned a 404 (Not Found), No user matches for specified terms."
        )
        resolve_twitter_ids()

        self.jane.refresh_from_db()
        self.assertTrue(self.jane.is_stopped)

        self.sarah = self.create_contact("sarah", twitter="sarah20")
        mock_lookup_user.side_effect = Exception("Unable to reach API")
        resolve_twitter_ids()

        self.sarah.refresh_from_db()
        self.assertFalse(self.sarah.is_stopped)
Exemplo n.º 9
0
    def _create_contact_batch(self, batch):
        """
        Bulk creates a batch of contacts from flat representations
        """
        for c in batch:
            c["object"] = Contact(
                org=c["org"],
                name=c["name"],
                language=c["language"],
                is_stopped=c["is_stopped"],
                is_blocked=c["is_blocked"],
                is_active=c["is_active"],
                created_by=c["user"],
                created_on=c["created_on"],
                modified_by=c["user"],
                modified_on=c["modified_on"],
                fields=c["fields_as_json"],
            )
        Contact.objects.bulk_create([c["object"] for c in batch])

        # now that contacts have pks, bulk create the actual URN, value and group membership objects
        batch_urns = []
        batch_memberships = []

        for c in batch:
            org = c["org"]
            c["urns"] = []

            if c["tel"]:
                c["urns"].append(
                    ContactURN(
                        org=org,
                        contact=c["object"],
                        priority=50,
                        scheme=TEL_SCHEME,
                        path=c["tel"],
                        identity=URN.from_tel(c["tel"]),
                    )
                )
            if c["twitter"]:
                c["urns"].append(
                    ContactURN(
                        org=org,
                        contact=c["object"],
                        priority=50,
                        scheme=TWITTER_SCHEME,
                        path=c["twitter"],
                        identity=URN.from_twitter(c["twitter"]),
                    )
                )
            for g in c["groups"]:
                batch_memberships.append(ContactGroup.contacts.through(contact=c["object"], contactgroup=g))

            batch_urns += c["urns"]

        ContactURN.objects.bulk_create(batch_urns)
        ContactGroup.contacts.through.objects.bulk_create(batch_memberships)
Exemplo n.º 10
0
    def _create_contact_batch(self, batch):
        """
        Bulk creates a batch of contacts from flat representations
        """
        for c in batch:
            c["object"] = Contact(
                org=c["org"],
                name=c["name"],
                language=c["language"],
                is_stopped=c["is_stopped"],
                is_blocked=c["is_blocked"],
                is_active=c["is_active"],
                created_by=c["user"],
                created_on=c["created_on"],
                modified_by=c["user"],
                modified_on=c["modified_on"],
                fields=c["fields_as_json"],
            )
        Contact.objects.bulk_create([c["object"] for c in batch])

        # now that contacts have pks, bulk create the actual URN, value and group membership objects
        batch_urns = []
        batch_memberships = []

        for c in batch:
            org = c["org"]
            c["urns"] = []

            if c["tel"]:
                c["urns"].append(
                    ContactURN(
                        org=org,
                        contact=c["object"],
                        priority=50,
                        scheme=TEL_SCHEME,
                        path=c["tel"],
                        identity=URN.from_tel(c["tel"]),
                    )
                )
            if c["twitter"]:
                c["urns"].append(
                    ContactURN(
                        org=org,
                        contact=c["object"],
                        priority=50,
                        scheme=TWITTER_SCHEME,
                        path=c["twitter"],
                        identity=URN.from_twitter(c["twitter"]),
                    )
                )
            for g in c["groups"]:
                batch_memberships.append(ContactGroup.contacts.through(contact=c["object"], contactgroup=g))

            batch_urns += c["urns"]

        ContactURN.objects.bulk_create(batch_urns)
        ContactGroup.contacts.through.objects.bulk_create(batch_memberships)
Exemplo n.º 11
0
    def _create_contact_batch(self, batch):
        """
        Bulk creates a batch of contacts from flat representations
        """
        for c in batch:
            c['object'] = Contact(org=c['org'], name=c['name'], language=c['language'],
                                  is_stopped=c['is_stopped'], is_blocked=c['is_blocked'],
                                  is_active=c['is_active'],
                                  created_by=c['user'], created_on=c['created_on'],
                                  modified_by=c['user'], modified_on=c['modified_on'])
        Contact.objects.bulk_create([c['object'] for c in batch])

        # now that contacts have pks, bulk create the actual URN, value and group membership objects
        batch_urns = []
        batch_values = []
        batch_memberships = []

        for c in batch:
            org = c['org']
            c['urns'] = []

            if c['tel']:
                c['urns'].append(ContactURN(org=org, contact=c['object'], priority=50, scheme=TEL_SCHEME,
                                            path=c['tel'], urn=URN.from_tel(c['tel'])))
            if c['twitter']:
                c['urns'].append(ContactURN(org=org, contact=c['object'], priority=50, scheme=TWITTER_SCHEME,
                                            path=c['twitter'], urn=URN.from_twitter(c['twitter'])))
            if c['gender']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['gender'],
                                          string_value=c['gender']))
            if c['age']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['age'],
                                          string_value=str(c['age']), decimal_value=c['age']))
            if c['joined']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['joined'],
                                          string_value=datetime_to_str(c['joined']), datetime_value=c['joined']))
            if c['ward']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['ward'],
                                          string_value=c['ward'].name, location_value=c['ward']))
            if c['district']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['district'],
                                          string_value=c['district'].name, location_value=c['district']))
            if c['state']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['state'],
                                          string_value=c['state'].name, location_value=c['state']))
            for g in c['groups']:
                batch_memberships.append(ContactGroup.contacts.through(contact=c['object'], contactgroup=g))

            batch_urns += c['urns']

        ContactURN.objects.bulk_create(batch_urns)
        Value.objects.bulk_create(batch_values)
        ContactGroup.contacts.through.objects.bulk_create(batch_memberships)
Exemplo n.º 12
0
    def _create_contact_batch(self, batch):
        """
        Bulk creates a batch of contacts from flat representations
        """
        for c in batch:
            c['object'] = Contact(org=c['org'],
                                  name=c['name'],
                                  language=c['language'],
                                  is_stopped=c['is_stopped'],
                                  is_blocked=c['is_blocked'],
                                  is_active=c['is_active'],
                                  created_by=c['user'],
                                  created_on=c['created_on'],
                                  modified_by=c['user'],
                                  modified_on=c['modified_on'],
                                  fields=c['fields_as_json'])
        Contact.objects.bulk_create([c['object'] for c in batch])

        # now that contacts have pks, bulk create the actual URN, value and group membership objects
        batch_urns = []
        batch_memberships = []

        for c in batch:
            org = c['org']
            c['urns'] = []

            if c['tel']:
                c['urns'].append(
                    ContactURN(org=org,
                               contact=c['object'],
                               priority=50,
                               scheme=TEL_SCHEME,
                               path=c['tel'],
                               identity=URN.from_tel(c['tel'])))
            if c['twitter']:
                c['urns'].append(
                    ContactURN(org=org,
                               contact=c['object'],
                               priority=50,
                               scheme=TWITTER_SCHEME,
                               path=c['twitter'],
                               identity=URN.from_twitter(c['twitter'])))
            for g in c['groups']:
                batch_memberships.append(
                    ContactGroup.contacts.through(contact=c['object'],
                                                  contactgroup=g))

            batch_urns += c['urns']

        ContactURN.objects.bulk_create(batch_urns)
        ContactGroup.contacts.through.objects.bulk_create(batch_memberships)
Exemplo n.º 13
0
    def send(self, channel, msg, text):
        twitter = TembaTwython.from_channel(channel)
        start = time.time()

        try:
            urn = getattr(msg, 'urn', URN.from_twitter(msg.urn_path))
            (scheme, path, display) = URN.to_parts(urn)

            # this is a legacy URN (no display), the path is our screen name
            if scheme == TWITTER_SCHEME:
                dm = twitter.send_direct_message(screen_name=path, text=text)

            # this is a new twitterid URN, our path is our user id
            else:
                dm = twitter.send_direct_message(user_id=path, text=text)

        except Exception as e:
            error_code = getattr(e, 'error_code', 400)
            fatal = False

            if error_code == 404:  # handle doesn't exist
                fatal = True
            elif error_code == 403:
                for err in self.FATAL_403S:
                    if six.text_type(e).find(err) >= 0:
                        fatal = True
                        break

            # if message can never be sent, stop them contact
            if fatal:
                contact = Contact.objects.get(id=msg.contact)
                contact.stop(contact.modified_by)

            raise SendException(str(e),
                                events=twitter.events,
                                fatal=fatal,
                                start=start)

        external_id = dm['id']
        Channel.success(channel,
                        msg,
                        WIRED,
                        start,
                        events=twitter.events,
                        external_id=external_id)
Exemplo n.º 14
0
    def send(self, channel, msg, text):
        twitter = TembaTwython.from_channel(channel)
        start = time.time()

        try:
            urn = getattr(msg, 'urn', URN.from_twitter(msg.urn_path))
            (scheme, path, display) = URN.to_parts(urn)
            print("scheme %s" % (scheme))
            print("path %s" % (path))
            print("display %s" % (display))
            # this is a legacy URN (no display), the path is our screen name
            if scheme == TWITTER_SCHEME:
                dm = twitter.send_direct_message(screen_name=path, text=text)
                external_id = dm['id']

            # this is a new twitterid URN, our path is our user id
            else:
                metadata = msg.metadata if hasattr(msg, 'metadata') else {}
                quick_replies = metadata.get('quick_replies', [])
                formatted_replies = [
                    dict(label=item[:self.quick_reply_text_size])
                    for item in quick_replies
                ]

                if quick_replies:
                    params = {
                        'event': {
                            'type': 'message_create',
                            'message_create': {
                                'target': {
                                    'recipient_id': path
                                },
                                'message_data': {
                                    'text': text,
                                    'quick_reply': {
                                        'type': 'options',
                                        'options': formatted_replies
                                    }
                                }
                            }
                        }
                    }
                    dm = twitter.post('direct_messages/events/new',
                                      params=params)
                    external_id = dm['event']['id']
                else:
                    print(path)
                    print(text)
                    dm = twitter.send_direct_message(user_id=path, text=text)
                    external_id = dm['id']

        except Exception as e:
            error_code = getattr(e, 'error_code', 400)
            fatal = False
            print("Twitter type")
            print(e)

            if error_code == 404:  # handle doesn't exist
                fatal = True
            elif error_code == 403:
                for err in self.FATAL_403S:
                    if six.text_type(e).find(err) >= 0:
                        fatal = True
                        break

            # if message can never be sent, stop them contact
            if fatal:
                contact = Contact.objects.get(id=msg.contact)
                contact.stop(contact.modified_by)

            raise SendException(str(e),
                                events=twitter.events,
                                fatal=fatal,
                                start=start)

        Channel.success(channel,
                        msg,
                        WIRED,
                        start,
                        events=twitter.events,
                        external_id=external_id)
Exemplo n.º 15
0
    def create_contacts(self, orgs, locations, num_total):
        batch_size = 5000
        num_test_contacts = len(orgs) * len(USERS)
        group_membership_model = ContactGroup.contacts.through
        group_counts = defaultdict(int)

        self._log("Creating %d test contacts...\n" % num_test_contacts)

        for org in orgs:
            for user in org.cache['users']:
                Contact.get_test_contact(user)

        self._log("Creating %d regular contacts...\n" % (num_total - num_test_contacts))

        base_contact_id = self.get_current_id(Contact) + 1

        # Disable table triggers to speed up insertion and in the case of contact group m2m, avoid having an unsquashed
        # count row for every contact
        with DisableTriggersOn(Contact, ContactURN, Value, group_membership_model):
            names = [('%s %s' % (c1, c2)).strip() for c2 in CONTACT_NAMES[1] for c1 in CONTACT_NAMES[0]]
            names = [n if n else None for n in names]

            batch = 1
            for index_batch in chunk_list(range(num_total - num_test_contacts), batch_size):
                contacts = []
                urns = []
                values = []
                memberships = []

                def add_to_group(g):
                    group_counts[g] += 1
                    memberships.append(group_membership_model(contact_id=c['id'], contactgroup=g))

                for c_index in index_batch:  # pragma: no cover

                    org = orgs[c_index] if c_index < len(orgs) else self.random_org(orgs)  # at least 1 contact per org
                    name = self.random_choice(names)
                    location = self.random_choice(locations) if self.probability(CONTACT_HAS_FIELD_PROB) else None
                    created_on = self.timeline_date(float(num_test_contacts + c_index) / num_total)

                    c = {
                        'id': base_contact_id + c_index,  # database id this contact will have when created
                        'org': org,
                        'user': org.cache['users'][0],
                        'name': name,
                        'tel': '+2507%08d' % c_index if self.probability(CONTACT_HAS_TEL_PROB) else None,
                        'twitter': '%s%d' % (name.replace(' ', '_').lower() if name else 'tweep', c_index) if self.probability(CONTACT_HAS_TWITTER_PROB) else None,
                        'gender': self.random_choice(('M', 'F')) if self.probability(CONTACT_HAS_FIELD_PROB) else None,
                        'age': self.random.randint(16, 80) if self.probability(CONTACT_HAS_FIELD_PROB) else None,
                        'joined': self.random_date() if self.probability(CONTACT_HAS_FIELD_PROB) else None,
                        'ward': location[0] if location else None,
                        'district': location[1] if location else None,
                        'state': location[2] if location else None,
                        'language': self.random_choice(CONTACT_LANGS),
                        'is_stopped': self.probability(CONTACT_IS_STOPPED_PROB),
                        'is_blocked': self.probability(CONTACT_IS_BLOCKED_PROB),
                        'is_active': self.probability(1 - CONTACT_IS_DELETED_PROB),
                        'created_on': created_on,
                        'modified_on': self.random_date(created_on, self.db_ends_on),
                    }

                    if c['is_active']:
                        if not c['is_blocked'] and not c['is_stopped']:
                            add_to_group(org.cache['system_groups'][ContactGroup.TYPE_ALL])
                        if c['is_blocked']:
                            add_to_group(org.cache['system_groups'][ContactGroup.TYPE_BLOCKED])
                        if c['is_stopped']:
                            add_to_group(org.cache['system_groups'][ContactGroup.TYPE_STOPPED])

                    contacts.append(Contact(org=org, name=c['name'], language=c['language'],
                                            is_stopped=c['is_stopped'], is_blocked=c['is_blocked'],
                                            is_active=c['is_active'],
                                            created_by=user, created_on=c['created_on'],
                                            modified_by=user, modified_on=c['modified_on']))

                    if c['tel']:
                        urns.append(ContactURN(org=org, contact_id=c['id'], priority=50, scheme=TEL_SCHEME,
                                               path=c['tel'], urn=URN.from_tel(c['tel'])))
                    if c['twitter']:
                        urns.append(ContactURN(org=org, contact_id=c['id'], priority=50, scheme=TWITTER_SCHEME,
                                               path=c['twitter'], urn=URN.from_twitter(c['twitter'])))
                    if c['gender']:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['gender'],
                                            string_value=c['gender']))
                    if c['age']:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['age'],
                                            string_value=str(c['age']), decimal_value=c['age']))
                    if c['joined']:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['joined'],
                                            string_value=datetime_to_str(c['joined']), datetime_value=c['joined']))
                    if location:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['ward'],
                                            string_value=c['ward'].name, location_value=c['ward']))
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['district'],
                                            string_value=c['district'].name, location_value=c['district']))
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['state'],
                                            string_value=c['state'].name, location_value=c['state']))

                    # let each group decide if it is taking this contact
                    for g in org.cache['groups']:
                        if g.member(c) if callable(g.member) else self.probability(g.member):
                            add_to_group(g)

                Contact.objects.bulk_create(contacts)
                ContactURN.objects.bulk_create(urns)
                Value.objects.bulk_create(values)
                group_membership_model.objects.bulk_create(memberships)

                self._log(" > Created batch %d of %d\n" % (batch, max(num_total // batch_size, 1)))
                batch += 1

        # create group count records manually
        counts = []
        for group, count in group_counts.items():
            counts.append(ContactGroupCount(group=group, count=count, is_squashed=True))
        ContactGroupCount.objects.bulk_create(counts)

        # for sanity check that our presumed last contact id matches the last actual contact id
        assert c['id'] == Contact.objects.order_by('-id').first().id