%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/bitrix/www/bitrix/modules/rest/lib/api/
Upload File :
Create Path :
Current File : //home/bitrix/www/bitrix/modules/rest/lib/api/event.php

<?php
namespace Bitrix\Rest\Api;


use Bitrix\Bitrix24\Feature;
use Bitrix\Main\ArgumentException;
use Bitrix\Main\ArgumentNullException;
use Bitrix\Main\Loader;
use Bitrix\Main\Type\DateTime;
use Bitrix\Rest\AccessException;
use Bitrix\Rest\AppTable;
use Bitrix\Rest\AuthTypeException;
use Bitrix\Rest\EventOfflineTable;
use Bitrix\Rest\EventTable;
use Bitrix\Rest\HandlerHelper;
use Bitrix\Rest\LicenseException;
use Bitrix\Rest\OAuth\Auth;
use Bitrix\Rest\RestException;

class Event extends \IRestService
{
	const FEATURE_EXTENDED_MODE = 'rest_offline_extended';

	/**
	 * Returns description of events REST API
	 *
	 * @return array
	 */
	public static function onRestServiceBuildDescription()
	{
		return array(
			\CRestUtil::GLOBAL_SCOPE => array(
				'events' => array(__CLASS__, 'eventsList'),
				'event.bind' => array(__CLASS__, 'eventBind'),
				'event.unbind' => array(__CLASS__, 'eventUnBind'),
				'event.get' => array(__CLASS__, 'eventGet'),
				'event.offline.get' => array(__CLASS__, 'eventOfflineGet'),
				'event.offline.clear' => array(__CLASS__, 'eventOfflineClear'),
				'event.offline.error' => array(__CLASS__, 'eventOfflineError'),
				'event.offline.list' => array(__CLASS__, 'eventOfflineList'),

				'event.test' => array(
					'callback' => array(__CLASS__, 'eventTest'),
					'options' => array()
				),
			),
		);
	}

	/**
	 * /rest/events method handler
	 *
	 * Administrator rights required
	 *
	 * Query format:
	 *
	 * SCOPE - limit events list by some scope
	 * FULL - get all events regardless of application scope
	 *
	 * @param array $query
	 * @param $n
	 * @param \CRestServer $server
	 *
	 * @return array
	 *
	 * @throws AuthTypeException
	 */
	public static function eventsList($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		$serviceDescription = $server->getServiceDescription();

		$scopeList = array(\CRestUtil::GLOBAL_SCOPE);
		$result = array();

		$query = array_change_key_case($query, CASE_UPPER);

		if(isset($query['SCOPE']))
		{
			if($query['SCOPE'] != '')
			{
				$scopeList = array($query['SCOPE']);
			}
		}
		elseif($query['FULL'] == true)
		{
			$scopeList = array_keys($serviceDescription);
		}
		else
		{
			$scopeList = $server->getAuthScope();
			$scopeList[] = \CRestUtil::GLOBAL_SCOPE;
		}

		foreach ($serviceDescription as $scope => $scopeMethods)
		{
			if(in_array($scope, $scopeList) && isset($scopeMethods[\CRestUtil::EVENTS]))
			{
				$result = array_merge($result, array_keys($scopeMethods[\CRestUtil::EVENTS]));
			}
		}

		return $result;
	}


	/**
	 * /rest/event.bind method handler
	 *
	 * Administrator rights required
	 *
	 * Query format:
	 *
	 * - EVENT - event name
	 * - EVENT_TYPE = {online|offline} - type of event handling. Default: online
	 * - AUTH_TYPE - User ID, whose auth will be generated for handler. Useless for offline type. Default value is 0, which means getting auth for user, authorized when event is called
	 * - HANDLER - URL of event handler. Useless for offline type
	 *
	 * @param array $query
	 * @param $n
	 * @param \CRestServer $server
	 *
	 * @return bool
	 *
	 * @throws AccessException
	 * @throws ArgumentException
	 * @throws ArgumentNullException
	 * @throws AuthTypeException
	 * @throws RestException
	 * @throws \Exception
	 */
	public static function eventBind($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== \Bitrix\Rest\OAuth\Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		if(\CRestUtil::isAdmin())
		{
			$query = array_change_key_case($query, CASE_UPPER);

			$eventName = ToUpper($query['EVENT']);
			$eventType = ToLower($query['EVENT_TYPE']);
			$eventUser = intval($query['AUTH_TYPE']);
			$eventCallback = $query['HANDLER'];

			$authData = $server->getAuthData();

			$connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';

			if(strlen($eventName) <= 0)
			{
				throw new ArgumentNullException("EVENT");
			}

			if(strlen($eventType) > 0)
			{
				if(!in_array($eventType, array(EventTable::TYPE_ONLINE, EventTable::TYPE_OFFLINE)))
				{
					throw new ArgumentException('Value must be one of {'.EventTable::TYPE_ONLINE.'|'.EventTable::TYPE_OFFLINE.'}', 'EVENT_TYPE');
				}
			}
			else
			{
				$eventType = EventTable::TYPE_ONLINE;
			}

			if($eventType === EventTable::TYPE_OFFLINE)
			{
				$eventCallback = '';
				$eventUser = 0;
			}
			elseif(strlen($eventCallback) <= 0 && $eventType === EventTable::TYPE_ONLINE)
			{
				throw new ArgumentNullException("HANDLER");
			}

			$clientInfo = AppTable::getByClientId($server->getClientId());

			if(strlen($eventCallback) <= 0 || HandlerHelper::checkCallback($eventCallback, $clientInfo))
			{
				$scopeList = $server->getAuthScope();
				$scopeList[] = \CRestUtil::GLOBAL_SCOPE;

				$serviceDescription = $server->getServiceDescription();

				foreach($scopeList as $scope)
				{
					if(
						isset($serviceDescription[$scope])
						&& is_array($serviceDescription[$scope][\CRestUtil::EVENTS])
						&& array_key_exists($eventName, $serviceDescription[$scope][\CRestUtil::EVENTS])
					)
					{
						$eventInfo = $serviceDescription[$scope][\CRestUtil::EVENTS][$eventName];
						if(is_array($eventInfo))
						{
							$eventHandlerFields = array(
								'APP_ID' => $clientInfo['ID'],
								'EVENT_NAME' => $eventName,
								'EVENT_HANDLER' => $eventCallback,
								'CONNECTOR_ID' => $connectorId,
							);

							if($eventUser > 0)
							{
								$eventHandlerFields['USER_ID'] = $eventUser;
							}

							$result = EventTable::add($eventHandlerFields);
							if($result->isSuccess())
							{
								\Bitrix\Rest\Event\Sender::bind($eventInfo[0], $eventInfo[1]);
							}
							else
							{
								$errorMessage = $result->getErrorMessages();
								throw new RestException('Unable to set event handler: '.implode('. ', $errorMessage), RestException::ERROR_CORE);
							}
						}

						return true;
					}
				}

				throw new RestException('Event not found', EventTable::ERROR_EVENT_NOT_FOUND);
			}
			else
			{
				return false;
			}
		}
		else
		{
			throw new AccessException();
		}
	}

	/**
	 * /rest/event.unbind method handler
	 *
	 * Returns count of unbinded events
	 *
	 * Administrator rights required
	 *
	 * Query format:
	 *
	 * - EVENT - event name
	 * - EVENT_TYPE = {online|offline} - type of event handling. Default: online
	 * - AUTH_TYPE - The same value as event.bind was called with. Useless for offline type. Default 0
	 * - HANDLER - URL of event handler. Useless for offline type
	 *
	 * @param array $query
	 * @param $n
	 * @param \CRestServer $server
	 *
	 * @return array
	 *
	 * @throws AccessException
	 * @throws ArgumentException
	 * @throws ArgumentNullException
	 * @throws AuthTypeException
	 * @throws \Bitrix\Main\ObjectPropertyException
	 * @throws \Bitrix\Main\SystemException
	 * @throws \Exception
	 */
	public static function eventUnbind($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		if(\CRestUtil::isAdmin())
		{
			$query = array_change_key_case($query, CASE_UPPER);

			$eventName = ToUpper($query['EVENT']);
			$eventType = ToLower($query['EVENT_TYPE']);
			$eventCallback = $query['HANDLER'];

			if(strlen($eventName) <= 0)
			{
				throw new ArgumentNullException("EVENT");
			}

			if(strlen($eventType) > 0)
			{
				if(!in_array($eventType, array(EventTable::TYPE_ONLINE, EventTable::TYPE_OFFLINE)))
				{
					throw new ArgumentException('Value must be one of {'.EventTable::TYPE_ONLINE.'|'.EventTable::TYPE_OFFLINE.'}', 'EVENT_TYPE');
				}
			}
			else
			{
				$eventType = EventTable::TYPE_ONLINE;
			}

			if($eventType === EventTable::TYPE_OFFLINE)
			{
				$eventCallback = '';
			}
			elseif(strlen($eventCallback) <= 0)
			{
				throw new ArgumentNullException("HANDLER");
			}

			$clientInfo = AppTable::getByClientId($server->getClientId());

			$filter = array(
				'=APP_ID' => $clientInfo["ID"],
				'=EVENT_NAME' => $eventName,
				'=EVENT_HANDLER' => $eventCallback,
			);

			if($eventType === EventTable::TYPE_OFFLINE)
			{
				$authData = $server->getAuthData();
				$filter['=CONNECTOR_ID'] = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';
			}
			else
			{
				if(isset($query['AUTH_TYPE']))
				{
					$filter['=USER_ID'] = intval($query['AUTH_TYPE']);
				}
			}

			$dbRes = EventTable::getList(array(
				'filter' => $filter
			));

			$cnt = 0;
			while($eventInfo = $dbRes->fetch())
			{
				$result = EventTable::delete($eventInfo["ID"]);
				if($result->isSuccess())
				{
					// we shouldn't make Unbind here, it'll be done during the first event call
					$cnt++;
				}
			}

			return array('count' => $cnt);
		}
		else
		{
			throw new AccessException();
		}
	}


	public static function eventGet($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		if(\CRestUtil::isAdmin())
		{
			$result = array();

			$clientInfo = AppTable::getByClientId($server->getClientId());

			$dbRes = EventTable::getList(array(
				"filter" => array(
					"=APP_ID" => $clientInfo["ID"],
				),
				'order' => array(
					"ID" => "ASC",
				),
			));
			while($eventHandler = $dbRes->fetch())
			{
				if(strlen($eventHandler['EVENT_HANDLER']) > 0)
				{
					$result[] = array(
						"event" => $eventHandler['EVENT_NAME'],
						"handler" => $eventHandler['EVENT_HANDLER'],
						"auth_type" => $eventHandler['USER_ID'],
						"offline" => 0
					);
				}
				else
				{
					$result[] = array(
						"event" => $eventHandler['EVENT_NAME'],
						"connector_id" => $eventHandler['CONNECTOR_ID'] === null ? '' : $eventHandler['CONNECTOR_ID'],
						"offline" => 1
					);
				}
			}

			return $result;
		}
		else
		{
			throw new AccessException();
		}
	}


	public static function eventTest($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		$clientInfo = AppTable::getByClientId($server->getClientId());

		foreach(GetModuleEvents("rest", "OnRestAppTest", true) as $event)
		{
			ExecuteModuleEventEx($event, array(array(
				"APP_ID" => $clientInfo["ID"],
				"QUERY" => $query
			)));
		}

		return 1;
	}


	public static function eventOfflineGet($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		if(!\CRestUtil::isAdmin())
		{
			throw new AccessException();
		}

		$query = array_change_key_case($query, CASE_LOWER);

		$clearEvents = !isset($query['clear']) ? 1 : intval($query['clear']);
		$processId = isset($query['process_id']) ? trim($query['process_id']) : null;

		if(!$clearEvents && !static::isExtendedModeEnabled())
		{
			throw new LicenseException('extended offline events handling');
		}

		$filter = isset($query['filter']) ? $query['filter'] : array();
		$order = isset($query['order']) ? $query['order'] : array('TIMESTAMP_X' => 'ASC');
		$limit = isset($query['limit']) ? intval($query['limit']) : static::LIST_LIMIT;

		$getErrors = isset($query['error']) && intval($query['error']) === 1;

		$authData = $server->getAuthData();
		$connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';

		$returnProcessId = !$clearEvents;

		if($limit <= 0)
		{
			throw new ArgumentException('Value must be positive integer', 'LIMIT');
		}

		$queryFilter = static::sanitizeFilter($filter);

		$order = static::sanitizeOrder($order);

		$clientInfo = AppTable::getByClientId($server->getClientId());

		$queryFilter['=APP_ID'] = $clientInfo['ID'];
		$queryFilter['=CONNECTOR_ID'] = $connectorId;
		$queryFilter['=ERROR'] = $getErrors ? 1 : 0;

		if($processId === null)
		{
			$queryFilter['=PROCESS_ID'] = '';
			$processId = EventOfflineTable::markEvents($queryFilter, $order, $limit);
		}
		else
		{
			$returnProcessId = true;
		}

		$queryFilter['=PROCESS_ID'] = $processId;

		$dbRes = EventOfflineTable::getList(array(
			'select' => array(
				'ID', 'TIMESTAMP_X', 'EVENT_NAME', 'EVENT_DATA', 'EVENT_ADDITIONAL', 'MESSAGE_ID'
			),
			'filter' => $queryFilter,
			'limit' => $limit,
			'order' => $order,
		));

		$result = array();

		while($event = $dbRes->fetch())
		{
			/** @var DateTime $ts */
			$ts = $event['TIMESTAMP_X'];

			$event['TIMESTAMP_X'] = \CRestUtil::convertDateTime($ts->toString());
			$event['EVENT_ADDITIONAL'] = array(
				'user_id' => $event['EVENT_ADDITIONAL'][Auth::PARAM_LOCAL_USER],
			);

			$result[] = $event;
		}

		if($clearEvents && count($result) > 0)
		{
			EventOfflineTable::clearEvents($processId, $clientInfo['ID'], $connectorId);
		}

		return array(
			'process_id' => $returnProcessId ? $processId : null,
			'events' => $result
		);
	}

	public static function eventOfflineClear($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		if(!\CRestUtil::isAdmin())
		{
			throw new AccessException();
		}

		$query = array_change_key_case($query, CASE_LOWER);

		$processId = isset($query['process_id']) ? trim($query['process_id']) : null;

		$authData = $server->getAuthData();
		$connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';

		if($processId === null)
		{
			throw new ArgumentNullException('PROCESS_ID');
		}

		$clientInfo = AppTable::getByClientId($server->getClientId());

		if(isset($query['message_id']))
		{
			$listIds = false;
			if(!is_array($query['message_id']))
			{
				throw new ArgumentException('Value must be array of MESSAGE_ID values', 'message_id');
			}

			foreach($query['message_id'] as $messageId)
			{
				$messageId = trim($messageId);

				if(strlen($messageId) !== 32)
				{
					throw new ArgumentException('Value must be array of MESSAGE_ID values', 'messsage_id');
				}

				$listIds[] = $messageId;
			}

			EventOfflineTable::clearEventsByMessageId($processId, $clientInfo['ID'], $connectorId, $listIds);
		}
		else
		{
			$listIds = false;
			if(isset($query['id']))
			{
				if(!is_array($query['id']))
				{
					throw new ArgumentException('Value must be array of integers', 'id');
				}

				foreach($query['id'] as $id)
				{
					$id = intval($id);

					if($id <= 0)
					{
						throw new ArgumentException('Value must be array of integers', 'id');
					}

					$listIds[] = $id;
				}
			}

			EventOfflineTable::clearEvents($processId, $clientInfo['ID'], $connectorId, $listIds);
		}

		return true;
	}

	public static function eventOfflineError($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		if(!\CRestUtil::isAdmin())
		{
			throw new AccessException();
		}

		$query = array_change_key_case($query, CASE_LOWER);

		$processId = isset($query['process_id']) ? trim($query['process_id']) : null;
		$messageId = isset($query['message_id']) ? $query['message_id'] : null;

		$authData = $server->getAuthData();
		$connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';

		if($processId === null)
		{
			throw new ArgumentNullException('PROCESS_ID');
		}

		if(!is_array($messageId))
		{
			throw new ArgumentException('Value must be array of MESSAGE_ID values', 'message_id');
		}

		$clientInfo = AppTable::getByClientId($server->getClientId());
		if(count($messageId) > 0)
		{
			EventOfflineTable::markError($processId, $clientInfo['ID'], $connectorId, $messageId);
		}

		return true;
	}

	public static function eventOfflineList($query, $n, \CRestServer $server)
	{
		if($server->getAuthType() !== Auth::AUTH_TYPE)
		{
			throw new AuthTypeException();
		}

		if(!\CRestUtil::isAdmin())
		{
			throw new AccessException();
		}

		$query = array_change_key_case($query, CASE_LOWER);

		$filter = isset($query['filter']) ? $query['filter'] : array();
		$order = isset($query['order']) ? $query['order'] : array('ID' => 'ASC');

		$authData = $server->getAuthData();
		$connectorId = isset($authData['auth_connector']) ? $authData['auth_connector'] : '';

		$queryFilter = static::sanitizeFilter($filter, array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID', 'PROCESS_ID', 'ERROR'));

		$order = static::sanitizeOrder($order, array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID', 'PROCESS_ID', 'ERROR'));

		$clientInfo = AppTable::getByClientId($server->getClientId());

		$queryFilter['=APP_ID'] = $clientInfo['ID'];
		$queryFilter['=CONNECTOR_ID'] = $connectorId;

		$navParams = static::getNavData($n, true);

		$dbRes = EventOfflineTable::getList(array(
			'select' => array(
				'ID', 'TIMESTAMP_X', 'EVENT_NAME', 'EVENT_DATA', 'EVENT_ADDITIONAL', 'MESSAGE_ID', 'PROCESS_ID', 'ERROR'
			),
			'filter' => $queryFilter,
			'limit' => $navParams['limit'],
			'offset' => $navParams['offset'],
			'count_total' => true,
			'order' => $order,
		));

		$result = array();

		while($event = $dbRes->fetch())
		{
			/** @var DateTime $ts */
			$ts = $event['TIMESTAMP_X'];

			$event['TIMESTAMP_X'] = \CRestUtil::convertDateTime($ts->toString());
			$event['EVENT_ADDITIONAL'] = array(
				'user_id' => $event['EVENT_ADDITIONAL'][Auth::PARAM_LOCAL_USER],
			);

			$result[] = $event;
		}

		return static::setNavData($result, array(
			"count" => $dbRes->getCount(),
			"offset" => $navParams['offset']
		));
	}

	protected static function sanitizeFilter($filter, array $availableFields = null, $valueCallback = null, array $availableOperations = null)
	{
		static $defaultFields = array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID');

		if($availableFields === null)
		{
			$availableFields = $defaultFields;
		}

		return parent::sanitizeFilter(
			$filter,
			$availableFields,
			function($field, $value)
			{
				switch($field)
				{
					case 'TIMESTAMP_X':

						return DateTime::createFromUserTime(\CRestUtil::unConvertDateTime($value));

					break;
				}
				return $value;
			}
		);
	}

	protected static function sanitizeOrder($order, array $availableFields = null)
	{
		static $defaultFields = array('ID', 'TIMESTAMP_X', 'EVENT_NAME', 'MESSAGE_ID');

		if($availableFields === null)
		{
			$availableFields = $defaultFields;
		}

		return parent::sanitizeOrder($order, $availableFields);
	}

	protected static function isExtendedModeEnabled()
	{
		return !Loader::includeModule('bitrix24')
			|| Feature::isFeatureEnabled(static::FEATURE_EXTENDED_MODE);
	}
}

Zerion Mini Shell 1.0