From 161536fb5b28d930fdd518f757da521d37c366fd Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Tue, 5 Dec 2023 18:56:01 +0000 Subject: [PATCH] Fix weekly restriction bug in LayerUtil --- Common/Types/Date.ts | 35 ++++++++- Common/Types/Day/DayOfWeek.ts | 21 +++++ Common/Types/OnCallDutyPolicy/Layer.ts | 101 ++++++++++++++++++++++--- 3 files changed, 147 insertions(+), 10 deletions(-) diff --git a/Common/Types/Date.ts b/Common/Types/Date.ts index 5f822c9d36..2cdce32233 100644 --- a/Common/Types/Date.ts +++ b/Common/Types/Date.ts @@ -1,5 +1,5 @@ import InBetween from './Database/InBetween'; -import DayOfWeek from './Day/DayOfWeek'; +import DayOfWeek, { DayOfWeekUtil } from './Day/DayOfWeek'; import BadDataException from './Exception/BadDataException'; import { JSONObject, ObjectType } from './JSON'; import PositiveNumber from './PositiveNumber'; @@ -8,6 +8,39 @@ import moment from 'moment-timezone'; export const Moment: typeof moment = moment; export default class OneUptimeDate { + public static moveDateToTheDayOfWeek( + date: Date, + moveToWeek: Date, + dayOfWeek: DayOfWeek + ): Date { + // date will be moved to the week of "moveToWeek" and then to the day of week "dayOfWeek" + + date = this.fromString(date); + date = this.keepTimeButMoveDay(date, moveToWeek); + + // now move the date to the day of week + + const dateDayOfWeek: DayOfWeek = this.getDayOfWeek(date); + + if (dateDayOfWeek === dayOfWeek) { + return date; + } + + const numberOfDayOfWeek: number = + DayOfWeekUtil.getNumberOfDayOfWeek(dayOfWeek); + + const dateDayOfWeekNumber: number = + DayOfWeekUtil.getNumberOfDayOfWeek(dateDayOfWeek); + + const difference: number = numberOfDayOfWeek - dateDayOfWeekNumber; + + if (difference === 0) { + return date; + } + + return this.addRemoveDays(date, difference); + } + public static isOverlapping( start: Date, end: Date, diff --git a/Common/Types/Day/DayOfWeek.ts b/Common/Types/Day/DayOfWeek.ts index bb0020084b..c673cddd27 100644 --- a/Common/Types/Day/DayOfWeek.ts +++ b/Common/Types/Day/DayOfWeek.ts @@ -8,4 +8,25 @@ enum DayOfWeek { Saturday = 'Saturday', } +export class DayOfWeekUtil { + public static getNumberOfDayOfWeek(dayOfWeek: DayOfWeek): number { + switch (dayOfWeek) { + case DayOfWeek.Sunday: + return 0; + case DayOfWeek.Monday: + return 1; + case DayOfWeek.Tuesday: + return 2; + case DayOfWeek.Wednesday: + return 3; + case DayOfWeek.Thursday: + return 4; + case DayOfWeek.Friday: + return 5; + case DayOfWeek.Saturday: + return 6; + } + } +} + export default DayOfWeek; diff --git a/Common/Types/OnCallDutyPolicy/Layer.ts b/Common/Types/OnCallDutyPolicy/Layer.ts index 19aaee74ff..1dd95c3235 100644 --- a/Common/Types/OnCallDutyPolicy/Layer.ts +++ b/Common/Types/OnCallDutyPolicy/Layer.ts @@ -9,6 +9,7 @@ import OneUptimeDate from '../Date'; import EventInterval from '../Events/EventInterval'; import StartAndEndTime from '../Time/StartAndEndTime'; import Typeof from '../Typeof'; +import DayOfWeek from '../Day/DayOfWeek'; export interface LayerProps { users: Array; @@ -517,8 +518,19 @@ export default class LayerUtil { ]; } - if (restrictionTimes.restictionType === RestrictionType.Daily) { - return LayerUtil.getEventsByDailyRestriction(data); + if ( + restrictionTimes.restictionType === RestrictionType.Daily && + restrictionTimes.dayRestrictionTimes + ) { + return LayerUtil.getEventsByDailyRestriction({ + eventStartTime: data.eventStartTime, + eventEndTime: data.eventEndTime, + restrictionStartAndEndTime: + restrictionTimes.dayRestrictionTimes, + props: { + intervalType: EventInterval.Day, + }, + }); } if (restrictionTimes.restictionType === RestrictionType.Weekly) { @@ -538,7 +550,7 @@ export default class LayerUtil { // if there are no weekly restriction times, we dont have any restrictions and we can return the event start and end times - const trimmedStartAndEndTimes: Array = []; + let trimmedStartAndEndTimes: Array = []; if (!weeklyRestrictionTimes || weeklyRestrictionTimes.length === 0) { return [ @@ -549,19 +561,90 @@ export default class LayerUtil { ]; } - // const eventStartTime: Date = data.eventStartTime; - // const eventStartDayOfWeek: DayOfWeek = OneUptimeDate.getDayOfWeek(eventStartTime); + const restrictionStartAndEndTimes: Array = + LayerUtil.getWeeklyRestrictionTimesForWeek(data); + + for (const restrictionStartAndEndTime of restrictionStartAndEndTimes) { + const trimmedStartAndEndTimesForRestriction: Array = + LayerUtil.getEventsByDailyRestriction({ + eventStartTime: restrictionStartAndEndTime.startTime, + eventEndTime: restrictionStartAndEndTime.endTime, + restrictionStartAndEndTime: restrictionStartAndEndTime, + props: { + intervalType: EventInterval.Week, + }, + }); + + trimmedStartAndEndTimes = [ + ...trimmedStartAndEndTimes, + ...trimmedStartAndEndTimesForRestriction, + ]; + } return trimmedStartAndEndTimes; } + public static getWeeklyRestrictionTimesForWeek(data: { + eventStartTime: Date; + eventEndTime: Date; + restrictionTimes: RestrictionTimes; + }): Array { + const weeklyRestrictionTimes: Array = + data.restrictionTimes.weeklyRestrictionTimes; + + const eventStartTime: Date = data.eventStartTime; + + const startAndEndTimesOfWeeklyRestrictions: Array = []; + + for (const weeklyRestriction of weeklyRestrictionTimes) { + // move all of these to the week of the event start time + + const startDayOfWeek: DayOfWeek = weeklyRestriction.startDay; + const endDayOfWeek: DayOfWeek = weeklyRestriction.endDay; + + let startTime: Date = weeklyRestriction.startTime; + let endTime: Date = weeklyRestriction.endTime; + + // move start and end times to the week of the event start time + + startTime = OneUptimeDate.moveDateToTheDayOfWeek( + startTime, + eventStartTime, + startDayOfWeek + ); + endTime = OneUptimeDate.moveDateToTheDayOfWeek( + endTime, + eventStartTime, + endDayOfWeek + ); + + // now we have true start and end times of the weekly restriction + + // if start time is after end time, we need to add one week to the end time + + if (OneUptimeDate.isAfter(startTime, endTime)) { + endTime = OneUptimeDate.addRemoveWeeks(endTime, 1); + } + + startAndEndTimesOfWeeklyRestrictions.push({ + startTime, + endTime, + }); + } + + return startAndEndTimesOfWeeklyRestrictions; + } + public static getEventsByDailyRestriction(data: { eventStartTime: Date; eventEndTime: Date; - restrictionTimes: RestrictionTimes; + restrictionStartAndEndTime: StartAndEndTime; + props: { + intervalType: EventInterval; + }; }): Array { const dayRestrictionTimes: StartAndEndTime | null = - data.restrictionTimes.dayRestrictionTimes; + data.restrictionStartAndEndTime; // if there are no day restriction times, we dont have any restrictions and we can return the event start and end times @@ -697,11 +780,11 @@ export default class LayerUtil { restrictionStartTime = OneUptimeDate.addRemoveDays( restrictionStartTime, - 1 + data.props.intervalType === EventInterval.Day ? 1 : 7 // daily or weekly ); restrictionEndTime = OneUptimeDate.addRemoveDays( restrictionEndTime, - 1 + data.props.intervalType === EventInterval.Day ? 1 : 7 // daily or weekly ); } }