Your IP : 18.188.23.110


Current Path : /var/www/axolotl/data/www/kirov.axolotls.ru/bitrix/modules/rpa/lib/controller/
Upload File :
Current File : /var/www/axolotl/data/www/kirov.axolotls.ru/bitrix/modules/rpa/lib/controller/item.php

<?php

namespace Bitrix\Rpa\Controller;

use Bitrix\Main\Engine\ActionFilter\Csrf;
use Bitrix\Main\Engine\Response\Component;
use Bitrix\Main\Engine\Response\BFile;
use Bitrix\Main\Error;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Type\Date;
use Bitrix\Main\Type\DateTime;
use Bitrix\Main\UI\FileInputUtility;
use Bitrix\Main\UI\PageNavigation;
use Bitrix\Main\Engine\Response\Converter;
use Bitrix\Main\Engine\Response\DataType\Page;
use Bitrix\Main\UserField\Types\DateTimeType;
use Bitrix\Rpa\Driver;
use Bitrix\Rpa\Filter\Item\Provider;
use Bitrix\Rpa\Filter\Item\Settings;
use Bitrix\Rpa\Model\ItemSortTable;
use Bitrix\Rpa\UserField\Display;
use Bitrix\Rpa\UserField\UserField;

class Item extends Base
{
	protected $uploadedFiles = [];

	public function configureActions(): array
	{
		$configureActions = parent::configureActions();
		$configureActions['getFile'] = [
			'-prefilters' => [
				Csrf::class,
			],
		];

		return $configureActions;
	}

	protected function processFields(\Bitrix\Rpa\Model\Item $item, array $fields): void
	{
		$userFieldCollection = $item->getType()->getUserFieldCollection();
		foreach($userFieldCollection as $userField)
		{
			if(!isset($fields[$userField->getName()]))
			{
				continue;
			}

			if(empty($fields[$userField->getName()]))
			{
				$item->set($userField->getName(), null);
				continue;
			}

			if($userField->isBaseTypeFile())
			{
				$this->processFileField($userField, $item, $fields);
			}
			elseif($this->getScope() === self::SCOPE_REST && $userField->isBaseTypeDate())
			{
				if($userField->getUserTypeId() === DateTimeType::USER_TYPE_ID)
				{
					$convertDateMethod = 'unConvertDateTime';
				}
				else
				{
					$convertDateMethod = 'unConvertDate';
				}
				if($userField->isMultiple())
				{
					$result = [];
					$value = $fields[$userField->getName()];
					if(!is_array($value))
					{
						$value = [$value];
					}
					foreach($value as $date)
					{
						$result[] = \CRestUtil::$convertDateMethod($date);
					}
					$item->set($userField->getName(), $result);
				}
				else
				{
					$item->set($userField->getName(), \CRestUtil::$convertDateMethod($fields[$userField->getName()]));
				}
			}
			else
			{
				$item->set($userField->getName(), $fields[$userField->getName()]);
			}
		}
	}

	protected function processFileField(UserField $userField, \Bitrix\Rpa\Model\Item $item, array $fields): void
	{
		$userFieldName = $userField->getName();
		if($userField->isMultiple())
		{
			$fileData = $fields[$userFieldName];
			if(!is_array($fileData))
			{
				return;
			}

			$result = [];
			$currentFiles = array_flip($item->get($userFieldName) ?? []);
			foreach($fileData as $file)
			{
				$fileId = (int) $file['id'];
				if($fileId > 0)
				{
					if(isset($currentFiles[$fileId]))
					{
						$result[] = $fileId;
						$this->registerFile($userField, $fileId);
					}

					continue;
				}

				$fileId = $this->uploadFile($file);
				if($fileId > 0)
				{
					$result[] = $fileId;
					$this->uploadedFiles[] = $fileId;
					$this->registerFile($userField, $fileId);
				}
			}

			$item->set($userFieldName, $result);
		}
		else
		{
			$fileData = $fields[$userFieldName];
			$currentFile = $item->get($userFieldName);
			if(isset($fileData['id']))
			{
				if((int) $fileData['id'] === $currentFile)
				{
					return;
				}
			}
			$fileId = $this->uploadFile($fileData);
			if($fileId > 0)
			{
				$this->uploadedFiles[] = $fileId;
				$this->registerFile($userField, $fileId);
			}
			$item->set($userFieldName, $fileId);
		}
	}

	protected function registerFile(UserField $userField, int $fileId): void
	{
		$fileInputUtility = FileInputUtility::instance();
		$controlId = $fileInputUtility->getUserFieldCid($userField->toArray());

		$fileInputUtility->registerControl($controlId, $controlId);
		$fileInputUtility->registerFile($controlId, $fileId);
	}

	protected function deleteUploadedFiles(): void
	{
		foreach($this->uploadedFiles as $fileId)
		{
			if($fileId > 0)
			{
				\CFile::Delete($fileId);
			}
		}
	}

	public function getAction(\Bitrix\Rpa\Model\Type $type, int $id): ?array
	{
		$item = $type->getItem($id);
		if(!$item)
		{
			$this->addError(new Error(Loc::getMessage('RPA_ITEM_NOT_FOUND_ERROR')));
			return null;
		}
		if(!Driver::getInstance()->getUserPermissions()->canViewItem($item))
		{
			$this->addError(new Error(Loc::getMessage('RPA_VIEW_ITEM_ACCESS_DENIED')));
			return null;
		}

		return [
			'item' => $this->prepareItemData($item),
		];
	}

	public function addAction(\Bitrix\Rpa\Model\Type $type, array $fields = [], string $eventId = null): ?array
	{
		$item = $type->createItem();

		$this->processFields($item, $fields);

		$command = Driver::getInstance()->getFactory()->getAddCommand($item);
		if($eventId)
		{
			$command->setPullEventId($eventId);
		}
		$result = $command->run();
		if($result->isSuccess())
		{
			$item = $command->getItem();

			return [
				'item' => $this->prepareItemData($item),
			];
		}

		$this->deleteUploadedFiles();
		$this->addErrors($result->getErrors());

		return null;
	}

	public function updateAction(\Bitrix\Rpa\Model\Type $type, int $id, array $fields, string $eventId = null): ?array
	{
		$item = $type->getItem($id);
		if(!$item)
		{
			$this->addError(new Error(Loc::getMessage('RPA_ITEM_NOT_FOUND_ERROR')));
			return null;
		}
		$previousItemId = null;
		if(isset($fields['previousItemId']))
		{
			$previousItemId = (int) $fields['previousItemId'];
		}

		$stageId = $item->getStageId();
		if(isset($fields['stageId']))
		{
			$item->setStageId($fields['stageId']);
		}
		$this->processFields($item, $fields);
		$command = Driver::getInstance()->getFactory()->getUpdateCommand($item);
		if($eventId)
		{
			$command->setPullEventId($eventId);
		}
		$result = $command->run();
		if($result->isSuccess())
		{
			$item = $command->getItem();
			if($previousItemId !== null && $item->getStageId() === $stageId)
			{
				$userId = Driver::getInstance()->getUserId();
				if($userId > 0)
				{
					$sort = $this->getSortByPreviousItemId($item, $userId, $previousItemId);
					ItemSortTable::setSortForItem($item, $userId, $sort);
				}
			}
			return [
				'item' => $this->prepareItemData($item, [
					'withDisplay' => ($this->getScope() !== self::SCOPE_REST),
					'withTasks' => true,
					'withUsers' => true,
					'withPermissions' => ($this->getScope() !== self::SCOPE_REST),
				]),
			];
		}

		$this->deleteUploadedFiles();
		$this->addErrors($result->getErrors());

		return null;
	}

	public function sortAction(\Bitrix\Rpa\Model\Type $type, int $id, int $previousItemId = 0): ?array
	{
		$item = $type->getItem($id);
		if(!$item)
		{
			$this->addError(new Error(Loc::getMessage('RPA_ITEM_NOT_FOUND_ERROR')));
			return null;
		}
		if(!Driver::getInstance()->getUserPermissions()->canViewItem($item))
		{
			$this->addError(new Error(Loc::getMessage('RPA_VIEW_ITEM_ACCESS_DENIED')));
			return null;
		}
		$userId = Driver::getInstance()->getUserId();
		if($userId > 0)
		{
			$sort = $this->getSortByPreviousItemId($item, $userId, $previousItemId);
			$result = ItemSortTable::setSortForItem($item, $userId, $sort);
			if($result->isSuccess())
			{
				return [
					'item' => $this->prepareItemData($item),
				];
			}

			$this->addErrors($result->getErrors());
			return null;
		}

		return null;
	}

	public function listAction(
		\Bitrix\Rpa\Model\Type $type,
		array $order = null,
		array $filter = null,
		PageNavigation $pageNavigation = null
	): ?Page
	{
		if(!Driver::getInstance()->getUserPermissions()->canViewType($type->getId()))
		{
			$this->addError(new Error(Loc::getMessage('RPA_COMMON_TYPE_VIEW_ACCESS_DENIED')));
			return null;
		}
		$parameters = [];
		$parameters['filter'] = $this->removeDotsFromKeys($this->prepareFilter($type, $filter));
		$converter = new Converter(Converter::TO_UPPER | Converter::KEYS | Converter::TO_SNAKE);
		if(is_array($order))
		{
			$parameters['order'] = $converter->process($order);
		}
		$parameters['select'] = ['*'];

		if($pageNavigation)
		{
			$parameters['offset'] = $pageNavigation->getOffset();
			$parameters['limit'] = $pageNavigation->getLimit();
		}

		$result = [];
		$items = $type->getItems($parameters);
		foreach($items as $item)
		{
			$result[] = $this->prepareItemData($item, [
				'withDisplay' => false,
				'withTasks' => false,
				'withUsers' => false,
				'withPermissions' => false,
			]);
		}

		return new Page('items', $result, static function() use ($parameters, $type)
		{
			return $type->getItemsCount($parameters['filter']);
		});
	}

	protected function prepareFilter(\Bitrix\Rpa\Model\Type $type, array $filter = null): array
	{
		if(empty($filter))
		{
			return Driver::getInstance()->getUserPermissions()->getFilterForViewableItems($type);
		}

		$converter = new Converter(Converter::TO_UPPER | Converter::TO_SNAKE);
		$logic = null;
		$tasks = null;
		foreach($filter as $name => $value)
		{
			if($name === 'logic')
			{
				$logic = $value;
				unset($filter[$name]);
				continue;
			}
			if($name === 'tasks')
			{
				$tasks = $value;
				unset($filter[$name]);
				continue;
			}
			if(is_numeric($name))
			{
				$filter[$name] = $this->prepareFilter($type, $filter[$name]);
			}
			elseif(strpos($name, 'UF_RPA_') === false)
			{
				$nameCamel = $converter->process($name);
				$filter[$nameCamel] = $filter[$name];
				unset($filter[$name]);
			}
		}
		if($logic)
		{
			$filter = array_merge(['LOGIC' => $logic], $filter);
		}
		if($tasks)
		{
			$settings = new Settings([
				'ID' => $this->getScope().'_list',
			], $type);

			$itemProvider = new Provider($settings);
			$itemProvider->processTasksFilter($tasks, $filter);
		}

		if($this->getScope() === self::SCOPE_REST)
		{
			$this->prepareDateTimeFieldsForFilter($filter, $this->getItemDateTimeFieldNames($type));
		}

		return [
			$filter,
			Driver::getInstance()->getUserPermissions()->getFilterForViewableItems($type),
		];
	}

	public function deleteAction(\Bitrix\Rpa\Model\Type $type, $id): void
	{
		$item = $type->getItem($id);
		if(!$item)
		{
			$this->addError(new Error('Item of type '.$type->getName().' with id '.$id.' is not found'));
			return;
		}
		$command = Driver::getInstance()->getFactory()->getDeleteCommand($item);
		$result = $command->run();
		if(!$result->isSuccess())
		{
			$this->addErrors($result->getErrors());
		}
	}

	public function getEditorAction(int $typeId, int $id, int $stageId = null, string $eventId = null): Component
	{
		return new Component('bitrix:rpa.item.editor', '', [
			'typeId' => $typeId,
			'id' => $id,
			'stageId' => $stageId,
			'isEmbedded' => true,
			'eventId' => $eventId,
		]);
	}

	public function prepareItemData(\Bitrix\Rpa\Model\Item $item, array $params = []): array
	{
		$withDisplay = $params['withDisplay'] ?? false;
		$withTasks = $params['withTasks'] ?? true;
		$withPermissions = $params['withPermissions'] ?? true;
		$withUsers = $params['withUsers'] ?? true;

		$userPermissions = Driver::getInstance()->getUserPermissions();
		$canModifyItemsInStage = $userPermissions->canModifyItemsInStage($item->getType(), $item->getStageId());
		$canMoveFromStage = $userPermissions->canMoveFromStage($item->getType(), $item->getStageId());
		$canMoveToStage = $userPermissions->canMoveToStage($item->getStage());

		$data = [];
		$data['id'] = $item->getId();
		$data['stageId'] = $item->getStageId();
		$data['previousStageId'] = $item->getPreviousStageId();
		$data['name'] = $item->getName();
		$data['typeId'] = $item->getType()->getId();
		$data['createdBy'] = $item->getCreatedBy();
		$data['updatedBy'] = $item->getUpdatedBy();
		$data['movedBy'] = $item->getMovedBy();
		$data['createdTime'] = $this->prepareDateTimeValue($item->getCreatedTime());
		$data['updatedTime'] = $item->getUpdatedTime() ? $this->prepareDateTimeValue($item->getUpdatedTime()) : null;
		$data['movedTime'] = $item->getMovedTime() ? $this->prepareDateTimeValue($item->getMovedTime()) : null;
		$data['detailUrl'] = Driver::getInstance()->getUrlManager()->getItemDetailUrl(
			$item->getType()->getId(),
			$item->getId()
		);

		if($item->getStage())
		{
			$userFieldCollection = $item->getStage()->getUserFieldCollection();
		}
		else
		{
			$userFieldCollection = $item->getType()->getUserFieldCollection();
		}
		if(
			$canModifyItemsInStage
			|| $canMoveFromStage
			|| ($canMoveToStage && $item->getMovedBy() === $userPermissions->getUserId())
		)
		{
			foreach($userFieldCollection as $userField)
			{
//				if($userField->isVisible())
//				{
					$value = $this->prepareValue($userField, $item);
					$data[$userField->getName()] = $value;
//				}
			}
		}

		if($withPermissions)
		{
			$hasEmptyNotEditableMandatoryFields = false;
			if(!$canModifyItemsInStage)
			{
				foreach($userFieldCollection as $userField)
				{
					if(
						$userField->isMandatory() &&
						$item->isEmptyUserFieldValue($userField->getName()) &&
						(!$userField->isVisible() || !$userField->isEditable())
					)
					{
						$hasEmptyNotEditableMandatoryFields = true;
						break;
					}
				}
			}
			$data['permissions'] = [
				'draggable' => (
					($canMoveFromStage && !$hasEmptyNotEditableMandatoryFields) ||
					($canMoveToStage && $item->getMovedBy() === $userPermissions->getUserId())
				),
				'droppable' => ($canModifyItemsInStage || $canMoveFromStage || $canMoveToStage),
				'canDelete' => $userPermissions->canDeleteItem($item),
			];
		}

		if($withTasks)
		{
			$data['tasksCounter'] = 0;
			$data['tasksFaces'] = [];
			if ($item->getId())
			{
				$taskManager = Driver::getInstance()->getTaskManager();
				if($taskManager)
				{
					$data['tasksCounter'] = $taskManager->getUserItemIncompleteCounter($item);
					$data['tasksFaces'] = $taskManager->getItemFaces($item->getType()->getId(), $item->getId());
				}
			}
		}

		if($withDisplay)
		{
			$display = new Display($item->getType(), [
				$item->getId() => $data,
			]);
			$data['display'] = $display->getValues($item->getId());
		}

		if($withUsers)
		{
			$userIds = $item->getUserIds();

			if(isset($data['tasksFaces']['all']) && is_array($data['tasksFaces']['all']))
			{
				$userIds = array_merge($userIds, $data['tasksFaces']['all']);
			}

			$data['users'] = \Bitrix\Rpa\Components\Base::getUsers($userIds);
		}

		return $data;
	}

	protected function prepareValue(UserField $userField, \Bitrix\Rpa\Model\Item $item)
	{
		$value = $item->get($userField->getName());

		if(is_object($value))
		{
			if($value instanceof Date)
			{
				return $value;
			}
			if(class_exists($value) && method_exists($value, '__toString'))
			{
				return (string) $value;
			}

			return null;
		}

		if($userField->isBaseTypeFile() && $this->getScope() === self::SCOPE_REST)
		{
			if(is_array($value) && $userField->isMultiple())
			{
				foreach($value as &$file)
				{
					if($file > 0)
					{
						$file = [
							'id' => $file,
							'url' => Driver::getInstance()->getUrlManager()->getFileUrl($item->getType()->getId(), $item->getId(), $userField->getName(), $file),
						];
					}
				}
			}
			elseif($value > 0)
			{
				$value = [
					'id' => $value,
					'url' => Driver::getInstance()->getUrlManager()->getFileUrl($item->getType()->getId(), $item->getId(), $userField->getName(), $value),
				];
			}
		}

		return $value;
	}

	public function getSortByPreviousItemId(\Bitrix\Rpa\Model\Item $item, int $userId, int $previousItemId = 0): int
	{
		return ItemSortTable::getSort($userId, $item->getType(), $item->getStageId(), $previousItemId);
	}

	protected function getItemDateTimeFieldNames(\Bitrix\Rpa\Model\Type $type): array
	{
		$fields = ['CREATED_TIME', 'UPDATED_TIME', 'MOVED_TIME'];
		foreach($type->getUserFieldCollection() as $userField)
		{
			if($userField->isBaseTypeDate())
			{
				$fields[] = $userField->getName();
			}
		}

		return $fields;
	}

	public function getFileAction(\Bitrix\Rpa\Model\Type $type, int $id, string $fieldName, int $file_id): ?BFile
	{
		$item = $type->getItem($id);
		if(!$item)
		{
			$this->addError(new Error(Loc::getMessage('RPA_ITEM_NOT_FOUND_ERROR')));
			return null;
		}
		if(!Driver::getInstance()->getUserPermissions()->canViewItem($item))
		{
			$this->addError(new Error(Loc::getMessage('RPA_VIEW_ITEM_ACCESS_DENIED')));
			return null;
		}

		$value = $item->get($fieldName);
		if(
			($value === $file_id)
			||
			(is_array($value) && in_array($file_id, $value))
		)
		{
			return BFile::createByFileId($file_id);
		}

		return null;
	}

	public function getTasksAction(\Bitrix\Rpa\Model\Type $type, int $id): ?array
	{
		$item = $type->getItem($id);
		if(!$item)
		{
			$this->addError(new Error(Loc::getMessage('RPA_ITEM_NOT_FOUND_ERROR')));
			return null;
		}
		if(!Driver::getInstance()->getUserPermissions()->canViewItem($item))
		{
			$this->addError(new Error(Loc::getMessage('RPA_VIEW_ITEM_ACCESS_DENIED')));
			return null;
		}

		$taskManager = Driver::getInstance()->getTaskManager();
		if(!$taskManager)
		{
			return null;
		}

		return [
			'tasks' => $taskManager->getTimelineTasks($item)
		];
	}
}