@@ -255,74 +255,194 @@ public function deleteCalendar( int $id ): JsonResponse {
255255 * @throws Exception
256256 */
257257 public function getEvents ( Request $ request ) {
258- $ request ->validate ( [
259- 'start ' => 'required|date ' ,
260- 'end ' => 'required|date ' ,
261- ] );
258+ // Special case: If looking for a specific event by ID
259+ $ eventId = $ request ->input ( 'eventId ' );
260+ if ( $ eventId ) {
261+ try {
262+ // Check if tables exist first
263+ if ( ! \Schema::hasTable ( 'calendars ' ) || ! \Schema::hasTable ( 'calendar_items ' ) ) {
264+ return response ()->json ( [] );
265+ }
262266
263- $ defaultTimezone = config ( 'app.timezone ' );
267+ $ events = [];
268+ $ calendars = Calendar::all ();
269+
270+ foreach ( $ calendars as $ calendar ) {
271+ if ( $ calendar ->enabled === false ) {
272+ continue ;
273+ }
274+ $ permissions = $ calendar ->permissionsForCurrentUser ();
275+ if ( $ permissions === null ) {
276+ continue ;
277+ }
278+ if ( $ permissions ['showInCalendar ' ] !== true ) {
279+ continue ;
280+ }
281+
282+ // For normal calendars, try to find the specific event
283+ if ( $ calendar ->type === 'normal ' ) {
284+ $ event = CalendarItem::where ( 'uid ' , $ eventId )
285+ ->orWhere ( 'id ' , $ eventId )
286+ ->where ( 'calendar_id ' , $ calendar ->id )
287+ ->first ();
288+
289+ if ( $ event ) {
290+ // Found the event, return it
291+ $ eventData = json_decode ( $ event ->toJson (), true );
292+
293+ // Generate mapping for used custom fields
294+ if ( isset ( $ eventData ['custom_fields ' ] ) && is_array ( $ eventData ['custom_fields ' ] ) ) {
295+ $ eventData ['custom_fields_mapping ' ] = $ this ->generateCustomFieldMapping (
296+ $ calendar ->custom_fields ,
297+ $ eventData ['custom_fields ' ]
298+ );
299+ }
300+
301+ // Set default timezone
302+ $ defaultTimezone = config ( 'app.timezone ' );
303+ $ eventData ['start ' ] = ( new DateTimeImmutable ( $ eventData ['start ' ], new DateTimeZone ( 'UTC ' ) ) )->setTimezone ( new DateTimeZone ( $ defaultTimezone ) )->format ( 'Y-m-d H:i:s ' );
304+ $ eventData ['end ' ] = ( new DateTimeImmutable ( $ eventData ['end ' ], new DateTimeZone ( 'UTC ' ) ) )->setTimezone ( new DateTimeZone ( $ defaultTimezone ) )->format ( 'Y-m-d H:i:s ' );
305+
306+ if ( empty ( $ eventData ['id ' ] ) && ! empty ( $ eventData ['uid ' ] ) ) {
307+ $ eventData ['id ' ] = $ eventData ['uid ' ];
308+ }
309+ if ( empty ( $ eventData ['uid ' ] ) && ! empty ( $ eventData ['id ' ] ) ) {
310+ $ eventData ['uid ' ] = $ eventData ['id ' ];
311+ }
312+ if ( empty ( $ eventData ['title ' ] ) ) {
313+ $ eventData ['title ' ] = '' ;
314+ }
315+
316+ $ events [] = $ eventData ;
317+ break ;
318+ }
319+ }
320+
321+ // For external calendars, we need to look through all events
322+ if ( $ calendar ->type === 'ics ' || $ calendar ->type === 'caldav ' ) {
323+ // Use a wider date range when searching for a specific event
324+ // Use an extremely wide date range to find any event, regardless of when it occurred
325+ // 5 years in past, 5 years in future
326+ $ wideStart = ( new DateTimeImmutable () )->sub ( new DateInterval ( 'P5Y ' ) )->setTimezone ( new DateTimeZone ( 'UTC ' ) );
327+ $ wideEnd = ( new DateTimeImmutable () )->add ( new DateInterval ( 'P5Y ' ) )->setTimezone ( new DateTimeZone ( 'UTC ' ) );
328+
329+ try {
330+ $ calendarEvents = $ calendar ->events ( $ wideStart , $ wideEnd );
331+ foreach ( $ calendarEvents as $ event ) {
332+ if ( isset ( $ event ['id ' ] ) && $ event ['id ' ] === $ eventId ) {
333+ // Found the event, prepare it for return
334+ if ( isset ( $ event ['custom_fields ' ] ) && is_array ( $ event ['custom_fields ' ] ) ) {
335+ $ event ['custom_fields_mapping ' ] = $ this ->generateCustomFieldMapping (
336+ $ calendar ->custom_fields ,
337+ $ event ['custom_fields ' ]
338+ );
339+ }
340+ $ events [] = $ event ;
341+ break ;
342+ }
343+ }
344+ } catch ( \Exception $ e ) {
345+ // Log and continue - we don't want a single calendar to break the entire request
346+ \Log::error ( 'Error fetching events from external calendar: ' . $ e ->getMessage () );
347+ }
348+ }
349+ }
264350
265- $ start = ( new DateTimeImmutable ( $ request ->input ( 'start ' ), new DateTimeZone ( $ defaultTimezone ) ) )->setTimezone ( new DateTimeZone ( 'UTC ' ) );
266- $ end = ( new DateTimeImmutable ( $ request ->input ( 'end ' ), new DateTimeZone ( $ defaultTimezone ) ) )->setTimezone ( new DateTimeZone ( 'UTC ' ) );
351+ // Restore timezones
352+ $ defaultTimezone = config ( 'app.timezone ' );
353+ foreach ( $ events as &$ event ) {
354+ $ event ['start ' ] = ( new DateTimeImmutable ( $ event ['start ' ], new DateTimeZone ( 'UTC ' ) ) )->setTimezone ( new DateTimeZone ( $ defaultTimezone ) )->format ( 'Y-m-d H:i:s ' );
355+ $ event ['end ' ] = ( new DateTimeImmutable ( $ event ['end ' ], new DateTimeZone ( 'UTC ' ) ) )->setTimezone ( new DateTimeZone ( $ defaultTimezone ) )->format ( 'Y-m-d H:i:s ' );
356+ }
357+ unset( $ event );
267358
268- $ calendars = Calendar::all ();
269- $ events = [];
359+ return response ()->json ( $ events );
360+ } catch ( \Exception $ e ) {
361+ // Log the error but return a valid response
362+ \Log::error ( 'Error in getEvents by ID: ' . $ e ->getMessage () );
270363
271- foreach ( $ calendars as $ calendar ) {
272- if ( $ calendar ->enabled === false ) {
273- continue ;
274- }
275- $ permissions = $ calendar ->permissionsForCurrentUser ();
276- if ( $ permissions === null ) {
277- continue ;
364+ return response ()->json ( [] );
278365 }
279- if ( $ permissions ['showInCalendar ' ] !== true ) {
280- continue ;
366+ }
367+
368+ try {
369+ // Regular date range query
370+ $ request ->validate ( [
371+ 'start ' => 'required|date ' ,
372+ 'end ' => 'required|date ' ,
373+ ] );
374+
375+ // Check if tables exist first
376+ if ( ! \Schema::hasTable ( 'calendars ' ) || ! \Schema::hasTable ( 'calendar_items ' ) ) {
377+ return response ()->json ( [] );
281378 }
282379
283- $ calendarEvents = $ calendar ->events ( $ start , $ end );
284- foreach ( $ calendarEvents as $ event ) {
285- // Generate mapping for used custom fields
286- if ( isset ( $ event ['custom_fields ' ] ) && is_array ( $ event ['custom_fields ' ] ) ) {
287- $ event ['custom_fields_mapping ' ] = $ this ->generateCustomFieldMapping (
288- $ calendar ->custom_fields ,
289- $ event ['custom_fields ' ]
290- );
380+ $ defaultTimezone = config ( 'app.timezone ' );
381+
382+ $ start = ( new DateTimeImmutable ( $ request ->input ( 'start ' ), new DateTimeZone ( $ defaultTimezone ) ) )->setTimezone ( new DateTimeZone ( 'UTC ' ) );
383+ $ end = ( new DateTimeImmutable ( $ request ->input ( 'end ' ), new DateTimeZone ( $ defaultTimezone ) ) )->setTimezone ( new DateTimeZone ( 'UTC ' ) );
384+
385+ $ calendars = Calendar::all ();
386+ $ events = [];
387+
388+ foreach ( $ calendars as $ calendar ) {
389+ if ( $ calendar ->enabled === false ) {
390+ continue ;
391+ }
392+ $ permissions = $ calendar ->permissionsForCurrentUser ();
393+ if ( $ permissions === null ) {
394+ continue ;
395+ }
396+ if ( $ permissions ['showInCalendar ' ] !== true ) {
397+ continue ;
291398 }
292- $ events [] = $ event ;
293- }
294- }
295399
296- /**
297- * Restore timezones
298- */
299- foreach ( $ events as &$ event ) {
300- if ( empty ( $ event ['id ' ] ) && ! empty ( $ event ['uid ' ] ) ) {
301- $ event ['id ' ] = $ event ['uid ' ];
302- }
303- if ( empty ( $ event ['uid ' ] ) && ! empty ( $ event ['id ' ] ) ) {
304- $ event ['uid ' ] = $ event ['id ' ];
400+ try {
401+ $ calendarEvents = $ calendar ->events ( $ start , $ end );
402+ foreach ( $ calendarEvents as $ event ) {
403+ // Generate mapping for used custom fields
404+ if ( isset ( $ event ['custom_fields ' ] ) && is_array ( $ event ['custom_fields ' ] ) ) {
405+ $ event ['custom_fields_mapping ' ] = $ this ->generateCustomFieldMapping (
406+ $ calendar ->custom_fields ,
407+ $ event ['custom_fields ' ]
408+ );
409+ }
410+ $ events [] = $ event ;
411+ }
412+ } catch ( \Exception $ e ) {
413+ // Log and continue - we don't want a single calendar to break the entire request
414+ \Log::error ( 'Error fetching events from calendar ' . $ calendar ->id . ': ' . $ e ->getMessage () );
415+ }
305416 }
306- if ( empty ( $ event ['title ' ] ) ) {
307- $ event ['title ' ] = '' ;
417+
418+ /**
419+ * Restore timezones
420+ */
421+ foreach ( $ events as &$ event ) {
422+ if ( empty ( $ event ['id ' ] ) && ! empty ( $ event ['uid ' ] ) ) {
423+ $ event ['id ' ] = $ event ['uid ' ];
424+ }
425+ if ( empty ( $ event ['uid ' ] ) && ! empty ( $ event ['id ' ] ) ) {
426+ $ event ['uid ' ] = $ event ['id ' ];
427+ }
428+ if ( empty ( $ event ['title ' ] ) ) {
429+ $ event ['title ' ] = '' ;
430+ }
431+
432+ $ event ['start ' ] = ( new DateTimeImmutable ( $ event ['start ' ], new DateTimeZone ( 'UTC ' ) ) )->setTimezone ( new DateTimeZone ( $ defaultTimezone ) )->format ( 'Y-m-d H:i:s ' );
433+ $ event ['end ' ] = ( new DateTimeImmutable ( $ event ['end ' ], new DateTimeZone ( 'UTC ' ) ) )->setTimezone ( new DateTimeZone ( $ defaultTimezone ) )->format ( 'Y-m-d H:i:s ' );
308434 }
435+ unset( $ event );
309436
310- $ event [ ' start ' ] = ( new DateTimeImmutable ( $ event [ ' start ' ], new DateTimeZone ( ' UTC ' ) ) )-> setTimezone ( new DateTimeZone ( $ defaultTimezone ) )-> format ( ' Y-m-d H:i:s ' );
311- $ event [ ' end ' ] = ( new DateTimeImmutable ( $ event [ ' end ' ], new DateTimeZone ( ' UTC ' ) ) )-> setTimezone ( new DateTimeZone ( $ defaultTimezone ) )-> format ( ' Y-m-d H:i:s ' );
312- }
313- unset( $ event );
437+ return response ()-> json ( $ events );
438+ } catch ( \ Exception $ e ) {
439+ // Log the error but return a valid response
440+ \Log:: error ( ' Error in getEvents date range: ' . $ e -> getMessage () );
314441
315- return response ()->json ( $ events );
442+ return response ()->json ( [] );
443+ }
316444 }
317445
318- /**
319- * Update an event
320- *
321- * @param Request $request
322- *
323- * @return JsonResponse
324- * @throws Exception
325- */
326446 /**
327447 * Update an event
328448 *
0 commit comments