PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
← All changes | app/Http/Controllers/BookingController.php +117 -3 2.2.0 → 2.5.0 View file →
@@ -5,8 +5,9 @@
5 5 use FluentBooking\App\App;
6 6 use FluentBooking\App\Models\Booking;
7 7 use FluentBooking\App\Models\CalendarSlot;
8 8 use FluentBooking\App\Services\BookingService;
9 +use FluentBooking\App\Services\RescheduleService;
9 10 use FluentBooking\App\Services\DateTimeHelper;
10 11 use FluentBooking\App\Services\BookingFieldService;
11 12 use FluentBooking\App\Hooks\Handlers\FrontEndHandler;
12 13 use FluentBooking\App\Hooks\Handlers\TimeSlotServiceHandler;
@@ -87,13 +88,15 @@
87 88
88 89 $locationType = Arr::get($postedData, 'location_type');
89 90
90 91 if ($calendarEvent->isPhoneRequired()) {
91 - $rules['location_description'] = 'required';
92 + $rules['location_description'] = ['required', $this->validPhoneNumberRule()];
92 93 $messages['location_description.required'] = __('Please provide attendee\'s phone number', 'fluent-booking');
93 94 } else if ($calendarEvent->isAddressRequired()) {
94 95 $rules['location_description'] = 'required';
95 96 $messages['location_description.required'] = __('Please provide attendee\'s address', 'fluent-booking');
97 + } else if ($locationType === 'phone_guest') {
98 + $rules['location_description'] = [$this->validPhoneNumberRule()];
96 99 }
97 100
98 101 $additionalGuests = Arr::get($postedData, 'guests', []);
99 102 if (!empty($additionalGuests)) {
@@ -194,9 +197,17 @@
194 197 $bookingData['source_url'] = sanitize_url($sourceUrl);
195 198 }
196 199
197 200 if ($hostUserId = Arr::get($postedData, 'host_user_id', null)) {
198 - $bookingData['host_user_id'] = (int) $hostUserId;
201 + $hostUserId = (int) $hostUserId;
202 +
203 + if (!in_array($hostUserId, array_map('intval', $calendarEvent->getHostIds()), true)) {
204 + return $this->sendError([
205 + 'message' => __('The selected host is not a host of this event', 'fluent-booking')
206 + ], 422);
207 + }
208 +
209 + $bookingData['host_user_id'] = $hostUserId;
199 210 }
200 211
201 212 $hostIds = null;
202 213 if ($calendarEvent->isRoundRobin() && !$hostUserId) {
@@ -252,8 +263,20 @@
252 263 'message' => __('Booking has been created', 'fluent-booking'),
253 264 ];
254 265 }
255 266
267 + /**
268 + * @return \Closure
269 + */
270 + private function validPhoneNumberRule()
271 + {
272 + return function ($attribute, $value) {
273 + if (!empty($value) && !Helper::isValidPhoneNumber($value)) {
274 + return __('Please provide a valid phone number', 'fluent-booking');
275 + }
276 + };
277 + }
278 +
256 279 public function getEvent(Request $request, $eventId)
257 280 {
258 281 $calendarEvent = CalendarSlot::find($eventId);
259 282
@@ -291,9 +314,19 @@
291 314
292 315 $duration = $calendarEvent->getDuration($request->get('duration'));
293 316
294 317 $hostId = $request->get('host_id', null);
295 -
318 +
319 + if ($hostId) {
320 + $hostId = (int) $hostId;
321 +
322 + if (!in_array($hostId, array_map('intval', $calendarEvent->getHostIds()), true)) {
323 + wp_send_json([
324 + 'message' => __('The selected host is not a host of this event', 'fluent-booking')
325 + ], 422);
326 + }
327 + }
328 +
296 329 $timeSlotService = TimeSlotServiceHandler::initService($calendar, $calendarEvent);
297 330
298 331 if (is_wp_error($timeSlotService)) {
299 332 return TimeSlotServiceHandler::sendError($timeSlotService, $calendarEvent, $timeZone);
@@ -368,8 +401,89 @@
368 401
369 402 return [
370 403 'bookings' => $formattedBookings,
371 404 'total' => $totalBookings
405 + ];
406 + }
407 +
408 + public function getRescheduleSlots(Request $request, $eventId, $bookingId)
409 + {
410 + return $this->getEvent($request, $eventId);
411 + }
412 +
413 + public function rescheduleBooking(Request $request, $eventId, $bookingId)
414 + {
415 + $booking = Booking::with(['calendar_event'])->findOrFail($bookingId);
416 +
417 + $data = $request->all();
418 +
419 + $this->validate($data, [
420 + 'event_time' => 'required',
421 + 'timezone' => 'required'
422 + ], [
423 + 'event_time.required' => __('Please select a date and time', 'fluent-booking'),
424 + 'timezone.required' => __('Please select the timezone', 'fluent-booking')
425 + ]);
426 +
427 + $calendarEvent = $booking->calendar_event;
428 +
429 + if (!$calendarEvent || (int) $calendarEvent->id !== (int) $eventId) {
430 + return $this->sendError(['message' => __('The event of this booking was not found', 'fluent-booking')], 422);
431 + }
432 +
433 + if (!in_array($booking->status, ['scheduled', 'pending', 'approved', 'rescheduled'], true)) {
434 + return $this->sendError(['message' => __('This booking can not be rescheduled', 'fluent-booking')], 422);
435 + }
436 +
437 + $timezone = sanitize_text_field(Arr::get($data, 'timezone'));
438 +
439 + if (!in_array($timezone, \DateTimeZone::listIdentifiers(), true)) {
440 + return $this->sendError(['message' => __('Please select a valid timezone', 'fluent-booking')], 422);
441 + }
442 +
443 + $eventTime = sanitize_text_field(Arr::get($data, 'event_time'));
444 +
445 + if (!\DateTime::createFromFormat('Y-m-d H:i:s', $eventTime)) {
446 + return $this->sendError(['message' => __('Please select a valid date and time', 'fluent-booking')], 422);
447 + }
448 +
449 + $startTime = DateTimeHelper::convertToUtc($eventTime, $timezone);
450 + $endTime = gmdate('Y-m-d H:i:s', strtotime($startTime) + ($booking->slot_minutes * 60)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
451 +
452 + $hostUserId = null;
453 +
454 + if (!Arr::isTrue($data, 'ignore_availability')) {
455 + $timeSlotService = TimeSlotServiceHandler::initService($calendarEvent->calendar, $calendarEvent);
456 +
457 + if (is_wp_error($timeSlotService)) {
458 + return $this->sendError(['message' => $timeSlotService->get_error_message()], 422);
459 + }
460 +
461 + $isSlotLocked = Helper::lockRoundRobinSlot($calendarEvent, $startTime, $endTime);
462 +
463 + if (!$isSlotLocked || !$timeSlotService->isSpotAvailable($startTime, $endTime, $booking->slot_minutes)) {
464 + return $this->sendError([
465 + 'message' => __('This selected time slot is not available. Maybe someone booked the spot just a few seconds ago.', 'fluent-booking')
466 + ], 422);
467 + }
468 +
469 + if ($calendarEvent->isRoundRobin()) {
470 + $hostUserId = $timeSlotService->hostUserId;
471 + }
472 + }
473 +
474 + $result = RescheduleService::reschedule($booking, $calendarEvent, $startTime, $timezone, [
475 + 'reason' => Arr::get($data, 'reason', ''),
476 + 'host_user_id' => $hostUserId,
477 + 'source' => __('Admin Panel', 'fluent-booking')
478 + ]);
479 +
480 + if (is_wp_error($result)) {
481 + return $this->sendError(['message' => $result->get_error_message()], 422);
482 + }
483 +
484 + return [
485 + 'message' => __('Booking has been rescheduled', 'fluent-booking')
372 486 ];
373 487 }
374 488
375 489 private static function sanitize_mapped_data($settings)