diff --git a/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php b/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php index 6d63ddb4a..0f299788b 100644 --- a/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php +++ b/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php @@ -24,11 +24,20 @@ define('POWER_USER_PORTAL_PROFILE_NAME', 'Portal power user'); */ class UserProfilesEventListener implements iEventServiceSetup { + private $oUserPortalProfile; + private $bIsRepairmentEnabled = false; + /** * @inheritDoc */ public function RegisterEventsAndListeners() { + $this->Init(); + + if (false === $this->bIsRepairmentEnabled){ + return; + } + $callback = [$this, 'OnUserProfileLinkChange']; $aEventSource = [\User::class, \UserExternal::class, \UserInternal::class]; @@ -45,23 +54,82 @@ class UserProfilesEventListener implements iEventServiceSetup ); } + public function IsRepairmentEnabled() : bool + { + return $this->bIsRepairmentEnabled; + } + public function OnUserProfileLinkChange(EventData $oEventData): void { /** @var \User $oObject */ $oUser = $oEventData->Get('object'); try { - self::RepairProfiles($oUser); - } catch (Exception $oException) { - IssueLog::Error('Exception occurred on OnUserProfileLinkChange', LogChannels::DM_CRUD, [ + $this->RepairProfiles($oUser); + } catch (Exception $e) { + IssueLog::Error('Exception occurred on RepairProfiles', LogChannels::DM_CRUD, [ 'user_class' => get_class($oUser), 'user_id' => $oUser->GetKey(), - 'exception_message' => $oException->getMessage(), - 'exception_stacktrace' => $oException->getTraceAsString(), + 'exception_message' => $e->getMessage(), + 'exception_stacktrace' => $e->getTraceAsString(), ]); } } - public static function RepairProfiles(\User $oUser) : void + /** + * @param $aPortalDispatcherData: passed only for testing purpose + * + * @return void + * @throws \ConfigException + * @throws \CoreException + */ + public function Init($aPortalDispatcherData=null) : void { + if (is_null($aPortalDispatcherData)){ + $aPortalDispatcherData = \PortalDispatcherData::GetData(); + } + + $sRepairmentProfile = \utils::GetConfig()->GetModuleSetting('itop-profiles-itil', 'poweruserportal-repair-profile', null); + + if (is_null($sRepairmentProfile) && sizeof($aPortalDispatcherData) > 2){ + //when there are further portals we dont want to force a specific portal by repairing the associated profiles to a user + $this->bIsRepairmentEnabled = false; + return; + } + + if (is_null($sRepairmentProfile)){ + $sRepairmentProfile = PORTAL_PROFILE_NAME; + } + + try { + $sOQL = sprintf("SELECT URP_Profiles WHERE name = '%s'", $sRepairmentProfile); + $oSearch = \DBSearch::FromOQL($sOQL); + $oSearch->AllowAllData(); + $oSet = new \DBObjectSet($oSearch); + if ($oSet->Count() !== 1) { + //user portal profile does not exist + //current iTop is customized enough to disable repairment + $this->bIsRepairmentEnabled = false; + return; + } + + $this->oUserPortalProfile = $oSet->Fetch(); + if (is_null($this->oUserPortalProfile)){ + //may be not required. preventive code to disable repairment + $this->bIsRepairmentEnabled = false; + return; + } + } catch (\Exception $e) { + IssueLog::Error('Exception when searching user portal profile', LogChannels::DM_CRUD, [ + 'exception_message' => $e->getMessage(), + 'exception_stacktrace' => $e->getTraceAsString(), + ]); + $this->bIsRepairmentEnabled = false; + return; + } + + $this->bIsRepairmentEnabled = true; + } + + public function RepairProfiles(\User $oUser) : void { if (!is_null($oUser)) { @@ -72,17 +140,8 @@ class UserProfilesEventListener implements iEventServiceSetup if (POWER_USER_PORTAL_PROFILE_NAME === $oProfile->Get('profile')){ //add portal user // power portal user is not a standalone profile (it will break console UI) - $sOQL = sprintf("SELECT URP_Profiles WHERE name = '%s'", PORTAL_PROFILE_NAME); - $oSearch = \DBSearch::FromOQL($sOQL); - $oSearch->AllowAllData(); - $oSet = new \DBObjectSet($oSearch); - if ($oSet->Count() !==1){ - return; - } - - $oUserPortalProfile = $oSet->Fetch(); $oUserProfile = new \URP_UserProfile(); - $oUserProfile->Set('profileid', $oUserPortalProfile->GetKey()); + $oUserProfile->Set('profileid', $this->oUserPortalProfile->GetKey()); $oCurrentUserProfileSet->AddItem($oUserProfile); $oUser->Set('profile_list', $oCurrentUserProfileSet); } diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index 80993cd4e..0b4cc29e4 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -26,7 +26,6 @@ namespace Combodo\iTop\Test\UnitTest\Core; -use Combodo\iTop\Application\UI\Base\Layout\NavigationMenu\NavigationMenuFactory; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use CoreCannotSaveObjectException; use CoreException; @@ -553,328 +552,4 @@ class UserRightsTest extends ItopDataTestCase ['Person', 'team_list', false], ]; } - - public function PortaPowerUserProvider(){ - return [ - 'Portal power user only => user should be repaired by adding User portal profile' => [ - 'aAssociatedProfilesBeforeUserCreation' => [ - 'Portal power user' - ], - 'aExpectedAssociatedProfilesAfterUserCreation'=> [ - 'Portal power user', - 'Portal user', - ] - ], - 'Portal power user + Support Agent => profiles untouched' => [ - 'aAssociatedProfilesBeforeUserCreation' => [ - 'Portal power user', - 'Support Agent', - ], - 'aExpectedAssociatedProfilesAfterUserCreation'=> [ - 'Portal power user', - 'Support Agent', - ] - ], - ]; - } - - /** - * @since 3.1.0 N°5324 - * @dataProvider PortaPowerUserProvider - */ - public function testUserLocalCreation($aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $oUser = new \UserLocal(); - $sLogin = 'testUserLocalCreationWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - $oUser->Set('password', 'ABCD1234@gabuzomeu'); - $oUser->Set('language', 'EN US'); - $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); - } - - /** - * @since 3.1.0 N°5324 - * @dataProvider PortaPowerUserProvider - */ - public function testUserLocalUpdate($aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $oUser = new \UserLocal(); - $sLogin = 'testUserLocalUpdateWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - $oUser->Set('password', 'ABCD1234@gabuzomeu'); - $oUser->Set('language', 'EN US'); - $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); - } - - /** - * @since 3.1.0 N°5324 - * @dataProvider PortaPowerUserProvider - */ - public function testUserLDAPCreation($aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $oUser = new \UserLDAP(); - $sLogin = 'testUserLDAPCreationWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); - } - - /** - * @since 3.1.0 N°5324 - * @dataProvider PortaPowerUserProvider - */ - public function testUserLDAPUpdate($aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $oUser = new \UserLDAP(); - $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); - } - - /** - * @since 3.1.0 N°5324 - * @dataProvider PortaPowerUserProvider - */ - public function testUserExternalCreation($aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $oUser = new \UserExternal(); - $sLogin = 'testUserLDAPCreationWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); - } - - /** - * @since 3.1.0 N°5324 - * @dataProvider PortaPowerUserProvider - */ - public function testUserExternalUpdate($aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $oUser = new \UserExternal(); - $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); - } - - public function CreateUserForProfileTesting(\User $oUserToCreate, array $aAssociatedProfilesBeforeUserCreation) : array - { - $aProfiles = []; - $oSearch = \DBSearch::FromOQL("SELECT URP_Profiles"); - $oProfileSet = new DBObjectSet($oSearch); - while (($oProfile = $oProfileSet->Fetch()) != null){ - $aProfiles[$oProfile->Get('name')] = $oProfile; - } - - $this->CreateTestOrganization(); - $oContact = $this->CreatePerson("1"); - $iContactid = $oContact->GetKey(); - - $oUserToCreate->Set('contactid', $iContactid); - $sUserClass = get_class($oUserToCreate); - - $oUserProfileList = $oUserToCreate->Get('profile_list'); - foreach ($aAssociatedProfilesBeforeUserCreation as $sProfileName){ - $oUserProfile = new URP_UserProfile(); - $oProfile = $aProfiles[$sProfileName]; - $oUserProfile->Set('profileid', $oProfile->GetKey()); - $oUserProfile->Set('reason', 'UNIT Tests'); - $oUserProfileList->AddItem($oUserProfile); - } - - $oUserToCreate->Set('profile_list', $oUserProfileList); - $sId = $oUserToCreate->DBInsert(); - - return [ $sId, $aProfiles]; - } - - public function commonUserCreation($oUserToCreate, $aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $sUserClass = get_class($oUserToCreate); - list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUserToCreate, $aAssociatedProfilesBeforeUserCreation); - - $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation); - } - - public function CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation){ - $oUser = \MetaModel::GetObject($sUserClass, $sId); - $oUserProfileList = $oUser->Get('profile_list'); - $aProfilesAfterCreation=[]; - while (($oProfile = $oUserProfileList->Fetch()) != null){ - $aProfilesAfterCreation[] = $oProfile->Get('profile'); - } - - foreach ($aExpectedAssociatedProfilesAfterUserCreation as $sExpectedProfileName){ - $this->assertTrue(in_array($sExpectedProfileName, $aProfilesAfterCreation), - "profile \'$sExpectedProfileName\' should be asociated to user after creation. " . var_export($aProfilesAfterCreation, true) ); - } - - $_SESSION = []; - - //$this->expectException(\Exception::class); - UserRights::Login($oUser->Get('login')); - - if (! UserRights::IsPortalUser()) { - //calling this API triggers Fatal Error on below OQL used by \User->GetContactObject() for a user with only 'portal power user' profile - /** - * Error: No result for the single row query: 'SELECT DISTINCT `Contact`.`id` AS `Contactid`, `Contact`.`name` AS `Contactname`, `Contact`.`status` AS `Contactstatus`, `Contact`.`org_id` AS `Contactorg_id`, `Organization_org_id`.`name` AS `Contactorg_name`, `Contact`.`email` AS `Contactemail`, `Contact`.`phone` AS `Contactphone`, `Contact`.`notify` AS `Contactnotify`, `Contact`.`function` AS `Contactfunction`, `Contact`.`finalclass` AS `Contactfinalclass`, IF((`Contact`.`finalclass` IN ('Team', 'Contact')), CAST(CONCAT(COALESCE(`Contact`.`name`, '')) AS CHAR), CAST(CONCAT(COALESCE(`Contact_poly_Person`.`first_name`, ''), COALESCE(' ', ''), COALESCE(`Contact`.`name`, '')) AS CHAR)) AS `Contactfriendlyname`, COALESCE((`Contact`.`status` = 'inactive'), 0) AS `Contactobsolescence_flag`, `Contact`.`obsolescence_date` AS `Contactobsolescence_date`, CAST(CONCAT(COALESCE(`Organization_org_id`.`name`, '')) AS CHAR) AS `Contactorg_id_friendlyname`, COALESCE((`Organization_org_id`.`status` = 'inactive'), 0) AS `Contactorg_id_obsolescence_flag` FROM `contact` AS `Contact` INNER JOIN `organization` AS `Organization_org_id` ON `Contact`.`org_id` = `Organization_org_id`.`id` LEFT JOIN `person` AS `Contact_poly_Person` ON `Contact`.`id` = `Contact_poly_Person`.`id` WHERE ((`Contact`.`id` = 40) AND 0) '. - */ - NavigationMenuFactory::MakeStandard(); - } - - $this->assertTrue(true, 'after fix N°5324 no exception raised'); - // logout - $_SESSION = []; - } - - public function commonUserUpdate($oUserToCreate, $aAssociatedProfilesBeforeUserCreation, - $aExpectedAssociatedProfilesAfterUserCreation) - { - $sUserClass = get_class($oUserToCreate); - list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUserToCreate, ["Administrator"]); - - $oUserToUpdate = \MetaModel::GetObject($sUserClass, $sId); - $oProfileList = $oUserToUpdate->Get('profile_list'); - while($oObj = $oProfileList->Fetch()){ - $oProfileList->RemoveItem($oObj->GetKey()); - } - - foreach ($aAssociatedProfilesBeforeUserCreation as $sProfileName){ - $oAdminUrpProfile = new URP_UserProfile(); - $oProfile = $aProfiles[$sProfileName]; - $oAdminUrpProfile->Set('profileid', $oProfile->GetKey()); - $oAdminUrpProfile->Set('reason', 'UNIT Tests'); - $oProfileList->AddItem($oAdminUrpProfile); - } - - $oUserToUpdate->Set('profile_list', $oProfileList); - $oUserToUpdate->DBWrite(); - - $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation); - } - - public function testUpdateUserExternalProfilesViaLinks(){ - $aInitialProfiles = [ "Administrator", "Portal power user"]; - - $oUser = new \UserExternal(); - $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - - $sUserClass = get_class($oUser); - list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, $aInitialProfiles); - - $aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId); - $aProfilesToRemove = ["Administrator"]; - foreach ($aProfilesToRemove as $sProfileName){ - if (array_key_exists($sProfileName, $aURPUserProfileByUser)){ - $oURPUserProfile = $aURPUserProfileByUser[$sProfileName]; - $oURPUserProfile->DBDelete(); - } - } - - $aExpectedProfilesAfterUpdate = ["Portal power user", "Portal user"]; - $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedProfilesAfterUpdate); - } - - public function BulkUpdateUserExternalProfilesViaLinksProvider(){ - return [ - 'user profiles REPAIR 1' => [ - "aInitialProfiles" => [ "Administrator"], - "aOperation" => [ - '-Administrator', - '+Portal power user', - ], - "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"], - ], - 'user profiles REPAIR 2' => [ - "aInitialProfiles" => [ "Administrator"], - "aOperation" => [ - '+Portal power user', - '-Administrator', - ], - "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"], - ], - 'user profiles REPAIR 3' => [ - "aInitialProfiles" => [ "Administrator", "Portal power user"], - "aOperation" => [ - '-Administrator', - ], - "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"], - ], - 'NOTHING DONE with 1 profile' => [ - "aInitialProfiles" => [ "Administrator", "Portal power user"], - "aOperation" => [ - '-Portal power user', - ], - "aExpectedProfilesAfterUpdate" => ["Administrator"], - ], - 'NOTHING DONE with 2 profiles including power...' => [ - "aInitialProfiles" => [ "Administrator"], - "aOperation" => [ - '+Portal power user', - ], - "aExpectedProfilesAfterUpdate" => ["Administrator", "Portal power user"], - ], - 'NOTHING DONE with 2 profiles including power again ...' => [ - "aInitialProfiles" => [ "Administrator"], - "aOperation" => [ - '+Portal power user', - ], - "aExpectedProfilesAfterUpdate" => ["Portal user", "Portal power user"], - ], - ]; - } - - /** - * @dataProvider BulkUpdateUserExternalProfilesViaLinksProvider - */ - public function testBulkUpdateUserExternalProfilesViaLinks($aInitialProfiles, $aOperation, $aExpectedProfilesAfterUpdate){ - $oUser = new \UserExternal(); - $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); - $oUser->Set('login', $sLogin); - - $sUserClass = get_class($oUser); - list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, $aInitialProfiles); - - \cmdbAbstractObject::SetEventDBLinksChangedBlocked(true); - - $aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId); - foreach ($aOperation as $sOperation){ - $sOp = substr($sOperation,0, 1); - $sProfileName = substr($sOperation,1); - - if ($sOp === "-"){ - if (array_key_exists($sProfileName, $aURPUserProfileByUser)){ - $oURPUserProfile = $aURPUserProfileByUser[$sProfileName]; - $oURPUserProfile->DBDelete(); - } - } else { - $oAdminUrpProfile = new URP_UserProfile(); - $oProfile = $aProfiles[$sProfileName]; - $oAdminUrpProfile->Set('profileid', $oProfile->GetKey()); - $oAdminUrpProfile->Set('userid', $sId); - $oAdminUrpProfile->DBInsert(); - } - } - - \cmdbAbstractObject::SetEventDBLinksChangedBlocked(false); - \cmdbAbstractObject::FireEventDbLinksChangedForAllObjects(); - - $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedProfilesAfterUpdate); - } - - private function GetURPUserProfileByUser($iUserId) : array { - $aRes = []; - $oSearch = \DBSearch::FromOQL("SELECT URP_UserProfile WHERE userid=$iUserId"); - $oSet = new DBObjectSet($oSearch); - while (($oURPUserProfile = $oSet->Fetch()) != null){ - $aRes[$oURPUserProfile->Get('profile')] = $oURPUserProfile; - } - - return $aRes; - } } diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-profiles-itil/UserProfilesEventListenerTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-profiles-itil/UserProfilesEventListenerTest.php new file mode 100644 index 000000000..6d020f6de --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-profiles-itil/UserProfilesEventListenerTest.php @@ -0,0 +1,448 @@ + +// + +/** + * Created by PhpStorm. + * User: Eric + * Date: 25/01/2018 + * Time: 11:12 + */ + +namespace Combodo\iTop\Test\UnitTest\Module\iTopProfilesItil; + +use Combodo\iTop\Application\UI\Base\Layout\NavigationMenu\NavigationMenuFactory; +use Combodo\iTop\ItilProfiles\UserProfilesEventListener; +use Combodo\iTop\Test\UnitTest\ItopDataTestCase; +use DBObjectSet; +use URP_UserProfile; +use UserRights; + +/** + * @group itopRequestMgmt + * @group userRights + * @group defaultProfiles + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * @backupGlobals disabled + */ +class UserProfilesEventListenerTest extends ItopDataTestCase +{ + public function PortaPowerUserProvider(){ + return [ + 'Portal power user only => user should be repaired by adding User portal profile' => [ + 'aAssociatedProfilesBeforeUserCreation' => [ + 'Portal power user' + ], + 'aExpectedAssociatedProfilesAfterUserCreation'=> [ + 'Portal power user', + 'Portal user', + ] + ], + 'Portal power user + Support Agent => profiles untouched' => [ + 'aAssociatedProfilesBeforeUserCreation' => [ + 'Portal power user', + 'Support Agent', + ], + 'aExpectedAssociatedProfilesAfterUserCreation'=> [ + 'Portal power user', + 'Support Agent', + ] + ], + ]; + } + + /** + * @since 3.1.0 N°5324 + * @dataProvider PortaPowerUserProvider + */ + public function testUserLocalCreation($aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $oUser = new \UserLocal(); + $sLogin = 'testUserLocalCreationWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + $oUser->Set('password', 'ABCD1234@gabuzomeu'); + $oUser->Set('language', 'EN US'); + $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); + } + + /** + * @since 3.1.0 N°5324 + * @dataProvider PortaPowerUserProvider + */ + public function testUserLocalUpdate($aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $oUser = new \UserLocal(); + $sLogin = 'testUserLocalUpdateWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + $oUser->Set('password', 'ABCD1234@gabuzomeu'); + $oUser->Set('language', 'EN US'); + $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); + } + + /** + * @since 3.1.0 N°5324 + * @dataProvider PortaPowerUserProvider + */ + public function testUserLDAPCreation($aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $oUser = new \UserLDAP(); + $sLogin = 'testUserLDAPCreationWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); + } + + /** + * @since 3.1.0 N°5324 + * @dataProvider PortaPowerUserProvider + */ + public function testUserLDAPUpdate($aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $oUser = new \UserLDAP(); + $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); + } + + /** + * @since 3.1.0 N°5324 + * @dataProvider PortaPowerUserProvider + */ + public function testUserExternalCreation($aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $oUser = new \UserExternal(); + $sLogin = 'testUserLDAPCreationWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); + } + + /** + * @since 3.1.0 N°5324 + * @dataProvider PortaPowerUserProvider + */ + public function testUserExternalUpdate($aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $oUser = new \UserExternal(); + $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation); + } + + public function CreateUserForProfileTesting(\User $oUserToCreate, array $aAssociatedProfilesBeforeUserCreation, $bDbInsert=true) : array + { + $aProfiles = []; + $oSearch = \DBSearch::FromOQL("SELECT URP_Profiles"); + $oProfileSet = new DBObjectSet($oSearch); + while (($oProfile = $oProfileSet->Fetch()) != null){ + $aProfiles[$oProfile->Get('name')] = $oProfile; + } + + $this->CreateTestOrganization(); + $oContact = $this->CreatePerson("1"); + $iContactid = $oContact->GetKey(); + + $oUserToCreate->Set('contactid', $iContactid); + $sUserClass = get_class($oUserToCreate); + + $oUserProfileList = $oUserToCreate->Get('profile_list'); + foreach ($aAssociatedProfilesBeforeUserCreation as $sProfileName){ + $oUserProfile = new URP_UserProfile(); + $oProfile = $aProfiles[$sProfileName]; + $oUserProfile->Set('profileid', $oProfile->GetKey()); + $oUserProfile->Set('reason', 'UNIT Tests'); + $oUserProfileList->AddItem($oUserProfile); + } + + $oUserToCreate->Set('profile_list', $oUserProfileList); + if ($bDbInsert){ + $sId = $oUserToCreate->DBInsert(); + } else { + $sId = -1; + } + + return [ $sId, $aProfiles]; + } + + public function commonUserCreation($oUserToCreate, $aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $sUserClass = get_class($oUserToCreate); + list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUserToCreate, $aAssociatedProfilesBeforeUserCreation); + + $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation); + } + + public function CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation){ + $oUser = \MetaModel::GetObject($sUserClass, $sId); + $oUserProfileList = $oUser->Get('profile_list'); + $aProfilesAfterCreation=[]; + while (($oProfile = $oUserProfileList->Fetch()) != null){ + $aProfilesAfterCreation[] = $oProfile->Get('profile'); + } + + foreach ($aExpectedAssociatedProfilesAfterUserCreation as $sExpectedProfileName){ + $this->assertTrue(in_array($sExpectedProfileName, $aProfilesAfterCreation), + "profile \'$sExpectedProfileName\' should be asociated to user after creation. " . var_export($aProfilesAfterCreation, true) ); + } + + $_SESSION = []; + + //$this->expectException(\Exception::class); + UserRights::Login($oUser->Get('login')); + + if (! UserRights::IsPortalUser()) { + //calling this API triggers Fatal Error on below OQL used by \User->GetContactObject() for a user with only 'portal power user' profile + /** + * Error: No result for the single row query: 'SELECT DISTINCT `Contact`.`id` AS `Contactid`, `Contact`.`name` AS `Contactname`, `Contact`.`status` AS `Contactstatus`, `Contact`.`org_id` AS `Contactorg_id`, `Organization_org_id`.`name` AS `Contactorg_name`, `Contact`.`email` AS `Contactemail`, `Contact`.`phone` AS `Contactphone`, `Contact`.`notify` AS `Contactnotify`, `Contact`.`function` AS `Contactfunction`, `Contact`.`finalclass` AS `Contactfinalclass`, IF((`Contact`.`finalclass` IN ('Team', 'Contact')), CAST(CONCAT(COALESCE(`Contact`.`name`, '')) AS CHAR), CAST(CONCAT(COALESCE(`Contact_poly_Person`.`first_name`, ''), COALESCE(' ', ''), COALESCE(`Contact`.`name`, '')) AS CHAR)) AS `Contactfriendlyname`, COALESCE((`Contact`.`status` = 'inactive'), 0) AS `Contactobsolescence_flag`, `Contact`.`obsolescence_date` AS `Contactobsolescence_date`, CAST(CONCAT(COALESCE(`Organization_org_id`.`name`, '')) AS CHAR) AS `Contactorg_id_friendlyname`, COALESCE((`Organization_org_id`.`status` = 'inactive'), 0) AS `Contactorg_id_obsolescence_flag` FROM `contact` AS `Contact` INNER JOIN `organization` AS `Organization_org_id` ON `Contact`.`org_id` = `Organization_org_id`.`id` LEFT JOIN `person` AS `Contact_poly_Person` ON `Contact`.`id` = `Contact_poly_Person`.`id` WHERE ((`Contact`.`id` = 40) AND 0) '. + */ + NavigationMenuFactory::MakeStandard(); + } + + $this->assertTrue(true, 'after fix N°5324 no exception raised'); + // logout + $_SESSION = []; + } + + public function commonUserUpdate($oUserToCreate, $aAssociatedProfilesBeforeUserCreation, + $aExpectedAssociatedProfilesAfterUserCreation) + { + $sUserClass = get_class($oUserToCreate); + list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUserToCreate, ["Administrator"]); + + $oUserToUpdate = \MetaModel::GetObject($sUserClass, $sId); + $oProfileList = $oUserToUpdate->Get('profile_list'); + while($oObj = $oProfileList->Fetch()){ + $oProfileList->RemoveItem($oObj->GetKey()); + } + + foreach ($aAssociatedProfilesBeforeUserCreation as $sProfileName){ + $oAdminUrpProfile = new URP_UserProfile(); + $oProfile = $aProfiles[$sProfileName]; + $oAdminUrpProfile->Set('profileid', $oProfile->GetKey()); + $oAdminUrpProfile->Set('reason', 'UNIT Tests'); + $oProfileList->AddItem($oAdminUrpProfile); + } + + $oUserToUpdate->Set('profile_list', $oProfileList); + $oUserToUpdate->DBWrite(); + + $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation); + } + + public function testUpdateUserExternalProfilesViaLinks(){ + $aInitialProfiles = [ "Administrator", "Portal power user"]; + + $oUser = new \UserExternal(); + $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + + $sUserClass = get_class($oUser); + list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, $aInitialProfiles); + + $aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId); + $sProfileNameToRemove = "Administrator"; + if (array_key_exists($sProfileNameToRemove, $aURPUserProfileByUser)){ + $oURPUserProfile = $aURPUserProfileByUser[$sProfileNameToRemove]; + $oURPUserProfile->DBDelete(); + } + + $aExpectedProfilesAfterUpdate = ["Portal power user", "Portal user"]; + $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedProfilesAfterUpdate); + } + + public function BulkUpdateUserExternalProfilesViaLinksProvider(){ + return [ + 'user profiles REPAIR 1' => [ + "aInitialProfiles" => [ "Administrator"], + "aOperation" => [ + '-Administrator', + '+Portal power user', + ], + "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"], + ], + 'user profiles REPAIR 2' => [ + "aInitialProfiles" => [ "Administrator"], + "aOperation" => [ + '+Portal power user', + '-Administrator', + ], + "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"], + ], + 'user profiles REPAIR 3' => [ + "aInitialProfiles" => [ "Administrator", "Portal power user"], + "aOperation" => [ + '-Administrator', + ], + "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"], + ], + 'NOTHING DONE with 1 profile' => [ + "aInitialProfiles" => [ "Administrator", "Portal power user"], + "aOperation" => [ + '-Portal power user', + ], + "aExpectedProfilesAfterUpdate" => ["Administrator"], + ], + 'NOTHING DONE with 2 profiles including power...' => [ + "aInitialProfiles" => [ "Administrator"], + "aOperation" => [ + '+Portal power user', + ], + "aExpectedProfilesAfterUpdate" => ["Administrator", "Portal power user"], + ], + 'NOTHING DONE with 2 profiles including power again ...' => [ + "aInitialProfiles" => [ "Portal user"], + "aOperation" => [ + '+Portal power user', + ], + "aExpectedProfilesAfterUpdate" => ["Portal user", "Portal power user"], + ], + ]; + } + + /** + * @dataProvider BulkUpdateUserExternalProfilesViaLinksProvider + */ + public function testBulkUpdateUserExternalProfilesViaLinks($aInitialProfiles, $aOperation, $aExpectedProfilesAfterUpdate){ + $oUser = new \UserExternal(); + $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + + $sUserClass = get_class($oUser); + list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, $aInitialProfiles); + + \cmdbAbstractObject::SetEventDBLinksChangedBlocked(true); + + $aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId); + foreach ($aOperation as $sOperation){ + $sOp = substr($sOperation,0, 1); + $sProfileName = substr($sOperation,1); + + if ($sOp === "-"){ + if (array_key_exists($sProfileName, $aURPUserProfileByUser)){ + $oURPUserProfile = $aURPUserProfileByUser[$sProfileName]; + $oURPUserProfile->DBDelete(); + } + } else { + $oAdminUrpProfile = new URP_UserProfile(); + $oProfile = $aProfiles[$sProfileName]; + $oAdminUrpProfile->Set('profileid', $oProfile->GetKey()); + $oAdminUrpProfile->Set('userid', $sId); + $oAdminUrpProfile->DBInsert(); + } + } + + \cmdbAbstractObject::SetEventDBLinksChangedBlocked(false); + \cmdbAbstractObject::FireEventDbLinksChangedForAllObjects(); + + $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedProfilesAfterUpdate); + } + + private function GetURPUserProfileByUser($iUserId) : array { + $aRes = []; + $oSearch = \DBSearch::FromOQL("SELECT URP_UserProfile WHERE userid=$iUserId"); + $oSet = new DBObjectSet($oSearch); + while (($oURPUserProfile = $oSet->Fetch()) != null){ + $aRes[$oURPUserProfile->Get('profile')] = $oURPUserProfile; + } + + return $aRes; + } + + public function testUserProfilesEventListenerInit_nominal(){ + $oUserProfilesEventListener = new UserProfilesEventListener(); + $oUserProfilesEventListener->Init(); + + $this->assertTrue($oUserProfilesEventListener->IsRepairmentEnabled()); + } + + public function testUserProfilesEventListenerInit_furtherportals_norepairmentconfigured(){ + $aPortalDispatcherData = [ + 'itop-portal', + 'customer-portal', + 'backoffice' + ]; + + $oUserProfilesEventListener = new UserProfilesEventListener(); + $oUserProfilesEventListener->Init($aPortalDispatcherData); + + $this->assertFalse($oUserProfilesEventListener->IsRepairmentEnabled()); + } + + public function testUserProfilesEventListenerInit_furtherportals_repairmentconfigured(){ + $aPortalDispatcherData = [ + 'itop-portal', + 'customer-portal', + 'backoffice' + ]; + + \MetaModel::GetConfig()->SetModuleSetting('itop-profiles-itil', 'poweruserportal-repair-profile', 'Portal user'); + + $oUserProfilesEventListener = new UserProfilesEventListener(); + $oUserProfilesEventListener->Init($aPortalDispatcherData); + + $this->assertTrue($oUserProfilesEventListener->IsRepairmentEnabled()); + } + + public function testUserProfilesEventListenerInit_with_unknownprofile(){ + $aPortalDispatcherData = [ + 'itop-portal', + 'customer-portal', + 'backoffice' + ]; + + \MetaModel::GetConfig()->SetModuleSetting('itop-profiles-itil', 'poweruserportal-repair-profile', 'Dummy Profile'); + + $oUserProfilesEventListener = new UserProfilesEventListener(); + $oUserProfilesEventListener->Init($aPortalDispatcherData); + + $this->assertFalse($oUserProfilesEventListener->IsRepairmentEnabled()); + } + + public function testRepairProfiles_WithAnotherFallbackProfile() + { + $oUser = new \UserLocal(); + $sLogin = 'testUserLocalCreationWithPortalPowerUserProfile-'.uniqid(); + $oUser->Set('login', $sLogin); + $oUser->Set('password', 'ABCD1234@gabuzomeu'); + $oUser->Set('language', 'EN US'); + + \MetaModel::GetConfig()->SetModuleSetting('itop-profiles-itil', 'poweruserportal-repair-profile', 'Change Supervisor'); + $oUserProfilesEventListener = new UserProfilesEventListener(); + $oUserProfilesEventListener->Init(); + $this->assertTrue($oUserProfilesEventListener->IsRepairmentEnabled()); + + $this->CreateUserForProfileTesting($oUser, ['Portal power user'], false); + $oUserProfilesEventListener->RepairProfiles($oUser); + + $oUserProfileList = $oUser->Get('profile_list'); + $aProfilesAfterCreation=[]; + while (($oProfile = $oUserProfileList->Fetch()) != null){ + $aProfilesAfterCreation[] = $oProfile->Get('profile'); + } + + $this->assertContains('Change Supervisor', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true)); + $this->assertContains('Portal power user', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true)); + } +}