Exemple #1
0
    def saved_report_context_data(self):
        """
        Returns a dictionary with every saved report config associated with the report
        """
        def _get_context_for_saved_report(report_config):
            if report_config:
                report_config_data = report_config.to_json()
                report_config_data['filters'].update(
                    report_config.get_date_range())
                return report_config_data
            else:
                return ReportConfig.default()

        context = {
            'report_configs': [
                _get_context_for_saved_report(saved_report) for saved_report in
                ReportConfig.by_domain_and_owner(self.domain,
                                                 self.request.couch_user._id,
                                                 report_slug=self.slug)
            ],
            'default_config':
            _get_context_for_saved_report(self.saved_report_config),
            'datespan_filters':
            ReportConfig.datespan_filter_choices(self.datespan_filters,
                                                 self.lang),
        }

        return context
Exemple #2
0
    def saved_report_context_data(self):
        def _get_context_for_saved_report(report_config):
            if report_config:
                report_config_data = report_config.to_json()
                report_config_data['filters'].update(
                    report_config.get_date_range())
                return report_config_data
            else:
                return ReportConfig.default()

        saved_report_config_id = self.request.GET.get('config_id')
        saved_report_config = get_document_or_404(ReportConfig, self.domain, saved_report_config_id) \
            if saved_report_config_id else None

        return {
            'report_configs': [
                _get_context_for_saved_report(saved_report) for saved_report in
                ReportConfig.by_domain_and_owner(self.domain,
                                                 self.request.couch_user._id,
                                                 report_slug=self.slug)
            ],
            'default_config':
            _get_context_for_saved_report(saved_report_config),
            'datespan_filters':
            ReportConfig.datespan_filter_choices(self.datespan_filters,
                                                 self.lang),
        }
Exemple #3
0
def _migrate_report_filters(apps, schema_editor):
    """
        Migrates ReportConfig filters with multiple values from CHOICE_DELIMITER-delimited strings to lists.
    """
    key = ["name slug"]
    results = ReportConfig.get_db().view(
        "reportconfig/configs_by_domain",
        reduce=False,
        include_docs=True,
        startkey=key,
        endkey=key + [{}]
    )
    count = 0
    for result in results:
        dirty = False
        doc = result['doc']
        config = ReportConfig.wrap(doc)
        for name, value in config['filters'].items():
            if isinstance(value, str) and CHOICE_DELIMITER in value:
                print("Updating config {} filter {}".format(config._id, name))
                config['filters'][name] = value.split(CHOICE_DELIMITER)
                dirty = True
        if dirty:
            count = count + 1
            config.save()
    print("Updated {} configs".format(count))
Exemple #4
0
    def _update_initial_context(self):
        """
            Intention: Don't override.
        """
        report_configs = ReportConfig.by_domain_and_owner(self.domain,
            self.request.couch_user._id, report_slug=self.slug)
        current_config_id = self.request.GET.get('config_id', '')
        default_config = ReportConfig.default()

        def is_editable_datespan(field):
            if isinstance(field, six.string_types):
                soft_assert_type_text(field)
            field_fn = to_function(field) if isinstance(field, six.string_types) else field
            return issubclass(field_fn, DatespanFilter) and field_fn.is_editable

        has_datespan = any([is_editable_datespan(field) for field in self.fields])

        self.context.update(
            report=dict(
                title=self.rendered_report_title,
                description=self.description,
                section_name=self.section_name,
                slug=self.slug,
                sub_slug=None,
                type=self.dispatcher.prefix,
                url_root=self.url_root,
                is_async=self.asynchronous,
                is_exportable=self.exportable,
                dispatcher=self.dispatcher,
                filter_set=self.filter_set,
                needs_filters=self.needs_filters,
                has_datespan=has_datespan,
                show=(
                    self.override_permissions_check
                    or self.request.couch_user.can_view_some_reports(self.domain)
                ),
                is_emailable=self.emailable,
                is_export_all = self.exportable_all,
                is_printable=self.printable,
                is_admin=self.is_admin_report,
                special_notice=self.special_notice,
                report_title=self.report_title or self.rendered_report_title,
                report_subtitles=self.report_subtitles,
                export_target=self.export_target,
                js_options=self.js_options,
                custom_filter_action_template=(
                    self.custom_filter_action_template
                    if hasattr(self, 'custom_filter_action_template')
                    else False
                ),
            ),
            current_config_id=current_config_id,
            default_config=default_config,
            report_configs=report_configs,
            show_time_notice=self.show_time_notice,
            domain=self.domain,
            layout_flush_content=self.flush_layout
        )
Exemple #5
0
    def test_can_delete_saved_report(self):
        report = self._create_saved_report(domain=self.domain,
                                           user_id=self.user._id)

        response = self.delete_config(self.domain, report._id)
        self.assertEqual(response.status_code, 200)

        with self.assertRaises(ResourceNotFound):
            ReportConfig.get(report._id)
Exemple #6
0
    def _create_saved_report(self, domain=None, user_id=None):
        config = ReportConfig(domain=domain or self.domain,
                              owner_id=user_id or self.user._id,
                              name='Test',
                              description='Test Saved Report',
                              report_slug='worker_activity',
                              report_type='project_report')
        config.save()
        self.addCleanup(config.delete)

        return config
Exemple #7
0
    def test_other_admin_can_edit_shared_saved_report(self, *args):
        config1 = self.create_report_config(
            domain=self.DOMAIN,
            owner_id=self.admin_user._id,
            name='Name',
            description='',
        )
        # Create ReportNotification as to make confi1 shared
        self.create_report_notification([config1],
                                        owner_id=self.admin_user._id)
        ReportConfig.shared_on_domain.clear(ReportConfig,
                                            self.DOMAIN,
                                            only_id=True)

        new_description = 'This is a description'
        post_data = {
            'description': new_description,
            'name': config1.name,
            '_id': config1._id,
        }

        self.log_user_in(self.other_admin_user.username)
        response = self.client.post(
            self.URL,
            json.dumps(post_data),
            content_type='application/json;charset=UTF-8',
        )
        self.assertEqual(response.status_code, 200)

        updated_config = ReportConfig.get(config1._id)
        self.assertTrue(updated_config.description, new_description)
Exemple #8
0
    def test_non_admin_cannot_edit_other_shared_configs(self):
        config1 = self.create_report_config(
            domain=self.DOMAIN,
            owner_id=self.admin_user._id,
            name='Name',
            description='',
        )

        post_data = {
            'description': 'Malicious description',
            'name': config1.name,
            '_id': config1._id,
        }

        self.log_user_in(self.non_admin_user.username)
        try:
            _response = self.client.post(
                self.URL,
                json.dumps(post_data),
                content_type='application/json;charset=UTF-8',
            )
        except Exception as e:
            self.assertTrue(e.__class__ == AssertionError)

        # Validate that config1 is untouched
        original_config = ReportConfig.get(config1._id)
        self.assertEqual(original_config.description, '')
 def _get_context_for_saved_report(report_config):
     if report_config:
         report_config_data = report_config.to_json()
         report_config_data['filters'].update(report_config.get_date_range())
         return report_config_data
     else:
         return ReportConfig.default()
Exemple #10
0
    def clean(self):
        name = self.cleaned_data['name']
        _id = self.cleaned_data['_id']

        user_configs = ReportConfig.by_domain_and_owner(
            self.domain, self.user_id)
        if not _id and name in [c.name for c in user_configs]:
            raise forms.ValidationError(
                "A saved report with the name '%(name)s' already exists." % {
                    'name': name,
                })

        date_range = self.cleaned_data['date_range']

        if (self.cleaned_data['report_type'] == ConfigurableReportView.prefix
                and not self.cleaned_data['datespan_slug']):
            self.cleaned_data['date_range'] = None
        else:
            if date_range == 'last7':
                self.cleaned_data['days'] = 7
            elif date_range == 'last30':
                self.cleaned_data['days'] = 30
            elif (date_range == 'lastn'
                  and self.cleaned_data.get('days') is None
                  and self.cleaned_data['report_type'] !=
                  ConfigurableReportView.prefix):
                raise forms.ValidationError(
                    "Field 'days' was expected but not provided.")

        return self.cleaned_data
Exemple #11
0
    def clean(self):
        name = self.cleaned_data['name']
        _id = self.cleaned_data['_id']

        user_configs = ReportConfig.by_domain_and_owner(self.domain, self.user_id)
        if not _id and name in [c.name for c in user_configs]:
            raise forms.ValidationError(
                "A saved report with the name '%(name)s' already exists." % {
                    'name': name,
                }
            )

        date_range = self.cleaned_data['date_range']

        if (
            self.cleaned_data['report_type'] == ConfigurableReportView.prefix
            and not self.cleaned_data['datespan_slug']
        ):
            self.cleaned_data['date_range'] = None
        else:
            if date_range == 'last7':
                self.cleaned_data['days'] = 7
            elif date_range == 'last30':
                self.cleaned_data['days'] = 30
            elif (date_range == 'lastn' and self.cleaned_data.get('days') is None
                  and self.cleaned_data['report_type'] != ConfigurableReportView.prefix):
                raise forms.ValidationError(
                    "Field 'days' was expected but not provided."
                )

        return self.cleaned_data
    def test_saved_report_serialized_filters(self):
        report_config = ReportConfig.wrap({
            "domain": 'saved-report-tests',
            "report_slug": "worker_activity",
            "owner_id": '0123456789',
            "report_type": ConfigurableReportView.prefix,
            "filters": {
                "date-start": "2020-01-01",
                "date-end": "2020-12-31",
                "test-filter": "test"
            }
        })
        report_config._id = 'abc123'

        self.assertEqual(date, type(report_config.filters['date-start']))
        self.assertEqual(date, type(report_config.filters['date-end']))

        filters = report_config.serialized_filters

        expected_filters = {
            "date-start": "2020-01-01",
            "date-end": "2020-12-31",
            "test-filter": "test"
        }
        self.assertEqual(filters, expected_filters)
Exemple #13
0
 def _get_context_for_saved_report(report_config):
     if report_config:
         report_config_data = report_config.to_json()
         report_config_data['filters'].update(report_config.get_date_range())
         return report_config_data
     else:
         return ReportConfig.default()
Exemple #14
0
    def test_admin_can_edit_normal_config(self, *args):
        config1 = self.create_report_config(
            domain=self.DOMAIN,
            owner_id=self.admin_user._id,
            name='Name',
            description='',
        )

        new_description = 'This is a description'
        post_data = {
            'description': new_description,
            'name': config1.name,
            '_id': config1._id,
        }

        self.log_user_in(self.admin_user.username)
        response = self.client.post(
            self.URL,
            json.dumps(post_data),
            content_type='application/json;charset=UTF-8',
        )
        self.assertEqual(response.status_code, 200)

        updated_config = ReportConfig.get(config1._id)
        self.assertTrue(updated_config.description, new_description)
Exemple #15
0
    def test_domain_has_shared_configs(self):
        config = ReportConfig(domain=self.DOMAIN, owner_id=self.OWNER_ID)
        config.save()
        self.addCleanup(config.delete)

        self._create_scheduled_report(
            domain=self.DOMAIN,
            owner_id=self.OWNER_ID,
            config_ids=[config._id],
        )
        # Clear cached value
        ReportConfig.shared_on_domain.clear(ReportConfig, domain=self.DOMAIN)

        configs = list(ReportConfig.shared_on_domain(self.DOMAIN))

        self.assertEqual(len(configs), 1)
        self.assertEqual(configs[0]._id, config._id)
Exemple #16
0
 def total(self):
     key = ["name", self.request.domain, self.request.couch_user._id]
     results = ReportConfig.get_db().view(
         'reportconfig/configs_by_domain',
         include_docs=False,
         startkey=key,
         endkey=key+[{}],
         reduce=True,
     ).all()
     return results[0]['value'] if results else 0
Exemple #17
0
 def total(self):
     key = ["name", self.request.domain, self.request.couch_user._id]
     results = ReportConfig.get_db().view(
         'reportconfig/configs_by_domain',
         include_docs=False,
         startkey=key,
         endkey=key + [{}],
         reduce=True,
     ).all()
     return results[0]['value'] if results else 0
Exemple #18
0
    def test_config_used_in_multiple_report_notifications(self):
        config = ReportConfig(domain=self.DOMAIN, owner_id=self.OWNER_ID)
        config.save()
        self.addCleanup(config.delete)

        self._create_scheduled_report(
            domain=self.DOMAIN,
            owner_id=self.OWNER_ID,
            config_ids=[config._id],
        )
        self._create_scheduled_report(
            domain=self.DOMAIN,
            owner_id=self.OWNER_ID,
            config_ids=[config._id],
        )

        configs = list(ReportConfig.shared_on_domain(self.DOMAIN))
        self.assertEqual(len(configs), 1)
        self.assertEqual(configs[0]._id, config._id)
Exemple #19
0
    def test_no_shared_configs(self):
        config = self.create_report_config(self.DOMAIN, self.admin_user._id)
        configs = ReportConfig.by_domain_and_owner(
            self.DOMAIN,
            self.admin_user._id,
            include_shared=True,
            stale=False,
        )

        self.assertEqual(len(configs), 1)
        self.assertEqual(configs[0]._id, config._id)
Exemple #20
0
 def _paginated_items(self, items_per_page, skip):
     reports = ReportConfig.by_domain_and_owner(self.request.domain,
                                                self.request.couch_user._id,
                                                limit=items_per_page,
                                                skip=skip)
     for report in reports:
         yield self._fmt_item(report.name,
                              report.url,
                              description="%(desc)s (%(date)s)" % {
                                  'desc': report.description,
                                  'date': report.date_description,
                              },
                              full_name=report.full_name)
Exemple #21
0
    def saved_report_context_data(self):
        def _get_context_for_saved_report(report_config):
            if report_config:
                report_config_data = report_config.to_json()
                report_config_data['filters'].update(report_config.get_date_range())
                return report_config_data
            else:
                return ReportConfig.default()

        saved_report_config_id = self.request.GET.get('config_id')
        saved_report_config = get_document_or_404(ReportConfig, self.domain, saved_report_config_id) \
            if saved_report_config_id else None

        return {
            'report_configs': [
                _get_context_for_saved_report(saved_report)
                for saved_report in ReportConfig.by_domain_and_owner(
                    self.domain, self.request.couch_user._id, report_slug=self.slug
                )
            ],
            'default_config': _get_context_for_saved_report(saved_report_config),
            'datespan_filters': ReportConfig.datespan_filter_choices(self.datespan_filters, self.lang),
        }
Exemple #22
0
    def test_with_other_owner_shared_config(self):
        _config = self.create_report_config(self.DOMAIN, self.admin_user._id)
        config2 = self.create_report_config(self.DOMAIN,
                                            self.other_admin_user._id)
        self.create_report_notification([config2],
                                        owner_id=self.other_admin_user._id)

        configs = ReportConfig.by_domain_and_owner(
            self.DOMAIN,
            self.admin_user._id,
            include_shared=True,
            stale=False,
        )
        self.assertEqual(len(configs), 2)
 def handle(self, report_slug, *args, **options):
     kwargs = {'stale': settings.COUCH_STALE_QUERY}
     key = ["name slug"]
     result = cache_core.cached_view(
         ReportConfig.get_db(),
         "reportconfig/configs_by_domain",
         reduce=False, include_docs=False,
         startkey=key, endkey=key + [{}],
         **kwargs)
     for report_config in result:
         domain, owner_id, slug = report_config['key'][1:4]
         if slug == report_slug:
             print("%s, %s, %s" % (
                 domain, owner_id, slug
             ))
 def handle(self, report_slug, *args, **options):
     kwargs = {'stale': settings.COUCH_STALE_QUERY}
     key = ["name slug"]
     result = cache_core.cached_view(
         ReportConfig.get_db(),
         "reportconfig/configs_by_domain",
         reduce=False, include_docs=False,
         startkey=key, endkey=key + [{}],
         **kwargs)
     for report_config in result:
         domain, owner_id, slug = report_config['key'][1:4]
         if slug == report_slug:
             print("%s, %s, %s" % (
                 domain, owner_id, slug
             ))
Exemple #25
0
 def _paginated_items(self, items_per_page, skip):
     reports = ReportConfig.by_domain_and_owner(
         self.request.domain, self.request.couch_user._id,
         limit=items_per_page, skip=skip
     )
     for report in reports:
         yield self._fmt_item(
             report.name,
             report.url,
             description="%(desc)s (%(date)s)" % {
                 'desc': report.description,
                 'date': report.date_description,
             },
             full_name=report.full_name
         )
Exemple #26
0
    def test_with_shared_config(self):
        config = self.create_report_config(self.DOMAIN, self.admin_user._id)

        self.create_report_notification([config], owner_id=self.admin_user._id)
        # Clear cached value
        ReportConfig.shared_on_domain.clear(ReportConfig, domain=self.DOMAIN)

        configs = ReportConfig.by_domain_and_owner(
            self.DOMAIN,
            self.admin_user._id,
            include_shared=True,
            stale=False,
        )
        self.assertEqual(len(configs), 1)
        self.assertEqual(configs[0]._id, config._id)
 def test_get_scheduled_report_response(self):
     domain = self.domain
     report_config = ReportConfig.wrap({
         "date_range": "last30",
         "days": 30,
         "domain": domain,
         "report_slug": "worker_activity",
         "report_type": "project_report",
         "owner_id": self.user._id,
     })
     report_config.save()
     report = ReportNotification(
         hour=12, minute=None, day=30, interval='monthly', config_ids=[report_config._id]
     )
     report.save()
     response = get_scheduled_report_response(
         couch_user=self.user, domain=domain, scheduled_report_id=report._id
     )[0]
     self.assertTrue(self.user.username in response.decode('utf-8'))
 def test_get_scheduled_report_response(self):
     domain = self.domain
     report_config = ReportConfig.wrap({
         "date_range": "last30",
         "days": 30,
         "domain": domain,
         "report_slug": "worker_activity",
         "report_type": "project_report",
         "owner_id": self.user._id,
     })
     report_config.save()
     report = ReportNotification(hour=12,
                                 minute=None,
                                 day=30,
                                 interval='monthly',
                                 config_ids=[report_config._id])
     report.save()
     response = get_scheduled_report_response(
         couch_user=self.user,
         domain=domain,
         scheduled_report_id=report._id)[0]
     self.assertTrue(self.user.username in response.decode('utf-8'))
Exemple #29
0
def send_email_report(self, recipient_emails, domain, report_slug, report_type,
                      request_data, once, cleaned_data):
    """
    Function invokes send_HTML_email to email the html text report.
    If the report is too large to fit into email then a download link is
    sent via email to download report
    :Parameter recipient_list:
            list of recipient to whom email is to be sent
    :Parameter domain:
            domain name
    :Parameter report_slug:
            report slug
    :Parameter report_type:
            type of the report
    :Parameter request_data:
            Dict containing request data
    :Parameter once
            boolean argument specifying whether the report is once off report
            or scheduled report
    :Parameter cleaned_data:
            Dict containing cleaned data from the submitted form
    """
    from corehq.apps.reports.views import _render_report_configs, render_full_report_notification

    user_id = request_data['couch_user']
    couch_user = CouchUser.get_by_user_id(user_id)
    mock_request = HttpRequest()

    mock_request.method = 'GET'
    mock_request.GET = request_data['GET']

    config = ReportConfig()

    # see ReportConfig.query_string()
    object.__setattr__(config, '_id', 'dummy')
    config.name = _("Emailed report")
    config.report_type = report_type
    config.report_slug = report_slug
    config.owner_id = user_id
    config.domain = domain

    config.start_date = request_data['datespan'].startdate.date()
    if request_data['datespan'].enddate:
        config.date_range = 'range'
        config.end_date = request_data['datespan'].enddate.date()
    else:
        config.date_range = 'since'

    GET = dict(six.iterlists(request_data['GET']))
    exclude = ['startdate', 'enddate', 'subject', 'send_to_owner', 'notes', 'recipient_emails']
    filters = {}
    for field in GET:
        if field not in exclude:
            filters[field] = GET.get(field)

    config.filters = filters

    subject = cleaned_data['subject'] or _("Email report from CommCare HQ")

    try:
        content = _render_report_configs(
            mock_request, [config], domain, user_id, couch_user, True, lang=couch_user.language,
            notes=cleaned_data['notes'], once=once
        )[0]
        body = render_full_report_notification(None, content).content

        for recipient in recipient_emails:
            send_HTML_email(subject, recipient,
                            body, email_from=settings.DEFAULT_FROM_EMAIL,
                            smtp_exception_skip_list=LARGE_FILE_SIZE_ERROR_CODES)

    except Exception as er:
        notify_exception(
            None,
            message="Encountered error while generating report or sending email",
            details={
                'subject': subject,
                'recipients': str(recipient_emails),
                'error': er,
            }
        )
        if getattr(er, 'smtp_code', None) in LARGE_FILE_SIZE_ERROR_CODES or type(er) == ESError:
            # If the email doesn't work because it is too large to fit in the HTML body,
            # send it as an excel attachment.
            report_state = {
                'request': request_data,
                'request_params': json_request(request_data['GET']),
                'domain': domain,
                'context': {},
            }
            export_all_rows_task(config.report, report_state, recipient_list=recipient_emails)
        else:
            self.retry(exc=er)
Exemple #30
0
def send_email_report(self, recipient_emails, domain, report_slug, report_type,
                      request_data, once, cleaned_data):
    """
    Function invokes send_HTML_email to email the html text report.
    If the report is too large to fit into email then a download link is
    sent via email to download report
    :Parameter recipient_list:
            list of recipient to whom email is to be sent
    :Parameter domain:
            domain name
    :Parameter report_slug:
            report slug
    :Parameter report_type:
            type of the report
    :Parameter request_data:
            Dict containing request data
    :Parameter once
            boolean argument specifying whether the report is once off report
            or scheduled report
    :Parameter cleaned_data:
            Dict containing cleaned data from the submitted form
    """
    from corehq.apps.reports.views import _render_report_configs, render_full_report_notification

    user_id = request_data['couch_user']
    couch_user = CouchUser.get_by_user_id(user_id)
    mock_request = HttpRequest()

    mock_request.method = 'GET'
    mock_request.GET = request_data['GET']

    config = ReportConfig()

    # see ReportConfig.query_string()
    object.__setattr__(config, '_id', 'dummy')
    config.name = _("Emailed report")
    config.report_type = report_type
    config.report_slug = report_slug
    config.owner_id = user_id
    config.domain = domain

    config.start_date = request_data['datespan'].startdate.date()
    if request_data['datespan'].enddate:
        config.date_range = 'range'
        config.end_date = request_data['datespan'].enddate.date()
    else:
        config.date_range = 'since'

    GET = dict(six.iterlists(request_data['GET']))
    exclude = [
        'startdate', 'enddate', 'subject', 'send_to_owner', 'notes',
        'recipient_emails'
    ]
    filters = {}
    for field in GET:
        if field not in exclude:
            filters[field] = GET.get(field)

    config.filters = filters

    subject = cleaned_data['subject'] or _("Email report from CommCare HQ")

    content = _render_report_configs(mock_request, [config],
                                     domain,
                                     user_id,
                                     couch_user,
                                     True,
                                     lang=couch_user.language,
                                     notes=cleaned_data['notes'],
                                     once=once)[0]
    body = render_full_report_notification(None, content).content

    try:
        for recipient in recipient_emails:
            send_HTML_email(
                subject,
                recipient,
                body,
                email_from=settings.DEFAULT_FROM_EMAIL,
                smtp_exception_skip_list=LARGE_FILE_SIZE_ERROR_CODES)

    except Exception as er:
        if getattr(er, 'smtp_code', None) in LARGE_FILE_SIZE_ERROR_CODES:
            # If the smtp server rejects the email because of its large size.
            # Then sends the report download link in the email.
            report_state = {
                'request': request_data,
                'request_params': json_request(request_data['GET']),
                'domain': domain,
                'context': {},
            }
            export_all_rows_task(config.report,
                                 report_state,
                                 recipient_list=recipient_emails)
        else:
            self.retry(exc=er)
Exemple #31
0
 def test_domain_does_not_have_shared_configs(self):
     self.assertEqual(len(ReportConfig.shared_on_domain(self.DOMAIN)), 0)
Exemple #32
0
 def create_report_config(self, domain, owner_id, **kwargs):
     rc = ReportConfig(domain=domain, owner_id=owner_id, **kwargs)
     rc.save()
     self.addCleanup(rc.delete)
     return rc