From 48fd71f78ae95a44283ba634405ddd97d669b336 Mon Sep 17 00:00:00 2001 From: Kumar Saurabh Date: Sat, 5 Sep 2026 09:45:07 +0530 Subject: [PATCH] fix(appointments): validate availability input Signed-off-by: Kumar Saurabh --- .../AppointmentConfigController.php | 19 ++++++ .../AppointmentConfigControllerTest.php | 63 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/lib/Controller/AppointmentConfigController.php b/lib/Controller/AppointmentConfigController.php index de47018be7..578bb67aeb 100644 --- a/lib/Controller/AppointmentConfigController.php +++ b/lib/Controller/AppointmentConfigController.php @@ -82,16 +82,35 @@ private function validateAvailability(array $availability): void { if ($expectedKeys !== $actualKeys) { throw new InvalidArgumentException('Invalid value for availability'); } + if (!is_string($availability['timezoneId']) || $availability['timezoneId'] === '') { + throw new InvalidArgumentException('Invalid value for availability timezone'); + } + try { + new \DateTimeZone($availability['timezoneId']); + } catch (\Exception $e) { + throw new InvalidArgumentException('Invalid value for availability timezone', 0, $e); + } $expectedDayKeys = ['FR', 'MO', 'SA', 'SU', 'TH', 'TU', 'WE']; + if (!is_array($availability['slots'])) { + throw new InvalidArgumentException('Invalid value for availability slots'); + } $actualDayKeys = array_keys($availability['slots']); sort($actualDayKeys); if ($expectedDayKeys !== $actualDayKeys) { throw new InvalidArgumentException('Invalid value for availability slots'); } + foreach ($availability['slots'] as $daySlots) { + if (!is_array($daySlots)) { + throw new InvalidArgumentException('Invalid value for availability slots'); + } + } $slots = array_merge(...array_values($availability['slots'])); foreach ($slots as $slot) { + if (!is_array($slot) || !isset($slot['start'], $slot['end']) || !is_int($slot['start']) || !is_int($slot['end']) || $slot['start'] >= $slot['end']) { + throw new InvalidArgumentException('Invalid value for availability slot'); + } $slotKeys = array_keys($slot); sort($slotKeys); if ($slotKeys !== ['end', 'start']) { diff --git a/tests/php/unit/Controller/AppointmentConfigControllerTest.php b/tests/php/unit/Controller/AppointmentConfigControllerTest.php index 8ad307020f..a710336833 100644 --- a/tests/php/unit/Controller/AppointmentConfigControllerTest.php +++ b/tests/php/unit/Controller/AppointmentConfigControllerTest.php @@ -145,6 +145,69 @@ public function testCreateEmptyAvailability(): void { self::assertEquals(422, $response->getStatus()); } + public function testCreateWithInvalidAvailabilityTimezone(): void { + $availability = $this->availability; + $availability['timezoneId'] = 'Invalid/Timezone'; + + $this->service->expects(self::never()) + ->method('create'); + + $response = $this->controller->create( + 'Test', + 'Test', + 'Test', + 'PUBLIC', + 'test', + $availability, + 5 * 60, + 5 * 60 + ); + + self::assertEquals(422, $response->getStatus()); + } + + public function testCreateWithInvalidAvailabilitySlot(): void { + $availability = $this->availability; + $availability['slots']['MO'][] = ['start' => '10:00', 'end' => '11:00']; + + $this->service->expects(self::never()) + ->method('create'); + + $response = $this->controller->create( + 'Test', + 'Test', + 'Test', + 'PUBLIC', + 'test', + $availability, + 5 * 60, + 5 * 60 + ); + + self::assertEquals(422, $response->getStatus()); + } + + public function testCreateWithInvalidAvailabilityDay(): void { + $availability = $this->availability; + $availability['slots']['MO'] = 'invalid'; + + $this->service->expects(self::never()) + ->method('create'); + + $response = $this->controller->create( + 'Test', + 'Test', + 'Test', + 'PUBLIC', + 'test', + $availability, + 5 * 60, + 5 * 60 + ); + + self::assertEquals(422, $response->getStatus()); + } + public function testCreate(): void { $appointment = new AppointmentConfig(); $appointment->setName('Test');