def test_missing_column_id(self):
     config = ReportConfiguration(
         domain='somedomain',
         config_id='someconfig',
         aggregation_columns=['doc_id'],
         columns=[{
             'type': 'percent',
             #  'column_id': 'pct',
             'numerator': {
                 "aggregation": "sum",
                 "field": "pct_numerator",
                 "type": "field",
                 "column_id": "pct_numerator",
             },
             'denominator': {
                 "aggregation": "sum",
                 "field": "pct_denominator",
                 "type": "field",
             },
         }],
         filters=[],
         configured_charts=[]
     )
     with self.assertRaises(BadSpecError):
         config.validate()
Example #2
0
    def create_report(self):
        """
        Creates data source and report config.
        """
        matching_data_source = self.ds_builder.get_existing_match()
        if matching_data_source:
            data_source_config_id = matching_data_source['id']
        else:
            data_source_config_id = self._build_data_source()

        report = ReportConfiguration(
            domain=self.domain,
            config_id=data_source_config_id,
            title=self.report_name,
            aggregation_columns=self._report_aggregation_cols,
            columns=self._report_columns,
            filters=self._report_filters,
            configured_charts=self._report_charts,
            report_meta=ReportMeta(
                created_by_builder=True,
                builder_report_type=self.report_type
            )
        )
        report.validate()
        report.save()
        return report
Example #3
0
    def test_expand_column_infos(self):

        aggregated_report = ReportConfiguration(
            domain=self.domain.name,
            config_id=self.data_source._id,
            aggregation_columns=["opened_by"],
            columns=[
                {
                    "column_id": self.field_name,
                    "type": "field",
                    "field": self.field_name,
                    "aggregation": "expand",
                }
            ],
            filters=[],
        )
        aggregated_report.save()

        response = self.client.get(
            self.single_endpoint(aggregated_report._id))
        response_dict = json.loads(response.content)
        columns = response_dict["columns"]

        for c in columns:
            self.assertIn("expand_column_value", c)
        self.assertSetEqual(set(self.case_property_values), {c['expand_column_value'] for c in columns})
Example #4
0
    def test_report_data_source(self):
        # bootstrap report data sources against indicator data sources
        report_config_template = get_sample_report_config()
        report_config_1 = ReportConfiguration.wrap(report_config_template.to_json())
        report_config_1.config_id = self.ds_1._id
        report_config_2 = ReportConfiguration.wrap(report_config_template.to_json())
        report_config_2.config_id = self.ds_2._id

        # save a few docs to ds 1
        sample_doc, _ = get_sample_doc_and_indicators()
        num_docs = 3
        for i in range(num_docs):
            sample_doc['_id'] = uuid.uuid4().hex
            self.ds1_adapter.save(sample_doc)

        # ds 1 should have data, ds2 should not
        ds1_rows = ReportFactory.from_spec(report_config_1).get_data()
        self.assertEqual(1, len(ds1_rows))
        self.assertEqual(num_docs, ds1_rows[0]['count'])
        ds2_rows = ReportFactory.from_spec(report_config_2).get_data()
        self.assertEqual(0, len(ds2_rows))

        # save one doc to ds 2
        sample_doc['_id'] = uuid.uuid4().hex
        self.ds2_adapter.save(sample_doc)

        # ds 1 should still have same data, ds2 should now have one row
        ds1_rows = ReportFactory.from_spec(report_config_1).get_data()
        self.assertEqual(1, len(ds1_rows))
        self.assertEqual(num_docs, ds1_rows[0]['count'])
        ds2_rows = ReportFactory.from_spec(report_config_2).get_data()
        self.assertEqual(1, len(ds2_rows))
        self.assertEqual(1, ds2_rows[0]['count'])
    def test_get_by_domain(self):
        results = ReportConfiguration.by_domain("foo")
        self.assertEqual(2, len(results))
        for item in results:
            self.assertTrue(item.config_id in ("foo1", "foo2"))

        results = ReportConfiguration.by_domain("not-foo")
        self.assertEqual(0, len(results))
    def testGetByDomain(self):
        results = ReportConfiguration.by_domain('foo')
        self.assertEqual(2, len(results))
        for item in results:
            self.assertTrue(item.config_id in ('foo1', 'foo2'))

        results = ReportConfiguration.by_domain('not-foo')
        self.assertEqual(0, len(results))
Example #7
0
def get_all_report_configs():
    from corehq.apps.userreports.models import ReportConfiguration
    ids = [res['id'] for res in ReportConfiguration.view(
        'userreports/report_configs_by_domain',
        reduce=False,
        include_docs=False,
    )]
    for result in iter_docs(ReportConfiguration.get_db(), ids):
        yield ReportConfiguration.wrap(result)
 def _create_report(self, aggregation_columns, columns):
     report_config = ReportConfiguration(
         domain=self.domain,
         config_id=self.data_source_config._id,
         title="foo",
         aggregation_columns=aggregation_columns,
         columns=columns,
     )
     report_config.save()
     return report_config
Example #9
0
    def _build_report(self, vals, field="my_field", build_data_source=True):
        """
        Build a new report, and populate it with cases.

        Return a ConfigurableReportDataSource and a FieldColumn
        :param vals: List of values to populate the given report field with.
        :param field: The name of a field in the data source/report
        :return: Tuple containing a ConfigurableReportDataSource and FieldColumn.
        The column is a column mapped to the given field.
        """

        # Create Cases
        for v in vals:
            self._new_case({field: v}).save()

        # Create report
        data_source_config = DataSourceConfiguration(
            domain=self.domain,
            display_name="foo",
            referenced_doc_type="CommCareCase",
            table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)),
            configured_filter={
                "type": "boolean_expression",
                "operator": "eq",
                "expression": {"type": "property_name", "property_name": "type"},
                "property_value": self.case_type,
            },
            configured_indicators=[
                {
                    "type": "expression",
                    "expression": {"type": "property_name", "property_name": field},
                    "column_id": field,
                    "display_name": field,
                    "datatype": "string",
                }
            ],
        )
        data_source_config.validate()
        data_source_config.save()
        if build_data_source:
            tasks.rebuild_indicators(data_source_config._id)

        report_config = ReportConfiguration(
            domain=self.domain,
            config_id=data_source_config._id,
            title="foo",
            aggregation_columns=["doc_id"],
            columns=[{"type": "expanded", "field": field, "display": field, "format": "default"}],
            filters=[],
            configured_charts=[],
        )
        report_config.save()
        data_source = ReportFactory.from_spec(report_config)

        return data_source, data_source.column_configs[0]
Example #10
0
 def _create_report(self, aggregation_columns, columns):
     backend_id = settings.OVERRIDE_UCR_BACKEND or UCR_SQL_BACKEND
     report_config = ReportConfiguration(
         domain=self.domain,
         config_id=self.data_sources[backend_id]._id,
         title='foo',
         aggregation_columns=aggregation_columns,
         columns=columns,
     )
     report_config.save()
     return report_config
 def _create_report(self, aggregation_columns, columns, filters=None):
     report_config = ReportConfiguration(
         domain=self.domain,
         config_id=self.data_source._id,
         title='foo',
         aggregation_columns=aggregation_columns,
         columns=columns,
         filters=filters or [],
     )
     report_config.save()
     return report_config
 def _create_report(self, aggregation_columns, columns, sort_expression=None):
     report_config = ReportConfiguration(
         domain=self.domain,
         config_id=self.data_source._id,
         title='foo',
         aggregation_columns=aggregation_columns,
         columns=columns,
     )
     if sort_expression:
         report_config.sort_expression = sort_expression
     report_config.save()
     return report_config
Example #13
0
 def setUpClass(cls):
     cls.data_source_id = 'd36c7c934cb84725899cca9a0ef96e3a'
     cls.domain = 'userreport-dbaccessors'
     cls.report_configs = [
         ReportConfiguration(domain=cls.domain,
                             config_id=cls.data_source_id, title='A'),
         ReportConfiguration(domain=cls.domain,
                             config_id=cls.data_source_id, title='B'),
         ReportConfiguration(domain=cls.domain,
                             config_id='asabsdjf', title='C'),
         ReportConfiguration(domain='mallory',
                             config_id=cls.data_source_id, title='X'),
     ]
     ReportConfiguration.get_db().bulk_save(cls.report_configs)
Example #14
0
def _shared_context(domain):
    custom_data_sources = list(CustomDataSourceConfiguration.by_domain(domain))
    return {
        'domain': domain,
        'reports': ReportConfiguration.by_domain(domain),
        'data_sources': DataSourceConfiguration.by_domain(domain) + custom_data_sources,
    }
Example #15
0
def _get_report_module_context(app, module):
    def _report_to_config(report):
        return {
            'report_id': report._id,
            'title': report.title,
            'description': report.description,
            'charts': [chart for chart in report.charts if
                       chart.type == 'multibar'],
            'filter_structure': report.filters,
        }

    all_reports = ReportConfiguration.by_domain(app.domain)
    warnings = []
    validity = module.check_report_validity()

    if not validity.is_valid:
        module.report_configs = validity.valid_report_configs
        warnings.append(
            gettext_lazy(
                'Your app contains references to reports that are deleted. These will be removed on save.')
        )
    return {
        'all_reports': [_report_to_config(r) for r in all_reports],
        'current_reports': [r.to_json() for r in module.report_configs],
        'warnings': warnings,
    }
Example #16
0
def _get_configurable_reports(project):
    """
    User configurable reports
    """
    configs = ReportConfiguration.by_domain(project.name)
    if configs:
        def _make_report_class(config):
            from corehq.apps.reports.generic import GenericReportView

            # this is really annoying.
            # the report metadata should really be pulled outside of the report classes
            @classmethod
            def get_url(cls, domain, **kwargs):
                return reverse(ConfigurableReport.slug, args=[domain, config._id])

            @classmethod
            def show_in_navigation(cls, domain=None, project=None, user=None):
                return config.visible or (user and toggles.USER_CONFIGURABLE_REPORTS.enabled(user.username))

            return type('DynamicReport{}'.format(config._id), (GenericReportView, ), {
                'name': config.title,
                'description': config.description or None,
                'get_url': get_url,
                'show_in_navigation': show_in_navigation,
            })

        yield (_('Project Reports'), [_make_report_class(config) for config in configs])
Example #17
0
def _get_report_module_context(app, module):
    def _report_to_config(report):
        return {
            'report_id': report._id,
            'title': report.title,
            'description': report.description,
            'charts': [chart for chart in report.charts if
                       chart.type == 'multibar'],
            'filter_structure': report.filters_without_prefilters,
        }

    all_reports = ReportConfiguration.by_domain(app.domain) + \
                  StaticReportConfiguration.by_domain(app.domain)
    warnings = []
    validity = module.check_report_validity()

    # We're now proactively deleting these references, so after that's been
    # out for a while, this can be removed (say June 2016 or later)
    if not validity.is_valid:
        module.report_configs = validity.valid_report_configs
        warnings.append(
            gettext_lazy('Your app contains references to reports that are '
                         'deleted. These will be removed on save.')
        )

    return {
        'all_reports': [_report_to_config(r) for r in all_reports],
        'current_reports': [r.to_json() for r in module.report_configs],
        'warnings': warnings,
    }
Example #18
0
def _get_report_module_context(app, module):
    def _report_to_config(report):
        return {
            'report_id': report._id,
            'title': report.title,
            'description': report.description,
            'charts': [chart for chart in report.charts if
                       chart.type == 'multibar'],
            'filter_structure': report.filters,
        }

    all_reports = ReportConfiguration.by_domain(app.domain)
    all_report_ids = set([r._id for r in all_reports])
    invalid_report_references = filter(
        lambda r: r.report_id not in all_report_ids, module.report_configs)
    warnings = []
    if invalid_report_references:
        module.report_configs = filter(lambda r: r.report_id in all_report_ids,
                                       module.report_configs)
        warnings.append(
            gettext_lazy(
                'Your app contains references to reports that are deleted. These will be removed on save.')
        )
    return {
        'all_reports': [_report_to_config(r) for r in all_reports],
        'current_reports': [r.to_json() for r in module.report_configs],
        'invalid_report_references': invalid_report_references,
        'warnings': warnings,
    }
Example #19
0
def _get_report_builder_reports(project):
    from corehq.apps.userreports.models import ReportConfiguration
    reports = ReportConfiguration.by_domain(project.name)
    return filter(
        lambda report: report.report_meta.created_by_builder,
        reports
    )
Example #20
0
    def test_updating_report_that_shares_data_source(self):
        """
        If a report builder builder report shares a data source with another report,
        then editing the report builder report should result in a new data source
        being created for the report.
        """

        # Make report
        builder_form = ConfigureListReportForm(
            "Test Report",
            self.app._id,
            "form",
            self.form.unique_id,
            existing_report=None,
            data={
                'user_filters': '[]',
                'default_filters': '[]',
                'columns': '[{"property": "/data/first_name", "display_text": "first name"}]',
            }
        )
        self.assertTrue(builder_form.is_valid())
        report = builder_form.create_report()

        # Make another report that references the same data source
        report_two = ReportConfiguration(
            domain="domain",
            config_id=report.config_id
        )
        report_two.save()

        # Make an edit to the first report builder report
        builder_form = ConfigureListReportForm(
            "Test Report",
            self.app._id,
            "form",
            self.form.unique_id,
            existing_report=report,
            data={
                'user_filters': '[]',
                'default_filters': '[]',
                'columns': '[{"property": "/data/first_name", "display_text": "first name"}]',
            }
        )
        self.assertTrue(builder_form.is_valid())
        report = builder_form.update_report()

        self.assertNotEqual(report.config_id, report_two.config_id)
Example #21
0
def _shared_context(domain):
    static_reports = list(StaticReportConfiguration.by_domain(domain))
    static_data_sources = list(StaticDataSourceConfiguration.by_domain(domain))
    return {
        'domain': domain,
        'reports': ReportConfiguration.by_domain(domain) + static_reports,
        'data_sources': DataSourceConfiguration.by_domain(domain) + static_data_sources,
    }
Example #22
0
def _get_existing_reports(domain):
    from corehq.apps.userreports.models import ReportConfiguration
    from corehq.apps.userreports.views import TEMP_REPORT_PREFIX
    existing_reports = ReportConfiguration.by_domain(domain)
    return [
        report for report in existing_reports
        if not report.title.startswith(TEMP_REPORT_PREFIX)
    ]
Example #23
0
 def main_context(self):
     static_reports = list(StaticReportConfiguration.by_domain(self.domain))
     static_data_sources = list(StaticDataSourceConfiguration.by_domain(self.domain))
     context = super(BaseUserConfigReportsView, self).main_context
     context.update({
         'reports': ReportConfiguration.by_domain(self.domain) + static_reports,
         'data_sources': DataSourceConfiguration.by_domain(self.domain) + static_data_sources,
     })
     return context
Example #24
0
    def test_purge_report_from_mobile_ucr(self, get_db):
        report_config = ReportConfiguration(domain='domain', config_id='foo1')
        report_config._id = "my_report_config"

        app = Application.new_app('domain', "App")
        report_module = app.add_module(ReportModule.new_module('Reports', None))
        report_module.report_configs = [
            ReportAppConfig(report_id=report_config._id, header={'en': 'CommBugz'}),
            ReportAppConfig(report_id='other_config_id', header={'en': 'CommBugz'})
        ]
        self.assertEqual(len(app.modules[0].report_configs), 2)

        with patch('corehq.apps.app_manager.util.get_apps_in_domain') as get_apps:
            get_apps.return_value = [app]
            # this will get called when report_config is deleted
            purge_report_from_mobile_ucr(report_config)

        self.assertEqual(len(app.modules[0].report_configs), 1)
Example #25
0
 def migrate_report(self, report_config):
     rc = ReportConfiguration.wrap(report_config)
     for column in rc.report_columns:
         if column.transform and column.transform['type'] == 'translation':
             column.transform['mobile_or_web'] = 'mobile'
             column.transform['translations'] = reformat_translations(column.transform['translations'])
             self.reports_using_transform.add(rc._id)
     if not self.dry_run:
         return DocUpdate(rc.to_json())
Example #26
0
    def create_report(self):
        """
        Creates data source and report config.
        """
        matching_data_source = self.ds_builder.get_existing_match()
        if matching_data_source:
            data_source_config_id = matching_data_source['id']
        else:
            data_source_config = DataSourceConfiguration(
                domain=self.domain,
                display_name=self.ds_builder.data_source_name,
                referenced_doc_type=self.ds_builder.source_doc_type,
                # The uuid gets truncated, so it's not really universally unique.
                table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)),
                configured_filter=self.ds_builder.filter,
                configured_indicators=self.ds_builder.indicators,
                meta=DataSourceMeta(build=DataSourceBuildInformation(
                    source_id=self.report_source_id,
                    app_id=self.app._id,
                    app_version=self.app.version,
                ))
            )
            data_source_config.validate()
            data_source_config.save()
            tasks.rebuild_indicators.delay(data_source_config._id)
            data_source_config_id = data_source_config._id

        report = ReportConfiguration(
            domain=self.domain,
            config_id=data_source_config_id,
            title=self.report_name,
            aggregation_columns=self._report_aggregation_cols,
            columns=self._report_columns,
            filters=self._report_filters,
            configured_charts=self._report_charts,
            report_meta=ReportMeta(
                created_by_builder=True,
                builder_report_type=self.report_type
            )
        )
        report.validate()
        report.save()
        return report
Example #27
0
def get_number_of_report_configs_by_data_source(domain, data_source_id):
    """
    Return the number of report configurations that use the given data source.
    """
    from corehq.apps.userreports.models import ReportConfiguration
    return ReportConfiguration.view(
        'userreports/report_configs_by_data_source',
        reduce=True,
        key=[domain, data_source_id]
    ).one()['value']
Example #28
0
def clean_columns(json_spec):
    static_config = StaticReportConfiguration.wrap(deepcopy(json_spec))
    report_config = ReportConfiguration.wrap(static_config.config)
    cleaned_columns = []
    for col_spec, wrapped_col in zip(json_spec['config']['columns'],
                                     report_config.report_columns):
        print("Checking column '{}'".format(col_spec['column_id']))
        new_col_spec = clean_spec(col_spec, wrapped_col)
        cleaned_columns.append(order_dict(new_col_spec, COLUMN_PARAMS_ORDER))
    return cleaned_columns
Example #29
0
def _get_report_module_context(app, module):
    def _report_to_config(report):
        return {
            'report_id': report._id,
            'title': report.title,
            'description': report.description,
            'charts': [chart for chart in report.charts if
                       chart.type == 'multibar'],
            'filter_structure': report.filters_without_prefilters,
        }

    all_reports = ReportConfiguration.by_domain(app.domain) + \
                  StaticReportConfiguration.by_domain(app.domain)
    validity = module.check_report_validity()

    # We're now proactively deleting these references, so after that's been
    # out for a while, this can be removed (say June 2016 or later)
    if not validity.is_valid:
        module.report_configs = validity.valid_report_configs

    filter_choices = [
        {'slug': f.doc_type, 'description': f.short_description} for f in get_all_mobile_filter_configs()
    ]
    auto_filter_choices = [
        {'slug': f.slug, 'description': f.short_description} for f in get_auto_filter_configurations()

    ]
    from corehq.apps.app_manager.suite_xml.features.mobile_ucr import get_column_xpath_client_template, get_data_path
    data_path_placeholders = {}
    for r in module.report_configs:
        data_path_placeholders[r.report_id] = {}
        for chart_id in r.complete_graph_configs.keys():
            data_path_placeholders[r.report_id][chart_id] = get_data_path(r, app.domain)

    context = {
        'report_module_options': {
            'moduleName': module.name,
            'moduleFilter': module.module_filter,
            'availableReports': [_report_to_config(r) for r in all_reports],  # structure for all reports
            'currentReports': [r.to_json() for r in module.report_configs],  # config data for app reports
            'columnXpathTemplate': get_column_xpath_client_template(app.mobile_ucr_restore_version),
            'dataPathPlaceholders': data_path_placeholders,
            'languages': app.langs,
            'mobileUcrV1': app.mobile_ucr_restore_version == MOBILE_UCR_VERSION_1,
            'globalSyncDelay': Domain.get_by_name(app.domain).default_mobile_ucr_sync_interval,
        },
        'static_data_options': {
            'filterChoices': filter_choices,
            'autoFilterChoices': auto_filter_choices,
            'dateRangeOptions': [choice._asdict() for choice in get_simple_dateranges()],
        },
        'uuids_by_instance_id': get_uuids_by_instance_id(app.domain),
        'legacy_select2': True,
    }
    return context
Example #30
0
def _safely_get_report_configs(project_name):
    try:
        configs = ReportConfiguration.by_domain(project_name)
    except BadSpecError as e:
        logging.exception(e)

        # Pick out the UCRs that don't have spec errors
        configs = []
        for config_id in get_doc_ids_in_domain_by_class(project_name, ReportConfiguration):
            try:
                configs.append(ReportConfiguration.get(config_id))
            except BadSpecError as e:
                logging.error("%s with report config %s" % (e.message, config_id))

    try:
        configs.extend(StaticReportConfiguration.by_domain(project_name))
    except BadSpecError as e:
        logging.exception(e)

    return configs
 def setUpClass(cls):
     super(LocationChoiceProviderTest, cls).setUpClass()
     report = ReportConfiguration(domain=cls.domain)
     choice_tuples = [(location.name,
                       SearchableChoice(location.location_id,
                                        location.display_name,
                                        searchable_text=[
                                            location.site_code,
                                            location.name
                                        ]))
                      for location in cls.locations.values()]
     choice_tuples.sort()
     choices = [choice for name, choice in choice_tuples]
     cls.web_user = WebUser.create(cls.domain, 'blah', 'password', None,
                                   None)
     cls.choice_provider = LocationChoiceProvider(report, None)
     cls.choice_provider.configure({
         "include_descendants": False,
         "show_full_path": False,
     })
     cls.static_choice_provider = StaticChoiceProvider(choices)
     cls.choice_query_context = partial(ChoiceQueryContext,
                                        user=cls.web_user)
    def setUpClass(cls):
        cls.domain_obj = create_domain(cls.domain)
        report = ReportConfiguration(domain=cls.domain)
        bootstrap_location_types(cls.domain)

        location_code_name_pairs = (
            ('cambridge_ma', 'Cambridge'),
            ('somerville_ma', 'Somerville'),
            ('boston_ma', 'Boston'),
        )
        cls.locations = []
        choices = []

        for location_code, location_name in location_code_name_pairs:
            location = cls.make_location(location_code, location_name)
            cls.locations.append(location)
            choices.append(
                SearchableChoice(
                    location.location_id,
                    location.sql_location.display_name,
                    searchable_text=[location_code, location_name]))
        choices.sort(key=lambda choice: choice.display)
        cls.choice_provider = LocationChoiceProvider(report, None)
        cls.static_choice_provider = StaticChoiceProvider(choices)
Example #33
0
    def _release_report(self, domain_link, model):
        report_id = model['detail']['report_id']
        found = False
        for linked_report in get_report_configs_for_domain(
                domain_link.linked_domain):
            if linked_report.report_meta.master_id == report_id:
                found = True
                update_linked_ucr(domain_link, linked_report.get_id)

        if not found:
            report = ReportConfiguration.get(report_id)
            if report.report_meta.created_by_builder:
                view = 'edit_report_in_builder'
            else:
                view = 'edit_configurable_report'
            url = get_url_base() + reverse(
                view, args=[domain_link.master_domain, report_id])
            return self._error_tuple(
                _('Could not find report. <a href="{}">Click here</a> and click "Link Report" to link this '
                  + 'report.').format(url),
                text=
                _('Could not find report. Please check that the report has been linked.'
                  ),
            )
Example #34
0
    def setUpClass(cls):
        report = ReportConfiguration(domain=cls.domain)

        cls.web_user = cls.make_web_user('*****@*****.**')
        cls.users = [
            cls.make_mobile_worker('bernice'),
            cls.web_user,
            cls.make_mobile_worker('dennis'),
            cls.make_mobile_worker('elizabeth'),
            cls.make_mobile_worker('albert'),
            # test that docs in other domains are filtered out
            cls.make_mobile_worker('aaa', domain='some-other-domain'),
        ]
        choices = [
            SearchableChoice(user.get_id,
                             user.raw_username,
                             searchable_text=[
                                 user.username, user.last_name, user.first_name
                             ]) for user in cls.users
            if user.is_member_of(cls.domain)
        ]
        choices.sort(key=lambda choice: choice.display)
        cls.choice_provider = UserChoiceProvider(report, None)
        cls.static_choice_provider = StaticChoiceProvider(choices)
Example #35
0
 def setUpClass(cls):
     super(DBAccessorsTest, cls).setUpClass()
     cls.data_source_id = 'd36c7c934cb84725899cca9a0ef96e3a'
     cls.domain_1 = Domain(name='userreport-dbaccessors')
     cls.domain_1.save()
     cls.domain_2 = Domain(name='mallory')
     cls.domain_2.save()
     cls.report_configs = [
         ReportConfiguration(domain=cls.domain_1.name,
                             config_id=cls.data_source_id,
                             title='A'),
         ReportConfiguration(domain=cls.domain_1.name,
                             config_id=cls.data_source_id,
                             title='B'),
         ReportConfiguration(domain=cls.domain_1.name,
                             config_id='asabsdjf',
                             title='C'),
         ReportConfiguration(domain=cls.domain_2.name,
                             config_id=cls.data_source_id,
                             title='X'),
     ]
     ReportConfiguration.get_db().bulk_save(cls.report_configs)
Example #36
0
    def create_report(self):
        """
        Creates data source and report config.
        """
        matching_data_source = self.ds_builder.get_existing_match()
        if matching_data_source:
            data_source_config_id = matching_data_source['id']
        else:
            data_source_config_id = self._build_data_source()

        report = ReportConfiguration(
            domain=self.domain,
            config_id=data_source_config_id,
            title=self.report_name,
            aggregation_columns=self._report_aggregation_cols,
            columns=self._report_columns,
            filters=self._report_filters,
            configured_charts=self._report_charts,
            report_meta=ReportMeta(created_by_builder=True,
                                   builder_report_type=self.report_type))
        report.validate()
        report.save()
        return report
Example #37
0
    def setUp(self):
        super(ReportDataTest, self).setUp()
        # Create report
        self.domain = 'test-ucr-report-data'
        self.data_source = DataSourceConfiguration(
            domain=self.domain,
            referenced_doc_type='CommCareCase',
            table_id=uuid.uuid4().hex,
            configured_filter={},
            configured_indicators=[{
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'name'
                },
                "column_id": 'name',
                "display_name": 'name',
                "datatype": "string"
            }, {
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'number'
                },
                "column_id": 'number',
                "display_name": 'number',
                "datatype": "integer"
            }, {
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'number'
                },
                "column_id": 'string-number',
                "display_name": 'string-number',
                "datatype": "string"
            }, {
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'just_for_sorting'
                },
                "column_id": 'just_for_sorting',
                "display_name": 'just_for_sorting',
                "datatype": "string"
            }],
        )
        self.data_source.validate()
        self.data_source.save()
        self.adapter = get_indicator_adapter(self.data_source)
        self.adapter.rebuild_table()
        self.addCleanup(self.data_source.delete)

        # initialize a report on the data
        self.report_config = ReportConfiguration(
            domain=self.domain,
            config_id=self.data_source._id,
            aggregation_columns=['doc_id'],
            columns=[{
                "type": "field",
                "field": "name",
                "column_id": "name",
                "display": "Name",
                "aggregation": "simple",
            }, {
                "type": "field",
                "field": "number",
                "column_id": "number",
                "display": "Number",
                "aggregation": "simple",
                "calculate_total": True,
            }, {
                "type": "expression",
                "column_id": "ten",
                "display": "The Number Ten",
                "expression": {
                    'type': 'constant',
                    'constant': 10,
                }
            }, {
                "type": "expression",
                "column_id": "by_tens",
                "display": "Counting by tens",
                "expression": {
                    "type": "evaluator",
                    "statement": "a * b",
                    "context_variables": {
                        "a": {
                            "type": "property_name",
                            "property_name": "number",
                        },
                        "b": {
                            "type": "property_name",
                            "property_name": "ten",
                        }
                    }
                }
            }, {
                "type": "field",
                "field": 'string-number',
                "display": 'Display Number',
                "aggregation": "simple",
                "transform": {
                    "type": "translation",
                    "translations": {
                        "0": "zero",
                        "1": {
                            "en": "one",
                            "es": "uno"
                        },
                        "2": {
                            "en": "two",
                            "es": "dos"
                        }
                    },
                },
            }],
            filters=[],
            configured_charts=[],
            sort_expression=[{
                'field': 'just_for_sorting',
                'order': 'DESC'
            }])
        self.report_config.save()
        self.addCleanup(self.report_config.delete)
Example #38
0
class ReportDataTest(TestCase):
    def setUp(self):
        super(ReportDataTest, self).setUp()
        # Create report
        self.domain = 'test-ucr-report-data'
        self.data_source = DataSourceConfiguration(
            domain=self.domain,
            referenced_doc_type='CommCareCase',
            table_id=uuid.uuid4().hex,
            configured_filter={},
            configured_indicators=[{
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'name'
                },
                "column_id": 'name',
                "display_name": 'name',
                "datatype": "string"
            }, {
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'number'
                },
                "column_id": 'number',
                "display_name": 'number',
                "datatype": "integer"
            }, {
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'number'
                },
                "column_id": 'string-number',
                "display_name": 'string-number',
                "datatype": "string"
            }, {
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'just_for_sorting'
                },
                "column_id": 'just_for_sorting',
                "display_name": 'just_for_sorting',
                "datatype": "string"
            }],
        )
        self.data_source.validate()
        self.data_source.save()
        self.adapter = get_indicator_adapter(self.data_source)
        self.adapter.rebuild_table()
        self.addCleanup(self.data_source.delete)

        # initialize a report on the data
        self.report_config = ReportConfiguration(
            domain=self.domain,
            config_id=self.data_source._id,
            aggregation_columns=['doc_id'],
            columns=[{
                "type": "field",
                "field": "name",
                "column_id": "name",
                "display": "Name",
                "aggregation": "simple",
            }, {
                "type": "field",
                "field": "number",
                "column_id": "number",
                "display": "Number",
                "aggregation": "simple",
                "calculate_total": True,
            }, {
                "type": "expression",
                "column_id": "ten",
                "display": "The Number Ten",
                "expression": {
                    'type': 'constant',
                    'constant': 10,
                }
            }, {
                "type": "expression",
                "column_id": "by_tens",
                "display": "Counting by tens",
                "expression": {
                    "type": "evaluator",
                    "statement": "a * b",
                    "context_variables": {
                        "a": {
                            "type": "property_name",
                            "property_name": "number",
                        },
                        "b": {
                            "type": "property_name",
                            "property_name": "ten",
                        }
                    }
                }
            }, {
                "type": "field",
                "field": 'string-number',
                "display": 'Display Number',
                "aggregation": "simple",
                "transform": {
                    "type": "translation",
                    "translations": {
                        "0": "zero",
                        "1": {
                            "en": "one",
                            "es": "uno"
                        },
                        "2": {
                            "en": "two",
                            "es": "dos"
                        }
                    },
                },
            }],
            filters=[],
            configured_charts=[],
            sort_expression=[{
                'field': 'just_for_sorting',
                'order': 'DESC'
            }])
        self.report_config.save()
        self.addCleanup(self.report_config.delete)

    def _add_some_rows(self, count):
        rows = [
            ReportDataTestRow(uuid.uuid4().hex, i, i) for i in range(count)
        ]
        self._add_rows(rows)
        return rows

    def _add_rows(self, rows):
        pillow = get_kafka_ucr_pillow()
        pillow.bootstrap(configs=[self.data_source])

        def _get_case(row):
            return {
                '_id': uuid.uuid4().hex,
                'domain': self.domain,
                'doc_type': 'CommCareCase',
                'type': 'city',
                'name': row.name,
                'number': row.number,
                'just_for_sorting': row.sort_key,
            }

        for row in rows:
            pillow.process_change(doc_to_change(_get_case(row)))

    def test_basic_query(self):
        # add a few rows to the data source
        rows = self._add_some_rows(3)

        # check the returned data from the report looks right
        report_data_source = ConfigurableReportDataSource.from_spec(
            self.report_config)
        report_data = report_data_source.get_data()
        self.assertEqual(len(rows), len(report_data))
        rows_by_name = {r.name: r for r in rows}
        for row in report_data:
            self.assertTrue(row['name'] in rows_by_name)
            self.assertEqual(rows_by_name[row['name']].number, row['number'])
            self.assertEqual(10, row['ten'])
            self.assertEqual(10 * row['number'], row['by_tens'])

    def test_limit(self):
        count = 5
        self._add_some_rows(count)
        report_data_source = ConfigurableReportDataSource.from_spec(
            self.report_config)
        original_data = report_data_source.get_data()
        self.assertEqual(count, len(original_data))
        limited_data = report_data_source.get_data(limit=3)
        self.assertEqual(3, len(limited_data))
        self.assertEqual(original_data[:3], limited_data)

    def test_skip(self):
        count = 5
        self._add_some_rows(count)
        report_data_source = ConfigurableReportDataSource.from_spec(
            self.report_config)
        original_data = report_data_source.get_data()
        self.assertEqual(count, len(original_data))
        skipped = report_data_source.get_data(start=3)
        self.assertEqual(count - 3, len(skipped))
        self.assertEqual(original_data[3:], skipped)

    def test_total_row(self):
        rows = self._add_some_rows(3)
        report_data_source = ConfigurableReportDataSource.from_spec(
            self.report_config)

        total_number = sum(row.number for row in rows)
        self.assertEqual(report_data_source.get_total_row(),
                         ['Total', total_number, '', '', ''])

    def test_transform(self):
        count = 5
        self._add_some_rows(count)
        report_data_source = ConfigurableReportDataSource.from_spec(
            self.report_config)
        original_data = report_data_source.get_data()
        self.assertEqual(count, len(original_data))
        rows_by_number = {int(row['number']): row for row in original_data}
        # Make sure the translations happened
        self.assertEqual(rows_by_number[0]['string-number'], "zero")
        self.assertEqual(rows_by_number[1]['string-number'], "one")
        self.assertEqual(rows_by_number[2]['string-number'], "two")
        # These last two are untranslated
        self.assertEqual(rows_by_number[3]['string-number'], "3")
        self.assertEqual(rows_by_number[4]['string-number'], "4")
Example #39
0
 def test_duplicate_column_ids(self):
     spec = self.config._doc
     spec['columns'].append(spec['columns'][-1])
     wrapped = ReportConfiguration.wrap(spec)
     with self.assertRaises(BadSpecError):
         wrapped.validate()
Example #40
0
    def setUpClass(cls):
        super(TestConfigurableReportDataResource, cls).setUpClass()

        case_type = "my_case_type"
        cls.field_name = "my_field"
        cls.case_property_values = ["foo", "foo", "bar", "baz"]

        cls.cases = []
        for val in cls.case_property_values:
            id = uuid.uuid4().hex
            case_block = CaseBlock(
                create=True,
                case_id=id,
                case_type=case_type,
                update={
                    cls.field_name: val
                },
            ).as_xml()
            post_case_blocks([case_block], {'domain': cls.domain.name})
            cls.cases.append(CommCareCase.get(id))

        cls.report_columns = [{
            "column_id": cls.field_name,
            "type": "field",
            "field": cls.field_name,
            "aggregation": "simple",
        }]
        cls.report_filters = [{
            'datatype': 'string',
            'field': cls.field_name,
            'type': 'dynamic_choice_list',
            'slug': 'my_field_filter',
        }]

        cls.data_source = DataSourceConfiguration(
            domain=cls.domain.name,
            referenced_doc_type="CommCareCase",
            table_id=uuid.uuid4().hex,
            configured_filter={
                "type": "boolean_expression",
                "operator": "eq",
                "expression": {
                    "type": "property_name",
                    "property_name": "type"
                },
                "property_value": case_type,
            },
            configured_indicators=[
                {
                    "type": "expression",
                    "expression": {
                        "type": "property_name",
                        "property_name": cls.field_name
                    },
                    "column_id": cls.field_name,
                    "display_name": cls.field_name,
                    "datatype": "string"
                },
                {
                    "type": "expression",
                    "expression": {
                        "type": "property_name",
                        "property_name": "opened_by"
                    },
                    "column_id": "opened_by",
                    "display_name": "opened_by",
                    "datatype": "string"
                },
            ],
        )
        cls.data_source.validate()
        cls.data_source.save()
        rebuild_indicators(cls.data_source._id)

        cls.report_configuration = ReportConfiguration(
            domain=cls.domain.name,
            config_id=cls.data_source._id,
            aggregation_columns=["doc_id"],
            columns=cls.report_columns,
            filters=cls.report_filters,
        )
        cls.report_configuration.save()
Example #41
0
def get_sample_report_config():
    folder = os.path.join(os.path.dirname(__file__), 'data', 'configs')
    sample_file = os.path.join(folder, 'sample_report_config.json')
    with open(sample_file, encoding='utf-8') as f:
        structure = json.loads(f.read())
        return ReportConfiguration.wrap(structure)
Example #42
0
def _get_report_module_context(app, module):
    def _report_to_config(report):
        return {
            'report_id':
            report._id,
            'title':
            report.title,
            'description':
            report.description,
            'charts':
            [chart for chart in report.charts if chart.type == 'multibar'],
            'filter_structure':
            report.filters_without_prefilters,
        }

    all_reports = ReportConfiguration.by_domain(app.domain) + \
                  StaticReportConfiguration.by_domain(app.domain)
    validity = module.check_report_validity()

    # We're now proactively deleting these references, so after that's been
    # out for a while, this can be removed (say June 2016 or later)
    if not validity.is_valid:
        module.report_configs = validity.valid_report_configs

    filter_choices = [{
        'slug': f.doc_type,
        'description': f.short_description
    } for f in get_all_mobile_filter_configs()]
    auto_filter_choices = [{
        'slug': f.slug,
        'description': f.short_description
    } for f in get_auto_filter_configurations()]
    from corehq.apps.app_manager.suite_xml.features.mobile_ucr import get_column_xpath_client_template, get_data_path
    data_path_placeholders = {}
    for r in module.report_configs:
        data_path_placeholders[r.report_id] = {}
        for chart_id in r.complete_graph_configs.keys():
            data_path_placeholders[r.report_id][chart_id] = get_data_path(
                r, app.domain)

    context = {
        'report_module_options': {
            'moduleName':
            module.name,
            'moduleFilter':
            module.module_filter,
            'availableReports':
            [_report_to_config(r)
             for r in all_reports],  # structure for all reports
            'currentReports': [r.to_json() for r in module.report_configs
                               ],  # config data for app reports
            'columnXpathTemplate':
            get_column_xpath_client_template(app.mobile_ucr_restore_version),
            'dataPathPlaceholders':
            data_path_placeholders,
            'languages':
            app.langs,
            'mobileUcrV1':
            app.mobile_ucr_restore_version == MOBILE_UCR_VERSION_1,
            'globalSyncDelay':
            Domain.get_by_name(app.domain).default_mobile_ucr_sync_interval,
        },
        'static_data_options': {
            'filterChoices':
            filter_choices,
            'autoFilterChoices':
            auto_filter_choices,
            'dateRangeOptions':
            [choice._asdict() for choice in get_simple_dateranges()],
        },
        'uuids_by_instance_id': get_uuids_by_instance_id(app.domain),
        'legacy_select2': True,
    }
    return context
Example #43
0
def _get_report_builder_reports(project):
    from corehq.apps.userreports.models import ReportConfiguration
    reports = ReportConfiguration.by_domain(project.name)
    return [
        report for report in reports if report.report_meta.created_by_builder
    ]
Example #44
0
 def obj_get_list(self, bundle, **kwargs):
     domain = kwargs['domain']
     return ReportConfiguration.by_domain(domain)
Example #45
0
 def config(self):
     if self.report_id is None:
         return ReportConfiguration(domain=self.domain)
     return get_report_config_or_404(self.report_id, self.domain)[0]
Example #46
0
def number_of_report_builder_reports(domain):
    from corehq.apps.userreports.models import ReportConfiguration
    existing_reports = ReportConfiguration.by_domain(domain)
    builder_reports = filter(
        lambda report: report.report_meta.created_by_builder, existing_reports)
    return len(builder_reports)
    def test_report_module(self):
        from corehq.apps.userreports.tests.utils import get_sample_report_config

        app = Application.new_app('domain', "Untitled Application")

        report_module = app.add_module(ReportModule.new_module(
            'Reports', None))
        report_module.unique_id = 'report_module'
        report = get_sample_report_config()
        report._id = 'd3ff18cd83adf4550b35db8d391f6008'

        report_app_config = ReportAppConfig(
            report_id=report._id,
            header={'en': 'CommBugz'},
            uuid='ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i',
            xpath_description='"report description"',
            use_xpath_description=True)
        report_app_config._report = report
        report_module.report_configs = [report_app_config]
        report_module._loaded = True
        self.assertXmlPartialEqual(
            self.get_xml('reports_module_menu'),
            app.create_suite(),
            "./menu",
        )

        app.multimedia_map = {
            "jr://file/commcare/image/module0_en.png":
            HQMediaMapItem(
                multimedia_id='bb4472b4b3c702f81c0b208357eb22f8',
                media_type='CommCareImage',
                unique_id='fe06454697634053cdb75fd9705ac7e6',
            ),
        }
        report_module.media_image = {
            'en': 'jr://file/commcare/image/module0_en.png',
        }
        self.assertXmlPartialEqual(
            self.get_xml('reports_module_menu_multimedia'),
            app.create_suite(),
            "./menu",
        )

        self.assertXmlPartialEqual(
            self.get_xml('reports_module_select_detail'),
            app.create_suite(),
            "./detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.select']",
        )
        self.assertXmlPartialEqual(
            self.get_xml(
                'reports_module_summary_detail_use_xpath_description'),
            app.create_suite(),
            "./detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.summary']",
        )
        self.assertXmlPartialEqual(
            self.get_xml('reports_module_data_detail'),
            app.create_suite(),
            "./detail/detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.data']",
        )
        self.assertXmlPartialEqual(
            self.get_xml('reports_module_data_entry'),
            app.create_suite(),
            "./entry",
        )
        self.assertIn(
            'reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i=CommBugz',
            app.create_app_strings('default'),
        )

        report_app_config.use_xpath_description = False
        self.assertXmlPartialEqual(
            self.get_xml(
                'reports_module_summary_detail_use_localized_description'),
            app.create_suite(),
            "./detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.summary']",
        )

        # Tuple mapping translation formats to the expected output of each
        translation_formats = [
            ({
                u'एक': {
                    'en': 'one',
                    'es': 'uno',
                },
                '2': {
                    'en': 'two',
                    'es': 'dos\'',
                    'hin': u'दो',
                },
            }, 'reports_module_data_detail-translated'),
            ({
                u'एक': 'one',
                '2': 'two',
            }, 'reports_module_data_detail-translated-simple'),
            ({
                u'एक': {
                    'en': 'one',
                    'es': 'uno',
                },
                '2': 'two',
            }, 'reports_module_data_detail-translated-mixed'),
        ]
        for translation_format, expected_output in translation_formats:
            report_app_config._report.columns[0]['transform'] = {
                'type': 'translation',
                'translations': translation_format,
            }
            report_app_config._report = ReportConfiguration.wrap(
                report_app_config._report._doc)
            self.assertXmlPartialEqual(
                self.get_xml(expected_output),
                app.create_suite(),
                "./detail/detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.data']",
            )
Example #48
0
    def _build_report_and_view(self):
        # Create report
        data_source_config = DataSourceConfiguration(
            domain=self.domain,
            display_name='foo',
            referenced_doc_type='CommCareCase',
            table_id="woop_woop",
            configured_filter={
                "type": "boolean_expression",
                "operator": "eq",
                "expression": {
                    "type": "property_name",
                    "property_name": "type"
                },
                "property_value": self.case_type,
            },
            configured_indicators=[
                {
                    "type": "expression",
                    "expression": {
                        "type": "property_name",
                        "property_name": 'fruit'
                    },
                    "column_id": 'indicator_col_id_fruit',
                    "display_name": 'indicator_display_name_fruit',
                    "datatype": "string"
                },
                {
                    "type": "expression",
                    "expression": {
                        "type": "property_name",
                        "property_name": 'num1'
                    },
                    "column_id": 'indicator_col_id_num1',
                    "datatype": "integer"
                },
                {
                    "type": "expression",
                    "expression": {
                        "type": "property_name",
                        "property_name": 'num2'
                    },
                    "column_id": 'indicator_col_id_num2',
                    "datatype": "integer"
                },
            ],
        )
        data_source_config.validate()
        data_source_config.save()
        self.addCleanup(data_source_config.delete)
        tasks.rebuild_indicators(data_source_config._id)
        adapter = get_indicator_adapter(data_source_config)
        adapter.refresh_table()

        report_config = ReportConfiguration(
            domain=self.domain,
            config_id=data_source_config._id,
            title='foo',
            aggregation_columns=['doc_id'],
            columns=[
                {
                    "type": "field",
                    "display": "report_column_display_fruit",
                    "field": 'indicator_col_id_fruit',
                    'column_id': 'report_column_col_id_fruit',
                    'aggregation': 'simple'
                },
                {
                    "type": "percent",
                    "display": "report_column_display_percent",
                    'column_id': 'report_column_col_id_percent',
                    'format': 'percent',
                    "denominator": {
                        "type": "field",
                        "aggregation": "sum",
                        "field": "indicator_col_id_num1",
                        "column_id": "report_column_col_id_percent_num1"
                    },
                    "numerator": {
                        "type": "field",
                        "aggregation": "sum",
                        "field": "indicator_col_id_num2",
                        "column_id": "report_column_col_id_percent_num2"
                    }
                },
            ],
        )
        report_config.save()
        self.addCleanup(report_config.delete)

        view = ConfigurableReport(request=HttpRequest())
        view._domain = self.domain
        view._lang = "en"
        view._report_config_id = report_config._id

        return report_config, view
Example #49
0
def delete_all_report_configs():
    from corehq.apps.userreports.models import ReportConfiguration
    delete_all_docs_by_doc_type(ReportConfiguration.get_db(),
                                ('ReportConfiguration', ))
Example #50
0
    def _get_master_model_status(self,
                                 apps,
                                 fixtures,
                                 reports,
                                 keywords,
                                 ignore_models=None):
        model_status = []
        ignore_models = ignore_models or []

        for model, name in LINKED_MODELS:
            if (model not in ignore_models
                    and model not in (MODEL_APP, MODEL_FIXTURE, MODEL_REPORT,
                                      MODEL_KEYWORD) and
                (model != MODEL_CASE_SEARCH
                 or toggles.SYNC_SEARCH_CASE_CLAIM.enabled(self.domain))
                    and (model != MODEL_DATA_DICTIONARY
                         or toggles.DATA_DICTIONARY.enabled(self.domain))
                    and (model != MODEL_DIALER_SETTINGS
                         or toggles.WIDGET_DIALER.enabled(self.domain))
                    and (model != MODEL_OTP_SETTINGS
                         or toggles.GAEN_OTP_SERVER.enabled(self.domain))
                    and (model != MODEL_HMAC_CALLOUT_SETTINGS
                         or toggles.HMAC_CALLOUT.enabled(self.domain))):
                model_status.append({
                    'type': model,
                    'name': name,
                    'last_update': ugettext('Never'),
                    'detail': None,
                    'can_update': True
                })

        linked_models = dict(LINKED_MODELS)
        for app in apps.values():
            update = {
                'type': MODEL_APP,
                'name': '{} ({})'.format(linked_models['app'], app.name),
                'last_update': None,
                'detail': AppLinkDetail(app_id=app._id).to_json(),
                'can_update': True
            }
            model_status.append(update)
        for fixture in fixtures.values():
            update = {
                'type': MODEL_FIXTURE,
                'name': '{} ({})'.format(linked_models['fixture'],
                                         fixture.tag),
                'last_update': None,
                'detail': FixtureLinkDetail(tag=fixture.tag).to_json(),
                'can_update': fixture.is_global,
            }
            model_status.append(update)
        for report in reports.values():
            report = ReportConfiguration.get(report.get_id)
            update = {
                'type': MODEL_REPORT,
                'name': f"{linked_models['report']} ({report.title})",
                'last_update': None,
                'detail': ReportLinkDetail(report_id=report.get_id).to_json(),
                'can_update': True,
            }
            model_status.append(update)

        for keyword in keywords.values():
            update = {
                'type': MODEL_KEYWORD,
                'name': f"{linked_models['keyword']} ({keyword.keyword})",
                'last_update': None,
                'detail':
                KeywordLinkDetail(keyword_id=str(keyword.id)).to_json(),
                'can_update': True,
            }
            model_status.append(update)

        return model_status
Example #51
0
    def _get_model_status(self, master_link, apps, fixtures, reports,
                          keywords):
        model_status = []
        if not master_link:
            return model_status

        models_seen = set()
        history = DomainLinkHistory.objects.filter(
            link=master_link
        ).annotate(row_number=RawSQL(
            'row_number() OVER (PARTITION BY model, model_detail ORDER BY date DESC)',
            []))
        linked_models = dict(LINKED_MODELS)
        timezone = get_timezone_for_request()
        for action in history:
            models_seen.add(action.model)
            if action.row_number != 1:
                # first row is the most recent
                continue
            name = linked_models[action.model]
            update = {
                'type': action.model,
                'name': name,
                'last_update': server_to_user_time(action.date, timezone),
                'detail': action.model_detail,
                'can_update': True
            }
            if action.model == 'app':
                app_name = ugettext('Unknown App')
                if action.model_detail:
                    detail = action.wrapped_detail
                    app = apps.pop(detail.app_id, None)
                    app_name = app.name if app else detail.app_id
                    if app:
                        update['detail'] = action.model_detail
                    else:
                        update['can_update'] = False
                else:
                    update['can_update'] = False
                update['name'] = '{} ({})'.format(name, app_name)

            if action.model == 'fixture':
                tag_name = ugettext('Unknown Table')
                can_update = False
                if action.model_detail:
                    detail = action.wrapped_detail
                    tag = action.wrapped_detail.tag
                    try:
                        fixture = fixtures.get(tag)
                        del fixtures[tag]
                    except KeyError:
                        fixture = get_fixture_data_type_by_tag(
                            self.domain, tag)
                    tag_name = fixture.tag
                    can_update = fixture.is_global
                update['name'] = f'{name} ({tag_name})'
                update['can_update'] = can_update
            if action.model == 'report':
                report_id = action.wrapped_detail.report_id
                try:
                    report = reports.get(report_id)
                    del reports[report_id]
                except KeyError:
                    report = ReportConfiguration.get(report_id)
                update['name'] = f'{name} ({report.title})'
            if action.model == 'keyword':
                keyword_id = action.wrapped_detail.linked_keyword_id
                try:
                    keyword = keywords[keyword_id].keyword
                    del keywords[keyword_id]
                except KeyError:
                    try:
                        keyword = Keyword.objects.get(id=keyword_id).keyword
                    except Keyword.DoesNotExist:
                        keyword = ugettext_lazy("Deleted Keyword")
                        update['can_update'] = False
                update['name'] = f'{name} ({keyword})'

            model_status.append(update)

        # Add in models and apps that have never been synced
        model_status.extend(
            self._get_master_model_status(apps,
                                          fixtures,
                                          reports,
                                          keywords,
                                          ignore_models=models_seen))

        return model_status
    def test_report_builder_datasource_deactivation(self):
        def _get_data_source(id_):
            return get_datasource_config(id_, self.project.name)[0]

        # Upgrade the domain
        # (for the upgrade to work, there has to be an existing subscription,
        # which is why we subscribe to advanced first)
        self._subscribe_to_advanced()
        pro_with_rb_sub = self._subscribe_to_pro_with_rb()

        # Create reports and data sources
        builder_report_data_source = DataSourceConfiguration(
            domain=self.project.name,
            is_deactivated=False,
            referenced_doc_type="XFormInstance",
            table_id="foo",
        )
        other_data_source = DataSourceConfiguration(
            domain=self.project.name,
            is_deactivated=False,
            referenced_doc_type="XFormInstance",
            table_id="bar",
        )
        builder_report_data_source.save()
        other_data_source.save()
        report_builder_report = ReportConfiguration(
            domain=self.project.name,
            config_id=builder_report_data_source._id,
            report_meta=ReportMeta(created_by_builder=True),
        )
        report_builder_report.save()

        # downgrade the domain
        community_sub = pro_with_rb_sub.change_plan(
            DefaultProductPlan.get_default_plan_version())

        # Check that the builder data source is deactivated
        builder_report_data_source = _get_data_source(
            builder_report_data_source._id)
        self.assertTrue(builder_report_data_source.is_deactivated)
        # Check that the other data source has not been deactivated
        other_data_source = _get_data_source(other_data_source._id)
        self.assertFalse(other_data_source.is_deactivated)

        # upgrade the domain
        # (for the upgrade to work, there has to be an existing subscription,
        # which is why we subscribe to advanced first)
        community_sub.change_plan(
            DefaultProductPlan.get_default_plan_version(
                edition=SoftwarePlanEdition.ADVANCED))
        pro_with_rb_sub = self._subscribe_to_pro_with_rb()

        # check that the data source is activated
        builder_report_data_source = _get_data_source(
            builder_report_data_source._id)
        self.assertFalse(builder_report_data_source.is_deactivated)

        # delete the data sources
        builder_report_data_source.delete()
        other_data_source.delete()
        # Delete the report
        report_builder_report.delete()

        # reset the subscription
        pro_with_rb_sub.change_plan(
            DefaultProductPlan.get_default_plan_version())
Example #53
0
    def _build_report(self, vals, field='my_field', build_data_source=True):
        """
        Build a new report, and populate it with cases.

        Return a ConfigurableReportDataSource and a FieldColumn
        :param vals: List of values to populate the given report field with.
        :param field: The name of a field in the data source/report
        :return: Tuple containing a ConfigurableReportDataSource and FieldColumn.
        The column is a column mapped to the given field.
        """

        # Create Cases
        for v in vals:
            update_props = {field: v} if v is not None else {}
            self._new_case(update_props).save()

        # Create report
        data_source_config = DataSourceConfiguration(
            domain=self.domain,
            display_name='foo',
            referenced_doc_type='CommCareCase',
            table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)),
            configured_filter={
                "type": "boolean_expression",
                "operator": "eq",
                "expression": {
                    "type": "property_name",
                    "property_name": "type"
                },
                "property_value": self.case_type,
            },
            configured_indicators=[{
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": field
                },
                "column_id": field,
                "display_name": field,
                "datatype": "string"
            }],
        )
        data_source_config.validate()
        data_source_config.save()
        self.addCleanup(data_source_config.delete)
        if build_data_source:
            tasks.rebuild_indicators(data_source_config._id)
            adapter = get_indicator_adapter(data_source_config)
            adapter.refresh_table()

        report_config = ReportConfiguration(domain=self.domain,
                                            config_id=data_source_config._id,
                                            title='foo',
                                            aggregation_columns=['doc_id'],
                                            columns=[{
                                                "type": "expanded",
                                                "field": field,
                                                "display": field,
                                                "format": "default",
                                            }],
                                            filters=[],
                                            configured_charts=[])
        report_config.save()
        self.addCleanup(report_config.delete)
        data_source = ReportFactory.from_spec(report_config)
        adapter = get_indicator_adapter(data_source_config)
        if build_data_source:
            adapter.refresh_table()

        return data_source, data_source.top_level_columns[0]
Example #54
0
 def test_config_id_is_required(self):
     with self.assertRaises(BadValueError):
         ReportConfiguration(domain='foo').save()
Example #55
0
class ReportDataTest(TestCase):
    def setUp(self):
        super(ReportDataTest, self).setUp()
        # Create report
        self.domain = 'test-ucr-report-data'
        self.data_source = DataSourceConfiguration(
            domain=self.domain,
            referenced_doc_type='CommCareCase',
            table_id=uuid.uuid4().hex,
            configured_filter={},
            configured_indicators=[{
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'name'
                },
                "column_id": 'name',
                "display_name": 'name',
                "datatype": "string"
            }, {
                "type": "expression",
                "expression": {
                    "type": "property_name",
                    "property_name": 'number'
                },
                "column_id": 'number',
                "display_name": 'number',
                "datatype": "integer"
            }],
        )
        self.data_source.validate()
        self.data_source.save()
        self.adapter = get_indicator_adapter(self.data_source)
        self.adapter.rebuild_table()
        self.addCleanup(self.data_source.delete)

        # initialize a report on the data
        self.report_config = ReportConfiguration(
            domain=self.domain,
            config_id=self.data_source._id,
            aggregation_columns=['doc_id'],
            columns=[{
                "type": "field",
                "field": "name",
                "column_id": "name",
                "display": "Name",
                "aggregation": "simple",
            }, {
                "type": "field",
                "field": "number",
                "column_id": "number",
                "display": "Number",
                "aggregation": "simple",
            }, {
                "type": "expression",
                "column_id": "ten",
                "display": "The Number Ten",
                "expression": {
                    'type': 'constant',
                    'constant': 10,
                }
            }, {
                "type": "expression",
                "column_id": "by_tens",
                "display": "Counting by tens",
                "expression": {
                    "type": "evaluator",
                    "statement": "a * b",
                    "context_variables": {
                        "a": {
                            "type": "property_name",
                            "property_name": "number",
                        },
                        "b": {
                            "type": "property_name",
                            "property_name": "ten",
                        }
                    }
                }
            }],
            filters=[],
            configured_charts=[])
        self.report_config.save()
        self.addCleanup(self.report_config.delete)

    def _add_some_rows(self, count):
        rows = [ReportDataTestRow(uuid.uuid4().hex, i) for i in range(count)]
        self._add_rows(rows)
        self.adapter.refresh_table()
        return rows

    def _add_rows(self, rows):
        pillow = get_kafka_ucr_pillow()
        pillow.bootstrap(configs=[self.data_source])

        def _get_case(row):
            return {
                '_id': uuid.uuid4().hex,
                'domain': self.domain,
                'doc_type': 'CommCareCase',
                'type': 'city',
                'name': row.name,
                'number': row.number,
            }

        for row in rows:
            pillow.process_change(doc_to_change(_get_case(row)))

    @run_with_all_ucr_backends
    def test_basic_query(self):
        # add a few rows to the data source
        rows = self._add_some_rows(3)

        # check the returned data from the report looks right
        report_data_source = ReportFactory.from_spec(self.report_config)
        report_data = report_data_source.get_data()
        self.assertEqual(len(rows), len(report_data))
        rows_by_name = {r.name: r for r in rows}
        for row in report_data:
            self.assertTrue(row['name'] in rows_by_name)
            self.assertEqual(rows_by_name[row['name']].number, row['number'])
            self.assertEqual(10, row['ten'])
            self.assertEqual(10 * row['number'], row['by_tens'])

    @run_with_all_ucr_backends
    def test_limit(self):
        count = 5
        self._add_some_rows(count)
        report_data_source = ReportFactory.from_spec(self.report_config)
        original_data = report_data_source.get_data()
        self.assertEqual(count, len(original_data))
        limited_data = report_data_source.get_data(limit=3)
        self.assertEqual(3, len(limited_data))
        self.assertEqual(original_data[:3], limited_data)

    @run_with_all_ucr_backends
    def test_skip(self):
        count = 5
        self._add_some_rows(count)
        report_data_source = ReportFactory.from_spec(self.report_config)
        original_data = report_data_source.get_data()
        self.assertEqual(count, len(original_data))
        skipped = report_data_source.get_data(start=3)
        self.assertEqual(count - 3, len(skipped))
        self.assertEqual(original_data[3:], skipped)
Example #56
0
 def setUp(self):
     super(ReportTranslationTest, self).setUp()
     report = ReportConfiguration.by_domain(self.DOMAIN)[0]
     self.report_source = ReportFactory.from_spec(report)
Example #57
0
 def tearDownClass(cls):
     ReportConfiguration.get_db().bulk_delete(cls.report_configs)
     cls.domain_1.delete()
     cls.domain_2.delete()
Example #58
0
def _get_report_module_context(app, module):
    def _report_to_config(report):
        return {
            'report_id':
            report._id,
            'title':
            report.title,
            'description':
            report.description,
            'charts':
            [chart for chart in report.charts if chart.type == 'multibar'],
            'filter_structure':
            report.filters_without_prefilters,
        }

    all_reports = ReportConfiguration.by_domain(app.domain) + \
                  StaticReportConfiguration.by_domain(app.domain)
    validity = module.check_report_validity()

    # We're now proactively deleting these references, so after that's been
    # out for a while, this can be removed (say June 2016 or later)
    if not validity.is_valid:
        module.report_configs = validity.valid_report_configs

    filter_choices = [{
        'slug': f.doc_type,
        'description': f.short_description
    } for f in get_all_mobile_filter_configs()]
    auto_filter_choices = [{
        'slug': f.slug,
        'description': f.short_description
    } for f in get_auto_filter_configurations()]
    from corehq.apps.app_manager.suite_xml.features.mobile_ucr import COLUMN_XPATH_CLIENT_TEMPLATE, get_data_path
    current_reports = []
    data_path_placeholders = {}
    for r in module.report_configs:
        r.migrate_graph_configs(app.domain)
        current_reports.append(r.to_json())
        data_path_placeholders[r.report_id] = {}
        for chart_id in r.complete_graph_configs.keys():
            data_path_placeholders[r.report_id][chart_id] = get_data_path(
                r, app.domain)

    context = {
        'report_module_options': {
            'moduleName': module.name,
            'moduleFilter': module.module_filter,
            'availableReports':
            [_report_to_config(r)
             for r in all_reports],  # structure for all reports
            'currentReports': current_reports,  # config data for app reports
            'columnXpathTemplate': COLUMN_XPATH_CLIENT_TEMPLATE,
            'dataPathPlaceholders': data_path_placeholders,
            'languages': app.langs,
        },
        'static_data_options': {
            'filterChoices':
            filter_choices,
            'autoFilterChoices':
            auto_filter_choices,
            'dateRangeOptions':
            [choice._asdict() for choice in get_simple_dateranges()],
        },
    }
    return context
Example #59
0
MAKE_REPORT_CONFIG = lambda domain, report_id: ReportConfiguration(
    _id=report_id,
    title="Entry Report",
    aggregation_columns=["color_94ec39e6"],
    config_id="516c494736e95b023cc7845b557de0f5",
    domain=domain,
    report_meta=ReportMeta(builder_report_type="chart",
                           created_by_builder=True),
    columns=[
        FieldColumn(type='field',
                    aggregation="simple",
                    column_id="color_94ec39e6",
                    display="color",
                    field="color_94ec39e6").to_json(),
    ],
    configured_charts=[
        MultibarChartSpec(type='multibar',
                          chart_id="7451243209119342931",
                          x_axis_column="color_94ec39e6",
                          y_axis_columns=[
                              GraphDisplayColumn(column_id="count",
                                                 display="count")
                          ]).to_json()
    ],
    filters=[
        DynamicChoiceListFilterSpec(type='dynamic_choice_list',
                                    display="owner name",
                                    field="computed_owner_name_40cc88a0",
                                    slug="computed_owner_name_40cc88a0_1").
        to_json(),
        ChoiceListFilterSpec(type='choice_list',
                             display="fav color",
                             field="fav_fruit_abc123",
                             slug="fav_fruit_abc123_1",
                             choices=[
                                 FilterChoice(value='a', display='apple'),
                                 FilterChoice(value='b', display='banana'),
                                 FilterChoice(value='c', display='clementine'),
                             ]).to_json()
    ],
)
Example #60
0
def _get_report_builder_reports(project):
    from corehq.apps.userreports.models import ReportConfiguration
    reports = ReportConfiguration.by_domain(project.name)
    return filter(lambda report: report.report_meta.created_by_builder,
                  reports)