Example #1
0
    def test_repeater_failed_sends(self):
        """
        This tests records that fail to send three times
        """
        def now():
            return datetime.utcnow()

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=now())
        self.assertEqual(len(repeat_records), 2)

        for repeat_record in repeat_records:
            with patch(
                    'corehq.apps.repeaters.models.simple_post_with_cached_timeout',
                    return_value=MockResponse(status_code=404)) as mock_post:
                repeat_record.fire()
                self.assertEqual(mock_post.call_count, 3)
            repeat_record.save()

        next_check_time = now() + timedelta(minutes=60)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=now() + timedelta(minutes=15),
        )
        self.assertEqual(len(repeat_records), 0)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=next_check_time,
        )
        self.assertEqual(len(repeat_records), 2)
Example #2
0
 def setUpClass(cls):
     cls.records = [
         RepeatRecord(domain='a'),
         RepeatRecord(domain='b'),
         RepeatRecord(domain='c'),
     ]
     RepeatRecord.bulk_save(cls.records)
Example #3
0
    def test_repeater_successful_send(self):

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())

        for repeat_record in repeat_records:
            with patch(
                    'corehq.apps.repeaters.models.simple_post',
                    return_value=MockResponse(status_code=200, reason='No Reason')) as mock_post:
                repeat_record.fire()
                self.assertEqual(mock_post.call_count, 1)
                mock_post.assert_any_call(
                    repeat_record.get_payload(),
                    repeat_record.repeater.get_url(repeat_record),
                    headers=repeat_record.repeater.get_headers(repeat_record),
                    timeout=POST_TIMEOUT,
                    auth=repeat_record.repeater.get_auth(),
                )

        # The following is pretty fickle and depends on which of
        #   - corehq.apps.repeaters.signals
        #   - casexml.apps.case.signals
        # gets loaded first.
        # This is deterministic but easily affected by minor code changes
        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=datetime.utcnow(),
        )
        for repeat_record in repeat_records:
            self.assertEqual(repeat_record.succeeded, True)
            self.assertEqual(repeat_record.next_check, None)

        self.assertEqual(len(self.repeat_records(self.domain)), 0)

        self.post_xml(self.update_xform_xml, self.domain)
        self.assertEqual(len(self.repeat_records(self.domain)), 2)
Example #4
0
    def test_repeater_failed_sends(self):
        """
        This tests records that fail are requeued later
        """
        def now():
            return datetime.utcnow()

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=now())
        self.assertEqual(len(repeat_records), 2)

        for repeat_record in repeat_records:
            with patch(
                    'corehq.apps.repeaters.models.simple_post',
                    return_value=MockResponse(status_code=404, reason='Not Found')) as mock_post:
                repeat_record.fire()
                self.assertEqual(mock_post.call_count, 1)

        next_check_time = now() + timedelta(minutes=60)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=now() + timedelta(minutes=15),
        )
        self.assertEqual(len(repeat_records), 0)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=next_check_time,
        )
        self.assertEqual(len(repeat_records), 2)
Example #5
0
    def test_repeat_record_created(self):
        '''
        Tests that whenever an application with a repeater is saved that a repeat record is created.
        '''
        application = Application(domain=self.domain)
        application.save()

        repeat_records = RepeatRecord.all(domain=self.domain,
                                          due_before=datetime.utcnow())
        self.assertEqual(len(repeat_records), 0)

        app_structure_repeater = AppStructureRepeater(domain=self.domain,
                                                      url=self.forwarding_url)
        app_structure_repeater.save()

        application.save()
        repeat_records = RepeatRecord.all(domain=self.domain,
                                          due_before=datetime.utcnow())

        self.assertEqual(len(repeat_records), 1)
        for repeat_record in repeat_records:
            self.assertEqual(repeat_record.url, self.forwarding_url)
            self.assertEqual(repeat_record.get_payload(), application.get_id)
            repeat_record.delete()

        application.delete()
        app_structure_repeater.delete()
Example #6
0
    def test_repeat_record_status_check(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        # Do not trigger cancelled records
        for repeat_record in RepeatRecord.all():
            repeat_record.cancelled = True
            repeat_record.save()
        with patch('corehq.apps.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)

        # trigger force send records if not cancelled and tries not exhausted
        for repeat_record in RepeatRecord.all():
            with patch('corehq.apps.repeaters.models.simple_post',
                       return_value=MockResponse(status_code=200, reason='')
                       ) as mock_fire:
                repeat_record.fire(force_send=True)
                self.assertEqual(mock_fire.call_count, 1)

        # all records should be in SUCCESS state after force try
        for repeat_record in RepeatRecord.all():
                self.assertEqual(repeat_record.state, RECORD_SUCCESS_STATE)
                self.assertEqual(repeat_record.overall_tries, 1)

        # not trigger records succeeded triggered after cancellation
        with patch('corehq.apps.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)
            for repeat_record in RepeatRecord.all():
                self.assertEqual(repeat_record.state, RECORD_SUCCESS_STATE)
Example #7
0
    def test_get_all_repeat_records_by_domain_since(self):
        new_records = [
            # FAIL
            RepeatRecord(
                domain=self.domain,
                repeater_id=self.repeater_id,
                last_checked=datetime(2017, 5, 24, 0, 0, 0),
                failure_reason='some error',
            ),
            # CANCELLED
            RepeatRecord(
                domain=self.domain,
                repeater_id=self.repeater_id,
                last_checked=datetime(2017, 5, 10, 0, 0, 0),
                cancelled=True,
            ),
            # CANCELLED
            RepeatRecord(
                domain=self.domain,
                repeater_id=self.repeater_id,
                last_checked=datetime(2017, 5, 24, 0, 0, 0),
                cancelled=True,
            ),
        ]
        RepeatRecord.bulk_save(new_records)
        self.addCleanup(RepeatRecord.bulk_delete, new_records)

        records = list(
            iter_repeat_records_by_domain(self.domain,
                                          state=RECORD_CANCELLED_STATE,
                                          since=datetime(2017, 5, 20)))
        self.assertEqual(len(records), 1)
        record, = records
        self.assertEqual(record.to_json(), new_records[-1].to_json())
Example #8
0
    def test_update_failure_next_check(self):
        now = datetime.utcnow()
        record = RepeatRecord(domain=self.domain, next_check=now)
        self.assertIsNone(record.last_checked)

        record.update_failure()
        self.assertTrue(record.last_checked > now)
        self.assertEqual(record.next_check, record.last_checked + MIN_RETRY_WAIT)
    def test_update_failure_next_check(self):
        now = datetime.utcnow()
        record = RepeatRecord(domain=self.domain, next_check=now)
        self.assertIsNone(record.last_checked)

        record.set_next_try()
        self.assertTrue(record.last_checked > now)
        self.assertEqual(record.next_check, record.last_checked + MIN_RETRY_WAIT)
Example #10
0
    def test_update_failure_next_check(self):
        now = datetime.utcnow()
        record = RepeatRecord(domain=self.domain, next_check=now)
        self.assertIsNone(record.last_checked)

        attempt = record.make_set_next_try_attempt(None)
        record.add_attempt(attempt)
        self.assertTrue(record.last_checked > now)
        self.assertEqual(record.next_check, record.last_checked + MIN_RETRY_WAIT)
Example #11
0
 def testLocks(self):
     r = RepeatRecord(domain='test')
     r.save()
     r2 = RepeatRecord.get(r._id)
     self.assertTrue(r.acquire_lock(datetime.utcnow()))
     r3 = RepeatRecord.get(r._id)
     self.assertFalse(r2.acquire_lock(datetime.utcnow()))
     self.assertFalse(r3.acquire_lock(datetime.utcnow()))
     r.release_lock()
     r4 = RepeatRecord.get(r._id)
     self.assertTrue(r4.acquire_lock(datetime.utcnow()))
Example #12
0
 def test_skip_device_logs(self):
     devicelog_xml = XFORM_XML_TEMPLATE.format(DEVICE_LOG_XMLNS, USER_ID,
                                               '1234', '')
     self.post_xml(devicelog_xml, self.domain)
     repeat_records = RepeatRecord.all(domain=self.domain)
     for repeat_record in repeat_records:
         self.assertNotEqual(repeat_record.payload_id, '1234')
Example #13
0
 def tearDown(self):
     self.case_repeater.delete()
     self.form_repeater.delete()
     XFormInstance.get(instance_id).delete()
     repeat_records = RepeatRecord.all()
     for repeat_record in repeat_records:
         repeat_record.delete()
Example #14
0
def check_repeaters(request, domain):
    if request.method == 'GET':
        return HttpResponse(PAGE % {'status': '', 'domain': domain})
    elif request.method == 'POST':
        start = datetime.utcnow()
        repeat_records = RepeatRecord.all(domain, due_before=start, limit=100)
        process_repeater_list(repeat_records)
        return HttpResponse(PAGE % {'status': 'Done', 'domain': domain})
Example #15
0
 def post(self, request, domain):
     # Retriggers a repeat record
     record = RepeatRecord.get(request.POST.get('record_id'))
     record.fire(max_tries=1, force_send=True)
     return json_response({
         'success': record.succeeded,
         'failure_reason': record.failure_reason,
     })
Example #16
0
 def post(self, request, domain):
     # Retriggers a repeat record
     record = RepeatRecord.get(request.POST.get('record_id'))
     record.fire(max_tries=1, force_send=True)
     record.save()
     return json_response({
         'success': record.succeeded,
         'failure_reason': record.failure_reason,
     })
Example #17
0
    def setUpClass(cls):
        before = datetime.utcnow() - timedelta(minutes=5)

        failed = RepeatRecord(
            domain=cls.domain,
            failure_reason='Some python error',
            repeater_id=cls.repeater_id,
            next_check=before,
        )
        success = RepeatRecord(
            domain=cls.domain,
            succeeded=True,
            repeater_id=cls.repeater_id,
            next_check=before,
        )
        pending = RepeatRecord(
            domain=cls.domain,
            succeeded=False,
            repeater_id=cls.repeater_id,
            next_check=before,
        )
        overdue = RepeatRecord(
            domain=cls.domain,
            succeeded=False,
            repeater_id=cls.repeater_id,
            next_check=before - timedelta(minutes=10),
        )
        other_id = RepeatRecord(
            domain=cls.domain,
            succeeded=False,
            repeater_id=cls.other_id,
            next_check=before,
        )

        cls.records = [
            failed,
            success,
            pending,
            overdue,
            other_id,
        ]

        for record in cls.records:
            record.save()
Example #18
0
    def test_process_repeat_record_locking(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        with patch('corehq.apps.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 2)

        with patch('corehq.apps.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 0)

        records = RepeatRecord.all()
        # Saving should unlock them again by changing the rev
        for record in records:
            record.save()

        with patch('corehq.apps.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 2)
Example #19
0
    def test_check_repeat_records(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        with patch('corehq.apps.repeaters.models.simple_post_with_cached_timeout') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 2)

        with patch('corehq.apps.repeaters.models.simple_post_with_cached_timeout') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)
Example #20
0
    def test_process_repeat_record_locking(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        with patch('corehq.apps.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 2)

        with patch('corehq.apps.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 0)

        records = RepeatRecord.all()
        # Saving should unlock them again by changing the rev
        for record in records:
            record.save()

        with patch('corehq.apps.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 2)
Example #21
0
    def test_ignore_document(self):
        """
        When get_payload raises IgnoreDocument, fire should call update_success
        """
        repeat_records = RepeatRecord.all(domain=self.domain, )
        for repeat_record_ in repeat_records:
            repeat_record_.fire()

            self.assertIsNone(repeat_record_.next_check)
            self.assertTrue(repeat_record_.succeeded)
Example #22
0
    def get_record_or_404(request, domain, record_id):
        try:
            record = RepeatRecord.get(record_id)
        except ResourceNotFound:
            raise Http404()

        if record.domain != domain:
            raise Http404()

        return record
Example #23
0
    def test_check_repeat_records(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        with patch('corehq.apps.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 2)

        with patch('corehq.apps.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)
Example #24
0
    def handle(self, *args, **options):
        if len(args) == 1:
            domain = args[0]
        else:
            raise CommandError('Usage: %s\n%s' % (self.args, self.help))

        next_year = datetime.datetime.utcnow() + datetime.timedelta(days=365)
        records = RepeatRecord.all(domain=domain, due_before=next_year)
        for record in records:
            record.fire(post_fn=simple_post)
            record.save()
            print '{} {}'.format(record._id, 'successful' if record.succeeded else 'failed')
Example #25
0
    def handle(self, *args, **options):
        if len(args) == 1:
            domain = args[0]
        else:
            raise CommandError('Usage: %s\n%s' % (self.args, self.help))

        next_year = datetime.datetime.utcnow() + datetime.timedelta(days=365)
        records = RepeatRecord.all(domain=domain, due_before=next_year)
        for record in records:
            record.fire(post_fn=simple_post)
            print('{} {}'.format(
                record._id, 'successful' if record.succeeded else 'failed'))
Example #26
0
    def test_ignore_document(self):
        """
        When get_payload raises IgnoreDocument, fire should call update_success
        """
        repeat_records = RepeatRecord.all(
            domain=self.domain,
        )
        for repeat_record_ in repeat_records:
            repeat_record_.fire()

            self.assertIsNone(repeat_record_.next_check)
            self.assertTrue(repeat_record_.succeeded)
Example #27
0
    def test_repeater_successful_send(self):

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())
        mocked_responses = [
            MockResponse(status_code=404, reason='Not Found'),
            MockResponse(status_code=200, reason='No Reason')
        ]
        for repeat_record in repeat_records:
            with patch(
                    'corehq.apps.repeaters.models.simple_post_with_cached_timeout',
                    side_effect=mocked_responses) as mock_post:
                repeat_record.fire()
                self.assertEqual(mock_post.call_count, 2)
                mock_post.assert_any_call(
                    repeat_record.get_payload(),
                    repeat_record.repeater.get_url(repeat_record),
                    headers=repeat_record.repeater.get_headers(repeat_record),
                    force_send=False,
                    timeout=POST_TIMEOUT,
                )
            repeat_record.save()

        # The following is pretty fickle and depends on which of
        #   - corehq.apps.repeaters.signals
        #   - casexml.apps.case.signals
        # gets loaded first.
        # This is deterministic but easily affected by minor code changes
        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=datetime.utcnow(),
        )
        for repeat_record in repeat_records:
            self.assertEqual(repeat_record.succeeded, True)
            self.assertEqual(repeat_record.next_check, None)

        self.assertEqual(len(self.repeat_records(self.domain)), 0)

        self.post_xml(self.update_xform_xml, self.domain)
        self.assertEqual(len(self.repeat_records(self.domain)), 2)
Example #28
0
    def test_repeat_record_created(self):
        '''
        Tests that whenever an application with a repeater is saved that a repeat record is created.
        '''
        application = Application(domain=self.domain)
        application.save()

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())
        self.assertEqual(len(repeat_records), 0)
        
        app_structure_repeater = AppStructureRepeater(domain=self.domain, url=self.forwarding_url)
        app_structure_repeater.save()

        application.save()
        repeat_records = RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())

        self.assertEqual(len(repeat_records), 1)
        for repeat_record in repeat_records:
                self.assertEqual(repeat_record.url, self.forwarding_url)
                self.assertEqual(repeat_record.get_payload(), application.get_id)
                repeat_record.delete()
        
        application.delete()
        app_structure_repeater.delete()
Example #29
0
 def setUp(self):
     super(TestBetsResponseHandling, self).setUp()
     user = CommCareUser.create(
         self.domain,
         "*****@*****.**",
         "123",
     )
     self.repeater = BETSUserRepeater(
         domain=self.domain,
         url='super-cool-url',
     )
     self.repeater.save()
     self.repeat_record = RepeatRecord(
         repeater_id=self.repeater.get_id,
         payload_id=user.user_id,
         next_check=datetime.utcnow(),
     )
Example #30
0
 def loop():
     # take LIMIT records off the top
     # the assumption is that they all get 'popped' in the for loop
     # the only exception I can see is if there's a problem with the
     # locking, a large number of locked tasks could pile up at the top,
     # so make a provision for that worst case
     number_locked = progress_report['number_locked']
     repeat_records = RepeatRecord.all(
         due_before=start,
         limit=LIMIT + number_locked
     )
     return process_repeater_list(
         repeat_records,
         start=start,
         cutoff=start + CHECK_REPEATERS_INTERVAL,
         progress_report=progress_report
     )
Example #31
0
    def test_ignore_document(self):
        """
        When get_payload raises IgnoreDocument, fire should call update_success
        """

        @RegisterGenerator(FormRepeater, 'new_format', 'XML')
        class NewFormGenerator(BasePayloadGenerator):
            def get_payload(self, repeat_record, payload_doc):
                raise IgnoreDocument

        repeat_records = RepeatRecord.all(
            domain=self.domain,
        )
        for repeat_record_ in repeat_records:
            repeat_record_.fire()

            self.assertIsNone(repeat_record_.next_check)
            self.assertTrue(repeat_record_.succeeded)
Example #32
0
    def get(self, request, domain):
        record = RepeatRecord.get(request.GET.get('record_id'))
        content_type = record.repeater.get_payload_generator(
            record.repeater.format_or_default_format()
        ).content_type
        try:
            payload = record.get_payload()
        except XFormNotFound:
            return json_response({
                'error': u'Odd, could not find payload for: {}'.format(record.payload_id)
            }, status_code=404)

        if content_type == 'text/xml':
            payload = indent_xml(payload)

        return json_response({
            'payload': payload,
            'content_type': content_type,
        })
Example #33
0
    def get(self, request, domain):
        record = RepeatRecord.get(request.GET.get('record_id'))
        content_type = record.repeater.get_payload_generator(
            record.repeater.format_or_default_format()
        ).content_type
        try:
            payload = record.get_payload()
        except XFormNotFound:
            return json_response({
                'error': u'Odd, could not find payload for: {}'.format(record.payload_id)
            }, status_code=404)

        if content_type == 'text/xml':
            payload = indent_xml(payload)
        elif content_type == 'application/json':
            payload = json.dumps(json.loads(payload), indent=4)

        return json_response({
            'payload': payload,
            'content_type': content_type,
        })
Example #34
0
 def handle(self, domain, **options):
     next_year = datetime.datetime.utcnow() + datetime.timedelta(days=365)
     records = RepeatRecord.all(domain=domain, due_before=next_year)
     for record in records:
         record.fire(post_fn=simple_post)
         print('{} {}'.format(record._id, 'successful' if record.succeeded else 'failed'))
Example #35
0
 def test_skip_device_logs(self):
     devicelog_xml = XFORM_XML_TEMPLATE.format(DEVICE_LOG_XMLNS, USER_ID, '1234', '')
     self.post_xml(devicelog_xml, self.domain)
     repeat_records = RepeatRecord.all(domain=self.domain)
     for repeat_record in repeat_records:
         self.assertNotEqual(repeat_record.payload_id, '1234')
Example #36
0
    def test_repeater(self):
        #  this test should probably be divided into more units

        CommCareCase.get(case_id)

        def now():
            return datetime.utcnow()

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=now())
        self.assertEqual(len(repeat_records), 2)

        self.clear_log()

        records_by_repeater_id = {}
        for repeat_record in repeat_records:
            repeat_record.fire(post_fn=self.make_post_fn([404, 404, 404]))
            repeat_record.save()
            records_by_repeater_id[repeat_record.repeater_id] = repeat_record

        for (url, status, data, headers) in self.log:
            self.assertEqual(status, 404)

        self.clear_log()

        next_check_time = now() + timedelta(minutes=60)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=now() + timedelta(minutes=15),
        )
        self.assertEqual(len(repeat_records), 0)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=next_check_time + timedelta(seconds=2),
        )
        self.assertEqual(len(repeat_records), 2)

        for repeat_record in repeat_records:
            self.assertLess(abs(next_check_time - repeat_record.next_check),
                            timedelta(seconds=3))
            repeat_record.fire(post_fn=self.make_post_fn([404, 200]))
            repeat_record.save()

        self.assertEqual(len(self.log), 4)

        # The following is pretty fickle and depends on which of
        #   - corehq.apps.repeaters.signals
        #   - casexml.apps.case.signals
        # gets loaded first.
        # This is deterministic but easily affected by minor code changes

        # check case stuff
        rec = records_by_repeater_id[self.case_repeater.get_id]
        self.assertEqual(self.log[1][:2], (self.case_repeater.get_url(rec), 200))
        self.assertIn('server-modified-on', self.log[1][3])
        check_xml_line_by_line(self, self.log[1][2], case_block)

        # check form stuff
        rec = records_by_repeater_id[self.form_repeater.get_id]
        self.assertEqual(self.log[3][:3],
                         (self.form_repeater.get_url(rec), 200, xform_xml))
        self.assertIn('received-on', self.log[3][3])

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=next_check_time,
        )
        for repeat_record in repeat_records:
            self.assertEqual(repeat_record.succeeded, True)
            self.assertEqual(repeat_record.next_check, None)

        self.assertEqual(len(self.repeat_records(self.domain)), 0)

        self.post_xml(update_xform_xml, self.domain)
        self.assertEqual(len(self.repeat_records(self.domain)), 2)
Example #37
0
 def tearDownClass(cls):
     RepeatRecord.bulk_delete(cls.records)
Example #38
0
 def tearDown(self):
     self.repeater.delete()
     repeat_records = RepeatRecord.all()
     for repeat_record in repeat_records:
         repeat_record.delete()
Example #39
0
 def test_skip_device_logs(self):
     devicelog_xml = xform_xml_template.format(DEVICE_LOG_XMLNS, '1234', '')
     self.post_xml(devicelog_xml, self.domain)
     repeat_records = RepeatRecord.all(domain=self.domain)
     for repeat_record in repeat_records:
         self.assertNotEqual(repeat_record.payload_id, '1234')
Example #40
0
 def repeat_records(self):
     return RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())
Example #41
0
 def repeat_records(cls, domain_name):
     return RepeatRecord.all(domain=domain_name, due_before=datetime.utcnow())
Example #42
0
 def repeat_records(cls, domain_name):
     return RepeatRecord.all(domain=domain_name, due_before=datetime.utcnow())