Example #1
0
    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))
Example #2
0
        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
Example #3
0
        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()
Example #4
0
    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))
Example #5
0
    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.")
Example #6
0
    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")