Use shift public key in events
This commit is contained in:
parent
fea2456a8f
commit
87fda3caf6
7 changed files with 67 additions and 73 deletions
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue