From 6c1cf2e58f906484fcc294c88296a7bc181e0b73 Mon Sep 17 00:00:00 2001 From: Martin Schuhmacher <55735359+MartinSchuhmacher@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:19:58 +0100 Subject: [PATCH] BC-8213 - validate room dates (#5347) * fixing room date validation on create and update --- .../modules/room/domain/do/room.do.spec.ts | 52 ------------------- .../src/modules/room/domain/do/room.do.ts | 14 ----- .../room/domain/service/room.service.spec.ts | 17 ++++++ .../room/domain/service/room.service.ts | 11 ++++ 4 files changed, 28 insertions(+), 66 deletions(-) diff --git a/apps/server/src/modules/room/domain/do/room.do.spec.ts b/apps/server/src/modules/room/domain/do/room.do.spec.ts index bd213e52259..465fc4b95e8 100644 --- a/apps/server/src/modules/room/domain/do/room.do.spec.ts +++ b/apps/server/src/modules/room/domain/do/room.do.spec.ts @@ -1,4 +1,3 @@ -import { ValidationError } from '@shared/common'; import { EntityId } from '@shared/domain/types'; import { roomFactory } from '../../testing'; import { RoomColor } from '../type'; @@ -71,55 +70,4 @@ describe('Room', () => { const expectedUpdatedAt = new Date('2024-01-01'); expect(room.updatedAt).toEqual(expectedUpdatedAt); }); - - describe('time frame validation', () => { - const setup = () => { - const props: RoomProps = { - id: roomId, - name: 'Conference Room', - color: RoomColor.BLUE, - startDate: new Date('2024-01-01'), - endDate: new Date('2024-12-31'), - createdAt: new Date('2024-01-01'), - updatedAt: new Date('2024-01-01'), - }; - - return { props }; - }; - - describe('when costructor is called with invalid time frame', () => { - it('should throw validation error', () => { - const buildInvalid = () => { - const { props } = setup(); - props.startDate = new Date('2024-12-31'); - props.endDate = new Date('2024-01-01'); - // eslint-disable-next-line no-new - new Room(props); - }; - expect(buildInvalid).toThrowError(ValidationError); - }); - }); - - describe('when setting start date after end date', () => { - it('should throw validation error', () => { - const setInvalidStartDate = () => { - const { props } = setup(); - const inValidRoom = new Room(props); - inValidRoom.startDate = new Date('2025-01-01'); - }; - expect(setInvalidStartDate).toThrowError(ValidationError); - }); - }); - - describe('when setting end date before start date', () => { - it('should throw validation error', () => { - const setInvalidEndDate = () => { - const { props } = setup(); - const inValidRoom = new Room(props); - inValidRoom.endDate = new Date('2023-12-31'); - }; - expect(setInvalidEndDate).toThrowError(ValidationError); - }); - }); - }); }); diff --git a/apps/server/src/modules/room/domain/do/room.do.ts b/apps/server/src/modules/room/domain/do/room.do.ts index 05feb9d07d4..1cdd5093a63 100644 --- a/apps/server/src/modules/room/domain/do/room.do.ts +++ b/apps/server/src/modules/room/domain/do/room.do.ts @@ -1,4 +1,3 @@ -import { ValidationError } from '@shared/common'; import { AuthorizableObject, DomainObject } from '@shared/domain/domain-object'; import { EntityId } from '@shared/domain/types'; import { RoomColor } from '../type'; @@ -19,7 +18,6 @@ export type RoomUpdateProps = RoomCreateProps; // will probably change in the fu export class Room extends DomainObject { public constructor(props: RoomProps) { super(props); - this.validateTimeSpan(); } public getProps(): RoomProps { @@ -54,7 +52,6 @@ export class Room extends DomainObject { public set startDate(value: Date) { this.props.startDate = value; - this.validateTimeSpan(); } public get endDate(): Date | undefined { @@ -63,7 +60,6 @@ export class Room extends DomainObject { public set endDate(value: Date) { this.props.endDate = value; - this.validateTimeSpan(); } public get createdAt(): Date { @@ -73,14 +69,4 @@ export class Room extends DomainObject { public get updatedAt(): Date { return this.props.updatedAt; } - - private validateTimeSpan() { - if (this.props.startDate != null && this.props.endDate != null && this.props.startDate > this.props.endDate) { - throw new ValidationError( - `Invalid room timespan. Start date '${this.props.startDate.toISOString()}' has to be before end date: '${this.props.endDate.toISOString()}'. Room id='${ - this.id - }'` - ); - } - } } diff --git a/apps/server/src/modules/room/domain/service/room.service.spec.ts b/apps/server/src/modules/room/domain/service/room.service.spec.ts index 5edb5710a03..2eb114a4f1f 100644 --- a/apps/server/src/modules/room/domain/service/room.service.spec.ts +++ b/apps/server/src/modules/room/domain/service/room.service.spec.ts @@ -2,6 +2,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { Page } from '@shared/domain/domainobject'; import { EntityId } from '@shared/domain/types'; +import { ValidationError } from '@shared/common'; import { RoomRepo } from '../../repo'; import { roomFactory } from '../../testing'; import { Room, RoomCreateProps, RoomUpdateProps } from '../do'; @@ -80,6 +81,14 @@ describe('RoomService', () => { expect(roomRepo.save).toHaveBeenCalledWith(expect.objectContaining(props)); }); + + it('should throw validation error if start date is after end date', async () => { + const { props } = setup(); + props.startDate = new Date('2024-12-31'); + props.endDate = new Date('2024-01-01'); + + await expect(service.createRoom(props)).rejects.toThrowError(ValidationError); + }); }); describe('getSingleRoom', () => { @@ -137,6 +146,14 @@ describe('RoomService', () => { expect(roomRepo.save).toHaveBeenCalledWith(room); }); + + it('should throw validation error if start date is after end date', async () => { + const { props, room } = setup(); + props.startDate = new Date('2024-12-31'); + props.endDate = new Date('2024-01-01'); + + await expect(service.updateRoom(room, props)).rejects.toThrowError(ValidationError); + }); }); describe('deleteRoom', () => { diff --git a/apps/server/src/modules/room/domain/service/room.service.ts b/apps/server/src/modules/room/domain/service/room.service.ts index 9f0a974ae5b..4ec2c62c779 100644 --- a/apps/server/src/modules/room/domain/service/room.service.ts +++ b/apps/server/src/modules/room/domain/service/room.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@nestjs/common'; import { Page } from '@shared/domain/domainobject'; import { IFindOptions } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; +import { ValidationError } from '@shared/common'; import { RoomRepo } from '../../repo'; import { Room, RoomCreateProps, RoomProps, RoomUpdateProps } from '../do'; @@ -29,6 +30,7 @@ export class RoomService { createdAt: new Date(), updatedAt: new Date(), }; + this.validateTimeSpan(props, roomProps.id); const room = new Room(roomProps); await this.roomRepo.save(room); @@ -43,6 +45,7 @@ export class RoomService { } public async updateRoom(room: Room, props: RoomUpdateProps): Promise { + this.validateTimeSpan(props, room.id); Object.assign(room, props); await this.roomRepo.save(room); @@ -51,4 +54,12 @@ export class RoomService { public async deleteRoom(room: Room): Promise { await this.roomRepo.delete(room); } + + private validateTimeSpan(props: RoomCreateProps | RoomUpdateProps, roomId: string): void { + if (props.startDate != null && props.endDate != null && props.startDate > props.endDate) { + throw new ValidationError( + `Invalid room timespan. Start date '${props.startDate.toISOString()}' has to be before end date: '${props.endDate.toISOString()}'. Room id='${roomId}'` + ); + } + } }