Use shift public key in events

This commit is contained in:
Matias Bordese 2022-07-06 15:47:21 -03:00
parent fea2456a8f
commit 87fda3caf6
7 changed files with 67 additions and 73 deletions

View file

@ -429,7 +429,9 @@ def test_events_calendar(
"calendar_type": OnCallSchedule.PRIMARY,
"is_empty": False,
"is_gap": False,
"shift_uuid": str(on_call_shift.uuid),
"shift": {
"pk": on_call_shift.public_primary_key,
},
}
],
}
@ -490,7 +492,9 @@ def test_filter_events_calendar(
"calendar_type": OnCallSchedule.PRIMARY,
"is_empty": False,
"is_gap": False,
"shift_uuid": str(on_call_shift.uuid),
"shift": {
"pk": on_call_shift.public_primary_key,
},
},
{
"all_day": False,
@ -502,7 +506,9 @@ def test_filter_events_calendar(
"calendar_type": OnCallSchedule.PRIMARY,
"is_empty": False,
"is_gap": False,
"shift_uuid": str(on_call_shift.uuid),
"shift": {
"pk": on_call_shift.public_primary_key,
},
},
],
}
@ -566,7 +572,9 @@ def test_filter_events_range_calendar(
"calendar_type": OnCallSchedule.PRIMARY,
"is_empty": False,
"is_gap": False,
"shift_uuid": str(on_call_shift.uuid),
"shift": {
"pk": on_call_shift.public_primary_key,
},
}
],
}

View file

@ -217,7 +217,9 @@ class ScheduleView(
"calendar_type": shift["calendar_type"],
"is_empty": len(shift["users"]) == 0 and not is_gap,
"is_gap": is_gap,
"shift_uuid": shift["shift_uuid"],
"shift": {
"pk": shift["shift_pk"],
},
}
events.append(shift_json)

View file

@ -1,5 +1,4 @@
import pytz
from django.utils import timezone
from rest_framework import serializers
from apps.public_api.serializers.schedules_base import ScheduleBaseSerializer
@ -35,7 +34,7 @@ class ScheduleWebSerializer(ScheduleBaseSerializer):
def validate_time_zone(self, tz):
try:
timezone.now().astimezone(pytz.timezone(tz))
pytz.timezone(tz)
except pytz.exceptions.UnknownTimeZoneError:
raise BadRequest(detail="Invalid time zone")
return tz

View file

@ -75,7 +75,8 @@ ICAL_DESCRIPTION = "DESCRIPTION"
ICAL_ATTENDEE = "ATTENDEE"
ICAL_UID = "UID"
RE_PRIORITY = re.compile(r"^\[L(\d)\]")
RE_EVENT_UID = re.compile(r"amixr-([\w\d-]+)-U(\d+)-E(\d+)-S(\d+)")
RE_EVENT_UID_V1 = re.compile(r"amixr-([\w\d-]+)-U(\d+)-E(\d+)-S(\d+)")
RE_EVENT_UID_V2 = re.compile(r"oncall-([\w\d-]+)-PK([\w\d]+)-U(\d+)-E(\d+)-S(\d+)")
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
@ -140,7 +141,7 @@ def list_of_oncall_shifts_from_ical(
"source": None,
"calendar_type": None,
"is_gap": True,
"shift_uuid": None,
"shift_pk": None,
}
)
result = sorted(result_datetime, key=lambda dt: dt["start"]) + result_date
@ -154,7 +155,7 @@ def get_shifts_dict(calendar, calendar_type, schedule, datetime_start, datetime_
result_date = []
for event in events:
priority = parse_priority_from_string(event.get(ICAL_SUMMARY, "[L0]"))
uuid, source = parse_event_uid(event.get(ICAL_UID))
pk, source = parse_event_uid(event.get(ICAL_UID))
users = get_users_from_ical_event(event, schedule.organization)
# Define on-call shift out of ical event that has the actual user
if len(users) > 0 or with_empty_shifts:
@ -170,7 +171,7 @@ def get_shifts_dict(calendar, calendar_type, schedule, datetime_start, datetime_
"priority": priority,
"source": source,
"calendar_type": calendar_type,
"shift_uuid": uuid,
"shift_pk": pk,
}
)
else:
@ -185,7 +186,7 @@ def get_shifts_dict(calendar, calendar_type, schedule, datetime_start, datetime_
"priority": priority,
"source": source,
"calendar_type": calendar_type,
"shift_uuid": uuid,
"shift_pk": pk,
}
)
return result_datetime, result_date
@ -193,7 +194,7 @@ def get_shifts_dict(calendar, calendar_type, schedule, datetime_start, datetime_
EmptyShift = namedtuple(
"EmptyShift",
["start", "end", "summary", "description", "attendee", "all_day", "calendar_type", "calendar_tz", "shift_uuid"],
["start", "end", "summary", "description", "attendee", "all_day", "calendar_type", "calendar_tz", "shift_pk"],
)
@ -237,7 +238,7 @@ def list_of_empty_shifts_in_schedule(schedule, start_date, end_date):
summary = event.get(ICAL_SUMMARY, "")
description = event.get(ICAL_DESCRIPTION, "")
attendee = event.get(ICAL_ATTENDEE, "")
uuid, _ = parse_event_uid(event.get(ICAL_UID))
pk, _ = parse_event_uid(event.get(ICAL_UID))
event_hash = hash(f"{event[ICAL_UID]}{summary}{description}{attendee}")
if event_hash in checked_events:
@ -265,7 +266,7 @@ def list_of_empty_shifts_in_schedule(schedule, start_date, end_date):
all_day=all_day,
calendar_type=calendar_type,
calendar_tz=calendar_tz,
shift_uuid=uuid,
shift_pk=pk,
)
)
empty_shifts.extend(empty_shifts_per_calendar)
@ -340,15 +341,26 @@ def parse_priority_from_string(string):
def parse_event_uid(string):
uuid = None
pk = None
source = None
source_verbal = None
match = RE_EVENT_UID.match(string)
match = RE_EVENT_UID_V2.match(string)
if match:
uuid, _, _, source = match.groups()
_, pk, _, _, source = match.groups()
else:
# eventually this path would be automatically deprecated
# once all ical representations are refreshed
match = RE_EVENT_UID_V1.match(string)
if match:
_, _, _, source = match.groups()
if source is not None:
source = int(source)
CustomOnCallShift = apps.get_model("schedules", "CustomOnCallShift")
source_verbal = CustomOnCallShift.SOURCE_CHOICES[source][1]
return uuid, source_verbal
return pk, source_verbal
def get_usernames_from_ical_event(event):

View file

@ -230,7 +230,7 @@ class CustomOnCallShift(models.Model):
def generate_ical(self, user, start, user_counter, counter=1, time_zone="UTC"):
# create event for each user in a list because we can't parse multiple users from ical summary
event = Event()
event["uid"] = f"amixr-{self.uuid}-U{user_counter}-E{counter}-S{self.source}"
event["uid"] = f"oncall-{self.uuid}-PK{self.public_primary_key}-U{user_counter}-E{counter}-S{self.source}"
event.add("summary", self.get_summary_with_user_for_ical(user))
event.add("dtstart", self.convert_dt_to_schedule_timezone(start, time_zone))
event.add("dtend", self.convert_dt_to_schedule_timezone(start + self.duration, time_zone))

View file

@ -213,10 +213,14 @@ class OnCallSchedule(PolymorphicModel):
raise NotImplementedError
def _drop_primary_ical_file(self):
raise NotImplementedError
self.prev_ical_file_primary = self.cached_ical_file_primary
self.cached_ical_file_primary = None
self.save(update_fields=["cached_ical_file_primary", "prev_ical_file_primary"])
def _drop_overrides_ical_file(self):
raise NotImplementedError
self.prev_ical_file_overrides = self.cached_ical_file_overrides
self.cached_ical_file_overrides = None
self.save(update_fields=["cached_ical_file_overrides", "prev_ical_file_overrides"])
class OnCallScheduleICal(OnCallSchedule):
@ -255,26 +259,6 @@ class OnCallScheduleICal(OnCallSchedule):
cached_ical_file = self.cached_ical_file_overrides
return cached_ical_file
def _drop_primary_ical_file(self):
self.prev_ical_file_primary = self.cached_ical_file_primary
self.cached_ical_file_primary = None
self.save(
update_fields=[
"cached_ical_file_primary",
"prev_ical_file_primary",
]
)
def _drop_overrides_ical_file(self):
self.prev_ical_file_overrides = self.cached_ical_file_overrides
self.cached_ical_file_overrides = None
self.save(
update_fields=[
"cached_ical_file_overrides",
"prev_ical_file_overrides",
]
)
def _refresh_primary_ical_file(self):
self.prev_ical_file_primary = self.cached_ical_file_primary
if self.ical_url_primary is not None:
@ -351,26 +335,6 @@ class OnCallScheduleCalendar(OnCallSchedule):
)
self.save(update_fields=["cached_ical_file_overrides", "prev_ical_file_overrides", "ical_file_error_overrides"])
def _drop_primary_ical_file(self):
self.prev_ical_file_primary = self.cached_ical_file_primary
self.cached_ical_file_primary = None
self.save(
update_fields=[
"cached_ical_file_primary",
"prev_ical_file_primary",
]
)
def _drop_overrides_ical_file(self):
self.prev_ical_file_overrides = self.cached_ical_file_overrides
self.cached_ical_file_overrides = None
self.save(
update_fields=[
"cached_ical_file_overrides",
"prev_ical_file_overrides",
]
)
def _generate_ical_file_primary(self):
"""
Generate iCal events file from custom on-call shifts (created via API)
@ -438,11 +402,6 @@ class OnCallScheduleWeb(OnCallSchedule):
self.cached_ical_file_primary = self._generate_ical_file_primary()
self.save(update_fields=["cached_ical_file_primary", "prev_ical_file_primary"])
def _drop_primary_ical_file(self):
self.prev_ical_file_primary = self.cached_ical_file_primary
self.cached_ical_file_primary = None
self.save(update_fields=["cached_ical_file_primary", "prev_ical_file_primary"])
@cached_property
def _ical_file_overrides(self):
"""Return cached ical file with iCal events from custom on-call overrides shifts."""
@ -455,8 +414,3 @@ class OnCallScheduleWeb(OnCallSchedule):
self.prev_ical_file_overrides = self.cached_ical_file_overrides
self.cached_ical_file_overrides = self._generate_ical_file_overrides()
self.save(update_fields=["cached_ical_file_overrides", "prev_ical_file_overrides"])
def _drop_overrides_ical_file(self):
self.prev_ical_file_overrides = self.cached_ical_file_overrides
self.cached_ical_file_overrides = None
self.save(update_fields=["cached_ical_file_overrides", "prev_ical_file_overrides"])

View file

@ -1,7 +1,9 @@
from uuid import uuid4
import pytest
from django.utils import timezone
from apps.schedules.ical_utils import list_users_to_notify_from_ical, users_in_ical
from apps.schedules.ical_utils import list_users_to_notify_from_ical, parse_event_uid, users_in_ical
from apps.schedules.models import CustomOnCallShift, OnCallScheduleCalendar
from common.constants.role import Role
@ -58,3 +60,20 @@ def test_list_users_to_notify_from_ical_viewers_inclusion(
else:
assert len(users_on_call) == 1
assert set(users_on_call) == {user}
def test_parse_event_uid_v1():
uuid = uuid4()
event_uid = f"amixr-{uuid}-U1-E2-S1"
pk, source = parse_event_uid(event_uid)
assert pk is None
assert source == "api"
def test_parse_event_uid_v2():
uuid = uuid4()
pk_value = "OABCDEF12345"
event_uid = f"oncall-{uuid}-PK{pk_value}-U3-E1-S2"
pk, source = parse_event_uid(event_uid)
assert pk == pk_value
assert source == "slack"