PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / trunk
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution vtrunk
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 1.7.2 All 33 releases
← All changes | app/Services/CalendarService.php +89 -13 1.5.21trunk View file →
@@ -92,9 +92,9 @@
92 92
93 93 foreach ($createdEvents as $index => $event) {
94 94 $eventMetasData = Arr::get($createEventMetasData, $index, []);
95 95
96 - $eventMetasData = self::prepareEventMetas($eventMetasData);
96 + $eventMetasData = self::prepareEventMetas($eventMetasData, $event);
97 97
98 98 $event->event_metas()->createMany($eventMetasData);
99 99 }
100 100
@@ -146,9 +146,9 @@
146 146 $firstCalendar = Calendar::where('user_id', $preparedData['user_id'])->where('type', 'simple')->first();
147 147
148 148 if ($isHostCalendar && $firstCalendar) {
149 149 if ($isFileInput) {
150 - return new \WP_Error('calendar_exists', esc_html__('The user already have a calendar. Please delete it first to create a new one', 'fluent-booking'));
150 + return new \WP_Error('calendar_exists', esc_html__('The user already has a calendar. Please delete it first to create a new one', 'fluent-booking'));
151 151 }
152 152 return $firstCalendar;
153 153 }
154 154
@@ -168,9 +168,11 @@
168 168
169 169 $preparedCalendarMetas[] = [
170 170 'key' => sanitize_text_field($calendarMeta['key']),
171 171 'value' => is_array($value) ? self::sanitize_mapped_data($value) : sanitize_text_field($value),
172 - 'object_type' => sanitize_text_field($calendarMeta['object_type'])
172 + // Bound to the imported calendar; never let the payload pick the type
173 + // (e.g. a user_meta / _access_permissions row).
174 + 'object_type' => 'Calendar'
173 175 ];
174 176 }
175 177
176 178 return $preparedCalendarMetas;
@@ -180,9 +182,9 @@
180 182 {
181 183 $preparedEventData = [
182 184 'title' => sanitize_text_field(Arr::get($eventData, 'title')),
183 185 'duration' => (int)Arr::get($eventData, 'duration', 30),
184 - 'description' => sanitize_textarea_field(Arr::get($eventData, 'description')),
186 + 'description' => wp_kses_post(Arr::get($eventData, 'description')),
185 187 'type' => sanitize_text_field(Arr::get($eventData, 'type')),
186 188 'status' => sanitize_text_field(Arr::get($eventData, 'status', 'active')),
187 189 'color_schema' => sanitize_text_field(Arr::get($eventData, 'color_schema', '#0099ff')),
188 190 'event_type' => sanitize_text_field(Arr::get($eventData, 'event_type')),
@@ -208,10 +210,10 @@
208 210 }
209 211
210 212 $preparedEventData['settings'] = [
211 213 'schedule_type' => sanitize_text_field(Arr::get($eventSettings, 'schedule_type')),
212 - 'weekly_schedules' => SanitizeService::weeklySchedules(Arr::get($eventSettings, 'weekly_schedules', []), $calendar->author_timezone, 'UTC'),
213 - 'date_overrides' => SanitizeService::slotDateOverrides(Arr::get($eventSettings, 'date_overrides', []), $calendar->author_timezone, 'UTC'),
214 + 'weekly_schedules' => SanitizeService::weeklySchedules(Arr::get($eventSettings, 'weekly_schedules', []), $calendar->author_timezone, 'UTC', true),
215 + 'date_overrides' => SanitizeService::slotDateOverrides(Arr::get($eventSettings, 'date_overrides', []), $calendar->author_timezone, 'UTC', null, true),
214 216 'range_type' => sanitize_text_field(Arr::get($eventSettings, 'range_type')),
215 217 'range_days' => (int)(Arr::get($eventSettings, 'range_days', 60)) ?: 60,
216 218 'range_date_between' => SanitizeService::rangeDateBetween(Arr::get($eventSettings, 'range_date_between', ['', ''])),
217 219 'schedule_conditions' => SanitizeService::scheduleConditions(Arr::get($eventSettings, 'schedule_conditions', [])),
@@ -236,14 +238,52 @@
236 238 'lock_timezone' => [
237 239 'enabled' => Arr::isTrue($eventSettings, 'lock_timezone.enabled'),
238 240 'timezone' => sanitize_text_field(Arr::get($eventSettings, 'lock_timezone.timezone'))
239 241 ],
242 + 'booking_title' => sanitize_text_field(Arr::get($eventSettings, 'booking_title')),
243 + 'submit_button_text' => sanitize_text_field(Arr::get($eventSettings, 'submit_button_text')),
244 + 'custom_redirect' => [
245 + 'enabled' => Arr::isTrue($eventSettings, 'custom_redirect.enabled'),
246 + 'redirect_url' => sanitize_url(Arr::get($eventSettings, 'custom_redirect.redirect_url')),
247 + 'is_query_string' => Arr::get($eventSettings, 'custom_redirect.is_query_string') == 'yes' ? 'yes' : 'no',
248 + 'query_string' => sanitize_text_field(Arr::get($eventSettings, 'custom_redirect.query_string')),
249 + ],
250 + 'requires_confirmation' => [
251 + 'enabled' => Arr::isTrue($eventSettings, 'requires_confirmation.enabled'),
252 + 'type' => sanitize_text_field(Arr::get($eventSettings, 'requires_confirmation.type')),
253 + 'condition' => [
254 + 'unit' => sanitize_text_field(Arr::get($eventSettings, 'requires_confirmation.condition.unit')),
255 + 'value' => intval(Arr::get($eventSettings, 'requires_confirmation.condition.value'))
256 + ]
257 + ],
258 + 'multiple_booking' => [
259 + 'enabled' => Arr::isTrue($eventSettings, 'multiple_booking.enabled'),
260 + 'limit' => intval(Arr::get($eventSettings, 'multiple_booking.limit'))
261 + ],
262 + 'can_not_cancel' => [
263 + 'enabled' => Arr::isTrue($eventSettings, 'can_not_cancel.enabled'),
264 + 'type' => sanitize_text_field(Arr::get($eventSettings, 'can_not_cancel.type')),
265 + 'message' => sanitize_text_field(Arr::get($eventSettings, 'can_not_cancel.message')),
266 + 'condition' => [
267 + 'unit' => sanitize_text_field(Arr::get($eventSettings, 'can_not_cancel.condition.unit')),
268 + 'value' => intval(Arr::get($eventSettings, 'can_not_cancel.condition.value'))
269 + ]
270 + ],
271 + 'can_not_reschedule' => [
272 + 'enabled' => Arr::isTrue($eventSettings, 'can_not_reschedule.enabled'),
273 + 'type' => sanitize_text_field(Arr::get($eventSettings, 'can_not_reschedule.type')),
274 + 'message' => sanitize_text_field(Arr::get($eventSettings, 'can_not_reschedule.message')),
275 + 'condition' => [
276 + 'unit' => sanitize_text_field(Arr::get($eventSettings, 'can_not_reschedule.condition.unit')),
277 + 'value' => intval(Arr::get($eventSettings, 'can_not_reschedule.condition.value'))
278 + ]
279 + ]
240 280 ];
241 281
242 282 return $preparedEventData;
243 283 }
244 284
245 - protected static function prepareEventMetas($eventMetasData)
285 + protected static function prepareEventMetas($eventMetasData, $event = null)
246 286 {
247 287 $preparedEventMetas = [];
248 288
249 289 foreach ($eventMetasData as $eventMeta) {
@@ -252,16 +292,28 @@
252 292 }
253 293
254 294 $value = $eventMeta['value'];
255 295
296 + // Only the two types an event actually stores; anything else in the
297 + // payload (e.g. user_meta / _access_permissions) is dropped.
298 + $objectType = sanitize_text_field(Arr::get($eventMeta, 'object_type'));
299 + if (!in_array($objectType, ['calendar_event', 'integration'], true)) {
300 + continue;
301 + }
302 +
256 303 if ($eventMeta['key'] == 'email_notification') {
257 304 $value = self::updateNotificationImageUrl($value);
258 305 }
259 306
307 + // Rendered on the public form via {@html}; sanitize as the admin path does.
308 + if ($eventMeta['key'] == 'booking_fields' && is_array($value)) {
309 + $value = BookingFieldService::sanitizeBookingFields($value, $event);
310 + }
311 +
260 312 $preparedEventMetas[] = [
261 313 'key' => sanitize_text_field($eventMeta['key']),
262 314 'value' => is_array($value) ? self::sanitize_mapped_data($value) : sanitize_text_field($value),
263 - 'object_type' => sanitize_text_field($eventMeta['object_type'])
315 + 'object_type' => $objectType
264 316 ];
265 317 }
266 318
267 319 return $preparedEventMetas;
@@ -301,12 +353,17 @@
301 353
302 354 return $formattedNotifications;
303 355 }
304 356
305 - public static function getSlotOptions($calendarId)
357 + public static function getSlotOptions($calendarId = null, $userId = null)
306 358 {
307 359 $calendarSlots = CalendarSlot::select(['id', 'title'])
308 - ->where('calendar_id', $calendarId)
360 + ->when($calendarId, function ($query) use ($calendarId) {
361 + return $query->where('calendar_id', $calendarId);
362 + })
363 + ->when($userId, function ($query) use ($userId) {
364 + return $query->where('user_id', $userId);
365 + })
309 366 ->where('status', '!=', 'expired')
310 367 ->latest()
311 368 ->get();
312 369
@@ -355,9 +412,9 @@
355 412 }
356 413
357 414 public static function getCalendarOptionsByTitle($condition = '')
358 415 {
359 - $calendarsQuery = Calendar::select(['id', 'title'])
416 + $calendarsQuery = Calendar::select(['id', 'title', 'user_id'])
360 417 ->where('status', '!=', 'expired')
361 418 ->with(['slots' => function ($query) {
362 419 $query->where('status', '!=', 'expired');
363 420 }]);
@@ -428,8 +485,27 @@
428 485
429 486 return $calendarIds;
430 487 }
431 488
489 + public static function isSharedCalendar($calendar)
490 + {
491 + $calendarEvents = $calendar->events;
492 +
493 + $userId = get_current_user_id();
494 +
495 + foreach ($calendarEvents as $event) {
496 + if ($event->user_id == $userId) {
497 + return true;
498 + }
499 + $teamMembers = Arr::get($event, 'settings.team_members', []);
500 + if (in_array($userId, $teamMembers)) {
501 + return true;
502 + }
503 + }
504 +
505 + return false;
506 + }
507 +
432 508 public static function updateCalendarEventsSchedule($calendarId, $oldTimezone, $updatedTimezone)
433 509 {
434 510 $calendarEvents = CalendarSlot::query()->where('calendar_id', $calendarId)->get();
435 511
@@ -435,14 +511,14 @@
435 511
436 512 foreach ($calendarEvents as $event) {
437 513 if ($weeklySchedule = Arr::get($event->settings, 'weekly_schedules', [])) {
438 514 $originalSchedule = SanitizeService::weeklySchedules($weeklySchedule, 'UTC', $oldTimezone);
439 - $weeklySchedule = SanitizeService::weeklySchedules($originalSchedule, $updatedTimezone, 'UTC');
515 + $weeklySchedule = SanitizeService::weeklySchedules($originalSchedule, $updatedTimezone, 'UTC', true);
440 516 }
441 517
442 518 if ($dateOverride = Arr::get($event->settings, 'date_overrides', [])) {
443 519 $originalOverride = SanitizeService::slotDateOverrides($dateOverride, 'UTC', $oldTimezone);
444 - $dateOverride = SanitizeService::slotDateOverrides($originalOverride, $updatedTimezone, 'UTC');
520 + $dateOverride = SanitizeService::slotDateOverrides($originalOverride, $updatedTimezone, 'UTC', null, true);
445 521 }
446 522
447 523 $event->settings = [
448 524 'weekly_schedules' => $weeklySchedule,