From f0c73ccc39e56bb00bfb24f42f6e4eb960e8c91b Mon Sep 17 00:00:00 2001 From: Matias Bordese Date: Thu, 30 Mar 2023 08:53:39 -0300 Subject: [PATCH] RRULE until values must be specified in UTC tz (#1661) When generating ical information for an event, the RRULE until value must be specified in UTC. Related to https://github.com/grafana/support-escalations/issues/5426. --- CHANGELOG.md | 1 + .../schedules/models/custom_on_call_shift.py | 4 +- .../tests/test_custom_on_call_shift.py | 40 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 882c2df1..71b0d5c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Addressed bug with iOS mobile push notifications always being set to critical by @imtoori and @joeyorlando ([#1646](https://github.com/grafana/oncall/pull/1646)) - Fixed issue where Viewer was not able to view which people were oncall in a schedule ([#999](https://github.com/grafana/oncall/issues/999)) - Fixed a bug with syncing teams from Grafana API by @vadimkerr ([#1652](https://github.com/grafana/oncall/pull/1652)) +- Fixed bug when web schedules/shifts use non-UTC timezone and shift is deleted by @matiasb ([#1661](https://github.com/grafana/oncall/pull/1661)) ## v1.2.3 (2023-03-28) diff --git a/engine/apps/schedules/models/custom_on_call_shift.py b/engine/apps/schedules/models/custom_on_call_shift.py index cbba2bb6..6003a5d0 100644 --- a/engine/apps/schedules/models/custom_on_call_shift.py +++ b/engine/apps/schedules/models/custom_on_call_shift.py @@ -584,8 +584,8 @@ class CustomOnCallShift(models.Model): if self.week_start is not None: rules["wkst"] = CustomOnCallShift.ICAL_WEEKDAY_MAP[self.week_start] if self.until is not None: - time_zone = self.time_zone if self.time_zone is not None else "UTC" - rules["until"] = self.convert_dt_to_schedule_timezone(self.until, time_zone) + # RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware + rules["until"] = self.convert_dt_to_schedule_timezone(self.until, "UTC") return rules @cached_property diff --git a/engine/apps/schedules/tests/test_custom_on_call_shift.py b/engine/apps/schedules/tests/test_custom_on_call_shift.py index f21674f4..77a7f46d 100644 --- a/engine/apps/schedules/tests/test_custom_on_call_shift.py +++ b/engine/apps/schedules/tests/test_custom_on_call_shift.py @@ -1625,3 +1625,43 @@ def test_delete_override( if (starting_day + duration) < 0 else on_call_shift.duration < original_duration ) + + +@pytest.mark.django_db +def test_until_rrule_must_be_utc( + make_organization_and_user, + make_user_for_organization, + make_schedule, + make_on_call_shift, +): + organization, user_1 = make_organization_and_user() + user_2 = make_user_for_organization(organization) + schedule = make_schedule(organization, schedule_class=OnCallScheduleWeb, time_zone="Europe/Warsaw") + + date = timezone.now().replace(microsecond=0) - timezone.timedelta(days=7) + data = { + "priority_level": 1, + "start": date, + "rotation_start": date, + "duration": timezone.timedelta(seconds=10800), + "frequency": CustomOnCallShift.FREQUENCY_WEEKLY, + "interval": 2, + "time_zone": "Europe/Warsaw", + "schedule": schedule, + } + on_call_shift = make_on_call_shift( + organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data + ) + rolling_users = [[user_1], [user_2]] + on_call_shift.add_rolling_users(rolling_users) + + # finish the rotation, will set until value + on_call_shift.delete() + + on_call_shift.refresh_from_db() + assert on_call_shift.until.tzname() == "UTC" + ical_data = on_call_shift.convert_to_ical() + ical_rrule_until = on_call_shift.until.strftime("%Y%m%dT%H%M%S") + expected_rrule = f"RRULE:FREQ=WEEKLY;UNTIL={ical_rrule_until}Z;INTERVAL=4;WKST=SU" + + assert expected_rrule in ical_data