コード例 #1
0
ファイル: views_base.py プロジェクト: elbic/rapidpro-docker
    def normalize_urn(self, value):
        if self.request.user.get_org().is_anon:
            raise InvalidQueryError("URN lookups not allowed for anonymous organizations")

        try:
            return URN.identity(URN.normalize(value))
        except ValueError:
            raise InvalidQueryError("Invalid URN: %s" % value)
コード例 #2
0
ファイル: fields.py プロジェクト: Ilhasoft/rapidpro
    def get_object(self, value):
        # try to normalize as URN but don't blow up if it's a UUID
        try:
            as_urn = URN.normalize(value)
        except ValueError:
            as_urn = value

        return self.get_queryset().filter(Q(uuid=value) | Q(urns__urn=as_urn)).first()
コード例 #3
0
ファイル: fields.py プロジェクト: sHalnes/rapidpro
    def get_object(self, value):
        # try to normalize as URN but don't blow up if it's a UUID
        try:
            as_urn = URN.identity(URN.normalize(value))
        except ValueError:
            as_urn = value

        return self.get_queryset().filter(Q(uuid=value) | Q(urns__identity=as_urn)).first()
コード例 #4
0
ファイル: fields.py プロジェクト: Ilhasoft/rapidpro
def validate_urn(value, strict=True):
    try:
        normalized = URN.normalize(value)

        if strict and not URN.validate(normalized):
            raise ValueError()
    except ValueError:
        raise serializers.ValidationError("Invalid URN: %s. Ensure phone numbers contain country codes." % value)
    return normalized
コード例 #5
0
ファイル: fields.py プロジェクト: eHealthAfrica/rapidpro
    def to_internal_value(self, data):
        try:
            normalized = URN.normalize(data)
            if not URN.validate(normalized):
                raise ValueError()
        except ValueError:
            raise serializers.ValidationError("Invalid URN: %s. Ensure phone numbers contain country codes." % data)

        return normalized
コード例 #6
0
ファイル: fields.py プロジェクト: sHalnes/rapidpro
def validate_urn(value, strict=True):
    try:
        normalized = URN.normalize(value)

        if strict and not URN.validate(normalized):
            raise ValueError()
    except ValueError:
        raise serializers.ValidationError("Invalid URN: %s. Ensure phone numbers contain country codes." % value)
    return normalized
コード例 #7
0
    def to_internal_value(self, data):
        try:
            country_code = self.context['org'].get_country_code()
            normalized = URN.normalize(data, country_code=country_code)
            if not URN.validate(normalized):
                raise ValueError()
        except ValueError:
            raise serializers.ValidationError("Invalid URN: %s" % data)

        return normalized
コード例 #8
0
ファイル: fields.py プロジェクト: teehamaral/rapidpro
    def get_object(self, value):
        # try to normalize as URN but don't blow up if it's a UUID
        try:
            as_urn = URN.identity(URN.normalize(value))
        except ValueError:
            as_urn = value

        contact_ids_with_urn = list(ContactURN.objects.filter(identity=as_urn).values_list("contact_id", flat=True))

        return self.get_queryset().filter(Q(uuid=value) | Q(id__in=contact_ids_with_urn)).first()
コード例 #9
0
    def get_object(self, value):
        # try to normalize as URN but don't blow up if it's a UUID
        try:
            as_urn = URN.identity(URN.normalize(value))
        except ValueError:
            as_urn = value

        contact_ids_with_urn = list(ContactURN.objects.filter(identity=as_urn).values_list('contact_id', flat=True))

        return self.get_queryset().filter(Q(uuid=value) | Q(id__in=contact_ids_with_urn)).first()
コード例 #10
0
ファイル: fields.py プロジェクト: weddingjuma/rapidpro-1
    def to_internal_value(self, data):
        try:
            normalized = URN.normalize(data)
            if not URN.validate(normalized):
                raise ValueError()
        except ValueError:
            raise serializers.ValidationError(
                "Invalid URN: %s. Ensure phone numbers contain country codes."
                % data)

        return normalized
コード例 #11
0
ファイル: serializers.py プロジェクト: cybort/rapidpro
    def validate(self, data):
        if data.get('urns') is not None and data.get('phone') is not None:
            raise serializers.ValidationError(
                "Cannot provide both urns and phone parameters together")

        if data.get('group_uuids') is not None and data.get(
                'groups') is not None:
            raise serializers.ValidationError(
                "Parameter groups is deprecated and can't be used together with group_uuids"
            )

        if self.org.is_anon and self.instance and self.parsed_urns is not None:
            raise serializers.ValidationError(
                "Cannot update contact URNs on anonymous organizations")

        if self.parsed_urns is not None:
            # look up these URNs, keeping track of the contacts that are connected to them
            urn_contacts = set()
            country = self.org.get_country_code()

            for parsed_urn in self.parsed_urns:
                normalized_urn = URN.identity(
                    URN.normalize(parsed_urn, country))
                urn = ContactURN.objects.filter(
                    org=self.org, identity__exact=normalized_urn).first()
                if urn and urn.contact:
                    urn_contacts.add(urn.contact)

            if len(urn_contacts) > 1:
                raise serializers.ValidationError(
                    _("URNs are used by multiple contacts"))

            contact_by_urns = urn_contacts.pop(
            ) if len(urn_contacts) > 0 else None

            if self.instance and contact_by_urns and contact_by_urns != self.instance:  # pragma: no cover
                raise serializers.ValidationError(
                    _("URNs are used by other contacts"))
        else:
            contact_by_urns = None

        contact = self.instance or contact_by_urns

        # if contact is blocked, they can't be added to groups
        if contact and contact.is_blocked and self.group_objs:
            raise serializers.ValidationError(
                "Cannot add blocked contact to groups")

        return data
コード例 #12
0
    def validate_urns(self, value):
        if value is not None:
            self.parsed_urns = []
            for urn in value:
                try:
                    normalized = URN.normalize(urn)
                    scheme, path, display = URN.to_parts(normalized)
                    # for backwards compatibility we don't validate phone numbers here
                    if scheme != TEL_SCHEME and not URN.validate(normalized):  # pragma: needs cover
                        raise ValueError()
                except ValueError:
                    raise serializers.ValidationError("Invalid URN: '%s'" % urn)

                self.parsed_urns.append(normalized)

        return value
コード例 #13
0
ファイル: serializers.py プロジェクト: teehamaral/rapidpro
    def validate_urns(self, value):
        if value is not None:
            self.parsed_urns = []
            for urn in value:
                try:
                    normalized = URN.normalize(urn)
                    scheme, path, query, display = URN.to_parts(normalized)
                    # for backwards compatibility we don't validate phone numbers here
                    if scheme != TEL_SCHEME and not URN.validate(normalized):  # pragma: needs cover
                        raise ValueError()
                except ValueError:
                    raise serializers.ValidationError("Invalid URN: '%s'" % urn)

                self.parsed_urns.append(normalized)

        return value
コード例 #14
0
ファイル: serializers.py プロジェクト: teehamaral/rapidpro
    def validate_urn(self, value):
        urns = []
        if value:
            # if we have tel URNs, we may need a country to normalize by
            country = self.org.get_country_code()

            for urn in value:
                try:
                    normalized = URN.normalize(urn, country)
                except ValueError as e:  # pragma: needs cover
                    raise serializers.ValidationError(str(e))

                if not URN.validate(normalized, country):  # pragma: needs cover
                    raise serializers.ValidationError("Invalid URN: '%s'" % urn)
                urns.append(normalized)

        return urns
コード例 #15
0
    def validate_urn(self, value):
        urns = []
        if value:
            # if we have tel URNs, we may need a country to normalize by
            country = self.org.get_country_code()

            for urn in value:
                try:
                    normalized = URN.normalize(urn, country)
                except ValueError as e:  # pragma: needs cover
                    raise serializers.ValidationError(six.text_type(e))

                if not URN.validate(normalized, country):  # pragma: needs cover
                    raise serializers.ValidationError("Invalid URN: '%s'" % urn)
                urns.append(normalized)

        return urns
コード例 #16
0
def update_urns_locally(contact, urns: list[str]):
    country = contact.org.default_country_code
    priority = ContactURN.PRIORITY_HIGHEST

    urns_created = []  # new URNs created
    urns_attached = []  # existing orphan URNs attached
    urns_retained = []  # existing URNs retained

    for urn_as_string in urns:
        normalized = URN.normalize(urn_as_string, country)
        urn = ContactURN.lookup(contact.org, normalized)

        if not urn:
            urn = ContactURN.create(contact.org,
                                    contact,
                                    normalized,
                                    priority=priority)
            urns_created.append(urn)

        # unassigned URN or different contact
        elif not urn.contact or urn.contact != contact:
            urn.contact = contact
            urn.priority = priority
            urn.save()
            urns_attached.append(urn)

        else:
            if urn.priority != priority:
                urn.priority = priority
                urn.save()
            urns_retained.append(urn)

        # step down our priority
        priority -= 1

    # detach any existing URNs that weren't included
    urn_ids = [u.pk for u in (urns_created + urns_attached + urns_retained)]
    urns_detached = ContactURN.objects.filter(contact=contact).exclude(
        id__in=urn_ids)
    urns_detached.update(contact=None)
コード例 #17
0
ファイル: serializers.py プロジェクト: teehamaral/rapidpro
    def validate(self, data):
        if data.get("urns") is not None and data.get("phone") is not None:
            raise serializers.ValidationError("Cannot provide both urns and phone parameters together")

        if data.get("group_uuids") is not None and data.get("groups") is not None:
            raise serializers.ValidationError(
                "Parameter groups is deprecated and can't be used together with group_uuids"
            )

        if self.org.is_anon and self.instance and self.parsed_urns is not None:
            raise serializers.ValidationError("Cannot update contact URNs on anonymous organizations")

        if self.parsed_urns is not None:
            # look up these URNs, keeping track of the contacts that are connected to them
            urn_contacts = set()
            country = self.org.get_country_code()

            for parsed_urn in self.parsed_urns:
                normalized_urn = URN.identity(URN.normalize(parsed_urn, country))
                urn = ContactURN.objects.filter(org=self.org, identity__exact=normalized_urn).first()
                if urn and urn.contact:
                    urn_contacts.add(urn.contact)

            if len(urn_contacts) > 1:
                raise serializers.ValidationError(_("URNs are used by multiple contacts"))

            contact_by_urns = urn_contacts.pop() if len(urn_contacts) > 0 else None

            if self.instance and contact_by_urns and contact_by_urns != self.instance:  # pragma: no cover
                raise serializers.ValidationError(_("URNs are used by other contacts"))
        else:
            contact_by_urns = None

        contact = self.instance or contact_by_urns

        # if contact is blocked, they can't be added to groups
        if contact and contact.is_blocked and self.group_objs:
            raise serializers.ValidationError("Cannot add blocked contact to groups")

        return data
コード例 #18
0
    def contact_resolve(self, org_id: int, channel_id: int, urn: str):
        org = Org.objects.get(id=org_id)
        user = get_anonymous_user()

        try:
            urn = URN.normalize(urn, org.default_country_code)
            if not URN.validate(urn, org.default_country_code):
                raise ValueError()
        except ValueError:
            raise MailroomException("contact/resolve", None,
                                    {"error": "invalid URN"})

        contact_urn = ContactURN.lookup(org, urn)
        if contact_urn:
            contact = contact_urn.contact
        else:
            contact = create_contact_locally(org,
                                             user,
                                             name="",
                                             language="",
                                             urns=[urn],
                                             fields={},
                                             group_uuids=[])
            contact_urn = ContactURN.lookup(org, urn)

        return {
            "contact": {
                "id": contact.id,
                "uuid": str(contact.uuid),
                "name": contact.name
            },
            "urn": {
                "id": contact_urn.id,
                "identity": contact_urn.identity
            },
        }
コード例 #19
0
ファイル: serializers.py プロジェクト: ewheeler/rapidpro
    def to_internal_value(self, data):
        if not URN.validate(data):
            raise ValidationError("Invalid URN: %s" % data)

        return URN.normalize(data)
コード例 #20
0
ファイル: tasks.py プロジェクト: UNICEFIndia/RapidPro
def resolve_twitter_ids():
    r = get_redis_connection()
    # TODO: we can't use our non-overlapping task decorator as it creates a loop in the celery resolver when registering
    if r.get("resolve_twitter_ids_task"):  # pragma: no cover
        return

    with r.lock("resolve_twitter_ids_task", 1800):
        # look up all 'twitter' URNs, limiting to 30k since that's the most our API would allow anyways
        twitter_urns = ContactURN.objects.filter(
            scheme=TWITTER_SCHEME, contact__is_stopped=False, contact__is_blocked=False
        ).exclude(contact=None)
        twitter_urns = twitter_urns[:30000].only("id", "org", "contact", "path")
        api_key = settings.TWITTER_API_KEY
        api_secret = settings.TWITTER_API_SECRET
        client = Twython(api_key, api_secret)

        updated = 0
        print("found %d twitter urns to resolve" % len(twitter_urns))

        # contacts we will stop
        stop_contacts = []

        # we try to look these up 100 at a time
        for urn_batch in chunk_list(twitter_urns, 100):
            screen_names = [u.path for u in urn_batch]
            screen_map = {u.path: u for u in urn_batch}

            # try to fetch our users by screen name
            try:
                resp = client.lookup_user(screen_name=",".join(screen_names))

                for twitter_user in resp:
                    screen_name = twitter_user["screen_name"].lower()
                    twitter_id = twitter_user["id"]

                    if screen_name in screen_map and twitter_user["id"]:
                        twitterid_urn = URN.normalize(URN.from_twitterid(twitter_id, screen_name))
                        old_urn = screen_map[screen_name]

                        # create our new contact URN
                        new_urn = ContactURN.get_or_create(old_urn.org, old_urn.contact, twitterid_urn)

                        # if our new URN already existed for another contact and it is newer
                        # than our old contact, reassign it to the old contact
                        if (
                            new_urn.contact != old_urn.contact
                            and new_urn.contact.created_on > old_urn.contact.created_on
                        ):
                            new_urn.contact = old_urn.contact
                            new_urn.save(update_fields=["contact"])

                        # get rid of our old URN
                        ContactURN.objects.filter(id=old_urn.id).update(contact=None)
                        del screen_map[screen_name]
                        updated += 1

            except Exception as e:
                # if this wasn't an exception caused by not finding any of the users, then break
                if str(e).find("No user matches") < 0:
                    # exit, we'll try again later
                    print("exiting resolve_twitter_ids due to exception: %s" % e)
                    break

            # add all remaining contacts to the contacts we will stop
            for contact in screen_map.values():
                stop_contacts.append(contact)

        # stop all the contacts we couldn't resolve that have only a twitter URN
        stopped = 0
        for contact_urn in stop_contacts:
            contact = contact_urn.contact
            if len(contact.urns.all()) == 1:
                contact.stop(contact.created_by)
                stopped += 1

        if len(twitter_urns) > 0:
            print("updated %d twitter urns, %d stopped" % (updated, len(stop_contacts)))
コード例 #21
0
ファイル: serializers.py プロジェクト: writefaruq/rapidpro
    def to_internal_value(self, data):
        if not URN.validate(data):
            raise ValidationError("Invalid URN: %s" % data)

        return URN.normalize(data)