Handle non-UTC UNTIL datetime value when repeating ical events (#2241)

This commit is contained in:
Matias Bordese 2023-06-15 10:53:53 -03:00 committed by GitHub
parent 687fcc2829
commit d38315def7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 0 deletions

View file

@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update notification text for "You're going on call" push notifications to include information about the shift start
and end times by @joeyorlando ([#2131](https://github.com/grafana/oncall/pull/2131))
### Fixed
- Handle non-UTC UNTIL datetime value when repeating ical events [#2241](https://github.com/grafana/oncall/pull/2241)
## v1.2.44 (2023-06-14)
### Added

View file

@ -1,4 +1,5 @@
import datetime
import re
import typing
from collections import defaultdict
@ -30,6 +31,8 @@ class AmixrUnfoldableCalendar(UnfoldableCalendar):
"""
class RepeatedEvent(UnfoldableCalendar.RepeatedEvent):
RE_DATETIME_VALUE = re.compile(r"\d+T\d+")
class Repetition(UnfoldableCalendar.RepeatedEvent.Repetition):
"""
A repetition of an event. Overridden version of
@ -40,6 +43,26 @@ class AmixrUnfoldableCalendar(UnfoldableCalendar):
ATTRIBUTES_TO_DELETE_ON_COPY = ["RDATE", "EXDATE"]
def create_rule_with_start(self, rule_string, start):
"""Override to handle issue with non-UTC UNTIL value including time information."""
try:
return super().create_rule_with_start(rule_string, start)
except ValueError:
# string: FREQ=WEEKLY;UNTIL=20191023T100000;BYDAY=TH;WKST=SU
# ValueError: RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware
# https://stackoverflow.com/a/49991809
rule_list = rule_string.split(";UNTIL=")
assert len(rule_list) == 2
date_end_index = rule_list[1].find(";")
if date_end_index == -1:
date_end_index = len(rule_list[1])
until_string = rule_list[1][:date_end_index]
if self.RE_DATETIME_VALUE.match(until_string):
rule_string = rule_list[0] + rule_list[1][date_end_index:] + ";UNTIL=" + until_string + "Z"
return super().create_rule_with_start(rule_string, self.start)
# otherwise, keep raising
raise
def between(self, start, stop):
"""Return events at a time between start (inclusive) and end (inclusive)"""
span_start = self.to_datetime(start)

View file

@ -1744,3 +1744,39 @@ def test_refresh_ical_final_schedule_all_day_date_event(
calendar = icalendar.Calendar.from_ical(schedule.cached_ical_final_schedule)
events = [component for component in calendar.walk() if component.name == ICAL_COMPONENT_VEVENT]
assert len(events) == 0
@pytest.mark.django_db
def test_event_until_non_utc(make_organization, make_schedule):
organization = make_organization()
cached_ical_primary_schedule = textwrap.dedent(
"""
BEGIN:VCALENDAR
VERSION:2.0
PRODID:testing
CALSCALE:GREGORIAN
BEGIN:VEVENT
CREATED:20220316T121102Z
LAST-MODIFIED:20230127T151619Z
DTSTAMP:20230127T151619Z
UID:something
SUMMARY:testing
RRULE:FREQ=WEEKLY;UNTIL=20221231T010101
DTSTART;TZID=Europe/Madrid:20220309T130000
DTEND;TZID=Europe/Madrid:20220309T133000
SEQUENCE:4
END:VEVENT
END:VCALENDAR
"""
)
schedule = make_schedule(
organization,
schedule_class=OnCallScheduleICal,
cached_ical_file_primary=cached_ical_primary_schedule,
)
now = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0)
# check this works without raising exception
schedule.final_events("UTC", now, days=7)