def derive_initial(self): trigger = self.object trigger_type = trigger.trigger_type if trigger_type == Trigger.TYPE_SCHEDULE: repeat_period = trigger.schedule.repeat_period omnibox = omnibox_serialize(trigger.org, trigger.groups.all(), trigger.contacts.all()) return dict(repeat_period=repeat_period, omnibox=omnibox)
def test_update_near_day_boundary(self): self.org.timezone = pytz.timezone("US/Eastern") self.org.save() tz = self.org.timezone omnibox = omnibox_serialize(self.org, [], [self.joe], True) self.login(self.admin) post_data = dict(text="A scheduled message to Joe", omnibox=omnibox, sender=self.channel.pk, schedule=True) self.client.post(reverse("msgs.broadcast_send"), post_data, follow=True) bcast = Broadcast.objects.get() sched = bcast.schedule update_url = reverse("schedules.schedule_update", args=[sched.pk]) # way off into the future, but at 11pm NYT start_date = datetime(2050, 1, 3, 23, 0, 0, 0) start_date = tz.localize(start_date) start_date = pytz.utc.normalize(start_date.astimezone(pytz.utc)) post_data = dict() post_data["repeat_period"] = "D" post_data["start"] = "later" post_data["start_datetime_value"] = "%d" % time.mktime( start_date.timetuple()) self.client.post(update_url, post_data) sched = Schedule.objects.get(pk=sched.pk) # 11pm in NY should be 4am UTC the next day self.assertEqual("2050-01-04 04:00:00+00:00", str(sched.next_fire)) start_date = datetime(2050, 1, 3, 23, 45, 0, 0) start_date = tz.localize(start_date) start_date = pytz.utc.normalize(start_date.astimezone(pytz.utc)) post_data = dict() post_data["repeat_period"] = "D" post_data["start"] = "later" post_data["start_datetime_value"] = "%d" % time.mktime( start_date.timetuple()) self.client.post(update_url, post_data) sched = Schedule.objects.get(pk=sched.pk) # next fire should fall at the right hour and minute self.assertIn("04:45:00+00:00", str(sched.next_fire))
def test_update(self): self.login(self.admin) # create a schedule broadcast self.client.post( reverse("msgs.broadcast_send"), { "text": "A scheduled message to Joe", "omnibox": omnibox_serialize(self.org, [], [self.joe], True), "sender": self.channel.id, "schedule": True, }, ) schedule = Broadcast.objects.get().schedule update_url = reverse("schedules.schedule_update", args=[schedule.id]) # viewer can't access self.login(self.user) response = self.client.get(update_url) self.assertLoginRedirect(response) # editor can access self.login(self.editor) response = self.client.get(update_url) self.assertEqual(response.status_code, 200) # as can admin user self.login(self.admin) response = self.client.get(update_url) self.assertEqual(response.status_code, 200) now = timezone.now() now_stamp = time.mktime(now.timetuple()) tommorrow = now + timedelta(days=1) tommorrow_stamp = time.mktime(tommorrow.timetuple()) # user in other org can't make changes self.login(self.admin2) response = self.client.post(update_url, {"start": "never", "repeat_period": "D"}) self.assertLoginRedirect(response) # check schedule is unchanged schedule.refresh_from_db() self.assertEqual("O", schedule.repeat_period) self.login(self.admin) # update to never start response = self.client.post(update_url, {"start": "never", "repeat_period": "O"}) self.assertEqual(302, response.status_code) schedule.refresh_from_db() self.assertIsNone(schedule.next_fire) self.client.post(update_url, {"start": "stop", "repeat_period": "O"}) schedule.refresh_from_db() self.assertIsNone(schedule.next_fire) response = self.client.post( update_url, {"start": "now", "repeat_period": "O", "start_datetime_value": "%d" % now_stamp} ) self.assertEqual(302, response.status_code) schedule.refresh_from_db() self.assertEqual(schedule.repeat_period, "O") self.assertFalse(schedule.next_fire) response = self.client.post( update_url, {"repeat_period": "D", "start": "later", "start_datetime_value": "%d" % tommorrow_stamp} ) self.assertEqual(302, response.status_code) schedule.refresh_from_db() self.assertEqual(schedule.repeat_period, "D") response = self.client.post( update_url, {"repeat_period": "D", "start": "later", "start_datetime_value": "%d" % tommorrow_stamp} ) self.assertEqual(302, response.status_code) schedule.refresh_from_db() self.assertEqual(schedule.repeat_period, "D") # can't omit repeat_days_of_week for weekly response = self.client.post( update_url, { "repeat_period": "W", "start": "later", "repeat_days_of_week": "", "start_datetime_value": str(now_stamp), }, ) self.assertFormError(response, "form", "__all__", "Must specify at least one day of the week") schedule.refresh_from_db() self.assertEqual(schedule.repeat_period, "D") # unchanged self.assertEqual(schedule.repeat_days_of_week, "") # can't set repeat_days_of_week to invalid day response = self.client.post( update_url, { "repeat_period": "W", "start": "later", "repeat_days_of_week": "X", "start_datetime_value": str(now_stamp), }, ) self.assertFormError(response, "form", "repeat_days_of_week", "X is not a valid day of the week") schedule.refresh_from_db() self.assertEqual(schedule.repeat_period, "D") # unchanged self.assertEqual(schedule.repeat_days_of_week, "") # can set to valid days response = self.client.post( update_url, { "repeat_period": "W", "start": "later", "repeat_days_of_week": "MF", "start_datetime_value": str(now_stamp), }, ) self.assertEqual(response.status_code, 302) schedule.refresh_from_db() self.assertEqual(schedule.repeat_period, "W") self.assertEqual(schedule.repeat_days_of_week, "MF")
def test_schedule_ui(self): self.login(self.admin) joe = self.create_contact("Joe Blow", "123") # test missing recipients omnibox = omnibox_serialize(self.org, [], [], True) post_data = dict(text="message content", omnibox=omnibox, sender=self.channel.pk, schedule=True) response = self.client.post(reverse("msgs.broadcast_send"), post_data, follow=True) self.assertContains(response, "At least one recipient is required") # missing message omnibox = omnibox_serialize(self.org, [], [self.joe], True) post_data = dict(text="", omnibox=omnibox, sender=self.channel.pk, schedule=True) response = self.client.post(reverse("msgs.broadcast_send"), post_data, follow=True) self.assertContains(response, "This field is required") # finally create our message post_data = dict(text="A scheduled message to Joe", omnibox=omnibox, sender=self.channel.pk, schedule=True) headers = {"HTTP_X_PJAX": "True"} response = self.client.post(reverse("msgs.broadcast_send"), post_data, **headers) self.assertIn("/broadcast/schedule_read", response["Temba-Success"]) # should have a schedule with no next fire bcast = Broadcast.objects.get() schedule = bcast.schedule self.assertIsNone(schedule.next_fire) self.assertEqual(Schedule.REPEAT_NEVER, schedule.repeat_period) # fetch our formax page response = self.client.get(response["Temba-Success"]) self.assertContains(response, "id-schedule") broadcast = response.context["object"] # update our message post_data = dict(message="An updated scheduled message", omnibox="c-%s" % joe.uuid) self.client.post(reverse("msgs.broadcast_update", args=[broadcast.pk]), post_data) self.assertEqual(Broadcast.objects.get(id=broadcast.id).text, {"base": "An updated scheduled message"}) start = datetime(2045, 9, 19, hour=10, minute=15, second=0, microsecond=0) start = pytz.utc.normalize(self.org.timezone.localize(start)) start_stamp = time.mktime(start.timetuple()) # update the schedule post_data = dict( repeat_period=Schedule.REPEAT_WEEKLY, repeat_days_of_week="W", start="later", start_datetime_value=start_stamp, ) response = self.client.post(reverse("schedules.schedule_update", args=[broadcast.schedule.pk]), post_data) # assert out next fire was updated properly schedule.refresh_from_db() self.assertEqual(Schedule.REPEAT_WEEKLY, schedule.repeat_period) self.assertEqual("W", schedule.repeat_days_of_week) self.assertEqual(10, schedule.repeat_hour_of_day) self.assertEqual(15, schedule.repeat_minute_of_hour) self.assertEqual(start, schedule.next_fire) # manually set our fire in the past schedule.next_fire = timezone.now() - timedelta(days=1) schedule.save(update_fields=["next_fire"]) self.assertIsNotNone(str(schedule))
def test_trigger_schedule(self, mock_async_start): self.login(self.admin) flow = self.create_flow() chester = self.create_contact("Chester", "+250788987654") shinoda = self.create_contact("Shinoda", "+250234213455") linkin_park = self.create_group("Linkin Park", [chester, shinoda]) stromae = self.create_contact("Stromae", "+250788645323") now = timezone.now() now_stamp = time.mktime(now.timetuple()) tommorrow = now + timedelta(days=1) tommorrow_stamp = time.mktime(tommorrow.timetuple()) omnibox_selection = omnibox_serialize(flow.org, [linkin_park], [stromae], True) # try to create trigger without a flow or omnibox response = self.client.post( reverse("triggers.trigger_schedule"), { "omnibox": omnibox_selection, "repeat_period": "D", "start": "later", "start_datetime_value": str(tommorrow_stamp), }, ) self.assertEqual(list(response.context["form"].errors.keys()), ["flow"]) self.assertFalse(Trigger.objects.all()) self.assertFalse(Schedule.objects.all()) # survey flows should not be an option flow.flow_type = Flow.TYPE_SURVEY flow.save(update_fields=("flow_type", )) response = self.client.get(reverse("triggers.trigger_schedule")) # check no flows listed self.assertEqual( response.context["form"].fields["flow"].queryset.all().count(), 0) # revert flow to messaging flow type flow.flow_type = Flow.TYPE_MESSAGE flow.save(update_fields=("flow_type", )) self.assertEqual( response.context["form"].fields["flow"].queryset.all().count(), 1) # this time provide a flow but leave out omnibox.. response = self.client.post( reverse("triggers.trigger_schedule"), { "flow": flow.id, "repeat_period": "D", "start": "later", "start_datetime_value": str(tommorrow_stamp) }, ) self.assertEqual(list(response.context["form"].errors.keys()), ["omnibox"]) self.assertFalse(Trigger.objects.all()) self.assertFalse(Schedule.objects.all()) # ok, really create it self.client.post( reverse("triggers.trigger_schedule"), { "flow": flow.id, "omnibox": omnibox_selection, "repeat_period": "D", "start": "later", "start_datetime_value": str(tommorrow_stamp), }, ) self.assertEqual(Trigger.objects.count(), 1) self.client.post( reverse("triggers.trigger_schedule"), { "flow": flow.id, "omnibox": omnibox_selection, "repeat_period": "D", "start": "later", "start_datetime_value": str(tommorrow_stamp), }, ) self.assertEqual(2, Trigger.objects.all().count()) trigger = Trigger.objects.order_by("id").last() self.assertTrue(trigger.schedule) self.assertEqual(trigger.schedule.repeat_period, "D") self.assertEqual(set(trigger.groups.all()), {linkin_park}) self.assertEqual(set(trigger.contacts.all()), {stromae}) update_url = reverse("triggers.trigger_update", args=[trigger.pk]) # try to update a trigger without a flow response = self.client.post( update_url, { "omnibox": omnibox_selection, "repeat_period": "O", "start": "later", "start_datetime_value": str(now_stamp), }, ) self.assertEqual(list(response.context["form"].errors.keys()), ["flow"]) # provide flow this time, update contact self.client.post( update_url, { "flow": flow.id, "omnibox": omnibox_serialize(flow.org, [linkin_park], [shinoda], True), "repeat_period": "D", "start": "later", "start_datetime_value": str(now_stamp), }, ) trigger.refresh_from_db() self.assertTrue(trigger.schedule) self.assertEqual(trigger.schedule.repeat_period, "D") self.assertTrue(trigger.schedule.next_fire) self.assertEqual(set(trigger.groups.all()), {linkin_park}) self.assertEqual(set(trigger.contacts.all()), {shinoda}) # can't submit weekly repeat without specifying the days to repeat on response = self.client.post( update_url, { "flow": flow.id, "omnibox": omnibox_selection, "repeat_period": "W", "start": "later", "start_datetime_value": str(now_stamp), }, ) self.assertFormError(response, "form", "__all__", "Must specify at least one day of the week") # or submit with invalid days response = self.client.post( update_url, { "flow": flow.id, "omnibox": omnibox_selection, "repeat_period": "W", "repeat_days_of_week": "X", "start": "later", "start_datetime_value": str(now_stamp), }, ) self.assertFormError(response, "form", "repeat_days_of_week", "X is not a valid day of the week")