14Loader::includeModule(
'rest');
22 private static $allowedOperations = [
'',
'!',
'<',
'<=',
'>',
'>='];
40 private const ALLOWED_TASK_ACTIVITIES = [
43 'RequestInformationActivity',
44 'RequestInformationOptionalActivity'
51 if (\CBPRuntime::isFeatureEnabled())
55 'bizproc.activity.add' => [__CLASS__,
'addActivity'],
56 'bizproc.activity.update' => [__CLASS__,
'updateActivity'],
57 'bizproc.activity.delete' => [__CLASS__,
'deleteActivity'],
58 'bizproc.activity.log' => [__CLASS__,
'writeActivityLog'],
59 'bizproc.activity.list' => [__CLASS__,
'getActivityList'],
62 'bizproc.event.send' => [__CLASS__,
'sendEvent'],
65 'bizproc.task.list' => [__CLASS__,
'getTaskList'],
66 'bizproc.task.complete' => [__CLASS__,
'completeTask'],
69 'bizproc.workflow.terminate' => [__CLASS__,
'terminateWorkflow'],
70 'bizproc.workflow.kill' => [__CLASS__,
'killWorkflow'],
71 'bizproc.workflow.start' => [__CLASS__,
'startWorkflow'],
74 'bizproc.workflow.instance.list' => [__CLASS__,
'getWorkflowInstances'],
77 'bizproc.workflow.template.list' => [__CLASS__,
'getWorkflowTemplates'],
78 'bizproc.workflow.template.add' => [__CLASS__,
'addWorkflowTemplate'],
79 'bizproc.workflow.template.update' => [__CLASS__,
'updateWorkflowTemplate'],
80 'bizproc.workflow.template.delete' => [__CLASS__,
'deleteWorkflowTemplate'],
83 'bizproc.workflow.instances' => [__CLASS__,
'getWorkflowInstances'],
88 \CBPRuntime::isFeatureEnabled()
89 || \CBPRuntime::isFeatureEnabled(
'crm_automation_lead')
90 || \CBPRuntime::isFeatureEnabled(
'crm_automation_deal')
91 || \CBPRuntime::isFeatureEnabled(
'crm_automation_order')
92 || \CBPRuntime::isFeatureEnabled(
'tasks_automation')
95 $map = array_merge($map, array(
96 'bizproc.event.send' => [__CLASS__,
'sendEvent'],
97 'bizproc.activity.log' => [__CLASS__,
'writeActivityLog'],
100 'bizproc.robot.add' => array(__CLASS__,
'addRobot'),
101 'bizproc.robot.update' => array(__CLASS__,
'updateRobot'),
102 'bizproc.robot.delete' => array(__CLASS__,
'deleteRobot'),
103 'bizproc.robot.list' => array(__CLASS__,
'getRobotList'),
106 'bizproc.provider.add' => [__CLASS__,
'addProvider'],
107 'bizproc.provider.delete' => [__CLASS__,
'deleteProvider'],
108 'bizproc.provider.list' => [__CLASS__,
'getProviderList'],
113 $map[\CRestUtil::PLACEMENTS] = [
114 static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG => [
'private' =>
true],
118 static::SCOPE => $map,
129 $fields = array_change_key_case($fields, CASE_UPPER);
130 if (empty($fields[
'APP_ID']))
133 if (!Loader::includeModule(
'rest'))
136 $dbRes = AppTable::getById($fields[
'APP_ID']);
137 $app = $dbRes->fetch();
142 $iterator = RestActivityTable::getList(array(
143 'select' => array(
'ID'),
144 'filter' => array(
'=APP_ID' =>
$app[
'CLIENT_ID'])
147 while ($activity = $iterator->fetch())
149 RestActivityTable::delete($activity[
'ID']);
152 $iterator = RestProviderTable::getList(array(
153 'select' => array(
'ID'),
154 'filter' => array(
'=APP_ID' =>
$app[
'CLIENT_ID'])
157 while ($activity = $iterator->fetch())
159 RestProviderTable::delete($activity[
'ID']);
162 self::deleteAppPlacement(
$app[
'ID']);
172 static::onRestAppDelete($fields);
184 return self::addActivityInternal($params, $server,
false);
194 public static function addRobot($params, $n, $server)
196 return self::addActivityInternal($params, $server,
true);
207 private static function addActivityInternal($params, $server, $isRobot =
false)
209 if(!$server->getClientId())
214 self::checkAdminPermissions();
215 $params = self::prepareActivityData($params);
218 self::validateRobot($params, $server);
220 self::validateActivity($params, $server);
222 $appId = self::getAppId($server->getClientId());
223 $params[
'APP_ID'] = $server->getClientId();
224 $params[
'INTERNAL_CODE'] = self::generateInternalCode($params);
225 $params[
'APP_NAME'] = self::getAppName($params[
'APP_ID']);
227 $iterator = RestActivityTable::getList(array(
228 'select' => array(
'ID'),
229 'filter' => array(
'=INTERNAL_CODE' => $params[
'INTERNAL_CODE'])
231 $result = $iterator->fetch();
234 throw new RestException(
'Activity or Robot already installed!', self::ERROR_ACTIVITY_ALREADY_INSTALLED);
237 $params[
'AUTH_USER_ID'] = isset($params[
'AUTH_USER_ID'])? (int) $params[
'AUTH_USER_ID'] : 0;
238 $params[
'IS_ROBOT'] = $isRobot ?
'Y' :
'N';
239 $params[
'USE_PLACEMENT'] = (isset($params[
'USE_PLACEMENT']) && $params[
'USE_PLACEMENT'] ===
'Y') ?
'Y' :
'N';
241 if ($params[
'USE_PLACEMENT'] ===
'Y')
243 self::validateActivityHandler($params[
'PLACEMENT_HANDLER'] ??
null, $server);
244 self::upsertAppPlacement($appId, $params[
'CODE'], $params[
'PLACEMENT_HANDLER'] ??
null);
247 $result = RestActivityTable::add($params);
249 if ($result->getErrors())
251 if ($params[
'USE_PLACEMENT'] ===
'Y')
253 self::deleteAppPlacement($appId, $params[
'CODE']);
256 throw new RestException(
'Activity save error!', self::ERROR_ACTIVITY_ADD_FAILURE);
271 return self::updateActivityInternal($params, $server,
false);
283 return self::deleteActivityInternal($params, $server,
false);
295 return self::updateActivityInternal($params, $server,
true);
307 return self::deleteActivityInternal($params, $server,
true);
318 private static function deleteActivityInternal($params, $server, $isRobot =
false)
320 if(!$server->getClientId())
325 $params = array_change_key_case($params, CASE_UPPER);
326 self::checkAdminPermissions();
327 self::validateActivityCode($params[
'CODE']);
328 $params[
'APP_ID'] = $server->getClientId();
329 $internalCode = self::generateInternalCode($params);
331 $iterator = RestActivityTable::getList(array(
332 'select' => array(
'ID'),
334 '=INTERNAL_CODE' => $internalCode,
335 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
338 $result = $iterator->fetch();
341 throw new RestException(
'Activity or Robot not found!', self::ERROR_ACTIVITY_NOT_FOUND);
343 RestActivityTable::delete($result[
'ID']);
344 self::deleteAppPlacement(self::getAppId($params[
'APP_ID']), $params[
'CODE']);
360 private static function updateActivityInternal($params, $server, $isRobot =
false)
362 if(!$server->getClientId())
364 throw new AccessException(
"Application context required");
367 $params = self::prepareActivityData($params);
368 self::checkAdminPermissions();
369 self::validateActivityCode($params[
'CODE']);
370 $params[
'APP_ID'] = $server->getClientId();
371 $internalCode = self::generateInternalCode($params);
373 $iterator = RestActivityTable::getList(array(
374 'select' => array(
'ID'),
376 '=INTERNAL_CODE' => $internalCode,
377 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
380 $result = $iterator->fetch();
383 throw new RestException(
'Activity or Robot not found!', self::ERROR_ACTIVITY_NOT_FOUND);
386 $fields = (isset($params[
'FIELDS']) && is_array($params[
'FIELDS'])) ? $params[
'FIELDS'] :
null;
390 throw new RestException(
'No fields to update', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
395 if (isset($fields[
'HANDLER']))
397 self::validateActivityHandler($fields[
'HANDLER'], $server);
398 $toUpdate[
'HANDLER'] = $fields[
'HANDLER'];
401 if (isset($fields[
'AUTH_USER_ID']))
403 $toUpdate[
'AUTH_USER_ID'] = (int) $fields[
'AUTH_USER_ID'];
406 if (isset($fields[
'USE_SUBSCRIPTION']))
408 $toUpdate[
'USE_SUBSCRIPTION'] = (string) $fields[
'USE_SUBSCRIPTION'];
411 if (isset($fields[
'USE_PLACEMENT']))
413 $toUpdate[
'USE_PLACEMENT'] = ($fields[
'USE_PLACEMENT'] ===
'Y') ?
'Y' :
'N';
416 if (!empty($fields[
'NAME']))
418 $toUpdate[
'NAME'] = $fields[
'NAME'];
421 if (isset($fields[
'DESCRIPTION']))
423 $toUpdate[
'DESCRIPTION'] = $fields[
'DESCRIPTION'];
426 if (isset($fields[
'PROPERTIES']))
428 self::validateActivityProperties($fields[
'PROPERTIES']);
429 $toUpdate[
'PROPERTIES'] = $fields[
'PROPERTIES'];
432 if (isset($fields[
'RETURN_PROPERTIES']))
434 self::validateActivityProperties($fields[
'RETURN_PROPERTIES']);
435 $toUpdate[
'RETURN_PROPERTIES'] = $fields[
'RETURN_PROPERTIES'];
438 if (isset($fields[
'DOCUMENT_TYPE']))
440 if (empty($fields[
'DOCUMENT_TYPE']))
442 $toUpdate[
'DOCUMENT_TYPE'] =
null;
446 static::validateActivityDocumentType($fields[
'DOCUMENT_TYPE']);
447 $toUpdate[
'DOCUMENT_TYPE'] = $fields[
'DOCUMENT_TYPE'];
451 if (isset($fields[
'FILTER']))
453 if (empty($fields[
'FILTER']))
455 $toUpdate[
'FILTER'] =
null;
459 if (!is_array($fields[
'FILTER']))
461 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
463 $toUpdate[
'FILTER'] = $fields[
'FILTER'];
469 throw new RestException(
'No fields to update', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
472 if (isset($fields[
'PLACEMENT_HANDLER']))
474 self::validateActivityHandler($fields[
'PLACEMENT_HANDLER'], $server);
475 self::upsertAppPlacement(self::getAppId($params[
'APP_ID']), $params[
'CODE'], $fields[
'PLACEMENT_HANDLER']);
478 if (isset($toUpdate[
'USE_PLACEMENT']) && $toUpdate[
'USE_PLACEMENT'] ===
'N')
480 self::deleteAppPlacement(self::getAppId($params[
'APP_ID']), $params[
'CODE']);
483 RestActivityTable::update($result[
'ID'], $toUpdate);
498 $params = array_change_key_case($params, CASE_UPPER);
499 [$workflowId, $activityName, $eventId] = self::extractEventToken($params[
'EVENT_TOKEN']);
501 \CBPRuntime::sendExternalEvent(
505 'EVENT_ID' => $eventId,
506 'RETURN_VALUES' => isset($params[
'RETURN_VALUES']) ? $params[
'RETURN_VALUES'] : array(),
507 'LOG_MESSAGE' => isset($params[
'LOG_MESSAGE']) ? $params[
'LOG_MESSAGE'] :
'',
524 $params = array_change_key_case($params, CASE_UPPER);
525 [$workflowId, $activityName, $eventId] = self::extractEventToken($params[
'EVENT_TOKEN']);
527 $logMessage = isset($params[
'LOG_MESSAGE']) ? $params[
'LOG_MESSAGE'] :
'';
529 if (empty($logMessage))
530 throw new RestException(
'Empty log message!', self::ERROR_EMPTY_LOG_MESSAGE);
532 \CBPRuntime::sendExternalEvent(
536 'EVENT_ID' => $eventId,
537 'LOG_ACTION' =>
true,
538 'LOG_MESSAGE' => $logMessage
555 return self::getActivityListInternal($params, $server,
false);
568 return self::getActivityListInternal($params, $server,
true);
578 private static function getActivityListInternal($params, $server, $isRobot =
false)
580 if(!$server->getClientId())
585 self::checkAdminPermissions();
586 $iterator = RestActivityTable::getList(array(
587 'select' => array(
'CODE'),
589 '=APP_ID' => $server->getClientId(),
590 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
595 while ($row = $iterator->fetch())
597 $result[] = $row[
'CODE'];
613 self::checkAdminPermissions();
614 $params = array_change_key_case($params, CASE_UPPER);
618 'MODIFIED' =>
'MODIFIED',
619 'OWNED_UNTIL' =>
'OWNED_UNTIL',
620 'MODULE_ID' =>
'MODULE_ID',
621 'ENTITY' =>
'ENTITY',
622 'DOCUMENT_ID' =>
'DOCUMENT_ID',
623 'STARTED' =>
'STARTED',
624 'STARTED_BY' =>
'STARTED_BY',
625 'TEMPLATE_ID' =>
'WORKFLOW_TEMPLATE_ID',
628 $select = static::getSelect($params[
'SELECT'], $fields, array(
'ID',
'MODIFIED',
'OWNED_UNTIL'));
629 $filter = static::getFilter($params[
'FILTER'], $fields, array(
'MODIFIED',
'OWNED_UNTIL'));
630 $order = static::getOrder($params[
'ORDER'], $fields, array(
'MODIFIED' =>
'DESC'));
632 $iterator = WorkflowInstanceTable::getList(array(
636 'limit' => static::LIST_LIMIT,
637 'offset' => (
int) $n,
638 'count_total' =>
true,
642 while ($row = $iterator->fetch())
644 if (isset($row[
'MODIFIED']))
645 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
646 if (isset($row[
'STARTED']))
647 $row[
'STARTED'] = \CRestUtil::convertDateTime($row[
'STARTED']);
648 if (isset($row[
'OWNED_UNTIL']))
649 $row[
'OWNED_UNTIL'] = \CRestUtil::convertDateTime($row[
'OWNED_UNTIL']);
653 return static::setNavData($result, [
'count' => $iterator->getCount(),
'offset' => $n]);
666 self::checkAdminPermissions();
667 $params = array_change_key_case($params, CASE_UPPER);
669 if (empty($params[
'ID']))
671 throw new RestException(
'Empty workflow instance ID', self::ERROR_WRONG_WORKFLOW_ID);
675 $status = isset($params[
'STATUS']) ? (string)$params[
'STATUS'] :
'';
678 if (!\CBPDocument::terminateWorkflow($id, [], $errors, $status))
696 self::checkAdminPermissions();
697 $params = array_change_key_case($params, CASE_UPPER);
699 if (empty($params[
'ID']))
701 throw new RestException(
'Empty workflow instance ID', self::ERROR_WRONG_WORKFLOW_ID);
705 $errors = \CBPDocument::killWorkflow($id);
725 $params = array_change_key_case($params, CASE_UPPER);
727 if (empty($params[
'TEMPLATE_ID']))
729 throw new RestException(
'Empty TEMPLATE_ID', self::ERROR_WRONG_WORKFLOW_ID);
731 $templateId = (int)$params[
'TEMPLATE_ID'];
732 $tplDocumentType = self::getTemplateDocumentType($templateId);
734 if (!$tplDocumentType)
736 throw new RestException(
'Template not found', self::ERROR_WRONG_WORKFLOW_ID);
740 $getParams = array_change_key_case($_GET, CASE_UPPER);
741 if (isset($getParams[
'DOCUMENT_ID']) && is_array($getParams[
'DOCUMENT_ID']))
743 $params[
'DOCUMENT_ID'] = $getParams[
'DOCUMENT_ID'];
746 $documentId = self::getDocumentId($params[
'DOCUMENT_ID']);
753 $documentType = self::getDocumentType($documentId);
759 if (!self::isEqualDocumentType($tplDocumentType, $documentType))
761 throw new RestException(
'Template type and DOCUMENT_ID mismatch!');
764 self::checkStartWorkflowPermissions($documentId, $templateId);
766 $workflowParameters = isset($params[
'PARAMETERS']) && is_array($params[
'PARAMETERS']) ? $params[
'PARAMETERS'] : [];
768 $workflowParameters[\CBPDocument::PARAM_TAGRET_USER] = self::getCurrentUserId();
771 $workflowId = \CBPDocument::startWorkflow($templateId, $documentId, $workflowParameters, $errors);
781 private static function checkStartWorkflowPermissions(array $documentId, $templateId)
783 if (static::isAdmin())
789 \CBPDocument::CanUserOperateDocument(
790 \CBPCanUserOperateOperation::StartWorkflow,
791 static::getCurrentUserId(),
793 [
'WorkflowTemplateId' => $templateId]
800 throw new AccessException();
815 self::checkAdminPermissions();
816 $params = array_change_key_case($params, CASE_UPPER);
820 'MODULE_ID' =>
'MODULE_ID',
821 'ENTITY' =>
'ENTITY',
822 'DOCUMENT_TYPE' =>
'DOCUMENT_TYPE',
823 'AUTO_EXECUTE' =>
'AUTO_EXECUTE',
825 'DESCRIPTION' =>
'DESCRIPTION',
826 'TEMPLATE' =>
'TEMPLATE',
827 'PARAMETERS' =>
'PARAMETERS',
828 'VARIABLES' =>
'VARIABLES',
829 'CONSTANTS' =>
'CONSTANTS',
830 'MODIFIED' =>
'MODIFIED',
831 'IS_MODIFIED' =>
'IS_MODIFIED',
832 'USER_ID' =>
'USER_ID',
833 'SYSTEM_CODE' =>
'SYSTEM_CODE',
836 $select = static::getSelect($params[
'SELECT'], $fields, array(
'ID'));
837 $filter = static::getFilter($params[
'FILTER'], $fields, array(
'MODIFIED'));
838 $filter[
'<AUTO_EXECUTE'] = \CBPDocumentEventType::Automation;
840 $order = static::getOrder($params[
'ORDER'], $fields, array(
'ID' =>
'ASC'));
842 $iterator = WorkflowTemplateTable::getList(array(
846 'limit' => static::LIST_LIMIT,
847 'offset' => (
int) $n,
848 'count_total' =>
true,
851 $countTotal = $iterator->getCount();
853 $iterator = new \CBPWorkflowTemplateResult($iterator, \CBPWorkflowTemplateLoader::useGZipCompression());
856 while ($row = $iterator->fetch())
858 if (isset($row[
'MODIFIED']))
859 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
860 if (isset($row[
'STARTED']))
861 $row[
'STARTED'] = \CRestUtil::convertDateTime($row[
'STARTED']);
862 if (isset($row[
'OWNED_UNTIL']))
863 $row[
'OWNED_UNTIL'] = \CRestUtil::convertDateTime($row[
'OWNED_UNTIL']);
867 return static::setNavData($result, [
'count' => $countTotal,
'offset' => $n]);
879 if(!$server->getClientId())
884 self::checkAdminPermissions();
885 $params = array_change_key_case($params, CASE_UPPER);
887 self::validateTemplateDocumentType($params[
'DOCUMENT_TYPE']);
888 self::validateTemplateName($params[
'NAME']);
890 $autoExecute = \CBPDocumentEventType::None;
891 if (isset($params[
'AUTO_EXECUTE']))
893 self::validateTemplateAutoExecution($params[
'AUTO_EXECUTE']);
894 $autoExecute = (int) $params[
'AUTO_EXECUTE'];
897 $data = self::prepareTemplateData($params[
'TEMPLATE_DATA']);
899 return \CBPWorkflowTemplateLoader::ImportTemplate(
901 $params[
'DOCUMENT_TYPE'],
904 isset($params[
'DESCRIPTION']) ? (
string) $params[
'DESCRIPTION'] :
'',
906 self::generateTemplateSystemCode($server)
919 if(!$server->getClientId())
924 self::checkAdminPermissions();
925 $params = array_change_key_case($params, CASE_UPPER);
927 $fields = (isset($params[
'FIELDS']) && is_array($params[
'FIELDS'])) ? $params[
'FIELDS'] :
null;
934 $tpl = WorkflowTemplateTable::getList(array(
935 'select' => [
'ID',
'SYSTEM_CODE',
'NAME',
'DESCRIPTION',
'AUTO_EXECUTE',
'MODULE_ID',
'ENTITY',
'DOCUMENT_TYPE'],
936 'filter' => [
'=ID' => (
int) $params[
'ID']],
944 if ($tpl[
'SYSTEM_CODE'] !== self::generateTemplateSystemCode($server))
946 throw new RestException(
"You can update ONLY templates created by current application");
949 if (isset($fields[
'NAME']))
951 self::validateTemplateName($fields[
'NAME']);
952 $tpl[
'NAME'] = $fields[
'NAME'];
955 if (isset($fields[
'DESCRIPTION']))
957 $tpl[
'DESCRIPTION'] = (string) $fields[
'DESCRIPTION'];
960 if (isset($fields[
'AUTO_EXECUTE']))
962 self::validateTemplateAutoExecution($fields[
'AUTO_EXECUTE']);
963 $tpl[
'AUTO_EXECUTE'] = (int) $fields[
'AUTO_EXECUTE'];
966 if (isset($fields[
'TEMPLATE_DATA']))
968 $data = self::prepareTemplateData($fields[
'TEMPLATE_DATA']);
970 return \CBPWorkflowTemplateLoader::ImportTemplate(
972 [$tpl[
'MODULE_ID'], $tpl[
'ENTITY'], $tpl[
'DOCUMENT_TYPE']],
973 $tpl[
'AUTO_EXECUTE'],
982 return \CBPWorkflowTemplateLoader::Update($tpl[
'ID'], [
983 'NAME' => $tpl[
'NAME'],
984 'DESCRIPTION' => $tpl[
'DESCRIPTION'],
985 'AUTO_EXECUTE' => $tpl[
'AUTO_EXECUTE'],
999 if(!$server->getClientId())
1004 self::checkAdminPermissions();
1005 $params = array_change_key_case($params, CASE_UPPER);
1007 $tpl = WorkflowTemplateTable::getList(array(
1008 'select' => [
'ID',
'SYSTEM_CODE'],
1009 'filter' => [
'=ID' => (
int) $params[
'ID']],
1017 if ($tpl[
'SYSTEM_CODE'] !== self::generateTemplateSystemCode($server))
1019 throw new RestException(
"You can delete ONLY templates created by current application");
1022 \CBPWorkflowTemplateLoader::Delete($tpl[
'ID']);
1034 $params = array_change_key_case($params, CASE_UPPER);
1038 'ACTIVITY' =>
'ACTIVITY',
1039 'ACTIVITY_NAME' =>
'ACTIVITY_NAME',
1040 'WORKFLOW_ID' =>
'WORKFLOW_ID',
1041 'DOCUMENT_NAME' =>
'DOCUMENT_NAME',
1042 'DESCRIPTION' =>
'DESCRIPTION',
1044 'MODIFIED' =>
'MODIFIED',
1045 'WORKFLOW_STARTED' =>
'WORKFLOW_STARTED',
1046 'WORKFLOW_STARTED_BY' =>
'WORKFLOW_STARTED_BY',
1047 'OVERDUE_DATE' =>
'OVERDUE_DATE',
1048 'WORKFLOW_TEMPLATE_ID' =>
'WORKFLOW_TEMPLATE_ID',
1049 'WORKFLOW_TEMPLATE_NAME' =>
'WORKFLOW_TEMPLATE_NAME',
1050 'WORKFLOW_STATE' =>
'WORKFLOW_STATE',
1051 'STATUS' =>
'STATUS',
1052 'USER_ID' =>
'USER_ID',
1053 'USER_STATUS' =>
'USER_STATUS',
1054 'MODULE_ID' =>
'MODULE_ID',
1055 'ENTITY' =>
'ENTITY',
1056 'DOCUMENT_ID' =>
'DOCUMENT_ID',
1057 'PARAMETERS' =>
'PARAMETERS',
1060 $select = static::getSelect($params[
'SELECT'], $fields, array(
'ID',
'WORKFLOW_ID',
'DOCUMENT_NAME',
'NAME'));
1061 $select = array_merge(array(
'MODULE',
'ENTITY',
'DOCUMENT_ID'), $select);
1062 $filter = static::getFilter($params[
'FILTER'], $fields, array(
'MODIFIED',
'WORKFLOW_STARTED',
'OVERDUE_DATE'));
1063 $order = static::getOrder($params[
'ORDER'], $fields, array(
'ID' =>
'DESC'));
1065 $currentUserId = self::getCurrentUserId();
1066 $isAdmin = static::isAdmin();
1068 if (!$isAdmin && !isset($filter[
'USER_ID']))
1070 $filter[
'USER_ID'] = $currentUserId;
1073 $targetUserId = isset($filter[
'USER_ID'])? (int)$filter[
'USER_ID'] : 0;
1074 if ($targetUserId !== $currentUserId && !\CBPHelper::checkUserSubordination($currentUserId, $targetUserId))
1076 self::checkAdminPermissions();
1079 $iterator = \CBPTaskService::getList(
1083 static::getNavData($n),
1088 while ($row = $iterator->fetch())
1090 if (isset($row[
'MODIFIED']))
1091 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
1092 if (isset($row[
'WORKFLOW_STARTED']))
1093 $row[
'WORKFLOW_STARTED'] = \CRestUtil::convertDateTime($row[
'WORKFLOW_STARTED']);
1094 if (isset($row[
'OVERDUE_DATE']))
1095 $row[
'OVERDUE_DATE'] = \CRestUtil::convertDateTime($row[
'OVERDUE_DATE']);
1096 $row[
'DOCUMENT_URL'] = \CBPDocument::getDocumentAdminPage(array(
1097 $row[
'MODULE_ID'], $row[
'ENTITY'], $row[
'DOCUMENT_ID']
1100 if (isset($row[
'PARAMETERS']))
1102 $row[
'PARAMETERS'] = static::prepareTaskParameters($row[
'PARAMETERS'], $row);
1108 return static::setNavData($result, $iterator);
1111 private static function prepareTaskParameters(array $parameters, array $task)
1114 [
'CommentLabelMessage',
'CommentLabel'],
1115 'CommentRequired',
'ShowComment',
1116 [
'TaskButtonMessage',
'StatusOkLabel'],
1117 [
'TaskButton1Message',
'StatusYesLabel'],
1118 [
'TaskButton2Message',
'StatusNoLabel'],
1119 [
'TaskButtonCancelMessage',
'StatusCancelLabel'],
1120 [
'REQUEST',
'Fields'],
1125 foreach ($whiteList as $whiteKey)
1127 $filterKey = $whiteKey;
1128 if (is_array($whiteKey))
1130 $filterKey = $whiteKey[1];
1131 $whiteKey = $whiteKey[0];
1133 if (isset($parameters[$whiteKey]))
1135 $filtered[$filterKey] = $parameters[$whiteKey];
1139 if (isset($filtered[
'Fields']))
1141 $filtered[
'Fields'] = self::externalizeRequestFields($task, $filtered[
'Fields']);
1147 private static function externalizeRequestFields($task, array $fields): array
1149 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
1151 foreach ($fields as $requestField)
1153 $id = $requestField[
'Name'];
1154 $requestField[
'Name'] = $requestField[
'Title'];
1156 $property[
'Id'] = $id;
1158 $fieldTypeObject = $documentService->getFieldTypeObject($task[
"PARAMETERS"][
"DOCUMENT_TYPE"], $property);
1159 if ($fieldTypeObject)
1161 $fieldTypeObject->setDocumentId($task[
"PARAMETERS"][
"DOCUMENT_ID"]);
1162 $property[
'Default'] = $fieldTypeObject->externalizeValue(
'rest', $property[
'Default']);
1165 $result[] = $property;
1170 private static function internalizeRequestFields($task, array $values): array
1172 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
1175 foreach ($task[
'PARAMETERS'][
'REQUEST'] as $property)
1177 if (!isset($values[$property[
'Name']]))
1183 $fieldTypeObject = $documentService->getFieldTypeObject($task[
"PARAMETERS"][
"DOCUMENT_TYPE"], $property);
1184 if ($fieldTypeObject)
1186 $fieldTypeObject->setDocumentId($task[
"PARAMETERS"][
"DOCUMENT_ID"]);
1187 $result[$property[
'Name']] = $fieldTypeObject->internalizeValue(
'rest', $values[$property[
'Name']]);
1202 $params = array_change_key_case($params, CASE_UPPER);
1203 self::validateTaskParameters($params);
1205 $userId = self::getCurrentUserId();
1206 $task = static::getTask($params[
'TASK_ID'], $userId);
1208 if (!in_array($task[
'ACTIVITY'], self::ALLOWED_TASK_ACTIVITIES))
1210 throw new RestException(
'Incorrect task type', self::ERROR_TASK_TYPE);
1213 if (!empty($params[
'FIELDS']))
1215 $params[
'FIELDS'] = self::internalizeRequestFields($task, $params[
'FIELDS']);
1220 'INLINE_USER_STATUS' => \CBPTaskUserStatus::resolveStatus($params[
'STATUS']),
1221 'task_comment' => !empty($params[
'COMMENT']) && is_string($params[
'COMMENT']) ? $params[
'COMMENT'] :
null,
1222 'fields' => $params[
'FIELDS'] ??
null,
1225 if (!\CBPDocument::postTaskForm($task, $userId, $request, $errors))
1227 throw new RestException($errors[0][
"message"], self::ERROR_TASK_EXECUTION);
1233 private static function validateTaskParameters(array $params)
1235 if (empty($params[
'TASK_ID']))
1237 throw new RestException(
'empty TASK_ID', self::ERROR_TASK_VALIDATION);
1239 if (empty($params[
'STATUS']) || \CBPTaskUserStatus::resolveStatus($params[
'STATUS']) ===
null)
1241 throw new RestException(
'incorrect STATUS', self::ERROR_TASK_VALIDATION);
1245 private static function getTask($id, $userId)
1247 $dbTask = \CBPTaskService::getList(
1249 array(
"ID" => (
int)$id,
"USER_ID" => $userId),
1252 array(
"ID",
"WORKFLOW_ID",
"ACTIVITY",
"ACTIVITY_NAME",
"MODIFIED",
"OVERDUE_DATE",
"NAME",
"DESCRIPTION",
"PARAMETERS",
"USER_STATUS")
1254 $task = $dbTask->fetch();
1258 throw new RestException(
'Task not found', self::ERROR_TASK_NOT_FOUND);
1260 elseif ((
int)$task[
'USER_STATUS'] !== \CBPTaskUserStatus::Waiting)
1262 throw new RestException(
'Task already completed', self::ERROR_TASK_COMPLETED);
1267 $task[
"PARAMETERS"][
"DOCUMENT_ID"] = \CBPStateService::getStateDocumentId($task[
'WORKFLOW_ID']);
1268 $task[
"MODULE_ID"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][0];
1269 $task[
"ENTITY"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][1];
1270 $task[
"DOCUMENT_ID"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][2];
1285 if (Loader::includeModule(
'messageservice'))
1287 return \Bitrix\MessageService\RestService::addSender($params, $n, $server);
1290 if(!$server->getClientId())
1295 self::checkAdminPermissions();
1296 $params = self::prepareActivityData($params);
1298 self::validateProvider($params, $server);
1300 $params[
'APP_ID'] = $server->getClientId();
1301 $params[
'APP_NAME'] = self::getAppName($params[
'APP_ID']);
1303 $iterator = RestProviderTable::getList(array(
1304 'select' => array(
'ID'),
1306 '=APP_ID' => $params[
'APP_ID'],
1307 '=CODE' => $params[
'CODE']
1310 $result = $iterator->fetch();
1313 throw new RestException(
'Provider already installed!', self::ERROR_ACTIVITY_ALREADY_INSTALLED);
1316 $result = RestProviderTable::add($params);
1318 if ($result->getErrors())
1319 throw new RestException(
'Activity save error!', self::ERROR_ACTIVITY_ADD_FAILURE);
1333 if (Loader::includeModule(
'messageservice'))
1335 return \Bitrix\MessageService\RestService::deleteSender($params, $n, $server);
1338 if(!$server->getClientId())
1343 $params = array_change_key_case($params, CASE_UPPER);
1344 self::checkAdminPermissions();
1345 self::validateActivityCode($params[
'CODE']);
1346 $params[
'APP_ID'] = $server->getClientId();
1348 $iterator = RestProviderTable::getList(array(
1349 'select' => array(
'ID'),
1351 '=APP_ID' => $params[
'APP_ID'],
1352 '=CODE' => $params[
'CODE']
1355 $result = $iterator->fetch();
1358 throw new RestException(
'Provider not found!', self::ERROR_ACTIVITY_NOT_FOUND);
1360 RestProviderTable::delete($result[
'ID']);
1375 if (Loader::includeModule(
'messageservice'))
1377 return \Bitrix\MessageService\RestService::getSenderList($params, $n, $server);
1380 if(!$server->getClientId())
1385 self::checkAdminPermissions();
1386 $iterator = RestProviderTable::getList(array(
1387 'select' => array(
'CODE'),
1389 '=APP_ID' => $server->getClientId()
1394 while ($row = $iterator->fetch())
1396 $result[] = $row[
'CODE'];
1401 private static function getSelect($rules, $fields, $default = array())
1404 if (!empty($rules) && is_array($rules))
1406 foreach ($rules as $field)
1408 $field = mb_strtoupper($field);
1409 if (isset($fields[$field]) && !in_array($field, $select))
1410 $select[$field] = $fields[$field];
1414 return $select ? $select : $default;
1417 private static function getOrder($rules, $fields, array $default = array())
1420 if (!empty($rules) && is_array($rules))
1422 foreach ($rules as $field => $ordering)
1424 $field = mb_strtoupper($field);
1425 $ordering = mb_strtoupper($ordering);
1426 if (isset($fields[$field]))
1427 $order[$fields[$field]] = $ordering ==
'DESC' ?
'DESC' :
'ASC';
1431 return $order ? $order : $default;
1434 private static function getFilter($rules, $fields, array $datetimeFieldsList = array())
1437 if (!empty($rules) && is_array($rules))
1439 foreach ($rules as $key => $value)
1441 if (preg_match(
'/^([^a-zA-Z]*)(.*)/', $key, $matches))
1443 $operation = $matches[1];
1444 $field = $matches[2];
1446 if (in_array($operation, static::$allowedOperations,
true) && isset($fields[$field]))
1448 if (in_array($field, $datetimeFieldsList))
1449 $value = \CRestUtil::unConvertDateTime($value);
1451 $filter[$operation.$fields[$field]] = $value;
1460 private static function checkAdminPermissions()
1462 if (!static::isAdmin())
1464 throw new AccessException();
1468 private static function isAdmin()
1476 || Loader::includeModule(
'bitrix24') && \CBitrix24::isPortalAdmin($USER->getID())
1481 private static function getCurrentUserId()
1484 return (isset($USER) && is_object($USER)) ? (int)$USER->getID() : 0;
1487 private static function generateInternalCode($data)
1489 return md5($data[
'APP_ID'].
'@'.$data[
'CODE']);
1492 private static function getAppName($appId)
1494 if (!Loader::includeModule(
'rest'))
1495 return array(
'*' =>
'No app');
1497 $iterator = AppTable::getList(
1500 '=CLIENT_ID' => $appId
1502 'select' => array(
'ID',
'APP_NAME',
'CODE'),
1505 $app = $iterator->fetch();
1506 $result = array(
'*' =>
$app[
'APP_NAME'] ?
$app[
'APP_NAME'] :
$app[
'CODE']);
1508 $iterator = AppLangTable::getList(array(
1510 '=APP_ID' =>
$app[
'ID'],
1512 'select' => array(
'LANGUAGE_ID',
'MENU_NAME')
1514 while($lang = $iterator->fetch())
1516 $result[mb_strtoupper($lang[
'LANGUAGE_ID'])] = $lang[
'MENU_NAME'];
1522 private static function getAppId($clientId)
1524 if (!Loader::includeModule(
'rest'))
1529 $iterator = AppTable::getList(
1532 '=CLIENT_ID' => $clientId
1534 'select' => array(
'ID'),
1537 $app = $iterator->fetch();
1539 return (
int)
$app[
'ID'];
1542 private static function prepareActivityData(array $data, $ignore =
false)
1545 $data = array_change_key_case($data, CASE_UPPER);
1546 foreach ($data as $key => &$field)
1548 if (is_array($field))
1549 $field = self::prepareActivityData($field, $key ==
'PROPERTIES' || $key ==
'RETURN_PROPERTIES' || $key ==
'OPTIONS');
1554 private static function validateActivity($data, $server)
1556 if (!is_array($data) || empty($data))
1557 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1559 static::validateActivityCode($data[
'CODE']);
1560 static::validateActivityHandler($data[
'HANDLER'], $server);
1561 if (empty($data[
'NAME']))
1562 throw new RestException(
'Empty activity NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1564 if (isset($data[
'PROPERTIES']))
1565 static::validateActivityProperties($data[
'PROPERTIES']);
1567 if (isset($data[
'RETURN_PROPERTIES']))
1568 static::validateActivityProperties($data[
'RETURN_PROPERTIES']);
1569 if (isset($data[
'DOCUMENT_TYPE']))
1570 static::validateActivityDocumentType($data[
'DOCUMENT_TYPE']);
1571 if (isset($data[
'FILTER']) && !is_array($data[
'FILTER']))
1572 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1575 private static function validateProvider($data, $server)
1577 if (!is_array($data) || empty($data))
1578 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1580 static::validateActivityCode($data[
'CODE']);
1581 static::validateActivityHandler($data[
'HANDLER'], $server);
1582 if (empty($data[
'NAME']))
1583 throw new RestException(
'Empty provider NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1585 if (empty($data[
'TYPE']))
1586 throw new RestException(
'Empty provider TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1589 throw new RestException(
'Unknown provider TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1592 private static function validateRobot($data, $server)
1594 if (!is_array($data) || empty($data))
1595 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1597 static::validateActivityCode($data[
'CODE']);
1598 static::validateActivityHandler($data[
'HANDLER'], $server);
1599 if (empty($data[
'NAME']))
1600 throw new RestException(
'Empty activity NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1602 if (isset($data[
'PROPERTIES']))
1603 static::validateActivityProperties($data[
'PROPERTIES']);
1605 if (isset($data[
'RETURN_PROPERTIES']))
1606 static::validateActivityProperties($data[
'RETURN_PROPERTIES']);
1607 if (isset($data[
'FILTER']) && !is_array($data[
'FILTER']))
1608 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1611 private static function validateActivityCode($code)
1614 throw new RestException(
'Empty activity code!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1615 if (!preg_match(
'#^[a-z0-9\.\-_]+$#i', $code))
1616 throw new RestException(
'Wrong activity code!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1619 private static function validateActivityHandler($handler, $server)
1624 private static function validateActivityProperties($properties)
1626 if (!is_array($properties))
1627 throw new RestException(
'Wrong properties array!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1629 foreach ($properties as $key => $property)
1631 if (!preg_match(
'#^[a-z][a-z0-9_]*$#i', $key))
1632 throw new RestException(
'Wrong property key ('.$key.
')!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1633 if (empty($property[
'NAME']))
1634 throw new RestException(
'Empty property NAME ('.$key.
')!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1638 private static function validateActivityDocumentType($documentType)
1642 $runtime = \CBPRuntime::getRuntime();
1643 $runtime->startRuntime();
1645 $documentService = $runtime->getService(
'DocumentService');
1646 $documentService->getDocumentFieldTypes($documentType);
1648 catch (\CBPArgumentNullException $e)
1650 throw new RestException(
'Wrong activity DOCUMENT_TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1654 private static function getDocumentId($documentId): ?array
1656 $documentId = \CBPHelper::parseDocumentId($documentId);
1657 $documentService = \CBPRuntime::getRuntime(
true)->getDocumentService();
1658 $documentId = $documentService->normalizeDocumentId($documentId);
1660 if (!$documentService->getDocument($documentId))
1668 private static function getDocumentType(array $documentId): ?array
1672 $documentId = \CBPHelper::parseDocumentId($documentId);
1673 $runtime = \CBPRuntime::getRuntime(
true);
1674 $documentService = $runtime->getDocumentService();
1676 return $documentService->getDocumentType($documentId);
1678 catch (\CBPArgumentNullException $e) {}
1683 private static function getTemplateDocumentType(
int $id): ?array
1685 $tpl = WorkflowTemplateTable::getList([
1686 'select' => [
'MODULE_ID',
'ENTITY',
'DOCUMENT_TYPE'],
1687 'filter' => [
'=ID' => $id],
1692 return [$tpl[
'MODULE_ID'], $tpl[
'ENTITY'], $tpl[
'DOCUMENT_TYPE']];
1697 private static function isEqualDocumentType(array $a, array $b)
1700 (
string)$a[0] === (
string)$b[0]
1701 && (
string)$a[1] === (
string)$b[1]
1702 && (
string)$a[2] === (
string)$b[2]
1706 private static function validateTemplateName($name)
1710 throw new RestException(
'Empty activity code!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1714 private static function upsertAppPlacement(
int $appId,
string $code,
string $handler)
1717 '=APP_ID' => $appId,
1718 '=ADDITIONAL' => $code,
1719 '=PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1722 $dbRes = PlacementTable::getList(array(
1726 $placementHandler = $dbRes->fetch();
1728 if ($placementHandler)
1730 $result = PlacementTable::update($placementHandler[
'ID'], [
'PLACEMENT_HANDLER' => $handler]);
1734 $placementBind = array(
1736 'ADDITIONAL' => $code,
1737 'PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1738 'PLACEMENT_HANDLER' => $handler,
1741 $result = PlacementTable::add($placementBind);
1744 if(!$result->isSuccess())
1746 $errorMessage = $result->getErrorMessages();
1747 throw new RestException(
1748 'Unable to set placement handler: '.implode(
', ', $errorMessage),
1754 private static function deleteAppPlacement(
int $appId,
string $code =
null)
1757 '=APP_ID' => $appId,
1758 '=PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1763 $filter[
'=ADDITIONAL'] = $code;
1766 $dbRes = PlacementTable::getList(array(
1770 while($placementHandler = $dbRes->fetch())
1772 PlacementTable::delete($placementHandler[
"ID"]);
1776 private static function prepareTemplateData($data)
1780 $fileFields = \CRestUtil::saveFile($data);
1784 return file_get_contents($fileFields[
'tmp_name']);
1787 throw new RestException(
'Incorrect field TEMPLATE_DATA!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1790 private static function validateTemplateDocumentType($documentType)
1794 $documentService = \CBPRuntime::getRuntime(
true)->getDocumentService();
1795 $documentService->getDocumentFieldTypes($documentType);
1797 catch (\CBPArgumentNullException $e)
1799 throw new RestException(
'Incorrect field DOCUMENT_TYPE!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1803 private static function validateTemplateAutoExecution($flag)
1805 if ($flag === (
string) (
int) $flag)
1807 $flag = (int) $flag;
1812 \CBPDocumentEventType::None,
1813 \CBPDocumentEventType::Create,
1814 \CBPDocumentEventType::Edit,
1815 \CBPDocumentEventType::Create | \CBPDocumentEventType::Edit
1825 throw new RestException(
'Incorrect field AUTO_EXECUTE!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1828 private static function generateTemplateSystemCode(\CRestServer $server)
1830 $appId = self::getAppId($server->getClientId());
1832 return 'rest_app_'.$appId;
1835 private static function extractEventToken($token)
1837 $data = \CBPRestActivity::extractToken($token);
1839 throw new AccessException();
1849 private static function getApp($server)
1851 if(self::$app ==
null)
1853 if (Loader::includeModule(
'rest'))
1855 $result = AppTable::getList(
1858 '=CLIENT_ID' => $server->getClientId()
1862 self::$app = $result->fetch();
static normalizeProperty($property)
static onRestAppUpdate(array $fields)
static onRestServiceBuildDescription()
static onRestAppDelete(array $fields)
static getTaskList($params, $n, $server)
static deleteProvider($params, $n, $server)
const ERROR_ACTIVITY_NOT_FOUND
static writeActivityLog($params, $n, $server)
const ERROR_TASK_COMPLETED
static getActivityList($params, $n, $server)
const ERROR_ACTIVITY_ADD_FAILURE
static getWorkflowInstances($params, $n, $server)
const ERROR_TASK_EXECUTION
static updateActivity($params, $n, $server)
static getRobotList($params, $n, $server)
static deleteWorkflowTemplate($params, $n, $server)
const ERROR_WRONG_WORKFLOW_ID
static updateWorkflowTemplate($params, $n, $server)
static addWorkflowTemplate($params, $n, $server)
static addProvider($params, $n, $server)
static updateRobot($params, $n, $server)
static terminateWorkflow($params, $n, $server)
const ERROR_EMPTY_LOG_MESSAGE
static startWorkflow($params, $n, $server)
static deleteActivity($params, $n, $server)
const PLACEMENT_ACTIVITY_PROPERTIES_DIALOG
static getProviderList($params, $n, $server)
static addActivity($params, $n, $server)
const ERROR_TEMPLATE_VALIDATION_FAILURE
const ERROR_ACTIVITY_ALREADY_INSTALLED
const ERROR_TASK_VALIDATION
static completeTask($params, $n, $server)
const ERROR_TASK_NOT_FOUND
static getWorkflowTemplates($params, $n, $server)
static deleteRobot($params, $n, $server)
static sendEvent($params, $n, $server)
static killWorkflow($params, $n, $server)
static addRobot($params, $n, $server)
const ERROR_ACTIVITY_VALIDATION_FAILURE
static checkCallback($handlerUrl, $appInfo=array(), $checkInstallUrl=true)