protected function buildForEntity(Collection $attributes, Options $options, string $permEntity): string
{
$entityListAttributes = $attributes->getByEntityType($permEntity);
$scopeRegex = $this->getScopeRegexForEntity($permEntity);
$enableCumulativeMode = \COption::GetOptionString('crm', 'enable_permission_cumulative_mode', 'Y') === 'Y';
$userAccessAttributes = \Bitrix\Crm\Service\Container::getInstance()
->getUserPermissions($attributes->getUserId())
->getAttributesProvider()
->getUserAttributes()
;
$intranetAttrs = [];
$allIntranetAttrs =
isset($userAccessAttributes['INTRANET']) && is_array($userAccessAttributes['INTRANET'])
? $userAccessAttributes['INTRANET']
: [];
if (!empty($allIntranetAttrs))
{
foreach ($allIntranetAttrs as $attr)
{
if (preg_match('/^D\d+$/', $attr))
{
$intranetAttrs[] = "'{$attr}'";
}
}
}
$subIntranetAttrs = [];
$allSubIntranetAttrs =
isset($userAccessAttributes['SUBINTRANET']) && is_array($userAccessAttributes['SUBINTRANET'])
? $userAccessAttributes['SUBINTRANET']
: [];
if (!empty($allSubIntranetAttrs))
{
foreach ($allSubIntranetAttrs as $attr)
{
if (preg_match('/^D\d+$/', $attr))
{
$subIntranetAttrs[] = "'{$attr}'";
}
}
}
$permissionSets = [];
foreach ($entityListAttributes as &$attrs)
{
if (empty($attrs))
{
continue;
}
$permissionSet = [
'USER' => '',
'CONCERNED_USER' => '',
'DEPARTMENTS' => [],
'OPENED_ONLY' => '',
'SCOPES' => [],
];
$qty = count($attrs);
for ($i = 0; $i < $qty; $i++)
{
$attr = $attrs[$i];
if ($scopeRegex !== '' && preg_match($scopeRegex, $attr))
{
$permissionSet['SCOPES'][] = "'{$attr}'";
}
elseif ($attr === 'O')
{
$permissionSet['OPENED_ONLY'] = "'{$attr}'";
}
elseif (preg_match('/^U\d+$/', $attr))
{
$permissionSet['USER'] = "'{$attr}'";
$permissionSet['CONCERNED_USER'] = "'C{$attr}'";
}
elseif (preg_match('/^D\d+$/', $attr))
{
$permissionSet['DEPARTMENTS'][] = "'{$attr}'";
}
}
if (empty($permissionSet['SCOPES']))
{
if ($permissionSet['OPENED_ONLY'] !== '')
{
//HACK: for OPENED ONLY mode - allow user own entities too.
$userAttr = isset($userAccessAttributes['USER']) && is_array($userAccessAttributes['USER']) && !empty($userAccessAttributes['USER']) ? $userAccessAttributes['USER'][0] : '';
if ($userAttr !== '')
{
$permissionSets[] = [
'USER' => "'{$userAttr}'",
'CONCERNED_USER' => "'C{$userAttr}'",
'DEPARTMENTS' => [],
'OPENED_ONLY' => '',
'SCOPES' => [],
];
}
if ($enableCumulativeMode && !empty($intranetAttrs))
{
//OPENED ONLY mode - allow user department entities too.
$permissionSets[] = [
'USER' => '',
'CONCERNED_USER' => '',
'DEPARTMENTS' => array_unique(array_merge($intranetAttrs, $subIntranetAttrs)),
'OPENED_ONLY' => '',
'SCOPES' => [],
];
}
}
$permissionSets[] = &$permissionSet;
unset($permissionSet);
}
else
{
$permissionSet = $this->registerPermissionSet($permissionSets, $permissionSet);
if ($permissionSet['OPENED_ONLY'] !== '')
{
//HACK: for OPENED ONLY mode - allow user own entities too.
$userAttr = isset($userAccessAttributes['USER']) && is_array($userAccessAttributes['USER']) && !empty($userAccessAttributes['USER']) ? $userAccessAttributes['USER'][0] : '';
if ($userAttr !== '')
{
$this->registerPermissionSet(
$permissionSets,
[
'USER' => "'{$userAttr}'",
'CONCERNED_USER' => "'C{$userAttr}'",
'DEPARTMENTS' => [],
'OPENED_ONLY' => '',
'SCOPES' => $permissionSet['SCOPES'],
]
);
}
}
}
}
unset($attrs);
$isRestricted = false;
$subQueries = [];
$effectiveEntityIDs = $options->getLimitByIds();
$aliasPrefix = $options->getAliasPrefix();
foreach ($permissionSets as &$permissionSet)
{
$scopes = $permissionSet['SCOPES'];
$scopeQty = count($scopes);
if ($scopeQty === 0)
{
$restrictions = [];
if ($permissionSet['OPENED_ONLY'] !== '')
{
$attr = $permissionSet['OPENED_ONLY'];
$restrictions[] = "{$aliasPrefix}P.ATTR = {$attr}";
}
elseif ($permissionSet['USER'] !== '')
{
$restrictions[] = $aliasPrefix . 'P.ATTR = ' . $permissionSet['USER'];
if ($permissionSet['CONCERNED_USER'] !== '')
{
$restrictions[] = $aliasPrefix . 'P.ATTR = ' . $permissionSet['CONCERNED_USER'];
}
}
elseif (!empty($permissionSet['DEPARTMENTS']))
{
$departments = $permissionSet['DEPARTMENTS'];
$restrictions[] = count($departments) > 1
? $aliasPrefix . 'P.ATTR IN(' . implode(', ', $departments) . ')'
: $aliasPrefix . 'P.ATTR = ' . $departments[0];
}
if (!empty($restrictions))
{
foreach ($restrictions as $restriction)
{
$subQuery = "SELECT {$aliasPrefix}P.ENTITY_ID FROM b_crm_entity_perms {$aliasPrefix}P WHERE {$aliasPrefix}P.ENTITY = '{$permEntity}' AND {$restriction}";
if (!empty($effectiveEntityIDs))
{
$subQuery .= " AND {$aliasPrefix}P.ENTITY_ID IN (" . implode(', ', $effectiveEntityIDs) . ")";
}
$subQueries[] = $subQuery;
}
if (!$isRestricted)
{
$isRestricted = true;
}
}
}
else
{
$scopeSql = $scopeQty > 1
? $aliasPrefix . 'P2.ATTR IN (' . implode(', ', $scopes) . ')'
: $aliasPrefix . 'P2.ATTR = ' . $scopes[0];
$restrictions = [];
if ($permissionSet['OPENED_ONLY'] !== '')
{
$attr = $permissionSet['OPENED_ONLY'];
$restrictions[] = "{$aliasPrefix}P1.ATTR = {$attr}";
}
elseif ($permissionSet['USER'] !== '')
{
$restrictions[] = $aliasPrefix . 'P1.ATTR = ' . $permissionSet['USER'];
if ($permissionSet['CONCERNED_USER'] !== '')
{
$restrictions[] = $aliasPrefix . 'P1.ATTR = ' . $permissionSet['CONCERNED_USER'];
}
}
elseif (!empty($permissionSet['DEPARTMENTS']))
{
$departments = $permissionSet['DEPARTMENTS'];
$restrictions[] = count($departments) > 1
? $aliasPrefix . 'P1.ATTR IN(' . implode(', ', $departments) . ')'
: $aliasPrefix . 'P1.ATTR = ' . $departments[0];
}
if (!empty($restrictions))
{
foreach ($restrictions as $restriction)
{
$subQuery = "SELECT {$aliasPrefix}P2.ENTITY_ID FROM b_crm_entity_perms {$aliasPrefix}P1 INNER JOIN b_crm_entity_perms {$aliasPrefix}P2 ON {$aliasPrefix}P1.ENTITY = '{$permEntity}' AND {$aliasPrefix}P2.ENTITY = '{$permEntity}' AND {$aliasPrefix}P1.ENTITY_ID = {$aliasPrefix}P2.ENTITY_ID AND {$restriction} AND {$scopeSql}";
if (!empty($effectiveEntityIDs))
{
$subQuery .= " AND {$aliasPrefix}P2.ENTITY_ID IN (" . implode(',', $effectiveEntityIDs) . ")";
}
$subQueries[] = $subQuery;
}
}
else
{
$subQuery = "SELECT {$aliasPrefix}P2.ENTITY_ID FROM b_crm_entity_perms {$aliasPrefix}P2 WHERE {$aliasPrefix}P2.ENTITY = '{$permEntity}' AND {$scopeSql}";
if (!empty($effectiveEntityIDs))
{
$subQuery .= " AND {$aliasPrefix}P2.ENTITY_ID IN (" . implode(',', $effectiveEntityIDs) . ")";
}
$subQueries[] = $subQuery;
}
if (!$isRestricted)
{
$isRestricted = true;
}
}
}
unset($permissionSet);
if (!$isRestricted)
{
return '';
}
if ($options->isReadAllAllowed())
{
//Add permission 'Read allowed to Everyone' permission
$readAll = \CCrmPerms::ATTR_READ_ALL;
$subQuery = "SELECT {$aliasPrefix}P.ENTITY_ID FROM b_crm_entity_perms {$aliasPrefix}P WHERE {$aliasPrefix}P.ENTITY = '{$permEntity}' AND {$aliasPrefix}P.ATTR = '{$readAll}'";
if (!empty($effectiveEntityIDs))
{
$subQuery .= " AND {$aliasPrefix}P.ENTITY_ID IN (" . implode(',', $effectiveEntityIDs) . ")";
}
$subQueries[] = $subQuery;
}
$subQuerySql = implode($options->needUseDistinctUnion() ? ' UNION ' : ' UNION ALL ', $subQueries);
if ($options->needReturnRawQuery())
{
if ($options->getRawQueryLimit() > 0)
{
$order = $options->getRawQueryOrder();
$subQuerySql = \Bitrix\Main\Application::getConnection()->getSqlHelper()->getTopSql(
"{$subQuerySql} ORDER BY ENTITY_ID {$order}",
$options->getRawQueryLimit()
)
;
}
return $subQuerySql;
}
$identityCol = $options->getIdentityColumnName();
if ($options->needUseJoin())
{
return "INNER JOIN ({$subQuerySql}) {$aliasPrefix}GP ON {$aliasPrefix}.{$identityCol} = {$aliasPrefix}GP.ENTITY_ID";
}
return "{$aliasPrefix}.{$identityCol} IN ({$subQuerySql})";
}