%PDF- %PDF-
Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/bizproc/classes/general/ |
Current File : //proc/self/root/home/bitrix/www/bitrix/modules/bizproc/classes/general/restactivity.php |
<?php use \Bitrix\Bizproc\RestActivityTable; use \Bitrix\Rest\Sqs; use \Bitrix\Main\Loader; use \Bitrix\Main\Localization\Loc; Loc::loadMessages(__FILE__); class CBPRestActivity extends CBPActivity implements IBPEventActivity, IBPActivityExternalEventListener { const TOKEN_SALT = 'bizproc'; const PROPERTY_NAME_PREFIX = 'property_'; const REST_ACTIVITY_ID = 0; protected static $restActivityData = array(); protected $subscriptionId = 0; protected $eventId; private static function getRestActivityData() { if (!isset(static::$restActivityData[static::REST_ACTIVITY_ID])) { $result = RestActivityTable::getById(static::REST_ACTIVITY_ID); $row = $result->fetch(); static::$restActivityData[static::REST_ACTIVITY_ID] = $row ? $row : array(); } return static::$restActivityData[static::REST_ACTIVITY_ID]; } public function __construct($name) { parent::__construct($name); $activityData = self::getRestActivityData(); $this->arProperties = array( 'Title' => '', 'UseSubscription' => isset($activityData['USE_SUBSCRIPTION']) && $activityData['USE_SUBSCRIPTION'] == 'Y' ? 'Y' : 'N', 'IsTimeout' => 0, 'AuthUserId' => isset($activityData['AUTH_USER_ID']) ? 'user_'.$activityData['AUTH_USER_ID'] : null, 'SetStatusMessage' => 'Y', 'StatusMessage' => '', 'TimeoutDuration' => 0, 'TimeoutDurationType' => 's', ); if (!empty($activityData['PROPERTIES'])) { foreach ($activityData['PROPERTIES'] as $name => $property) { if (isset($this->arProperties[$name])) continue; $this->arProperties[$name] = isset($property['DEFAULT']) ? $property['DEFAULT'] : null; } } $types = array(); if (!empty($activityData['RETURN_PROPERTIES'])) { foreach ($activityData['RETURN_PROPERTIES'] as $name => $property) { if (isset($this->arProperties[$name])) continue; $this->arProperties[$name] = isset($property['DEFAULT']) ? $property['DEFAULT'] : null; if (isset($property['TYPE'])) $types[$name] = array( 'Type' => $property['TYPE'], 'Multiple' => CBPHelper::getBool($property['MULTIPLE']), ); } } $types['IsTimeout'] = array( 'Type' => 'int', ); $this->SetPropertiesTypes($types); } protected function ReInitialize() { parent::ReInitialize(); $this->IsTimeout = 0; $this->eventId = null; $activityData = self::getRestActivityData(); if (!empty($activityData['RETURN_PROPERTIES'])) { foreach ($activityData['RETURN_PROPERTIES'] as $name => $property) { $this->{$name} = isset($property['DEFAULT']) ? $property['DEFAULT'] : null; } } } public function Execute() { $activityData = $this->getRestActivityData(); if (!$activityData) throw new Exception(Loc::getMessage('BPRA_NOT_FOUND_ERROR')); if (!Loader::includeModule('rest') || !\Bitrix\Rest\OAuthService::getEngine()->isRegistered()) return CBPActivityExecutionStatus::Closed; $propertiesData = []; if (!empty($activityData['PROPERTIES'])) { foreach ($activityData['PROPERTIES'] as $name => $property) { $propertiesData[$name] = $this->{$name}; if ($propertiesData[$name] === null) { $propertiesData[$name] = ''; } } } /* $session = \Bitrix\Rest\Event\Session::get(); if(!$session) { throw new Exception('Rest session error'); } */ $dbRes = \Bitrix\Rest\AppTable::getList(array( 'filter' => array( '=CLIENT_ID' => $activityData['APP_ID'], ) )); $application = $dbRes->fetch(); if (!$application) { throw new Exception('Rest application not found.'); } $appStatus = \Bitrix\Rest\AppTable::getAppStatusInfo($application, ''); if($appStatus['PAYMENT_ALLOW'] === 'N') { throw new Exception('Rest application status error: payment required'); } $userId = CBPHelper::ExtractUsers($this->AuthUserId, $this->GetDocumentId(), true); $auth = array( 'WORKFLOW_ID' => $this->getWorkflowInstanceId(), 'ACTIVITY_NAME' => $this->name, 'CODE' => $activityData['CODE'], //\Bitrix\Rest\Event\Session::PARAM_SESSION => $session, \Bitrix\Rest\OAuth\Auth::PARAM_LOCAL_USER => $userId, "application_token" => \CRestUtil::getApplicationToken($application), ); $this->eventId = \Bitrix\Main\Security\Random::getString(32, true); $queryItems = array( Sqs::queryItem( $activityData['APP_ID'], $activityData['HANDLER'], array( 'workflow_id' => $this->getWorkflowInstanceId(), 'code' => $activityData['CODE'], 'document_id' => $this->GetDocumentId(), 'document_type' => $this->GetDocumentType(), 'event_token' => self::generateToken($this->getWorkflowInstanceId(), $this->name, $this->eventId), 'properties' => $propertiesData, 'use_subscription' => $this->UseSubscription, 'timeout_duration' => $this->CalculateTimeoutDuration(), 'ts' => time(), ), $auth, array( "sendAuth" => true, "sendRefreshToken" => true, "category" => Sqs::CATEGORY_BIZPROC, ) ), ); \Bitrix\Rest\OAuthService::getEngine()->getClient()->sendEvent($queryItems); if ($this->SetStatusMessage == 'Y') { $message = $this->StatusMessage; if (empty($message)) $message = Loc::getMessage('BPRA_DEFAULT_STATUS_MESSAGE'); $this->SetStatusTitle($message); } if ($this->UseSubscription != 'Y') return CBPActivityExecutionStatus::Closed; $this->Subscribe($this); return CBPActivityExecutionStatus::Executing; } public function Subscribe(IBPActivityExternalEventListener $eventHandler) { if ($eventHandler == null) throw new Exception('eventHandler'); $timeoutDuration = $this->CalculateTimeoutDuration(); if ($timeoutDuration > 0) { $schedulerService = $this->workflow->GetService('SchedulerService'); $this->subscriptionId = $schedulerService->SubscribeOnTime($this->workflow->GetInstanceId(), $this->name, time() + $timeoutDuration); } $this->workflow->AddEventHandler($this->name, $eventHandler); } public function Unsubscribe(IBPActivityExternalEventListener $eventHandler) { if ($eventHandler == null) throw new Exception('eventHandler'); $timeoutDuration = $this->CalculateTimeoutDuration(); if ($timeoutDuration > 0) { $schedulerService = $this->workflow->GetService("SchedulerService"); $schedulerService->UnSubscribeOnTime($this->subscriptionId); $this->subscriptionId = 0; } $this->eventId = null; $this->workflow->RemoveEventHandler($this->name, $eventHandler); } public function OnExternalEvent($eventParameters = array()) { if ($this->executionStatus == CBPActivityExecutionStatus::Closed) return; $onAgent = (array_key_exists('SchedulerService', $eventParameters) && $eventParameters['SchedulerService'] == 'OnAgent'); if ($onAgent) { $this->IsTimeout = 1; $this->Unsubscribe($this); $this->workflow->CloseActivity($this); return; } if ($this->eventId !== (string) $eventParameters['EVENT_ID']) return; if (!empty($eventParameters['RETURN_VALUES'])) { $activityData = self::getRestActivityData(); $whiteList = array(); if (!empty($activityData['RETURN_PROPERTIES'])) { foreach ($activityData['RETURN_PROPERTIES'] as $name => $property) { $whiteList[strtoupper($name)] = $name; } } $eventParameters['RETURN_VALUES'] = array_change_key_case((array) $eventParameters['RETURN_VALUES'], CASE_UPPER); foreach($eventParameters['RETURN_VALUES'] as $name => $value) { if (!isset($whiteList[$name])) continue; $this->{$whiteList[$name]} = $value; } } $this->WriteToTrackingService( !empty($eventParameters['LOG_MESSAGE']) ? $eventParameters['LOG_MESSAGE'] : Loc::getMessage('BPRA_DEFAULT_LOG_MESSAGE')); if (empty($eventParameters['LOG_ACTION'])) { $this->Unsubscribe($this); $this->workflow->CloseActivity($this); } } public function Cancel() { if ($this->UseSubscription == 'Y') $this->Unsubscribe($this); return CBPActivityExecutionStatus::Closed; } public function HandleFault(Exception $exception) { if ($exception == null) throw new Exception("exception"); $status = $this->Cancel(); if ($status == CBPActivityExecutionStatus::Canceling) return CBPActivityExecutionStatus::Faulting; return $status; } public static function GetPropertiesDialog($documentType, $activityName, $workflowTemplate, $workflowParameters, $workflowVariables, $currentValues = null, $formName = "") { $activityData = self::getRestActivityData(); $dialog = new \Bitrix\Bizproc\Activity\PropertiesDialog(__FILE__, array( 'documentType' => $documentType, 'activityName' => $activityName, 'workflowTemplate' => $workflowTemplate, 'workflowParameters' => $workflowParameters, 'workflowVariables' => $workflowVariables, 'currentValues' => $currentValues )); $map = array( 'AuthUserId' => array( 'Name' => 'AuthUserId', 'FieldName' => 'authuserid', 'Type' => 'user', 'Default' => 'user_'.$activityData['AUTH_USER_ID'] ), 'SetStatusMessage' => array( 'Name' => 'SetStatusMessage', 'FieldName' => 'setstatusmessage', 'Type' => 'bool', ), 'StatusMessage' => array( 'Name' => 'StatusMessage', 'FieldName' => 'statusmessage', 'Type' => 'text', 'Default' => Loc::getMessage('BPRA_DEFAULT_STATUS_MESSAGE'), ), 'UseSubscription' => array( 'Name' => 'StatusMessage', 'FieldName' => 'usesubscription', 'Type' => 'bool', 'Default' => $activityData['USE_SUBSCRIPTION'] ), 'TimeoutDuration' => array( 'Name' => 'StatusMessage', 'FieldName' => 'timeoutduration', 'Type' => 'int', ), 'TimeoutDurationType' => array( 'Name' => 'StatusMessage', 'FieldName' => 'timeoutdurationtype', 'Type' => 'string', 'Default' => 's' ), ); $properties = isset($activityData['PROPERTIES']) && is_array($activityData['PROPERTIES']) ? $activityData['PROPERTIES'] : array(); foreach ($properties as $name => $property) { if (!array_key_exists($name, $map)) $map[$name] = array( 'Name' => RestActivityTable::getLocalization($property['NAME'], LANGUAGE_ID), 'Description' => RestActivityTable::getLocalization($property['DESCRIPTION'], LANGUAGE_ID), 'FieldName' => static::PROPERTY_NAME_PREFIX.strtolower($name), 'Type' => $property['TYPE'], 'Required' => $property['REQUIRED'], 'Multiple' => $property['MULTIPLE'], 'Default' => $property['DEFAULT'], 'Options' => isset($property['OPTIONS']) ? $property['OPTIONS'] : null ); } $dialog ->setMap($map) ->setRuntimeData(array('ACTIVITY_DATA' => $activityData)) ->setRenderer(array(__CLASS__, 'renderPropertiesDialog')); return $dialog; } public static function renderPropertiesDialog(\Bitrix\Bizproc\Activity\PropertiesDialog $dialog) { $runtime = CBPRuntime::GetRuntime(); $data = $dialog->getRuntimeData(); $activityData = $data['ACTIVITY_DATA']; /** @var CBPDocumentService $documentService */ $documentService = $runtime->GetService("DocumentService"); $activityDocumentType = is_array($activityData['DOCUMENT_TYPE']) ? $activityData['DOCUMENT_TYPE'] : $dialog->getDocumentType(); $properties = isset($activityData['PROPERTIES']) && is_array($activityData['PROPERTIES']) ? $activityData['PROPERTIES'] : array(); $currentValues = $dialog->getCurrentValues(); ob_start(); foreach ($properties as $name => $property): $required = CBPHelper::getBool($property['REQUIRED']); $name = strtolower($name); $value = !CBPHelper::isEmptyValue($currentValues[static::PROPERTY_NAME_PREFIX.$name]) ? $currentValues[static::PROPERTY_NAME_PREFIX.$name] : $property['DEFAULT']; ?> <tr> <td align="right" width="40%" valign="top"> <span class="<?=$required?'adm-required-field':''?>"> <?= htmlspecialcharsbx(RestActivityTable::getLocalization($property['NAME'], LANGUAGE_ID)) ?>: </span> <?if (isset($property['DESCRIPTION'])):?> <br/><?= htmlspecialcharsbx(RestActivityTable::getLocalization($property['DESCRIPTION'], LANGUAGE_ID)) ?> <?endif;?> </td> <td width="60%"> <?=$documentService->getFieldInputControl( $activityDocumentType, $property, array('Field' => static::PROPERTY_NAME_PREFIX.$name, 'Form' => $dialog->getFormName()), $value, true, false )?> </td> </tr> <? endforeach; if (static::checkAdminPermissions()):?> <tr> <td align="right" width="40%" valign="top"><span class=""><?= Loc::getMessage("BPRA_PD_USER_ID") ?>:</span></td> <td width="60%"> <?=$dialog->renderFieldControl('AuthUserId', $currentValues['authuserid'], true, 0)?> </td> </tr> <?endif?> <tr> <td align="right"><?= Loc::getMessage("BPRA_PD_SET_STATUS_MESSAGE") ?>:</td> <td> <select name="setstatusmessage"> <option value="Y"<?= $currentValues["setstatusmessage"] == "Y" ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_YES") ?></option> <option value="N"<?= $currentValues["setstatusmessage"] == "N" ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_NO") ?></option> </select> </td> </tr> <tr> <td align="right"><?= Loc::getMessage("BPRA_PD_STATUS_MESSAGE") ?>:</td> <td valign="top"><?=CBPDocument::ShowParameterField("string", 'statusmessage', $currentValues['statusmessage'], Array('size'=>'45'))?></td> </tr> <tr> <td align="right"><?= Loc::getMessage("BPRA_PD_USE_SUBSCRIPTION") ?>:</td> <td> <select name="usesubscription" <?=!empty($activityData['USE_SUBSCRIPTION'])? 'disabled' : ''?>> <option value="Y"<?= $currentValues["usesubscription"] == 'Y' ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_YES") ?></option> <option value="N"<?= $currentValues["usesubscription"] == 'N' ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_NO") ?></option> </select> </td> </tr> <? if ($activityData['USE_SUBSCRIPTION'] != 'N'):?> <tr> <td align="right"><?= Loc::getMessage("BPRA_PD_TIMEOUT_DURATION") ?>:<br/><?= Loc::getMessage("BPRA_PD_TIMEOUT_DURATION_HINT") ?></td> <td valign="top"> <?=CBPDocument::ShowParameterField('int', 'timeoutduration', $currentValues["timeoutduration"], array('size' => 20))?> <select name="timeoutdurationtype"> <option value="s"<?= ($currentValues["timeoutdurationtype"] == "s") ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_TIME_S") ?></option> <option value="m"<?= ($currentValues["timeoutdurationtype"] == "m") ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_TIME_M") ?></option> <option value="h"<?= ($currentValues["timeoutdurationtype"] == "h") ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_TIME_H") ?></option> <option value="d"<?= ($currentValues["timeoutdurationtype"] == "d") ? " selected" : "" ?>><?= Loc::getMessage("BPRA_PD_TIME_D") ?></option> </select> <? $delayMinLimit = CBPSchedulerService::getDelayMinLimit(); if ($delayMinLimit): ?> <p style="color: red;">* <?= Loc::getMessage("BPRA_PD_TIMEOUT_LIMIT") ?>: <?=CBPHelper::FormatTimePeriod($delayMinLimit)?></p> <? endif; ?> </td> </tr> <?endif; return ob_get_clean(); } public static function GetPropertiesDialogValues($documentType, $activityName, &$workflowTemplate, &$workflowParameters, &$workflowVariables, $currentValues, &$errors) { $runtime = CBPRuntime::GetRuntime(); $errors = array(); $map = array( 'setstatusmessage' => 'SetStatusMessage', 'statusmessage' => 'StatusMessage', 'usesubscription' => 'UseSubscription', 'timeoutduration' => 'TimeoutDuration', 'timeoutdurationtype' => 'TimeoutDurationType' ); $properties = array(); foreach ($map as $key => $value) { $properties[$value] = $currentValues[$key]; } $activityData = self::getRestActivityData(); $activityProperties = isset($activityData['PROPERTIES']) && is_array($activityData['PROPERTIES']) ? $activityData['PROPERTIES'] : array(); /** @var CBPDocumentService $documentService */ $documentService = $runtime->GetService('DocumentService'); $activityDocumentType = is_array($activityData['DOCUMENT_TYPE']) ? $activityData['DOCUMENT_TYPE'] : $documentType; foreach ($activityProperties as $name => $property) { $requestName = static::PROPERTY_NAME_PREFIX.strtolower($name); if (isset($properties[$requestName])) continue; $errors = array(); $properties[$name] = $documentService->GetFieldInputValue( $activityDocumentType, $property, $requestName, $currentValues, $errors ); if (count($errors) > 0) return false; } if (static::checkAdminPermissions()) { $properties['AuthUserId'] = CBPHelper::usersStringToArray($currentValues['authuserid'], $documentType, $errors); if (count($errors) > 0) return false; } else { unset($properties['AuthUserId']); } if (!empty($activityData['USE_SUBSCRIPTION'])) $properties['UseSubscription'] = $activityData['USE_SUBSCRIPTION']; $errors = self::ValidateProperties($properties, new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser)); if (count($errors) > 0) return false; $currentActivity = &CBPWorkflowTemplateLoader::FindActivityByName($workflowTemplate, $activityName); $currentActivity["Properties"] = $properties; return true; } public static function ValidateProperties($testProperties = array(), CBPWorkflowTemplateUser $user = null) { $errors = array(); $activityData = self::getRestActivityData(); if (!$activityData) { $errors[] = array( 'code' => 'NoActivity', 'parameter' => 'ActivityData', 'message' => Loc::getMessage('BPRA_NOT_FOUND_ERROR') ); } $properties = isset($activityData['PROPERTIES']) && is_array($activityData['PROPERTIES']) ? $activityData['PROPERTIES'] : array(); foreach ($properties as $name => $property) { $value = isset($property['DEFAULT']) ? $property['DEFAULT'] : null; if (isset($testProperties[$name])) $value = $testProperties[$name]; if (CBPHelper::getBool($property['REQUIRED']) && CBPHelper::isEmptyValue($value)) { $errors[] = array( 'code' => 'NotExist', 'parameter' => $name, 'message' => Loc::getMessage('BPRA_PD_ERROR_EMPTY_PROPERTY', array( '#NAME#' => RestActivityTable::getLocalization($property['NAME'], LANGUAGE_ID) ) ) ); } } if ( isset($testProperties['AuthUserId']) && isset($activityData['AUTH_USER_ID']) && (string) $testProperties['AuthUserId'] !== $activityData['AUTH_USER_ID'] && !static::checkAdminPermissions() ) { $errors[] = array( 'code' => 'NotExist', 'parameter' => 'AuthUserId', 'message' => Loc::getMessage('BPRA_PD_ERROR_EMPTY_PROPERTY', array( '#NAME#' => Loc::getMessage('BPRA_PD_USER_ID') ) ) ); } return array_merge($errors, parent::ValidateProperties($testProperties, $user)); } private function CalculateTimeoutDuration() { $timeoutDuration = ($this->IsPropertyExists('TimeoutDuration') ? $this->TimeoutDuration : 0); $timeoutDurationType = ($this->IsPropertyExists('TimeoutDurationType') ? $this->TimeoutDurationType : "s"); $timeoutDurationType = strtolower($timeoutDurationType); if (!in_array($timeoutDurationType, array('s', 'd', 'h', 'm'))) $timeoutDurationType = 's'; $timeoutDuration = intval($timeoutDuration); switch ($timeoutDurationType) { case 'd': $timeoutDuration *= 3600 * 24; break; case 'h': $timeoutDuration *= 3600; break; case 'm': $timeoutDuration *= 60; break; default: break; } return $timeoutDuration; } private static function checkAdminPermissions() { $user = new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser); return $user->isAdmin(); } public static function generateToken($workflowId, $activityName, $eventId) { $signer = new \Bitrix\Main\Security\Sign\Signer; return $signer->sign($workflowId.'|'.$activityName.'|'.$eventId, self::TOKEN_SALT); } public static function extractToken($token) { $signer = new \Bitrix\Main\Security\Sign\Signer; try { $unsigned = $signer->unsign($token, self::TOKEN_SALT); $result = explode('|', $unsigned); } catch (\Exception $e) { $result = false; } return $result; } }