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], json_encode=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"] = (datetime_to_str(start_date, "%Y-%m-%d %H:%M", self.org.timezone), ) 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"] = (datetime_to_str(start_date, "%Y-%m-%d %H:%M", self.org.timezone), ) 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 derive_initial(self): initial = super().derive_initial() if self.object.trigger_type == Trigger.TYPE_SCHEDULE: schedule = self.object.schedule days_of_the_week = list(schedule.repeat_days_of_week) if schedule.repeat_days_of_week else [] contacts = self.object.contacts.all() initial["start_datetime"] = schedule.next_fire initial["repeat_period"] = schedule.repeat_period initial["repeat_days_of_week"] = days_of_the_week initial["contacts"] = omnibox_serialize(self.object.org, (), contacts) return initial
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()) repeat_days_of_week = [] if trigger.schedule.repeat_days_of_week: # pragma: needs cover repeat_days_of_week = list( trigger.schedule.repeat_days_of_week) return dict( repeat_period=repeat_period, omnibox=omnibox, start_datetime=trigger.schedule.next_fire, repeat_days_of_week=repeat_days_of_week, ) return super().derive_initial()
def test_schedule_ui(self): self.login(self.admin) # test missing recipients omnibox = omnibox_serialize(self.org, [], [], json_encode=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], json_encode=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 omnibox = omnibox_serialize(self.org, [], [self.joe], json_encode=True) post_data = dict(message="An updated scheduled message", omnibox=omnibox) 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)) # update the schedule post_data = dict( repeat_period=Schedule.REPEAT_WEEKLY, repeat_days_of_week="W", start="later", start_datetime=datetime_to_str(start, "%Y-%m-%d %H:%M", self.org.timezone), ) 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) create_url = reverse("triggers.trigger_schedule") flow = self.create_flow() background_flow = self.get_flow("background") self.get_flow("media_survey") chester = self.create_contact("Chester", phone="+250788987654") shinoda = self.create_contact("Shinoda", phone="+250234213455") linkin_park = self.create_group("Linkin Park", [chester, shinoda]) stromae = self.create_contact("Stromae", phone="+250788645323") response = self.client.get(create_url) # the normal flow and background flow should be options but not the surveyor flow self.assertEqual( list(response.context["form"].fields["flow"].queryset), [background_flow, flow]) now = timezone.now() tommorrow = now + timedelta(days=1) omnibox_selection = omnibox_serialize(flow.org, [linkin_park], [stromae], True) # try to create trigger without a flow or omnibox response = self.client.post( create_url, { "omnibox": omnibox_selection, "repeat_period": "D", "start": "later", "start_datetime": datetime_to_str(tommorrow, "%Y-%m-%d %H:%M", self.org.timezone), }, ) self.assertEqual(list(response.context["form"].errors.keys()), ["flow"]) self.assertFalse(Trigger.objects.all()) self.assertFalse(Schedule.objects.all()) # this time provide a flow but leave out omnibox.. response = self.client.post( create_url, { "flow": flow.id, "repeat_period": "D", "start": "later", "start_datetime": datetime_to_str(tommorrow, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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( create_url, { "flow": flow.id, "omnibox": omnibox_selection, "repeat_period": "D", "start": "later", "start_datetime": datetime_to_str(tommorrow, "%Y-%m-%d %H:%M", self.org.timezone), }, ) self.assertEqual(Trigger.objects.count(), 1) self.client.post( create_url, { "flow": flow.id, "omnibox": omnibox_selection, "repeat_period": "D", "start": "later", "start_datetime": datetime_to_str(tommorrow, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) self.assertFormError( response, "form", "repeat_days_of_week", "Select a valid choice. X is not one of the available choices.")
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() tommorrow = now + timedelta(days=1) # 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": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(tommorrow, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(tommorrow, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) 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": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) self.assertFormError( response, "form", "repeat_days_of_week", "Select a valid choice. X is not one of the available choices." ) 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": ["M", "F"], "start_datetime": datetime_to_str(now, "%Y-%m-%d %H:%M", self.org.timezone), }, ) self.assertEqual(response.status_code, 302) schedule.refresh_from_db() self.assertEqual(schedule.repeat_period, "W") self.assertEqual(schedule.repeat_days_of_week, "MF")