diff --git a/core/action.class.inc.php b/core/action.class.inc.php index 27947a6987..4054e2107a 100644 --- a/core/action.class.inc.php +++ b/core/action.class.inc.php @@ -41,9 +41,10 @@ require_once(APPROOT.'/core/email.class.inc.php'); */ abstract class Action extends cmdbAbstractObject { - /** @var $oCallingTrigger Trigger|null The trigger that called this action {@see DoExecute} + /** + * @var $oCallingTrigger Trigger|null The trigger that called this action {@see DoExecute} * @since 3.2.0 - * */ + */ protected ?Trigger $oCallingTrigger = null; /** diff --git a/core/datamodel.core.xml b/core/datamodel.core.xml index fab9c25725..059a3d6273 100644 --- a/core/datamodel.core.xml +++ b/core/datamodel.core.xml @@ -132,7 +132,7 @@ 96 256 256 - null + priority @@ -253,7 +253,7 @@ false public Get('recipients')); $oRecipientsSearch->AllowAllData(); @@ -262,15 +262,36 @@ while ($oRecipient = $oRecipientsSet->Fetch()) { // Skip recipients that have no users if (get_class($oRecipient) === Person::class && UserRights::GetUserFromPerson($oRecipient) === null) { - continue; - } + continue; + } if (!\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->IsSubscribed($oTrigger, $this, $oRecipient)) { - continue; - } + continue; + } + + if (array_key_exists('this->object()', $aContextArgs)) { + $iObjectId = $aContextArgs['this->object()']->GetKey(); + $sObjectClass = get_class($aContextArgs['this->object()']); + } else { + $iObjectId = 0; + $sObjectClass = null; + } + $oEvent = new EventiTopNotification(); $oEvent->Set('title', MetaModel::ApplyParams($this->Get('title'), $aContextArgs)); $oEvent->Set('message', MetaModel::ApplyParams($this->Get('message'), $aContextArgs)); - $oIcon = !$this->Get('icon')->IsEmpty() ? $this->Get('icon') : MetaModel::GetAttributeDef('EventiTopNotification', 'icon')->MakeRealValue(Combodo\iTop\Application\Branding::GetCompactMainLogoAbsoluteUrl(), $oEvent); + // Compute icon + // - First check if one is defined on the action + if (false === $this->Get('icon')->IsEmpty()) { + $oIcon = $this->Get('icon'); + } + // - Then, check if the action is for a DM object and if its class has an icon + elseif ($iObjectId > 0 && utils::IsNotNullOrEmptyString(MetaModel::GetClassIcon($sObjectClass, false))) { + $oIcon = MetaModel::GetAttributeDef(EventiTopNotification::class, 'icon')->MakeRealValue(MetaModel::GetClassIcon($sObjectClass, false), $oEvent); + } + // - Otherwise, fallback on the compact logo of the application + else { + $oIcon = MetaModel::GetAttributeDef(EventiTopNotification::class, 'icon')->MakeRealValue(\Combodo\iTop\Application\Branding::GetCompactMainLogoAbsoluteUrl(), $oEvent); + } $oEvent->Set('icon', $oIcon); $oEvent->Set('priority', $this->Get('priority')); $oEvent->Set('contact_id', $oRecipient->GetKey()); @@ -281,7 +302,7 @@ $oEvent->Set('url', MetaModel::ApplyParams($this->Get('url'), $aContextArgs)); $oEvent->DBInsertNoReload(); - \Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oRecipient); + \Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oRecipient); } $this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null); } @@ -317,7 +338,7 @@ icon true - null + priority diff --git a/datamodels/2.x/itop-structure/module.itop-structure.php b/datamodels/2.x/itop-structure/module.itop-structure.php index e0743c13c9..66e8381f5e 100644 --- a/datamodels/2.x/itop-structure/module.itop-structure.php +++ b/datamodels/2.x/itop-structure/module.itop-structure.php @@ -73,7 +73,7 @@ if (!class_exists('StructureInstaller')) SetupLog::Info("| Migrate ActionEmail language attribute values to its parent."); $sTableToRead = MetaModel::DBGetTable('ActionEmail'); $sTableToSet = MetaModel::DBGetTable('ActionNotification'); - self::MoveColumnInDB($sTableToRead, 'language', $sTableToSet, 'language'); + self::MoveColumnInDB($sTableToRead, 'language', $sTableToSet, 'language', true); SetupLog::Info("| ActionEmail migration done."); } // If you want to migrate data from one format to another, do it here diff --git a/sources/Controller/Newsroom/iTopNewsroomController.php b/sources/Controller/Newsroom/iTopNewsroomController.php index fac160da6b..b32a85c24d 100644 --- a/sources/Controller/Newsroom/iTopNewsroomController.php +++ b/sources/Controller/Newsroom/iTopNewsroomController.php @@ -11,6 +11,7 @@ use Combodo\iTop\Service\Router\Router; use CoreException; use DBObjectSearch; use DBObjectSet; +use Dict; use DisplayBlock; use MetaModel; use UserRights; diff --git a/sources/Service/Notification/NotificationsService.php b/sources/Service/Notification/NotificationsService.php index d0caf209f4..810e27b1ce 100644 --- a/sources/Service/Notification/NotificationsService.php +++ b/sources/Service/Notification/NotificationsService.php @@ -105,7 +105,7 @@ class NotificationsService { // Check if the user is already subscribed to the action notification $oSubscribedActionsNotificationsSet = NotificationsRepository::GetInstance()->SearchSubscriptionByTriggerContactAndAction($oTrigger->GetKey(), $oRecipient->GetKey(), $oActionNotification->GetKey()); if ($oSubscribedActionsNotificationsSet->Count() === 0) { - return false; + return true; } // Return the subscribed status diff --git a/tests/php-unit-tests/unitary-tests/application/LoginTest.php b/tests/php-unit-tests/unitary-tests/application/LoginTest.php index 52b4b70c94..583d30d3d5 100644 --- a/tests/php-unit-tests/unitary-tests/application/LoginTest.php +++ b/tests/php-unit-tests/unitary-tests/application/LoginTest.php @@ -26,7 +26,7 @@ class LoginTest extends ItopDataTestCase { @chmod($this->sConfigPath, 0770); $oConfig->WriteToFile(); - @chmod($this->sConfigPath, 0440); + @chmod($this->sConfigPath, 0444); } protected function tearDown(): void { @@ -34,7 +34,7 @@ class LoginTest extends ItopDataTestCase { //put config back @chmod($this->sConfigPath, 0770); file_put_contents($this->sConfigPath, file_get_contents($this->sConfigTmpBackupFile)); - @chmod($this->sConfigPath, 0440); + @chmod($this->sConfigPath, 0444); @unlink($this->sConfigTmpBackupFile); } parent::tearDown(); diff --git a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php index 122da9cbc4..b3dccfc544 100644 --- a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php +++ b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php @@ -58,7 +58,7 @@ class AttributeDefinitionTest extends ItopDataTestCase { // Note: This is test is not great as we are datamodel dependent and don't have a class with all the attribute types return [ 'AttributeDateTime' => [ - Change::class, + UserRequest::class, 'start_date', // no default value on this field <<Set('start_date', '2023-09-06 12:26:00'); diff --git a/tests/php-unit-tests/unitary-tests/core/iTopConfigParserTest.php b/tests/php-unit-tests/unitary-tests/core/iTopConfigParserTest.php index e096c99816..741ae52d61 100644 --- a/tests/php-unit-tests/unitary-tests/core/iTopConfigParserTest.php +++ b/tests/php-unit-tests/unitary-tests/core/iTopConfigParserTest.php @@ -47,7 +47,7 @@ class iTopConfigParserTest extends ItopTestCase @chmod($this->sConfigPath, 0770); $bRenameResult = rename($this->tmpSavePath, $this->sConfigPath); echo "Restored config file, result={$bRenameResult}"; - @chmod($this->sConfigPath, 0440); + @chmod($this->sConfigPath, 0444); } } diff --git a/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php b/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php index 129664c749..1952c2c84f 100644 --- a/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php @@ -32,11 +32,14 @@ class DBBackupDataTest extends ItopDataTestCase if ($bUnsafeFileException) { $this->expectExceptionMessage("Backup: Aborting, resource '$sExtraFile'. Considered as UNSAFE because not inside the iTop directory."); } - $aFiles = $this->InvokeNonPublicMethod('DBBackup', 'PrepareFilesToBackup', $oBackup, [APPROOT . '/conf/production/config-itop.php', $sTmpDir, true]); + $aFiles = $this->InvokeNonPublicMethod('DBBackup', 'PrepareFilesToBackup', $oBackup, [APPROOT . '/conf/'.$this->GetTestEnvironment().'/config-itop.php', $sTmpDir, true]); SetupUtils::rrmdir($sTmpDir); $aExpectedFiles = [ $sTmpDir . '/config-itop.php', ]; + if (file_exists(APPROOT.'/data/'.$this->GetTestEnvironment().'.delta.xml')) { + $aExpectedFiles[] = $sTmpDir . '/' . 'delta.xml'; + } foreach ($aExtraFiles as $sRelFile => $bExists) { if ($bExists) { $aExpectedFiles[] = $sTmpDir . '/' . $sRelFile; @@ -47,13 +50,17 @@ class DBBackupDataTest extends ItopDataTestCase foreach ($aExtraFiles as $sExtraFile => $bExists) { if ($bExists) { unlink(APPROOT . '/' . $sExtraFile); + $folderPath = dirname(APPROOT . '/' . $sExtraFile); + if (is_dir($folderPath) && count(glob($folderPath . '/*')) === 0) { + rmdir($folderPath); + } } } } sort($aFiles); sort($aExpectedFiles); - $this->assertEquals($aFiles, $aExpectedFiles); + $this->assertEquals($aExpectedFiles, $aFiles); } function prepareFilesToBackupProvider() diff --git a/tests/php-unit-tests/unitary-tests/sources/SessionTracker/SessionHandlerTest.php b/tests/php-unit-tests/unitary-tests/sources/SessionTracker/SessionHandlerTest.php index ac89a84216..b2ea7864de 100644 --- a/tests/php-unit-tests/unitary-tests/sources/SessionTracker/SessionHandlerTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/SessionTracker/SessionHandlerTest.php @@ -161,7 +161,7 @@ class SessionHandlerTest extends ItopDataTestCase $aJson = json_decode($sFirstContent, true); $this->assertNotEquals(false, $aJson, 'Should return a valid json string, found: '.$sFirstContent); $this->assertEquals($sUserId, $aJson['user_id'] ?? '', "Should report the login of the logged in user in [user_id]: $sFirstContent"); - $this->assertEquals(ContextTag::TAG_REST, $aJson['context'] ?? '', "Should report the context tag(s) in [context]: $sFirstContent"); + $this->assertStringContainsString(ContextTag::TAG_REST, $aJson['context'] ?? '', "Should report the context tag(s) in [context]: $sFirstContent"); $this->assertIsInt($aJson['creation_time'] ?? '', "Should report the session start timestamp in [creation_time]: $sFirstContent"); $this->assertEquals('foo_login_mode', $aJson['login_mode'] ?? '', "Should report the current login mode in [login_mode]: $sFirstContent"); diff --git a/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php b/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php index 612125035a..5e798d3f2d 100644 --- a/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php +++ b/tests/php-unit-tests/unitary-tests/webservices/CliResetSessionTest.php @@ -55,7 +55,7 @@ class CliResetSessionTest extends ItopDataTestCase @chmod($sConfigPath, 0770); $oConfig = new Config($this->sConfigTmpBackupFile); $oConfig->WriteToFile($sConfigPath); - @chmod($sConfigPath, 0440); + @chmod($sConfigPath, 0444); unlink($this->sConfigTmpBackupFile); } @@ -72,14 +72,14 @@ class CliResetSessionTest extends ItopDataTestCase MetaModel::GetConfig()->SetAllowedLoginTypes($aAllowedLoginTypes); MetaModel::GetConfig()->WriteToFile(); } - @chmod(MetaModel::GetConfig()->GetLoadedFile(), 0440); + @chmod(MetaModel::GetConfig()->GetLoadedFile(), 0444); } protected function SetLoginModes($aAllowedLoginTypes){ @chmod(MetaModel::GetConfig()->GetLoadedFile(), 0770); MetaModel::GetConfig()->SetAllowedLoginTypes($aAllowedLoginTypes); MetaModel::GetConfig()->WriteToFile(); - @chmod(MetaModel::GetConfig()->GetLoadedFile(), 0440); + @chmod(MetaModel::GetConfig()->GetLoadedFile(), 0444); } public function RestProvider(){