PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 3.9.0
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v3.9.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 / GoogleClient.php
embedpress / EmbedPress / ThirdParty / Googlecalendar Last commit date
assets 4 years ago Embedpress_Google_Helper.php 2 years ago GoogleClient.php 4 years ago
GoogleClient.php
414 lines
1 <?php
2
3 /**
4 * Exception with a description field.
5 **/
6 class EmbedPress_GoogleClient_RequestException extends Exception {
7
8 private $description;
9
10 function __construct($message, $code = 0, $description = '') {
11 parent::__construct($message, $code );
12 $this->description = $description;
13
14 }
15 public function getDescription() {
16 return $this->description;
17 }
18
19 }
20
21 /**
22 * Class that can do an HTTP request.
23 **/
24 class EmbedPress_GoogleClient_Request {
25
26 // See for example: https://developers.google.com/drive/v3/web/handle-errors
27 private static $HTTP_CODES = [
28 400 => 'Bad request. User error.',
29 401 => 'Invalid Credentials. Invalid authorization header. The access token you\'re using is either expired or invalid.',
30 403 => 'Rate Limit Exceeded.',
31 404 => 'Not found. The specified resource was not found.',
32 500 => 'Backend error.'
33 ];
34
35 /**
36 * Does a HTTP request
37 *
38 * @param string $url URL to request
39 * @param array $params Parameters to add to the URL or request body
40 * @param string $method HTTP method to use
41 * @param array $headers Headers for this request
42 *
43 * @return array JSON result decoded as an array
44 *
45 * @throws EmbedPress_GoogleClient_RequestException
46 **/
47 public static function doRequest($url, $params = [], $method = 'GET', $headers = []) {
48
49 $args = [];
50 if (!empty($headers)) {
51 $args['headers'] = $headers;
52 }
53
54 $args['timeout'] = 10; // default is 5 seconds.
55
56 switch ($method) {
57 case 'GET':
58 if (!empty($params)) {
59 $url .= '?' . http_build_query($params); // urlencoded is done for you
60 //$url = add_query_arg($params, $url); // wp variant, but I think you still have to urlencoded it
61 }
62 $result = wp_remote_get($url, $args);
63 break;
64 case 'POST':
65 if (!empty($params)) {
66 $args['body'] = $params; // TODO: Do we have to urlencoded these manually?
67 }
68 $result = wp_remote_post($url, $args);
69 break;
70 default:
71 throw new EmbedPress_GoogleClient_RequestException('Unknown request method.');
72 }
73
74 if (empty($result)) {
75 throw new EmbedPress_GoogleClient_RequestException('Request failed.');
76 }
77
78 if (is_wp_error($result)) {
79 throw new EmbedPress_GoogleClient_RequestException($result->get_error_message());
80 }
81
82 $decodedResult = json_decode(wp_remote_retrieve_body($result), true);
83 if (is_null($decodedResult)) {
84 throw new EmbedPress_GoogleClient_RequestException('Response is invalid JSON.', 0, $result);
85 }
86 if (!empty($decodedResult['error'])) {
87 $exCode = 0;
88 $exMessage = 'Something went wrong.';
89 $exDescription = '';
90 if (is_array($decodedResult['error'])) {
91 if (!empty($decodedResult['error']['message'])) {
92 $exMessage = $decodedResult['error']['message'];
93 }
94 if (!empty($decodedResult['error']['code']) && preg_match("/^\d+$/", $decodedResult['error']['code'])) {
95 $exCode = $decodedResult['error']['code'];
96 }
97 } else {
98 if (!empty($decodedResult['error_description'])) {
99 $exMessage = $decodedResult['error_description'];
100 }
101 if (!empty($decodedResult['code']) && preg_match("/^\d+$/", $decodedResult['code'])) {
102 $exCode = $decodedResult['code'];
103 }
104 }
105 if (!empty(self::$HTTP_CODES[$exCode])) {
106 $exDescription = self::$HTTP_CODES[$exCode];
107 }
108 throw new EmbedPress_GoogleClient_RequestException($exMessage, $exCode, $exDescription);
109 }
110 return $decodedResult;
111 }
112 }
113
114 /**
115 * The Google OAuth client class.
116 **/
117 class EmbedPress_GoogleClient {
118
119 /**
120 * Array of client_secret that can be downloaded from the Google api console at:
121 * https://console.developers.google.com
122 **/
123 private $clientInfo;
124
125 /**
126 * @var array The access token info as an array that is returned by the Google API.
127 **/
128 private $accessTokenInfo;
129
130 /**
131 * @var string The refreshed
132 **/
133 private $refreshToken;
134
135 private $scope;
136 private $redirectUri;
137
138 const GOOGLE_AUTH_URI = 'https://accounts.google.com/o/oauth2/v2/auth';
139 const GOOGLE_REFRESH_URI = 'https://www.googleapis.com/oauth2/v4/token';
140 const GOOGLE_CODE_URI = 'https://www.googleapis.com/oauth2/v4/token';
141 const GOOGLE_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
142
143 // Gets called whenever we receive a new access and optionally refresh token.
144 // So mostly after authorize phase (with refresh token) or after refresh token (only access token).
145 private $tokenCallback;
146 /**
147 * @var null|mixed
148 */
149 private $getAccessTokenInfo;
150
151 function __construct($clientInfo, $accessTokenInfo = null, $refreshToken = null, $tokenCallback = null) {
152 $this->clientInfo = $clientInfo;
153 $this->getAccessTokenInfo = $accessTokenInfo;
154 $this->refreshToken = $refreshToken;
155 $this->tokenCallback = $tokenCallback;
156 $this->scope = null;
157 $this->redirectUri = null;
158 }
159
160 public function setAccessTokenInfo($accessTokenInfo) {
161 $this->accessTokenInfo = $accessTokenInfo;
162 }
163
164 public function getAccessTokenInfo() {
165 return $this->accessTokenInfo;
166 }
167
168 // Helper
169 public function getAccessToken() {
170 return $this->accessTokenInfo['access_token'];
171 }
172
173 public function setRefreshToken($refreshToken) {
174 $this->refreshToken = $refreshToken;
175 }
176
177 public function getRefreshToken() {
178 return $this->refreshToken;
179 }
180
181 public function setTokenCallback($tokenCallback) {
182 $this->tokenCallback = $tokenCallback;
183 }
184
185 public function setScope($scope) {
186 $this->scope = $scope;
187 }
188
189 /**
190 * @throws Exception
191 */
192 public function setRedirectUri($redirectUri) {
193 if (!in_array($redirectUri, $this->clientInfo['web']['redirect_uris'])) {
194 throw new Exception('Redirect Uri does not exist in client info. Add it first to the project and download the JSON again.');
195 }
196 $this->redirectUri = $redirectUri;
197 }
198
199 public function isAccessTokenExpired() {
200 // Add 30 seconds, so we refresh them on time.
201 return $this->accessTokenInfo['expire_time'] + 30 < time();
202 }
203
204 private function updateTokens($response) {
205 // Compute when access token expires and add it to the info array.
206 $response['expire_time'] = time() + $response['expires_in'];
207 // Only after authorize we get a refresh token, so make sure to save it!
208 // If you loose it, you have to revoke permission and authorize again.
209 $this->setAccessTokenInfo($response);
210 $refreshToken = !empty($response['refresh_token']) ? $response['refresh_token'] : null;
211 if (!empty($refreshToken)) {
212 $this->setRefreshToken($refreshToken);
213 }
214 call_user_func($this->tokenCallback, $response, $refreshToken);
215 }
216
217 /**
218 * @throws EmbedPress_GoogleClient_RequestException
219 * @throws Exception
220 */
221 public function handleCodeRedirect($state = '') {
222 if (!empty($_GET['error'])) {
223 throw new Exception($_GET['error']);
224 }
225 if (empty($_GET['code'])) {
226 throw new Exception('Code missing');
227 }
228 $getState = !empty($_GET['state']) ? $_GET['state'] : '';
229 if ($getState !== $state) {
230 throw new Exception("State mismatch.");
231 }
232
233 $result = EmbedPress_GoogleClient_Request::doRequest(self::GOOGLE_CODE_URI, [
234 'code' => $_GET['code'],
235 'client_id' => $this->clientInfo['web']['client_id'],
236 'client_secret' => $this->clientInfo['web']['client_secret'],
237 'redirect_uri' => $this->redirectUri,
238 'grant_type' => 'authorization_code'
239 ], 'POST', [
240 'Content-Type' => 'application/x-www-form-urlencoded'
241 ]);
242
243 $this->updateTokens($result);
244 }
245
246 public function authorize($state = '') {
247 $params = [
248 'client_id' => $this->clientInfo['web']['client_id'],
249 'scope' => $this->scope,
250 'access_type' => 'offline',
251 'include_granted_scopes' => 'true',
252 'state' => $state,
253 'redirect_uri' => $this->redirectUri,
254 'response_type' => 'code'
255 ];
256 $url = self::GOOGLE_AUTH_URI . '?' . http_build_query($params);
257 header('Location: ' . $url);
258 exit;
259 }
260
261 /**
262 * @throws EmbedPress_GoogleClient_RequestException
263 */
264 public function refreshAccessToken() {
265 $result = EmbedPress_GoogleClient_Request::doRequest(
266 self::GOOGLE_REFRESH_URI,
267 [
268 'client_id' => $this->clientInfo['web']['client_id'],
269 'client_secret' => $this->clientInfo['web']['client_secret'],
270 'refresh_token' => $this->refreshToken,
271 'grant_type' => 'refresh_token'
272 ],
273 'POST',
274 [
275 'Content-Type' => 'application/x-www-form-urlencoded'
276 ]
277 );
278 $this->updateTokens($result);
279 }
280
281 /**
282 * @throws EmbedPress_GoogleClient_RequestException
283 * @throws Exception
284 */
285 public function revoke() {
286 // Can be done with access and refresh token,
287 // but as access tokens expire more frequent, first take refresh token.
288 // It can take some time before the revoke is processed.
289 $token = $this->getRefreshToken();
290 if (empty($token)) {
291 $token = $this->getAccessToken();
292 }
293 if (empty($token)) {
294 throw new Exception('No access and refresh token.');
295 }
296 EmbedPress_GoogleClient_Request::doRequest(
297 self::GOOGLE_REVOKE_URI, ['token' => $token]);
298 // TODO: do we have 200 status code???
299
300 }
301
302 }
303
304 // https://developers.google.com/google-apps/calendar/v3/reference/events/list
305 /**
306 * Class that can communicate with the Google Calendar API.
307 **/
308 class EmbedPress_GoogleCalendarClient {
309
310 const GOOGLE_CALENDAR_EVENTS_URI = 'https://www.googleapis.com/calendar/v3/calendars/$calendarId/events';
311 const GOOGLE_CALENDARLIST_URI = 'https://www.googleapis.com/calendar/v3/users/me/calendarList';
312 const GOOGLE_COLORLIST_URI = 'https://www.googleapis.com/calendar/v3/colors';
313
314 private $googleClient;
315
316 function __construct($client) {
317 $this->googleClient = $client;
318 }
319
320 /**
321 * @throws EmbedPress_GoogleClient_RequestException
322 */
323 public function getEvents($calendarId, $params) {
324 $url = str_replace('$calendarId', urlencode($calendarId), self::GOOGLE_CALENDAR_EVENTS_URI);
325 // https://developers.google.com/google-apps/calendar/performance#partial-response
326 $params['fields'] = "items(summary,description,start,end,htmlLink,creator,location,attendees,attachments,colorId)";
327 $result = EmbedPress_GoogleClient_Request::doRequest(
328 $url,
329 $params,
330 'GET',
331 [
332 'Authorization' => 'Bearer ' . $this->googleClient->getAccessToken(),
333 ]
334 );
335
336 return !empty($result['items']) ? $result['items'] : [];
337 }
338
339 /**
340 * @throws EmbedPress_GoogleClient_RequestException
341 */
342 public function getEventsPublic($calendarId, $params, $apiKey, $referer) {
343 $url = str_replace('$calendarId', urlencode($calendarId), self::GOOGLE_CALENDAR_EVENTS_URI);
344 // https://developers.google.com/google-apps/calendar/performance#partial-response
345 $params['fields'] = "items(summary,description,start,end,htmlLink,creator,location,attendees,attachments,colorId)";
346 $params['key'] = $apiKey;
347 $result = EmbedPress_GoogleClient_Request::doRequest(
348 $url,
349 $params,
350 'GET',
351 [
352 'Referer' => $referer
353 ]
354 );
355
356 return !empty($result['items']) ? $result['items'] : [];
357 }
358
359 /**
360 * @throws EmbedPress_GoogleClient_RequestException
361 */
362 public function getPrimaryEvents($params) {
363 return $this->getEvents('primary', $params);
364 }
365
366 /**
367 * @return string JSON with items as key each item is calendarListEntry
368 * calendarListEntry:
369 * 'id' => string 'ehqelgh6hq4juqhjd79g4b5qkk@group.calendar.google.com' ==> use this for event list
370 * 'summary' => string 'Vacationers'
371 * 'description' => string 'Agenda voor de vakantierooster'
372 * 'backgroundColor' => string '#cd74e6'
373 * 'foregroundColor' => string '#000000'
374 * 'selected' => boolean true ==> alleen aanwezig als geselecteerd! Geeft aan of de gebruiker deze calendat in de Google ui aan heeft gezet
375 * 'primary' => boolean true ==> alleen aanwezig bij primary calendar!
376 * 'accessRole' => we can get events only for 'owner' items, so we only query these.
377 * @throws EmbedPress_GoogleClient_RequestException
378 */
379 public function getCalendarList() {
380 $result = EmbedPress_GoogleClient_Request::doRequest(
381 self::GOOGLE_CALENDARLIST_URI,
382 [
383 'minAccessRole' => 'reader' // if 'owner', then you don't see calendars like national holidays.
384 ],
385 'GET',
386 [
387 'Authorization' => 'Bearer ' . $this->googleClient->getAccessToken()
388 ]
389 );
390
391 return !empty($result['items']) ? $result['items'] : [];
392 }
393
394 /**
395 * @throws EmbedPress_GoogleClient_RequestException
396 */
397 public function getColorList() {
398 $result = EmbedPress_GoogleClient_Request::doRequest(
399 self::GOOGLE_COLORLIST_URI,
400 null,
401 'GET',
402 [
403 'Authorization' => 'Bearer ' . $this->googleClient->getAccessToken()
404 ]
405 );
406 $calendar = !empty($result['calendar']) ? $result['calendar'] : [];
407 $event = !empty($result['event']) ? $result['event'] : [];
408 return [
409 'calendar' => $calendar,
410 'event' => $event
411 ];
412 }
413
414 }