Example #1
0
 def _create_report(self, domain=None, owner_id=None):
     domain = domain or self.domain
     owner_id = owner_id or self.user._id
     report = ReportNotification(domain=domain, owner_id=owner_id)
     report.save()
     self.addCleanup(report.delete)
     return report
Example #2
0
    def test_owner_can_delete_report(self, mock_success):
        report = self._create_report(owner_id=self.user._id)

        response = self.delete_scheduled_report(user=self.user,
                                                report_id=report._id)
        self.assertEqual(response.status_code, 302)
        with self.assertRaises(ResourceNotFound):
            ReportNotification.get(report._id)
Example #3
0
 def testIntervalReportDontIncludeOtherIntervals(self):
     ReportNotification(hour=1, minute=0, interval='hourly').save()
     ReportNotification(hour=1, minute=0, interval='daily').save()
     ReportNotification(hour=12, minute=0, day=4, interval='weekly').save()
     ReportNotification(hour=1, minute=0, interval='monthly').save()
     self._check('hourly', datetime(2014, 10, 1, 1, 0), 1)
     self._check('daily', datetime(2014, 10, 1, 1, 0), 1)
     self._check('weekly', datetime(2014, 10, 31, 12, 0), 1)
     self._check('monthly', datetime(2014, 10, 1, 1, 0), 1)
Example #4
0
    def test_domain_admin_can_delete_report(self, mock_success):
        domain_admin = self._create_user(username='******',
                                         is_admin=True)
        report = self._create_report(owner_id=self.user._id)

        response = self.delete_scheduled_report(user=domain_admin,
                                                report_id=report._id)
        self.assertEqual(response.status_code, 302)
        with self.assertRaises(ResourceNotFound):
            ReportNotification.get(report._id)
Example #5
0
 def _create_scheduled_report(self,
                              domain=None,
                              owner_id=None,
                              config_ids=[]):
     report = ReportNotification(domain=domain,
                                 owner_id=owner_id,
                                 config_ids=config_ids)
     report.save()
     self.addCleanup(report.delete)
     return report
Example #6
0
 def create_report_notification(self, configs, owner_id):
     domain = configs[0].domain
     config_ids = [c._id for c in configs]
     rn = ReportNotification(
         domain=domain,
         config_ids=config_ids,
         owner_id=owner_id,
         interval='daily',
     )
     rn.save()
     self.addCleanup(rn.delete)
     return rn
def delete_all_report_notifications():
    for report in ReportNotification.view(
            'reportconfig/all_notifications',
            include_docs=True,
            reduce=False,
    ).all():
        report.delete()
def delete_all_report_notifications():
    for report in ReportNotification.view(
            'reportconfig/all_notifications',
            include_docs=True,
            reduce=False,
    ).all():
        report.delete()
Example #9
0
def get_reports_by_domain(domain):
    key = [domain]
    reports = ReportNotification.view('reportconfig/user_notifications',
                                      reduce=False,
                                      include_docs=True,
                                      startkey=key,
                                      endkey=key + [{}])
    return reports
 def testDailyReportLenientWindow(self):
     ReportNotification(hour=12, minute=0, interval='daily').save()
     self._check('daily', datetime(2014, 10, 31, 12, 5),
                 1)  # lenient window
     # but not too lenient
     self.assertRaises(
         ValueError, lambda: list(
             get_scheduled_report_ids(
                 'daily', end_datetime=datetime(2014, 10, 31, 12, 6))))
 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'))
Example #12
0
def send_report(notification_id):
    notification = ReportNotification.get(notification_id)

    # If the report's start date is later than today, return and do not send the email
    if notification.start_date and notification.start_date > datetime.today().date():
        return

    try:
        notification.send()
    except UnsupportedScheduledReportError:
        pass
 def testDefaultValue(self):
     now = datetime.utcnow()
     # This line makes sure that the date of the ReportNotification is an increment of 15 minutes
     ReportNotification(hour=now.hour,
                        minute=(now.minute // 15) * 15,
                        interval='daily').save()
     if now.minute % 15 <= 5:
         self._check('daily', None, 1)
     else:
         self.assertRaises(
             ValueError,
             lambda: list(get_scheduled_report_ids('daily', None)))
Example #14
0
def send_report(notification_id):
    notification = ReportNotification.get(notification_id)

    # If the report's start date is later than today, return and do not send the email
    if notification.start_date and notification.start_date > datetime.today(
    ).date():
        return

    try:
        notification.send()
    except UnsupportedScheduledReportError:
        pass
 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'))
Example #16
0
def send_delayed_report(report_id):
    """
    Sends a scheduled report, via celery background task.
    """
    domain = ReportNotification.get(report_id).domain
    if (settings.SERVER_ENVIRONMENT == 'production' and any(
            re.match(pattern, domain)
            for pattern in settings.THROTTLE_SCHED_REPORTS_PATTERNS)):
        # This is to prevent a few scheduled reports from clogging up
        # the background queue.
        # https://manage.dimagi.com/default.asp?270029#BugEvent.1457969
        send_report_throttled.delay(report_id)
    else:
        send_report.delay(report_id)
Example #17
0
def send_delayed_report(report_id):
    """
    Sends a scheduled report, via celery background task.
    """
    domain = ReportNotification.get(report_id).domain
    if (
        settings.SERVER_ENVIRONMENT == 'production' and
        any(re.match(pattern, domain) for pattern in settings.THROTTLE_SCHED_REPORTS_PATTERNS)
    ):
        # This is to prevent a few scheduled reports from clogging up
        # the background queue.
        # https://manage.dimagi.com/default.asp?270029#BugEvent.1457969
        send_report_throttled.delay(report_id)
    else:
        send_report.delay(report_id)
Example #18
0
def get_scheduled_report_ids(period, as_of=None):
    as_of = as_of or datetime.utcnow()
    assert period in ('daily', 'weekly', 'monthly'), period

    def _keys(period, as_of):
        minute = guess_reporting_minute(as_of)
        if minute == 0:
            # for legacy purposes, on the hour also include reports that didn't have a minute set
            minutes = (None, minute)
        else:
            minutes = (minute, )

        if period == 'daily':
            for minute in minutes:
                yield {
                    'startkey': [period, as_of.hour, minute],
                    'endkey': [period, as_of.hour, minute, {}],
                }
        elif period == 'weekly':
            for minute in minutes:
                yield {
                    'key': [period, as_of.hour, minute,
                            as_of.weekday()],
                }
        else:
            # monthly
            for minute in minutes:
                yield {'key': [period, as_of.hour, minute, as_of.day]}
            if as_of.day == monthrange(as_of.year, as_of.month)[1]:
                for day in range(as_of.day + 1, 32):
                    for minute in minutes:
                        yield {'key': [period, as_of.hour, minute, day]}

    try:
        keys = _keys(period, as_of)
    except ValueError:
        _soft_assert(
            False,
            "Celery was probably down for a while. Lots of reports are getting dropped!"
        )
        raise StopIteration

    for key in keys:
        for result in ReportNotification.view("reportconfig/all_notifications",
                                              reduce=False,
                                              include_docs=False,
                                              **key).all():
            yield result['id']
Example #19
0
def get_scheduled_report_ids(period, start_datetime=None, end_datetime=None):
    end_datetime = end_datetime or datetime.utcnow()
    assert period in ('daily', 'weekly', 'monthly'), period
    if not start_datetime:
        start_datetime = _get_default_start_datetime(end_datetime)

    for target_point_in_time in _iter_15_minute_marks_in_range(
            start_datetime, end_datetime):
        keys = _make_all_notification_view_keys(period, target_point_in_time)
        for key in keys:
            for result in ReportNotification.view(
                    "reportconfig/all_notifications",
                    reduce=False,
                    include_docs=False,
                    **key).all():
                yield result['id']
Example #20
0
def get_scheduled_report_ids(period, start_datetime=None, end_datetime=None):
    end_datetime = end_datetime or datetime.utcnow()
    assert period in ('daily', 'weekly', 'monthly'), period
    if not start_datetime:
        start_datetime = _get_default_start_datetime(end_datetime)

    for target_point_in_time in _iter_15_minute_marks_in_range(start_datetime, end_datetime):
        keys = _make_all_notification_view_keys(period, target_point_in_time)
        for key in keys:
            for result in ReportNotification.view(
                "reportconfig/all_notifications",
                reduce=False,
                include_docs=False,
                **key
            ).all():
                yield result['id']
 def testMonthlyReportOnTheEndOfTheMonthDaysAfter31DontCount(self):
     ReportNotification(hour=12, minute=None, day=31,
                        interval='monthly').save()
     ReportNotification(hour=12, minute=None, day=32,
                        interval='monthly').save()
     self._check('monthly', datetime(2014, 10, 31, 12, 0), 1)
 def testMonthlyReportBeforeTheEndOfTheMonth(self):
     ReportNotification(hour=12, minute=None, day=30,
                        interval='monthly').save()
     ReportNotification(hour=12, minute=None, day=31,
                        interval='monthly').save()
     self._check('monthly', datetime(2014, 10, 30, 12, 0), 1)
 def testDailyReportWithMinute(self):
     ReportNotification(hour=12, minute=0, interval='daily').save()
     self._check('daily', datetime(2014, 10, 31, 12, 0), 1)
     self._check('daily', datetime(2014, 10, 31, 12, 30), 0)
 def testDailyReportOtherHoursDontCount(self):
     ReportNotification(hour=12, minute=0, day=31, interval='daily').save()
     self._check('daily', datetime(2014, 10, 31, 11, 0), 0)
Example #25
0
 def testHourlyReportWithoutMinute(self):
     # We don't currently cater for minute-specific hourly reporting;
     # every report with 'hourly' interval will be sent on the zero-minute hour
     ReportNotification(hour=1, minute=None, interval='hourly').save()
     self._check('hourly', datetime(2014, 10, 31, 1, 0), 1)
Example #26
0
 def testHourlyReportOtherTypesDontCount(self):
     ReportNotification(hour=1, minute=0, interval='hourly').save()
     self._check('daily', datetime(2014, 10, 31, 1, 0), 0)
     self._check('weekly', datetime(2014, 10, 31, 1, 0), 0)
     self._check('monthly', datetime(2014, 10, 31, 1, 0), 0)
Example #27
0
 def testHourlyReportHourDontMatter(self):
     ReportNotification(hour=1, minute=0, interval='hourly').save()
     self._check('hourly', datetime(2014, 10, 31, 1, 0), 1)
     self._check('hourly', datetime(2014, 10, 31, 12, 0), 1)
     self._check('hourly', datetime(2014, 10, 31, 23, 0), 1)
 def testDailyReportEmptyMinute(self):
     ReportNotification(hour=12, minute=None, interval='daily').save()
     self._check('daily', datetime(2014, 10, 31, 12, 0), 1)
     self._check('daily', datetime(2014, 10, 31, 12, 30),
                 0)  # half hour shouldn't count
 def testWeeklyReportOtherDaysDontCount(self):
     ReportNotification(hour=12, minute=0, day=4, interval='weekly').save()
     self._check('weekly', datetime(2014, 10, 30, 12, 0), 0)
 def testMonthlyReportOtherDaysDontCount(self):
     ReportNotification(hour=12, minute=None, day=31,
                        interval='monthly').save()
     self._check('monthly', datetime(2014, 10, 30, 12, 0), 0)
 def testMonthlyReportOnTheEndOfTheMonthEmptyMinute(self):
     ReportNotification(hour=12, minute=None, day=30,
                        interval='monthly').save()
     ReportNotification(hour=12, minute=None, day=31,
                        interval='monthly').save()
     self._check('monthly', datetime(2014, 11, 30, 12, 0), 2)
Example #32
0
class ScheduledReportForm(forms.Form):
    INTERVAL_CHOICES = [("daily", "Daily"), ("weekly", "Weekly"),
                        ("monthly", "Monthly")]

    config_ids = forms.MultipleChoiceField(
        label=_("Saved report(s)"),
        validators=[MinLengthValidator(1)],
        help_text='Note: not all built-in reports support email delivery, so'
        ' some of your saved reports may not appear in this list')

    interval = forms.TypedChoiceField(label=_('Interval'),
                                      widget=SelectToggle(
                                          choices=INTERVAL_CHOICES,
                                          apply_bindings=True),
                                      choices=INTERVAL_CHOICES)

    day = forms.TypedChoiceField(label=_("Day"),
                                 coerce=int,
                                 required=False,
                                 choices=[(i, i) for i in range(0, 32)])

    hour = forms.TypedChoiceField(label=_('Time'),
                                  coerce=int,
                                  choices=ReportNotification.hour_choices())

    start_date = forms.DateField(label=_('Report Start Date'), required=False)

    send_to_owner = forms.BooleanField(label=_('Send to owner'),
                                       required=False)

    attach_excel = forms.BooleanField(label=_('Attach Excel Report'),
                                      required=False)

    recipient_emails = MultiEmailField(label=_('Other recipients'),
                                       required=False)
    email_subject = forms.CharField(
        required=False,
        help_text=
        'Translated into recipient\'s language if set to "%(default_subject)s".'
        % {
            'default_subject': DEFAULT_REPORT_NOTIF_SUBJECT,
        },
    )

    language = forms.ChoiceField(label=_('Language'),
                                 required=False,
                                 choices=[('', '')] +
                                 langcodes.get_all_langs_for_select(),
                                 widget=forms.Select())

    def __init__(self, *args, **kwargs):
        self.helper = FormHelper()
        self.helper.form_class = 'form-horizontal'
        self.helper.form_id = 'id-scheduledReportForm'
        self.helper.label_class = 'col-sm-3 col-md-2'
        self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6'
        self.helper.add_layout(
            crispy.Layout(
                crispy.Fieldset(
                    ugettext("Configure Scheduled Report"), 'config_ids',
                    'interval', 'day', 'hour', 'start_date',
                    crispy.Field(
                        'email_subject',
                        css_class='input-xlarge',
                    ), crispy.Field('send_to_owner'),
                    crispy.Field('attach_excel'), 'recipient_emails',
                    'language',
                    crispy.HTML(
                        render_to_string(
                            'reports/partials/privacy_disclaimer.html'))),
                FormActions(crispy.Submit('submit_btn', 'Submit'))))

        super(ScheduledReportForm, self).__init__(*args, **kwargs)

    def clean(self):
        cleaned_data = super(ScheduledReportForm, self).clean()
        if cleaned_data["interval"] == "daily":
            del cleaned_data["day"]
        _verify_email(cleaned_data)
        return cleaned_data
 def testMonthlyReportOnTheEndOfTheMonthWithMinuteHalfHour(self):
     ReportNotification(hour=12, minute=30, day=30,
                        interval='monthly').save()
     ReportNotification(hour=12, minute=30, day=31,
                        interval='monthly').save()
     self._check('monthly', datetime(2014, 11, 30, 12, 30), 2)
Example #34
0
 def testHourlyReportWithMinuteZero(self):
     ReportNotification(hour=1, minute=0, interval='hourly').save()
     self._check('hourly', datetime(2014, 10, 31, 1, 0), 1)
     self._check('hourly', datetime(2014, 10, 31, 1, 30), 0)
Example #35
0
    def test_scheduled_reports_identified(self):
        point_1 = datetime.datetime(2019, 3, 22, 22, 46, 0, 439979)
        # target point in time: datetime.datetime(2019, 3, 22, 23, 0, 0, 0)
        point_2 = datetime.datetime(2019, 3, 22, 23, 11, 38, 363898)
        test_cases = [
            ('daily minute None', True,
             ReportNotification(hour=23, minute=None, interval='daily')),
            ('daily minute 0', True,
             ReportNotification(hour=23, minute=0, interval='daily')),
            ('daily minute off', False,
             ReportNotification(hour=23, minute=15, interval='daily')),
            ('daily hour off', False,
             ReportNotification(hour=22, minute=0, interval='daily')),
            ('weekly minute None', True,
             ReportNotification(hour=23, minute=None, day=4,
                                interval='weekly')),
            ('weekly minute 0', True,
             ReportNotification(hour=23, minute=0, day=4, interval='weekly')),
            ('weekly minute off', False,
             ReportNotification(hour=23, minute=15, day=4, interval='weekly')),
            ('weekly hour off', False,
             ReportNotification(hour=22, minute=0, day=4, interval='weekly')),
            ('weekly day off', False,
             ReportNotification(hour=22, minute=0, day=3, interval='weekly')),
            ('monthly minute None', True,
             ReportNotification(hour=23,
                                minute=None,
                                day=22,
                                interval='monthly')),
            ('monthly minute 0', True,
             ReportNotification(hour=23, minute=0, day=22,
                                interval='monthly')),
            ('monthly minute off', False,
             ReportNotification(hour=23, minute=15, day=22,
                                interval='monthly')),
            ('monthly hour off', False,
             ReportNotification(hour=22, minute=0, day=22,
                                interval='monthly')),
            ('monthly day off', False,
             ReportNotification(hour=22, minute=0, day=20,
                                interval='monthly')),
        ]

        create_records_for_scheduled_reports(fake_now_for_tests=point_1)

        for _, _, report in test_cases:
            report.save()

        report_ids = create_records_for_scheduled_reports(
            fake_now_for_tests=point_2)

        for description, should_fire, report in test_cases:
            if should_fire:
                self.assertIn(
                    report._id, report_ids,
                    "{}: should have fired but didn't".format(description))
            else:
                self.assertNotIn(
                    report._id, report_ids,
                    "{}: shouldn't have fired but did".format(description))