Ejemplo n.º 1
0
    def as_elasticsearch(self, org, prop_map):
        prop_type, field = prop_map[self.prop]

        if prop_type == ContactQuery.PROP_FIELD:
            field_uuid = str(field.uuid)
            es_query = es_Q("term", **{"fields.field": field_uuid})

            if field.value_type == Value.TYPE_TEXT:
                query_value = self.value.lower()

                if self.comparator == "=":
                    es_query &= es_Q("term", **{"fields.text": query_value})
                elif self.comparator == "!=":
                    es_query &= es_Q("term", **{"fields.text": query_value})
                    es_query &= es_Q("exists", **{"field": "fields.text"})

                    # search for the inverse of what was specified
                    return ~es_Q("nested", path="fields", query=es_query)

                else:
                    raise SearchException(_(f"Unknown text comparator: '{self.comparator}'"))

            elif field.value_type == Value.TYPE_NUMBER:
                query_value = str(self._parse_number(self.value))

                if self.comparator == "=":
                    es_query &= es_Q("match", **{"fields.number": query_value})
                elif self.comparator == ">":
                    es_query &= es_Q("range", **{"fields.number": {"gt": query_value}})
                elif self.comparator == ">=":
                    es_query &= es_Q("range", **{"fields.number": {"gte": query_value}})
                elif self.comparator == "<":
                    es_query &= es_Q("range", **{"fields.number": {"lt": query_value}})
                elif self.comparator == "<=":
                    es_query &= es_Q("range", **{"fields.number": {"lte": query_value}})
                else:
                    raise SearchException(_(f"Unknown number comparator: '{self.comparator}'"))

            elif field.value_type == Value.TYPE_DATETIME:
                query_value = str_to_date(self.value, field.org.get_dayfirst())

                if not query_value:
                    raise SearchException(_(f"Unable to parse the date '{self.value}'"))

                # datetime contact values are serialized as ISO8601 timestamps in local time on ElasticSearch
                lower_bound, upper_bound = date_to_day_range_utc(query_value, org)

                if self.comparator == "=":
                    es_query &= es_Q(
                        "range", **{"fields.datetime": {"gte": lower_bound.isoformat(), "lt": upper_bound.isoformat()}}
                    )
                elif self.comparator == ">":
                    es_query &= es_Q("range", **{"fields.datetime": {"gte": upper_bound.isoformat()}})
                elif self.comparator == ">=":
                    es_query &= es_Q("range", **{"fields.datetime": {"gte": lower_bound.isoformat()}})
                elif self.comparator == "<":
                    es_query &= es_Q("range", **{"fields.datetime": {"lt": lower_bound.isoformat()}})
                elif self.comparator == "<=":
                    es_query &= es_Q("range", **{"fields.datetime": {"lt": upper_bound.isoformat()}})
                else:
                    raise SearchException(_(f"Unknown datetime comparator: '{self.comparator}'"))

            elif field.value_type in (Value.TYPE_STATE, Value.TYPE_DISTRICT, Value.TYPE_WARD):
                query_value = self.value.lower()

                if field.value_type == Value.TYPE_WARD:
                    field_name = "fields.ward"
                elif field.value_type == Value.TYPE_DISTRICT:
                    field_name = "fields.district"
                elif field.value_type == Value.TYPE_STATE:
                    field_name = "fields.state"
                else:  # pragma: no cover
                    raise SearchException(_(f"Unknown location type: '{field.value_type}'"))

                if self.comparator == "=":
                    field_name += "_keyword"
                    es_query &= es_Q("term", **{field_name: query_value})
                elif self.comparator == "!=":
                    field_name += "_keyword"
                    es_query &= es_Q("term", **{field_name: query_value})
                    es_query &= es_Q("exists", **{"field": field_name})

                    return ~es_Q("nested", path="fields", query=es_query)

                else:
                    raise SearchException(_(f"Unsupported comparator '{self.comparator}' for location field"))

            else:  # pragma: no cover
                raise SearchException(_(f"Unrecognized contact field type '{field.value_type}'"))

            return es_Q("nested", path="fields", query=es_query)

        elif prop_type == ContactQuery.PROP_ATTRIBUTE:
            query_value = self.value.lower()

            field_key = field.key

            if field_key == "name":
                if self.comparator == "=":
                    field_name = "name.keyword"
                    es_query = es_Q("term", **{field_name: query_value})
                elif self.comparator == "~":
                    field_name = "name"
                    es_query = es_Q("match", **{field_name: query_value})
                elif self.comparator == "!=":
                    field_name = "name.keyword"
                    es_query = ~es_Q("term", **{field_name: query_value})
                else:
                    raise SearchException(_(f"Unknown attribute comparator: '{self.comparator}'"))
            elif field_key == "id":
                es_query = es_Q("ids", **{"values": [query_value]})
            elif field_key == "language":
                if self.comparator == "=":
                    field_name = "language"
                    es_query = es_Q("term", **{field_name: query_value})
                elif self.comparator == "!=":
                    field_name = "language"
                    es_query = ~es_Q("term", **{field_name: query_value})
                else:
                    raise SearchException(_(f"Unknown attribute comparator: '{self.comparator}'"))
            elif field_key == "created_on":
                query_value = str_to_date(self.value, field.org.get_dayfirst())

                if not query_value:
                    raise SearchException(_(f"Unable to parse the date '{self.value}'"))

                # contact created_on is serialized as ISO8601 timestamp in utc time on ElasticSearch
                lower_bound, upper_bound = date_to_day_range_utc(query_value, org)

                if self.comparator == "=":
                    es_query = es_Q(
                        "range", **{"created_on": {"gte": lower_bound.isoformat(), "lt": upper_bound.isoformat()}}
                    )
                elif self.comparator == ">":
                    es_query = es_Q("range", **{"created_on": {"gte": upper_bound.isoformat()}})
                elif self.comparator == ">=":
                    es_query = es_Q("range", **{"created_on": {"gte": lower_bound.isoformat()}})
                elif self.comparator == "<":
                    es_query = es_Q("range", **{"created_on": {"lt": lower_bound.isoformat()}})
                elif self.comparator == "<=":
                    es_query = es_Q("range", **{"created_on": {"lt": upper_bound.isoformat()}})
                else:
                    raise SearchException(_(f"Unknown created_on comparator: '{self.comparator}'"))
            else:  # pragma: no cover
                raise SearchException(_(f"Unknown attribute field '{field}'"))
            return es_query

        elif prop_type == ContactQuery.PROP_SCHEME:
            query_value = self.value.lower()
            es_query = es_Q("term", **{"urns.scheme": field.lower()})

            if org.is_anon:
                return es_Q("ids", **{"values": [-1]})
            else:
                if self.comparator == "=":
                    es_query &= es_Q("term", **{"urns.path.keyword": query_value})
                elif self.comparator == "~":
                    es_query &= es_Q("match_phrase", **{"urns.path": query_value})
                else:
                    raise SearchException(_(f"Unknown scheme comparator: '{self.comparator}'"))

                return es_Q("nested", path="urns", query=es_query)
        else:  # pragma: no cover
            raise SearchException(_(f"Unrecognized contact field type '{prop_type}'"))
Ejemplo n.º 2
0
    def evaluate(self, org, contact_json, prop_map):
        prop_type, field = prop_map[self.prop]

        if self.comparator.lower() in self.IS_SET_LOOKUPS:
            is_set = True
        elif self.comparator.lower() in self.IS_NOT_SET_LOOKUPS:
            is_set = False
        else:  # pragma: no cover
            raise SearchException(_("Invalid operator for empty string comparison"))

        if prop_type == ContactQuery.PROP_FIELD:
            field_uuid = str(field.uuid)
            contact_fields = contact_json.get("fields")

            contact_field = contact_fields.get(field_uuid)

            # contact field does not exist
            if contact_field is None:
                if is_set:
                    return False
                else:
                    return True
            else:
                if field.value_type == Value.TYPE_TEXT:
                    contact_value = contact_field.get("text")
                    if is_set:
                        if contact_value is not None:
                            return True
                        else:  # pragma: can't cover
                            return False
                    else:
                        if contact_value is not None:
                            return False
                        else:  # pragma: can't cover
                            return True
                elif field.value_type == Value.TYPE_NUMBER:
                    try:
                        contact_value = self._parse_number(contact_field.get("decimal", contact_field.get("number")))
                    except SearchException:
                        contact_value = None

                    if is_set:
                        if contact_value is not None:
                            return True
                        else:
                            return False
                    else:
                        if contact_value is not None:
                            return False
                        else:
                            return True

                elif field.value_type == Value.TYPE_DATETIME:
                    contact_value = str_to_date(contact_field.get("datetime"), field.org.get_dayfirst())
                    if is_set:
                        if contact_value is not None:
                            return True
                        else:
                            return False
                    else:
                        if contact_value is not None:
                            return False
                        else:
                            return True

                elif field.value_type == Value.TYPE_WARD:
                    contact_value = contact_field.get("ward")
                    if is_set:
                        if contact_value is not None:
                            return True
                        else:
                            return False
                    else:
                        if contact_value is not None:
                            return False
                        else:
                            return True

                elif field.value_type == Value.TYPE_DISTRICT:
                    contact_value = contact_field.get("district")
                    if is_set:
                        if contact_value is not None:
                            return True
                        else:
                            return False
                    else:
                        if contact_value is not None:
                            return False
                        else:
                            return True

                elif field.value_type == Value.TYPE_STATE:
                    contact_value = contact_field.get("state")
                    if is_set:
                        if contact_value is not None:
                            return True
                        else:
                            return False
                    else:
                        if contact_value is not None:
                            return False
                        else:
                            return True

                else:  # pragma: no cover
                    raise SearchException(_(f"Unrecognized contact field type '{field.value_type}'"))

        elif prop_type == ContactQuery.PROP_SCHEME:
            urn_exists = next((urn for urn in contact_json.get("urns") if urn.get("scheme") == field), None)

            if not urn_exists:
                if is_set:
                    return False
                else:
                    return True
            else:
                if is_set:
                    return True
                else:
                    return False
        elif prop_type == ContactQuery.PROP_ATTRIBUTE:
            field_key = field.key

            if field_key == "language":
                contact_value = contact_json.get("language")
                if is_set:
                    if contact_value is not None:
                        return True
                    else:
                        return False
                else:
                    if contact_value is not None:
                        return False
                    else:
                        return True

            elif field_key == "name":
                contact_value = contact_json.get("name")
                if is_set:
                    if contact_value is not None:
                        return True
                    else:
                        return False
                else:
                    if contact_value is not None:
                        return False
                    else:
                        return True

            else:  # pragma: no cover
                raise SearchException(_(f"No support for attribute field: '{field}'"))
        else:  # pragma: no cover
            raise SearchException(_(f"Unrecognized contact field type '{prop_type}'"))
Ejemplo n.º 3
0
    def evaluate(self, org, contact_json, prop_map):
        prop_type, field = prop_map[self.prop]

        if prop_type == ContactQuery.PROP_FIELD:
            field_uuid = str(field.uuid)
            contact_fields = contact_json.get("fields", {})

            if field.value_type == Value.TYPE_TEXT:
                query_value = self.value.upper()
                contact_value = contact_fields.get(field_uuid, {"text": ""}).get("text").upper()

                if self.comparator == "=":
                    return contact_value == query_value
                elif self.comparator == "!=":
                    return contact_value != query_value
                else:
                    raise SearchException(_(f"Unknown text comparator: '{self.comparator}'"))

            elif field.value_type == Value.TYPE_NUMBER:
                query_value = self._parse_number(self.value)

                number_value = contact_fields.get(field_uuid, {"number": None}).get(
                    "number", contact_fields.get(field_uuid, {"decimal": None}).get("decimal")
                )
                if number_value is None:
                    return False

                contact_value = self._parse_number(number_value)

                if self.comparator == "=":
                    return contact_value == query_value
                elif self.comparator == ">":
                    return contact_value > query_value
                elif self.comparator == ">=":
                    return contact_value >= query_value
                elif self.comparator == "<":
                    return contact_value < query_value
                elif self.comparator == "<=":
                    return contact_value <= query_value
                else:
                    raise SearchException(_(f"Unknown number comparator: '{self.comparator}'"))

            elif field.value_type == Value.TYPE_DATETIME:
                query_value = str_to_date(self.value, field.org.get_dayfirst())
                if not query_value:
                    raise SearchException(_(f"Unable to parse the date '{self.value}'"))

                lower_bound, upper_bound = date_to_day_range_utc(query_value, org)

                contact_datetime_value = contact_fields.get(field_uuid, {"datetime": None}).get("datetime")
                if contact_datetime_value is None:
                    return False

                # datetime contact values are serialized as ISO8601 timestamps in local time
                contact_value = str_to_datetime(contact_datetime_value, pytz.UTC, field.org.get_dayfirst())
                contact_value_utc = contact_value.astimezone(pytz.UTC)

                if self.comparator == "=":
                    return contact_value_utc >= lower_bound and contact_value_utc < upper_bound
                elif self.comparator == ">":
                    return contact_value_utc >= upper_bound
                elif self.comparator == ">=":
                    return contact_value_utc >= lower_bound
                elif self.comparator == "<":
                    return contact_value_utc < lower_bound
                elif self.comparator == "<=":
                    return contact_value_utc < upper_bound
                else:
                    raise SearchException(_(f"Unknown datetime comparator: '{self.comparator}'"))

            elif field.value_type in (Value.TYPE_STATE, Value.TYPE_DISTRICT, Value.TYPE_WARD):
                query_value = self.value.upper()

                if field.value_type == Value.TYPE_WARD:
                    ward_value = contact_fields.get(field_uuid, {"ward": ""}).get("ward", "")

                    contact_value = ward_value.upper().split(" > ")[-1]
                elif field.value_type == Value.TYPE_DISTRICT:
                    district_value = contact_fields.get(field_uuid, {"district": ""}).get("district", "")

                    contact_value = district_value.upper().split(" > ")[-1]
                elif field.value_type == Value.TYPE_STATE:
                    state_value = contact_fields.get(field_uuid, {"state": ""}).get("state", "")

                    contact_value = state_value.upper().split(" > ")[-1]
                else:  # pragma: no cover
                    raise SearchException(_(f"Unknown location type: '{field.value_type}'"))

                if self.comparator == "=":
                    return contact_value == query_value
                elif self.comparator == "!=":
                    return contact_value != query_value
                else:
                    raise SearchException(_(f"Unsupported comparator '{self.comparator}' for location field"))

            else:  # pragma: no cover
                raise SearchException(_(f"Unrecognized contact field type '{field.value_type}'"))

        elif prop_type == ContactQuery.PROP_SCHEME:
            for urn in contact_json.get("urns"):
                if urn.get("scheme") == field:
                    contact_value = urn.get("path").upper()
                    query_value = self.value.upper()

                    if self.comparator == "=":
                        if contact_value == query_value:
                            return True
                    elif self.comparator == "~":
                        if query_value in contact_value:
                            return True
                    else:
                        raise SearchException(_(f"Unknown urn scheme comparator: '{self.comparator}'"))

            return False

        elif prop_type == ContactQuery.PROP_ATTRIBUTE:
            field_key = field.key

            if field_key == "language":
                query_value = self.value.upper()
                raw_contact_value = contact_json.get("language")
                if raw_contact_value is None:
                    contact_value = ""
                else:
                    contact_value = raw_contact_value.upper()

                if self.comparator == "=":
                    return contact_value == query_value
                elif self.comparator == "!=":
                    return contact_value != query_value
                else:
                    raise SearchException(_(f"Unknown language comparator: '{self.comparator}'"))

            elif field_key == "created_on":
                query_value = str_to_date(self.value, field.org.get_dayfirst())
                if not query_value:
                    raise SearchException(_(f"Unable to parse the date '{self.value}'"))

                lower_bound, upper_bound = date_to_day_range_utc(query_value, org)

                # contact created_on is serialized as ISO8601 timestamp in utc time
                contact_value = str_to_datetime(contact_json.get("created_on"), pytz.UTC, field.org.get_dayfirst())
                contact_value_utc = contact_value.astimezone(pytz.UTC)

                if self.comparator == "=":
                    return contact_value_utc >= lower_bound and contact_value_utc < upper_bound
                elif self.comparator == ">":
                    return contact_value_utc >= upper_bound
                elif self.comparator == ">=":
                    return contact_value_utc >= lower_bound
                elif self.comparator == "<":
                    return contact_value_utc < lower_bound
                elif self.comparator == "<=":
                    return contact_value_utc < upper_bound
                else:
                    raise SearchException(_(f"Unknown created_on comparator: '{self.comparator}'"))

            elif field_key == "name":
                query_value = self.value.upper()
                raw_contact_value = contact_json.get("name")
                if raw_contact_value is None:
                    contact_value = ""
                else:
                    contact_value = raw_contact_value.upper()

                if self.comparator == "=":
                    return contact_value == query_value
                elif self.comparator == "~":
                    return query_value in contact_value
                elif self.comparator == "!=":
                    return contact_value != query_value
                else:  # pragma: no cover
                    raise SearchException(_(f"Unknown name comparator: '{self.comparator}'"))
            else:
                raise SearchException(_(f"No support for attribute field: '{field}'"))
        else:  # pragma: no cover
            raise SearchException(_(f"Unrecognized contact field type '{prop_type}'"))