PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 3.3.3
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v3.3.3
4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / ThirdParty / Googlecalendar / Embedpress_Google_Helper.php
embedpress / EmbedPress / ThirdParty / Googlecalendar Last commit date
assets 4 years ago Embedpress_Google_Helper.php 4 years ago GoogleClient.php 4 years ago
Embedpress_Google_Helper.php
948 lines
1 <?php
2
3 if ( !class_exists( 'EmbedPress_GoogleClient') ) {
4 require_once 'GoogleClient.php';
5 }
6 if ( !defined( 'EPGC_NOTICES_VERIFY_SUCCESS') ) {
7 define('EPGC_NOTICES_VERIFY_SUCCESS', __('Verify OK!', 'embedpress'));
8 define('EPGC_NOTICES_REVOKE_SUCCESS', __('Access revoked. This plugin does not have access to your calendars anymore.', 'embedpress'));
9 define('EPGC_NOTICES_REMOVE_SUCCESS', sprintf(__('Plugin data removed. Make sure to also manually revoke access to your calendars in the Google <a target="__blank" href="%s">Permissions</a> page!', 'embedpress'), 'https://myaccount.google.com/permissions'));
10 define('EPGC_NOTICES_CALENDARLIST_UPDATE_SUCCESS', __('Calendars updated.', 'embedpress'));
11 define('EPGC_NOTICES_COLORLIST_UPDATE_SUCCESS', __('Colors updated.', 'embedpress'));
12 define('EPGC_NOTICES_CACHE_DELETED', __('Cache deleted.', 'embedpress'));
13
14 define('EPGC_ERRORS_CLIENT_SECRET_MISSING', __('No client secret.', 'embedpress'));
15 define('EPGC_ERRORS_CLIENT_SECRET_INVALID', __('Invalid client secret.', 'embedpress'));
16 define('EPGC_ERRORS_ACCESS_TOKEN_MISSING', __('No access token.', 'embedpress'));
17 define('EPGC_ERRORS_REFRESH_TOKEN_MISSING', sprintf(__('Your refresh token is missing!<br><br>This can only be solved by manually revoking this plugin&#39;s access in the Google <a target="__blank" href="%s">Permissions</a> page and remove all plugin data.', 'embedpress'), 'https://myaccount.google.com/permissions'));
18 define('EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING', __('No access and refresh tokens.', 'embedpress'));
19 define('EPGC_ERRORS_REDIRECT_URI_MISSING', __('URI <code>%s</code> missing in the client secret file. Adjust your Google project and upload the new client secret file.', 'embedpress'));
20 define('EPGC_ERRORS_INVALID_FORMAT', __('Invalid format', 'embedpress'));
21 define('EPGC_ERRORS_NO_CALENDARS', __('No calendars', 'embedpress'));
22 define('EPGC_ERRORS_NO_SELECTED_CALENDARS', __('No selected calendars', 'embedpress'));
23 define('EPGC_ERRORS_TOKEN_AND_API_KEY_MISSING', __('Access token and API key are missing.', 'embedpress'));
24 define('EPGC_TRANSIENT_PREFIX', 'pgc_ev_');
25 define('EPGC_ENQUEUE_ACTION_PRIORITY', 11);
26 define( 'EPGC_REDIRECT_URL', admin_url('admin.php?page=embedpress&page_type=google-calendar'));
27 }
28 if (!defined('EPGC_EVENTS_MAX_RESULTS')) {
29 define('EPGC_EVENTS_MAX_RESULTS', 250);
30 }
31
32 if (!defined('EPGC_EVENTS_DEFAULT_TITLE')) {
33 define('EPGC_EVENTS_DEFAULT_TITLE', '');
34 }
35
36
37 if (!defined('EPGC_ASSET_URL')) {
38 define('EPGC_ASSET_URL', plugin_dir_url(__FILE__) .'assets/');
39 }
40
41 class Embedpress_Google_Helper {
42
43 public static function print_calendar_list($calendarList = []) {
44 if ( empty( $calendarList) ) {
45 $calendarList = static::getDecoded( 'epgc_calendarlist' ); //settings_selected_calendar_ids_json_cb
46 }
47 if ( ! empty( $calendarList ) ) {
48 $selectedCalendarIds = get_option( 'epgc_selected_calendar_ids' ); // array
49 if ( empty( $selectedCalendarIds ) ) {
50 $selectedCalendarIds = [];
51 }
52 ?>
53 <ul>
54 <?php foreach ( $calendarList as $calendar ) { ?>
55 <?php
56 $calendarId = $calendar['id'];
57 $htmlId = md5( $calendarId );
58 ?>
59 <p class="epgc-calendar-filter">
60 <input id="<?php echo $htmlId; ?>" type="checkbox" name="epgc_selected_calendar_ids[]"
61 <?php if ( in_array( $calendarId, $selectedCalendarIds ) ) {
62 echo ' checked ';
63 } ?>
64 value="<?php echo esc_attr( $calendarId ); ?>"/>
65 <label for="<?php echo $htmlId; ?>">
66 <span class="epgc-calendar-color" style="background-color:<?php echo esc_attr( $calendar['backgroundColor'] ); ?>"></span>
67 <?php echo esc_html( $calendar['summary'] ); ?><?php if ( ! empty( $calendar['primary'] ) ) {
68 echo ' (primary)';
69 } ?>
70 </label>
71 <br>ID: <?php echo esc_html( $calendarId ); ?>
72 </p>
73 <?php } ?>
74 </ul>
75 <?php
76 $refreshToken = get_option( "epgc_refresh_token" );
77 if ( empty( $refreshToken ) ) {
78 static::show_notice( EPGC_ERRORS_REFRESH_TOKEN_MISSING, 'error', false );
79 }
80 } else {
81 ?>
82 <p><?php _e( 'No calendar was found.', 'embedpress' ); ?></p>
83 <?php
84 }
85 }
86
87 /**
88 * Helper function to return array from option (that should be a JSON string).
89 * @return array or $default = null
90 */
91 public static function getDecoded($optionName, $default = null) {
92 $item = get_option($optionName);
93 // $item should be a JSON string.
94 if (!empty($item)) {
95 return json_decode($item, true);
96 }
97 return $default;
98 }
99
100
101 public static function show_notice($notice, $type, $dismissable) {
102 ?>
103 <div class="notice notice-<?php echo esc_attr($type); echo $dismissable ? ' is-dismissible' : ''; ?>">
104 <p><?php echo $notice; ?></p>
105 </div>
106 <?php
107 }
108
109 public static function ajax_get_calendar() {
110
111 check_ajax_referer('epgc_nonce');
112
113 try {
114
115 if (empty($_POST['start']) || empty($_POST['end'])) {
116 throw new Exception(EPGC_ERRORS_INVALID_FORMAT);
117 }
118
119 // Start and end are in ISO8601 string format with timezone offset (e.g. 2018-09-01T12:30:00-05:00)
120 $start = $_POST['start'];
121 $end = $_POST['end'];
122
123 $thisCalendarids = [];
124 $postedCalendarIds = [];
125 if (array_key_exists('thisCalendarids', $_POST) && !empty($_POST['thisCalendarids'])) {
126 $postedCalendarIds = array_map('trim', explode(',', $_POST['thisCalendarids']));
127 }
128 $privateSettingsCalendarListIds = array_map(function($item) {
129 return $item['id'];
130 }, static::getDecoded('epgc_calendarlist', []));
131 if (!empty($privateSettingsCalendarListIds)) {
132 $privateSettingsSelectedCalendarListIds = get_option('epgc_selected_calendar_ids');
133 // if (empty($postedCalendarIds)) {
134 // // If we have private selected calendars in settings and we get NO selected calendars from widget, shortcode, Gutenberg block, this means
135 // // ALL private calendars will be used.
136 // $postedCalendarIds = $privateSettingsSelectedCalendarListIds;
137 // }
138 foreach ($postedCalendarIds as $calId) {
139 if (!in_array($calId, $privateSettingsCalendarListIds) || in_array($calId, $privateSettingsSelectedCalendarListIds)) {
140 $thisCalendarids[] = $calId;
141 }
142 }
143 } else {
144 $thisCalendarids = $postedCalendarIds;
145 }
146
147 $cacheTime = get_option('epgc_cache_time'); // empty == no cache!
148
149 // We can have mutiple calendars with different calendar selections,
150 // so key should be including calendar selection.
151 $transientKey = EPGC_TRANSIENT_PREFIX . $start . $end . md5(implode('-', $thisCalendarids));
152
153 $transientItems = !empty($cacheTime) ? get_transient($transientKey) : false;
154
155 $calendarListByKey = static::get_calendars_by_key($thisCalendarids);
156
157 if ($transientItems !== false) {
158 wp_send_json(['items' => $transientItems, 'calendars' => $calendarListByKey]);
159 wp_die();
160 }
161
162 $colorList = false; // false means not queried yet / otherwise [] or filled []
163
164 $results = [];
165
166 $optParams = array(
167 'maxResults' => EPGC_EVENTS_MAX_RESULTS,
168 'orderBy' => 'startTime',
169 'singleEvents' => 'true',
170 'timeMin' => $start,
171 'timeMax' => $end,
172 );
173 if (!empty($_POST['timeZone'])) {
174 $optParams['timeZone'] = $_POST['timeZone'];
175 }
176
177 $hasAccessToken = get_option('epgc_access_token');
178
179 if (!empty($hasAccessToken)) {
180
181 $client = static::getGoogleClient(true);
182 if ($client->isAccessTokenExpired()) {
183 if (!$client->getRefreshTOken()) {
184 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
185 }
186 $client->refreshAccessToken();
187 }
188 $service = new EmbedPress_GoogleCalendarClient($client);
189
190 foreach ($thisCalendarids as $calendarId) {
191 $results[$calendarId] = $service->getEvents($calendarId, $optParams);
192 }
193
194 } elseif (!empty(get_option('epgc_api_key'))) {
195
196 $referer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
197 $apiKey = get_option('epgc_api_key');
198 $service = new EmbedPress_GoogleCalendarClient(null);
199 foreach ($thisCalendarids as $calendarId) {
200 $results[$calendarId] = $service->getEventsPublic($calendarId, $optParams, $apiKey, $referer);
201 }
202
203 } else {
204 // No API key and no OAuth2 token
205 throw new Exception(EPGC_ERRORS_TOKEN_AND_API_KEY_MISSING);
206 }
207
208 $items = [];
209 foreach ($results as $calendarId => $events) {
210 foreach ($events as $item) {
211 $newItem = [
212 'title' => empty($item['summary']) ? EPGC_EVENTS_DEFAULT_TITLE : $item['summary'],
213 'htmlLink' => $item['htmlLink'],
214 'description' => !empty($item['description']) ? $item['description'] : '',
215 'calId' => $calendarId,
216 'creator' => !empty($item['creator']) ? $item['creator'] : [],
217 'attendees' => !empty($item['attendees']) ? $item['attendees'] : [],
218 'attachments' => !empty($item['attachments']) ? $item['attachments'] : [],
219 'location' => !empty($item['location']) ? $item['location'] : ''
220 ];
221 if (!empty($item['start']['date'])) {
222 $newItem['allDay'] = true;
223 $newItem['start'] = $item['start']['date'];
224 $newItem['end'] = $item['end']['date'];
225 // $newItem['timeZone'] = $item['start']['timeZone']; // TODO? end timezone also exists...
226 } else {
227 $newItem['start'] = $item['start']['dateTime'];
228 $newItem['end'] = $item['end']['dateTime'];
229 // $newItem['timeZone'] = $item['start']['timeZone']; // TODO? end timezone also exists...
230 }
231 if (!empty($item['colorId'])) {
232 if ($colorList === false) {
233 $colorList = static::getDecoded('pgc_colorlist', []);
234 }
235 if (array_key_exists('event', $colorList) && array_key_exists($item['colorId'], $colorList['event'])) {
236 $newItem['bColor'] = $colorList['event'][$item['colorId']]['background'];
237 $newItem['fColor'] = $colorList['event'][$item['colorId']]['foreground'];
238 }
239 }
240
241 $items[] = $newItem;
242 }
243 }
244
245 if (!empty($cacheTime)) {
246 set_transient($transientKey, $items, $cacheTime * MINUTE_IN_SECONDS);
247 }
248
249 wp_send_json(['items' => $items, 'calendars' => $calendarListByKey]);
250 wp_die();
251 } catch (EmbedPress_GoogleClient_RequestException $ex) {
252 wp_send_json([
253 'error' => $ex->getMessage(),
254 'errorCode' => $ex->getCode(),
255 'errorDescription' => $ex->getDescription()]);
256 wp_die();
257 } catch (Exception $ex) {
258 wp_send_json([
259 'error' => $ex->getMessage(),
260 'errorCode' => $ex->getCode()]);
261 wp_die();
262 }
263 }
264
265 public static function get_calendars_by_key($calendarIds) {
266
267 $publicCalendarList = get_option('pgc_public_calendarlist');
268 if (empty($publicCalendarList)) {
269 $publicCalendarList = [];
270 }
271 $privateCalendarList = static::getDecoded('epgc_calendarlist', []);
272 if (empty($privateCalendarList)) {
273 $privateCalendarList = [];
274 }
275 $calendarList = $publicCalendarList + $privateCalendarList;
276 $keyedCalendarList = [];
277 foreach ($calendarList as $cal) {
278 $keyedCalendarList[$cal['id']] = $cal;
279 }
280
281 $calendarListByKey = [];
282 foreach ($calendarIds as $calId) {
283 $cal = array_key_exists($calId, $keyedCalendarList) ? $keyedCalendarList[$calId] : [
284 'summary' => $calId,
285 'backgroundColor' => 'rgb(121, 134, 203)'
286 ];
287 $calendarListByKey[$calId] = [
288 'summary' => $cal['summary'],
289 'backgroundColor' => $cal['backgroundColor']
290 ];
291 }
292
293 return $calendarListByKey;
294 }
295 /**
296 * Helper function that returns a valid Google Client.
297 * @return Embedpress_GoogleClient instance
298 * @param bool $withTokens If true, also get tokens.
299 * @throws Exception.
300 */
301 public static function getGoogleClient($withTokens = false) {
302
303 $authConfig = get_option('epgc_client_secret');
304 if (empty($authConfig)) {
305 throw new Exception(EPGC_ERRORS_CLIENT_SECRET_MISSING);
306 }
307 $authConfig = static::getDecoded('epgc_client_secret');
308 if (empty($authConfig)) {
309 throw new Exception(EPGC_ERRORS_CLIENT_SECRET_INVALID);
310 }
311
312 $c = new Embedpress_GoogleClient($authConfig);
313 $c->setScope('https://www.googleapis.com/auth/calendar.readonly');
314 if (!self::check_redirect_uri($authConfig)) {
315 throw new Exception(sprintf(EPGC_ERRORS_REDIRECT_URI_MISSING, EPGC_REDIRECT_URL));
316 }
317 $c->setRedirectUri(EPGC_REDIRECT_URL);
318 $c->setTokenCallback(function($accessTokenInfo, $refreshToken) {
319 update_option('epgc_access_token', json_encode($accessTokenInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), false);
320 if (!empty($refreshToken)) {
321 update_option('epgc_refresh_token', $refreshToken, false);
322 }
323 });
324
325 if ($withTokens) {
326 $accessToken = static::getDecoded('epgc_access_token');
327 if (empty($accessToken)) {
328 throw new Exception(EPGC_ERRORS_ACCESS_TOKEN_MISSING);
329 }
330 $c->setAccessTokenInfo($accessToken);
331 $refreshToken = get_option("epgc_refresh_token");
332 if (empty($refreshToken)) {
333 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
334 }
335 $c->setRefreshToken($refreshToken);
336 }
337
338 return $c;
339
340 }
341
342 /**
343 * Helper function to check if we have a valid redirect uri in the client secret.
344 * @return bool
345 */
346 public static function check_redirect_uri($decodedClientSecret) {
347 return !empty($decodedClientSecret)
348 && !empty($decodedClientSecret['web'])
349 && !empty($decodedClientSecret['web']['redirect_uris'])
350 && in_array(EPGC_REDIRECT_URL, $decodedClientSecret['web']['redirect_uris']);
351 }
352
353
354 /**
355 * Get a valid formatted client secret.
356 * @return array|false Secret Array, false if no exists, Exception for invalid one
357 **/
358 public static function get_valid_client_secret(&$error = '') {
359 $clientSecret = get_option('epgc_client_secret');
360 if (empty($clientSecret)) {
361 return false;
362 }
363 $clientSecret = static::getDecoded('epgc_client_secret');
364 if (empty($clientSecret)
365 || empty($clientSecret['web'])
366 || empty($clientSecret['web']['client_secret'])
367 || empty($clientSecret['web']['client_id']))
368 {
369 $error = EPGC_ERRORS_CLIENT_SECRET_INVALID;
370 } elseif (!self::check_redirect_uri($clientSecret))
371 {
372 $error = sprintf(EPGC_ERRORS_REDIRECT_URI_MISSING, admin_url('options-general.php?page=pgc'));
373 }
374 return $clientSecret;
375 }
376
377 public static function delete_calendar_cache() {
378 global $wpdb;
379 $wpdb->query("DELETE FROM " . $wpdb->options
380 . " WHERE option_name LIKE '_transient_timeout_" . EPGC_TRANSIENT_PREFIX . "%' OR option_name LIKE '_transient_" . EPGC_TRANSIENT_PREFIX . "%'");
381 }
382
383 /**
384 * Helper function to delete all plugin options.
385 */
386 public static function delete_options($which) { // which = all, public, private
387 if ($which === 'all' || $which === 'private') {
388 delete_option('epgc_access_token');
389 delete_option('epgc_refresh_token');
390 delete_option('epgc_selected_calendar_ids');
391 delete_option('epgc_calendarlist');
392 delete_option('epgc_client_secret');
393 }
394 if ($which === 'all' || $which === 'public') {
395 delete_option('epgc_api_key');
396 }
397 if ($which === 'all') {
398 delete_option('epgc_cache_time');
399 }
400 }
401
402 public static function uninstall() {
403 try {
404 $client = static::getGoogleClient();
405 $accessToken = static::getDecoded('epgc_access_token');
406 if (!empty($accessToken)) {
407 $client->setAccessTokenInfo($accessToken);
408 }
409 $refreshToken = get_option("epgc_refresh_token");
410 if (!empty($refreshToken)) {
411 $client->setRefreshToken($refreshToken);
412 }
413 if (empty($accessToken) && empty($refreshToken)) {
414 throw new Exception(EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING);
415 }
416 $client->revoke();
417 } catch (Exception $ex) {
418 // Too bad...
419 } finally {
420 // Clear all plugin data
421 static::delete_plugin_data();
422 }
423 }
424
425 /**
426 * Helper function to delete all plugin data.
427 */
428 public static function delete_plugin_data($which = 'all') {
429 self::delete_calendar_cache();
430 self::delete_options($which);
431 }
432 public static function removable_query_args($removable_query_args) {
433 $removable_query_args[] = 'epgcnotice';
434 return $removable_query_args;
435 }
436
437 public static function notices_init() {
438 if (!empty($_GET['epgcnotice'])) {
439 $epgcnotices = get_option('epgc_notices_' . get_current_user_id());
440 if (empty($epgcnotices)) {
441 return;
442 }
443 delete_option('epgc_notices_' . get_current_user_id());
444 add_action('admin_notices', function() use ($epgcnotices) {
445 foreach ($epgcnotices as $notice) {
446 ?>
447 <div class="notice notice-<?php echo esc_attr($notice['type']); ?> is-dismissible">
448 <p><?php echo $notice['content']; ?></p>
449 </div>
450 <?php
451 }
452 });
453 }
454 }
455
456 /**
457 * Helper function to add notice messages.
458 * @param bool $redirect Redirect if true.
459 */
460 public static function add_notice($content, $type = 'success', $redirect = false) {
461 $epgcnotices = get_option('epgc_notices_' . get_current_user_id());
462 if (empty($epgcnotices)) {
463 $epgcnotices = [];
464 }
465 $epgcnotices[] = [
466 'content' => $content,
467 'type' => $type
468 ];
469 update_option('epgc_notices_' . get_current_user_id(), $epgcnotices, false);
470 if ($redirect) {
471 wp_redirect(EPGC_REDIRECT_URL ."&epgcnotice=true");
472 }
473 }
474
475 /**
476 * Helper function die with different kind of errors.
477 */
478 public static function embedpress_die($error = null) {
479 error_log( 'got hittt in error');
480 error_log( print_r( $error, 1));
481 $backLink = '<br><br><a href="' . admin_url('admin.php?page=embedpress&page_type=google-calendar') . '">' . __('Back', 'embedpress') . '</a>';
482 if (empty($error)) {
483 wp_die(__('Unknown error', 'embedpress') . $backLink);
484 }
485 if ($error instanceof Exception) {
486 $s = [];
487 if ($error->getCode()) {
488 $x[] = $error->getCode();
489 }
490 $s[] = $error->getMessage();
491 if ($error instanceof Embedpress_GoogleClient_RequestException) {
492 if ($error->getDescription()) {
493 $s[] = $error->getDescription();
494 }
495 }
496 wp_die(implode("<br>", $s) . $backLink);
497 } elseif (is_array($error)) {
498 wp_die(implode("<br>", $error) . $backLink);
499 } elseif (is_string($error)) {
500 wp_die($error . $backLink);
501 } else {
502 wp_die(__('Unknown error format', 'embedpress') . $backLink);
503 }
504 }
505
506 /**
507 * Helper function to return pretty printed JSON string.
508 * @return string
509 */
510 public static function getPrettyJSONString($jsonObject) {
511 return str_replace(" ", " ", json_encode($jsonObject, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
512 }
513
514 public static function sort_calendars(&$items) {
515 // Set locale to UTF-8 variant if this is not the case.
516 if (strpos(setlocale(LC_COLLATE, 0), '.UTF-8') === false) {
517 // If we set this to a non existing locale it will be the default locale after this call.
518 setlocale(LC_COLLATE, get_locale() . '.UTF-8');
519 }
520 usort($items, function($a, $b) {
521 return strcoll($a['summary'], $b['summary']);
522 });
523 }
524 public static function shortcode($atts = [], $content = null) {
525
526 // When we have no attributes, $atts is an empty string
527 if (!is_array($atts)) {
528 $atts = [];
529 }
530 wp_enqueue_style('dashicons');
531 wp_enqueue_style( 'fullcalendar');
532 wp_enqueue_style( 'fullcalendar_daygrid');
533 wp_enqueue_style( 'fullcalendar_timegrid');
534 wp_enqueue_style( 'fullcalendar_list');
535 wp_enqueue_style( 'epgc');
536 wp_enqueue_style( 'tippy_light');
537
538
539 wp_enqueue_script('popper');
540 wp_enqueue_script('tippy');
541 wp_enqueue_script('my_moment');
542 wp_enqueue_script('my_moment_timezone');
543 wp_enqueue_script('fullcalendar');
544 wp_enqueue_script('fullcalendar_moment');
545 wp_enqueue_script('fullcalendar_moment_timezone');
546 wp_enqueue_script('fullcalendar_daygrid');
547 wp_enqueue_script('fullcalendar_timegrid');
548 wp_enqueue_script('fullcalendar_list');
549 wp_enqueue_script('fullcalendar_locales');
550 wp_enqueue_script('epgc');
551 $defaultConfig = [
552 'header' => [
553 'left' => 'prev,next today',
554 'center' => 'title',
555 'right' => 'dayGridMonth,timeGridWeek,listWeek'
556 ]
557 ];
558 $userConfig = $defaultConfig; // copy
559 $userFilter = 'top';
560 $userEventPopup = 'true';
561 $userEventLink = 'true';
562 $userHidePassed = 'false';
563 $userHideFuture = 'false';
564 $userEventDescription = 'true';
565 $userEventLocation = 'true';
566 $userEventAttendees = 'false';
567 $userEventAttachments = 'false';
568 $userEventCreator = 'false';
569 $userEventCalendarname = 'false';
570 $calendarIds = '';
571 $uncheckedCalendarIds = ''; // in filter
572 // Get all non-fullcalendar known properties
573 foreach ($atts as $key => $value) {
574 if ($key === 'public') {
575 // This existsed in old versions, but we don't want it in our shortcode output, so skip it.
576 continue;
577 }
578 if ($key === 'filter') {
579 $userFilter = $value === 'true' ? 'top' : $value;
580 continue;
581 }
582 if ($key === 'eventpopup') {
583 $userEventPopup = $value;
584 continue;
585 }
586 if ($key === 'eventlink') {
587 $userEventLink = $value;
588 continue;
589 }
590 if ($key === 'hidepassed') {
591 $userHidePassed = $value;
592 continue;
593 }
594 if ($key === 'hidefuture') {
595 $userHideFuture = $value;
596 continue;
597 }
598 if ($key === 'eventdescription') {
599 $userEventDescription = $value;
600 continue;
601 }
602 if ($key === 'eventattachments') {
603 $userEventAttachments = $value;
604 continue;
605 }
606 if ($key === 'eventattendees') {
607 $userEventAttendees = $value;
608 continue;
609 }
610 if ($key === 'eventlocation') {
611 $userEventLocation = $value;
612 continue;
613 }
614 if ($key === 'eventcreator') {
615 $userEventCreator = $value;
616 continue;
617 }
618 if ($key === 'eventcalendarname') {
619 $userEventCalendarname = $value;
620 continue;
621 }
622 if ($key === 'uncheckedcalendarids' && !empty($value)) {
623 $uncheckedCalendarIds = $value; // comma separated string
624 continue;
625 }
626
627 if ($key === 'calendarids') {
628 if (!empty($value)) {
629 $calendarIds = $value; // comma separated string
630 }
631 continue;
632 }
633 if ($key === 'fullcalendarconfig') {
634 // A JSON string that we can directly send to FullCalendar
635 $userConfig = json_decode($value, true);
636 } else {
637 // Fullcalendar properties that get passed to fullCalendar instance.
638 $parts = explode('-', $key);
639 $partsCount = count($parts);
640 if ($partsCount > 1) {
641 $currentUserConfigLayer = &$userConfig;
642 for ($i = 0; $i < $partsCount; $i++) {
643 $part = $parts[$i];
644 if ($i + 1 === $partsCount) {
645 if ($value === 'true') {
646 $value = true;
647 } elseif ($value === 'false') {
648 $value = $value;
649 }
650 $currentUserConfigLayer[$part] = $value;
651 } else {
652 if (!array_key_exists($part, $currentUserConfigLayer)) {
653 $currentUserConfigLayer[$part] = [];
654 }
655 $currentUserConfigLayer = &$currentUserConfigLayer[$part];
656 }
657 }
658 } else {
659 $userConfig[$key] = $value;
660 }
661 }
662 }
663
664 $dataCalendarIds = '';
665 if (!empty($calendarIds)) {
666 $dataCalendarIds = 'data-calendarids=\'' . json_encode(array_map('trim', explode(',', $calendarIds))) . '\'';
667 } else {
668 $privateSettingsSelectedCalendarListIds = get_option('epgc_selected_calendar_ids', []);
669 if (!empty($privateSettingsSelectedCalendarListIds)) {
670 $dataCalendarIds = 'data-calendarids=\'' . json_encode($privateSettingsSelectedCalendarListIds) . '\'';
671 }
672 }
673
674 $dataUnchekedCalendarIds = '';
675 if (!empty($uncheckedCalendarIds)) {
676 $dataUnchekedCalendarIds = 'data-uncheckedcalendarids=\'' . json_encode(array_map('trim', explode(',', $uncheckedCalendarIds))) . '\'';
677 }
678
679 $filterHTML = '<div class="epgc-calendar-filter" ' . $dataUnchekedCalendarIds . '></div>';
680
681 return '<div class="epgc-calendar-wrapper epgc-calendar-page">' . ($userFilter === 'top' ? $filterHTML : '') . '<div '
682 . $dataCalendarIds . ' data-filter=\'' . $userFilter . '\' data-eventpopup=\'' . $userEventPopup . '\' data-eventlink=\''
683 . $userEventLink . '\' data-eventdescription=\'' . $userEventDescription . '\' data-eventlocation=\''
684 . $userEventLocation . '\' data-eventattachments=\'' . $userEventAttachments . '\' data-eventattendees=\''
685 . $userEventAttendees . '\' data-eventcreator=\'' . $userEventCreator . '\' data-eventcalendarname=\''
686 . $userEventCalendarname . '\' data-hidefuture=\'' . $userHideFuture . '\' data-hidepassed=\''
687 . $userHidePassed . '\' data-config=\'' . json_encode($userConfig) . '\' data-locale="'
688 . get_locale() . '" class="epgc-calendar"></div>' . ($userFilter === 'bottom' ? $filterHTML : '') . '</div>';
689 }
690
691 public static function admin_post_calendarlist() {
692 try {
693 $client = static::getGoogleClient(true);
694 if ($client->isAccessTokenExpired()) {
695 if (!$client->getRefreshToken()) {
696 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
697 }
698 $client->refreshAccessToken();
699 }
700 $service = new Embedpress_GoogleCalendarClient($client);
701 $items = $service->getCalendarList();
702
703 self::sort_calendars($items);
704
705 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
706 self::add_notice(PGC_NOTICES_CALENDARLIST_UPDATE_SUCCESS, 'success', true);
707 exit;
708 } catch (Exception $ex) {
709 self::embedpress_die($ex);
710 }
711 }
712 public static function admin_post_colorlist() {
713 try {
714 $client = static::getGoogleClient(true);
715 if ($client->isAccessTokenExpired()) {
716 if (!$client->getRefreshToken()) {
717 throw new Exception(PGC_ERRORS_REFRESH_TOKEN_MISSING);
718 }
719 $client->refreshAccessToken();
720 }
721 $service = new Embedpress_GoogleCalendarClient($client);
722 $items = $service->getColorList();
723 update_option('epgc_colorlist', self::getPrettyJSONString($items), false);
724 self::add_notice(EPGC_NOTICES_COLORLIST_UPDATE_SUCCESS, 'success', true);
725 exit;
726 } catch (Exception $ex) {
727 self::embedpress_die($ex);
728 }
729 }
730 public static function admin_post_deletecache() {
731 self::delete_calendar_cache();
732 self::add_notice(PGC_NOTICES_CACHE_DELETED, 'success', true);
733 exit;
734 }
735 public static function admin_post_verify() {
736 try {
737 $client = static::getGoogleClient(true);
738 $client->refreshAccessToken();
739 self::add_notice(PGC_NOTICES_VERIFY_SUCCESS, 'success', true);
740 exit;
741 } catch (Exception $ex) {
742 self::embedpress_die($ex);
743 }
744 }
745 public static function enqueue_scripts() {
746 wp_enqueue_style('dashicons');
747 wp_register_style('fullcalendar', EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.css', null, EMBEDPRESS_VERSION);
748 wp_register_style('fullcalendar_daygrid', EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
749 wp_register_style('fullcalendar_timegrid', EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.css', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION);
750 wp_register_style('fullcalendar_list', EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
751 wp_register_style('epgc', EPGC_ASSET_URL . 'css/epgc.css', ['fullcalendar_timegrid'], EMBEDPRESS_VERSION);
752 wp_register_style('tippy_light', EPGC_ASSET_URL . 'lib/tippy/light-border.css', null, EMBEDPRESS_VERSION);
753
754 //wp_enqueue_style( 'fullcalendar');
755 //wp_enqueue_style( 'fullcalendar_daygrid');
756 //wp_enqueue_style( 'fullcalendar_timegrid');
757 //wp_enqueue_style( 'fullcalendar_list');
758 //wp_enqueue_style( 'epgc');
759 //wp_enqueue_style( 'tippy_light');
760
761
762 wp_register_script('popper',EPGC_ASSET_URL . 'lib/popper.min.js', null, EMBEDPRESS_VERSION, true);
763 wp_register_script('tippy',EPGC_ASSET_URL . 'lib/tippy/tippy-bundle.umd.min.js', ['popper'], EMBEDPRESS_VERSION, true);
764 wp_register_script('my_moment',EPGC_ASSET_URL . 'lib/moment/moment-with-locales.min.js', null, EMBEDPRESS_VERSION, true);
765 wp_register_script('my_moment_timezone',EPGC_ASSET_URL . 'lib/moment/moment-timezone-with-data.min.js', ['my_moment'], EMBEDPRESS_VERSION, true);
766 wp_register_script('fullcalendar',EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.js', ['my_moment_timezone'], EMBEDPRESS_VERSION, true);
767 wp_register_script('fullcalendar_moment',EPGC_ASSET_URL . 'lib/fullcalendar4/moment/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
768 wp_register_script('fullcalendar_moment_timezone',EPGC_ASSET_URL . 'lib/fullcalendar4/moment-timezone/main.min.js', ['fullcalendar_moment'], EMBEDPRESS_VERSION, true);
769 wp_register_script('fullcalendar_daygrid',EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
770 wp_register_script('fullcalendar_timegrid',EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.js', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION, true);
771 wp_register_script('fullcalendar_list',EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
772 wp_register_script('fullcalendar_locales',EPGC_ASSET_URL . 'lib/fullcalendar4/core/locales-all.min.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
773 wp_register_script('epgc', EPGC_ASSET_URL . 'js/main.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
774
775 //wp_enqueue_script('popper');
776 //wp_enqueue_script('my_moment');
777 //wp_enqueue_script('my_moment_timezone');
778 //wp_enqueue_script('fullcalendar');
779 //wp_enqueue_script('fullcalendar_moment');
780 //wp_enqueue_script('fullcalendar_moment_timezone');
781 //wp_enqueue_script('fullcalendar_daygrid');
782 //wp_enqueue_script('fullcalendar_timegrid');
783 //wp_enqueue_script('fullcalendar_list');
784 //wp_enqueue_script('fullcalendar_locales');
785 //wp_enqueue_script('epgc');
786
787 $nonce = wp_create_nonce('epgc_nonce');
788 wp_localize_script('epgc', 'epgc_object', [
789 'ajax_url' => admin_url('admin-ajax.php'),
790 'nonce' => $nonce,
791 'trans' => [
792 'all_day' => __('All day', 'embedpress'),
793 'created_by' => __('Created by', 'embedpress'),
794 'go_to_event' => __('Go to event', 'embedpress'),
795 'unknown_error' => __('Unknown error', 'embedpress'),
796 'request_error' => __('Request error', 'embedpress'),
797 'loading' => __('Loading', 'embedpress')
798 ]
799 ]);
800
801 }
802
803 public static function remove_private_data() {
804 self::delete_plugin_data('private');
805 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
806 exit;
807 }
808
809 public static function admin_post_remove() {
810 self::delete_plugin_data();
811 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
812 exit;
813 }
814 public static function admin_post_revoke() {
815 try {
816 $client = self::getGoogleClient();
817 $accessToken = self::getDecoded('epgc_access_token');
818 if (!empty($accessToken)) {
819 $client->setAccessTokenInfo($accessToken);
820 }
821 $refreshToken = get_option("epgc_refresh_token");
822 if (!empty($refreshToken)) {
823 $client->setRefreshToken($refreshToken);
824 }
825 if (empty($accessToken) && empty($refreshToken)) {
826 throw new Exception(EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING);
827 }
828 $client->revoke();
829 // Clear access and refresh tokens
830 self::delete_plugin_data('private');
831 self::add_notice(EPGC_NOTICES_REVOKE_SUCCESS, 'success', true);
832 exit;
833 } catch (Exception $ex) {
834 self::embedpress_die($ex);
835 }
836 }
837 public static function admin_post_authorize() {
838 try {
839 $client = self::getGoogleClient();
840 $client->authorize();
841 exit;
842 } catch (Exception $ex) {
843 self::embedpress_die($ex);
844 }
845 }
846
847 public static function fetch_calendar() {
848 if ( empty( $_GET['page']) || 'embedpress' !== $_GET['page'] ) {
849 return;
850 }
851
852 if ( !current_user_can( 'manage_options') ) {
853 return;
854 }
855 if (!empty($_GET['code'])) {
856 // Redirect from Google authorize with code that we can use to get access and refresh tokens.
857 try {
858 $client = self::getGoogleClient();
859 // This will also set the access and refresh tokens on the client
860 // and call the token callback we have set to save them in the options table.
861 $client->handleCodeRedirect();
862 $service = new Embedpress_GoogleCalendarClient($client);
863 $items = $service->getCalendarList();
864 self::sort_calendars($items);
865
866 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
867 wp_redirect(EPGC_REDIRECT_URL);
868 exit;
869 } catch (Exception $ex) {
870 self::embedpress_die($ex);
871 }
872
873 }
874
875 $clientSecretError = '';
876 $clientSecret = self::get_valid_client_secret($clientSecretError);
877
878 $accessToken = self::getDecoded('epgc_access_token');
879
880 if (empty($clientSecret) || !empty($clientSecretError)) {
881 update_option('epgc_client_secret', '', false);
882 update_option('epgc_selected_calendar_ids', [], false);
883 }
884 if (!empty($accessToken)) {
885 // validate_selected_calendar_ids
886 }
887 if (empty($clientSecret) || !empty($clientSecretError)) {
888 // save new data from user input, show them input
889
890 } elseif (self::getDecoded('epgc_calendarlist')) {
891 // show calendar list
892 }
893
894 }
895 }
896
897
898
899
900
901
902 /**
903 * Add 'eepgcnotice' to the removable_query_args filter, so we can set this and
904 * WP will remove it for us. We use this for our custom admin notices. This way
905 * you can add parameters to the URL and check for them, but we won't see them
906 * in the URL.
907 */
908 add_filter('removable_query_args', [Embedpress_Google_Helper::class, 'removable_query_args']);
909
910 /**
911 * Check for 'epgcnotice' parameter and show admin notice if we have a option.
912 */
913 add_action('admin_init', [Embedpress_Google_Helper::class,'notices_init']);
914
915 /**
916 * Handle AJAX request from frontend.
917 */
918 add_action('wp_ajax_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
919 add_action('wp_ajax_nopriv_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
920
921 add_action('admin_post_epgc_calendarlist', [Embedpress_Google_Helper::class,'admin_post_calendarlist']);
922
923
924 add_action('admin_post_epgc_colorlist', [Embedpress_Google_Helper::class, 'admin_post_colorlist']);
925 add_action('admin_post_epgc_deletecache', [Embedpress_Google_Helper::class, 'admin_post_deletecache']);
926 /**
927 * Admin post action to verify if we have valid access and refresh token.
928 */
929 add_action('admin_post_epgc_verify', [Embedpress_Google_Helper::class, 'admin_post_verify']);
930
931 add_shortcode( 'embedpress_calendar', [Embedpress_Google_Helper::class, 'shortcode']);
932 add_action('wp_enqueue_scripts', [Embedpress_Google_Helper::class, 'enqueue_scripts'], EPGC_ENQUEUE_ACTION_PRIORITY);
933
934 add_action('admin_post_epgc_remove_private', [Embedpress_Google_Helper::class, 'remove_private_data']);
935 /**
936 * Admin post action to delete all plugin data.
937 */
938 add_action('admin_post_epgc_remove', [Embedpress_Google_Helper::class,'admin_post_remove']);
939
940
941 /**
942 * Admin post action to authorize access.
943 */
944 add_action('admin_post_epgc_authorize', [Embedpress_Google_Helper::class, 'admin_post_authorize']);
945
946 add_action('admin_init', [Embedpress_Google_Helper::class, 'fetch_calendar']);
947
948