diff --git a/vendor/magento/module-shared-catalog/Model/SharedCatalogValidator.php b/vendor/magento/module-shared-catalog/Model/SharedCatalogValidator.php index 95184c6d5c61..570058bd0ad9 100644 --- a/vendor/magento/module-shared-catalog/Model/SharedCatalogValidator.php +++ b/vendor/magento/module-shared-catalog/Model/SharedCatalogValidator.php @@ -13,6 +13,8 @@ */ class SharedCatalogValidator { + private const FILTERED_FLAG_NAME = 'admin_gws_filtered_b2b'; + /** * @var \Magento\SharedCatalog\Api\SharedCatalogManagementInterface */ @@ -304,6 +306,7 @@ private function validateSharedCatalogName(\Magento\SharedCatalog\Api\Data\Share } /** @var \Magento\SharedCatalog\Model\ResourceModel\SharedCatalog\Collection $collection */ $collection = $this->sharedCatalogCollectionFactory->create(); + $collection->setFlag(self::FILTERED_FLAG_NAME, true); $collection->addFieldToFilter($sharedCatalog::NAME, ['eq' => $sharedCatalog->getName()]); if (!empty($sharedCatalog->getId())) { $collection->addFieldToFilter($sharedCatalog::SHARED_CATALOG_ID, ['neq' => $sharedCatalog->getId()]); diff --git a/vendor/magento/module-shared-catalog/Plugin/Backend/Block/Adminhtml/Store/SwitcherRolePermissions.php b/vendor/magento/module-shared-catalog/Plugin/Backend/Block/Adminhtml/Store/SwitcherRolePermissions.php index 6060fe1d09ce..0149f18fb590 100644 --- a/vendor/magento/module-shared-catalog/Plugin/Backend/Block/Adminhtml/Store/SwitcherRolePermissions.php +++ b/vendor/magento/module-shared-catalog/Plugin/Backend/Block/Adminhtml/Store/SwitcherRolePermissions.php @@ -8,8 +8,8 @@ namespace Magento\SharedCatalog\Plugin\Backend\Block\Adminhtml\Store; use Magento\Backend\Model\Auth\Session; -use Magento\Framework\Stdlib\ArrayManager; use Magento\SharedCatalog\Block\Adminhtml\Store\Switcher; +use Magento\Store\Model\ResourceModel\Website\CollectionFactory; /** * Plugin for store switch permission based on role @@ -17,25 +17,18 @@ class SwitcherRolePermissions { /** - * @var Session + * @var array */ - private $backendAuthSession; - - /** - * @var ArrayManager - */ - private $arrayManager; + private $allWebsiteIds = []; /** * @param Session $backendAuthSession - * @param ArrayManager $arrayManager + * @param CollectionFactory $websiteCollectionFactory */ public function __construct( - Session $backendAuthSession, - ArrayManager $arrayManager + private readonly Session $backendAuthSession, + private readonly CollectionFactory $websiteCollectionFactory ) { - $this->backendAuthSession = $backendAuthSession; - $this->arrayManager = $arrayManager; } /** @@ -51,9 +44,33 @@ public function afterGetStoreOptionsAsArray( array $result ):array { $role = $this->backendAuthSession->getUser()->getRole(); - if (!$role->getGwsIsAll() && $this->arrayManager->exists(Switcher::ALL_STORES_ID, $result)) { - array_shift($result); + $allowedWebsites = $role->getGwsWebsites() ?? []; + if (!$role->getGwsIsAll() && + count(array_diff($this->getAllWebsiteIds(), $allowedWebsites)) !== 0) { + + if ($role->getGwsStoreGroups()) { + $result = array_filter($result, function ($item) use ($role) { + return in_array($item['id'], $role->getGwsStoreGroups()); + }); + } } - return $result; + + return array_values($result); + } + + /** + * Get all website ids excluding admin store. + * + * @return array + */ + private function getAllWebsiteIds(): array + { + if (!count($this->allWebsiteIds)) { + $websites = $this->websiteCollectionFactory->create()->getAllIds(); + $websites = array_filter($websites); + $this->allWebsiteIds = $websites; + } + + return $this->allWebsiteIds; } } diff --git a/vendor/magento/module-shared-catalog/Plugin/SharedCatalog/CollectionFilter.php b/vendor/magento/module-shared-catalog/Plugin/SharedCatalog/CollectionFilter.php new file mode 100644 index 000000000000..e427a40c44ad --- /dev/null +++ b/vendor/magento/module-shared-catalog/Plugin/SharedCatalog/CollectionFilter.php @@ -0,0 +1,236 @@ +getAdminRole(); + if ($role && $role->getId() && !$role->getGwsIsAll() && !$collection->getFlag(self::FILTERED_FLAG_NAME)) { + if (isset($collection->getSelect()->getPart(Select::FROM)['main_table'])) { + if ($collection->getFlag(self::INITIAL_FILTERED_FLAG)) { + // the store_id from shared_catalog is actually store_group_id from store_group table, + // but the initial filtering assumes that + // store_id is actually from store table (as store view) not store_group table (as store) + $this->resetStoreGroupConditions($collection); + } + $this->filterSharedCatalogsByAllowedStoreGroupIdsAndAdminUser($collection, $role); + $collection->setFlag(self::FILTERED_FLAG_NAME, true); + } + } + } + + /** + * Get admin user role for admin user context and webapi user context. + * + * @return Role|null + * @throws LocalizedException + */ + private function getAdminRole(): Role|null + { + if (!$this->adminRole) { + if ($this->backendSession->getUser()) { + $this->adminRole = $this->backendSession->getUser()->getRole(); + + } elseif ($this->userContext->getUserId() + && $this->userContext->getUserType() === UserContextInterface::USER_TYPE_ADMIN + ) { + $user = $this->userFactory->create(); + $user->load($this->userContext->getUserId()); + $this->adminRole = $user->getRole(); + } + } + return $this->adminRole; + } + + /** + * Get admin user id. + * + * @return int|null + */ + private function getAdminId(): ?int + { + if (!$this->adminId) { + $this->adminId = $this->userContext->getUserId(); + } + return $this->adminId; + } + + /** + * Filter the shared catalog collection by allowed store ids. + * + * @param Collection $collection + * @param Role $role + * @return void + * @throws \Zend_Db_Select_Exception + */ + private function filterSharedCatalogsByAllowedStoreGroupIdsAndAdminUser(Collection $collection, Role $role): void + { + $allowedStoreGroupIds = $role->getGwsStoreGroups() ?? []; + + //restricted admin user has all websites assigned like full admin, so no need to filter + $allowedWebsites = $role->getGwsWebsites() ?? []; + if (count(array_diff($this->getAllWebsiteIds(), $allowedWebsites)) === 0) { + $this->resetStoreGroupConditions($collection); + return; + } + + if ($this->request->getParam('shared_catalog_id')) { + $collection->getSelect()->where( + 'main_table.entity_id = ?', + (int)$this->request->getParam('shared_catalog_id') + ); + } else { + $adminUserId = $this->getAdminId(); + //filter by allowed store group ids when store_id is assigned to shared catalog, + //or by created_by for shared catalog without assigned store group + $collection->getSelect() + ->where('main_table.store_id IN (?)', $allowedStoreGroupIds, \Zend_Db::INT_TYPE) + ->orWhere( + '(main_table.store_id IS NULL AND main_table.created_by = ?)', + $adminUserId, + \Zend_Db::INT_TYPE + ); + } + } + + /** + * Reset store where conditions + * + * @param Collection $collection + * @return void + * @throws \Zend_Db_Select_Exception + */ + private function resetStoreGroupConditions(Collection $collection): void + { + $where = $collection->getSelect()->getPart(Select::WHERE); + foreach ($where as $key => $value) { + if (str_contains($value, 'main_table.store_id')) { + unset($where[$key]); + } + } + $collection->getSelect()->setPart(Select::WHERE, $where); + } + + /** + * Get all websites ids excluding admin store. + * + * @return array + */ + private function getAllWebsiteIds(): array + { + if (!count($this->allWebsiteIds)) { + $this->allWebsiteIds = array_filter($this->websiteCollectionFactory->create()->getAllIds()); + } + + return $this->allWebsiteIds; + } + + /** + * Adds only allowed stores to shared catalog filter count. + * + * @param Collection $collection + * @throws LocalizedException + * @throws \Zend_Db_Select_Exception + */ + public function beforeGetSelectCountSql(Collection $collection): void + { + $this->filterCollection($collection); + } + + /** + * Adds only restricted admin allowed stores to shared catalog filter. + * + * @param Collection $collection + * @param bool $printQuery + * @param bool $logQuery + * @return void + * @throws LocalizedException + * @throws \Zend_Db_Select_Exception + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeLoadWithFilter( + Collection $collection, + bool $printQuery = false, + bool $logQuery = false + ): void { + $this->filterCollection($collection); + } +} diff --git a/vendor/magento/module-shared-catalog/Plugin/Ui/DataProvider/WebsiteRolePermissions.php b/vendor/magento/module-shared-catalog/Plugin/Ui/DataProvider/WebsiteRolePermissions.php index 1399345b75a0..c7a44bae5ebe 100644 --- a/vendor/magento/module-shared-catalog/Plugin/Ui/DataProvider/WebsiteRolePermissions.php +++ b/vendor/magento/module-shared-catalog/Plugin/Ui/DataProvider/WebsiteRolePermissions.php @@ -7,9 +7,12 @@ namespace Magento\SharedCatalog\Plugin\Ui\DataProvider; +use Magento\Authorization\Model\Role; use Magento\Backend\Model\Auth\Session; use Magento\Framework\Stdlib\ArrayManager; use Magento\SharedCatalog\Ui\DataProvider\Website as Websites; +use Magento\Store\Model\ResourceModel\Website\CollectionFactory; +use Magento\Store\Model\StoreManagerInterface; /** * Plugin for store switch permission based on role @@ -28,13 +31,20 @@ class WebsiteRolePermissions */ private $backendAuthSession; + /** + * @var array + */ + private $allWebsiteIds = []; + /** * @param Session $backendAuthSession * @param ArrayManager $arrayManager + * @param CollectionFactory $websiteCollectionFactory */ public function __construct( Session $backendAuthSession, - ArrayManager $arrayManager + ArrayManager $arrayManager, + private readonly CollectionFactory $websiteCollectionFactory ) { $this->backendAuthSession = $backendAuthSession; $this->arrayManager = $arrayManager; @@ -53,9 +63,26 @@ public function afterGetWebsites( array $result ):array { $role = $this->backendAuthSession->getUser()->getRole(); - if (!$role->getGwsIsAll() && $this->arrayManager->exists(0, $result)) { + $allowedWebsites = $role->getGwsWebsites() ?? []; + if (!$role->getGwsIsAll() && + count(array_diff($this->getAllWebsiteIds(), $allowedWebsites)) !== 0 && + $this->arrayManager->exists(0, $result)) { array_shift($result); } return $result; } + + /** + * Get all website ids excluding admin store. + * + * @return array + */ + private function getAllWebsiteIds(): array + { + if (!count($this->allWebsiteIds)) { + $this->allWebsiteIds = array_filter($this->websiteCollectionFactory->create()->getAllIds()); + } + + return $this->allWebsiteIds; + } } diff --git a/vendor/magento/module-shared-catalog/ViewModel/Store/SwitcherAllowedValues.php b/vendor/magento/module-shared-catalog/ViewModel/Store/SwitcherAllowedValues.php new file mode 100644 index 000000000000..dfcffaf45ed0 --- /dev/null +++ b/vendor/magento/module-shared-catalog/ViewModel/Store/SwitcherAllowedValues.php @@ -0,0 +1,77 @@ +backendAuthSession->getUser()->getRole(); + $allowedWebsites = $role->getGwsWebsites() ?? []; + if (!$role->getGwsIsAll() + && count(array_diff($this->getAllWebsiteIds(), $allowedWebsites)) !== 0 + && $role->getGwsStoreGroups()) { + return current($role->getGwsStoreGroups()); + } + return (string)Store::DEFAULT_STORE_ID; + } + + /** + * Get all website ids excluding admin store. + * + * @return array + */ + private function getAllWebsiteIds(): array + { + if (!count($this->allWebsiteIds)) { + $this->allWebsiteIds = array_filter($this->websiteCollectionFactory->create()->getAllIds()); + } + + return $this->allWebsiteIds; + } +} diff --git a/vendor/magento/module-shared-catalog/etc/adminhtml/di.xml b/vendor/magento/module-shared-catalog/etc/adminhtml/di.xml index f8e0e0182c0c..a9c496e247a1 100644 --- a/vendor/magento/module-shared-catalog/etc/adminhtml/di.xml +++ b/vendor/magento/module-shared-catalog/etc/adminhtml/di.xml @@ -144,4 +144,7 @@ + + + diff --git a/vendor/magento/module-shared-catalog/etc/webapi_rest/di.xml b/vendor/magento/module-shared-catalog/etc/webapi_rest/di.xml index ecc4037a6e9a..90f9b7c936c7 100644 --- a/vendor/magento/module-shared-catalog/etc/webapi_rest/di.xml +++ b/vendor/magento/module-shared-catalog/etc/webapi_rest/di.xml @@ -17,4 +17,7 @@ + + + diff --git a/vendor/magento/module-shared-catalog/etc/webapi_soap/di.xml b/vendor/magento/module-shared-catalog/etc/webapi_soap/di.xml index ecc4037a6e9a..90f9b7c936c7 100644 --- a/vendor/magento/module-shared-catalog/etc/webapi_soap/di.xml +++ b/vendor/magento/module-shared-catalog/etc/webapi_soap/di.xml @@ -17,4 +17,7 @@ + + + diff --git a/vendor/magento/module-shared-catalog/view/adminhtml/layout/shared_catalog_sharedcatalog_wizard.xml b/vendor/magento/module-shared-catalog/view/adminhtml/layout/shared_catalog_sharedcatalog_wizard.xml index b0e3aee88018..f3873baff1f4 100644 --- a/vendor/magento/module-shared-catalog/view/adminhtml/layout/shared_catalog_sharedcatalog_wizard.xml +++ b/vendor/magento/module-shared-catalog/view/adminhtml/layout/shared_catalog_sharedcatalog_wizard.xml @@ -41,7 +41,11 @@ + template="Magento_SharedCatalog::wizard/step/structure/store/switcher.phtml"> + + Magento\SharedCatalog\ViewModel\Store\SwitcherAllowedValues + + @@ -55,7 +59,11 @@ + template="Magento_SharedCatalog::wizard/step/pricing/store/switcher.phtml"> + + Magento\SharedCatalog\ViewModel\Store\SwitcherAllowedValues + + diff --git a/vendor/magento/module-shared-catalog/view/adminhtml/templates/wizard/step/pricing/store/switcher.phtml b/vendor/magento/module-shared-catalog/view/adminhtml/templates/wizard/step/pricing/store/switcher.phtml index e0cb1751d1cc..747332f8779e 100644 --- a/vendor/magento/module-shared-catalog/view/adminhtml/templates/wizard/step/pricing/store/switcher.phtml +++ b/vendor/magento/module-shared-catalog/view/adminhtml/templates/wizard/step/pricing/store/switcher.phtml @@ -5,9 +5,10 @@ */ /** @var $block \Magento\SharedCatalog\Block\Adminhtml\SharedCatalog\Wizard\Store\Switcher */ +$selectedOptionValue = $block->getSelectedOptionValue() + ?? $block->getData('allowedValuesViewModel')->getSelectedOptionValue(); ?> -
+