Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
googleapipush.php
1<?php
2
4
11
15final class GoogleApiPush
16{
17 private const RENEW_LIMIT = 5;
18 private const CREATE_LIMIT = 2;
19 private const CLEAR_LIMIT = 6;
20 private const CHECK_LIMIT = 10;
21 public const TYPE_SECTION = 'SECTION';
22 public const TYPE_CONNECTION = 'CONNECTION';
23
24
29 public static function renewWatchChannels()
30 {
31 $pushRows = [];
32 $connectionIds = [];
33 $sectionIds = [];
34
35 $pushesDb = PushTable::getList([
36 'filter' => [
37 '<=EXPIRES' => (new Type\DateTime())->add('+1 day'),
38 ],
39 'order' => [
40 'EXPIRES' => 'ASC',
41 ],
42 'limit' => self::RENEW_LIMIT,
43 ]);
44
45 while ($row = $pushesDb->fetch())
46 {
47 $pushRows[] = $row;
48 if ($row['ENTITY_TYPE'] === self::TYPE_CONNECTION)
49 {
50 $connectionIds[] = (int)$row['ENTITY_ID'];
51 }
52
53 if ($row['ENTITY_TYPE'] === self::TYPE_SECTION)
54 {
55 $sectionIds[] = (int)$row['ENTITY_ID'];
56 }
57 }
58
59 if (!empty($pushRows))
60 {
61 global $DB;
62 $sections = [];
63 $connections = [];
64
65 if (!empty($sectionIds))
66 {
67 $sectionResult = $DB->query("SELECT * FROM b_calendar_section WHERE ID IN (" . implode(',', $sectionIds) . ")");
68 while($row = $sectionResult->fetch())
69 {
70 $sections[$row['ID']] = $row;
71 if (!empty($row['CAL_DAV_CON']) && !in_array((int)$row['CAL_DAV_CON'], $connectionIds, true))
72 {
73 $connectionIds[] = (int)$row['CAL_DAV_CON'];
74 }
75 }
76 }
77
78 if (!empty($connectionIds))
79 {
80 $connectionResult = $DB->query("SELECT * FROM b_dav_connections WHERE ID IN (" . implode(',', $connectionIds) . ")");
81 while($row = $connectionResult->fetch())
82 {
83 $connections[$row['ID']] = $row;
84 }
85 }
86
87 foreach ($pushRows as $row)
88 {
89 $channelInfo = false;
90 if ($row['ENTITY_TYPE'] === self::TYPE_CONNECTION && !empty($connections[$row['ENTITY_ID']]))
91 {
92 $connectionData = $connections[$row['ENTITY_ID']];
93 if (is_string($connectionData['LAST_RESULT']) && self::isAuthError($connectionData['LAST_RESULT']))
94 {
95 continue;
96 }
97 $googleApiConnection = new GoogleApiSync($connectionData['ENTITY_ID'], $connectionData['ID']);
98 $googleApiConnection->stopChannel($row['CHANNEL_ID'], $row['RESOURCE_ID']);
100 $channelInfo = $googleApiConnection->startWatchCalendarList($connectionData['NAME']);
101 }
102 elseif ($row['ENTITY_TYPE'] === self::TYPE_SECTION && !empty($sections[$row['ENTITY_ID']]))
103 {
104 $section = $sections[$row['ENTITY_ID']];
105
106 if (
107 (!empty($connectionData)
108 && is_string($connectionData['LAST_RESULT'])
109 && self::isAuthError($connectionData['LAST_RESULT'])
110 )
111 || self::isVirtualCalendar($section['GAPI_CALENDAR_ID'], $section['EXTERNAL_TYPE'])
112 )
113 {
114 continue;
115 }
116
117 $connectionData = $connections[$section['CAL_DAV_CON']];
118 $googleApiConnection = new GoogleApiSync($section['OWNER_ID'], $section['CAL_DAV_CON']);
119 $googleApiConnection->stopChannel($row['CHANNEL_ID'], $row['RESOURCE_ID']);
121 $channelInfo = $googleApiConnection->startWatchEventsChannel($section['GAPI_CALENDAR_ID']);
122 }
123 else
124 {
126 }
127
128 if (
129 $channelInfo
130 && isset($channelInfo['id'], $channelInfo['resourceId'])
131 && isset($googleApiConnection)
132 )
133 {
134 $googleApiConnection->updateSuccessLastResultConnection();
135 PushTable::add([
136 'ENTITY_TYPE' => $row['ENTITY_TYPE'],
137 'ENTITY_ID' => $row['ENTITY_ID'],
138 'CHANNEL_ID' => $channelInfo['id'],
139 'RESOURCE_ID' => $channelInfo['resourceId'],
140 'EXPIRES' => $channelInfo['expiration'],
141 'NOT_PROCESSED' => 'N'
142 ]);
143 }
144 }
145 }
146
147 if (count($pushRows) < 4)
148 {
149 \CAgent::removeAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::renewWatchChannels();", "calendar");
150
151 return false;
152 }
153
154 return false;
155 }
156
157 public static function checkSectionsPush($localSections, $userId, $connectionId)
158 {
159 $googleApiConnection = new GoogleApiSync($userId, $connectionId);
160 //Create new channels and refresh old push channels for sections of current connection
161 $sectionIds = self::getNotVirtualSectionIds($localSections);
162
163 $pushChannels = PushTable::getList([
164 'filter' => [
165 '=ENTITY_TYPE' => self::TYPE_SECTION,
166 '=ENTITY_ID' => $sectionIds,
167 ]
168 ]);
169 $inactiveSections = array_flip($sectionIds);
170
171 while($row = $pushChannels->fetch())
172 {
173 $now = time();
174 $tsExpires = strtotime($row['EXPIRES']);
175
176 if ($now > $tsExpires)
177 {
179 continue;
180 }
181
182 if (($tsExpires - $now) > GoogleApiSync::ONE_DAY
183 || self::isAuthError(self::getLastResultBySectionId((int)$row['ENTITY_ID']))
184 )
185 {
186 unset($inactiveSections[$row['ENTITY_ID']]);
187 continue;
188 }
189
190 $googleApiConnection->stopChannel($row['CHANNEL_ID'], $row['RESOURCE_ID']);
192 unset($inactiveSections[$row['ENTITY_ID']]);
193
194 $localCalendarIndex = array_search($row['ENTITY_ID'], array_column($localSections, 'ID'));
195 if ($localCalendarIndex !== false)
196 {
197 $channelInfo = $googleApiConnection->startWatchCalendarList($localSections[$localCalendarIndex]['GAPI_CALENDAR_ID']);
198
199 if ($channelInfo)
200 {
201 PushTable::update(
202 [
203 'ENTITY_TYPE' => $row['ENTITY_TYPE'],
204 'ENTITY_ID' => $row['ENTITY_ID']
205 ],
206 [
207 'CHANNEL_ID' => $channelInfo['id'],
208 'RESOURCE_ID' => $channelInfo['resourceId'],
209 'EXPIRES' => $channelInfo['expiration'],
210 'NOT_PROCESSED' => 'N'
211 ]
212 );
213 }
214 }
215 }
216
217 if (is_array($localSections) && is_array($inactiveSections) && $googleApiConnection instanceof GoogleApiSync)
218 {
219 self::startChannelForInActiveSections($localSections, $inactiveSections, $googleApiConnection);
220 }
221
222 return false;
223 }
224
232 public static function createWatchChannels($start = 0)
233 {
234 $pushOptionEnabled = \COption::getOptionString('calendar', 'sync_by_push', false);
235 if (!$pushOptionEnabled && !\CCalendar::isBitrix24())
236 {
237 return null;
238 }
239
240 $lastId = $start;
241 if(!Loader::includeModule('dav'))
242 {
243 return false;
244 }
245
246 $davConnections = \CDavConnection::getList(
247 ["ID" => "ASC"],
248 [
249 'ACCOUNT_TYPE' => Google\Helper::GOOGLE_ACCOUNT_TYPE_API,
250 '>ID' => $start
251 ],
252 false,
253 ['nTopCount' => self::CREATE_LIMIT]
254 );
255
256 $connections = [];
257 $pushConnectionIds = [];
258 while($row = $davConnections->fetch())
259 {
260 //connectivity check
261 if (!self::isConnectionError($row['LAST_RESULT']))
262 {
263 $lastId = $row['ID'];
264 $connections[] = $row;
265 $pushConnectionIds[] = $row['ID'];
266 }
267 }
268
269 if(!empty($connections))
270 {
271 $result = PushTable::getList(
272 [
273 'filter' => [
274 '=ENTITY_TYPE' => self::TYPE_CONNECTION,
275 '=ENTITY_ID' => $pushConnectionIds,
276 ],
277 ]
278 );
279
280 $pushChannels = [];
281 while($row = $result->fetch())
282 {
283 $pushChannels[$row['ENTITY_ID']] = $row;
284 }
285
286 foreach($connections as $davConnection)
287 {
288 if(isset($pushChannels[$davConnection['ID']]))
289 {
290 continue;
291 }
292
293 $googleApiConnection = new GoogleApiSync($davConnection['ENTITY_ID'], $davConnection['ID']);
294 $channelInfo = $googleApiConnection->startWatchCalendarList($connections['NAME']);
295 if($channelInfo && isset($channelInfo['id'], $channelInfo['resourceId']))
296 {
297 self::deletePushChannel(["ENTITY_TYPE" => self::TYPE_CONNECTION, 'ENTITY_ID' => $davConnection['ID']]);
298 $googleApiConnection->updateSuccessLastResultConnection();
299 PushTable::add([
300 'ENTITY_TYPE' => self::TYPE_CONNECTION,
301 'ENTITY_ID' => $davConnection['ID'],
302 'CHANNEL_ID' => $channelInfo['id'],
303 'RESOURCE_ID' => $channelInfo['resourceId'],
304 'EXPIRES' => $channelInfo['expiration'],
305 'NOT_PROCESSED' => 'N'
306 ]);
307 }
308 }
309 }
310
311 if($lastId == $start)
312 {
313 \CAgent::removeAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::createWatchChannels(".$start.");", "calendar");
314 \CAgent::removeAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::createWatchChannels(0);", "calendar");
315 return null;
316 }
317
318 return false;
319 }
320
327 public static function stopChannel(array $row = null, $ownerId = 0): void
328 {
329 if ($row)
330 {
331 if ($row['ENTITY_TYPE'] === self::TYPE_SECTION)
332 {
333 if (Loader::includeModule('dav'))
334 {
335 $connectionData = \CDavConnection::getById($row['ENTITY_ID']);
336 if ($ownerId === 0)
337 {
338 $ownerId = $connectionData['ENTITY_ID'];
339 }
340 }
341
342 if ($ownerId > 0 && isset($connectionData) && !self::isConnectionError($connectionData['LAST_RESULT']))
343 {
344 $googleApiConnection = new GoogleApiSync($ownerId, $row['ENTITY_ID']);
345 $googleApiConnection->stopChannel($row['CHANNEL_ID'], $row['RESOURCE_ID']);
346 }
347 }
348
349 if ($row['ENTITY_TYPE'] === self::TYPE_SECTION)
350 {
351 $section = \CCalendarSect::getById($row['ENTITY_ID']);
352 if ($ownerId === 0)
353 {
354 $ownerId = $section['OWNER_ID'];
355 }
356
357 //TODO: modify the saving of the result
358 if (Loader::includeModule('dav') && !empty($section['CAL_DAV_CON']))
359 {
360 $connectionData = \CDavConnection::getById($section['CAL_DAV_CON']);
361 }
362
363 if ($ownerId > 0 && isset($connectionData) && !self::isConnectionError($connectionData['LAST_RESULT']))
364 {
365 $googleApiConnection = new GoogleApiSync($ownerId, $section['CAL_DAV_CON']);
366 $googleApiConnection->stopChannel($row['CHANNEL_ID'], $row['RESOURCE_ID']);
367 }
368 }
369
371 }
372 }
373
378 public static function isConnectionError(string $lastResult = null): bool
379 {
380 return !empty($lastResult) && preg_match("/^\[(4\d\d)\][a-z0-9 _]*/i", $lastResult);
381 }
382
383 public static function isAuthError(string $lastResult = null): bool
384 {
385 return !empty($lastResult) && preg_match("/^\[(401)\][a-z0-9 _]*/i", $lastResult);
386 }
387
388 public static function isSyncTokenExpiresError(string $lastResult = null): bool
389 {
390 return !empty($lastResult) && preg_match("/^\[(410)\][a-z0-9 _]*/i", $lastResult);
391 }
392
397 public static function isWrongChannel(string $error = null): bool
398 {
399 return !empty($error)
400 && preg_match(
401 "/^\[404\] Channel \'[a-z0-9 _]*\' not found for project \'[a-z0-9 _]*\'/i",
402 $error
403 );
404 }
405
412 public static function clearPushChannels()
413 {
414 return null;
415 }
416
422 public static function receivePushSignal($channelId, $resourceId)
423 {
424 return;
425 }
426
427
434 public static function processIncomingPush(string $entityType, int $entityId)
435 {
436 global $DB;
437 if ($entityType === self::TYPE_SECTION)
438 {
439 $r = $DB->query(
440 "SELECT s.*, c.LAST_RESULT as LAST_RESULT
441 FROM b_calendar_section s
442 LEFT JOIN b_dav_connections c
443 ON s.CAL_DAV_CON = c.ID
444 WHERE s.ID=" . $entityId
445 );
446 if ($section = $r->fetch())
447 {
448 if (self::isAuthError($section['LAST_RESULT']))
449 {
450 return;
451 }
452
453 $tokens = [];
454 if (!empty($tokens))
455 {
456 if (empty($tokens['nextSyncToken']))
457 {
459 }
460
461 \CCalendarSect::edit(
462 [
463 'arFields' =>
464 [
465 'ID' => $section['ID'],
466 'SYNC_TOKEN' => $tokens['nextSyncToken'],
467 'PAGE_TOKEN' => $tokens['nextPageToken'],
468 ]
469 ]
470 );
471 }
472
473 \CCalendar::clearCache();
474 }
475 }
476 elseif ($entityType === self::TYPE_CONNECTION)
477 {
478 $r = $DB->query("SELECT * FROM b_dav_connections WHERE ID=" . $entityId);
479 if ($connection = $r->fetch())
480 {
481 if (
482 self::isAuthError($connection['LAST_RESULT'])
483 || !Loader::includeModule('dav')
484 )
485 {
486 return;
487 }
488
489// \CCalendarSync::syncConnection($connection);
490 \CCalendar::clearCache();
491 }
492 }
493 }
494
498 public static function processPush()
499 {
500 return false;
501 }
502
503 public static function checkPushChannel(int $lastIdConnection = 0)
504 {
505 $connections = [];
506 $connectionIds = [];
507
508 if (!Loader::includeModule('dav'))
509 {
510 return false;
511 }
512
513 $davConnectionsDb = \CDavConnection::getList(
514 ["ID" => "ASC"],
515 [
516 'ACCOUNT_TYPE' => Google\Helper::GOOGLE_ACCOUNT_TYPE_API,
517 '>ID' => $lastIdConnection,
518 ],
519 false,
520 ['nTopCount' => self::CHECK_LIMIT]
521 );
522
523 while ($davConnection = $davConnectionsDb->fetch())
524 {
525 if (self::isAuthError($davConnection['LAST_RESULT']))
526 {
527 continue;
528 }
529
530 $connections[$davConnection['ID']] = $davConnection;
531 $connectionIds[] = $davConnection['ID'];
532 $lastIdConnection = $davConnection['ID'];
533 }
534
535 if (!empty($connectionIds))
536 {
537 self::checkPushConnectionChannel($connectionIds, $connections);
538 self::checkPushSectionChannel($connectionIds, $connections);
539
540 return false;
541 }
542
543 return false;
544 }
545
550 private static function checkPushConnectionChannel(array $connectionIds, array $connections): void
551 {
552 $existedConnectionChannels = [];
553 $pushConnectionChannelsDb = PushTable::getList(
554 [
555 'filter' => [
556 '=ENTITY_TYPE' => self::TYPE_CONNECTION,
557 '=ENTITY_ID' => $connectionIds
558 ]
559 ]
560 );
561
562 while ($row = $pushConnectionChannelsDb->fetch())
563 {
564 $channelInfo = null;
565 if (!empty($connections[$row['ENTITY_ID']]))
566 {
567 $connectionData = $connections[$row['ENTITY_ID']];
568 if (!self::isConnectionError($connectionData['LAST_RESULT']))
569 {
570 $existedConnectionChannels[] = $row['ENTITY_ID'];
571 continue;
572 }
573
574 $googleApiConnection = new GoogleApiSync($connectionData['ENTITY_ID'], $connectionData['ID']);
575 if ($googleApiConnection->stopChannel($row['CHANNEL_ID'], $row['RESOURCE_ID']))
576 {
578 $channelInfo = $googleApiConnection->startWatchCalendarList($connectionData['NAME']);
579 }
580
581 if (is_string($googleApiConnection->getTransportConnectionError()))
582 {
584 }
585
586 if ($channelInfo && isset($channelInfo['id'], $channelInfo['resourceId']))
587 {
588 $existedConnectionChannels[] = $row['ENTITY_ID'];
589 $googleApiConnection->updateSuccessLastResultConnection();
590 PushTable::add([
591 'ENTITY_TYPE' => $row['ENTITY_TYPE'],
592 'ENTITY_ID' => $row['ENTITY_ID'],
593 'CHANNEL_ID' => $channelInfo['id'],
594 'RESOURCE_ID' => $channelInfo['resourceId'],
595 'EXPIRES' => $channelInfo['expiration'],
596 'NOT_PROCESSED' => 'N'
597 ]);
598 }
599 }
600 }
601
602 //create new channel for connections
603 $missedChannelConnections = array_diff($connectionIds, $existedConnectionChannels);
604 if (!empty($missedChannelConnections))
605 {
606 foreach ($missedChannelConnections as $missedConnection)
607 {
608 if (self::isAuthError($missedConnection['LAST_RESULT']))
609 {
610 continue;
611 }
612
613 $channelInfo = null;
614 $connectionData = $connections[$missedConnection];
615 $googleApiConnection = new GoogleApiSync($connectionData['ENTITY_ID'], $connectionData['ID']);
616 $channelInfo = $googleApiConnection->startWatchCalendarList($connectionData['NAME']);
617 if ($channelInfo && isset($channelInfo['id'], $channelInfo['resourceId']))
618 {
619 $googleApiConnection->updateSuccessLastResultConnection();
620 PushTable::add([
621 'ENTITY_TYPE' => self::TYPE_CONNECTION,
622 'ENTITY_ID' => $connectionData['ID'],
623 'CHANNEL_ID' => $channelInfo['id'],
624 'RESOURCE_ID' => $channelInfo['resourceId'],
625 'EXPIRES' => $channelInfo['expiration'],
626 'NOT_PROCESSED' => 'N'
627 ]);
628 }
629 else
630 {
631 $error = $googleApiConnection->getTransportConnectionError();
632 if (is_string($error))
633 {
634 $googleApiConnection->updateLastResultConnection($error);
635 }
636 }
637 }
638 }
639 }
640
646 private static function checkPushSectionChannel(array $connectionIds, array $connections): void
647 {
648 $existedSectionChannels = [];
649 $sections = [];
650 $sectionIds = [];
651
652 $sectionsDb = Internals\SectionTable::getList(
653 [
654 'filter' => [
655 'CAL_DAV_CON' => $connectionIds,
656 ],
657 'order' => [
658 'ID' => 'ASC',
659 ],
660 ]
661 );
662
663 while ($section = $sectionsDb->fetch())
664 {
665 $sections[$section['ID']] = $section;
666 $sectionIds[] = $section['ID'];
667 }
668
669 if (!empty($sectionIds))
670 {
671 $pushSectionChannelsDb = PushTable::getList(
672 [
673 'filter' => [
674 '=ENTITY_TYPE' => self::TYPE_SECTION,
675 '=ENTITY_ID' => $sectionIds
676 ]
677 ]
678 );
679
680 while ($row = $pushSectionChannelsDb->fetch())
681 {
682 $channelInfo = null;
683 if (!empty($sections[$row['ENTITY_ID']]))
684 {
685 $section = $sections[$row['ENTITY_ID']];
686
687 if (self::isVirtualCalendar($section['GAPI_CALENDAR_ID'], $section['EXTERNAL_TYPE']))
688 {
689 continue;
690 }
691
692 if (!self::isConnectionError($connections[$section['CAL_DAV_CON']]['LAST_RESULT']))
693 {
694 $existedSectionChannels[] = $row['ENTITY_ID'];
695 continue;
696 }
697
698 $googleApiConnection = new GoogleApiSync($section['OWNER_ID'], $section['CAL_DAV_CON']);
699 if ($googleApiConnection->stopChannel($row['CHANNEL_ID'], $row['RESOURCE_ID']))
700 {
702 $channelInfo = $googleApiConnection->startWatchEventsChannel($section['GAPI_CALENDAR_ID']);
703 }
704 if (is_string($googleApiConnection->getTransportConnectionError()))
705 {
707 }
708
709 if ($channelInfo && isset($channelInfo['id'], $channelInfo['resourceId']))
710 {
711 $existedSectionChannels[] = $row['ENTITY_ID'];
712 $googleApiConnection->updateSuccessLastResultConnection();
713 PushTable::add([
714 'ENTITY_TYPE' => $row['ENTITY_TYPE'],
715 'ENTITY_ID' => $row['ENTITY_ID'],
716 'CHANNEL_ID' => $channelInfo['id'],
717 'RESOURCE_ID' => $channelInfo['resourceId'],
718 'EXPIRES' => $channelInfo['expiration'],
719 'NOT_PROCESSED' => 'N'
720 ]);
721 }
722 }
723 }
724
725 //create new channel for sections
726 $missedChannelSections = array_diff($sectionIds, $existedSectionChannels);
727 if (!empty($missedChannelSections))
728 {
729 foreach ($missedChannelSections as $missedSection)
730 {
731 $channelInfo = null;
732 $connectionData = $connections[$sections[$missedSection]['CAL_DAV_CON']];
733 $section = $sections[$missedSection];
734 if (
735 self::isAuthError($connectionData['LAST_RESULT'])
736 || self::isVirtualCalendar($section['GAPI_CALENDAR_ID'], $section['EXTERNAL_TYPE'])
737 )
738 {
739 continue;
740 }
741
742 $googleApiConnection = new GoogleApiSync($connectionData['ENTITY_ID'], $connectionData['ID']);
743 $channelInfo = $googleApiConnection->startWatchEventsChannel($section['GAPI_CALENDAR_ID']);
744 if ($channelInfo && isset($channelInfo['id'], $channelInfo['resourceId']))
745 {
746 $googleApiConnection->updateSuccessLastResultConnection();
747 $row = [
748 'ENTITY_TYPE' => self::TYPE_SECTION,
749 'ENTITY_ID' => $missedSection,
750 'CHANNEL_ID' => $channelInfo['id'],
751 'RESOURCE_ID' => $channelInfo['resourceId'],
752 'EXPIRES' => $channelInfo['expiration'],
753 'NOT_PROCESSED' => 'N'
754 ];
756 PushTable::add($row);
757 }
758 else
759 {
760 $error = $googleApiConnection->getTransportConnectionError();
761 if (is_string($error))
762 {
763 $googleApiConnection->updateLastResultConnection($error);
764 }
765 }
766 }
767 }
768 }
769 }
770
775 public static function deletePushChannel(array $row): void
776 {
777 PushTable::delete(['ENTITY_TYPE' => $row['ENTITY_TYPE'], 'ENTITY_ID' => $row['ENTITY_ID']]);
778 }
779
785 private static function isVirtualCalendar(?string $gApiCalendarId, ?string $externalType): bool
786 {
787 return preg_match('/(holiday.calendar.google.com)/', $gApiCalendarId)
788 || preg_match('/(group.v.calendar.google.com)/', $gApiCalendarId)
789 || preg_match('/(@virtual)/', $gApiCalendarId)
790 || preg_match('/(_readonly)/', $externalType)
791 || preg_match('/(_freebusy)/', $externalType);
792 }
793
800 private static function startChannelForInActiveSections(
801 array $localSections,
802 array $inactiveSections,
803 GoogleApiSync $googleApiConnection
804 ): void
805 {
806 foreach ($localSections as $section)
807 {
808 if (self::isVirtualCalendar($section['GAPI_CALENDAR_ID'], $section['EXTERNAL_TYPE']))
809 {
810 continue;
811 }
812
813 if (isset($inactiveSections[$section['ID']]))
814 {
815 if (($push = self::getPush(self::TYPE_SECTION, $section['ID'])) && self::isValid($push))
816 {
817 continue;
818 }
819
820 $channelInfo = $googleApiConnection->startWatchEventsChannel($section['GAPI_CALENDAR_ID']);
821 if ($channelInfo && isset($channelInfo['id'], $channelInfo['resourceId']))
822 {
824 [
825 "ENTITY_TYPE" => self::TYPE_SECTION,
826 'ENTITY_ID' => $section['ID']
827 ]
828 );
829 $googleApiConnection->updateSuccessLastResultConnection();
830 PushTable::add([
831 'ENTITY_TYPE' => self::TYPE_SECTION,
832 'ENTITY_ID' => $section['ID'],
833 'CHANNEL_ID' => $channelInfo['id'],
834 'RESOURCE_ID' => $channelInfo['resourceId'],
835 'EXPIRES' => $channelInfo['expiration'],
836 'NOT_PROCESSED' => 'N'
837 ]);
838 }
839 else
840 {
841 $error = $googleApiConnection->getTransportConnectionError();
842 if (is_string($error))
843 {
844 $googleApiConnection->updateLastResultConnection($error);
845 }
846 }
847 }
848 }
849 }
850
855 private static function getLastResultBySectionId(int $sectionId): ?string
856 {
857 global $DB;
858
859 $strSql = "SELECT c.ID as CONNECTON_ID, c.LAST_RESULT, s.ID as SECTION_ID
860 FROM b_dav_connections c
861 INNER JOIN b_calendar_section s
862 ON s.ID = " . $sectionId
863 . " WHERE s.CAL_DAV_CON = c.ID";
864
865 $connectionDb = $DB->Query($strSql);
866 if ($connection = $connectionDb->Fetch())
867 {
868 return $connection['LAST_RESULT'];
869 }
870
871 return null;
872 }
873
878 private static function getNotVirtualSectionIds(array $localSections): array
879 {
880 $sectionIds = [];
881 foreach ($localSections as $section)
882 {
883 //Skip virtual calendars, because they are not pushable.
884 if (self::isVirtualCalendar($section['GAPI_CALENDAR_ID'], $section['EXTERNAL_TYPE']))
885 {
886 continue;
887 }
888
889 $sectionIds[] = (int)$section['ID'];
890 }
891
892 return $sectionIds;
893 }
894
902 public static function getConnectionPushByConnectionId(int $id)
903 {
904 $pushResultDb = PushTable::getByPrimary([
905 'ENTITY_TYPE' => self::TYPE_CONNECTION,
906 'ENTITY_ID' => $id,
907 ]);
908
909 return $pushResultDb->fetch();
910 }
911
916 public static function setBlockPush(string $type, int $entityId): void
917 {
918 global $DB;
919 $push = self::getPush($type,$entityId);
920 if (
921 $push
922 && isset($push['NOT_PROCESSED'])
923 && !in_array($push['NOT_PROCESSED'], Google\Dictionary::PUSH_STATUS_PROCESS, true)
924 )
925 {
926 $strSql = "UPDATE b_calendar_push"
927 . " SET NOT_PROCESSED = '" . Google\Dictionary::PUSH_STATUS_PROCESS['block'] . "'"
928 . " WHERE ENTITY_TYPE = '" . $type . "' AND ENTITY_ID = " . $entityId . ";";
929 $DB->Query($strSql);
930 }
931 }
932
937 public static function setUnblockPush(string $type, int $entityId): void
938 {
939 global $DB;
940
941 $push = self::getPush($type, $entityId);
942 if ($push !== null)
943 {
944 $strSql = "UPDATE b_calendar_push"
945 . " SET NOT_PROCESSED = 'N'"
946 . " WHERE ENTITY_TYPE = '" . $type . "' AND ENTITY_ID = " . $entityId . ";";
947 $DB->Query($strSql);
948
949 if ($push['NOT_PROCESSED'] === Dictionary::PUSH_STATUS_PROCESS['unprocessed'])
950 {
951 self::processIncomingPush($type, $entityId);
952 }
953 }
954 }
955
960 public static function setUnprocessedPush(string $type, int $entityId): void
961 {
962 global $DB;
963
964 $push = self::getPush($type, $entityId);
965 if (
966 $push
967 && isset($push['NOT_PROCESSED'])
968 && $push['NOT_PROCESSED'] !== Google\Dictionary::PUSH_STATUS_PROCESS['unprocessed']
969 )
970 {
971 $strSql = "UPDATE b_calendar_push"
972 . " SET NOT_PROCESSED = '" . Google\Dictionary::PUSH_STATUS_PROCESS['unprocessed'] ."'"
973 . " WHERE ENTITY_TYPE = '" . $type . "' AND ENTITY_ID = " . $entityId . ";";
974 $DB->Query($strSql);
975 }
976 }
977
983 public static function getPush(string $type, int $entityId): ?array
984 {
985 global $DB;
986
987 $strSql = "SELECT * FROM b_calendar_push"
988 . " WHERE ENTITY_TYPE = '" . $type . "' AND ENTITY_ID = " . $entityId . ";";
989 $pushDb = $DB->Query($strSql);
990
991 if ($push = $pushDb->Fetch())
992 {
993 return $push;
994 }
995
996 return null;
997 }
998
999 private static function isValid(?array $push): bool
1000 {
1001 if ($push === null)
1002 {
1003 return false;
1004 }
1005
1006 $now = time();
1007 $tsExpires = strtotime($push['EXPIRES']);
1008
1009 return !($now > $tsExpires);
1010 }
1011}
static setIntervalForAgent(int $agentInterval=self::REGULAR_CHECK_TIME, int $delay=self::REGULAR_CHECK_TIME)
static isWrongChannel(string $error=null)
static processIncomingPush(string $entityType, int $entityId)
static isConnectionError(string $lastResult=null)
static receivePushSignal($channelId, $resourceId)
static setBlockPush(string $type, int $entityId)
static stopChannel(array $row=null, $ownerId=0)
static getConnectionPushByConnectionId(int $id)
static checkPushChannel(int $lastIdConnection=0)
static checkSectionsPush($localSections, $userId, $connectionId)
static getPush(string $type, int $entityId)
static isSyncTokenExpiresError(string $lastResult=null)
static setUnprocessedPush(string $type, int $entityId)
static setUnblockPush(string $type, int $entityId)
static isAuthError(string $lastResult=null)