diff --git a/CHANGELOG.md b/CHANGELOG.md index a9d0a67c..c4dfc9a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Ignore ical cancelled events when calculating shifts ([#2776](https://github.com/grafana/oncall/pull/2776)) - Fix Slack acknowledgment reminders by @vadimkerr ([#2769](https://github.com/grafana/oncall/pull/2769)) - Fix issue with updating "Require resolution note" setting by @Ferril ([#2782](https://github.com/grafana/oncall/pull/2782)) diff --git a/engine/apps/schedules/ical_utils.py b/engine/apps/schedules/ical_utils.py index 8862aa5b..bd467c10 100644 --- a/engine/apps/schedules/ical_utils.py +++ b/engine/apps/schedules/ical_utils.py @@ -24,6 +24,8 @@ from apps.schedules.constants import ( ICAL_LOCATION, ICAL_RECURRENCE_ID, ICAL_SEQUENCE, + ICAL_STATUS, + ICAL_STATUS_CANCELLED, ICAL_SUMMARY, ICAL_UID, RE_EVENT_UID_V1, @@ -200,6 +202,10 @@ def get_shifts_dict( result_datetime = [] result_date = [] for event in events: + status = event.get(ICAL_STATUS) + if status == ICAL_STATUS_CANCELLED: + # ignore cancelled events + continue sequence = event.get(ICAL_SEQUENCE) recurrence_id = event.get(ICAL_RECURRENCE_ID) if recurrence_id: diff --git a/engine/apps/schedules/tests/test_ical_utils.py b/engine/apps/schedules/tests/test_ical_utils.py index 39951fef..c6520c96 100644 --- a/engine/apps/schedules/tests/test_ical_utils.py +++ b/engine/apps/schedules/tests/test_ical_utils.py @@ -16,7 +16,13 @@ from apps.schedules.ical_utils import ( parse_event_uid, users_in_ical, ) -from apps.schedules.models import CustomOnCallShift, OnCallSchedule, OnCallScheduleCalendar, OnCallScheduleWeb +from apps.schedules.models import ( + CustomOnCallShift, + OnCallSchedule, + OnCallScheduleCalendar, + OnCallScheduleICal, + OnCallScheduleWeb, +) def test_get_icalendar_tz_or_utc(): @@ -122,6 +128,38 @@ def test_list_users_to_notify_from_ical_viewers_inclusion( assert set(users_on_call) == {user} +@pytest.mark.django_db +def test_list_users_to_notify_from_ical_ignore_cancelled(make_organization_and_user, make_schedule): + organization, user = make_organization_and_user() + now = timezone.now().replace(second=0, microsecond=0) + end = now + timezone.timedelta(minutes=30) + ical_data = textwrap.dedent( + """ + BEGIN:VCALENDAR + VERSION:2.0 + CALSCALE:GREGORIAN + METHOD:PUBLISH + BEGIN:VEVENT + SUMMARY:{} + DTSTART;VALUE=DATE-TIME:{} + DTEND;VALUE=DATE-TIME:{} + DTSTAMP;VALUE=DATE-TIME:20230807T001508Z + UID:some-uid + LOCATION:primary + STATUS:CANCELLED + END:VEVENT + END:VCALENDAR + """.format( + user.username, now.strftime("%Y%m%dT%H%M%SZ"), end.strftime("%Y%m%dT%H%M%SZ") + ) + ) + schedule = make_schedule(organization, schedule_class=OnCallScheduleICal, cached_ical_file_primary=ical_data) + + # get users on-call + users_on_call = list_users_to_notify_from_ical(schedule, now + timezone.timedelta(minutes=5)) + assert len(users_on_call) == 0 + + @pytest.mark.django_db def test_list_users_to_notify_from_ical_until_terminated_event( make_organization_and_user, make_user_for_organization, make_schedule, make_on_call_shift