Current Path : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/landing/lib/ |
Current File : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/landing/lib/rights.php |
<?php namespace Bitrix\Landing; use \Bitrix\Landing\Internals\RightsTable; use \Bitrix\Main\Localization\Loc; use \Bitrix\Main\UserAccessTable; Loc::loadMessages(__FILE__); class Rights { /** * Site entity type. */ const ENTITY_TYPE_SITE = 'S'; /** * Access types for different levels. */ const ACCESS_TYPES = [ 'denied' => 'denied', 'read' => 'read', 'edit' => 'edit', 'sett' => 'sett', 'public' => 'public', 'delete' => 'delete' ]; /** * Additional rights for some functionality. */ const ADDITIONAL_RIGHTS = [ 'menu24' => 'menu24',//show in main menu of Bitrix24 'admin' => 'admin',//admin rights 'create' => 'create',//can create new sites 'unexportable' => 'unexportable', 'knowledge_menu24' => 'knowledge_menu24',// show Knowledge in main menu of Bitrix24 'knowledge_admin' => 'knowledge_admin',//admin rights 'knowledge_create' => 'knowledge_create',//can create new Knowledge base 'knowledge_unexportable' => 'knowledge_unexportable', 'knowledge_extension' => 'knowledge_extension', 'group_create' => 'group_create',//can create new social network group base 'group_admin' => 'group_admin',//admin rights 'group_menu24' => 'group_menu24',// show group in main menu of Bitrix24 'group_unexportable' => 'group_unexportable', ]; const SET_PREFIX = [ 'knowledge', 'group', ]; const REVERSE_RIGHTS = [ 'unexportable', 'knowledge_unexportable', 'group_unexportable', ]; /** * Allowed site ids with full access. * @var int[] */ protected static $allowedSites = []; /** * If true, rights is not checking. * @var bool */ protected static $available = true; /** * If true, rights is not checking (global mode). * @var bool */ protected static $globalAvailable = true; /** * Context user id. * @var int */ protected static $userId = null; /** * Set rights checking to 'no'. * @return void */ public static function setOff() { self::$available = false; } /** * Set rights checking to 'yes'. * @return void */ public static function setOn() { self::$available = true; } /** * Set rights checking to 'no' (global mode). * @return void */ public static function setGlobalOff() { self::$globalAvailable = false; } /** * Set rights checking to 'yes' (global mode). * @return void */ public static function setGlobalOn() { self::$globalAvailable = true; } /** * Check current status for checking rights. * @return bool */ public static function isOn() { if ( defined('LANDING_DISABLE_RIGHTS') && LANDING_DISABLE_RIGHTS === true ) { return false; } if (!self::$globalAvailable) { return false; } return self::$available; } /** * Current user is admin or not. * @return bool */ public static function isAdmin() { if (self::hasAdditionalRight(self::ADDITIONAL_RIGHTS['admin'], null, false, true)) { return true; } return Manager::isAdmin(); } /** * Returns allowed sites with full access. * @return int[] */ public static function getAllowedSites(): array { return self::$allowedSites; } /** * Sets context user id. * @param int $uid * @return void */ public static function setContextUserId(int $uid): void { self::$userId = $uid; } /** * Clears context user id. * @return void */ public static function clearContextUserId(): void { self::$userId = null; } /** * Returns context user id (current by default). * @return int */ public static function getContextUserId(): int { if (!self::$userId) { self::$userId = Manager::getUserId(); } return self::$userId; } /** * Available or not permission feature by current plan. * @return bool */ protected static function isFeatureOn() { return Manager::checkFeature( Manager::FEATURE_PERMISSIONS_AVAILABLE ); } /** * Gets tasks for access. * @return array */ public static function getAccessTasks() { static $tasks = []; if (empty($tasks)) { $res = \CTask::getList( ['LETTER' => 'ASC'], ['MODULE_ID' => 'landing'] ); while ($row = $res->fetch()) { $row['NAME'] = mb_substr($row['NAME'], 14); $tasks[$row['ID']] = $row; } } return $tasks; } /** * Gets tasks for access. * @return array */ public static function getAccessTasksReferences() { static $tasks = []; if (empty($tasks)) { foreach (self::getAccessTasks() as $accessTask) { $tasks[$accessTask['NAME']] = $accessTask['ID']; } } return $tasks; } /** * Remove all rows for entity. * @param int|array $entityId Entity id (id or array of id). * @param string $entityType Entity type. * @return void */ protected static function removeData($entityId, $entityType) { if (self::isFeatureOn()) { $res = RightsTable::getList([ 'select' => [ 'ID' ], 'filter' => [ 'ENTITY_ID' => $entityId, '=ENTITY_TYPE' => $entityType ] ]); while ($row = $res->fetch()) { RightsTable::delete($row['ID']); } } } /** * Remove all rows for site. * @param int|array $siteId Site id (id or array of id). * @return void */ public static function removeDataForSite($siteId) { self::removeData( $siteId, self::ENTITY_TYPE_SITE ); } /** * Get all rows for entity. * @param int|array $entityId Entity id (id or array of id). * @param string $entityType Entity type. * @param array $preDefined Predefined array of rights. * @return array */ protected static function getData($entityId, $entityType, array $preDefined = []) { static $access = null; $items = []; $codes = []; if ($access === null) { $access = new \CAccess; } // filter (with predefined_ $filter = [ 'ENTITY_ID' => $entityId, '=ENTITY_TYPE' => $entityType ]; if ($preDefined) { $filter['=ACCESS_CODE'] = array_keys($preDefined); } // main query $res = RightsTable::getList([ 'select' => [ 'TASK_ID', 'ACCESS_CODE' ], 'filter' => $filter ]); while ($row = $res->fetch()) { $codes[] = $row['ACCESS_CODE']; if (!isset($items[$row['ACCESS_CODE']])) { $row['TASK_ID'] = [$row['TASK_ID']]; $items[$row['ACCESS_CODE']] = $row; } else { $items[$row['ACCESS_CODE']]['TASK_ID'][] = $row['TASK_ID']; } if (isset($preDefined[$row['ACCESS_CODE']])) { unset($preDefined[$row['ACCESS_CODE']]); } } $items = array_values($items); // fill with predefined foreach ($preDefined as $accessCode => $rightCode) { $items[] = [ 'TASK_ID' => $rightCode, 'ACCESS_CODE' => $accessCode ]; $codes[] = $accessCode; } // get titles if ($items) { $codesNames = $access->getNames($codes); foreach ($items as &$item) { if (isset($codesNames[$item['ACCESS_CODE']])) { $item['ACCESS_PROVIDER'] = ( isset($codesNames[$item['ACCESS_CODE']]['provider']) && $codesNames[$item['ACCESS_CODE']]['provider'] ) ? $codesNames[$item['ACCESS_CODE']]['provider'] : ''; $item['ACCESS_NAME'] = isset($codesNames[$item['ACCESS_CODE']]['name']) ? $codesNames[$item['ACCESS_CODE']]['name'] : $item['ACCESS_CODE']; } } unset($item); } return $items; } /** * Get all rows for site. * @param int|array $siteId Site id (id or array of id). * @param array $preDefined Predefined array of rights. * @return array */ public static function getDataForSite($siteId, array $preDefined = []) { return self::getData( $siteId, self::ENTITY_TYPE_SITE, $preDefined ); } /** * Get all available operations for entity (for current user). * @param int|array $entityId Entity id (id or array of id). * @param string $entityType Entity type. * @return array */ protected static function getOperations($entityId, $entityType) { // full access for allowed sites if ( $entityType == self::ENTITY_TYPE_SITE && in_array($entityId, self::$allowedSites) ) { $types = self::ACCESS_TYPES; unset($types[self::ACCESS_TYPES['delete']]); return array_values($types); } // check scoped method if ( $entityType == self::ENTITY_TYPE_SITE && !is_array($entityId) && $entityId > 0 ) { $scopeOperationsSite = Site\Type::getOperationsForSite($entityId); if ($scopeOperationsSite !== null) { return array_values($scopeOperationsSite); } } $operations = []; $operationsDefault = []; $wasChecked = false; $uid = self::getContextUserId(); $extendedMode = self::isExtendedMode(); // full access for admin if ( $uid && self::isOn() && !self::isAdmin() && self::isFeatureOn() && self::exist() ) { $wasChecked = true; $entityIdFilter = $entityId; if (is_array($entityIdFilter)) { $entityIdFilter[] = 0; } else { $entityIdFilter = [ $entityIdFilter, 0 ]; } $filter = [ 'ENTITY_ID' => $entityIdFilter, '=ENTITY_TYPE' => $entityType, 'USER_ACCESS.USER_ID' => $uid, '!TASK_OPERATION.OPERATION.NAME' => false ]; if ($extendedMode) { $filter['ROLE_ID'] = 0; } else { $filter['ROLE_ID'] = Role::getExpectedRoleIds(); } $res = RightsTable::getList( [ 'select' => [ 'ENTITY_ID', 'OPERATION_NAME' => 'TASK_OPERATION.OPERATION.NAME' ], 'filter' => $filter ] ); while ($row = $res->fetch()) { if ($row['ENTITY_ID'] == 0) { $operationsDefault[] = mb_substr($row['OPERATION_NAME'], 8); continue; } if (!isset($operations[$row['ENTITY_ID']])) { $operations[$row['ENTITY_ID']] = array(); } $operations[$row['ENTITY_ID']][] = mb_substr($row['OPERATION_NAME'], 8); $operations[$row['ENTITY_ID']] = array_unique($operations[$row['ENTITY_ID']]); } } // set full rights, if rights are empty foreach ((array) $entityId as $id) { if (!isset($operations[$id])) { if ($wasChecked && !$extendedMode) { $operations[$id] = !empty($operationsDefault) ? $operationsDefault : [self::ACCESS_TYPES['denied']]; } else { $operations[$id] = array_values(self::ACCESS_TYPES); } } } return is_array($entityId) ? $operations : $operations[$entityId]; } /** * Returns all available operations for site (for current user). * @param int|array $siteId Site id (id or array of id). * @return array */ public static function getOperationsForSite($siteId): array { if ( is_array($siteId) || $siteId == 0 || Site::ping($siteId, true) ) { return self::getOperations( $siteId, self::ENTITY_TYPE_SITE ); } else { return []; } } /** * Can current user do something. * @param int $siteId Site id. * @param string $accessType Access type code. * @param bool $deleted And from recycle bin. * @return boolean */ public static function hasAccessForSite($siteId, $accessType, $deleted = false) { static $operations = []; $siteId = intval($siteId); if (!is_string($accessType)) { return false; } if (!isset($operations[$siteId])) { if ($siteId === 0 || !self::isOn() || Site::ping($siteId, $deleted)) { $operations[$siteId] = self::getOperations( $siteId, self::ENTITY_TYPE_SITE ); } else { $operations[$siteId] = []; } } return in_array($accessType, $operations[$siteId]); } /** * Can current user do something. * @param int $landingId Landing id. * @param string $accessType Access type code. * @return boolean */ public static function hasAccessForLanding($landingId, $accessType) { static $operations = []; $landingId = intval($landingId); if (!is_string($accessType)) { return false; } if (!isset($operations[$landingId])) { $site = Landing::getList([ 'select' => [ 'SITE_ID' ], 'filter' => [ 'ID' => $landingId, '=SITE.DELETED' => ['Y', 'N'], '=DELETED' => ['Y', 'N'] ] ])->fetch(); if ($site) { $operations[$landingId] = self::getOperations( $site['SITE_ID'], self::ENTITY_TYPE_SITE ); } else { $operations[$landingId] = []; } } return in_array($accessType, $operations[$landingId]); } /** * Set operations for entity. * @param int $entityId Entity id. * @param string $entityType Entity type. * @param array $rights Rights array (set empty for clear rights). * @return boolean */ protected static function setOperations($entityId, $entityType, array $rights = []) { if (!self::isFeatureOn()) { return false; } $tasks = self::getAccessTasksReferences(); $entityId = intval($entityId); self::removeData( $entityId, $entityType ); // add new rights foreach ($rights as $accessCode => $rightCodes) { $rightCodes = (array) $rightCodes; if (in_array(self::ACCESS_TYPES['denied'], $rightCodes)) { $rightCodes = [self::ACCESS_TYPES['denied']]; } else if (!in_array(self::ACCESS_TYPES['read'], $rightCodes)) { $rightCodes[] = self::ACCESS_TYPES['read']; } foreach ($rightCodes as $rightCode) { if (isset($tasks[$rightCode])) { RightsTable::add([ 'ENTITY_ID' => $entityId, 'ENTITY_TYPE' => $entityType, 'TASK_ID' => $tasks[$rightCode], 'ACCESS_CODE' => $accessCode ]); } } } return true; } /** * Set operations for site. * @param int $siteId Site id. * @param array $rights Rights array (set empty for clear rights). * @return bool */ public static function setOperationsForSite($siteId, array $rights = []) { $siteId = intval($siteId); if ($siteId == 0 || Site::ping($siteId)) { return self::setOperations( $siteId, self::ENTITY_TYPE_SITE, $rights ); } else { return false; } } /** * If any records of rights exists. * @return bool */ protected static function exist() { static $exist = null; if ($exist === null) { $type = Site\Type::getCurrentScopeId(); $res = RightsTable::getList([ 'select' => [ 'ID' ], 'filter' => $type ? ['=ROLE.TYPE' => $type] : [], 'limit' => 1 ]); $exist = (bool) $res->fetch(); } return $exist; } /** * Gets access filter for current user. * @param array $additionalFilterOr Additional filter for OR section. * @return array */ public static function getAccessFilter(array $additionalFilterOr = []) { $filter = []; if ( self::isOn() && !self::isAdmin() && self::isFeatureOn() && self::exist() ) { $tasks = self::getAccessTasksReferences(); $extendedRights = self::isExtendedMode(); $uid = self::getContextUserId(); if ($extendedRights) { $filter[] = [ 'LOGIC' => 'OR', [ '!RIGHTS.TASK_ID' => $tasks[Rights::ACCESS_TYPES['denied']], 'RIGHTS.USER_ACCESS.USER_ID' => $uid ], [ '=RIGHTS.TASK_ID' => null ], $additionalFilterOr ]; } else { if ($additionalFilterOr) { $filter[] = [ 'LOGIC' => 'OR', [ '!RIGHTS.TASK_ID' => $tasks[Rights::ACCESS_TYPES['denied']], 'RIGHTS.USER_ACCESS.USER_ID' => $uid ], $additionalFilterOr ]; } else { $filter['RIGHTS.USER_ACCESS.USER_ID'] = $uid; $filter['!RIGHTS.TASK_ID'] = $tasks[Rights::ACCESS_TYPES['denied']]; } } } return $filter; } /** * Extended mode available. * @return bool */ public static function isExtendedMode() { if (Manager::isB24()) { return Manager::getOption('rights_extended_mode', 'N') == 'Y'; } else { return true; } } /** * Switch extended mode. * @return void */ public static function switchMode() { if (self::isFeatureOn()) { $current = Manager::getOption('rights_extended_mode', 'N'); $current = ($current == 'Y') ? 'N' : 'Y'; Manager::setOption('rights_extended_mode', $current); } } /** * Refresh additional rights for all roles. * @param array $additionalRights Array for set additional. * @return void */ public static function refreshAdditionalRights(array $additionalRights = []) { if (!self::isFeatureOn()) { return; } $rights = []; foreach (self::ADDITIONAL_RIGHTS as $right) { $rights[$right] = []; } // get additional from all roles $res = Role::getList([ 'select' => [ 'ID', 'ACCESS_CODES', 'ADDITIONAL_RIGHTS' ] ]); while ($row = $res->fetch()) { $row['ACCESS_CODES'] = (array) $row['ACCESS_CODES']; $row['ADDITIONAL_RIGHTS'] = (array) $row['ADDITIONAL_RIGHTS']; foreach ($row['ADDITIONAL_RIGHTS'] as $right) { if (isset($rights[$right])) { $rights[$right][$row['ID']] = $row['ACCESS_CODES']; } } } // refresh options foreach ($rights as $code => $right) { // gets current from option $option = Manager::getOption('access_codes_' . $code, ''); $option = unserialize($option, ['allowed_classes' => false]); if (isset($option[0])) { $right[0] = $option[0]; } // rewrite some rights, if need if ( isset($additionalRights[$code]) && is_array($additionalRights[$code]) ) { foreach ($additionalRights[$code] as $i => $accCodes) { $right[$i] = (array) $accCodes; } } // set new rights in option Manager::setOption('access_codes_' . $code, $right ? serialize($right) : ''); // clear menu cache if (Manager::isB24()) { Manager::getCacheManager()->clearByTag( 'bitrix24_left_menu' ); Manager::getCacheManager()->cleanDir( 'menu' ); \CBitrixComponent::clearComponentCache( 'bitrix:menu' ); } } } /** * Set additional right. * @param string $code Code from ADDITIONAL_RIGHTS. * @param array $accessCodes Additional rights array. * @return void */ public static function setAdditionalRightExtended($code, array $accessCodes = []) { if (!is_string($code)) { return; } self::refreshAdditionalRights([ $code => [ 0 => $accessCodes ] ]); } /** * Gets additional right. * @param string $code Code from ADDITIONAL_RIGHTS. * @return array */ public static function getAdditionalRightExtended($code) { static $access = null; $return = []; if (!is_string($code)) { return $return; } if ($access === null) { $access = new \CAccess; } $option = Manager::getOption('access_codes_' . $code, ''); $option = unserialize($option, ['allowed_classes' => false]); $accessCodes = isset($option[0]) ? (array)$option[0] : []; $codesNames = $access->getNames($accessCodes); foreach ($accessCodes as $code) { if (isset($codesNames[$code])) { $provider = ( isset($codesNames[$code]['provider']) && $codesNames[$code]['provider'] ) ? $codesNames[$code]['provider'] : ''; $name = isset($codesNames[$code]['name']) ? $codesNames[$code]['name'] : $code; $return[$code] = [ 'CODE' => $code, 'PROVIDER' => $provider, 'NAME' => $name ]; } } return $return; } /** * Gets additional rights with labels. * @return array */ public static function getAdditionalRightsLabels() { $rights = []; $type = Site\Type::getCurrentScopeId(); foreach (self::ADDITIONAL_RIGHTS as $right) { if (mb_strpos($right, '_') > 0) { [$prefix, ] = explode('_', $right); $prefix = mb_strtoupper($prefix); if ($prefix != $type) { continue; } } else if ($type !== null) { continue; } $rights[$right] = Loc::getMessage('LANDING_RIGHTS_R_'.mb_strtoupper($right)); } return $rights; } /** * Has user some extra access? * @return bool */ protected static function hasExtraRights(): bool { // has context user access to crm forms if (\Bitrix\Main\Loader::includeModule('crm')) { $access = new \CCrmPerms(self::getContextUserId()); if (!$access->havePerm('WEBFORM', BX_CRM_PERM_NONE, 'WRITE')) { // grant access to crm forms sites $res = Site::getList([ 'select' => [ 'ID' ], 'filter' => [ 'CODE' => '/' . Site\Type::PSEUDO_SCOPE_CODE_FORMS . '%', '=SPECIAL' => 'Y', 'CHECK_PERMISSIONS' => 'N' ] ]); while ($row = $res->fetch()) { self::$allowedSites[] = $row['ID']; } return true; } } return false; } /** * Has current user additional right or not. * @param string $code Code from ADDITIONAL_RIGHTS. * @param string $type Scope type. * @param bool $checkExtraRights Check extra rights. * @return bool */ public static function hasAdditionalRight($code, $type = null, bool $checkExtraRights = false, bool $strict = false) { static $options = []; if ($checkExtraRights && self::hasExtraRights()) { return true; } if (!is_string($code)) { return false; } if ($type === null) { $type = Site\Type::getCurrentScopeId(); } if ($type !== null) { $type = mb_strtolower($type); //@todo: hotfix for group right if ($type == Site\Type::SCOPE_CODE_GROUP) { return true; } $code = $type . '_' . $code; } if (array_key_exists($code, self::ADDITIONAL_RIGHTS)) { if (!self::isFeatureOn()) { return true; } if (!self::getContextUserId()) { return false; } if (Manager::isAdmin()) { if (in_array($code, self::REVERSE_RIGHTS)) { return false; } return true; } $accessCodes = []; if (!isset($options[$code])) { $options[$code] = Manager::getOption('access_codes_' . $code, ''); $options[$code] = unserialize($options[$code], ['allowed_classes' => false]); } $option = $options[$code]; if (!is_array($option) && !$strict) { return true; } if (empty($option)) { return false; } if (self::isExtendedMode()) { if (isset($option[0]) && is_array($option[0])) { $accessCodes = $option[0]; } } else { if (isset($option[0])) { unset($option[0]); } foreach ($option as $roleAccess) { $accessCodes = array_merge($accessCodes, (array)$roleAccess); } $accessCodes = array_unique($accessCodes); } if ($accessCodes) { static $accessCodesStatic = []; sort($accessCodes); $accessCodesStr = implode('|', $accessCodes); if (array_key_exists($accessCodesStr, $accessCodesStatic)) { return $accessCodesStatic[$accessCodesStr]; } $res = UserAccessTable::getList([ 'select' => [ 'USER_ID' ], 'filter' => [ '=ACCESS_CODE' => $accessCodes, 'USER_ID' => self::getContextUserId() ] ]); $accessCodesStatic[$accessCodesStr] = (boolean)$res->fetch(); return $accessCodesStatic[$accessCodesStr]; } return false; } return false; } }