PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / 1.0.58
Timetics – Appointment Booking Calendar & Scheduling v1.0.58
1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 All 62 releases
timetics / core / integrations / google / service / calendar.php

calendar.php in Timetics – Appointment Booking Calendar & Scheduling 1.0.58, at core/integrations/google/service/calendar.php

396 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Google Calendar Class
4 *
5 * @package Timetics
6 */
7 namespace Timetics\Core\Integrations\Google\Service;
8
9 /**
10 * Class Calendar
11 */
12 class Calendar {
13 const TIMETICS_TIMEZONE_URI = 'https://www.googleapis.com/calendar/v3/users/me/settings/timezone';
14 const TIMETICS_CALENDAR_EVENT = 'https://www.googleapis.com/calendar/v3/calendars/primary/events';
15
16
17 /**
18 * Get events from the calendar for the last 3 months.
19 *
20 * @param int $user_id Team member ID.
21 * @param array $api_filters Additional API filters for google calendar API
22 *
23 * @return array List of calendar events.
24 */
25 public function get_events( $user_id, $api_filters = array() ) {
26 $access_token = timetics_get_google_access_token($user_id);
27
28 if ( ! $access_token ) {
29 return ['error' => 'Access token not found or expired.'];
30 }
31
32 // Define the time range for the last 3 months
33 // Use gmdate() for API queries to ensure UTC timestamps.
34 $three_months_ago = gmdate( 'c', strtotime( '-3 months' ) );
35 $three_months_ahead = gmdate( 'c', strtotime( '+3 months' ) ); // 3 months ahead date-time in RFC3339 format
36
37 $filters = array(
38 'timeMin' => rawurlencode($three_months_ago),
39 'timeMax' => rawurlencode($three_months_ahead),
40 'orderBy' => 'startTime',
41 'singleEvents' => 'true',
42 );
43
44 // add additional api filters if needed
45 $filters = array_merge( $filters, $api_filters );
46
47 // API URL with time range filter
48 $api_url = add_query_arg( $filters, self::TIMETICS_CALENDAR_EVENT);
49
50 // Set headers
51 $args = [
52 'headers' => [
53 'Authorization' => 'Bearer ' . $access_token,
54 'Content-Type' => 'application/json',
55 ],
56 ];
57
58 // Fetch data from Google Calendar API
59 $response = wp_remote_get( $api_url, $args );
60 if ( is_wp_error( $response ) ) {
61 return [];
62 }
63
64 $body = wp_remote_retrieve_body( $response );
65 $events = json_decode($body, true);
66
67 if ( empty( $events['items'] ) ) {
68 return [];
69 }
70
71 // Filter required fields
72 $filtered_events = [];
73 foreach ( $events['items'] as $event ) {
74 if ( empty( $event['start'] ) ) {
75 continue;
76 }
77
78 $start = ! empty($event['start']['dateTime']) ? $event['start']['dateTime'] : $event['start']['date'];
79 $end = ! empty($event['end']['dateTime']) ? $event['end']['dateTime'] : $event['end']['date'];
80
81 $timezone = $event['start']['timeZone'] ?? wp_timezone_string();
82 $timezone = new \DateTimeZone( $timezone );
83
84 $start_dt = new \DateTime( $start );
85 $start_dt->setTimezone( $timezone );
86
87 $end_dt = new \DateTime( $end );
88 $end_dt->setTimezone( $timezone );
89
90 $filtered_events[] = [
91 'id' => $event['id'] ?? '',
92 'start_date' => $start_dt->format( 'Y-m-d' ),
93 'start_time' => $start_dt->format( 'H:i:s' ),
94 'end_date' => $end_dt->format( 'Y-m-d' ),
95 'end_time' => $end_dt->format( 'H:i:s' ),
96 'summary' => $event['summary'] ?? '',
97 'description'=> $event['description'] ?? '',
98 ];
99 }
100
101 return $filtered_events;
102 }
103
104 /**
105 * Get event by ID
106 *
107 * @param string $event_id
108 *
109 * @return JSON | WP_Error
110 */
111 public function get_event( $event_id , $user_id = null ) {
112 if ( ! $user_id ) {
113 $user_id = get_current_user_id();
114 }
115
116 $access_token = timetics_get_google_access_token( $user_id );
117
118 $data = [
119 'headers' => [
120 'Authorization' => 'Bearer ' . $access_token,
121 ],
122 ];
123
124 $response = wp_remote_get(self::TIMETICS_CALENDAR_EVENT . '/' . $event_id, $data);
125
126 if ( is_wp_error( $response ) ) {
127 return ['error' => $response->get_error_message()];
128 }
129
130 $body = wp_remote_retrieve_body( $response );
131 $event = json_decode($body, true);
132
133 return $event;
134 }
135
136 /**
137 * Create event
138 *
139 * @param array $args Event data
140 *
141 * @return JSON | WP_Error
142 */
143 public function create_event( $args = [] ) {
144 $defaults = [
145 'summary' => '',
146 'description' => '',
147 'location' => '',
148 'start' => '',
149 'end' => '',
150 'attendees' => [],
151 'google_meet' => true,
152 'access_token' => '',
153 ];
154
155 $args = apply_filters( 'timetics/booking/create/google-event', $args);
156
157 $args = wp_parse_args( $args, $defaults );
158 $data = $this->prepare_request_data( $args );
159
160 $query_params = build_query( [
161 'conferenceDataVersion' => '1',
162 // 'sendUpdates' => 'all',
163 ] );
164
165 $response = wp_remote_post( self::TIMETICS_CALENDAR_EVENT . '?' . $query_params, $data );
166
167 if ( is_wp_error( $response ) ) {
168 return false;
169 }
170
171 $status_code = wp_remote_retrieve_response_code( $response );
172
173 if ( 200 != $status_code ) {
174 return false;
175 }
176
177 $data = json_decode( wp_remote_retrieve_body( $response ), true );
178
179 return $data;
180 }
181
182 /**
183 * Update calender event
184 *
185 * @param array $args
186 *
187 * @return array
188 */
189 public function update_event( $event_id, $args ) {
190 $defaults = [
191 'summary' => '',
192 'description' => '',
193 'location' => '',
194 'start' => '',
195 'end' => '',
196 'attendees' => [],
197 'google_meet' => true,
198 'access_token' => '',
199 'method' => 'PUT',
200 ];
201
202 $args = wp_parse_args( $args, $defaults );
203 $query_params = build_query( [
204 'conferenceDataVersion' => '1',
205 'sendUpdates' => 'all',
206 ] );
207
208 $data = $this->prepare_request_data( $args );
209 $data['method'] = 'PUT';
210
211 $response = wp_remote_post( self::TIMETICS_CALENDAR_EVENT . '/' . $event_id . '?' . $query_params, $data );
212
213 if ( is_wp_error( $response ) ) {
214 return false;
215 }
216
217 $status_code = wp_remote_retrieve_response_code( $response );
218
219 if ( 200 != $status_code ) {
220 return false;
221 }
222
223 $data = json_decode( wp_remote_retrieve_body( $response ), true );
224
225 return $data;
226 }
227
228 /**
229 * Get timzeson
230 *
231 * @return string | WP_Error
232 */
233 public function get_timezone( $access_token ) {
234 $data = [
235 'headers' => [
236 'Authorization' => 'Bearer ' . $access_token,
237 ],
238 ];
239
240 $response = wp_remote_get( self::TIMETICS_TIMEZONE_URI, $data );
241
242 if ( ! is_wp_error( $response ) ) {
243 $data = json_decode( wp_remote_retrieve_body( $response ), true );
244 return $data['value'];
245 }
246
247 return $response;
248 }
249
250 /**
251 * Delete google calendar event
252 *
253 * @param string $event_id
254 *
255 * @return array
256 */
257 public function delete_event( $event_id, $access_token ) {
258 $query_params = build_query( [
259 'conferenceDataVersion' => '1',
260 'sendUpdates' => 'all',
261 ] );
262
263 $response = wp_remote_post( self::TIMETICS_CALENDAR_EVENT . '/' . $event_id . '?' . $query_params, [
264 'headers' => [
265 'Authorization' => 'Bearer ' . $access_token,
266 'Content-Type' => 'application/json; charset=utf-8',
267 ],
268 'method' => 'DELETE',
269 ] );
270
271 if ( is_wp_error( $response ) ) {
272 return false;
273 }
274
275 $status_code = wp_remote_retrieve_response_code( $response );
276
277 if ( 200 != $status_code ) {
278 return false;
279 }
280
281 $data = json_decode( wp_remote_retrieve_body( $response ), true );
282
283 return $data;
284 }
285
286 /**
287 * Get timezone offset
288 *
289 * @param string $timezone
290 *
291 * @return string
292 */
293 public function get_timezone_offset( $timezone ) {
294 $current = timezone_open( $timezone );
295 $utc_time = new \DateTime( 'now', new \DateTimeZone( 'UTC' ) );
296 $offset_insecs = timezone_offset_get( $current, $utc_time );
297 $hours_and_sec = gmdate( 'H:i', abs( $offset_insecs ) );
298
299 return stripos( $offset_insecs, '-' ) === false ? "+{$hours_and_sec}" : "-{$hours_and_sec}";
300 }
301
302 /**
303 * Prepare time for calendar event
304 *
305 * @param array $data
306 *
307 * @return array
308 */
309 private function prepare_time( $data, $access_token ) {
310 $start_date = isset( $data['start']['date'] ) ? $data['start']['date'] : gmdate( 'Y-m-d' );
311 $start_time = isset( $data['start']['time'] ) ? $data['start']['time'] : gmdate( 'H:i:s' );
312 $end_date = isset( $data['end']['date'] ) ? $data['end']['date'] : gmdate( 'Y-m-d' );
313 $end_time = isset( $data['end']['time'] ) ? $data['end']['time'] : gmdate( 'H:i:s' );
314 $timezone = isset( $data['timezone'] ) ? $data['timezone'] : wp_timezone_string();
315
316 // Create DateTime objects with proper timezone to avoid double conversion.
317 $start_datetime = new \DateTime( $start_date . ' ' . $start_time, new \DateTimeZone( $timezone ) );
318 $end_datetime = new \DateTime( $end_date . ' ' . $end_time, new \DateTimeZone( $timezone ) );
319
320 return [
321 'start' => [
322 'dateTime' => $start_datetime->format( \DateTime::RFC3339 ),
323 'timeZone' => $timezone,
324 ],
325 'end' => [
326 'dateTime' => $end_datetime->format( \DateTime::RFC3339 ),
327 'timeZone' => $timezone,
328 ],
329 ];
330 }
331
332 /**
333 * Convet 12 hours format to 24 hours format
334 *
335 * @param string $time
336 *
337 * @return string
338 */
339 public function convertTo24HourFormat( $time ) {
340 // Use gmdate() instead of wp_date() to avoid timezone conversion
341 // since we're building an RFC3339 datetime string with explicit timezone offset.
342 return gmdate( 'H:i:s', strtotime( $time ) );
343 }
344
345 /**
346 * Prepare event create requested data
347 *
348 * @param array $args
349 *
350 * @return array
351 */
352 private function prepare_request_data( $args = [] ) {
353 $access_token = $args['access_token'];
354 $date = $this->prepare_time(
355 [
356 'start' => $args['start'],
357 'end' => $args['end'],
358 'timezone' => $args['timezone'],
359 ],
360 $access_token
361 );
362
363 $args['start'] = [$date['start']];
364 $args['end'] = [$date['end']];
365
366 if ( $args['google_meet'] ) {
367 $args['conferenceData'] = [
368 'createRequest' => [
369 'requestId' => 'sample123',
370 'conferenceSolutionKey' => ['type' => 'hangoutsMeet'],
371 ],
372 ];
373 }
374
375 unset( $args['access_token'] );
376 $data = [
377 'headers' => [
378 'Authorization' => 'Bearer ' . $access_token,
379 'Content-Type' => 'application/json; charset=utf-8',
380 ],
381 'body' => wp_json_encode( $args ),
382 ];
383
384 return $data;
385 }
386
387 /**
388 * Get google calendar auth scope
389 *
390 * @return string
391 */
392 public static function scope() {
393 return 'https://www.googleapis.com/auth/calendar';
394 }
395 }
396