From c99a63c52aaeab203f4a8a681e10b6aa2c81fe3e Mon Sep 17 00:00:00 2001 From: Thor Brink Date: Fri, 17 Jan 2025 10:34:57 +0100 Subject: [PATCH] feat: handle all CRUD for UserGroup on main site (#1260) --- library/App.php | 9 ++- .../Helper/User/Contracts/SetUserGroup.php | 16 ++++ library/Helper/User/User.php | 77 ++++++++++++++++--- library/Helper/User/User.test.php | 19 +++-- .../SetUserGroupFromSsoLoginGroup.php | 15 +--- .../SetUserGroupFromSsoLoginGroup.test.php | 33 +++----- 6 files changed, 116 insertions(+), 53 deletions(-) create mode 100644 library/Helper/User/Contracts/SetUserGroup.php diff --git a/library/App.php b/library/App.php index f0815f410..cecdccd29 100644 --- a/library/App.php +++ b/library/App.php @@ -95,7 +95,7 @@ public function __construct( */ $userGroupConfig = new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService); $userHelperConfig = new \Municipio\Helper\User\Config\UserConfig(); - $userHelper = new \Municipio\Helper\User\User($this->wpService, $this->acfService, $userHelperConfig, $userGroupConfig); + $userHelper = new \Municipio\Helper\User\User($this->wpService, $this->acfService, $userHelperConfig, $userGroupConfig, new \Municipio\Helper\Term\Term($this->wpService, $this->acfService)); /** * User group @@ -391,7 +391,7 @@ private function setUpBrokenLinksIntegration(): void private function setupLoginLogout(): void { //Needs setUser to be called before using the user object - $userHelper = new User($this->wpService, $this->acfService, new UserConfig(), new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService)); + $userHelper = new User($this->wpService, $this->acfService, new UserConfig(), new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService), new \Municipio\Helper\Term\Term($this->wpService, $this->acfService)); $filterAuthUrls = new \Municipio\Admin\Login\RelationalLoginLogourUrls($this->wpService); $filterAuthUrls->addHooks(); @@ -432,7 +432,7 @@ private function setupUserGroupFeature(): void // Setup dependencies $userGroupRestrictionConfig = new \Municipio\Admin\Private\Config\UserGroupRestrictionConfig(); $userHelperConfig = new \Municipio\Helper\User\Config\UserConfig(); - $userHelper = new \Municipio\Helper\User\User($this->wpService, $this->acfService, $userHelperConfig, $config); + $userHelper = new \Municipio\Helper\User\User($this->wpService, $this->acfService, $userHelperConfig, $config, new \Municipio\Helper\Term\Term($this->wpService, $this->acfService)); // Create user group taxonomy (new \Municipio\UserGroup\CreateUserGroupTaxonomy($this->wpService, $config))->addHooks(); @@ -468,6 +468,7 @@ private function setupUserGroupFeature(): void */ private function setUpMiniOrangeIntegration(): void { + $userHelper = new \Municipio\Helper\User\User($this->wpService, $this->acfService, new \Municipio\Helper\User\Config\UserConfig(), new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService), new \Municipio\Helper\Term\Term($this->wpService, $this->acfService)); $termHelper = new \Municipio\Helper\Term\Term($this->wpService, $this->acfService); $userGroupConfig = new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService); $config = new \Municipio\Integrations\MiniOrange\Config\MiniOrangeConfig($this->wpService); @@ -495,7 +496,7 @@ private function setUpMiniOrangeIntegration(): void } // Set group as taxonomy - $setGroupAsTaxonomy = new \Municipio\Integrations\MiniOrange\SetUserGroupFromSsoLoginGroup($this->wpService, $termHelper, $userGroupConfig); + $setGroupAsTaxonomy = new \Municipio\Integrations\MiniOrange\SetUserGroupFromSsoLoginGroup($this->wpService, $userHelper); $setGroupAsTaxonomy->addHooks(); } diff --git a/library/Helper/User/Contracts/SetUserGroup.php b/library/Helper/User/Contracts/SetUserGroup.php new file mode 100644 index 000000000..5f923b603 --- /dev/null +++ b/library/Helper/User/Contracts/SetUserGroup.php @@ -0,0 +1,16 @@ +maybeSwitchToMainSite(); $userGroup = $this->wpService->wpGetObjectTerms($user->ID, $this->userGroupConfig->getUserGroupTaxonomy()); + $this->switchToCurrentBlogIfSwitched(); + if (empty($userGroup) || $this->wpService->isWpError($userGroup)) { return null; } @@ -143,7 +149,9 @@ public function getUserGroupUrlType(?WP_Term $term = null, null|WP_User|int $use $term ??= $this->getUserGroup($user); $termId = $this->userGroupConfig->getUserGroupTaxonomy($user) . '_' . $term->term_id; + $this->maybeSwitchToMainSite(); return $this->acfService->getField('user_group_type_of_link', $termId) ?: null; + $this->switchToCurrentBlogIfSwitched(); } /** @@ -157,11 +165,10 @@ public function getUserPrefersGroupUrl(null|WP_User|int $user = null): ?bool return null; } - $perfersGroupUrl = $this->wpService->getUserMeta( - $user->ID, - $this->userConfig->getUserPrefersGroupUrlMetaKey(), - true - ); + $this->maybeSwitchToMainSite(); + $perfersGroupUrl = $this->wpService->getUserMeta($user->ID, $this->userConfig->getUserPrefersGroupUrlMetaKey(), true); + $this->switchToCurrentBlogIfSwitched(); + if ($perfersGroupUrl) { return true; } @@ -191,4 +198,54 @@ public function getRedirectToGroupUrl(null|WP_User|int $user = null): ?string return null; } + +/** + * Switch to main site if multisite and not on main site. + */ + private function maybeSwitchToMainSite(): void + { + if (!$this->wpService->isMultisite() || $this->wpService->isMainSite()) { + return; + } + + if ($this->wpService->getMainSiteId() === $this->wpService->getCurrentBlogId()) { + return; + } + + $this->wpService->switchToBlog($this->wpService->getMainSiteId()); + } + + /** + * Switch back from main site if multisite and switched. + */ + private function switchToCurrentBlogIfSwitched(): void + { + if (!$this->wpService->isMultisite() || !$this->wpService->msIsSwitched()) { + return; + } + + $this->wpService->restoreCurrentBlog(); + } + + /** + * @inheritDoc + */ + public function setUserGroup(string $groupName, null|WP_User|int $user = null): void + { + $user = $this->getUser($user); + + if (!$user) { + return; + } + + $taxonomy = $this->userGroupConfig->getUserGroupTaxonomy(); + + $this->maybeSwitchToMainSite(); + + if ($termId = $this->termHelper->createOrGetTermIdFromString($groupName, $taxonomy)) { + $this->wpService->wpSetObjectTerms($user->ID, $termId, $taxonomy, false); + } + + $this->switchToCurrentBlogIfSwitched(); + } } diff --git a/library/Helper/User/User.test.php b/library/Helper/User/User.test.php index 15ae70634..7c0393ef8 100644 --- a/library/Helper/User/User.test.php +++ b/library/Helper/User/User.test.php @@ -3,6 +3,7 @@ namespace Municipio\Helper\User; use AcfService\Implementations\FakeAcfService; +use Municipio\Helper\Term\Contracts\CreateOrGetTermIdFromString; use Municipio\Helper\User\Config\UserConfigInterface; use Municipio\TestUtils\WpMockFactory; use Municipio\UserGroup\Config\UserGroupConfigInterface; @@ -20,7 +21,8 @@ public function testCanBeInstantiated() new FakeWpService(), new FakeAcfService(), $this->createStub(UserConfigInterface::class), - $this->createStub(UserGroupConfigInterface::class) + $this->createStub(UserGroupConfigInterface::class), + $this->createStub(CreateOrGetTermIdFromString::class) ); $this->assertInstanceOf(User::class, $user); @@ -35,7 +37,8 @@ public function testGetUserReturnsSameUserAsProvidedIfUserOfTypeWPUserIsProvided new FakeWpService(), new FakeAcfService(), $this->createStub(UserConfigInterface::class), - $this->createStub(UserGroupConfigInterface::class) + $this->createStub(UserGroupConfigInterface::class), + $this->createStub(CreateOrGetTermIdFromString::class) ); $wpUser = WpMockFactory::createWpUser(['ID' => 1]); @@ -52,7 +55,8 @@ public function testGetUserReturnsNullIfUserOfTypeWPUserIsProvidedAndIdIs0() new FakeWpService(), new FakeAcfService(), $this->createStub(UserConfigInterface::class), - $this->createStub(UserGroupConfigInterface::class) + $this->createStub(UserGroupConfigInterface::class), + $this->createStub(CreateOrGetTermIdFromString::class) ); $wpUser = WpMockFactory::createWpUser(['ID' => 0]); @@ -71,7 +75,8 @@ public function testGetUserReturnsCurrentUserIfNoUserIsProvidedAndUserIsLoggedIn $wpService, new FakeAcfService(), $this->createStub(UserConfigInterface::class), - $this->createStub(UserGroupConfigInterface::class) + $this->createStub(UserGroupConfigInterface::class), + $this->createStub(CreateOrGetTermIdFromString::class) ); $this->assertEquals(123, $user->getUser()->ID); @@ -90,7 +95,8 @@ public function testGetUserReturnsUserFromDbIfUserIdIsProvidedAndUserExists() $wpService, new FakeAcfService(), $this->createStub(UserConfigInterface::class), - $this->createStub(UserGroupConfigInterface::class) + $this->createStub(UserGroupConfigInterface::class), + $this->createStub(CreateOrGetTermIdFromString::class) ); $this->assertEquals(123, $user->getUser(123)->ID); @@ -109,7 +115,8 @@ public function testGetUserReturnsNullIfUserIdIsProvidedAndUserDoesNotExist() $wpService, new FakeAcfService(), $this->createStub(UserConfigInterface::class), - $this->createStub(UserGroupConfigInterface::class) + $this->createStub(UserGroupConfigInterface::class), + $this->createStub(CreateOrGetTermIdFromString::class), ); $this->assertNull($user->getUser(123)); diff --git a/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.php b/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.php index 60cdbc0b7..f68b19d2d 100644 --- a/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.php +++ b/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.php @@ -2,9 +2,8 @@ namespace Municipio\Integrations\MiniOrange; -use Municipio\Helper\Term\Contracts\CreateOrGetTermIdFromString; +use Municipio\Helper\User\Contracts\SetUserGroup; use Municipio\HooksRegistrar\Hookable; -use Municipio\UserGroup\Config\UserGroupConfigInterface; use WpService\Contracts\{AddAction, GetTermBy, IsWpError, WpInsertTerm, WpSetObjectTerms}; /** @@ -17,8 +16,7 @@ class SetUserGroupFromSsoLoginGroup implements Hookable */ public function __construct( private AddAction&WpSetObjectTerms&GetTermBy&WpInsertTerm&IsWpError $wpService, - private CreateOrGetTermIdFromString $termHelper, - private UserGroupConfigInterface $config + private SetUserGroup $userHelper ) { } @@ -41,20 +39,13 @@ public function addHooks(): void */ public function setUserGroupFromSsoLoginGroup(int $userId, string|array $groupName): void { - $taxonomy = $this->config->getUserGroupTaxonomy(); $groupName = $this->getGroupNameFromMixed($groupName); if (!$groupName || is_numeric($groupName)) { return; } - if (!$userId) { - return; - } - - if ($termId = $this->termHelper->createOrGetTermIdFromString($groupName, $taxonomy)) { - $this->wpService->wpSetObjectTerms($userId, $termId, $taxonomy, false); - } + $this->userHelper->setUserGroup($groupName, $userId); } /** diff --git a/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.test.php b/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.test.php index 745359f75..a035c30c4 100644 --- a/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.test.php +++ b/library/Integrations/MiniOrange/SetUserGroupFromSsoLoginGroup.test.php @@ -2,8 +2,7 @@ namespace Municipio\Integrations\MiniOrange; -use Municipio\Helper\Term\Contracts\CreateOrGetTermIdFromString; -use Municipio\UserGroup\Config\UserGroupConfigInterface; +use Municipio\Helper\User\Contracts\SetUserGroup; use PHPUnit\Framework\TestCase; use WpService\Implementations\FakeWpService; @@ -14,9 +13,8 @@ class SetUserGroupFromSsoLoginGroupTest extends TestCase */ public function testCanBeInstantiated() { - $termHelper = $this->createMock(CreateOrGetTermIdFromString::class); - $config = $this->createMock(UserGroupConfigInterface::class); - $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup(new FakeWpService(), $termHelper, $config); + $userHelper = $this->createMock(SetUserGroup::class); + $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup(new FakeWpService(), $userHelper); $this->assertInstanceOf(SetUserGroupFromSsoLoginGroup::class, $setGroupAsTaxonomy); } @@ -27,10 +25,9 @@ public function testCanBeInstantiated() public function testSetUserGroupFromSsoLoginGroupDoesNotConnectUserToTermIfGroupNameIsNumeric() { $wpService = new FakeWpService(); - $termHelper = $this->createMock(CreateOrGetTermIdFromString::class); - $config = $this->createMock(UserGroupConfigInterface::class); + $userHelper = $this->createMock(SetUserGroup::class); - $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $termHelper, $config); + $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $userHelper); $setGroupAsTaxonomy->setUserGroupFromSsoLoginGroup(1, 1); $this->assertArrayNotHasKey('wpSetObjectTerms', $wpService->methodCalls); @@ -42,10 +39,9 @@ public function testSetUserGroupFromSsoLoginGroupDoesNotConnectUserToTermIfGroup public function testSetUserGroupFromSsoLoginGroupDoesNotConnectUserToTermIfGroupNameIsEmpty() { $wpService = new FakeWpService(); - $termHelper = $this->createMock(CreateOrGetTermIdFromString::class); - $config = $this->createMock(UserGroupConfigInterface::class); + $userHelper = $this->createMock(SetUserGroup::class); - $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $termHelper, $config); + $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $userHelper); $setGroupAsTaxonomy->setUserGroupFromSsoLoginGroup(1, ''); $this->assertArrayNotHasKey('wpSetObjectTerms', $wpService->methodCalls); @@ -57,10 +53,9 @@ public function testSetUserGroupFromSsoLoginGroupDoesNotConnectUserToTermIfGroup public function testSetUserGroupFromSsoLoginGroupDoesNotConnectUserToTermIfUserIdIsEmpty() { $wpService = new FakeWpService(); - $termHelper = $this->createMock(CreateOrGetTermIdFromString::class); - $config = $this->createMock(UserGroupConfigInterface::class); + $userHelper = $this->createMock(SetUserGroup::class); - $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $termHelper, $config); + $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $userHelper); $setGroupAsTaxonomy->setUserGroupFromSsoLoginGroup(0, 'group'); $this->assertArrayNotHasKey('wpSetObjectTerms', $wpService->methodCalls); @@ -72,14 +67,10 @@ public function testSetUserGroupFromSsoLoginGroupDoesNotConnectUserToTermIfUserI public function testSetUserGroupFromSsoLoginGroupConnectsUserToTerm() { $wpService = new FakeWpService(['wpSetObjectTerms' => []]); - $termHelper = $this->createMock(CreateOrGetTermIdFromString::class); - $config = $this->createMock(UserGroupConfigInterface::class); + $userHelper = $this->createMock(SetUserGroup::class); + $userHelper->expects($this->once())->method('setUserGroup'); - $termHelper->method('createOrGetTermIdFromString')->willReturn(1); - - $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $termHelper, $config); + $setGroupAsTaxonomy = new SetUserGroupFromSsoLoginGroup($wpService, $userHelper); $setGroupAsTaxonomy->setUserGroupFromSsoLoginGroup(1, 'group'); - - $this->assertArrayHasKey('wpSetObjectTerms', $wpService->methodCalls); } }