Example #1
0
def get_related_case_results(domain, cases, paths):
    """
    Given a set of cases and a set of case property paths,
    fetches ES documents for all cases referenced by those paths.
    """
    if not cases:
        return []

    results_cache = {}
    for path in paths:
        current_cases = cases
        parts = path.split("/")
        for index, identifier in enumerate(parts):
            fragment = "/".join(parts[:index + 1])
            if fragment in results_cache:
                current_cases = results_cache[fragment]
            else:
                indices = [
                    case.get_index(identifier) for case in current_cases
                ]
                related_case_ids = {i.referenced_id for i in indices if i}
                results = CaseSearchES().domain(domain).case_ids(
                    related_case_ids).run().hits
                current_cases = [
                    CommCareCase.wrap(flatten_result(result))
                    for result in results
                ]
                results_cache[fragment] = current_cases
Example #2
0
    def get_rows(self, paged=True):
        location_ids = self._get_voucher_location_ids()
        if location_ids:
            vouchers = []
            for location_id_chunk in chunked(location_ids, ES_MAX_CLAUSE_COUNT):
                vouchers += [
                    CommCareCase.wrap(flatten_result(result))
                    for result in self._search_results(paged, location_id_chunk).raw_hits
                ]
        else:
            vouchers = [
                CommCareCase.wrap(flatten_result(result))
                for result in self._search_results(paged).raw_hits
            ]

        return [row for voucher in vouchers for row in self._make_rows(voucher)]
Example #3
0
def app_aware_search(request, domain, app_id):
    """
    Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d"
    Returns results as a fixture with the same structure as a casedb instance.
    """
    criteria = request.GET.dict()
    try:
        case_type = criteria.pop('case_type')
    except KeyError:
        return HttpResponse('Search request must specify case type', status=400)

    try:
        case_search_criteria = CaseSearchCriteria(domain, case_type, criteria)
    except TooManyRelatedCasesError:
        return HttpResponse(_('Search has too many results. Please try a more specific search.'), status=400)
    search_es = case_search_criteria.search_es

    try:
        hits = search_es.run().raw_hits
    except Exception as e:
        notify_exception(request, str(e), details=dict(
            exception_type=type(e),
        ))
        return HttpResponse(status=500)

    # Even if it's a SQL domain, we just need to render the hits as cases, so CommCareCase.wrap will be fine
    cases = [CommCareCase.wrap(flatten_result(result, include_score=True)) for result in hits]
    if app_id:
        cases.extend(get_related_cases(domain, app_id, case_type, cases))

    fixtures = CaseDBFixture(cases).fixture
    return HttpResponse(fixtures, content_type="text/xml; charset=utf-8")
Example #4
0
def search(request, domain):
    """
    Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d"
    Returns results as a fixture with the same structure as a casedb instance.
    """
    criteria = request.GET.dict()
    try:
        case_type = criteria.pop('case_type')
    except KeyError:
        return HttpResponse('Search request must specify case type',
                            status=400)
    try:
        case_search_criteria = CaseSearchCriteria(domain, case_type, criteria)
        search_es = case_search_criteria.search_es
    except QueryMergeException as e:
        return _handle_query_merge_exception(request, e)
    try:
        hits = search_es.run().raw_hits
    except Exception as e:
        return _handle_es_exception(
            request, e, case_search_criteria.query_addition_debug_details)

    # Even if it's a SQL domain, we just need to render the hits as cases, so CommCareCase.wrap will be fine
    cases = [
        CommCareCase.wrap(flatten_result(result, include_score=True))
        for result in hits
    ]
    fixtures = CaseDBFixture(cases).fixture
    return HttpResponse(fixtures, content_type="text/xml; charset=utf-8")
Example #5
0
def search(request, domain):
    """
    Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d"
    Returns results as a fixture with the same structure as a casedb instance.
    """
    criteria = request.GET.dict()
    try:
        case_type = criteria.pop('case_type')
    except KeyError:
        return HttpResponse('Search request must specify case type',
                            status=400)
    try:
        include_closed = criteria.pop('include_closed')
    except KeyError:
        include_closed = False

    search_es = (CaseSearchES().domain(domain).case_type(case_type).size(
        CASE_SEARCH_MAX_RESULTS))

    if include_closed != 'True':
        search_es = search_es.is_closed(False)

    try:
        config = CaseSearchConfig.objects.get(domain=domain)
    except CaseSearchConfig.DoesNotExist as e:
        from corehq.util.soft_assert import soft_assert
        _soft_assert = soft_assert(to="{}@{}.com".format('frener', 'dimagi'),
                                   notify_admins=False,
                                   send_to_ops=False)
        _soft_assert(
            False,
            u"Someone in domain: {} tried accessing case search without a config"
            .format(domain), e)
        config = CaseSearchConfig(domain=domain)

    query_addition_id = criteria.pop(SEARCH_QUERY_ADDITION_KEY, None)

    fuzzies = config.config.get_fuzzy_properties_for_case_type(case_type)
    for key, value in criteria.items():
        search_es = search_es.case_property_query(key,
                                                  value,
                                                  fuzzy=(key in fuzzies))

    query_addition_debug_details = {}
    try:
        search_es = _add_case_search_addition(request, domain, search_es,
                                              query_addition_id,
                                              query_addition_debug_details)
    except QueryMergeException as e:
        return _handle_query_merge_exception(request, e)
    try:
        results = search_es.values()
    except Exception as e:
        return _handle_es_exception(request, e, query_addition_debug_details)

    # Even if it's a SQL domain, we just need to render the results as cases, so CommCareCase.wrap will be fine
    cases = [CommCareCase.wrap(flatten_result(result)) for result in results]
    fixtures = CaseDBFixture(cases).fixture
    return HttpResponse(fixtures, content_type="text/xml")
Example #6
0
    def test_get_related_case_results(self):
        # Note that cases must be defined before other cases can reference them
        cases = [
            {
                '_id': 'c1',
                'case_type': 'monster',
                'description': 'grandparent of first person'
            },
            {
                '_id': 'c2',
                'case_type': 'monster',
                'description': 'parent of first person',
                'index': {
                    'parent': ('monster', 'c1')
                }
            },
            {
                '_id': 'c3',
                'case_type': 'monster',
                'description': 'parent of host'
            },
            {
                '_id': 'c4',
                'case_type': 'monster',
                'description': 'host of second person',
                'index': {
                    'parent': ('monster', 'c3')
                }
            },
            {
                '_id': 'c5',
                'description': 'first person',
                'index': {
                    'parent': ('monster', 'c2')
                }
            },
            {
                '_id': 'c6',
                'description': 'second person',
                'index': {
                    'host': ('monster', 'c4')
                }
            },
        ]
        self._bootstrap_cases_in_es_for_domain(self.domain, cases)

        hits = CaseSearchES().domain(self.domain).case_type(
            self.case_type).run().hits
        cases = [CommCareCase.wrap(flatten_result(result)) for result in hits]
        self.assertEqual({case.case_id for case in cases}, {'c5', 'c6'})

        self._assert_related_case_ids(cases, set(), set())
        self._assert_related_case_ids(cases, {"parent"}, {"c2"})
        self._assert_related_case_ids(cases, {"host"}, {"c4"})
        self._assert_related_case_ids(cases, {"parent/parent"}, {"c1"})
        self._assert_related_case_ids(cases, {"host/parent"}, {"c3"})
        self._assert_related_case_ids(cases, {"host", "parent"}, {"c2", "c4"})
        self._assert_related_case_ids(cases, {"host", "parent/parent"},
                                      {"c4", "c1"})
Example #7
0
def _get_assigned_cases(checkin_case):
    query = (CaseSearchES().domain(checkin_case.domain).filter(
        filters.OR(case_type("patient"),
                   case_type("contact"))).case_property_query(
                       "assigned_to_primary_checkin_case_id",
                       checkin_case.case_id))

    return [CommCareCase.wrap(flatten_result(hit)) for hit in query.run().hits]
Example #8
0
 def get_rows(self, paged=True):
     vouchers = [
         CommCareCase.wrap(flatten_result(result))
         for result in self._search_results(paged).raw_hits
     ]
     return [
         row for voucher in vouchers for row in self._make_rows(voucher)
     ]
 def rows(self):
     track_workflow(self.request.couch_user.username,
                    "Case List Explorer: Search Performed")
     send_email_to_dev_more(
         self.domain, self.request.couch_user.username,
         XpathCaseSearchFilter.get_value(self.request, self.domain),
         self.es_results['hits'].get('total', 0))
     data = (flatten_result(row)
             for row in self.es_results['hits'].get('hits', []))
     return self._get_rows(data)
Example #10
0
 def rows(self):
     track_workflow(self.request.couch_user.username, "Case List Explorer: Search Performed")
     send_email_to_dev_more(
         self.domain,
         self.request.couch_user.username,
         XpathCaseSearchFilter.get_value(self.request, self.domain),
         self.es_results['hits'].get('total', 0)
     )
     data = (flatten_result(row) for row in self.es_results['hits'].get('hits', []))
     return self._get_rows(data)
Example #11
0
def get_usercase_from_checkin(checkin_case):
    username = checkin_case.get_case_property("username")
    query = (CaseSearchES().domain(
        checkin_case.domain).case_type(USERCASE_TYPE).case_property_query(
            "username", username))

    results = query.run().hits
    if not results:
        return None

    return CommCareCase.wrap(flatten_result(results[0]))
 def test_flatten_result(self):
     expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz'}
     self.assertEqual(
         flatten_result(
             {
                 'name': 'blah',
                 'case_properties': [
                     {'key': 'foo', 'value': 'bar'},
                     {'key': 'baz', 'value': 'buzz'}]
             }
         ),
         expected
     )
Example #13
0
 def test_flatten_result(self):
     expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz'}
     self.assertEqual(
         flatten_result({
             'name':
             'blah',
             'case_properties': [{
                 'key': 'foo',
                 'value': 'bar'
             }, {
                 'key': 'baz',
                 'value': 'buzz'
             }]
         }), expected)
Example #14
0
def _get_assigned_cases(checkin_case):
    """
    An assigned case is a case for which all of the following are true
    Case type patient or contact
    Exists in the same domain as the user case
    The case property assigned_to_primary_checkin_case_id equals an associated checkin case's case_id
    """

    query = (CaseSearchES().domain(checkin_case.domain).filter(
        filters.OR(case_type("patient"),
                   case_type("contact"))).case_property_query(
                       "assigned_to_primary_checkin_case_id",
                       checkin_case.case_id))

    return [CommCareCase.wrap(flatten_result(hit)) for hit in query.run().hits]
Example #15
0
 def test_flatten_result(self):
     expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz', RELEVANCE_SCORE: "1.095"}
     self.assertEqual(
         flatten_result(
             {
                 "_score": "1.095",
                 "_source": {
                     'name': 'blah',
                     'case_properties': [
                         {'key': '@case_id', 'value': '123'},
                         {'key': 'foo', 'value': 'bar'},
                         {'key': 'baz', 'value': 'buzz'}]
                 }
             }
         ),
         expected
     )
Example #16
0
def search(request, domain):
    """
    Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d"
    Returns results as a fixture with the same structure as a casedb instance.
    """
    criteria = request.GET.dict()
    try:
        case_type = criteria.pop('case_type')
    except KeyError:
        return HttpResponse('Search request must specify case type', status=400)
    try:
        include_closed = criteria.pop('include_closed')
    except KeyError:
        include_closed = False

    search_es = (CaseSearchES()
                 .domain(domain)
                 .case_type(case_type)
                 .size(CASE_SEARCH_MAX_RESULTS))

    if include_closed != 'True':
        search_es = search_es.is_closed(False)

    try:
        config = CaseSearchConfig.objects.get(domain=domain)
    except CaseSearchConfig.DoesNotExist as e:
        from corehq.util.soft_assert import soft_assert
        _soft_assert = soft_assert(
            to="{}@{}.com".format('frener', 'dimagi'),
            notify_admins=False, send_to_ops=False
        )
        _soft_assert(False, "Someone in domain: {} tried accessing case search without a config".format(domain), e)
        config = CaseSearchConfig(domain=domain)

    fuzzies = config.config.get_fuzzy_properties_for_case_type(case_type)
    for key, value in criteria.items():
        search_es = search_es.case_property_query(key, value, fuzzy=(key in fuzzies))
    results = search_es.values()
    # Even if it's a SQL domain, we just need to render the results as cases, so CommCareCase.wrap will be fine
    cases = [CommCareCase.wrap(flatten_result(result)) for result in results]
    fixtures = CaseDBFixture(cases).fixture
    return HttpResponse(fixtures, content_type="text/xml")
Example #17
0
 def test_flatten_result(self):
     expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz', RELEVANCE_SCORE: "1.095"}
     self.assertEqual(
         flatten_result(
             {
                 "_score": "1.095",
                 "_source": {
                     'name': 'blah',
                     'case_properties': [
                         {'key': '@case_id', 'value': 'should be removed'},
                         {'key': 'name', 'value': 'should be removed'},
                         {'key': 'case_name', 'value': 'should be removed'},
                         {'key': 'last_modified', 'value': 'should be removed'},
                         {'key': 'foo', 'value': 'bar'},
                         {'key': 'baz', 'value': 'buzz'}]
                 }
             },
             include_score=True
         ),
         expected
     )
Example #18
0
 def test_flatten_result(self):
     expected = {'name': 'blah', 'foo': 'bar', 'baz': 'buzz', RELEVANCE_SCORE: "1.095"}
     self.assertEqual(
         flatten_result(
             {
                 "_score": "1.095",
                 "_source": {
                     'name': 'blah',
                     'case_properties': [
                         {'key': '@case_id', 'value': 'should be removed'},
                         {'key': 'name', 'value': 'should be removed'},
                         {'key': 'case_name', 'value': 'should be removed'},
                         {'key': 'last_modified', 'value': 'should be removed'},
                         {'key': 'foo', 'value': 'bar'},
                         {'key': 'baz', 'value': 'buzz'}]
                 }
             },
             include_score=True
         ),
         expected
     )
Example #19
0
def search(request, domain):
    """
    Accepts search criteria as GET params, e.g. "https://www.commcarehq.org/a/domain/phone/search/?a=b&c=d"
    Returns results as a fixture with the same structure as a casedb instance.
    """
    criteria = request.GET.dict()
    try:
        case_type = criteria.pop('case_type')
    except KeyError:
        return HttpResponse('Search request must specify case type', status=400)
    try:
        case_search_criteria = CaseSearchCriteria(domain, case_type, criteria)
        search_es = case_search_criteria.search_es
    except QueryMergeException as e:
        return _handle_query_merge_exception(request, e)
    try:
        hits = search_es.run().raw_hits
    except Exception as e:
        return _handle_es_exception(request, e, case_search_criteria.query_addition_debug_details)

    # Even if it's a SQL domain, we just need to render the hits as cases, so CommCareCase.wrap will be fine
    cases = [CommCareCase.wrap(flatten_result(result, include_score=True)) for result in hits]
    fixtures = CaseDBFixture(cases).fixture
    return HttpResponse(fixtures, content_type="text/xml; charset=utf-8")
Example #20
0
 def get_data(self):
     for row in self.es_results['hits'].get('hits', []):
         yield flatten_result(row)
Example #21
0
 def __init__(self, request, domain, raw_data):
     super(CaseDataFormatter, self).__init__(request, domain, raw_data)
     self.raw_data = flatten_result(raw_data)
Example #22
0
 def get_all_rows(self):
     data = (flatten_result(r)
             for r in iter_es_docs_from_query(self._build_query(
                 sort=False)))
     return self._get_rows(data)
Example #23
0
 def rows(self):
     track_workflow(self.request.couch_user.username,
                    "Case List Explorer: Search Performed")
     data = (flatten_result(row)
             for row in self.es_results['hits'].get('hits', []))
     return self._get_rows(data)
Example #24
0
 def rows(self):
     track_workflow(self.request.couch_user.username, "Case List Explorer: Search Performed")
     data = (flatten_result(row) for row in self.es_results['hits'].get('hits', []))
     return self._get_rows(data)
Example #25
0
 def get_all_rows(self):
     data = (flatten_result(r) for r in iter_es_docs_from_query(self._build_query(sort=False)))
     return self._get_rows(data)
Example #26
0
 def __init__(self, request, domain, raw_data):
     super(CaseDataFormatter, self).__init__(request, domain, raw_data)
     self.raw_data = flatten_result(raw_data)