Skip to content

Commit

Permalink
Update shift week_start when translating to UTC (#2134)
Browse files Browse the repository at this point in the history
Reworked #2124
  • Loading branch information
matiasb authored Jun 8, 2023
1 parent 84d6961 commit 7f9e13c
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 6 deletions.
18 changes: 17 additions & 1 deletion engine/apps/api/serializers/on_call_shifts.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class OnCallShiftSerializer(EagerLoadingMixin, serializers.ModelSerializer):
shift_start = serializers.DateTimeField(source="start")
shift_end = serializers.SerializerMethodField()
by_day = serializers.ListField(required=False, allow_null=True)
week_start = serializers.CharField(required=False, allow_null=True)
rolling_users = RollingUsersField(
allow_null=True,
required=False,
Expand Down Expand Up @@ -51,6 +52,7 @@ class Meta:
"frequency",
"interval",
"by_day",
"week_start",
"source",
"rolling_users",
"updated_shift",
Expand All @@ -65,6 +67,11 @@ class Meta:
def get_shift_end(self, obj):
return obj.start + obj.duration

def to_representation(self, instance):
ret = super().to_representation(instance)
ret["week_start"] = CustomOnCallShift.ICAL_WEEKDAY_MAP[instance.week_start]
return ret

def to_internal_value(self, data):
data["source"] = CustomOnCallShift.SOURCE_WEB
if not data.get("shift_end"):
Expand All @@ -80,6 +87,15 @@ def validate_by_day(self, by_day):
raise serializers.ValidationError(["Invalid day value."])
return by_day

def validate_week_start(self, week_start):
if week_start is None:
week_start = CustomOnCallShift.MONDAY

if week_start not in CustomOnCallShift.WEB_WEEKDAY_MAP:
raise serializers.ValidationError(["Invalid week start value."])

return CustomOnCallShift.ICAL_WEEKDAY_REVERSE_MAP[week_start]

def validate_interval(self, interval):
if interval is not None:
if not isinstance(interval, int) or interval <= 0:
Expand Down Expand Up @@ -171,7 +187,7 @@ def _correct_validated_data(self, event_type, validated_data):
if validated_data.get("schedule"):
validated_data["team"] = validated_data["schedule"].team

validated_data["week_start"] = CustomOnCallShift.MONDAY
validated_data["week_start"] = validated_data.get("week_start", CustomOnCallShift.MONDAY)

return validated_data

Expand Down
17 changes: 14 additions & 3 deletions engine/apps/api/tests/test_oncall_shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def test_create_on_call_shift_rotation(on_call_shift_internal_api_setup, make_us
CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY],
CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.FRIDAY],
],
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY],
"rolling_users": [[user1.public_primary_key], [user2.public_primary_key]],
}

Expand Down Expand Up @@ -86,6 +87,7 @@ def test_create_on_call_shift_override(on_call_shift_internal_api_setup, make_us
"id": response.data["id"],
"updated_shift": None,
"rolling_users": returned_rolling_users,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY],
}

assert response.status_code == status.HTTP_201_CREATED
Expand Down Expand Up @@ -130,6 +132,7 @@ def test_get_on_call_shift(
"frequency": None,
"interval": None,
"by_day": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.SUNDAY],
"rolling_users": [[user1.public_primary_key], [user2.public_primary_key]],
"updated_shift": None,
}
Expand Down Expand Up @@ -180,6 +183,7 @@ def test_list_on_call_shift(
"frequency": None,
"interval": None,
"by_day": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.SUNDAY],
"rolling_users": [[user1.public_primary_key], [user2.public_primary_key]],
"updated_shift": None,
}
Expand Down Expand Up @@ -237,6 +241,7 @@ def test_list_on_call_shift_filter_schedule_id(
"frequency": None,
"interval": None,
"by_day": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.SUNDAY],
"rolling_users": [[user1.public_primary_key], [user2.public_primary_key]],
"updated_shift": None,
}
Expand Down Expand Up @@ -318,6 +323,7 @@ def test_update_future_on_call_shift(
"frequency": None,
"interval": None,
"by_day": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY],
"rolling_users": [[user1.public_primary_key]],
"updated_shift": None,
}
Expand Down Expand Up @@ -385,6 +391,7 @@ def test_update_started_on_call_shift(
"frequency": None,
"interval": None,
"by_day": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY],
"rolling_users": [[user1.public_primary_key]],
"updated_shift": None,
}
Expand Down Expand Up @@ -413,19 +420,19 @@ def test_update_started_on_call_shift_force_update(
client = APIClient()
start_date = (timezone.now() - timezone.timedelta(hours=1)).replace(microsecond=0)

title = "Test Shift Rotation"
name = "Test Shift Rotation"
on_call_shift = make_on_call_shift(
schedule.organization,
shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT,
schedule=schedule,
title=title,
name=name,
start=start_date,
duration=timezone.timedelta(hours=3),
rotation_start=start_date,
rolling_users=[{user1.pk: user1.public_primary_key}],
)
data_to_update = {
"title": title,
"name": name,
"priority_level": 2,
"shift_start": start_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
"shift_end": (start_date + timezone.timedelta(hours=1)).strftime("%Y-%m-%dT%H:%M:%SZ"),
Expand All @@ -434,6 +441,7 @@ def test_update_started_on_call_shift_force_update(
"frequency": None,
"interval": None,
"by_day": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.SUNDAY],
"rolling_users": [[user1.public_primary_key]],
}

Expand Down Expand Up @@ -525,6 +533,7 @@ def test_update_old_on_call_shift_with_future_version(
"type": CustomOnCallShift.TYPE_ROLLING_USERS_EVENT,
"schedule": schedule.public_primary_key,
"updated_shift": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY],
}

assert response.status_code == status.HTTP_200_OK
Expand Down Expand Up @@ -579,6 +588,7 @@ def test_update_started_on_call_shift_name(
"frequency": None,
"interval": None,
"by_day": None,
"week_start": "MO",
"rolling_users": [[user1.public_primary_key]],
}

Expand All @@ -593,6 +603,7 @@ def test_update_started_on_call_shift_name(
"type": CustomOnCallShift.TYPE_ROLLING_USERS_EVENT,
"schedule": schedule.public_primary_key,
"updated_shift": None,
"week_start": CustomOnCallShift.ICAL_WEEKDAY_MAP[CustomOnCallShift.MONDAY],
}

assert response.status_code == status.HTTP_200_OK
Expand Down
10 changes: 8 additions & 2 deletions grafana-plugin/src/containers/RotationForm/RotationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ import { Schedule, Shift } from 'models/schedule/schedule.types';
import { getTzOffsetString } from 'models/timezone/timezone.helpers';
import { Timezone } from 'models/timezone/timezone.types';
import { User } from 'models/user/user.types';
import { getDateTime, getStartOfWeek, getUTCByDay, getUTCString } from 'pages/schedule/Schedule.helpers';
import {
getDateTime,
getStartOfWeek,
getUTCByDay,
getUTCString,
getUTCWeekStart,
} from 'pages/schedule/Schedule.helpers';
import { useStore } from 'state/useStore';
import { getCoords, waitForElement } from 'utils/DOM';
import { GRAFANA_HEADER_HEIGTH } from 'utils/consts';
Expand Down Expand Up @@ -204,7 +210,7 @@ const RotationForm2 = observer((props: RotationForm2Props) => {
interval: repeatEveryValue,
frequency: repeatEveryPeriod,
by_day: getUTCByDay(store.scheduleStore.byDayOptions, selectedDays, shiftStart),

week_start: getUTCWeekStart(store.scheduleStore.byDayOptions, shiftStart),
priority_level: shiftId === 'new' ? layerPriority : shift?.priority_level,
title: rotationTitle,
}),
Expand Down
1 change: 1 addition & 0 deletions grafana-plugin/src/models/schedule/schedule.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export interface CreateScheduleExportTokenResponse {

export interface Shift {
by_day: string[];
week_start: string;
frequency: number | null;
id: string;
interval: number;
Expand Down
20 changes: 20 additions & 0 deletions grafana-plugin/src/pages/schedule/Schedule.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@ export const getUTCByDay = (dayOptions: SelectOption[], by_day: string[], moment
return by_day;
};

export const getUTCWeekStart = (dayOptions: SelectOption[], moment: dayjs.Dayjs) => {
let week_start_index = 0;
let byDayOptions = [];
dayOptions.forEach(({ value }) => byDayOptions.push(value));
if (moment.day() !== moment.utc().day()) {
// when converting to UTC, shift starts on a different day,
// so we may need to change when week starts based on the UTC start time
// depending on the UTC side, move one day before or after
let offset = moment.utcOffset();
if (offset < 0) {
// move one day after
week_start_index = (week_start_index + 1) % 7;
} else {
// move one day before
week_start_index = (((week_start_index - 1) % 7) + 7) % 7;
}
}
return byDayOptions[week_start_index];
};

export const getColorSchemeMappingForUsers = (
store: RootStore,
scheduleId: string,
Expand Down

0 comments on commit 7f9e13c

Please sign in to comment.