def test_reminder_delete(self): reminder = (CaseReminderHandler .create(self.domain, 'test') .set_case_criteria_start_condition('participant', 'status', MATCH_EXACT, 'green') .set_case_criteria_start_date() .set_case_recipient() .set_sms_content_type('en') .set_daily_schedule(fire_time=time(12, 0), message={'en': 'Hello {case.name}, your test result was normal.'}) .set_stop_condition(max_iteration_count=REPEAT_SCHEDULE_INDEFINITELY) .set_advanced_options()) reminder.save() r1 = CaseReminder(domain=self.domain, handler_id=reminder.get_id) r2 = CaseReminder(domain=self.domain, handler_id='abc') r3 = CaseReminder(domain='def', handler_id='ghi') r1.save() r2.save() r3.save() self.assertEqual(len(self.get_all_reminders()), 3) reminder.retire() self.assertEqual(len(self.get_all_reminders()), 2) r1 = CaseReminder.get(r1.get_id) r2 = CaseReminder.get(r2.get_id) r3 = CaseReminder.get(r3.get_id) self.assertEqual(r1.doc_type, 'CaseReminder-Deleted') self.assertEqual(r2.doc_type, 'CaseReminder') self.assertEqual(r3.doc_type, 'CaseReminder')
def get_reminder_domain(reminder_id): """ A reminder instance's domain should never change once set, so we can use a very long timeout. """ from corehq.apps.reminders.models import CaseReminder return CaseReminder.get(reminder_id).domain
def _fire_reminder(reminder_id): utcnow = datetime.utcnow() reminder = CaseReminder.get(reminder_id) # This key prevents doc update conflicts with rule running key = "rule-update-definition-%s-case-%s" % (reminder.handler_id, reminder.case_id) with CriticalSection([key], timeout=(settings.REMINDERS_QUEUE_PROCESSING_LOCK_TIMEOUT * 60)): # Refresh the reminder reminder = CaseReminder.get(reminder_id) if not reminder.retired and reminder.active and utcnow >= reminder.next_fire: handler = reminder.handler if reminder_is_stale(reminder, utcnow): handler.set_next_fire(reminder, utcnow) reminder.save() return if handler.fire(reminder): handler.set_next_fire(reminder, utcnow) reminder.save()
def reminders_in_error(request, domain): handler_map = {} if request.method == "POST": form = RemindersInErrorForm(request.POST) if form.is_valid(): kwargs = {} if is_bigcouch(): # Force a write to all nodes before returning kwargs["w"] = bigcouch_quorum_count() current_timestamp = datetime.utcnow() for reminder_id in form.cleaned_data.get("selected_reminders"): reminder = CaseReminder.get(reminder_id) if reminder.domain != domain: continue if reminder.handler_id in handler_map: handler = handler_map[reminder.handler_id] else: handler = reminder.handler handler_map[reminder.handler_id] = handler reminder.error = False reminder.error_msg = None handler.set_next_fire(reminder, current_timestamp) reminder.save(**kwargs) timezone = report_utils.get_timezone(request.couch_user.user_id, domain) reminders = [] for reminder in CaseReminder.view("reminders/reminders_in_error", startkey=[domain], endkey=[domain, {}], include_docs=True).all(): if reminder.handler_id in handler_map: handler = handler_map[reminder.handler_id] else: handler = reminder.handler handler_map[reminder.handler_id] = handler recipient = reminder.recipient case = reminder.case reminders.append({ "reminder_id": reminder._id, "handler_id": reminder.handler_id, "handler_name": handler.nickname, "case_id": case.get_id if case is not None else None, "case_name": case.name if case is not None else None, "next_fire": tz_utils.adjust_datetime_to_timezone( reminder.next_fire, pytz.utc.zone, timezone.zone).strftime("%Y-%m-%d %H:%M:%S"), "error_msg": reminder.error_msg, "recipient_name": get_recipient_name(recipient), })
def _fire_reminder(reminder_id): utcnow = datetime.utcnow() reminder = CaseReminder.get(reminder_id) # This key prevents doc update conflicts with rule running key = "rule-update-definition-%s-case-%s" % (reminder.handler_id, reminder.case_id) with CriticalSection([key], timeout=(settings.REMINDERS_QUEUE_PROCESSING_LOCK_TIMEOUT*60)): # Refresh the reminder reminder = CaseReminder.get(reminder_id) if (not reminder.retired and reminder.active and utcnow >= reminder.next_fire): handler = reminder.handler if reminder_is_stale(reminder, utcnow): handler.set_next_fire(reminder, utcnow) reminder.save() return if handler.fire(reminder): handler.set_next_fire(reminder, utcnow) reminder.save()
def reminders_in_error(request, domain): handler_map = {} if request.method == "POST": form = RemindersInErrorForm(request.POST) if form.is_valid(): kwargs = {} if is_bigcouch(): # Force a write to all nodes before returning kwargs["w"] = bigcouch_quorum_count() current_timestamp = datetime.utcnow() for reminder_id in form.cleaned_data.get("selected_reminders"): reminder = CaseReminder.get(reminder_id) if reminder.domain != domain: continue if reminder.handler_id in handler_map: handler = handler_map[reminder.handler_id] else: handler = reminder.handler handler_map[reminder.handler_id] = handler reminder.error = False reminder.error_msg = None handler.set_next_fire(reminder, current_timestamp) reminder.save(**kwargs) timezone = report_utils.get_timezone(request.couch_user.user_id, domain) reminders = [] for reminder in CaseReminder.view("reminders/reminders_in_error", startkey=[domain], endkey=[domain, {}], include_docs=True).all(): if reminder.handler_id in handler_map: handler = handler_map[reminder.handler_id] else: handler = reminder.handler handler_map[reminder.handler_id] = handler recipient = reminder.recipient case = reminder.case reminders.append({ "reminder_id" : reminder._id, "handler_id" : reminder.handler_id, "handler_name" : handler.nickname, "case_id" : case.get_id if case is not None else None, "case_name" : case.name if case is not None else None, "next_fire" : tz_utils.adjust_datetime_to_timezone(reminder.next_fire, pytz.utc.zone, timezone.zone).strftime("%Y-%m-%d %H:%M:%S"), "error_msg" : reminder.error_msg, "recipient_name" : get_recipient_name(recipient), }) context = { "domain" : domain, "reminders" : reminders, "timezone" : timezone, "timezone_now" : datetime.now(tz=timezone), } return render(request, "reminders/partial/reminders_in_error.html", context)
def handle(self, **options): num_dups = 0 make_fixes = options["fix"] ids = {} rows = CaseReminder.view("reminders/by_domain_handler_case", include_docs=False).all() for row in rows: row_key = row["key"] if row_key[2]: ids_key = "|".join(row_key) if ids_key in ids: ids[ids_key].append(row["id"]) else: ids[ids_key] = [row["id"]] for k, v in ids.items(): if len(v) > 1: num_dups += 1 split_key = k.split("|") print("Duplicate found: ", split_key) handler = CaseReminderHandler.get(split_key[1]) if handler.start_condition_type != CASE_CRITERIA: print("ERROR: Duplicate with the above key is not a case " "criteria reminder") continue all_match = True reminders = [CaseReminder.get(i) for i in v] for r in reminders[1:]: all_match = all_match and self.reminders_match( reminders[0], r) if all_match: if make_fixes: print("Removing duplicate(s)...") for r in reminders[1:]: r.retire() c = CommCareCase.get(split_key[2]) messaging_case_changed_receiver(None, c) else: print( "ERROR: Not all of the reminders with the above key match" ) print("%s Duplicate(s) were found" % num_dups)
def handle(self, *args, **options): num_dups = 0 make_fixes = options["fix"] ids = {} rows = CaseReminder.view("reminders/by_domain_handler_case", include_docs=False).all() for row in rows: row_key = row["key"] if row_key[2]: ids_key = "|".join(row_key) if ids_key in ids: ids[ids_key].append(row["id"]) else: ids[ids_key] = [row["id"]] for k, v in ids.items(): if len(v) > 1: num_dups += 1 split_key = k.split("|") print "Duplicate found: ", split_key handler = CaseReminderHandler.get(split_key[1]) if handler.start_condition_type != CASE_CRITERIA: print ("ERROR: Duplicate with the above key is not a case " "criteria reminder") continue all_match = True reminders = [CaseReminder.get(i) for i in v] for r in reminders[1:]: all_match = all_match and self.reminders_match(reminders[0], r) if all_match: if make_fixes: print "Removing duplicate(s)..." for r in reminders[1:]: r.retire() c = CommCareCase.get(split_key[2]) case_changed_receiver(None, c) else: print "ERROR: Not all of the reminders with the above key match" print "%s Duplicate(s) were found" % num_dups
def test_ok(self): with create_test_case(self.domain, 'case_type_a', 'test-case', drop_signals=False, user_id=self.user.get_id) as case: # Test changing a start condition which is a string # Spawn the reminder with an "ok" start condition value CaseReminderHandler.now = datetime(year=2012, month=2, day=17, hour=12, minute=0) self.assertIsNone(self.handler1.get_reminder(case)) update_case(self.domain, case.case_id, {'start_sending1': 'ok'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, CaseReminderHandler.now + timedelta(days=self.handler1.start_offset)) # Test that saving the case without changing the start condition has no effect old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'case_property1': 'abc'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual(reminder.get_id, old_reminder_id) # Test retiring the reminder old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': ''}, user_id=self.user.get_id) self.assertIsNone(self.handler1.get_reminder(case)) self.assertEqual( CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test changing a start condition which is a date value # Spawn the reminder with date start condition value update_case(self.domain, case.case_id, {'start_sending1': '2012-02-20'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 20) + timedelta(days=self.handler1.start_offset)) # Reset the date start condition old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': '2012-02-22'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 22) + timedelta(days=self.handler1.start_offset)) self.assertEqual( CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test that saving the case without changing the start condition has no effect old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'case_property1': 'abc'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual(reminder.get_id, old_reminder_id) # Retire the reminder old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': ''}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNone(reminder) self.assertEqual( CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test changing a start condition which is a string representation of a datetime value # Spawn the reminder with datetime start condition value update_case(self.domain, case.case_id, {'start_sending1': '2012-02-25 11:15'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 25, 11, 15) + timedelta(days=self.handler1.start_offset)) # Reset the datetime start condition old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': '2012-02-26 11:20'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 26, 11, 20) + timedelta(days=self.handler1.start_offset)) self.assertEqual( CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test that saving the case without changing the start condition has no effect old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'case_property1': 'xyz'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual(reminder.get_id, old_reminder_id) # Retire the reminder old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': ''}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNone(reminder) self.assertEqual( CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted")
def test_ok(self): with create_test_case(self.domain, 'case_type_a', 'test-case', drop_signals=False, user_id=self.user.get_id) as case: # Test changing a start condition which is a string # Spawn the reminder with an "ok" start condition value CaseReminderHandler.now = datetime(year=2012, month=2, day=17, hour=12, minute=0) self.assertIsNone(self.handler1.get_reminder(case)) update_case(self.domain, case.case_id, {'start_sending1': 'ok'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, CaseReminderHandler.now + timedelta(days=self.handler1.start_offset) ) # Test that saving the case without changing the start condition has no effect old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'case_property1': 'abc'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual(reminder.get_id, old_reminder_id) # Test retiring the reminder old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': ''}, user_id=self.user.get_id) self.assertIsNone(self.handler1.get_reminder(case)) self.assertEqual(CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test changing a start condition which is a date value # Spawn the reminder with date start condition value update_case(self.domain, case.case_id, {'start_sending1': '2012-02-20'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 20) + timedelta(days=self.handler1.start_offset) ) # Reset the date start condition old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': '2012-02-22'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 22) + timedelta(days=self.handler1.start_offset) ) self.assertEqual(CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test that saving the case without changing the start condition has no effect old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'case_property1': 'abc'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual(reminder.get_id, old_reminder_id) # Retire the reminder old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': ''}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNone(reminder) self.assertEqual(CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test changing a start condition which is a string representation of a datetime value # Spawn the reminder with datetime start condition value update_case(self.domain, case.case_id, {'start_sending1': '2012-02-25 11:15'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 25, 11, 15) + timedelta(days=self.handler1.start_offset) ) # Reset the datetime start condition old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': '2012-02-26 11:20'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual( reminder.next_fire, datetime(2012, 2, 26, 11, 20) + timedelta(days=self.handler1.start_offset) ) self.assertEqual(CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted") # Test that saving the case without changing the start condition has no effect old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'case_property1': 'xyz'}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNotNone(reminder) self.assertEqual(reminder.get_id, old_reminder_id) # Retire the reminder old_reminder_id = reminder.get_id update_case(self.domain, case.case_id, {'start_sending1': ''}, user_id=self.user.get_id) reminder = self.handler1.get_reminder(case) self.assertIsNone(reminder) self.assertEqual(CaseReminder.get(old_reminder_id).doc_type, "CaseReminder-Deleted")