Merge remote-tracking branch 'origin/support/3.2' into develop

# Conflicts:
#	core/attributedef.class.inc.php
#	setup/extensionsmap.class.inc.php
#	tests/php-unit-tests/composer.lock
This commit is contained in:
Benjamin DALSASS
2026-03-17 08:05:10 +01:00
35 changed files with 555 additions and 63 deletions

View File

@@ -79,16 +79,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.12.1",
"version": "1.13.4",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
"reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"shasum": ""
},
"require": {
@@ -127,7 +127,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
},
"funding": [
{
@@ -135,20 +135,20 @@
"type": "tidelift"
}
],
"time": "2024-11-08T17:47:46+00:00"
"time": "2025-08-01T08:46:24+00:00"
},
{
"name": "nikic/php-parser",
"version": "v5.3.1",
"version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
"reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
@@ -167,7 +167,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
"dev-master": "5.x-dev"
}
},
"autoload": {
@@ -191,9 +191,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
},
"time": "2024-10-08T18:51:32+00:00"
"time": "2025-12-06T11:56:16+00:00"
},
{
"name": "phar-io/manifest",
@@ -634,16 +634,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.21",
"version": "9.6.34",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa"
"reference": "b36f02317466907a230d3aa1d34467041271ef4a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
"reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a",
"reference": "b36f02317466907a230d3aa1d34467041271ef4a",
"shasum": ""
},
"require": {
@@ -654,7 +654,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.12.0",
"myclabs/deep-copy": "^1.13.4",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=7.3",
@@ -665,11 +665,11 @@
"phpunit/php-timer": "^5.0.3",
"sebastian/cli-parser": "^1.0.2",
"sebastian/code-unit": "^1.0.8",
"sebastian/comparator": "^4.0.8",
"sebastian/comparator": "^4.0.10",
"sebastian/diff": "^4.0.6",
"sebastian/environment": "^5.1.5",
"sebastian/exporter": "^4.0.6",
"sebastian/global-state": "^5.0.7",
"sebastian/exporter": "^4.0.8",
"sebastian/global-state": "^5.0.8",
"sebastian/object-enumerator": "^4.0.4",
"sebastian/resource-operations": "^3.0.4",
"sebastian/type": "^3.2.1",
@@ -717,7 +717,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.34"
},
"funding": [
{
@@ -728,12 +728,20 @@
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
"type": "tidelift"
}
],
"time": "2024-09-19T10:50:18+00:00"
"time": "2026-01-27T05:45:00+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -904,16 +912,16 @@
},
{
"name": "sebastian/comparator",
"version": "4.0.8",
"version": "4.0.10",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "fa0f136dd2334583309d32b62544682ee972b51a"
"reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
"reference": "fa0f136dd2334583309d32b62544682ee972b51a",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d",
"reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d",
"shasum": ""
},
"require": {
@@ -966,15 +974,27 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.10"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
"type": "tidelift"
}
],
"time": "2022-09-14T12:41:17+00:00"
"time": "2026-01-24T09:22:56+00:00"
},
{
"name": "sebastian/complexity",
@@ -1164,16 +1184,16 @@
},
{
"name": "sebastian/exporter",
"version": "4.0.6",
"version": "4.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
"reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c",
"reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c",
"shasum": ""
},
"require": {
@@ -1229,28 +1249,40 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
"type": "tidelift"
}
],
"time": "2024-03-02T06:33:00+00:00"
"time": "2025-09-24T06:03:27+00:00"
},
{
"name": "sebastian/global-state",
"version": "5.0.7",
"version": "5.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
"reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
"reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
"shasum": ""
},
"require": {
@@ -1293,15 +1325,27 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
"type": "tidelift"
}
],
"time": "2024-03-02T06:35:11+00:00"
"time": "2025-08-10T07:10:35+00:00"
},
{
"name": "sebastian/lines-of-code",
@@ -1474,16 +1518,16 @@
},
{
"name": "sebastian/recursion-context",
"version": "4.0.5",
"version": "4.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
"reference": "539c6691e0623af6dc6f9c20384c120f963465a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
"reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0",
"reference": "539c6691e0623af6dc6f9c20384c120f963465a0",
"shasum": ""
},
"require": {
@@ -1525,15 +1569,27 @@
"homepage": "https://github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
"source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
"type": "tidelift"
}
],
"time": "2023-02-03T06:07:39+00:00"
"time": "2025-08-10T06:57:39+00:00"
},
{
"name": "sebastian/resource-operations",
@@ -1738,16 +1794,16 @@
},
{
"name": "theseer/tokenizer",
"version": "1.2.3",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
"reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
"reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
"shasum": ""
},
"require": {
@@ -1776,7 +1832,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
"source": "https://github.com/theseer/tokenizer/tree/1.3.1"
},
"funding": [
{
@@ -1784,7 +1840,7 @@
"type": "github"
}
],
"time": "2024-03-03T12:36:25+00:00"
"time": "2025-11-17T20:03:58+00:00"
}
],
"aliases": [],
@@ -1794,5 +1850,5 @@
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.9.0"
}

View File

@@ -0,0 +1,177 @@
<?php
declare(strict_types=1);
namespace Combodo\iTop\Test\UnitTest\Application;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use Config;
use Exception;
use MetaModel;
class LoginWebPageTest extends ItopDataTestCase
{
public const USE_TRANSACTION = false;
public const PASSWORD = 'a209320P!ù;ralùqpi,pàcqi"nr';
public function setUp(): void
{
parent::setUp();
$sConfigPath = MetaModel::GetConfig()->GetLoadedFile();
$this->oConfig = new Config($sConfigPath);
$this->BackupConfiguration();
$sFolderPath = APPROOT.'env-production/extension-with-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
throw new Exception("Folder $sFolderPath already exists, please remove it before running the test");
}
mkdir($sFolderPath);
$this->RecurseCopy(__DIR__.'/extension-with-delegated-authentication-endpoints-list', $sFolderPath);
$sFolderPath = APPROOT.'env-production/extension-without-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
throw new Exception("Folder $sFolderPath already exists, please remove it before running the test");
}
mkdir($sFolderPath);
$this->RecurseCopy(__DIR__.'/extension-without-delegated-authentication-endpoints-list', $sFolderPath);
}
public function tearDown(): void
{
parent::tearDown();
$sFolderPath = APPROOT.'env-production/extension-with-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
$this->RecurseRmdir($sFolderPath);
} else {
throw new Exception("Folder $sFolderPath does not exist, it should have been created in setUp");
}
$sFolderPath = APPROOT.'env-production/extension-without-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
$this->RecurseRmdir($sFolderPath);
} else {
throw new Exception("Folder $sFolderPath does not exist, it should have been created in setUp");
}
}
protected function GivenConfigFileAllowedLoginTypes($aAllowedLoginTypes): void
{
@chmod($this->oConfig->GetLoadedFile(), 0770);
$this->oConfig->SetAllowedLoginTypes($aAllowedLoginTypes);
$this->oConfig->WriteToFile($this->oConfig->GetLoadedFile());
@chmod($this->oConfig->GetLoadedFile(), 0444);
}
/**
*
* @throws \Exception
*/
public function testInDelegatedAuthenticationEndpoints()
{
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileInDelegatedAuthenticationEndpointsList.php",
[],
[],
true
);
$this->assertStringNotContainsString('<title>iTop login</title>', $sPageContent, 'File listed in delegated authentication endpoints list (in the module), login should not be requested by exec.');
}
public function testUserCanAccessAnyFile()
{
// generate random login
$sUserLogin = 'user-'.date('YmdHis');
$this->CreateUser($sUserLogin, self::$aURP_Profiles['Service Desk Agent'], self::PASSWORD);
$this->GivenConfigFileAllowedLoginTypes(explode('|', 'form'));
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileNotInDelegatedAuthenticationEndpointsList.php",
[
'auth_user' => $sUserLogin,
'auth_pwd' => self::PASSWORD,
],
[],
true
);
$this->assertStringContainsString('Yo', $sPageContent, 'Logged in user should access any file via exec.php even if the page isn\'t listed in delegated authentication endpoints list');
}
public function testWithoutDelegatedAuthenticationEndpointsListWithForceLoginConf()
{
@chmod($this->oConfig->GetLoadedFile(), 0770);
$this->oConfig->Set('security.force_login_when_no_delegated_authentication_endpoints_list', true, 'AnythingButEmptyOrUnknownValue'); // 3rd param to write file even if show_in_conf_sample is false
$this->oConfig->WriteToFile();
@chmod($this->oConfig->GetLoadedFile(), 0444);
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-without-delegated-authentication-endpoints-list&exec_page=src/Controller/File.php",
);
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'if itop is configured to force login when no there is no delegated authentication endpoints list, then login should be required.');
}
public function testWithoutDelegatedAuthenticationEndpointsListWithDefaultConfiguration()
{
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-without-delegated-authentication-endpoints-list&exec_page=src/Controller/File.php",
[],
[],
true
);
$this->assertStringContainsString('Yo', $sPageContent, 'by default (until N°9343) if no delegated authentication endpoints list is defined, not logged in persons should access pages');
}
public function testNotInDelegatedAuthenticationEndpointsList()
{
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileNotInDelegatedAuthenticationEndpointsList.php",
[],
[],
true
);
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'Since an delegated authentication endpoints list is defined and file isn\'t listed in it, login should be required');
}
/**
* @dataProvider InDelegatedAuthenticationEndpointsWithAdminRequiredProvider
*
* @throws \Exception
*/
public function testInDelegatedAuthenticationEndpointsWithAdminRequired($iProfileId, $bShouldSeeForbiddenAdminPage)
{
// generate random login
$sUserLogin = 'user-'.date('YmdHis');
$this->CreateUser($sUserLogin, $iProfileId, self::PASSWORD);
$this->GivenConfigFileAllowedLoginTypes(explode('|', 'form'));
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileInDelegatedAuthenticationEndpointsListAndAdminRequired.php",
[
'auth_user' => $sUserLogin,
'auth_pwd' => self::PASSWORD,
],
[],
true
);
$bShouldSeeForbiddenAdminPage ?
$this->assertStringContainsString('Access restricted to people having administrator privileges', $sPageContent, 'Should prevent non admin user to access this page') : // in delegated authentication endpoints list (in the module), login should not be required
$this->assertStringContainsString('Yo !', $sPageContent, 'Should execute the file and see its content since user has admin profile');
}
public function InDelegatedAuthenticationEndpointsWithAdminRequiredProvider()
{
return [
'Administrator profile' => [
self::$aURP_Profiles['Administrator'],
'Should see forbidden admin page' => false,
],
'ReadOnly profile' => [
self::$aURP_Profiles['Service Desk Agent'],
'Should see forbidden admin page' => true,
],
];
}
}

View File

@@ -0,0 +1,51 @@
<?php
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'extension-with-delegated-authentication-endpoints-list/0.0.1',
[
// Identification
//
'label' => 'Templates foundation',
'category' => 'business',
// Setup
//
'dependencies' => [],
'mandatory' => true,
'visible' => false,
'installer' => 'TemplatesBaseInstaller',
// Security
'delegated_authentication_endpoints' => [
'src/Controller/FileInDelegatedAuthenticationEndpointsList.php',
'src/Controller/FileInDelegatedAuthenticationEndpointsListAndAdminRequired.php',
],
// Components
//
'datamodel' => [
'model.templates-base.php',
],
'webservice' => [],
'data.struct' => [// add your 'structure' definition XML files here,
],
'data.sample' => [// add your sample data XML files here,
],
// Documentation
//
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
'doc.more_information' => '', // hyperlink to more information, if any
// Default settings
//
'settings' => [
// Select where, in the main UI, the extra data should be displayed:
// tab (dedicated tab)
// properties (right after the properties, but before the log if any)
// none (extra data accessed only by programs)
'view_extra_data' => 'relations',
],
]
);

View File

@@ -0,0 +1,10 @@
<?php
if (UserRights::IsLoggedIn()) {
throw new Exception("User should not be authenticated at this point");
}
require_once(APPROOT.'/application/startup.inc.php');
LoginWebPage::DoLogin(true);
echo 'Yo !';

View File

@@ -0,0 +1,45 @@
<?php
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'extension-without-delegated-authentication-endpoints-list/0.0.1',
[
// Identification
//
'label' => 'Templates foundation',
'category' => 'business',
// Setup
//
'dependencies' => [],
'mandatory' => true,
'visible' => false,
'installer' => 'TemplatesBaseInstaller',
// Components
//
'datamodel' => [
'model.templates-base.php',
],
'webservice' => [],
'data.struct' => [// add your 'structure' definition XML files here,
],
'data.sample' => [// add your sample data XML files here,
],
// Documentation
//
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
'doc.more_information' => '', // hyperlink to more information, if any
// Default settings
//
'settings' => [
// Select where, in the main UI, the extra data should be displayed:
// tab (dedicated tab)
// properties (right after the properties, but before the log if any)
// none (extra data accessed only by programs)
'view_extra_data' => 'relations',
],
]
);

View File

@@ -9,6 +9,7 @@ namespace Combodo\iTop\Test\UnitTest\Core;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use InlineImage;
use ormDocument;
class InlineImageTest extends ItopDataTestCase
{
@@ -98,4 +99,36 @@ HTML;
$this->assertStringContainsString(\utils::EscapeHtml(\utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.'123&s=abc'), $sResult);
$this->assertStringContainsString(\utils::EscapeHtml(\utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.'456&s=def'), $sResult);
}
/**
* @covers InlineImage::ReplaceInlineImagesWithBase64Representation
*/
public function testReplaceInlineImagesWithBase64Representation()
{
// create an inline image in the database
$oInlineImage = $this->createObject(InlineImage::class, [
'expire' => (new \DateTime('+1 day'))->format('Y-m-d H:i:s'),
'item_class' => 'UserRequest',
'item_id' => 999,
'item_org_id' => 1,
'contents' => new ormDocument('0x89504E470D0A1A0A0000000D494844520000000E0000000E08060000001F482DD1000000017352474200AECE1CE90000000467414D410000B18F0BFC6105000000097048597300000EC300000EC301C76FA8640000001E49444154384F63782BA3F29F1CCC802E402C1ED588078F6AC483E9AF11008B8BA9C08A7A3F290000000049454E44AE426082', 'image/png', 'square_red.png'),
'secret' => 'a94bff3ea6a872bdbc359a1704cdddb3',
]);
$sInlineImageId = $oInlineImage->GetKey();
$sInlineImageSecret = $oInlineImage->Get('secret');
// HTML with inline image
$sHtml = <<<HTML
<img src="http://host/iTop/pages/ajax.document.php?operation=download_inlineimage&amp;id=$sInlineImageId&amp;s=$sInlineImageSecret" data-img-id="$sInlineImageId" data-img-secret="$sInlineImageSecret" />
HTML;
// expected HTML with base64 representation of the image
$sExpected = <<<HTML
<img src="data:image/png;base64,MHg4OTUwNEU0NzBEMEExQTBBMDAwMDAwMEQ0OTQ4NDQ1MjAwMDAwMDBFMDAwMDAwMEUwODA2MDAwMDAwMUY0ODJERDEwMDAwMDAwMTczNTI0NzQyMDBBRUNFMUNFOTAwMDAwMDA0Njc0MTRENDEwMDAwQjE4RjBCRkM2MTA1MDAwMDAwMDk3MDQ4NTk3MzAwMDAwRUMzMDAwMDBFQzMwMUM3NkZBODY0MDAwMDAwMUU0OTQ0NDE1NDM4NEY2Mzc4MkJBM0YyOUYxQ0NDODAyRTQwMkMxRUQ1ODgwNzhGNkFDNDgzRTlBRjExMDA4QjhCQTlDMDhBN0EzRjI5MDAwMDAwMDA0OTQ1NEU0NEFFNDI2MDgy" />
HTML;
// test the method
$sResult = InlineImage::ReplaceInlineImagesWithBase64Representation($sHtml);
$this->assertEquals($sExpected, $sResult);
}
}