Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
event.php
1<?php
3
4
5use Bitrix\Bitrix24\Feature;
20
21class Event extends \IRestService
22{
23 const FEATURE_EXTENDED_MODE = 'rest_offline_extended';
24
30 public static function onRestServiceBuildDescription()
31 {
32 return array(
33 \CRestUtil::GLOBAL_SCOPE => array(
34 'events' => array(__CLASS__, 'eventsList'),
35 'event.bind' => array(__CLASS__, 'eventBind'),
36 'event.unbind' => array(__CLASS__, 'eventUnBind'),
37 'event.get' => array(__CLASS__, 'eventGet'),
38 'event.offline.get' => array(__CLASS__, 'eventOfflineGet'),
39 'event.offline.clear' => array(__CLASS__, 'eventOfflineClear'),
40 'event.offline.error' => array(__CLASS__, 'eventOfflineError'),
41 'event.offline.list' => array(__CLASS__, 'eventOfflineList'),
42
43 'event.test' => array(
44 'callback' => array(__CLASS__, 'eventTest'),
45 'options' => array()
46 ),
47 \CRestUtil::EVENTS => array(
48 'onOfflineEvent' => array(
49 'rest',
50 'onAfterOfflineEventCall',
51 array(EventOfflineTable::class, 'prepareOfflineEvent'),
52 array(
53 "sendRefreshToken" => true,
54 "disableOffline" => true,
55 "allowOptions" => [
56 'minTimeout' => 'int'
57 ],
58 ),
59 )
60 ),
61 ),
62 );
63 }
64
83 public static function eventsList($query, $n, \CRestServer $server)
84 {
85 if($server->getAuthType() !== Auth::AUTH_TYPE)
86 {
87 throw new AuthTypeException();
88 }
89
90 $serviceDescription = $server->getServiceDescription();
91
92 $scopeList = array(\CRestUtil::GLOBAL_SCOPE);
93 $result = array();
94
95 $query = array_change_key_case($query, CASE_UPPER);
96
97 if(isset($query['SCOPE']))
98 {
99 if($query['SCOPE'] != '')
100 {
101 $scopeList = array($query['SCOPE']);
102 }
103 }
104 elseif($query['FULL'] == true)
105 {
106 $scopeList = array_keys($serviceDescription);
107 }
108 else
109 {
110 $scopeList = $server->getAuthScope();
111 $scopeList[] = \CRestUtil::GLOBAL_SCOPE;
112 }
113
114 foreach ($serviceDescription as $scope => $scopeMethods)
115 {
116 if(in_array($scope, $scopeList) && isset($scopeMethods[\CRestUtil::EVENTS]))
117 {
118 $result = array_merge($result, array_keys($scopeMethods[\CRestUtil::EVENTS]));
119 }
120 }
121
122 return $result;
123 }
124
125
151 public static function eventBind($query, $n, \CRestServer $server)
152 {
153 global $USER;
154
155 if($server->getAuthType() !== \Bitrix\Rest\OAuth\Auth::AUTH_TYPE)
156 {
157 throw new AuthTypeException();
158 }
159
160 $query = array_change_key_case($query, CASE_UPPER);
161
162 $eventName = ToUpper($query['EVENT']);
163 $eventType = ToLower($query['EVENT_TYPE']);
164 $eventUser = intval($query['AUTH_TYPE']);
165 $eventCallback = $query['HANDLER'];
166 $options = is_array($query['OPTIONS']) ? $query['OPTIONS'] : [];
167
168 if($eventUser > 0)
169 {
170 if(!\CRestUtil::isAdmin() && $eventUser !== intval($USER->GetID()))
171 {
172 throw new AccessException('Event binding with AUTH_TYPE requires administrator access rights');
173 }
174 }
175 elseif(!\CRestUtil::isAdmin())
176 {
177 $eventUser = intval($USER->GetID());
178 }
179
180 $authData = $server->getAuthData();
181
182 $connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';
183
184 if($eventName == '')
185 {
186 throw new ArgumentNullException("EVENT");
187 }
188
189 if($eventType <> '')
190 {
191 if(!in_array($eventType, array(EventTable::TYPE_ONLINE, EventTable::TYPE_OFFLINE)))
192 {
193 throw new ArgumentException('Value must be one of {'.EventTable::TYPE_ONLINE.'|'.EventTable::TYPE_OFFLINE.'}', 'EVENT_TYPE');
194 }
195 }
196 else
197 {
198 $eventType = EventTable::TYPE_ONLINE;
199 }
200
201 if($eventType === EventTable::TYPE_OFFLINE)
202 {
203 if(!\CRestUtil::isAdmin())
204 {
205 throw new AccessException('Offline events binding requires administrator access rights');
206 }
207
208 $eventCallback = '';
209 $eventUser = 0;
210 }
211 elseif($eventCallback == '' && $eventType === EventTable::TYPE_ONLINE)
212 {
213 throw new ArgumentNullException("HANDLER");
214 }
215
216 $clientInfo = AppTable::getByClientId($server->getClientId());
217
218 if($eventCallback == '' || HandlerHelper::checkCallback($eventCallback, $clientInfo))
219 {
220 $scopeList = $server->getAuthScope();
221 $scopeList[] = \CRestUtil::GLOBAL_SCOPE;
222
223 $serviceDescription = $server->getServiceDescription();
224
225 foreach($scopeList as $scope)
226 {
227 if(
228 isset($serviceDescription[$scope])
229 && is_array($serviceDescription[$scope][\CRestUtil::EVENTS])
230 && array_key_exists($eventName, $serviceDescription[$scope][\CRestUtil::EVENTS])
231 )
232 {
233 $eventInfo = $serviceDescription[$scope][\CRestUtil::EVENTS][$eventName];
234 if(is_array($eventInfo))
235 {
236 $eventHandlerFields = array(
237 'APP_ID' => $clientInfo['ID'],
238 'EVENT_NAME' => $eventName,
239 'EVENT_HANDLER' => $eventCallback,
240 'CONNECTOR_ID' => $connectorId,
241 'OPTIONS' => []
242 );
243
244 if($eventUser > 0)
245 {
246 $eventHandlerFields['USER_ID'] = $eventUser;
247 }
248
249 if (
250 $eventCallback === ''
251 && isset($eventInfo[3]['disableOffline'])
252 && $eventInfo[3]['disableOffline'] === true
253 )
254 {
255 throw new RestException('Offline event cannot be registered for this event.', RestException::ERROR_ARGUMENT);
256 }
257
258 if (!empty($options) && isset($eventInfo[3]['allowOptions']) && is_array($eventInfo[3]['allowOptions']))
259 {
260 foreach ($eventInfo[3]['allowOptions'] as $code => $type)
261 {
262 if (isset($options[$code]))
263 {
264 if ($type === 'int')
265 {
266 $eventHandlerFields['OPTIONS'][$code] = (int) $options[$code];
267 }
268 elseif($type === 'str' && is_string($options[$code]))
269 {
270 $eventHandlerFields['OPTIONS'][$code] = $options[$code];
271 }
272 }
273 }
274 }
275
276 $result = EventTable::add($eventHandlerFields);
277 if($result->isSuccess())
278 {
279 \Bitrix\Rest\Event\Sender::bind($eventInfo[0], $eventInfo[1]);
280 }
281 else
282 {
283 $errorMessage = $result->getErrorMessages();
284 throw new RestException('Unable to set event handler: '.implode('. ', $errorMessage), RestException::ERROR_CORE);
285 }
286 }
287
288 return true;
289 }
290 }
291
292 throw new RestException('Event not found', EventTable::ERROR_EVENT_NOT_FOUND);
293 }
294 else
295 {
296 return false;
297 }
298 }
299
328 public static function eventUnbind($query, $n, \CRestServer $server)
329 {
330 global $USER;
331
332 if($server->getAuthType() !== Auth::AUTH_TYPE)
333 {
334 throw new AuthTypeException();
335 }
336
337 $query = array_change_key_case($query, CASE_UPPER);
338
339 $eventName = ToUpper($query['EVENT']);
340 $eventType = ToLower($query['EVENT_TYPE']);
341 $eventCallback = $query['HANDLER'];
342
343 if($eventName == '')
344 {
345 throw new ArgumentNullException("EVENT");
346 }
347
348 if($eventType <> '')
349 {
350 if(!in_array($eventType, array(EventTable::TYPE_ONLINE, EventTable::TYPE_OFFLINE)))
351 {
352 throw new ArgumentException('Value must be one of {'.EventTable::TYPE_ONLINE.'|'.EventTable::TYPE_OFFLINE.'}', 'EVENT_TYPE');
353 }
354 }
355 else
356 {
357 $eventType = EventTable::TYPE_ONLINE;
358 }
359
360 if($eventType === EventTable::TYPE_OFFLINE)
361 {
362 if(!\CRestUtil::isAdmin())
363 {
364 throw new AccessException('Offline events unbinding requires administrator access rights');
365 }
366
367 $eventCallback = '';
368 }
369 elseif($eventCallback == '')
370 {
371 throw new ArgumentNullException("HANDLER");
372 }
373
374 $clientInfo = AppTable::getByClientId($server->getClientId());
375
376 $filter = array(
377 '=APP_ID' => $clientInfo["ID"],
378 '=EVENT_NAME' => $eventName,
379 '=EVENT_HANDLER' => $eventCallback,
380 );
381
382 if($eventType === EventTable::TYPE_OFFLINE)
383 {
384 $authData = $server->getAuthData();
385 $filter['=CONNECTOR_ID'] = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';
386 }
387 else
388 {
389 if(isset($query['AUTH_TYPE']))
390 {
391 if(!\CRestUtil::isAdmin() && $query['AUTH_TYPE'] !== intval($USER->GetID()))
392 {
393 throw new AccessException('Event unbinding with AUTH_TYPE requires administrator access rights');
394 }
395
396 $filter['=USER_ID'] = intval($query['AUTH_TYPE']);
397 }
398 elseif(!\CRestUtil::isAdmin())
399 {
400 $filter['=USER_ID'] = intval($USER->GetID());
401 }
402 }
403
404 $dbRes = EventTable::getList(array(
405 'filter' => $filter,
406 'select' => ['ID']
407 ));
408
409 $cnt = 0;
410 while($eventInfo = $dbRes->fetch())
411 {
412 $result = EventTable::delete($eventInfo["ID"]);
413 if($result->isSuccess())
414 {
415 // we shouldn't make Unbind here, it'll be done during the first event call
416 $cnt++;
417 }
418 }
419
420 return array('count' => $cnt);
421 }
422
423
424 public static function eventGet($query, $n, \CRestServer $server)
425 {
426 global $USER;
427
428 if($server->getAuthType() !== Auth::AUTH_TYPE)
429 {
430 throw new AuthTypeException();
431 }
432
433 $result = array();
434
435 $clientInfo = AppTable::getByClientId($server->getClientId());
436
437 $filter = array(
438 "=APP_ID" => $clientInfo["ID"],
439 );
440
441 if(!\CRestUtil::isAdmin())
442 {
443 $filter['=USER_ID'] = $USER->GetID();
444 }
445
446 $dbRes = EventTable::getList(array(
447 "filter" => $filter,
448 'order' => array(
449 "ID" => "ASC",
450 ),
451 ));
452 while($eventHandler = $dbRes->fetch())
453 {
454 if($eventHandler['EVENT_HANDLER'] <> '')
455 {
456 $result[] = array(
457 "event" => $eventHandler['EVENT_NAME'],
458 "handler" => $eventHandler['EVENT_HANDLER'],
459 "auth_type" => $eventHandler['USER_ID'],
460 "offline" => 0
461 );
462 }
463 else
464 {
465 $result[] = array(
466 "event" => $eventHandler['EVENT_NAME'],
467 "connector_id" => $eventHandler['CONNECTOR_ID'] === null ? '' : $eventHandler['CONNECTOR_ID'],
468 "offline" => 1
469 );
470 }
471 }
472
473 return $result;
474 }
475
476
477 public static function eventTest($query, $n, \CRestServer $server)
478 {
479 if($server->getAuthType() !== Auth::AUTH_TYPE)
480 {
481 throw new AuthTypeException();
482 }
483
484 $clientInfo = AppTable::getByClientId($server->getClientId());
485
486 foreach(GetModuleEvents("rest", "OnRestAppTest", true) as $event)
487 {
488 ExecuteModuleEventEx($event, array(array(
489 "APP_ID" => $clientInfo["ID"],
490 "QUERY" => $query
491 )));
492 }
493
494 return 1;
495 }
496
497
498 public static function eventOfflineGet($query, $n, \CRestServer $server)
499 {
500 if ($server->getAuthType() !== Auth::AUTH_TYPE)
501 {
502 throw new AuthTypeException();
503 }
504
505 if (!\CRestUtil::isAdmin())
506 {
507 throw new AccessException();
508 }
509
510 $query = array_change_key_case($query, CASE_LOWER);
511
512 $clearEvents = !isset($query['clear']) ? 1 : intval($query['clear']);
513 $processId = isset($query['process_id']) ? trim($query['process_id']) : null;
514
515 if (!$clearEvents && !static::isExtendedModeEnabled())
516 {
517 throw new LicenseException('extended offline events handling');
518 }
519
520 $filter = isset($query['filter']) ? $query['filter'] : array();
521 $order = isset($query['order']) ? $query['order'] : array('TIMESTAMP_X' => 'ASC');
522 $limit = isset($query['limit']) ? intval($query['limit']) : static::LIST_LIMIT;
523
524 $getErrors = isset($query['error']) && intval($query['error']) === 1;
525
526 $authData = $server->getAuthData();
527 $connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';
528
529 $returnProcessId = !$clearEvents;
530
531 if ($limit <= 0)
532 {
533 throw new Exceptions\ArgumentException('Value must be positive integer', 'LIMIT');
534 }
535
536 $queryFilter = static::sanitizeFilter($filter);
537
538 $order = static::sanitizeOrder($order);
539
540 $clientInfo = AppTable::getByClientId($server->getClientId());
541
542 $queryFilter['=APP_ID'] = $clientInfo['ID'];
543 $queryFilter['=CONNECTOR_ID'] = $connectorId;
544 $queryFilter['=ERROR'] = $getErrors ? 1 : 0;
545
546 if ($processId === null)
547 {
548 $queryFilter['=PROCESS_ID'] = '';
549 $processId = EventOfflineTable::markEvents($queryFilter, $order, $limit);
550 }
551 else
552 {
553 $returnProcessId = true;
554 }
555
556 $queryFilter['=PROCESS_ID'] = $processId;
557
558 $dbRes = EventOfflineTable::getList(array(
559 'select' => array(
560 'ID', 'TIMESTAMP_X', 'EVENT_NAME', 'EVENT_DATA', 'EVENT_ADDITIONAL', 'MESSAGE_ID'
561 ),
562 'filter' => $queryFilter,
563 'limit' => $limit,
564 'order' => $order,
565 ));
566
567 $result = array();
568
569 while ($event = $dbRes->fetch())
570 {
572 $ts = $event['TIMESTAMP_X'];
573
574 $event['TIMESTAMP_X'] = \CRestUtil::convertDateTime($ts->toString());
575
576 if (isset($event['EVENT_ADDITIONAL'][Auth::PARAM_LOCAL_USER]))
577 {
578 $event['EVENT_ADDITIONAL'] = [
579 'user_id' => $event['EVENT_ADDITIONAL'][Auth::PARAM_LOCAL_USER],
580 ];
581 }
582
583 $result[] = $event;
584 }
585
586 if ($clearEvents && count($result) > 0)
587 {
588 EventOfflineTable::clearEvents($processId, $clientInfo['ID'], $connectorId);
589 }
590
591 return array(
592 'process_id' => $returnProcessId ? $processId : null,
593 'events' => $result
594 );
595 }
596
597 public static function eventOfflineClear($query, $n, \CRestServer $server)
598 {
599 if ($server->getAuthType() !== Auth::AUTH_TYPE)
600 {
601 throw new AuthTypeException();
602 }
603
604 if (!\CRestUtil::isAdmin())
605 {
606 throw new AccessException();
607 }
608
609 $query = array_change_key_case($query, CASE_LOWER);
610
611 $processId = isset($query['process_id']) ? trim($query['process_id']) : null;
612
613 $authData = $server->getAuthData();
614 $connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';
615
616 if ($processId === null)
617 {
618 throw new Exceptions\ArgumentNullException('PROCESS_ID');
619 }
620
621 $clientInfo = AppTable::getByClientId($server->getClientId());
622
623 if (isset($query['message_id']))
624 {
625 $listIds = false;
626 if (!is_array($query['message_id']))
627 {
628 throw new Exceptions\ArgumentException('Value must be array of MESSAGE_ID values', 'message_id');
629 }
630
631 foreach($query['message_id'] as $messageId)
632 {
633 $messageId = trim($messageId);
634
635 if (mb_strlen($messageId) !== 32)
636 {
637 throw new Exceptions\ArgumentException('Value must be array of MESSAGE_ID values', 'messsage_id');
638 }
639
640 $listIds[] = $messageId;
641 }
642
643 EventOfflineTable::clearEventsByMessageId($processId, $clientInfo['ID'], $connectorId, $listIds);
644 }
645 else
646 {
647 $listIds = false;
648 if (isset($query['id']))
649 {
650 if (!is_array($query['id']))
651 {
652 throw new Exceptions\ArgumentException('Value must be array of integers', 'id');
653 }
654
655 foreach($query['id'] as $id)
656 {
657 $id = intval($id);
658
659 if ($id <= 0)
660 {
661 throw new Exceptions\ArgumentException('Value must be array of integers', 'id');
662 }
663
664 $listIds[] = $id;
665 }
666 }
667
668 EventOfflineTable::clearEvents($processId, $clientInfo['ID'], $connectorId, $listIds);
669 }
670
671 return true;
672 }
673
674 public static function eventOfflineError($query, $n, \CRestServer $server)
675 {
676 if($server->getAuthType() !== Auth::AUTH_TYPE)
677 {
678 throw new AuthTypeException();
679 }
680
681 if(!\CRestUtil::isAdmin())
682 {
683 throw new AccessException();
684 }
685
686 $query = array_change_key_case($query, CASE_LOWER);
687
688 $processId = isset($query['process_id']) ? trim($query['process_id']) : null;
689 $messageId = isset($query['message_id']) ? $query['message_id'] : null;
690
691 $authData = $server->getAuthData();
692 $connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';
693
694 if($processId === null)
695 {
696 throw new ArgumentNullException('PROCESS_ID');
697 }
698
699 if(!is_array($messageId))
700 {
701 throw new ArgumentException('Value must be array of MESSAGE_ID values', 'message_id');
702 }
703
704 $clientInfo = AppTable::getByClientId($server->getClientId());
705 if(count($messageId) > 0)
706 {
707 EventOfflineTable::markError($processId, $clientInfo['ID'], $connectorId, $messageId);
708 }
709
710 return true;
711 }
712
713 public static function eventOfflineList($query, $n, \CRestServer $server)
714 {
715 if($server->getAuthType() !== Auth::AUTH_TYPE)
716 {
717 throw new AuthTypeException();
718 }
719
720 if(!\CRestUtil::isAdmin())
721 {
722 throw new AccessException();
723 }
724
725 $query = array_change_key_case($query, CASE_LOWER);
726
727 $filter = isset($query['filter']) ? $query['filter'] : array();
728 $order = isset($query['order']) ? $query['order'] : array('ID' => 'ASC');
729
730 $authData = $server->getAuthData();
731 $connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';
732
733 $queryFilter = static::sanitizeFilter($filter, array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID', 'PROCESS_ID', 'ERROR'));
734
735 $order = static::sanitizeOrder($order, array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID', 'PROCESS_ID', 'ERROR'));
736
737 $clientInfo = AppTable::getByClientId($server->getClientId());
738
739 $queryFilter['=APP_ID'] = $clientInfo['ID'];
740
741 $getEventQuery = EventOfflineTable::query();
742
743 if ($connectorId === '')
744 {
745 $getEventQuery->where('CONNECTOR_ID', '');
746 }
747 else
748 {
749 $queryFilter['=CONNECTOR_ID'] = $connectorId;
750 }
751
752 $navParams = static::getNavData($n, true);
753
754 $getEventQuery
755 ->setSelect(['ID', 'TIMESTAMP_X', 'EVENT_NAME', 'EVENT_DATA', 'EVENT_ADDITIONAL', 'MESSAGE_ID', 'PROCESS_ID', 'ERROR'])
756 ->setFilter($queryFilter)
757 ->setOrder($order)
758 ->setLimit($navParams['limit'])
759 ->setOffset($navParams['offset']);
760
761 $result = array();
762 $dbRes = $getEventQuery->exec();
763
764 while($event = $dbRes->fetch())
765 {
767 $ts = $event['TIMESTAMP_X'];
768
769 $event['TIMESTAMP_X'] = \CRestUtil::convertDateTime($ts->toString());
770
771 if (isset($event['EVENT_ADDITIONAL'][Auth::PARAM_LOCAL_USER]))
772 {
773 $event['EVENT_ADDITIONAL'] = [
774 'user_id' => $event['EVENT_ADDITIONAL'][Auth::PARAM_LOCAL_USER],
775 ];
776 }
777
778 $result[] = $event;
779 }
780
781 return static::setNavData($result, array(
782 "count" => $getEventQuery->queryCountTotal(),
783 "offset" => $navParams['offset']
784 ));
785 }
786
787 protected static function sanitizeFilter($filter, array $availableFields = null, $valueCallback = null, array $availableOperations = null)
788 {
789 static $defaultFields = array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID');
790
791 if($availableFields === null)
792 {
793 $availableFields = $defaultFields;
794 }
795
796 return parent::sanitizeFilter(
797 $filter,
798 $availableFields,
799 function($field, $value)
800 {
801 switch($field)
802 {
803 case 'TIMESTAMP_X':
804
805 return DateTime::createFromUserTime(\CRestUtil::unConvertDateTime($value));
806
807 break;
808 }
809 return $value;
810 }
811 );
812 }
813
814 protected static function sanitizeOrder($order, array $availableFields = null)
815 {
816 static $defaultFields = array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID');
817
818 if($availableFields === null)
819 {
820 $availableFields = $defaultFields;
821 }
822
823 return parent::sanitizeOrder($order, $availableFields);
824 }
825
826 protected static function isExtendedModeEnabled()
827 {
828 return !Loader::includeModule('bitrix24')
829 || Feature::isFeatureEnabled(static::FEATURE_EXTENDED_MODE);
830 }
831}
static createFromUserTime($timeString)
Definition datetime.php:180
static sanitizeOrder($order, array $availableFields=null)
Definition event.php:814
static onRestServiceBuildDescription()
Definition event.php:30
const FEATURE_EXTENDED_MODE
Definition event.php:23
static eventsList($query, $n, \CRestServer $server)
Definition event.php:83
static sanitizeFilter($filter, array $availableFields=null, $valueCallback=null, array $availableOperations=null)
Definition event.php:787
static eventBind($query, $n, \CRestServer $server)
Definition event.php:151
static eventUnbind($query, $n, \CRestServer $server)
Definition event.php:328
static eventTest($query, $n, \CRestServer $server)
Definition event.php:477
static eventGet($query, $n, \CRestServer $server)
Definition event.php:424
static isExtendedModeEnabled()
Definition event.php:826
static eventOfflineClear($query, $n, \CRestServer $server)
Definition event.php:597
static eventOfflineError($query, $n, \CRestServer $server)
Definition event.php:674
static getByClientId($clientId)
Definition app.php:929
static clearEvents($processId, $appId, $connectorId, $listIds=false)
static clearEventsByMessageId($processId, $appId, $connectorId, $listIds=false)
static markError($processId, $appId, $connectorId, array $listIds)
static markEvents($filter, $order, $limit)
const ERROR_EVENT_NOT_FOUND
Definition event.php:38
static checkCallback($handlerUrl, $appInfo=array(), $checkInstallUrl=true)