diff --git a/engine/apps/alerts/tasks/notify_ical_schedule_shift.py b/engine/apps/alerts/tasks/notify_ical_schedule_shift.py index ce7049b0..9ec0f7e6 100644 --- a/engine/apps/alerts/tasks/notify_ical_schedule_shift.py +++ b/engine/apps/alerts/tasks/notify_ical_schedule_shift.py @@ -265,7 +265,7 @@ def notify_ical_schedule_shift(schedule_pk): for prev_ical_file, current_ical_file in prev_and_current_ical_files: if prev_ical_file is not None and ( - current_ical_file is None or not is_icals_equal(current_ical_file, prev_ical_file) + current_ical_file is None or not is_icals_equal(current_ical_file, prev_ical_file, schedule) ): # If icals are not equal then compare current_events from them is_prev_ical_diff = True diff --git a/engine/apps/schedules/ical_utils.py b/engine/apps/schedules/ical_utils.py index d78b99af..aa9ab809 100644 --- a/engine/apps/schedules/ical_utils.py +++ b/engine/apps/schedules/ical_utils.py @@ -33,7 +33,7 @@ This is a hack to allow us to load models for type checking without circular dep This module likely needs to refactored to be part of the OnCallSchedule module. """ if TYPE_CHECKING: - from apps.schedules.models import OnCallSchedule + from apps.schedules.models import OnCallSchedule, OnCallScheduleICal # noqa from apps.user_management.models import User @@ -408,7 +408,7 @@ def get_users_from_ical_event(event, organization): return users -def is_icals_equal(first, second): +def is_icals_equal_line_by_line(first, second): first = first.split("\n") second = second.split("\n") if len(first) != len(second): @@ -425,6 +425,30 @@ def is_icals_equal(first, second): return True +def is_icals_equal(first, second, schedule): + from apps.schedules.models import OnCallScheduleICal # noqa + + if isinstance(schedule, OnCallScheduleICal): + first_cal = Calendar.from_ical(first) + second_cal = Calendar.from_ical(second) + first_subcomponents = first_cal.subcomponents + second_subcomponents = second_cal.subcomponents + if len(first_subcomponents) != len(second_subcomponents): + return False + for idx, first_cmp in enumerate(first_cal.subcomponents): + second_cmp = second_subcomponents[idx] + if first_cmp.name == second_cmp.name == "VEVENT": + first_uid, first_seq = first_cmp.get("UID", None), first_cmp.get("SEQUENCE", None) + second_uid, second_seq = second_cmp.get("UID", None), second_cmp.get("SEQUENCE", None) + if first_uid != second_uid: + return False + elif first_seq != second_seq: + return False + return True + else: + return is_icals_equal_line_by_line(first, second) + + def ical_date_to_datetime(date, tz, start): datetime_to_combine = datetime.time.min all_day = False diff --git a/engine/apps/schedules/tasks/refresh_ical_files.py b/engine/apps/schedules/tasks/refresh_ical_files.py index 5797c668..cad0baee 100644 --- a/engine/apps/schedules/tasks/refresh_ical_files.py +++ b/engine/apps/schedules/tasks/refresh_ical_files.py @@ -46,7 +46,9 @@ def refresh_ical_file(schedule_pk): run_task_primary = True task_logger.info(f"run_task_primary {schedule_pk} {run_task_primary} prev_ical_file_primary is None") else: - run_task_primary = not is_icals_equal(schedule.cached_ical_file_primary, schedule.prev_ical_file_primary) + run_task_primary = not is_icals_equal( + schedule.cached_ical_file_primary, schedule.prev_ical_file_primary, schedule + ) task_logger.info(f"run_task_primary {schedule_pk} {run_task_primary} icals not equal") run_task_overrides = False if schedule.cached_ical_file_overrides is not None: @@ -55,7 +57,7 @@ def refresh_ical_file(schedule_pk): task_logger.info(f"run_task_overrides {schedule_pk} {run_task_primary} prev_ical_file_overrides is None") else: run_task_overrides = not is_icals_equal( - schedule.cached_ical_file_overrides, schedule.prev_ical_file_overrides + schedule.cached_ical_file_overrides, schedule.prev_ical_file_overrides, schedule ) task_logger.info(f"run_task_overrides {schedule_pk} {run_task_primary} icals not equal") run_task = run_task_primary or run_task_overrides