Compare commits

...

4 Commits

Author SHA1 Message Date
jf-cbd
57f1409d44 N°10246 - Fix LDAP server URI configuration (#1102)
Co-authored-by: JavierMartinezIgarle <272137723+JavierMartinezIgarle@users.noreply.github.com>
2026-10-28 15:20:58 +01:00
Amine
25598e31dd N°10179 - MTP/upgrade not working (#1101) 2026-10-28 14:45:13 +01:00
odain-cbd
f2ab9f2902 N°10151 - Missing extension.xml in extension disturb setup (#1067)
* N°10151 - Missing extension.xml in extension disturb setup

* N°10151 - Missing extension.xml in extension disturb setup

* N°10151 - add weird usecase with multi xml files in same extension

* N°10151 - fix module not installed after MTP

* N°10151 - fix broken extension with further extension.xml

* N°10151 - code style
2026-10-19 17:09:20 +02:00
Anne-Catherine
7e671eccc1 N°10196 - Fix TriggerOnAttachmentDownload (#1078) 2026-10-14 11:49:47 +02:00
7 changed files with 163 additions and 39 deletions

View File

@@ -85,12 +85,13 @@ if (function_exists('ldap_connect')) {
$aServers = $oConfiguration->GetModuleSetting('authent-ldap', 'servers', []);
foreach ($aServers as &$aServer) {
if (!array_key_exists($aServer, 'uri')) {
$sLDAPHost = $aServerParams['host'] ?? 'localhost';
$iLDAPPort = $aServerParams['port'] ?? 389;
if (!array_key_exists('uri', $aServer)) {
$sLDAPHost = $aServer['host'] ?? 'localhost';
$iLDAPPort = $aServer['port'] ?? 389;
$aServer['uri'] = preg_match('#^ldaps?://#i', $sLDAPHost) ? $sLDAPHost : 'ldap://'.$sLDAPHost.':'.$iLDAPPort;
}
}
unset($aServer);
$oConfiguration->SetModuleSetting('authent-ldap', 'servers', $aServers);
}
}

View File

@@ -159,7 +159,7 @@ class EventListener implements iEventServiceSetup
while ($oTrigger = $oTriggerSet->Fetch()) {
try {
$aContextArgs = $aTriggerContextArgs;
if ($oTrigger->Get('file_in_email')) {
if (MetaModel::IsValidAttCode(get_class($oTrigger), 'file_in_email') && $oTrigger->Get('file_in_email')) {
$aContextArgs['attachments'] = [$oDocument];
}
$oTrigger->DoActivate($aContextArgs);

View File

@@ -62,20 +62,22 @@ class iTopExtensionsMap
*
* @throws \Exception
*/
private function __construct(string $sFromEnvironment = ITOP_DEFAULT_ENV, array $aExtraDirs = [], ?string $sAppRootForTests = null)
private function __construct(string $sFromEnvironment = ITOP_DEFAULT_ENV, array $aExtraDirs = [], ?string $sAppRootForTests = null, bool $bNoScan = false)
{
$this->aExtensions = [];
$this->aExtensionsByCode = [];
$this->aScannedDirs = [];
$sAppRoot = $sAppRootForTests ?? APPROOT;
$this->ScanDisk($sFromEnvironment, $sAppRoot);
if (! $bNoScan) {
$sAppRoot = $sAppRootForTests ?? APPROOT;
$this->ScanDisk($sFromEnvironment, $sAppRoot);
foreach ($aExtraDirs as $sDir) {
$this->ReadDir($sDir, iTopExtension::SOURCE_REMOTE, bIsRootDir: true);
foreach ($aExtraDirs as $sDir) {
$this->ReadDir($sDir, iTopExtension::SOURCE_REMOTE, bIsRootDir: true);
}
$this->CheckDependencies($sAppRoot);
}
$this->CheckDependencies($sAppRoot);
}
/**
@@ -261,7 +263,7 @@ class iTopExtensionsMap
foreach ($aExtensionCodes as $sCode => $sLabel) {
$sRealCode = is_int($sCode) ? $sLabel : $sCode;
/** @var \iTopExtension $oExtension */
/** @var ?\iTopExtension $oExtension */
$oExtension = $this->GetFromExtensionCode($sRealCode);
if (!is_null($oExtension)) {
$aRemovedExtension [] = $oExtension;
@@ -298,7 +300,7 @@ class iTopExtensionsMap
$aSubDirectories = [];
// First check if there is an extension.xml file in this directory
if (is_readable($sSearchDir.'/extension.xml')) {
if ($sParentExtensionId === null && is_readable($sSearchDir.'/extension.xml')) {
$oXml = new XMLParameters($sSearchDir.'/extension.xml');
$oExtension = new iTopExtension();
$oExtension->sCode = $oXml->Get('extension_code');
@@ -357,7 +359,7 @@ class iTopExtensionsMap
$oExtension->sVersion = $sModuleVersion;
$oExtension->sSource = $sSource;
$oExtension->bMandatory = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]['mandatory'];
$oExtension->sMoreInfoUrl = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]['doc.more_information'];
$oExtension->sMoreInfoUrl = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]['doc.more_information'] ?? '';
$oExtension->aModules = [$sModuleName];
$oExtension->aModuleVersion[$sModuleName] = $sModuleVersion;
$oExtension->aModuleInfo[$sModuleName] = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG];
@@ -403,27 +405,15 @@ class iTopExtensionsMap
return [];
}
$aExtensions = [];
$hDir = opendir($sSearchDir);
if ($hDir !== false) {
$oiTopExtensionsMap = new iTopExtensionsMap(bNoScan: true);
$oiTopExtensionsMap->ReadDir($sSearchDir, iTopExtension::SOURCE_REMOTE, bIsRootDir: true);
// Then scan the other files and subdirectories
while (($sDir = readdir($hDir)) !== false) {
if (($sDir === '.') || ($sDir === '..') || !is_dir($sSearchDir.$sDir)) {
continue;
}
// First check if there is an extension.xml file in this directory
if (is_readable($sSearchDir.$sDir.'/extension.xml')) {
$oXml = new XMLParameters($sSearchDir.$sDir.'/extension.xml');
$aExtensions[$oXml->Get('extension_code')] = $oXml->Get('label');
}
}
closedir($hDir);
$aRes = [];
foreach ($oiTopExtensionsMap->aExtensionsByCode as $sCode => $oExtension) {
/** @var iTopExtension $oExtension */
$aRes[$sCode] = $oExtension->sLabel;
}
return $aExtensions;
return $aRes;
}
/**

View File

@@ -57,7 +57,12 @@ class ModelReflectionSerializer
$sPHPExec = trim(utils::GetConfig()->Get('php_path'));
$aOutput = null;
$iRes = 0;
$sCommandLine = sprintf("$sPHPExec %s/get_model_reflection.php --env=%s", __DIR__, escapeshellarg($sEnv));
$sCommandLine = sprintf(
'%s %s --env=%s',
$sPHPExec,
escapeshellarg(__DIR__.'/get_model_reflection.php'),
escapeshellarg($sEnv)
);
exec($sCommandLine, $aOutput, $iRes);
if ($iRes != 0) {
$sError = $aOutput[0] ?? 'Invalid output when serializing model';

View File

@@ -11,8 +11,8 @@ class WizStepLandingBeforeAudit extends WizStepModulesChoice
public function __construct(WizardController $oWizard, $sCurrentState)
{
$this->oRuntimeEnv = new RunTimeEnvironment($oWizard->GetParameter('target_env', ITOP_DEFAULT_ENV));
$sBuildConfigFile = APPCONF.$this->oRuntimeEnv->GetBuildEnv().'/'.ITOP_CONFIG_FILE;
$this->oRuntimeEnv = new RunTimeEnvironment($oWizard->GetParameter('target_env', ITOP_DEFAULT_ENV), false);
$sBuildConfigFile = APPCONF.$this->oRuntimeEnv->GetFinalEnv().'/'.ITOP_CONFIG_FILE;
$this->oConfig = new Config($sBuildConfigFile);
$oWizard->SetParameter('previous_version_dir', APPROOT);
@@ -36,6 +36,8 @@ class WizStepLandingBeforeAudit extends WizStepModulesChoice
// should be done at the end
parent::__construct($oWizard, $sCurrentState, false);
$this->oExtensionsMap = iTopExtensionsMap::GetExtensionsMap($this->oRuntimeEnv->GetBuildEnv());
}
/**

View File

@@ -10,6 +10,7 @@ parameters:
bootstrapFiles:
- ../../../approot.inc.php
- ../../../bootstrap.inc.php
- ../../../tests/php-unit-tests/vendor/autoload.php
scanFiles:
# Files necessary as they contain some declarations (constants, classes, functions, ...)
@@ -36,6 +37,5 @@ parameters:
- ../../../env-php-unit-tests (?) # Irrelevant as it will either already be in `env-production` or might be desynchronized from `env-production`
- ../../../env-toolkit (?) # Irrelevent as it will either already be in `env-production` or might be desynchronized from `env-production` (for local run only, not useful in the CI)
#- ../../../tests (?) # Exclude tests for now
- ../../../toolkit (?) # Exclude toolkit for now
- ../../../setup/compat # Exclude fake DOMDocument & DOMElement declarations
- ../../../tests (?) # Exclude tests for now
- ../../../toolkit (?) # Exlclude toolkit for now

View File

@@ -420,4 +420,130 @@ XML;
return $aRes;
}
public function testGetExtensionsFromDir_MonoModuleExtensionWithXmlDefinition()
{
$oiTopExtensionsMap = iTopExtensionsMap::GetExtensionsMap();
$sTestDir = $this->PrepareTestDir();
$this->CreateExtensionFolder($sTestDir, "ext1", "ext_code1", "1.5.9");
$this->CreateModule($sTestDir, "module1", "module_code1", "9.5.1");
self::assertEquals(['ext_code1' => 'ext1'], $oiTopExtensionsMap->GetExtensionsFromDir($sTestDir));
}
public function testGetExtensionsFromDir_MultiModuleExtension()
{
$oiTopExtensionsMap = iTopExtensionsMap::GetExtensionsMap();
$sTestDir = $this->PrepareTestDir();
$this->CreateExtensionFolder($sTestDir, "ext1", "ext_code1", "1.5.9");
foreach ([1, 2, 3] as $i) {
$this->CreateModule($sTestDir, "module{$i}", "module_code{$i}", "9.5.{$i}");
}
self::assertEquals(['ext_code1' => 'ext1'], $oiTopExtensionsMap->GetExtensionsFromDir($sTestDir));
}
public function testGetExtensionsFromDir_MultiModuleExtensionWithOneXMLDefPerModule()
{
$oiTopExtensionsMap = iTopExtensionsMap::GetExtensionsMap();
$sTestDir = $this->PrepareTestDir();
$this->CreateExtensionFolder($sTestDir, "ext1", "ext_code1", "1.5.9");
foreach ([1, 2, 3] as $i) {
if (! is_dir("$sTestDir/module_code{$i}")) {
mkdir("$sTestDir/module_code{$i}");
}
$this->CreateExtensionFolder("$sTestDir/module_code{$i}", "ext{$i}", "ext_code{$i}", "9.5.{$i}");
$this->CreateModule($sTestDir, "module{$i}", "module_code{$i}", "9.5.{$i}");
}
self::assertEquals(['ext_code1' => 'ext1'], $oiTopExtensionsMap->GetExtensionsFromDir($sTestDir));
}
public function testGetExtensionsFromDir_FurtherMonoModuleExtensionsWithoutXmlDefinition()
{
$oiTopExtensionsMap = iTopExtensionsMap::GetExtensionsMap();
$sTestDir = $this->PrepareTestDir();
foreach ([1, 2, 3] as $i) {
$this->CreateModule($sTestDir, "module{$i}", "module_code{$i}", "9.5.{$i}");
}
$expected = [
'module_code1' => 'module1',
'module_code2' => 'module2',
'module_code3' => 'module3',
];
self::assertEquals($expected, $oiTopExtensionsMap->GetExtensionsFromDir($sTestDir));
}
public function testGetExtensionsFromDir_MonoModuleExtensionWithoutXmlDefinition()
{
$oiTopExtensionsMap = iTopExtensionsMap::GetExtensionsMap();
$sTestDir = $this->PrepareTestDir();
$this->CreateModule($sTestDir, "module1", "module_code1", "9.5.1");
self::assertEquals(['module_code1' => 'module1'], $oiTopExtensionsMap->GetExtensionsFromDir($sTestDir));
}
private function PrepareTestDir(): string
{
$sTestDir = tempnam(sys_get_temp_dir(), "ext_map");
unlink($sTestDir);
mkdir($sTestDir, 0777, true);
$this->aFileToClean[] = $sTestDir;
return $sTestDir;
}
private function CreateExtensionFolder(string $sDir, string $sExtensionLabel, string $sExtensionCode, string $sExtensionVersion)
{
$sXmlDef = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<extension format="1.0">
<extension_code>$sExtensionCode</extension_code>
<label><![CDATA[$sExtensionLabel]]></label>
<description><![CDATA[BLABLA]]></description>
<version>$sExtensionVersion</version>
<modules type="array">
<module>
<id>aaa</id>
<version>tags/6.6.6</version>
</module>
</modules>
<release_date>2023-07-19</release_date>
<itop_version_min>3.2.0</itop_version_min>
<status></status>
<mandatory>false</mandatory>
<more_info_url></more_info_url>
</extension>
XML;
file_put_contents($sDir.'/extension.xml', $sXmlDef);
}
private function CreateModule(string $sDir, string $sModuleLabel, string $sModuleCode, string $sVersion)
{
$sModuleDir = $sDir."/$sModuleCode";
if (! is_dir($sModuleDir)) {
mkdir($sModuleDir, 0777, true);
}
$sModuleContent = <<<PHP
<?php
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'$sModuleCode/$sVersion',
[
'label' => '$sModuleLabel',
'category' => 'authentication',
'dependencies' => [],
'mandatory' => true,
'visible' => true,
'datamodel' => [],
]
);
PHP;
file_put_contents($sModuleDir."/module.{$sModuleCode}.php", $sModuleContent);
}
}