403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/ui/lib/entityform/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/ui/lib/entityform/scope.php
<?php

namespace Bitrix\Ui\EntityForm;

use Bitrix\HumanResources\Enum\DepthLevel;
use Bitrix\HumanResources\Service\Container;
use Bitrix\Main\Access\AccessCode;
use Bitrix\Main\Application;
use Bitrix\Main\Engine\CurrentUser;
use Bitrix\Main\Error;
use Bitrix\Main\Event;
use Bitrix\Main\Loader;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ORM\Data\DeleteResult;
use Bitrix\Main\ORM\Data\UpdateResult;
use Bitrix\Main\ORM\Query\Query;
use Bitrix\Main\Result;
use Bitrix\Main\Text\HtmlFilter;
use Bitrix\Main\UI\AccessRights\DataProvider;
use Bitrix\Socialnetwork\UserToGroupTable;
use Bitrix\UI\Form\EntityEditorConfigScope;
use CAccess;
use CUserOptions;

/**
 * Class Scope
 * @package Bitrix\Ui\EntityForm
 */
class Scope
{
	protected const CODE_USER = 'U';
	protected const CODE_PROJECT = 'SG';
	protected const CODE_DEPARTMENT   = 'DR';

	protected const TYPE_USER = 'user';
	protected const TYPE_PROJECT = 'project';
	protected const TYPE_DEPARTMENT = 'department';

	protected static array $instances = [];
	private static array $userScopeIdsCache = [];

	public function __construct(
		private readonly int $userId,
	)
	{
	}

	public static function getInstance(?int $userId = null): static
	{
		if ($userId === null || $userId <= 0)
		{
			$userId = (int)CurrentUser::get()->getId();
		}

		if (!isset(static::$instances[$userId]))
		{
			Loader::includeModule('ui');
			static::$instances[$userId] = new static($userId);
		}

		return static::$instances[$userId];
	}

	/**
	 * @param string $entityTypeId
	 * @param string|null $moduleId
	 * @return array
	 */
	public function getUserScopes(string $entityTypeId, ?string $moduleId = null, bool $loadMetadata = true): array
	{
		return $this->getScopes($entityTypeId, $moduleId, $loadMetadata);
	}

	public function getAllUserScopes(string $entityTypeId, ?string $moduleId = null, bool $loadMetadata = true): array
	{
		return $this->getScopes($entityTypeId, $moduleId, false, $loadMetadata);
	}

	private function getScopes(
		string $entityTypeId,
		?string $moduleId = null,
		bool $excludeEmptyAccessCode = true,
		bool $loadMetadata = true,
	): array
	{
		static $results = [];
		$key = $entityTypeId . '-' . $moduleId . '-' . ($loadMetadata ? 'Y' : 'N');

		if (!isset($results[$key]))
		{
			$result = [];
			$isAdminForEntity = $moduleId
				&& (
					($scopeAccess = ScopeAccess::getInstance($moduleId, $this->userId))
					&& $scopeAccess->isAdminForEntityTypeId($entityTypeId)
				);

			if (!$isAdminForEntity)
			{
				$filter['@ID'] = $this->getScopesIdByUser();
			}

			$filter['@ENTITY_TYPE_ID'] = ($this->getEntityTypeIdMap()[$entityTypeId] ?? [$entityTypeId]);

			if ($excludeEmptyAccessCode)
			{
				$filter['!=ACCESS_CODE'] = '';
			}

			if ($isAdminForEntity || !empty($filter['@ID']))
			{
				$scopes = EntityFormConfigTable::getList([
					'select' => [
						'ID',
						'NAME',
						'AUTO_APPLY_SCOPE',
						'ACCESS_CODE' => '\Bitrix\Ui\EntityForm\EntityFormConfigAcTable:CONFIG.ACCESS_CODE',
					],
					'filter' => $filter,
				]);

				foreach ($scopes as $scope)
				{
					$result[$scope['ID']]['NAME'] = HtmlFilter::encode($scope['NAME']);
					$result[$scope['ID']]['AUTO_APPLY_SCOPE'] = $scope['AUTO_APPLY_SCOPE'];
					if (
						$loadMetadata
						&& !isset($result[$scope['ID']]['ACCESS_CODES'][$scope['ACCESS_CODE']])
						&& isset($scope['ACCESS_CODE'])
					)
					{
						$accessCode = new AccessCode($scope['ACCESS_CODE']);
						$member = (new DataProvider())->getEntity(
							$accessCode->getEntityType(),
							$accessCode->getEntityId()
						);
						$result[$scope['ID']]['ACCESS_CODES'][$scope['ACCESS_CODE']] = $scope['ACCESS_CODE'];
						$result[$scope['ID']]['MEMBERS'][$scope['ACCESS_CODE']] = $member->getMetaData();
					}
				}
			}

			$results[$key] = $result;
		}

		return $results[$key];
	}

	/**
	 * This method must return entityTypeId values that correspond to a single CRM entity only.
	 */
	protected function getEntityTypeIdMap(): array
	{
		return [
			'lead_details' => ['lead_details', 'returning_lead_details'],
			'returning_lead_details' => ['lead_details', 'returning_lead_details'],
		];
	}

	/**
	 * @param int $scopeId
	 * @return bool
	 */
	public function isHasScope(int $scopeId): bool
	{
		return in_array($scopeId, $this->getScopesIdByUser());
	}

	protected function getUserId(): int
	{
		return $this->userId;
	}

	private function getScopesIdByUser(): array
	{
		if (isset(self::$userScopeIdsCache[$this->getUserId()]))
		{
			return self::$userScopeIdsCache[$this->getUserId()];
		}

		$accessCodes = $this->getCurrentUserAccessCodes();
		$this->prepareAccessCodes($accessCodes);

		$params = [
			'select' => [
				'CONFIG_ID',
			],
			'filter' => [
				'@ACCESS_CODE' => $accessCodes,
			],
		];

		$scopes = EntityFormConfigAcTable::getList($params)->fetchAll();
		$scopesIds = array_unique(array_column($scopes, 'CONFIG_ID'));

		self::$userScopeIdsCache[$this->getUserId()] = $scopesIds;

		return self::$userScopeIdsCache[$this->getUserId()];
	}

	protected function prepareAccessCodes(array &$accessCodes): void
	{
		$accessCodes = array_filter($accessCodes, static fn($code) => mb_strpos($code, 'CHAT') !== 0);

		foreach ($accessCodes as &$accessCode)
		{
			$accessCode = preg_replace('|^(SG\d*?)(_[K,A,M])$|', '$1', $accessCode);
		}
		unset($accessCode);
	}

	/**
	 * @param int $scopeId
	 * @return array|null
	 */
	public function getScopeById(int $scopeId): ?array
	{
		if ($row = EntityFormConfigTable::getRowById($scopeId))
		{
			return (is_array($row['CONFIG']) ? $row['CONFIG'] : null);
		}
		return null;
	}

	/**
	 * @param int $scopeId
	 * @return array|null
	 */
	public function getById(int $scopeId): ?array
	{
		return EntityFormConfigTable::getRowById($scopeId);
	}

	/**
	 * @param iterable $ids
	 * @throws \Exception
	 */
	public function removeByIds(iterable $ids): void
	{
		foreach ($ids as $id)
		{
			$this->removeById($id);
		}
	}

	/**
	 * @param int $id
	 * @return DeleteResult
	 */
	private function removeById(int $id): DeleteResult
	{
		$this->removeScopeMembers($id);
		return EntityFormConfigTable::delete($id);
	}

	/**
	 * Set user option with config scope type and scopeId if selected custom scope
	 * @param string $categoryName
	 * @param string $guid
	 * @param string $scope
	 * @param int $userScopeId
	 */
	public function setScope(string $categoryName, string $guid, string $scope, int $userScopeId = 0, ?int $userId = null): void
	{
		$this->setScopeToUser($categoryName, $guid, $scope, $userScopeId, $userId);
	}

	public function setScopeConfig(
		string $category,
		string $entityTypeId,
		string $name,
		array $accessCodes,
		array $config,
		array $params = []
	)
	{
		if (empty($name))
		{
			$errors['name'] = new Error(Loc::getMessage('FIELD_REQUIRED'));
		}
		if (empty($accessCodes))
		{
			$errors['accessCodes'] = new Error(Loc::getMessage('FIELD_REQUIRED'));
		}
		if (empty($params['categoryName']))
		{
			$errors['categoryName'] = new Error(Loc::getMessage('FIELD_REQUIRED'));
		}
		if (!empty($errors))
		{
			return $errors;
		}

		$this->formatAccessCodes($accessCodes);

		$result = EntityFormConfigTable::add([
			'CATEGORY' => $category,
			'ENTITY_TYPE_ID' => $entityTypeId,
			'NAME' => $name,
			'CONFIG' => $config,
			'COMMON' => ($params['common'] ?? 'Y'),
			'AUTO_APPLY_SCOPE' => ($params['forceSetToUsers'] ?? 'N'),
			'OPTION_CATEGORY' => $params['categoryName']
		]);

		if ($result->isSuccess())
		{
			$configId = $result->getId();
			foreach ($accessCodes as $ac)
			{
				EntityFormConfigAcTable::add([
					'ACCESS_CODE' => $ac['id'],
					'CONFIG_ID' => $configId,
				]);
			}

			$forceSetToUsers = ($params['forceSetToUsers'] ?? false);
			if (mb_strtoupper($forceSetToUsers) === 'FALSE')
			{
				$forceSetToUsers = false;
			}

			Application::getInstance()->addBackgroundJob(
				static fn() => Scope::getInstance()->forceSetScopeToUsers($accessCodes, [
					'forceSetToUsers' => $forceSetToUsers,
					'categoryName' => ($params['categoryName'] ?? ''),
					'entityTypeId' => $entityTypeId,
					'configId' => $configId,
				])
			);

			return $configId;
		}

		return $result->getErrors();
	}

	/**
	 * @param array $accessCodes
	 */
	protected function formatAccessCodes(array &$accessCodes): void
	{
		foreach ($accessCodes as $key => $item)
		{
			if ($item['entityId'] === self::TYPE_USER)
			{
			$accessCodes[$key]['id'] = self::CODE_USER . (int)$accessCodes[$key]['id'];
			}
			elseif ($item['entityId'] === self::TYPE_DEPARTMENT)
			{
				$accessCodes[$key]['id'] = self::CODE_DEPARTMENT . (int)$accessCodes[$key]['id'];
			}
			elseif ($item['entityId'] === self::TYPE_PROJECT)
			{
				$accessCodes[$key]['id'] = self::CODE_PROJECT . (int)$accessCodes[$key]['id'];
			}
			else{
				unset($accessCodes[$key]);
			}
		}
	}

	/**
	 * @param array $accessCodes
	 * @param array $params
	 */
	protected function forceSetScopeToUsers(array $accessCodes = [], array $params = []): void
	{
		if ($params['forceSetToUsers'] && $params['categoryName'])
		{
			$codes = [];
			foreach ($accessCodes as $ac)
			{
				$codes[] = $ac['id'];
			}
			$this->setScopeByAccessCodes(
				$params['categoryName'],
				$params['entityTypeId'],
				EntityEditorConfigScope::CUSTOM,
				(int)$params['configId'],
				$codes
			);
		}
	}

	/**
	 * @param string $categoryName
	 * @param string $guid
	 * @param string $scope
	 * @param int $userScopeId
	 * @param int|null $userId
	 */
	protected function setScopeToUser(
		string $categoryName,
		string $guid,
		string $scope,
		int $userScopeId,
		?int $userId = null
	): void
	{
		$scope = (isset($scope) ? strtoupper($scope) : EntityEditorConfigScope::UNDEFINED);

		if (EntityEditorConfigScope::isDefined($scope))
		{
			if ($scope === EntityEditorConfigScope::CUSTOM && $userScopeId)
			{
				$value = [
					'scope' => $scope,
					'userScopeId' => $userScopeId,
				];
			}
			else
			{
				$value = $scope;
			}

			$userId = ($userId ?? false);
			CUserOptions::SetOption($categoryName, "{$guid}_scope", $value, false, $userId);
		}
	}

	public function updateScopeConfig(int $id, array $config)
	{
		return EntityFormConfigTable::update($id, [
			'CONFIG' => $config,
		]);
	}

	public function updateScopeName(int $id, string $name): UpdateResult
	{
		return EntityFormConfigTable::update($id, [
			'NAME' => $name,
		]);
	}

	/**
	 * @param int $configId
	 * @param array $accessCodes
	 * @return array
	 */
	public function updateScopeAccessCodes(int $configId, array $accessCodes = []): array
	{
		$this->removeScopeMembers($configId);
		$this->addAccessCodes($configId, $accessCodes);

		return $this->getScopeMembers($configId);
	}

	public function addAccessCodes(int $configId, array $accessCodes): Result
	{
		$accessCodeCollection = EntityFormConfigAcTable::createCollection();
		foreach ($accessCodes as $accessCode => $type)
		{
			$accessCodeItem = EntityFormConfigAcTable::createObject()
				->setAccessCode($accessCode)
				->setConfigId($configId);

			$accessCodeCollection->add($accessCodeItem);
		}

		return $accessCodeCollection->save(true);
	}

	/**
	 * @param int $configId
	 * @return array
	 */
	public function getScopeMembers(int $configId): array
	{
		$accessCodes = EntityFormConfigAcTable::getList([
			'select' => ['ACCESS_CODE'],
			'filter' => ['=CONFIG_ID' => $configId],
		])->fetchAll();
		$result = [];
		if (count($accessCodes))
		{
			foreach ($accessCodes as $accessCodeEntity)
			{
				$accessCode = new AccessCode($accessCodeEntity['ACCESS_CODE']);
				$member = (new DataProvider())->getEntity($accessCode->getEntityType(), $accessCode->getEntityId());
				$result[$accessCodeEntity['ACCESS_CODE']] = $member->getMetaData();
			}
		}
		return $result;
	}

	/**
	 * @param int $configId
	 */
	private function removeScopeMembers(int $configId): void
	{
		$entity = EntityFormConfigAcTable::getEntity();
		$connection = $entity->getConnection();

		$filter = ['CONFIG_ID' => $configId];

		$connection->query(sprintf(
			'DELETE FROM %s WHERE %s',
			$connection->getSqlHelper()->quote($entity->getDBTableName()),
			Query::buildFilterSql($entity, $filter)
		));
	}

	public function updateScopeAutoApplyScope(int $id, bool $autoApplyScope): UpdateResult
	{
		return EntityFormConfigTable::update($id, [
			'AUTO_APPLY_SCOPE' => $autoApplyScope ? 'Y' : 'N',
		]);
	}

	private function setScopeToDepartment(
		string $categoryName,
		string $guid,
		string $scope,
		int $userScopeId,
		int $departmentId
	): void
	{
		$userIds = $this->getUserIdsByDepartment($departmentId);
		foreach ($userIds as $userId)
		{
			$this->setScopeToUser($categoryName, $guid, $scope, $userScopeId, $userId);
		}
	}

	private function setScopeToSocialGroup(
		string $categoryName,
		string $guid,
		string $scope,
		int $userScopeId,
		int $socialGroupId
	): void
	{
		$userIds = $this->getUserIdsBySocialGroup($socialGroupId);
		foreach ($userIds as $userId)
		{
			$this->setScopeToUser($categoryName, $guid, $scope, $userScopeId, $userId);
		}
	}

	public static function handleMemberAddedToDepartment(Event $event): void
	{
		Application::getInstance()->addBackgroundJob(static function() use ($event)
		{
			$member = $event->getParameter('member');

			$memberId = $member->entityId;
			$departmentId = $member->nodeId;
			$scopeType = EntityEditorConfigScope::CUSTOM;
			$scopes = Scope::getInstance()->getScopesByDepartment($departmentId, true);

			$appliedEntities = [];
			foreach ($scopes as $scope)
			{
				if (!in_array($scope->getEntityTypeId(), $appliedEntities))
				{
					$appliedEntities[] = $scope->getEntityTypeId();
					Scope::getInstance()->setScopeToUser(
						$scope->getOptionCategory(),
						$scope->getEntityTypeId(),
						$scopeType,
						$scope->getId(),
						$memberId
					);
				}
			}
		});
	}

	public static function handleMemberAddedToSocialGroup(int $id, array $fields): void
	{
		Application::getInstance()->addBackgroundJob(static function() use ($id, $fields)
		{
			if (!\Bitrix\Main\Loader::includeModule('socialnetwork'))
			{
				return;
			}

			if (empty($fields['ROLE']) && $fields['ROLE'] !== UserToGroupTable::ROLE_USER)
			{
				return;
			}

			if (empty($fields['USER_ID']) || empty($fields['GROUP_ID']))
			{
				$userToGroup = UserToGroupTable::getById($id)->fetchObject();

				if (!$userToGroup)
				{
					return;
				}

				$memberId = $userToGroup->getUserId();
				$socialGroupId = $userToGroup->getGroupId();
			}
			else
			{
				$memberId = $fields['USER_ID'];
				$socialGroupId = $fields['GROUP_ID'];
			}

			$scopeType = EntityEditorConfigScope::CUSTOM;
			$scopes = Scope::getInstance()->getScopesBySocialGroupId($socialGroupId, true);

			$appliedEntities = [];
			foreach ($scopes as $scope)
			{
				if (!in_array($scope->getEntityTypeId(), $appliedEntities))
				{
					$appliedEntities[] = $scope->getEntityTypeId();
					Scope::getInstance()->setScopeToUser(
						$scope->getOptionCategory(),
						$scope->getEntityTypeId(),
						$scopeType,
						$scope->getId(),
						$memberId
					);
				}
			}
		});
	}

	private function getScopesByDepartment(int $departmentId, bool $onlyAutoApplyView = false): array
	{
		$accessCodes = [];
		$nodeRepository = Container::getNodeRepository();
		$node = $nodeRepository->getById($departmentId);
		if (!$node)
		{
			return $accessCodes;
		}

		$parentNodes = $nodeRepository->getParentOf($node, DepthLevel::FULL);
		foreach ($parentNodes as $node)
		{
			$accessCode = str_replace('D', 'DR', $node->accessCode);
			$accessCodes = array_merge($accessCodes, $this->getScopesByAccessCode($accessCode, $onlyAutoApplyView));
		}

		return $accessCodes;
	}

	private function getScopesBySocialGroupId(int $socialGroupId, bool $onlyAutoApplyView = false): array
	{
		$accessCode = 'SG' . $socialGroupId;

		return $this->getScopesByAccessCode($accessCode, $onlyAutoApplyView);
	}

	private function getScopesByAccessCode(string $accessCode, bool $onlyAutoApplyView = false)
	{
		$filter = ['=ACCESS_CODE' => $accessCode];
		if ($onlyAutoApplyView)
		{
			$filter['=CONFIG.AUTO_APPLY_SCOPE'] = 'Y';
		}

		$scopes = EntityFormConfigAcTable::query()
			->setSelect(['ACCESS_CODE', 'CONFIG'])
			->setFilter($filter)
			->setOrder(['CONFIG.ID' => 'DESC'])
			->fetchCollection();

		return $scopes->getConfigList();
	}

	public function setScopeForEligibleUsers(int $scopeId): void
	{
		$scope = EntityFormConfigTable::getById($scopeId)->fetchObject();

		if (!$scope)
		{
			return;
		}

		$accessCodes = $this->getScopeAccessCodesByScopeId($scopeId);

		$this->setScopeByAccessCodes(
			$scope->getOptionCategory(),
			$scope->getEntityTypeId(),
			EntityEditorConfigScope::CUSTOM,
			$scopeId,
			$accessCodes
		);
	}

	public function getScopeAccessCodesByScopeId(int $scopeId): array
	{
		$accessCodes = EntityFormConfigAcTable::query()
			->setSelect(['ACCESS_CODE'])
			->setFilter(['=CONFIG_ID' => $scopeId])
			->fetchCollection();
		$result = [];
		foreach ($accessCodes as $code)
		{
			$result[] = $code->getAccessCode();
		}

		return $result;
	}

	private function setScopeByAccessCodes(
		string $categoryName,
		string $entityTypeId,
		string $scope,
		int    $scopeId,
		array  $accessCodes
	): void
	{
		$userIdPattern = '/^U(\d+)$/';
		$departmentIdPattern = '/^DR(\d+)$/';
		$socialGroupIdPattern = '/^SG(\d+)$/';
		foreach ($accessCodes as $accessCode)
		{
			$matches = [];
			if (preg_match($userIdPattern, $accessCode, $matches))
			{
				$this->setScopeToUser(
					$categoryName,
					$entityTypeId,
					$scope,
					$scopeId,
					$matches[1]
				);
			}
			elseif (preg_match($departmentIdPattern, $accessCode, $matches))
			{
				$this->setScopeToDepartment(
					$categoryName,
					$entityTypeId,
					$scope,
					$scopeId,
					$matches[1]
				);
			}
			elseif (preg_match($socialGroupIdPattern, $accessCode, $matches))
			{
				$this->setScopeToSocialGroup(
					$categoryName,
					$entityTypeId,
					$scope,
					$scopeId,
					$matches[1]
				);
			}
		}
	}

	private function getUserIdsBySocialGroup(int $socialGroupId): array
	{
		if (!\Bitrix\Main\Loader::includeModule('socialnetwork'))
		{
			return [];
		}


		$userCollection = UserToGroupTable::query()
			->setSelect(['USER_ID'])
			->setFilter([
				'=GROUP_ID' => $socialGroupId,
				'@ROLE' => [
					UserToGroupTable::ROLE_MODERATOR,
					UserToGroupTable::ROLE_USER,
					UserToGroupTable::ROLE_OWNER,
				]
			])
			->fetchCollection();

		$userIds = [];
		foreach ($userCollection as $user)
		{
			$userIds[] = $user->getUserId();
		}

		return $userIds;
	}

	private function getUserIdsByDepartment(int $departmentId): array
	{
		$userIds = [];
		if (!\Bitrix\Main\Loader::includeModule('humanresources'))
		{
			return $userIds;
		}

		$hrServiceLocator = Container::instance();
		$accessCode = 'DR' . $departmentId;
		$node = $hrServiceLocator::getNodeRepository()->getByAccessCode($accessCode);
		if (!$node)
		{
			return $userIds;
		}

		$allEmp = $hrServiceLocator::getNodeMemberService()->getAllEmployees($node->id, true);
		foreach ($allEmp->getIterator() as $emp)
		{
			$userIds[] = $emp->entityId;
		}

		return $userIds;
	}

	private function getCurrentUserAccessCodes(): array
	{
		return CAccess::GetUserCodesArray($this->userId);
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit