23 private static $allowedOperations = [
'',
'!',
'<',
'<=',
'>',
'>='];
47 private const ALLOWED_TASK_ACTIVITIES = [
50 'RequestInformationActivity',
51 'RequestInformationOptionalActivity'
58 if (self::isEnabled())
62 'bizproc.activity.add' => [__CLASS__,
'addActivity'],
63 'bizproc.activity.update' => [__CLASS__,
'updateActivity'],
64 'bizproc.activity.delete' => [__CLASS__,
'deleteActivity'],
65 'bizproc.activity.log' => [__CLASS__,
'writeActivityLog'],
66 'bizproc.activity.list' => [__CLASS__,
'getActivityList'],
69 'bizproc.event.send' => [__CLASS__,
'sendEvent'],
72 'bizproc.task.list' => [__CLASS__,
'getTaskList'],
73 'bizproc.task.complete' => [__CLASS__,
'completeTask'],
74 'bizproc.task.delegate' => [__CLASS__,
'delegateTask'],
77 'bizproc.workflow.terminate' => [__CLASS__,
'terminateWorkflow'],
78 'bizproc.workflow.kill' => [__CLASS__,
'killWorkflow'],
79 'bizproc.workflow.start' => [__CLASS__,
'startWorkflow'],
82 'bizproc.workflow.instance.list' => [__CLASS__,
'getWorkflowInstances'],
85 'bizproc.workflow.template.list' => [__CLASS__,
'getWorkflowTemplates'],
86 'bizproc.workflow.template.add' => [__CLASS__,
'addWorkflowTemplate'],
87 'bizproc.workflow.template.update' => [__CLASS__,
'updateWorkflowTemplate'],
88 'bizproc.workflow.template.delete' => [__CLASS__,
'deleteWorkflowTemplate'],
91 'bizproc.workflow.instances' => [__CLASS__,
'getWorkflowInstances'],
97 || self::isEnabled(
'crm_automation_lead')
98 || self::isEnabled(
'crm_automation_deal')
99 || self::isEnabled(
'crm_automation_order')
100 || self::isEnabled(
'tasks_automation')
104 'bizproc.event.send' => [__CLASS__,
'sendEvent'],
105 'bizproc.activity.log' => [__CLASS__,
'writeActivityLog'],
108 'bizproc.robot.add' =>
array(__CLASS__,
'addRobot'),
109 'bizproc.robot.update' =>
array(__CLASS__,
'updateRobot'),
110 'bizproc.robot.delete' =>
array(__CLASS__,
'deleteRobot'),
111 'bizproc.robot.list' =>
array(__CLASS__,
'getRobotList'),
114 'bizproc.provider.add' => [__CLASS__,
'addProvider'],
115 'bizproc.provider.delete' => [__CLASS__,
'deleteProvider'],
116 'bizproc.provider.list' => [__CLASS__,
'getProviderList'],
121 $map[\CRestUtil::PLACEMENTS] = [
122 static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG => [
'private' =>
true],
126 static::SCOPE =>
$map,
130 private static function isEnabled(
string $feature =
'bizproc'): bool
132 if (Loader::includeModule(
'bitrix24'))
134 return \Bitrix\Bitrix24\Feature::isFeatureEnabled($feature);
151 if (!Loader::includeModule(
'rest'))
161 'select' =>
array(
'ID'),
162 'filter' =>
array(
'=APP_ID' =>
$app[
'CLIENT_ID'])
167 RestActivityTable::delete(
$activity[
'ID']);
171 'select' =>
array(
'ID'),
172 'filter' =>
array(
'=APP_ID' =>
$app[
'CLIENT_ID'])
177 RestProviderTable::delete(
$activity[
'ID']);
180 self::deleteAppPlacement(
$app[
'ID']);
190 static::onRestAppDelete(
$fields);
202 return self::addActivityInternal(
$params, $server,
false);
214 return self::addActivityInternal(
$params, $server,
true);
225 private static function addActivityInternal(
$params, $server, $isRobot =
false)
227 if(!$server->getClientId())
232 self::checkAdminPermissions();
236 self::validateRobot(
$params, $server);
238 self::validateActivity(
$params, $server);
240 $appId = self::getAppId($server->getClientId());
241 $params[
'APP_ID'] = $server->getClientId();
246 'select' =>
array(
'ID'),
247 'filter' =>
array(
'=INTERNAL_CODE' =>
$params[
'INTERNAL_CODE'])
252 throw new RestException(
'Activity or Robot already installed!', self::ERROR_ACTIVITY_ALREADY_INSTALLED);
256 $params[
'IS_ROBOT'] = $isRobot ?
'Y' :
'N';
257 $params[
'USE_PLACEMENT'] = (isset(
$params[
'USE_PLACEMENT']) &&
$params[
'USE_PLACEMENT'] ===
'Y') ?
'Y' :
'N';
259 if (
$params[
'USE_PLACEMENT'] ===
'Y')
261 self::validateActivityHandler(
$params[
'PLACEMENT_HANDLER'] ??
null, $server);
262 self::upsertAppPlacement($appId,
$params[
'CODE'],
$params[
'PLACEMENT_HANDLER'] ??
null);
269 catch (SqlQueryException $exception)
271 throw new RestException(
'Activity or Robot already added!', self::ERROR_ACTIVITY_ADD_FAILURE);
276 if (
$params[
'USE_PLACEMENT'] ===
'Y')
278 self::deleteAppPlacement($appId,
$params[
'CODE']);
281 throw new RestException(
'Activity save error!', self::ERROR_ACTIVITY_ADD_FAILURE);
296 return self::updateActivityInternal(
$params, $server,
false);
308 return self::deleteActivityInternal(
$params, $server,
false);
320 return self::updateActivityInternal(
$params, $server,
true);
332 return self::deleteActivityInternal(
$params, $server,
true);
343 private static function deleteActivityInternal(
$params, $server, $isRobot =
false)
345 if(!$server->getClientId())
351 self::checkAdminPermissions();
352 self::validateActivityCode(
$params[
'CODE']);
353 $params[
'APP_ID'] = $server->getClientId();
354 $internalCode = self::generateInternalCode(
$params);
357 'select' =>
array(
'ID'),
359 '=INTERNAL_CODE' => $internalCode,
360 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
366 throw new RestException(
'Activity or Robot not found!', self::ERROR_ACTIVITY_NOT_FOUND);
368 RestActivityTable::delete(
$result[
'ID']);
369 self::deleteAppPlacement(self::getAppId(
$params[
'APP_ID']),
$params[
'CODE']);
385 private static function updateActivityInternal(
$params, $server, $isRobot =
false)
387 if(!$server->getClientId())
389 throw new AccessException(
"Application context required");
393 self::checkAdminPermissions();
394 self::validateActivityCode(
$params[
'CODE']);
395 $params[
'APP_ID'] = $server->getClientId();
396 $internalCode = self::generateInternalCode(
$params);
399 'select' =>
array(
'ID'),
401 '=INTERNAL_CODE' => $internalCode,
402 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
408 throw new RestException(
'Activity or Robot not found!', self::ERROR_ACTIVITY_NOT_FOUND);
415 throw new RestException(
'No fields to update', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
422 self::validateActivityHandler(
$fields[
'HANDLER'], $server);
423 $toUpdate[
'HANDLER'] =
$fields[
'HANDLER'];
426 if (isset(
$fields[
'AUTH_USER_ID']))
428 $toUpdate[
'AUTH_USER_ID'] = (int)
$fields[
'AUTH_USER_ID'];
431 if (isset(
$fields[
'USE_SUBSCRIPTION']))
433 $toUpdate[
'USE_SUBSCRIPTION'] = (string)
$fields[
'USE_SUBSCRIPTION'];
436 if (isset(
$fields[
'USE_PLACEMENT']))
438 $toUpdate[
'USE_PLACEMENT'] = (
$fields[
'USE_PLACEMENT'] ===
'Y') ?
'Y' :
'N';
443 $toUpdate[
'NAME'] =
$fields[
'NAME'];
446 if (isset(
$fields[
'DESCRIPTION']))
448 $toUpdate[
'DESCRIPTION'] =
$fields[
'DESCRIPTION'];
451 if (isset(
$fields[
'PROPERTIES']))
453 self::validateActivityProperties(
$fields[
'PROPERTIES']);
454 $toUpdate[
'PROPERTIES'] =
$fields[
'PROPERTIES'];
457 if (isset(
$fields[
'RETURN_PROPERTIES']))
459 self::validateActivityProperties(
$fields[
'RETURN_PROPERTIES']);
460 $toUpdate[
'RETURN_PROPERTIES'] =
$fields[
'RETURN_PROPERTIES'];
463 if (isset(
$fields[
'DOCUMENT_TYPE']))
465 if (empty(
$fields[
'DOCUMENT_TYPE']))
467 $toUpdate[
'DOCUMENT_TYPE'] =
null;
471 static::validateActivityDocumentType(
$fields[
'DOCUMENT_TYPE']);
472 $toUpdate[
'DOCUMENT_TYPE'] =
$fields[
'DOCUMENT_TYPE'];
480 $toUpdate[
'FILTER'] =
null;
484 if (!is_array(
$fields[
'FILTER']))
486 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
488 $toUpdate[
'FILTER'] =
$fields[
'FILTER'];
494 throw new RestException(
'No fields to update', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
497 if (isset(
$fields[
'PLACEMENT_HANDLER']))
499 self::validateActivityHandler(
$fields[
'PLACEMENT_HANDLER'], $server);
500 self::upsertAppPlacement(self::getAppId(
$params[
'APP_ID']),
$params[
'CODE'],
$fields[
'PLACEMENT_HANDLER']);
503 if (isset($toUpdate[
'USE_PLACEMENT']) && $toUpdate[
'USE_PLACEMENT'] ===
'N')
505 self::deleteAppPlacement(self::getAppId(
$params[
'APP_ID']),
$params[
'CODE']);
508 $updateResult = RestActivityTable::update(
$result[
'ID'], $toUpdate);
510 if (!$updateResult->isSuccess())
512 throw new RestException(
513 implode(
'; ', $updateResult->getErrorMessages()),
514 self::ERROR_ACTIVITY_VALIDATION_FAILURE
532 [$workflowId, $activityName, $eventId] = self::extractEventToken(
$params[
'EVENT_TOKEN']);
535 \CBPDocument::sendExternalEvent(
539 'EVENT_ID' => $eventId,
540 'RETURN_VALUES' =>
$params[
'RETURN_VALUES'] ?? [],
541 'LOG_MESSAGE' =>
$params[
'LOG_MESSAGE'] ??
'',
566 [$workflowId, $activityName, $eventId] = self::extractEventToken(
$params[
'EVENT_TOKEN']);
568 $logMessage = isset(
$params[
'LOG_MESSAGE']) ?
$params[
'LOG_MESSAGE'] :
'';
570 if (empty($logMessage))
571 throw new RestException(
'Empty log message!', self::ERROR_EMPTY_LOG_MESSAGE);
574 \CBPDocument::sendExternalEvent(
578 'EVENT_ID' => $eventId,
579 'LOG_ACTION' =>
true,
580 'LOG_MESSAGE' => $logMessage
604 return self::getActivityListInternal(
$params, $server,
false);
617 return self::getActivityListInternal(
$params, $server,
true);
627 private static function getActivityListInternal(
$params, $server, $isRobot =
false)
629 if(!$server->getClientId())
634 self::checkAdminPermissions();
636 'select' =>
array(
'CODE'),
638 '=APP_ID' => $server->getClientId(),
639 '=IS_ROBOT' => $isRobot ?
'Y' :
'N'
662 self::checkAdminPermissions();
667 'MODIFIED' =>
'MODIFIED',
668 'OWNED_UNTIL' =>
'OWNED_UNTIL',
669 'MODULE_ID' =>
'MODULE_ID',
670 'ENTITY' =>
'ENTITY',
671 'DOCUMENT_ID' =>
'DOCUMENT_ID',
672 'STARTED' =>
'STARTED',
673 'STARTED_BY' =>
'STARTED_BY',
674 'TEMPLATE_ID' =>
'WORKFLOW_TEMPLATE_ID',
678 $filter = static::getFilter(
$params[
'FILTER'] ??
null,
$fields, [
'MODIFIED',
'OWNED_UNTIL',
'STARTED']);
680 $shouldCountTotal = (
$n >= 0);
682 $iterator = WorkflowInstanceTable::getList([
686 'limit' => static::LIST_LIMIT,
687 'offset' => max(0, (
int)
$n),
688 'count_total' => $shouldCountTotal,
694 if (isset($row[
'MODIFIED']))
696 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
698 if (isset($row[
'STARTED']))
700 $row[
'STARTED'] = \CRestUtil::convertDateTime($row[
'STARTED']);
702 if (isset($row[
'OWNED_UNTIL']))
704 $row[
'OWNED_UNTIL'] = \CRestUtil::convertDateTime($row[
'OWNED_UNTIL']);
711 return static::setNavData(
$result, [
'count' =>
$count,
'offset' =>
$n]);
724 self::checkAdminPermissions();
729 throw new RestException(
'Empty workflow instance ID', self::ERROR_WRONG_WORKFLOW_ID);
734 throw new RestException(
'Invalid workflow instance ID (string expected)', self::ERROR_WRONG_WORKFLOW_ID);
759 self::checkAdminPermissions();
764 throw new RestException(
'Empty workflow instance ID', self::ERROR_WRONG_WORKFLOW_ID);
768 $errors = \CBPDocument::killWorkflow($id);
790 if (empty(
$params[
'TEMPLATE_ID']))
792 throw new RestException(
'Empty TEMPLATE_ID', self::ERROR_WRONG_WORKFLOW_ID);
795 $tplDocumentType = self::getTemplateDocumentType(
$templateId);
797 if (!$tplDocumentType)
799 throw new RestException(
'Template not found', self::ERROR_WRONG_WORKFLOW_ID);
803 $getParams = array_change_key_case($_GET, CASE_UPPER);
804 if (isset($getParams[
'DOCUMENT_ID']) && is_array($getParams[
'DOCUMENT_ID']))
806 $params[
'DOCUMENT_ID'] = $getParams[
'DOCUMENT_ID'];
809 $documentId = self::getDocumentId(
$params[
'DOCUMENT_ID']);
816 $documentType = self::getDocumentType($documentId);
823 if (!\CBPHelper::isEqualDocument($tplDocumentType, $documentType))
825 throw new RestException(
'Template type and DOCUMENT_ID mismatch!');
828 self::checkStartWorkflowPermissions($documentId,
$templateId);
830 $workflowParameters = isset(
$params[
'PARAMETERS']) && is_array(
$params[
'PARAMETERS']) ?
$params[
'PARAMETERS'] : [];
832 $workflowParameters[\CBPDocument::PARAM_TAGRET_USER] =
'user_' . self::getCurrentUserId();
835 $workflowId = \CBPDocument::startWorkflow(
$templateId, $documentId, $workflowParameters,
$errors);
845 private static function checkStartWorkflowPermissions(
array $documentId,
$templateId)
847 if (static::isAdmin())
853 \CBPDocument::CanUserOperateDocument(
855 static::getCurrentUserId(),
864 throw new AccessException();
879 self::checkAdminPermissions();
884 'MODULE_ID' =>
'MODULE_ID',
885 'ENTITY' =>
'ENTITY',
886 'DOCUMENT_TYPE' =>
'DOCUMENT_TYPE',
887 'AUTO_EXECUTE' =>
'AUTO_EXECUTE',
889 'DESCRIPTION' =>
'DESCRIPTION',
890 'TEMPLATE' =>
'TEMPLATE',
891 'PARAMETERS' =>
'PARAMETERS',
892 'VARIABLES' =>
'VARIABLES',
893 'CONSTANTS' =>
'CONSTANTS',
894 'MODIFIED' =>
'MODIFIED',
895 'IS_MODIFIED' =>
'IS_MODIFIED',
896 'USER_ID' =>
'USER_ID',
897 'SYSTEM_CODE' =>
'SYSTEM_CODE',
905 $shouldCountTotal = (
$n >= 0);
911 'limit' => static::LIST_LIMIT,
912 'offset' => max(0, (
int)
$n),
913 'count_total' => $shouldCountTotal,
916 $countTotal = $shouldCountTotal ?
$iterator->getCount() : 0;
918 $iterator = new \CBPWorkflowTemplateResult(
$iterator, \CBPWorkflowTemplateLoader::useGZipCompression());
923 if (isset($row[
'MODIFIED']))
924 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
925 if (isset($row[
'STARTED']))
926 $row[
'STARTED'] = \CRestUtil::convertDateTime($row[
'STARTED']);
927 if (isset($row[
'OWNED_UNTIL']))
928 $row[
'OWNED_UNTIL'] = \CRestUtil::convertDateTime($row[
'OWNED_UNTIL']);
932 return static::setNavData(
$result, [
'count' => $countTotal,
'offset' =>
$n]);
944 if(!$server->getClientId())
949 self::checkAdminPermissions();
952 self::validateTemplateDocumentType(
$params[
'DOCUMENT_TYPE']);
953 self::validateTemplateName(
$params[
'NAME']);
956 if (isset(
$params[
'AUTO_EXECUTE']))
958 self::validateTemplateAutoExecution(
$params[
'AUTO_EXECUTE']);
959 $autoExecute = (int)
$params[
'AUTO_EXECUTE'];
962 $data = self::prepareTemplateData(
$params[
'TEMPLATE_DATA']);
966 return \CBPWorkflowTemplateLoader::ImportTemplate(
971 isset(
$params[
'DESCRIPTION']) ? (
string)
$params[
'DESCRIPTION'] :
'',
973 self::generateTemplateSystemCode($server)
991 if(!$server->getClientId())
996 self::checkAdminPermissions();
1003 throw new RestException(
"No fields to update.", self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1006 $tpl = WorkflowTemplateTable::getList(
array(
1007 'select' => [
'ID',
'SYSTEM_CODE',
'NAME',
'DESCRIPTION',
'AUTO_EXECUTE',
'MODULE_ID',
'ENTITY',
'DOCUMENT_TYPE'],
1008 'filter' => [
'=ID' => (
int)
$params[
'ID']],
1013 throw new RestException(
"Workflow template not found.", self::ERROR_TEMPLATE_NOT_FOUND);
1016 if ($tpl[
'SYSTEM_CODE'] !== self::generateTemplateSystemCode($server))
1019 "You can update ONLY templates created by current application",
1020 self::ERROR_TEMPLATE_NOT_OWNER,
1026 self::validateTemplateName(
$fields[
'NAME']);
1027 $tpl[
'NAME'] =
$fields[
'NAME'];
1030 if (isset(
$fields[
'DESCRIPTION']))
1032 $tpl[
'DESCRIPTION'] = (string)
$fields[
'DESCRIPTION'];
1035 if (isset(
$fields[
'AUTO_EXECUTE']))
1037 self::validateTemplateAutoExecution(
$fields[
'AUTO_EXECUTE']);
1038 $tpl[
'AUTO_EXECUTE'] = (int)
$fields[
'AUTO_EXECUTE'];
1041 if (isset(
$fields[
'TEMPLATE_DATA']))
1043 $data = self::prepareTemplateData(
$fields[
'TEMPLATE_DATA']);
1045 return \CBPWorkflowTemplateLoader::ImportTemplate(
1047 [$tpl[
'MODULE_ID'], $tpl[
'ENTITY'], $tpl[
'DOCUMENT_TYPE']],
1048 $tpl[
'AUTO_EXECUTE'],
1050 $tpl[
'DESCRIPTION'],
1057 return \CBPWorkflowTemplateLoader::Update($tpl[
'ID'], [
1058 'NAME' => $tpl[
'NAME'],
1059 'DESCRIPTION' => $tpl[
'DESCRIPTION'],
1060 'AUTO_EXECUTE' => $tpl[
'AUTO_EXECUTE'],
1074 if(!$server->getClientId())
1079 self::checkAdminPermissions();
1082 $tpl = WorkflowTemplateTable::getList(
array(
1083 'select' => [
'ID',
'SYSTEM_CODE'],
1084 'filter' => [
'=ID' => (
int)
$params[
'ID']],
1089 throw new RestException(
"Workflow template not found.", self::ERROR_TEMPLATE_NOT_FOUND);
1092 if ($tpl[
'SYSTEM_CODE'] !== self::generateTemplateSystemCode($server))
1094 throw new RestException(
"You can delete ONLY templates created by current application");
1099 \CBPWorkflowTemplateLoader::Delete($tpl[
'ID']);
1120 'ACTIVITY' =>
'ACTIVITY',
1121 'ACTIVITY_NAME' =>
'ACTIVITY_NAME',
1122 'WORKFLOW_ID' =>
'WORKFLOW_ID',
1123 'DOCUMENT_NAME' =>
'DOCUMENT_NAME',
1124 'DESCRIPTION' =>
'DESCRIPTION',
1126 'MODIFIED' =>
'MODIFIED',
1127 'WORKFLOW_STARTED' =>
'WORKFLOW_STARTED',
1128 'WORKFLOW_STARTED_BY' =>
'WORKFLOW_STARTED_BY',
1129 'OVERDUE_DATE' =>
'OVERDUE_DATE',
1130 'WORKFLOW_TEMPLATE_ID' =>
'WORKFLOW_TEMPLATE_ID',
1131 'WORKFLOW_TEMPLATE_NAME' =>
'WORKFLOW_TEMPLATE_NAME',
1132 'WORKFLOW_STATE' =>
'WORKFLOW_STATE',
1133 'STATUS' =>
'STATUS',
1134 'USER_ID' =>
'USER_ID',
1135 'USER_STATUS' =>
'USER_STATUS',
1136 'MODULE_ID' =>
'MODULE_ID',
1137 'ENTITY' =>
'ENTITY',
1138 'DOCUMENT_ID' =>
'DOCUMENT_ID',
1139 'PARAMETERS' =>
'PARAMETERS',
1147 $currentUserId = self::getCurrentUserId();
1148 $isAdmin = static::isAdmin();
1150 if (!$isAdmin && !isset(
$filter[
'USER_ID']))
1152 $filter[
'USER_ID'] = $currentUserId;
1155 $targetUserId = isset(
$filter[
'USER_ID'])? (int)
$filter[
'USER_ID'] : 0;
1156 if ($targetUserId !== $currentUserId && !\CBPHelper::checkUserSubordination($currentUserId, $targetUserId))
1158 self::checkAdminPermissions();
1165 static::getNavData(
$n),
1172 if (isset($row[
'MODIFIED']))
1173 $row[
'MODIFIED'] = \CRestUtil::convertDateTime($row[
'MODIFIED']);
1174 if (isset($row[
'WORKFLOW_STARTED']))
1175 $row[
'WORKFLOW_STARTED'] = \CRestUtil::convertDateTime($row[
'WORKFLOW_STARTED']);
1176 if (isset($row[
'OVERDUE_DATE']))
1177 $row[
'OVERDUE_DATE'] = \CRestUtil::convertDateTime($row[
'OVERDUE_DATE']);
1178 $row[
'DOCUMENT_URL'] = \CBPDocument::getDocumentAdminPage(
array(
1179 $row[
'MODULE_ID'], $row[
'ENTITY'], $row[
'DOCUMENT_ID']
1182 if (isset($row[
'PARAMETERS']))
1184 $row[
'PARAMETERS'] = static::prepareTaskParameters($row[
'PARAMETERS'], $row);
1193 private static function prepareTaskParameters(
array $parameters,
array $task)
1196 [
'CommentLabelMessage',
'CommentLabel'],
1197 'CommentRequired',
'ShowComment',
1198 [
'TaskButtonMessage',
'StatusOkLabel'],
1199 [
'TaskButton1Message',
'StatusYesLabel'],
1200 [
'TaskButton2Message',
'StatusNoLabel'],
1201 [
'TaskButtonCancelMessage',
'StatusCancelLabel'],
1202 [
'REQUEST',
'Fields'],
1207 foreach ($whiteList as $whiteKey)
1209 $filterKey = $whiteKey;
1210 if (is_array($whiteKey))
1212 $filterKey = $whiteKey[1];
1213 $whiteKey = $whiteKey[0];
1215 if (isset($parameters[$whiteKey]))
1217 $filtered[$filterKey] = $parameters[$whiteKey];
1221 if (isset($filtered[
'Fields']))
1223 $filtered[
'Fields'] = self::externalizeRequestFields($task, $filtered[
'Fields']);
1231 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
1233 foreach (
$fields as $requestField)
1235 $id = $requestField[
'Name'];
1236 $requestField[
'Name'] = $requestField[
'Title'];
1238 $property[
'Id'] = $id;
1240 $fieldTypeObject = $documentService->getFieldTypeObject($task[
"PARAMETERS"][
"DOCUMENT_TYPE"], $property);
1241 if ($fieldTypeObject)
1243 $fieldTypeObject->setDocumentId($task[
"PARAMETERS"][
"DOCUMENT_ID"]);
1244 $property[
'Default'] = $fieldTypeObject->externalizeValue(
1246 $property[
'Default']
1255 private static function internalizeRequestFields($task,
array $values):
array
1257 $documentService = \CBPRuntime::GetRuntime(
true)->getDocumentService();
1260 foreach ($task[
'PARAMETERS'][
'REQUEST'] as $property)
1262 if (!isset($values[$property[
'Name']]))
1268 $fieldTypeObject = $documentService->getFieldTypeObject($task[
"PARAMETERS"][
"DOCUMENT_TYPE"], $property);
1269 if ($fieldTypeObject)
1271 $fieldTypeObject->setDocumentId($task[
"PARAMETERS"][
"DOCUMENT_ID"]);
1288 self::validateTaskParameters(
$params);
1290 $userId = self::getCurrentUserId();
1293 if (!in_array($task[
'ACTIVITY'], self::ALLOWED_TASK_ACTIVITIES))
1295 throw new RestException(
'Incorrect task type', self::ERROR_TASK_TYPE);
1298 if (!empty(
$params[
'FIELDS']))
1300 $params[
'FIELDS'] = self::internalizeRequestFields($task,
$params[
'FIELDS']);
1306 'task_comment' => !empty(
$params[
'COMMENT']) && is_string(
$params[
'COMMENT']) ?
$params[
'COMMENT'] :
null,
1307 'fields' =>
$params[
'FIELDS'] ??
null,
1321 $currentUserId = self::getCurrentUserId();
1323 if (!is_array(
$params[
'TASK_IDS']) || array_filter(
$params[
'TASK_IDS'],
static fn($id) => !is_numeric($id)))
1325 throw new RestException(
'Invalid TASK_IDS', self::ERROR_TASK_VALIDATION);
1327 $taskIds = array_map(
'intval',
$params[
'TASK_IDS']);
1329 if (!isset(
$params[
'FROM_USER_ID']) || !is_numeric(
$params[
'FROM_USER_ID']) ||
$params[
'FROM_USER_ID'] <= 0)
1331 throw new RestException(
'Invalid FROM_USER_ID', self::ERROR_INVALID_USER_ID);
1333 $fromUserId = (int)
$params[
'FROM_USER_ID'];
1335 if (!isset(
$params[
'TO_USER_ID']) || !is_numeric(
$params[
'TO_USER_ID']) ||
$params[
'TO_USER_ID'] <= 0)
1337 throw new RestException(
'Invalid TO_USER_ID', self::ERROR_INVALID_USER_ID);
1339 $toUserId = (int)
$params[
'TO_USER_ID'];
1343 $delegateTaskResult = $taskService->delegateTasks($tasksRequest);
1345 if (!$delegateTaskResult->isSuccess())
1347 $errors = implode(
';', $delegateTaskResult->getErrorMessages());
1354 private static function validateTaskParameters(
array $params)
1356 if (empty(
$params[
'TASK_ID']))
1358 throw new RestException(
'empty TASK_ID', self::ERROR_TASK_VALIDATION);
1362 throw new RestException(
'incorrect STATUS', self::ERROR_TASK_VALIDATION);
1366 private static function getTask($id,
$userId)
1368 $dbTask = \CBPTaskService::getList(
1373 array(
"ID",
"WORKFLOW_ID",
"ACTIVITY",
"ACTIVITY_NAME",
"MODIFIED",
"OVERDUE_DATE",
"NAME",
"DESCRIPTION",
"PARAMETERS",
"USER_STATUS")
1375 $task = $dbTask->fetch();
1379 throw new RestException(
'Task not found', self::ERROR_TASK_NOT_FOUND);
1383 throw new RestException(
'Task already completed', self::ERROR_TASK_COMPLETED);
1388 $task[
"PARAMETERS"][
"DOCUMENT_ID"] = \CBPStateService::getStateDocumentId($task[
'WORKFLOW_ID']);
1389 $task[
"MODULE_ID"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][0];
1390 $task[
"ENTITY"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][1];
1391 $task[
"DOCUMENT_ID"] = $task[
"PARAMETERS"][
"DOCUMENT_ID"][2];
1406 if (Loader::includeModule(
'messageservice'))
1408 return \Bitrix\MessageService\RestService::addSender(
$params,
$n, $server);
1411 if(!$server->getClientId())
1416 self::checkAdminPermissions();
1419 self::validateProvider(
$params, $server);
1421 $params[
'APP_ID'] = $server->getClientId();
1425 'select' =>
array(
'ID'),
1427 '=APP_ID' =>
$params[
'APP_ID'],
1434 throw new RestException(
'Provider already installed!', self::ERROR_ACTIVITY_ALREADY_INSTALLED);
1440 throw new RestException(
'Activity save error!', self::ERROR_ACTIVITY_ADD_FAILURE);
1454 if (Loader::includeModule(
'messageservice'))
1456 return \Bitrix\MessageService\RestService::deleteSender(
$params,
$n, $server);
1459 if(!$server->getClientId())
1465 self::checkAdminPermissions();
1466 self::validateActivityCode(
$params[
'CODE']);
1467 $params[
'APP_ID'] = $server->getClientId();
1470 'select' =>
array(
'ID'),
1472 '=APP_ID' =>
$params[
'APP_ID'],
1479 throw new RestException(
'Provider not found!', self::ERROR_ACTIVITY_NOT_FOUND);
1481 RestProviderTable::delete(
$result[
'ID']);
1496 if (Loader::includeModule(
'messageservice'))
1498 return \Bitrix\MessageService\RestService::getSenderList(
$params,
$n, $server);
1501 if(!$server->getClientId())
1506 self::checkAdminPermissions();
1508 'select' =>
array(
'CODE'),
1510 '=APP_ID' => $server->getClientId()
1522 private static function getSelect($rules,
$fields, $default =
array())
1525 if (!empty($rules) && is_array($rules))
1527 foreach ($rules as $field)
1529 if (!is_scalar($field))
1532 "Invalid data in SELECT parameter",
1533 self::ERROR_SELECT_VALIDATION_FAILURE,
1537 $field = mb_strtoupper($field);
1549 if (!empty($rules) && is_array($rules))
1551 foreach ($rules as $field => $ordering)
1553 $field = mb_strtoupper($field);
1554 $ordering = mb_strtoupper($ordering);
1556 $order[
$fields[$field]] = $ordering ==
'DESC' ?
'DESC' :
'ASC';
1563 private static function getFilter($rules,
$fields,
array $datetimeFieldsList =
array())
1566 if (!empty($rules) && is_array($rules))
1568 foreach ($rules as
$key => $value)
1575 if (in_array($operation, static::$allowedOperations,
true) && isset(
$fields[$field]))
1577 if (in_array($field, $datetimeFieldsList))
1579 $value = \CRestUtil::unConvertDateTime($value);
1591 private static function checkAdminPermissions()
1593 if (!static::isAdmin())
1595 throw new AccessException();
1599 private static function isAdmin()
1607 || Loader::includeModule(
'bitrix24') && \CBitrix24::isPortalAdmin(
$USER->getID())
1612 private static function getCurrentUserId()
1618 private static function generateInternalCode(
$data)
1620 return md5(
$data[
'APP_ID'].
'@'.
$data[
'CODE']);
1623 private static function getAppName($appId)
1625 if (!Loader::includeModule(
'rest'))
1626 return array(
'*' =>
'No app');
1631 '=CLIENT_ID' => $appId
1633 'select' =>
array(
'ID',
'APP_NAME',
'CODE'),
1641 '=APP_ID' =>
$app[
'ID'],
1643 'select' =>
array(
'LANGUAGE_ID',
'MENU_NAME')
1653 private static function getAppId(
$clientId)
1655 if (!Loader::includeModule(
'rest'))
1665 'select' =>
array(
'ID'),
1670 return (
int)
$app[
'ID'];
1673 private static function prepareActivityData(
array $data, $ignore =
false)
1676 $data = array_change_key_case(
$data, CASE_UPPER);
1679 if (is_array($field))
1680 $field = self::prepareActivityData($field,
$key ==
'PROPERTIES' ||
$key ==
'RETURN_PROPERTIES' ||
$key ==
'OPTIONS');
1685 private static function validateActivity(
$data, $server)
1688 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1690 static::validateActivityCode(
$data[
'CODE']);
1691 static::validateActivityHandler(
$data[
'HANDLER'], $server);
1692 if (empty(
$data[
'NAME']))
1693 throw new RestException(
'Empty activity NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1695 if (isset(
$data[
'PROPERTIES']))
1696 static::validateActivityProperties(
$data[
'PROPERTIES']);
1698 if (isset(
$data[
'RETURN_PROPERTIES']))
1699 static::validateActivityProperties(
$data[
'RETURN_PROPERTIES']);
1700 if (isset(
$data[
'DOCUMENT_TYPE']))
1701 static::validateActivityDocumentType(
$data[
'DOCUMENT_TYPE']);
1702 if (isset(
$data[
'FILTER']) && !is_array(
$data[
'FILTER']))
1703 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1706 private static function validateProvider(
$data, $server)
1709 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1711 static::validateActivityCode(
$data[
'CODE']);
1712 static::validateActivityHandler(
$data[
'HANDLER'], $server);
1713 if (empty(
$data[
'NAME']))
1714 throw new RestException(
'Empty provider NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1716 if (empty(
$data[
'TYPE']))
1717 throw new RestException(
'Empty provider TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1720 throw new RestException(
'Unknown provider TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1723 private static function validateRobot(
$data, $server)
1726 throw new RestException(
'Empty data!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1728 static::validateActivityCode(
$data[
'CODE']);
1729 static::validateActivityHandler(
$data[
'HANDLER'], $server);
1730 if (empty(
$data[
'NAME']))
1731 throw new RestException(
'Empty activity NAME!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1733 if (isset(
$data[
'PROPERTIES']))
1734 static::validateActivityProperties(
$data[
'PROPERTIES']);
1736 if (isset(
$data[
'RETURN_PROPERTIES']))
1737 static::validateActivityProperties(
$data[
'RETURN_PROPERTIES']);
1738 if (isset(
$data[
'FILTER']) && !is_array(
$data[
'FILTER']))
1739 throw new RestException(
'Wrong activity FILTER!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1742 private static function validateActivityCode(
$code)
1746 throw new RestException(
'Empty activity code!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1748 if (!is_string(
$code) || !preg_match(
'#^[a-z0-9\.\-_]+$#i',
$code))
1750 throw new RestException(
'Wrong activity code!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1754 private static function validateActivityHandler($handler, $server)
1759 private static function validateActivityProperties($properties)
1761 if (!is_array($properties))
1762 throw new RestException(
'Wrong properties array!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1764 foreach ($properties as
$key => $property)
1766 if (!preg_match(
'#^[a-z][a-z0-9_]*$#i',
$key))
1767 throw new RestException(
'Wrong property key ('.
$key.
')!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1768 if (empty($property[
'NAME']))
1769 throw new RestException(
'Empty property NAME ('.
$key.
')!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1773 private static function validateActivityDocumentType($documentType)
1777 $runtime = \CBPRuntime::getRuntime();
1778 $runtime->startRuntime();
1780 $documentService = $runtime->getService(
'DocumentService');
1781 $documentService->getDocumentFieldTypes($documentType);
1783 catch (\CBPArgumentNullException $e)
1785 throw new RestException(
'Wrong activity DOCUMENT_TYPE!', self::ERROR_ACTIVITY_VALIDATION_FAILURE);
1789 private static function getDocumentId($documentId): ?
array
1793 $documentService = \CBPRuntime::getRuntime()->getDocumentService();
1794 $documentId = $documentService->normalizeDocumentId($documentId);
1795 if ($documentService->getDocument($documentId,
select: [
'ID']))
1800 catch (\CBPArgumentException $exception) {}
1805 private static function getDocumentType(
array $documentId): ?
array
1809 $documentId = \CBPHelper::parseDocumentId($documentId);
1810 $runtime = \CBPRuntime::getRuntime(
true);
1811 $documentService = $runtime->getDocumentService();
1813 return $documentService->getDocumentType($documentId);
1815 catch (\Exception $e) {}
1820 private static function getTemplateDocumentType(
int $id): ?
array
1822 $tpl = WorkflowTemplateTable::getList([
1823 'select' => [
'MODULE_ID',
'ENTITY',
'DOCUMENT_TYPE'],
1824 'filter' => [
'=ID' => $id],
1829 return [$tpl[
'MODULE_ID'], $tpl[
'ENTITY'], $tpl[
'DOCUMENT_TYPE']];
1834 private static function validateTemplateName(
$name)
1838 throw new RestException(
'Empty template name!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1842 private static function upsertAppPlacement(
int $appId,
string $code,
string $handler)
1845 '=APP_ID' => $appId,
1846 '=ADDITIONAL' =>
$code,
1847 '=PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1854 $placementHandler =
$dbRes->fetch();
1856 if ($placementHandler)
1858 $result = PlacementTable::update($placementHandler[
'ID'], [
'PLACEMENT_HANDLER' => $handler]);
1862 $placementBind =
array(
1864 'ADDITIONAL' =>
$code,
1865 'PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1866 'PLACEMENT_HANDLER' => $handler,
1869 $result = PlacementTable::add($placementBind);
1875 throw new RestException(
1876 'Unable to set placement handler: '.implode(
', ',
$errorMessage),
1877 RestException::ERROR_CORE
1882 private static function deleteAppPlacement(
int $appId,
string $code =
null)
1885 '=APP_ID' => $appId,
1886 '=PLACEMENT' => static::PLACEMENT_ACTIVITY_PROPERTIES_DIALOG,
1898 while($placementHandler =
$dbRes->fetch())
1900 PlacementTable::delete($placementHandler[
"ID"]);
1904 private static function prepareTemplateData(
$data)
1908 $fileFields = \CRestUtil::saveFile(
$data);
1912 return \Bitrix\Main\IO\File::getFileContents($fileFields[
'tmp_name']);
1915 throw new RestException(
'Incorrect field TEMPLATE_DATA!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1918 private static function validateTemplateDocumentType($documentType)
1922 $documentService = \CBPRuntime::getRuntime(
true)->getDocumentService();
1923 $documentService->getDocumentFieldTypes($documentType);
1925 catch (\CBPArgumentNullException $e)
1927 throw new RestException(
'Incorrect field DOCUMENT_TYPE!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1931 private static function validateTemplateAutoExecution($flag)
1933 if ($flag === (
string) (
int) $flag)
1935 $flag = (int) $flag;
1953 throw new RestException(
'Incorrect field AUTO_EXECUTE!', self::ERROR_TEMPLATE_VALIDATION_FAILURE);
1956 private static function generateTemplateSystemCode(\CRestServer $server)
1960 return 'rest_app_'.$appId;
1963 private static function extractEventToken($token)
1965 $data = \CBPRestActivity::extractToken($token);
1967 throw new AccessException();
1977 private static function getApp($server)
1979 if(self::$app ==
null)
1981 if (Loader::includeModule(
'rest'))
1986 '=CLIENT_ID' => $server->getClientId()
1990 self::$app =
$result->fetch();