1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
googleapitransport.php
См. документацию.
1<?
2namespace Bitrix\Calendar\Sync;
3
4use Bitrix\Calendar\Sync\Util\RequestLogger;
5use Bitrix\Main\Application;
6use Bitrix\Main\ArgumentException;
7use Bitrix\Main\ArgumentNullException;
8use Bitrix\Main\ArgumentOutOfRangeException;
9use Bitrix\Main\LoaderException;
10use Bitrix\Main\SystemException;
11use Bitrix\Main\Loader;
12use Bitrix\Main\Web;
13use CCalendar;
14use CSocServGoogleOAuth;
15use CSocServGoogleProxyOAuth;
16use Exception;
17
25{
26 private const API_BASE_URL = Google\Helper::GOOGLE_SERVER_PATH_V3;
27 protected const SERVICE_NAME = 'google';
28 private $client;
29 private $errors;
30 private $currentMethod = '';
34 private $oAuth;
38 protected $requestLogger;
39
49 public function __construct($userId)
50 {
51 if (!Loader::includeModule('socialservices'))
52 {
53 throw new SystemException("Can not include module \"SocialServices\"! " . __METHOD__);
54 }
55
56 $this->client = new Web\HttpClient();
57 if (RequestLogger::isEnabled())
58 {
59 $this->requestLogger = new RequestLogger((int)$userId, self::SERVICE_NAME);
60 }
61
62 if (CSocServGoogleProxyOAuth::isProxyAuth())
63 {
64 $oAuth = new CSocServGoogleProxyOAuth($userId);
65 }
66 else
67 {
68 $oAuth = new CSocServGoogleOAuth($userId);
69 }
70
71 $oAuth->getEntityOAuth()->addScope([
72 'https://www.googleapis.com/auth/calendar',
73 'https://www.googleapis.com/auth/calendar.readonly',
74 ]);
75 $oAuth->getEntityOAuth()->removeScope('https://www.googleapis.com/auth/drive');
76
77 $oAuth->getEntityOAuth()->setUser($userId);
78 if ($oAuth->getEntityOAuth()->GetAccessToken())
79 {
80 $this->client->setHeader('Authorization', 'Bearer ' . $oAuth->getEntityOAuth()->getToken());
81 $this->client->setHeader('Content-Type', 'application/json');
82 $this->client->setHeader('Referer', $this->getDomain());
83 unset($oAuth);
84 }
85 else
86 {
87 $this->errors[] = array("code" => "NO_ACCESS_TOKEN", "message" => "No access token found");
88 }
89 }
90
99 public function openCalendarListChannel($channelInfo): array
100 {
101 $this->currentMethod = __METHOD__;
102
103 return $this->doRequest(
104 Web\HttpClient::HTTP_POST,
105 self::API_BASE_URL. '/users/me/calendarList/watch',
106 Web\Json::encode($channelInfo, JSON_UNESCAPED_SLASHES)
107 );
108 }
109
119 public function openEventsWatchChannel($calendarId, $channelInfo): array
120 {
121 $this->currentMethod = __METHOD__;
122
123 return $this->doRequest(
124 Web\HttpClient::HTTP_POST,
125 self::API_BASE_URL . '/calendars/' . urlencode($calendarId) . '/events/watch',
126 Web\Json::encode($channelInfo, JSON_UNESCAPED_SLASHES)
127 );
128 }
129
140 {
141 $this->currentMethod = __METHOD__;
142
143 return $this->doRequest(
144 Web\HttpClient::HTTP_POST,
145 self::API_BASE_URL . '/channels/stop',
146 Web\Json::encode(['id' => $channelId, 'resourceId' => $resourceId], JSON_UNESCAPED_SLASHES)
147 );
148 }
149
158 private function doRequest($type, $url, $requestParams = '')
159 {
160 $this->errors = $response = [];
161
162 if (!in_array($type, [Web\HttpClient::HTTP_PATCH, Web\HttpClient::HTTP_PUT, Web\HttpClient::HTTP_DELETE, Web\HttpClient::HTTP_GET, Web\HttpClient::HTTP_POST], true))
163 {
164 throw new ArgumentException('Bad request type');
165 }
166
167 $this->client->query($type, $url, ($requestParams ?: null));
168
169 //Only "OK" response is acceptable.
170 if ($this->client->getStatus() === 200)
171 {
172 $contentType = $this->client->getHeaders()->getContentType();
173
174 if ($contentType === 'multipart/mixed')
175 {
176 $response = $this->multipartDecode($this->client->getResult());
177 }
178 else
179 {
180 try
181 {
182 $response = Web\Json::decode($this->client->getResult());
183 }
184 catch (ArgumentException $exception)
185 {
186 $response = null;
187 }
188 }
189 }
190 else
191 {
192 try
193 {
194 $error = Web\Json::decode($this->client->getResult());
195 $this->errors[] = ["code" => "CONNECTION", "message" => "[" . $error['error']['code'] . "] " . $error['error']['message']];
196 }
197 catch (ArgumentException $exception)
198 {
199 foreach($this->client->getError() as $code => $error)
200 {
201 $this->errors[] = ["code" => $code, "message" => $error];
202 }
203 }
204 }
205
206 if ($this->requestLogger)
207 {
208 $this->requestLogger->write([
209 'requestParams' => $requestParams,
210 'url' => $url,
211 'method' => $type,
212 'statusCode' => $this->client->getStatus(),
213 'response' => $this->prepareResponseForDebug($response),
214 'error' => $this->prepareErrorForDebug(),
215 ]);
216 }
217
218 return $response;
219 }
220
228 public function deleteEvent($eventId, $calendarId)
229 {
230 $this->currentMethod = __METHOD__;
231 return $this->doRequest(Web\HttpClient::HTTP_DELETE, self::API_BASE_URL . '/calendars/' . $calendarId . '/events/' . $eventId);
232 }
233
242 public function patchEvent($patchData, $calendarId, $eventId)
243 {
244 $this->currentMethod = __METHOD__;
245 $requestBody = Web\Json::encode($patchData, JSON_UNESCAPED_SLASHES);
246 return $this->doRequest(Web\HttpClient::HTTP_PUT, self::API_BASE_URL . '/calendars/' . $calendarId . '/events/' . $eventId, $requestBody);
247 }
248
257 public function updateEvent($eventData, $calendarId, $eventId)
258 {
259 $this->currentMethod = __METHOD__;
260 $requestBody = Web\Json::encode($eventData, JSON_UNESCAPED_SLASHES);
261 return $this->doRequest(Web\HttpClient::HTTP_PUT, self::API_BASE_URL . '/calendars/' . $calendarId . '/events/' . $eventId, $requestBody);
262 }
263
271 public function insertEvent($eventData, $calendarId)
272 {
273 $this->currentMethod = __METHOD__;
274 $requestBody = Web\Json::encode($eventData, JSON_UNESCAPED_SLASHES);
275 return $this->doRequest(Web\HttpClient::HTTP_POST, self::API_BASE_URL . '/calendars/' . $calendarId . '/events/', $requestBody);
276 }
277
285 public function importEvent($eventData, $calendarId)
286 {
287 $this->currentMethod = __METHOD__;
288 $requestBody = Web\Json::encode($eventData, JSON_UNESCAPED_SLASHES);
289 return $this->doRequest(Web\HttpClient::HTTP_POST, self::API_BASE_URL . '/calendars/' . $calendarId . '/events/import', $requestBody);
290 }
291
297 public function getCalendarList(array $requestParameters = null): ?array
298 {
299 $this->currentMethod = __METHOD__;
300
301 $url = self::API_BASE_URL . '/users/me/calendarList';
302 $url .= empty($requestParameters) ? '' : '?' . preg_replace('/(%3D)/', '=', http_build_query($requestParameters));
303
304 return $this->doRequest(Web\HttpClient::HTTP_GET, $url);
305 }
306
312 public function getColors()
313 {
314 $this->currentMethod = __METHOD__;
315 return $this->doRequest(Web\HttpClient::HTTP_GET, self::API_BASE_URL . '/colors');
316 }
317
325 public function getEvents($calendarId, $requestParams = array())
326 {
327 $this->currentMethod = __METHOD__;
328 $requestParams = array_filter($requestParams);
329 $url = self::API_BASE_URL . '/calendars/' . urlencode($calendarId) . '/events';
330 $url .= empty($requestParams) ? '' : '?' . preg_replace('/(%3D)/', '=', http_build_query($requestParams));
331 return $this->doRequest(Web\HttpClient::HTTP_GET, $url);
332 }
333
339 public function getErrors()
340 {
341 return $this->errors;
342 }
343
350 public function getErrorsByCode($code)
351 {
352 return array_filter($this->errors, function($error) use ($code)
353 {
354 return $error['code'] == $code;
355 });
356 }
357
364 public function getErrorByCode($code)
365 {
366 if (!is_array($this->errors))
367 {
368 return [];
369 }
370
371 $errorsByCode = array_filter($this->errors, function($error) use ($code)
372 {
373 return $error['code'] == $code;
374 });
375
376 if (!empty($errorsByCode))
377 {
378 return end($errorsByCode);
379 }
380
381 return [];
382 }
383
392 public function getInstanceRecurringEvent($calendarId, $eventId, $originalStart)
393 {
394 $this->currentMethod = __METHOD__;
395
396 $requestParameters = ['originalStart' => $originalStart];
397 $requestParameters = array_filter($requestParameters);
398 $url = self::API_BASE_URL . '/calendars/' . urlencode($calendarId) . '/events/' . urlencode($eventId) . '/instances/';
399 $url .= empty($requestParameters) ? '' : '?' . preg_replace('/(%3D)/', '=', http_build_query($requestParameters));
400
401 return $this->doRequest(Web\HttpClient::HTTP_GET, $url);
402 }
403
410 public function insertCalendar($calendarData)
411 {
412 $this->currentMethod = __METHOD__;
413 $requestBody = Web\Json::encode($calendarData, JSON_UNESCAPED_SLASHES);
414 return $this->doRequest(Web\HttpClient::HTTP_POST, self::API_BASE_URL . '/calendars/', $requestBody);
415 }
416
417 public function sendBatchEvents($body, $calendarId, $params)
418 {
419 $url = "https://www.googleapis.com/batch/calendar/v3/";
420 $requestBody = $this->prepareMultipartMixed($body, $calendarId, $params);
421 return $this->doRequest(Web\HttpClient::HTTP_POST, $url, $requestBody);
422 }
423
430 protected function prepareMultipartMixed($postData, $calendarId, $params)
431 {
432 if (is_array($postData))
433 {
434 $boundary = 'BXC'.md5(rand().time());
435 $this->client->setHeader('Content-type', 'multipart/mixed; boundary='.$boundary);
436
437 $data = '';
438
439 foreach ($postData as $key => $value)
440 {
441 $data .= '--'.$boundary."\r\n";
442
443 if (is_array($value))
444 {
445 $contentId = '<item'.$key.':'.$key.'>';
446
447 if (is_array($value))
448 {
449 $data .= 'Content-Type: application/http'."\r\n";
450 $data .= 'Content-ID: '.$contentId."\r\n\r\n";
451
452 if (!empty($value['gEventId']))
453 {
454 $data .= $params['method'].' /calendar/v3/calendars/'.$calendarId.'/events/'.$value['gEventId']."\r\n";
455 }
456 else
457 {
458 $data .= 'POST /calendar/v3/calendars/'.$calendarId.'/events'."\r\n";
459 }
460
461 $data .= 'Content-type: application/json'."\r\n";
462
463 $data .= 'Content-Length: '.mb_strlen($value['partBody'])."\r\n\r\n";
464 $data .= $value['partBody'];
465 $data .= "\r\n\r\n";
466 }
467 }
468 }
469
470 $data .= '--'.$boundary."--\r\n";
472 }
473
474 return $postData;
475 }
476
483 {
484 $events = [];
485
486 $boundary = $this->client->getHeaders()->getBoundary();
487
488 $response = str_replace("--$boundary--", "--$boundary", $response);
489 $parts = explode("--$boundary\r\n", $response);
490
491 foreach ($parts as $key => $part)
492 {
493 $part = trim($part);
494 if (!empty($part))
495 {
496 $partEvent = explode("\r\n\r\n", $part);
497 $data = $this->getMetaInfo($partEvent[1]);
498
499 if ($data['status'] === 200)
500 {
501 $id = $this->getId($partEvent[0]);
502 if ($id === null)
503 {
504 continue;
505 }
506
507 try
508 {
509 $event = Web\Json::decode($partEvent[2]);
510 }
511 catch(Exception $exception)
512 {
513 continue;
514 }
515
516 $event['etag'] = $data['etag'];
517 $events[$id] = $event;
518 }
519 }
520 }
521
522 return $events;
523 }
524
525 private function getMetaInfo($headers): array
526 {
527 $data = [];
528 foreach (explode("\n", $headers) as $k => $header)
529 {
530 if($k === 0)
531 {
532 if(preg_match('#HTTP\S+ (\d+)#', $header, $find))
533 {
534 $data['status'] = (int)$find[1];
535 }
536 }
537 elseif(mb_strpos($header, ':') !== false)
538 {
539 [$headerName, $headerValue] = explode(':', $header, 2);
540 if(mb_strtolower($headerName) === 'etag')
541 {
542 $data['etag'] = trim($headerValue);
543 }
544 }
545 }
546
547 return $data;
548 }
549
554 private function getId ($headers): ?int
555 {
556 $id = null;
557 foreach (explode("\n", $headers) as $k => $header)
558 {
559 if(mb_strpos($header, ':') !== false)
560 {
561 [$headerName, $headerValue] = explode(':', $header, 2);
562 if(mb_strtolower($headerName) === 'content-id')
563 {
564 $part = explode(':', $headerValue);
565 $id = rtrim($part[1], ">");
566 }
567 }
568 }
569
570 return (int)$id;
571 }
572
578 public function deleteCalendar(string $calendarId): array
579 {
580 $this->currentMethod = __METHOD__;
581 return $this->doRequest(Web\HttpClient::HTTP_DELETE, self::API_BASE_URL . '/calendars/' . $calendarId . '');
582 }
583
587 private function getDomain(): string
588 {
589 if (CCalendar::isBitrix24())
590 {
591 return 'https://bitrix24.com';
592 }
593
594 if (defined('BX24_HOST_NAME') && BX24_HOST_NAME)
595 {
596 return "https://" . (string)BX24_HOST_NAME;
597 }
598
599 $server = Application::getInstance()->getContext()->getServer();
600
601 return "https://" . (string)$server['HTTP_HOST'];
602 }
603
610 public function updateCalendar(string $calendarId, $calendarData): array
611 {
612 $this->currentMethod = __METHOD__;
613 $requestBody = Web\Json::encode($calendarData, JSON_UNESCAPED_SLASHES);
614
615 return $this->doRequest(Web\HttpClient::HTTP_PUT, self::API_BASE_URL . '/calendars/' . $calendarId, $requestBody);
616 }
617
624 public function updateCalendarList(string $calendarId, $calendarData): array
625 {
626 $this->currentMethod = __METHOD__;
627
628 $url = self::API_BASE_URL . '/users/me/calendarList/' . $calendarId;
629 $url .= '?' . preg_replace('/(%3D)/', '=', http_build_query(['colorRgbFormat' => "True"]));
630
631 $requestBody = Web\Json::encode($calendarData, JSON_UNESCAPED_SLASHES);
632
633 return $this->doRequest(Web\HttpClient::HTTP_PUT, $url, $requestBody);
634 }
635
640 private function prepareResponseForDebug($response): string
641 {
642 if (!$response || !is_array($response))
643 {
644 return '';
645 }
646
647 $result = '';
648
649 foreach ($response as $key => $value)
650 {
651 if (is_string($value))
652 {
653 $result .= "{$key}:{$value}; ";
654 }
655 elseif (is_array($value))
656 {
657 $result .= "{$key}:";
658 foreach ($value as $valueKey => $valueValue)
659 {
660 $result .= "{$valueKey}:{$valueValue}, ";
661 }
662 $result .= "; ";
663 }
664 }
665
666 return $result;
667 }
668
672 private function prepareErrorForDebug(): string
673 {
674 if (!$this->errors || !is_array($this->errors))
675 {
676 return '';
677 }
678
679 $result = '';
680 foreach ($this->errors as $error)
681 {
682 $result .= $error['code'] . " " . $error['message'] . "; ";
683 }
684
685 return $result;
686 }
687}
$type
Определения options.php:106
$resourceId
Определения push.php:24
if(empty( $fields)) foreach($fields as $field) $channelId
Определения push.php:23
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
const GOOGLE_SERVER_PATH_V3
Определения helper.php:25
openCalendarListChannel($channelInfo)
Определения googleapitransport.php:99
sendBatchEvents($body, $calendarId, $params)
Определения googleapitransport.php:417
getEvents($calendarId, $requestParams=array())
Определения googleapitransport.php:325
stopChannel($channelId, $resourceId)
Определения googleapitransport.php:139
deleteCalendar(string $calendarId)
Определения googleapitransport.php:578
updateCalendar(string $calendarId, $calendarData)
Определения googleapitransport.php:610
prepareMultipartMixed($postData, $calendarId, $params)
Определения googleapitransport.php:430
deleteEvent($eventId, $calendarId)
Определения googleapitransport.php:228
importEvent($eventData, $calendarId)
Определения googleapitransport.php:285
updateCalendarList(string $calendarId, $calendarData)
Определения googleapitransport.php:624
getCalendarList(array $requestParameters=null)
Определения googleapitransport.php:297
updateEvent($eventData, $calendarId, $eventId)
Определения googleapitransport.php:257
insertEvent($eventData, $calendarId)
Определения googleapitransport.php:271
patchEvent($patchData, $calendarId, $eventId)
Определения googleapitransport.php:242
getInstanceRecurringEvent($calendarId, $eventId, $originalStart)
Определения googleapitransport.php:392
openEventsWatchChannel($calendarId, $channelInfo)
Определения googleapitransport.php:119
static decode($data)
Определения json.php:50
static encode($data, $options=null)
Определения json.php:22
$data['IS_AVAILABLE']
Определения .description.php:13
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$errors
Определения iblock_catalog_edit.php:74
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
Определения options.php:195
$requestParams
Определения urlrewrite.php:46
Определения cookie.php:3
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$contentType
Определения quickway.php:301
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$response
Определения result.php:21
$postData
Определения index.php:29
$contentId
Определения sonet_set_content_view.php:27
$error
Определения subscription_card_product.php:20
$k
Определения template_pdf.php:567
$url
Определения iframe.php:7