mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-19 08:38:45 +02:00
Compare commits
11 Commits
feature/88
...
feature/77
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e27d1f6ede | ||
|
|
f730eb5823 | ||
|
|
9b15bbab75 | ||
|
|
debfa83c64 | ||
|
|
8b19069b3f | ||
|
|
c74df181bc | ||
|
|
8bd5473fde | ||
|
|
a332e06896 | ||
|
|
77e9136c27 | ||
|
|
909cf9d759 | ||
|
|
77b420b7d2 |
@@ -2418,7 +2418,6 @@ class Config
|
||||
public function SetAllowedLoginTypes($aAllowedLoginTypes)
|
||||
{
|
||||
$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
|
||||
$this->Set('allowed_login_types', implode('|', $aAllowedLoginTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -462,19 +462,6 @@ abstract class MetaModel
|
||||
return call_user_func([$sClass, 'GetClassDescription'], $sClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final public static function GetCreatedIn($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
return self::$m_aClassParams[$sClass]["created_in"] ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
@@ -3158,7 +3145,6 @@ abstract class MetaModel
|
||||
$aMandatParams = [
|
||||
"category" => "group classes by modules defining their visibility in the UI",
|
||||
"key_type" => "autoincrement | string",
|
||||
//"created_in" => "module_name where class is defined",
|
||||
"name_attcode" => "define which attribute is the class name, may be an array of attributes (format specified in the dictionary as 'Class:myclass/Name' => '%1\$s %2\$s...'",
|
||||
"state_attcode" => "define which attribute is representing the state (object lifecycle)",
|
||||
"reconc_keys" => "define the attributes that will 'almost uniquely' identify an object in batch processes",
|
||||
|
||||
@@ -72,6 +72,15 @@
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-flow-map</extension_code>
|
||||
<title>Data flow</title>
|
||||
<description>Map data flows between applications</description>
|
||||
<modules type="array">
|
||||
<module>itop-flow-map</module>
|
||||
</modules>
|
||||
<default>false</default>
|
||||
</choice>
|
||||
</options>
|
||||
</step>
|
||||
<step>
|
||||
|
||||
@@ -323,38 +323,18 @@
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="stock">
|
||||
<code>stock</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-neutral-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-neutral-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>40</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
@@ -6917,29 +6897,14 @@
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
|
||||
@@ -135,7 +135,7 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment
|
||||
$aAvailableModules[$oModule->GetName()] = $oModule;
|
||||
}
|
||||
// TODO check the auto-selected modules here
|
||||
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
|
||||
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
if ($oExtension->bMarkedAsChosen) {
|
||||
foreach ($oExtension->aModules as $sModuleName) {
|
||||
if (!isset($aRet[$sModuleName]) && isset($aAvailableModules[$sModuleName])) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<DataFlowType alias="DataFlowType" id="1">
|
||||
<name>http</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="2">
|
||||
<name>https</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="3">
|
||||
<name>ftp</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="4">
|
||||
<name>sftp</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="5">
|
||||
<name>AS2</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="6">
|
||||
<name>X.400</name>
|
||||
</DataFlowType>
|
||||
</Set>
|
||||
747
datamodels/2.x/itop-flow-map/datamodel.itop-flow-map.xml
Normal file
747
datamodels/2.x/itop-flow-map/datamodel.itop-flow-map.xml
Normal file
@@ -0,0 +1,747 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
||||
<classes>
|
||||
<class id="DataFlow" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>dataflow</db_table>
|
||||
<style>
|
||||
<icon>images/icons8-sorting-arrows-horizontal.svg</icon>
|
||||
</style>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
<attribute id="destination_id"/>
|
||||
<attribute id="org_id"/>
|
||||
<attribute id="source_id"/>
|
||||
<attribute id="flowtype_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition>status='inactive'</condition>
|
||||
</obsolescence>
|
||||
<fields_semantic>
|
||||
<state_attribute>status</state_attribute>
|
||||
</fields_semantic>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="org_id" xsi:type="AttributeExternalKey">
|
||||
<sql>org_id</sql>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>Organization</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="source_id" xsi:type="AttributeExternalKey">
|
||||
<sql>source_id</sql>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>FunctionalCI</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="source_impact" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="yes">
|
||||
<code>yes</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="no">
|
||||
<code>no</code>
|
||||
<rank>20</rank>
|
||||
</value>
|
||||
</values>
|
||||
<sql>source_impact</sql>
|
||||
<default_value>yes</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>radio_horizontal</display_style>
|
||||
</field>
|
||||
<field id="destination_id" xsi:type="AttributeExternalKey">
|
||||
<sql>destination_id</sql>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>FunctionalCI</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="destination_impact" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="yes">
|
||||
<code>yes</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="no">
|
||||
<code>no</code>
|
||||
<rank>20</rank>
|
||||
</value>
|
||||
</values>
|
||||
<sql>destination_impact</sql>
|
||||
<default_value>no</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>radio_horizontal</display_style>
|
||||
</field>
|
||||
<field id="dataflowtype_id" xsi:type="AttributeExternalKey">
|
||||
<sql>dataflowtype_id</sql>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<target_class>DataFlowType</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="description" xsi:type="AttributeHTML">
|
||||
<sql>description</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sql>status</sql>
|
||||
<values>
|
||||
<value id="active">
|
||||
<code>active</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="inactive">
|
||||
<code>inactive</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sort_type>label</sort_type>
|
||||
<default_value>active</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="business_criticity" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="high">
|
||||
<code>high</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="medium">
|
||||
<code>medium</code>
|
||||
<rank>20</rank>
|
||||
</value>
|
||||
<value id="low">
|
||||
<code>low</code>
|
||||
<rank>30</rank>
|
||||
</value>
|
||||
</values>
|
||||
<sql>business_criticity</sql>
|
||||
<default_value>low</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
<field id="execution_frequency" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="realtime">
|
||||
<code>realtime</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="ondemand">
|
||||
<code>ondemand</code>
|
||||
<rank>20</rank>
|
||||
</value>
|
||||
<value id="hourly">
|
||||
<code>hourly</code>
|
||||
<rank>30</rank>
|
||||
</value>
|
||||
<value id="daily">
|
||||
<code>daily</code>
|
||||
<rank>40</rank>
|
||||
</value>
|
||||
<value id="weekly">
|
||||
<code>weekly</code>
|
||||
<rank>50</rank>
|
||||
</value>
|
||||
<value id="monthly">
|
||||
<code>monthly</code>
|
||||
<rank>60</rank>
|
||||
</value>
|
||||
<value id="yearly">
|
||||
<code>yearly</code>
|
||||
<rank>70</rank>
|
||||
</value>
|
||||
</values>
|
||||
<sql>execution_frequency</sql>
|
||||
<default_value>daily</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
<field id="contacts_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkContactToDataFlow</linked_class>
|
||||
<ext_key_to_me>dataflow_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>contact_id</ext_key_to_remote>
|
||||
<duplicates/>
|
||||
</field>
|
||||
<field id="documents_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkDocumentToDataFlow</linked_class>
|
||||
<ext_key_to_me>dataflow_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>document_id</ext_key_to_remote>
|
||||
<duplicates/>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<list>
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="source_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="destination_id">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="dataflowtype_id">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
<item id="business_criticity">
|
||||
<rank>50</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
<search>
|
||||
<items>
|
||||
<item id="org_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="source_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="destination_id">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="status">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<details>
|
||||
<items>
|
||||
<item id="col:col1">
|
||||
<items>
|
||||
<item id="fieldset:DataFlow:baseinfo">
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="org_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="status">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="business_criticity">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="fieldset:DataFlow:moreinfo">
|
||||
<items>
|
||||
<item id="source_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="source_impact">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="destination_id">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="destination_impact">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
<item id="dataflowtype_id">
|
||||
<rank>50</rank>
|
||||
</item>
|
||||
<item id="execution_frequency">
|
||||
<rank>60</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="col:col2">
|
||||
<items>
|
||||
<item id="fieldset:DataFlow:otherinfo">
|
||||
<items>
|
||||
<item id="description">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="contacts_list">
|
||||
<rank>70</rank>
|
||||
</item>
|
||||
<item id="documents_list">
|
||||
<rank>80</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<default_search>
|
||||
<items>
|
||||
<item id="org_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="source_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="destination_id">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="dataflowtype_id">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
<item id="status">
|
||||
<rank>50</rank>
|
||||
</item>
|
||||
</items>
|
||||
</default_search>
|
||||
<summary>
|
||||
<items>
|
||||
<item id="org_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="description">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</summary>
|
||||
</presentation>
|
||||
<relations>
|
||||
<relation id="impacts">
|
||||
<neighbours>
|
||||
<neighbour id="functionalci ">
|
||||
<query_down><![CDATA[SELECT FunctionalCI WHERE :this->destination_impact = 'yes' AND id = :this->destination_id]]></query_down>
|
||||
<query_up><![CDATA[SELECT DataFlow AS f JOIN FunctionalCI AS ci ON f.destination_id = ci.id WHERE f.destination_impact = 'yes' AND ci.id=:this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
</relations>
|
||||
</class>
|
||||
<class id="lnkDocumentToDataFlow" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>lnkdocumenttodataflow</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="document_id_friendlyname"/>
|
||||
<attribute id="dataflow_id_friendlyname"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon/>
|
||||
</style>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="dataflow_id"/>
|
||||
<attribute id="document_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="no_duplicate">
|
||||
<attributes>
|
||||
<attribute id="document_id"/>
|
||||
<attribute id="dataflow_id"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="dataflow_id" xsi:type="AttributeExternalKey">
|
||||
<sql>dataflow_id</sql>
|
||||
<target_class>DataFlow</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
<field id="document_id" xsi:type="AttributeExternalKey">
|
||||
<sql>document_id</sql>
|
||||
<target_class>Document</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="document_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="dataflow_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="document_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="document_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="lnkContactToDataFlow" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>lnkcontacttodataflow</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="contact_id_friendlyname"/>
|
||||
<attribute id="dataflow_id_friendlyname"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon/>
|
||||
</style>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="dataflow_id"/>
|
||||
<attribute id="contact_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="no_duplicate">
|
||||
<attributes>
|
||||
<attribute id="contact_id"/>
|
||||
<attribute id="dataflow_id"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="dataflow_id" xsi:type="AttributeExternalKey">
|
||||
<sql>dataflow_id</sql>
|
||||
<target_class>DataFlow</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
<field id="contact_id" xsi:type="AttributeExternalKey">
|
||||
<sql>contact_id</sql>
|
||||
<target_class>Contact</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="contact_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="dataflow_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="DataFlowType" _delta="define">
|
||||
<parent>Typology</parent>
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>dataflowtype</db_table>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields/>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<list>
|
||||
<items>
|
||||
<item id="finalclass">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
<search>
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<details>
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="FunctionalCI" _delta="must_exist">
|
||||
<fields>
|
||||
<field id="dataflows" xsi:type="AttributeDashboard" _delta="define">
|
||||
<is_user_editable>true</is_user_editable>
|
||||
<definition>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<title>FunctionalCI:DataFlow:Title</title>
|
||||
<auto_reload>
|
||||
<enabled>false</enabled>
|
||||
<interval>300</interval>
|
||||
</auto_reload>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="DataFlow_Inbound" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>FunctionalCI:DataFlow:Inbound</title>
|
||||
<query>SELECT DataFlow WHERE destination_id=:this->id</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="DataFlow_Outbound" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>FunctionalCI:DataFlow:Outbound</title>
|
||||
<query>SELECT DataFlow WHERE source_id=:this->id</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
</field>
|
||||
</fields>
|
||||
<relations>
|
||||
<relation id="impacts">
|
||||
<neighbours>
|
||||
<neighbour id="flow" _delta="define">
|
||||
<query_down><![CDATA[SELECT DataFlow WHERE source_id = :this->id AND source_impact = 'yes']]></query_down>
|
||||
<query_up><![CDATA[SELECT FunctionalCI AS ci JOIN DataFlow AS f ON f.source_id = ci.id WHERE f.source_impact = 'yes' AND f.id = :this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
</relations>
|
||||
</class>
|
||||
<class id="ApplicationSolution" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="DatabaseSchema" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="DBServer" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="Middleware" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="MiddlewareInstance" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="WebApplication" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="WebServer" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="OtherSoftware" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
</classes>
|
||||
<menus>
|
||||
<menu id="ConfigManagementOverview" xsi:type="DashboardMenuNode" _delta="must_exist">
|
||||
<definition>
|
||||
<cells>
|
||||
<cell id="3" delta="must_exist">
|
||||
<dashlets>
|
||||
<dashlet id="DataFlow_20" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>20</rank>
|
||||
<class>DataFlow</class>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
</menus>
|
||||
<user_rights>
|
||||
<groups>
|
||||
<group id="Configuration">
|
||||
<classes>
|
||||
<class id="DataFlow" _delta="define"/>
|
||||
<class id="DataFlowType" _delta="define"/>
|
||||
</classes>
|
||||
</group>
|
||||
</groups>
|
||||
<profiles>
|
||||
</profiles>
|
||||
</user_rights>
|
||||
</itop_design>
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Module combodo-flow-map
|
||||
*
|
||||
* @copyright Copyright (C) 2013 XXXXX
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
|
||||
'Class:FunctionalCI/Attribute:dataflows' => 'Data flows',
|
||||
'Class:FunctionalCI/Attribute:dataflows+' => 'Data flows for which this object is the source or the destination',
|
||||
'FunctionalCI:DataFlow:Title' => 'Data flows',
|
||||
'FunctionalCI:DataFlow:Inbound' => 'Inbound flows',
|
||||
'FunctionalCI:DataFlow:Outbound' => 'Outbound flows',
|
||||
|
||||
'DataFlow:baseinfo' => 'General information',
|
||||
'DataFlow:otherinfo' => 'Other information',
|
||||
'DataFlow:moreinfo' => 'Flow specifics',
|
||||
|
||||
'Class:DataFlow' => 'Flow',
|
||||
'Class:DataFlow+' => 'For application flow for example',
|
||||
'Class:DataFlow/Name' => '%1$s',
|
||||
'Class:DataFlow/Attribute:name' => 'Name',
|
||||
'Class:DataFlow/Attribute:name_id+' => 'Data that are transferred',
|
||||
'Class:DataFlow/Attribute:source_id' => 'Source',
|
||||
'Class:DataFlow/Attribute:source_id+' => 'Source Ci of the flow',
|
||||
'Class:DataFlow/Attribute:source_impact' => 'Source impacts?',
|
||||
'Class:DataFlow/Attribute:source_impact+' => 'Does the source impact the flow?',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:yes' => 'yes',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:yes+' => 'If the source falls down, the flow is impacted',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:no' => 'no',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:no+' => 'If the source falls down, the flow is not impacted',
|
||||
'Class:DataFlow/Attribute:destination_id' => 'Destination',
|
||||
'Class:DataFlow/Attribute:destination_id+' => 'Destination Ci for the flow',
|
||||
'Class:DataFlow/Attribute:destination_impact' => 'Destination impacted',
|
||||
'Class:DataFlow/Attribute:destination_impact+' => 'Is the destination impacted by the flow ?',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:yes' => 'yes',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:yes+' => 'If the flow stops, the destination is impacted',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no' => 'no',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no+' => 'If the flow stops, the destination is not impacted',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id' => 'Flow type',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id+' => 'Typology of Flow.',
|
||||
'Class:DataFlow/Attribute:description' => 'Description',
|
||||
'Class:DataFlow/Attribute:description+' => '',
|
||||
'Class:DataFlow/Attribute:status' => 'Status',
|
||||
'Class:DataFlow/Attribute:status+' => '',
|
||||
'Class:DataFlow/Attribute:status/Value:active' => 'active',
|
||||
'Class:DataFlow/Attribute:status/Value:inactive' => 'inactive',
|
||||
'Class:DataFlow/Attribute:org_id' => 'Organization',
|
||||
'Class:DataFlow/Attribute:org_id+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity' => 'Business criticality',
|
||||
'Class:DataFlow/Attribute:business_criticity+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high' => 'high',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low' => 'low',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium' => 'medium',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency' => 'Execution frequency',
|
||||
'Class:DataFlow/Attribute:execution_frequency+' => 'How often the data flow is executed',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime' => 'real-time',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:ondemand' => 'on demand',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:ondemand+' => 'on the fly, not scheduled',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:hourly' => 'hourly',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:hourly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:daily' => 'daily',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:daily+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:weekly' => 'weekly',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:weekly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly' => 'monthly',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly' => 'yearly',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly+' => '',
|
||||
'Class:DataFlow/Attribute:documents_list' => 'Documents',
|
||||
'Class:DataFlow/Attribute:documents_list+' => 'Eg: technical specifications, runbooks, etc.',
|
||||
'Class:DataFlow/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DataFlow/Attribute:contacts_list+' => 'Eg: flow owner, technical support, etc.',
|
||||
|
||||
/*
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname' => 'source_id_friendlyname',
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname+' => 'Full name',
|
||||
'Class:DataFlow/Attribute:source_id_finalclass_recall' => 'source_id->CI sub-class',
|
||||
'Class:DataFlow/Attribute:source_id_finalclass_recall+' => 'Name of the final class',
|
||||
'Class:DataFlow/Attribute:source_id_obsolescence_flag' => 'source_id->Obsolete',
|
||||
'Class:DataFlow/Attribute:source_id_obsolescence_flag+' => 'Computed dynamically on other attributes',
|
||||
'Class:DataFlow/Attribute:destination_id_friendlyname' => 'destination_id_friendlyname',
|
||||
'Class:DataFlow/Attribute:destination_id_friendlyname+' => 'Full name',
|
||||
'Class:DataFlow/Attribute:destination_id_finalclass_recall' => 'destination_id->CI sub-class',
|
||||
'Class:DataFlow/Attribute:destination_id_finalclass_recall+' => 'Name of the final class',
|
||||
'Class:DataFlow/Attribute:destination_id_obsolescence_flag' => 'destination_id->Obsolete',
|
||||
'Class:DataFlow/Attribute:destination_id_obsolescence_flag+' => 'Computed dynamically on other attributes',
|
||||
*/
|
||||
]);
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Module combodo-flow-map
|
||||
*
|
||||
* @copyright Copyright (C) 2013 XXXXX
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
|
||||
'Class:FunctionalCI/Attribute:dataflows' => 'Flux de données',
|
||||
'Class:FunctionalCI/Attribute:dataflows+' => 'Flux de données dont cet objet est la source ou la destination',
|
||||
'FunctionalCI:DataFlow:Title' => 'Flux de données',
|
||||
'FunctionalCI:DataFlow:Inbound' => 'Flux entrants',
|
||||
'FunctionalCI:DataFlow:Outbound' => 'Flux sortants',
|
||||
|
||||
'DataFlow:baseinfo' => 'Informations générales',
|
||||
'DataFlow:otherinfo' => 'Autres informations',
|
||||
'DataFlow:moreinfo' => 'Spécificités du flux',
|
||||
|
||||
'Class:DataFlow' => 'Flux de Données',
|
||||
'Class:DataFlow+' => 'Modélise les données transférées entre instances d\'application',
|
||||
'Class:DataFlow/Name' => '%1$s',
|
||||
'Class:DataFlow/Attribute:name' => 'Nom',
|
||||
'Class:DataFlow/Attribute:name_id+' => 'Type de données transferées',
|
||||
'Class:DataFlow/Attribute:source_id' => 'Source',
|
||||
'Class:DataFlow/Attribute:source_id+' => 'Instance d\application à la source du flux de données',
|
||||
'Class:DataFlow/Attribute:source_impact' => 'Source impactante ?',
|
||||
'Class:DataFlow/Attribute:source_impact+' => 'La source impacte-t-elle le flux de données ?',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:yes' => 'oui',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:yes+' => 'Si la source tombe en panne, le flux de données est impacté',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:no' => 'non',
|
||||
'Class:DataFlow/Attribute:source_impact/Value:no+' => 'Si la source tombe en panne, le flux de données n\'est pas impacté',
|
||||
'Class:DataFlow/Attribute:destination_id' => 'Destinataire',
|
||||
'Class:DataFlow/Attribute:destination_id+' => 'Destinataire des données, à choisir parmi les instances d\'application',
|
||||
'Class:DataFlow/Attribute:destination_impact' => 'Destinataire impacté ?',
|
||||
'Class:DataFlow/Attribute:destination_impact+' => 'Le destinataire est-il impacté si le flux de données s\'arrête ?',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:yes' => 'oui',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:yes+' => 'Si le flux s\'arrête, le destinataire est impacté',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no' => 'non',
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no+' => 'Si le flux s\'arrête, le destinataire n\'est pas impacté',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id' => 'Type de flux',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id+' => 'Typologie du flux',
|
||||
'Class:DataFlow/Attribute:description' => 'Description',
|
||||
'Class:DataFlow/Attribute:description+' => '',
|
||||
'Class:DataFlow/Attribute:status' => 'Etat',
|
||||
'Class:DataFlow/Attribute:status+' => '',
|
||||
'Class:DataFlow/Attribute:status/Value:active' => 'actif',
|
||||
'Class:DataFlow/Attribute:status/Value:inactive' => 'inactif',
|
||||
'Class:DataFlow/Attribute:org_id' => 'Organisation',
|
||||
'Class:DataFlow/Attribute:org_id+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity' => 'Criticité',
|
||||
'Class:DataFlow/Attribute:business_criticity+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high' => 'haute',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low' => 'basse',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium' => 'moyenne',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency' => 'Fréquence d\'exécution',
|
||||
'Class:DataFlow/Attribute:execution_frequency+' => 'À quelle fréquence le transfert de données est-il exécuté',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime' => 'temps réel',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:ondemand' => 'à la demande',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:ondemand+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:hourly' => 'horaire',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:hourly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:daily' => 'journalière',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:daily+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:weekly' => 'hebdomadaire',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:weekly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly' => 'mensuelle',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly' => 'annuelle',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly+' => '',
|
||||
'Class:DataFlow/Attribute:documents_list' => 'Documents',
|
||||
'Class:DataFlow/Attribute:documents_list+' => 'Eg: technical specifications, runbooks, etc.',
|
||||
'Class:DataFlow/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DataFlow/Attribute:contacts_list+' => 'Eg: flow owner, technical support, etc.',
|
||||
|
||||
/*
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname' => 'source_id_friendlyname',
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname+' => 'Nom complet',
|
||||
'Class:DataFlow/Attribute:source_id_finalclass_recall' => 'source_id->CI sub-class',
|
||||
'Class:DataFlow/Attribute:source_id_finalclass_recall+' => 'Classe finale',
|
||||
'Class:DataFlow/Attribute:source_id_obsolescence_flag' => 'source_id->Obsolete',
|
||||
'Class:DataFlow/Attribute:source_id_obsolescence_flag+' => 'Computed dynamically on other attributes',
|
||||
'Class:DataFlow/Attribute:destination_id_friendlyname' => 'destination_id_friendlyname',
|
||||
'Class:DataFlow/Attribute:destination_id_friendlyname+' => 'Nom complet',
|
||||
'Class:DataFlow/Attribute:destination_id_finalclass_recall' => 'destination_id->CI sub-class',
|
||||
'Class:DataFlow/Attribute:destination_id_finalclass_recall+' => 'Classe finale',
|
||||
'Class:DataFlow/Attribute:destination_id_obsolescence_flag' => 'destination_id->Obsolete',
|
||||
'Class:DataFlow/Attribute:destination_id_obsolescence_flag+' => 'Computed dynamically on other attributes',
|
||||
*/
|
||||
]);
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="mv_DwPz_GcV~datTQ_sP3a" x1="27.258" x2="38.501" y1="18.189" y2="44.314" gradientTransform="rotate(90 23.5 24)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3a)" d="M14,41.19V37h14c0.552,0,1-0.448,1-1v-4c0-0.552-0.448-1-1-1H14v-4.19 c0-0.72-0.87-1.08-1.379-0.571L5.92,32.939c-0.586,0.586-0.586,1.536,0,2.121l6.701,6.701C13.13,42.271,14,41.91,14,41.19z"/><linearGradient id="mv_DwPz_GcV~datTQ_sP3b" x1="32.674" x2="34.456" y1="9.581" y2="13.722" gradientTransform="rotate(90 23.5 24)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3b)" d="M35,36v-4c0-0.552,0.448-1,1-1l0,0c0.552,0,1,0.448,1,1v4c0,0.552-0.448,1-1,1l0,0 C35.448,37,35,36.552,35,36z"/><linearGradient id="mv_DwPz_GcV~datTQ_sP3c" x1="32.674" x2="34.456" y1="5.581" y2="9.722" gradientTransform="rotate(90 23.5 24)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3c)" d="M39,36v-4c0-0.552,0.448-1,1-1l0,0c0.552,0,1,0.448,1,1v4c0,0.552-0.448,1-1,1l0,0 C39.448,37,39,36.552,39,36z"/><linearGradient id="mv_DwPz_GcV~datTQ_sP3d" x1="32.674" x2="34.456" y1="13.581" y2="17.722" gradientTransform="rotate(90 23.5 24)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3d)" d="M31,36v-4c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v4c0,0.552-0.448,1-1,1h0 C31.448,37,31,36.552,31,36z"/><linearGradient id="mv_DwPz_GcV~datTQ_sP3e" x1="551.258" x2="562.501" y1="-252.291" y2="-226.167" gradientTransform="rotate(-90 421.24 151.26)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3e)" d="M33,7.81V12H19c-0.552,0-1,0.448-1,1v4c0,0.552,0.448,1,1,1h14v4.19 c0,0.72,0.87,1.08,1.379,0.571l6.701-6.701c0.586-0.586,0.586-1.536,0-2.121l-6.701-6.701C33.87,6.729,33,7.09,33,7.81z"/><linearGradient id="mv_DwPz_GcV~datTQ_sP3f" x1="556.674" x2="558.456" y1="-260.899" y2="-256.759" gradientTransform="rotate(-90 421.24 151.26)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3f)" d="M12,13v4c0,0.552-0.448,1-1,1h0c-0.552,0-1-0.448-1-1v-4c0-0.552,0.448-1,1-1h0 C11.552,12,12,12.448,12,13z"/><linearGradient id="mv_DwPz_GcV~datTQ_sP3g" x1="556.674" x2="558.456" y1="-264.899" y2="-260.759" gradientTransform="rotate(-90 421.24 151.26)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3g)" d="M8,13v4c0,0.552-0.448,1-1,1h0c-0.552,0-1-0.448-1-1v-4c0-0.552,0.448-1,1-1h0 C7.552,12,8,12.448,8,13z"/><linearGradient id="mv_DwPz_GcV~datTQ_sP3h" x1="556.674" x2="558.456" y1="-256.899" y2="-252.758" gradientTransform="rotate(-90 421.24 151.26)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#mv_DwPz_GcV~datTQ_sP3h)" d="M16,13v4c0,0.552-0.448,1-1,1h0c-0.552,0-1-0.448-1-1v-4c0-0.552,0.448-1,1-1h0 C15.552,12,16,12.448,16,13z"/></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -1,41 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'nominal_ext1_module1/6.6.6',
|
||||
'itop-flow-map/3.3.0',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Ext For Test',
|
||||
'category' => 'business',
|
||||
'label' => 'Map applications data flows',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-structure/3.2.0',
|
||||
'itop-config-mgmt/3.2.0',
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => '',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'model.nominal_ext1_module1.php',
|
||||
|
||||
],
|
||||
'webservice' => [],
|
||||
'data.struct' => [// add your 'structure' definition XML files here,
|
||||
'webservice' => [
|
||||
|
||||
],
|
||||
'data.sample' => [// add your sample data XML files here,
|
||||
'data.struct' => [
|
||||
'data/en_us.data.itop-flow-map.xml',
|
||||
],
|
||||
'data.sample' => [
|
||||
// add your sample data XML files here,
|
||||
],
|
||||
|
||||
// Documentation
|
||||
@@ -45,7 +43,8 @@ SetupWebPage::AddModule(
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => [// Module specific settings go here, if any
|
||||
'settings' => [
|
||||
// Module specific settings go here, if any
|
||||
],
|
||||
]
|
||||
);
|
||||
@@ -186,7 +186,9 @@ function collect_configuration()
|
||||
|
||||
// iTop modules
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
$aInstalledModules = ModuleInstallationService::GetInstance()->ReadFromDB($oConfig);
|
||||
$sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->Get('db_subname')."priv_module_install");
|
||||
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
|
||||
$aInstalledModules = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install WHERE installed = '".$sLatestInstallationDate."' AND parent_id != 0");
|
||||
|
||||
foreach ($aInstalledModules as $aDBInfo) {
|
||||
$aConfiguration['itop_modules'][$aDBInfo['name']] = $aDBInfo['version'];
|
||||
|
||||
@@ -76,9 +76,6 @@
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -179,32 +176,17 @@
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
@@ -1151,9 +1133,6 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<attribute id="organization_name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -1205,32 +1184,17 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
@@ -1573,9 +1537,6 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<attribute id="service_name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -1624,32 +1585,17 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
|
||||
@@ -76,9 +76,6 @@
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -179,32 +176,17 @@
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
@@ -1140,9 +1122,6 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<attribute id="organization_name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -1194,32 +1173,17 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
@@ -1584,9 +1548,6 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<attribute id="service_name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -1635,32 +1596,17 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
|
||||
@@ -1486,29 +1486,14 @@
|
||||
<value id="draft">
|
||||
<code>draft</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="published">
|
||||
<code>published</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
|
||||
@@ -43,38 +43,18 @@
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>30</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="implementation">
|
||||
<code>implementation</code>
|
||||
<rank>20</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="stock">
|
||||
<code>stock</code>
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-neutral-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-neutral-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
<value id="obsolete">
|
||||
<code>obsolete</code>
|
||||
<rank>40</rank>
|
||||
<style>
|
||||
<main_color>$ibo-lifecycle-frozen-state-primary-color</main_color>
|
||||
<complementary_color>$ibo-lifecycle-frozen-state-secondary-color</complementary_color>
|
||||
<decoration_classes/>
|
||||
</style>
|
||||
</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
|
||||
@@ -26,12 +26,23 @@ use Composer\Semver\VersionParser;
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
|
||||
* @internal
|
||||
*/
|
||||
private static $selfDir = null;
|
||||
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
@@ -309,6 +320,24 @@ class InstalledVersions
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private static function getSelfDir()
|
||||
{
|
||||
if (self::$selfDir === null) {
|
||||
self::$selfDir = strtr(__DIR__, '\\', '/');
|
||||
}
|
||||
|
||||
return self::$selfDir;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,7 +354,9 @@ class InstalledVersions
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = self::getSelfDir();
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
@@ -333,11 +364,14 @@ class InstalledVersions
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
$copiedLocalDir = true;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'name' => 'combodo/itop',
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => '469afdb2f9aea1b6e078a2a5bb12f09a969d60e0',
|
||||
'reference' => '19d062aa830b6d6c7d17ac4046fc9ee2c5e3fab1',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -22,7 +22,7 @@
|
||||
'combodo/itop' => array(
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => '469afdb2f9aea1b6e078a2a5bb12f09a969d60e0',
|
||||
'reference' => '19d062aa830b6d6c7d17ac4046fc9ee2c5e3fab1',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/ModuleInstallationService.php';
|
||||
|
||||
class AnalyzeInstallation
|
||||
{
|
||||
private static AnalyzeInstallation $oInstance;
|
||||
private ?array $aAvailableModules = null;
|
||||
private ?array $aSelectInstall = null;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): AnalyzeInstallation
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new AnalyzeInstallation();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?AnalyzeInstallation $oInstance): void
|
||||
{
|
||||
static::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the current installation and the possibilities
|
||||
*
|
||||
* @param null|Config $oConfig Defines the target environment (DB)
|
||||
* @param mixed $modulesPath Either a single string or an array of absolute paths
|
||||
* @param bool $bAbortOnMissingDependency ...
|
||||
* @param array $aModulesToLoad List of modules to search for, defaults to all if omitted
|
||||
*
|
||||
* @return array Array with the following format:
|
||||
* array =>
|
||||
* 'iTop' => array(
|
||||
* 'installed_version' => ... (could be empty in case of a fresh install)
|
||||
* 'available_version => ...
|
||||
* )
|
||||
* <module_name> => array(
|
||||
* 'installed_version' => ...
|
||||
* 'available_version' => ...
|
||||
* 'install' => array(
|
||||
* 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY
|
||||
* 'message' => ...
|
||||
* )
|
||||
* 'uninstall' => array(
|
||||
* 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY
|
||||
* 'message' => ...
|
||||
* )
|
||||
* 'label' => ...
|
||||
* 'dependencies' => array(<module1>, <module2>, ...)
|
||||
* 'visible' => true | false
|
||||
* )
|
||||
* )
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AnalyzeInstallation(?Config $oConfig, mixed $modulesPath, bool $bAbortOnMissingDependency = false, ?array $aModulesToLoad = null)
|
||||
{
|
||||
$aRes = [
|
||||
ROOT_MODULE => [
|
||||
'installed_version' => '',
|
||||
'available_version' => ITOP_VERSION_FULL,
|
||||
'name_code' => ITOP_APPLICATION,
|
||||
],
|
||||
];
|
||||
|
||||
$aDirs = is_array($modulesPath) ? $modulesPath : [$modulesPath];
|
||||
if (! is_null($this->aAvailableModules)) {
|
||||
//test only
|
||||
$aAvailableModules = $this->aAvailableModules;
|
||||
} else {
|
||||
$aAvailableModules = ModuleDiscovery::GetAvailableModules($aDirs, $bAbortOnMissingDependency, $aModulesToLoad);
|
||||
}
|
||||
|
||||
foreach ($aAvailableModules as $sModuleId => $aModuleInfo) {
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
|
||||
$aModuleInfo['installed_version'] = '';
|
||||
$aModuleInfo['available_version'] = $sModuleVersion;
|
||||
|
||||
if ($aModuleInfo['mandatory']) {
|
||||
$aModuleInfo['install'] = [
|
||||
'flag' => MODULE_ACTION_MANDATORY,
|
||||
'message' => 'the module is part of the application',
|
||||
];
|
||||
} else {
|
||||
$aModuleInfo['install'] = [
|
||||
'flag' => MODULE_ACTION_OPTIONAL,
|
||||
'message' => '',
|
||||
];
|
||||
}
|
||||
$aRes[$sModuleName] = $aModuleInfo;
|
||||
}
|
||||
|
||||
$aCurrentlyInstalledModules = ModuleInstallationService::GetInstance()->ReadComputeInstalledModules($oConfig);
|
||||
|
||||
// Adjust the list of proposed modules
|
||||
foreach ($aCurrentlyInstalledModules as $sModuleName => $aModuleDB) {
|
||||
if ($sModuleName == ROOT_MODULE) {
|
||||
$aRes[$sModuleName]['installed_version'] = $aModuleDB['version'];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!array_key_exists($sModuleName, $aRes)) {
|
||||
// A module was installed, it is not proposed in the new build... skip
|
||||
continue;
|
||||
}
|
||||
|
||||
$aRes[$sModuleName]['installed_version'] = $aModuleDB['version'];
|
||||
|
||||
if ($aRes[$sModuleName]['mandatory']) {
|
||||
$aRes[$sModuleName]['uninstall'] = [
|
||||
'flag' => MODULE_ACTION_IMPOSSIBLE,
|
||||
'message' => 'the module is part of the application',
|
||||
];
|
||||
} else {
|
||||
$aRes[$sModuleName]['uninstall'] = [
|
||||
'flag' => MODULE_ACTION_OPTIONAL,
|
||||
'message' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
<?php
|
||||
|
||||
class ModuleInstallationService
|
||||
{
|
||||
private static ModuleInstallationService $oInstance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): ModuleInstallationService
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new ModuleInstallationService();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?ModuleInstallationService $oInstance): void
|
||||
{
|
||||
static::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
private ?array $aSelectInstall = null;
|
||||
|
||||
/**
|
||||
* @param \Config|null $oConfig
|
||||
* @return array
|
||||
*/
|
||||
public function ReadComputeInstalledModules(?Config $oConfig): array
|
||||
{
|
||||
$aSelectInstall = [];
|
||||
try {
|
||||
$aSelectInstall = $this->ReadFromDB($oConfig);
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
}
|
||||
|
||||
return $this->ComputeInstalledModules($aSelectInstall);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Config|null $oConfig
|
||||
* @return array
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLQueryHasNoResultException
|
||||
*/
|
||||
public function ReadFromDB(?Config $oConfig): array
|
||||
{
|
||||
if (is_null($oConfig)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! is_null($this->aSelectInstall)) {
|
||||
//test only
|
||||
return $this->aSelectInstall;
|
||||
}
|
||||
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
//read db module installations
|
||||
$tableWithPrefix = $this->GetTableWithPrefix($oConfig);
|
||||
$iRootId = CMDBSource::QueryToScalar("SELECT max(parent_id) FROM $tableWithPrefix");
|
||||
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
|
||||
$sSQL = <<<SQL
|
||||
SELECT * FROM $tableWithPrefix
|
||||
WHERE
|
||||
parent_id='$iRootId'
|
||||
OR id='$iRootId'
|
||||
SQL;
|
||||
return CMDBSource::QueryToArray($sSQL);
|
||||
}
|
||||
|
||||
private function GetTableWithPrefix(Config $oConfig)
|
||||
{
|
||||
$sPrefix = $oConfig->Get('db_subname');
|
||||
if (utils::IsNullOrEmptyString($sPrefix)) {
|
||||
return "priv_module_install";
|
||||
}
|
||||
|
||||
return "{$sPrefix}priv_module_install";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Config $oConfig
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function GetApplicationVersion(Config $oConfig)
|
||||
{
|
||||
try {
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
$tableWithPrefix = $this->GetTableWithPrefix($oConfig);
|
||||
$sSQLQuery = "SELECT * FROM $tableWithPrefix";
|
||||
$aSelectInstall = CMDBSource::QueryToArray($sSQLQuery);
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
$this->log_error('Can not connect to the database: host: '.$oConfig->Get('db_host').', user:'.$oConfig->Get('db_user').', pwd:'.$oConfig->Get('db_pwd').', db name:'.$oConfig->Get('db_name'));
|
||||
$this->log_error('Exception '.$e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
$aResult = [];
|
||||
// Scan the list of installed modules to get the version of the 'ROOT' module which holds the main application version
|
||||
foreach ($aSelectInstall as $aInstall) {
|
||||
$sModuleVersion = $aInstall['version'];
|
||||
if ($sModuleVersion == '') {
|
||||
// Though the version cannot be empty in iTop 2.0, it used to be possible
|
||||
// therefore we have to put something here or the module will not be considered
|
||||
// as being installed
|
||||
$sModuleVersion = '0.0.0';
|
||||
}
|
||||
|
||||
if ($aInstall['parent_id'] == 0) {
|
||||
if ($aInstall['name'] == DATAMODEL_MODULE) {
|
||||
$aResult['datamodel_version'] = $sModuleVersion;
|
||||
$aComments = json_decode($aInstall['comment'], true);
|
||||
if (is_array($aComments)) {
|
||||
$aResult = array_merge($aResult, $aComments);
|
||||
}
|
||||
} else {
|
||||
$aResult['product_name'] = $aInstall['name'];
|
||||
$aResult['product_version'] = $sModuleVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!array_key_exists('datamodel_version', $aResult)) {
|
||||
// Versions prior to 2.0 did not record the version of the datamodel
|
||||
// so assume that the datamodel version is equal to the application version
|
||||
$aResult['datamodel_version'] = $aResult['product_version'];
|
||||
}
|
||||
$this->log_info("GetApplicationVersion returns: product_name: ".$aResult['product_name'].', product_version: '.$aResult['product_version']);
|
||||
return empty($aResult) ? false : $aResult;
|
||||
}
|
||||
|
||||
private function ComputeInstalledModules(array $aSelectInstall): array
|
||||
{
|
||||
$aInstallByModule = []; // array of <module> => array ('installed' => timestamp, 'version' => <version>)
|
||||
|
||||
//module installation datetime is mostly the same for all modules
|
||||
//unless there was issue recording things in DB
|
||||
$sFirstDatetime = null;
|
||||
$iFirstTime = -1;
|
||||
foreach ($aSelectInstall as $aInstall) {
|
||||
//$aInstall['comment']; // unsused
|
||||
$sDatetime = $aInstall['installed'];
|
||||
|
||||
if (is_null($sFirstDatetime)) {
|
||||
$sFirstDatetime = $sDatetime;
|
||||
$iFirstTime = strtotime($sDatetime);
|
||||
$iInstalled = $iFirstTime;
|
||||
} elseif ($sDatetime === $sFirstDatetime) {
|
||||
$iInstalled = $iFirstTime;
|
||||
} else {
|
||||
$sDatetime = $aInstall['installed'];
|
||||
$iInstalled = strtotime($sDatetime);
|
||||
}
|
||||
|
||||
$sModuleName = $aInstall['name'];
|
||||
$sModuleVersion = $aInstall['version'];
|
||||
if ($sModuleVersion == '') {
|
||||
// Though the version cannot be empty in iTop 2.0, it used to be possible
|
||||
// therefore we have to put something here or the module will not be considered
|
||||
// as being installed
|
||||
$sModuleVersion = '0.0.0';
|
||||
}
|
||||
|
||||
if ($aInstall['parent_id'] == 0) {
|
||||
$aInstallByModule[ROOT_MODULE] = [
|
||||
'installed_version' => $sModuleVersion,
|
||||
'installed' => $iInstalled,
|
||||
'version' => $sModuleVersion,
|
||||
];
|
||||
} else {
|
||||
$aInstallByModule[$sModuleName] = [
|
||||
'installed' => $iInstalled,
|
||||
'version' => $sModuleVersion,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $aInstallByModule;
|
||||
}
|
||||
}
|
||||
@@ -477,7 +477,7 @@ class MFCompiler
|
||||
$sClass = $oClass->getAttribute("id");
|
||||
$aAllClasses[] = $sClass;
|
||||
try {
|
||||
$sCompiledCode .= $this->CompileClass($oClass, $sModuleName, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
|
||||
$sCompiledCode .= $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
|
||||
} catch (DOMFormatException $e) {
|
||||
$sMessage = "Failed to process class '$sClass', ";
|
||||
if (!empty($sModuleRootDir)) {
|
||||
@@ -1189,7 +1189,6 @@ EOF
|
||||
|
||||
/**
|
||||
* @param \MFElement $oClass
|
||||
* @param string $sModuleName
|
||||
* @param string $sTempTargetDir
|
||||
* @param string $sFinalTargetDir
|
||||
* @param string $sModuleRelativeDir
|
||||
@@ -1197,7 +1196,7 @@ EOF
|
||||
* @return string
|
||||
* @throws \DOMFormatException
|
||||
*/
|
||||
protected function CompileClass($oClass, $sModuleName, $sTempTargetDir, $sFinalTargetDir, $sModuleRelativeDir)
|
||||
protected function CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sModuleRelativeDir)
|
||||
{
|
||||
$sClass = $oClass->getAttribute('id');
|
||||
$oProperties = $oClass->GetUniqueElement('properties');
|
||||
@@ -1210,7 +1209,6 @@ EOF
|
||||
$aClassParams = [];
|
||||
$aClassParams['category'] = $this->GetPropString($oProperties, 'category', '');
|
||||
$aClassParams['key_type'] = "'autoincrement'";
|
||||
$aClassParams['created_in'] = "'$sModuleName'";
|
||||
if ((bool)$this->GetPropNumber($oProperties, 'is_link', 0)) {
|
||||
$aClassParams['is_link'] = 'true';
|
||||
}
|
||||
|
||||
@@ -148,38 +148,32 @@ class iTopExtensionsMap
|
||||
{
|
||||
/**
|
||||
* The list of all discovered extensions
|
||||
* @var array $aExtensions
|
||||
* @param string $sFromEnvironment The environment to scan
|
||||
* @param bool $bNormailizeOldExtension true to "magically" convert some well-known old extensions (i.e. a set of modules) to the new iTopExtension format
|
||||
* @return void
|
||||
*/
|
||||
protected $aExtensions;
|
||||
/**
|
||||
* The list of all currently installed extensions
|
||||
* @var array $aInstalledExtensions
|
||||
* @var array|null
|
||||
*/
|
||||
protected array $aInstalledExtensions;
|
||||
protected ?array $aInstalledExtensions = null;
|
||||
|
||||
protected array $aExtensionsByCode;
|
||||
/**
|
||||
* The list of directories browsed using the ReadDir method when building the map
|
||||
* @var string[]
|
||||
*/
|
||||
protected $aScannedDirs;
|
||||
|
||||
/**
|
||||
* The list of all discovered extensions
|
||||
* @param string $sFromEnvironment The environment to scan
|
||||
* @param bool $bNormailizeOldExtension true to "magically" convert some well-known old extensions (i.e. a set of modules) to the new iTopExtension format
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($sFromEnvironment = 'production', $aExtraDirs = [])
|
||||
{
|
||||
$this->aExtensions = [];
|
||||
$this->aExtensionsByCode = [];
|
||||
$this->aScannedDirs = [];
|
||||
$this->ScanDisk($sFromEnvironment);
|
||||
foreach ($aExtraDirs as $sDir) {
|
||||
$this->ReadDir($sDir, iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
$this->CheckDependencies();
|
||||
$this->CheckDependencies($sFromEnvironment);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,10 +184,8 @@ class iTopExtensionsMap
|
||||
*/
|
||||
protected function ScanDisk($sEnvironment)
|
||||
{
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) {
|
||||
//no installation xml found in 2.x: let's read all extensions in 2.x first
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x') && !$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) {
|
||||
if (!$this->ReadDir(APPROOT.'/datamodels/2.x', iTopExtension::SOURCE_WIZARD)) {
|
||||
//nothing found in 2.x : fallback read in 1.x (flat structure)
|
||||
$this->ReadDir(APPROOT.'/datamodels/1.x', iTopExtension::SOURCE_WIZARD);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +261,6 @@ class iTopExtensionsMap
|
||||
// This "new" extension is "newer" than the previous one, let's replace the previous one
|
||||
unset($this->aExtensions[$key]);
|
||||
$this->aExtensions[$oNewExtension->sCode.'/'.$oNewExtension->sVersion] = $oNewExtension;
|
||||
$this->aExtensionsByCode[$oNewExtension->sCode] = $oNewExtension;
|
||||
return;
|
||||
} else {
|
||||
// This "new" extension is not "newer" than the previous one, let's ignore it
|
||||
@@ -279,22 +270,6 @@ class iTopExtensionsMap
|
||||
}
|
||||
// Finally it's not a duplicate, let's add it to the list
|
||||
$this->aExtensions[$oNewExtension->sCode.'/'.$oNewExtension->sVersion] = $oNewExtension;
|
||||
$this->aExtensionsByCode[$oNewExtension->sCode] = $oNewExtension;
|
||||
}
|
||||
|
||||
public function RemoveExtension(string $sCode): void
|
||||
{
|
||||
$oExtension = $this->GetFromExtensionCode($sCode);
|
||||
if (is_null($oExtension)) {
|
||||
\IssueLog::Error(__METHOD__.": cannot find extension to remove", null, [$sCode]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
\IssueLog::Debug(__METHOD__.": remove extension from map", null, [$oExtension->sCode => $oExtension->sSourceDir]);
|
||||
|
||||
unset($this->aExtensions[$oExtension->sCode.'/'.$oExtension->sVersion]);
|
||||
unset($this->aExtensionsByCode[$sCode]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,31 +280,13 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function GetFromExtensionCode(string $sExtensionCode): ?iTopExtension
|
||||
{
|
||||
return $this->aExtensionsByCode[$sExtensionCode] ?? null;
|
||||
}
|
||||
|
||||
/*public function GetMissingExtensions(array $aSelectedExtensions)
|
||||
{
|
||||
\SetupLog::Info(__METHOD__, null, ['selected' => $aSelectedExtensions]);
|
||||
$aExtensionsFromDb = array_keys($this->aExtensionsByCode);
|
||||
sort($aExtensionsFromDb);
|
||||
\SetupLog::Info(__METHOD__, null, ['found' => $aExtensionsFromDb]);
|
||||
|
||||
$aRes = [];
|
||||
foreach (array_diff($aExtensionsFromDb, $aSelectedExtensions) as $sExtensionCode) {
|
||||
$oExtension = $this->GetFromExtensionCode($sExtensionCode);
|
||||
if (!is_null($oExtension) && $oExtension->bVisible && $oExtension->sSource != iTopExtension::SOURCE_WIZARD) {
|
||||
|
||||
\SetupLog::Info(__METHOD__."$sExtensionCode", null, ['visible' => $oExtension->bVisible, 'mandatory' => $oExtension->bMandatory]);
|
||||
$aRes [] = $sExtensionCode;
|
||||
} else {
|
||||
\SetupLog::Info(__METHOD__." MISSING $sExtensionCode");
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode === $sExtensionCode) {
|
||||
return $oExtension;
|
||||
}
|
||||
}
|
||||
\SetupLog::Info(__METHOD__, null, $aRes);
|
||||
|
||||
return $aRes;
|
||||
}*/
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read (recursively) a directory to find if it contains extensions (or modules)
|
||||
@@ -389,15 +346,19 @@ class iTopExtensionsMap
|
||||
// to this extension
|
||||
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
if ($sModuleVersion == '') {
|
||||
// Provide a default module version since version is mandatory when recording ExtensionInstallation
|
||||
$sModuleVersion = '0.0.1';
|
||||
}
|
||||
$aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]['uninstallable'] ??= 'yes';
|
||||
|
||||
$oExtension = null;
|
||||
if ($sParentExtensionId !== null) {
|
||||
$oExtension = $this->aExtensions[$sParentExtensionId] ?? null;
|
||||
}
|
||||
|
||||
if (is_null($oExtension)) {
|
||||
// Not already inside an folder containing an 'extension.xml' file
|
||||
if (($sParentExtensionId !== null) && (array_key_exists($sParentExtensionId, $this->aExtensions)) && ($this->aExtensions[$sParentExtensionId] instanceof iTopExtension)) {
|
||||
// Already inside an extension, let's add this module the list of modules belonging to this extension
|
||||
$this->aExtensions[$sParentExtensionId]->aModules[] = $sModuleName;
|
||||
$this->aExtensions[$sParentExtensionId]->aModuleVersion[$sModuleName] = $sModuleVersion;
|
||||
$this->aExtensions[$sParentExtensionId]->aModuleInfo[$sModuleName] = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG];
|
||||
} else {
|
||||
// Not already inside a folder containing an 'extension.xml' file
|
||||
|
||||
// Ignore non-visible modules and auto-select ones, since these are never prompted
|
||||
// as a choice to the end-user
|
||||
@@ -421,13 +382,6 @@ class iTopExtensionsMap
|
||||
$oExtension->sSourceDir = $sSearchDir;
|
||||
$oExtension->bVisible = $bVisible;
|
||||
$this->AddExtension($oExtension);
|
||||
} else {
|
||||
$oExtension->aModules[] = $sModuleName;
|
||||
$oExtension->aModuleVersion[$sModuleName] = $sModuleVersion;
|
||||
$oExtension->aModuleInfo[$sModuleName] = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG];
|
||||
|
||||
$this->aExtensions[$sParentExtensionId] = $oExtension;
|
||||
$this->aExtensionsByCode[$oExtension->sCode] = $oExtension;
|
||||
}
|
||||
|
||||
closedir($hDir);
|
||||
@@ -449,9 +403,10 @@ class iTopExtensionsMap
|
||||
/**
|
||||
* Check if some extension contains a module with missing dependencies...
|
||||
* If so, populate the aMissingDepenencies array
|
||||
* @param string $sFromEnvironment
|
||||
* @return void
|
||||
*/
|
||||
protected function CheckDependencies()
|
||||
protected function CheckDependencies($sFromEnvironment)
|
||||
{
|
||||
$aSearchDirs = [];
|
||||
|
||||
@@ -463,7 +418,7 @@ class iTopExtensionsMap
|
||||
$aSearchDirs = array_merge($aSearchDirs, $this->aScannedDirs);
|
||||
|
||||
try {
|
||||
ModuleDiscovery::GetAvailableModules($aSearchDirs, true);
|
||||
$aAllModules = ModuleDiscovery::GetAvailableModules($aSearchDirs, true);
|
||||
} catch (MissingDependencyException $e) {
|
||||
// Some modules have missing dependencies
|
||||
// Let's check what is the impact at the "extensions" level
|
||||
@@ -511,17 +466,11 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function MarkAsChosen($sExtensionCode, $bMark = true)
|
||||
{
|
||||
$oExtension = $this->GetFromExtensionCode($sExtensionCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$oExtension->bMarkedAsChosen = $bMark;
|
||||
}
|
||||
}
|
||||
|
||||
public function MarkAsUninstallable($sExtensionCode, $bMark = true)
|
||||
{
|
||||
$oExtension = $this->GetFromExtensionCode($sExtensionCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$oExtension->bUninstallable = $bMark;
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode == $sExtensionCode) {
|
||||
$oExtension->bMarkedAsChosen = $bMark;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,11 +481,11 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function IsMarkedAsChosen($sExtensionCode)
|
||||
{
|
||||
$oExtension = $this->GetFromExtensionCode($sExtensionCode);
|
||||
if (!is_null($oExtension)) {
|
||||
return $oExtension->bMarkedAsChosen;
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode == $sExtensionCode) {
|
||||
return $oExtension->bMarkedAsChosen;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -548,9 +497,11 @@ class iTopExtensionsMap
|
||||
*/
|
||||
protected function SetInstalledVersion($sExtensionCode, $sInstalledVersion)
|
||||
{
|
||||
$oExtension = $this->GetFromExtensionCode($sExtensionCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$oExtension->sInstalledVersion = $sInstalledVersion;
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode == $sExtensionCode) {
|
||||
$oExtension->sInstalledVersion = $sInstalledVersion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,12 +527,7 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function LoadChoicesFromDatabase(Config $oConfig)
|
||||
{
|
||||
$aLoadInstalledExtensionsFromDatabase = $this->LoadInstalledExtensionsFromDatabase($oConfig);
|
||||
if (false === $aLoadInstalledExtensionsFromDatabase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($aLoadInstalledExtensionsFromDatabase as $oExtension) {
|
||||
foreach ($this->LoadInstalledExtensionsFromDatabase($oConfig) as $oExtension) {
|
||||
$this->MarkAsChosen($oExtension->sCode);
|
||||
$this->SetInstalledVersion($oExtension->sCode, $oExtension->sVersion);
|
||||
}
|
||||
@@ -639,6 +585,8 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function ModuleIsChosenAsPartOfAnExtension($sModuleNameToFind, $sInSourceOnly = iTopExtension::SOURCE_REMOTE)
|
||||
{
|
||||
$bChosen = false;
|
||||
|
||||
foreach ($this->GetAllExtensions() as $oExtension) {
|
||||
if (($oExtension->sSource == $sInSourceOnly) &&
|
||||
($oExtension->bMarkedAsChosen == true) &&
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use MetaModel;
|
||||
use RunTimeEnvironment;
|
||||
use SetupUtils;
|
||||
|
||||
class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
public const DRY_REMOVAL_AUDIT_ENV = "extension-removal";
|
||||
|
||||
protected array $aExtensionsByCode;
|
||||
private bool $bExtensionMapModified = false;
|
||||
|
||||
/**
|
||||
* Toolset for building a run-time environment
|
||||
*
|
||||
* @param string $sEnvironment (e.g. 'test')
|
||||
* @param bool $bAutoCommit (make the target environment directly, or build a temporary one)
|
||||
*/
|
||||
public function __construct($sEnvironment = self::DRY_REMOVAL_AUDIT_ENV, $bAutoCommit = true)
|
||||
{
|
||||
parent::__construct($sEnvironment, $bAutoCommit);
|
||||
$this->aExtensionsByCode = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sSourceEnv
|
||||
* @param array $aExtensionCodesToRemove
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Prepare(string $sSourceEnv, array $aExtensionCodesToRemove)
|
||||
{
|
||||
|
||||
$sEnv = $this->sFinalEnv;
|
||||
$this->aExtensionsByCode = $aExtensionCodesToRemove;
|
||||
//SetupUtils::rrmdir(APPROOT."/data/$sEnv-modules");
|
||||
$this->Cleanup();
|
||||
SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sEnv-modules");
|
||||
|
||||
if (count($aExtensionCodesToRemove) > 0) {
|
||||
$this->RemoveExtensionsLocally($aExtensionCodesToRemove);
|
||||
}
|
||||
$oDryRemovalConfig = clone(MetaModel::GetConfig());
|
||||
$oDryRemovalConfig->ChangeModulesPath($sSourceEnv, $this->sFinalEnv);
|
||||
$this->WriteConfigFileSafe($oDryRemovalConfig);
|
||||
}
|
||||
|
||||
private function RemoveExtensionsLocally(array $aExtensionCodes): void
|
||||
{
|
||||
$oExtensionsMap = new \iTopExtensionsMap($this->sFinalEnv);
|
||||
|
||||
foreach ($aExtensionCodes as $sCode) {
|
||||
/** @var \iTopExtension $oExtension */
|
||||
$oExtension = $oExtensionsMap->GetFromExtensionCode($sCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$sDir = $oExtension->sSourceDir;
|
||||
\IssueLog::Info(__METHOD__.": remove extension locally", null, [$oExtension->sCode => $sDir]);
|
||||
SetupUtils::rrmdir($sDir);
|
||||
} else {
|
||||
\IssueLog::Warning(__METHOD__." cannot find extensions", null, ['env' => $this->sFinalEnv, 'code' => $sCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function Cleanup()
|
||||
{
|
||||
$sEnv = $this->sFinalEnv;
|
||||
SetupUtils::rrmdir(APPROOT."/data/$sEnv-modules");
|
||||
SetupUtils::rrmdir(APPROOT."/data/cache-$sEnv");
|
||||
SetupUtils::rrmdir(APPROOT."/env-$sEnv");
|
||||
SetupUtils::rrmdir(APPROOT."/conf/$sEnv");
|
||||
@unlink(APPROOT."/data/datamodel-$sEnv.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \iTopExtensionsMap|null
|
||||
*/
|
||||
/*protected function GetExtensionMap(): ?iTopExtensionsMap
|
||||
{
|
||||
if (is_null(parent::GetExtensionMap())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->bExtensionMapModified) {
|
||||
$this->bExtensionMapModified = true;
|
||||
foreach ($this->aExtensionsByCode as $sCode) {
|
||||
parent::GetExtensionMap()->RemoveExtension($sCode);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::GetExtensionMap();
|
||||
}*/
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use CoreException;
|
||||
use Exception;
|
||||
|
||||
class ModelReflectionSerializer
|
||||
{
|
||||
private static ModelReflectionSerializer $oInstance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): ModelReflectionSerializer
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new ModelReflectionSerializer();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?ModelReflectionSerializer $oInstance): void
|
||||
{
|
||||
self::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
public function GetModelFromEnvironment(string $sEnv): array
|
||||
{
|
||||
\IssueLog::Info(__METHOD__, null, ['env' => $sEnv]);
|
||||
$sPHPExec = trim(\MetaModel::GetConfig()->Get('php_path'));
|
||||
$sOutput = "";
|
||||
$iRes = 0;
|
||||
exec(sprintf("$sPHPExec %s/get_model_reflection.php --env='%s'", __DIR__, $sEnv), $sOutput, $iRes);
|
||||
if ($iRes != 0) {
|
||||
\IssueLog::Error("Cannot get classes", null, ['env' => $sEnv, 'code' => $iRes, "output" => $sOutput]);
|
||||
throw new CoreException("Cannot get classes");
|
||||
}
|
||||
|
||||
$aClasses = json_decode($sOutput[0] ?? null, true);
|
||||
if (false === $aClasses) {
|
||||
\IssueLog::Error("Invalid JSON", null, ["output" => $sOutput]);
|
||||
throw new Exception("cannot get classes");
|
||||
}
|
||||
|
||||
if (!is_array($aClasses)) {
|
||||
\IssueLog::Error("not an array", null, ["classes" => $aClasses]);
|
||||
throw new Exception("cannot get classes");
|
||||
}
|
||||
|
||||
return $aClasses;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use MetaModel;
|
||||
|
||||
require_once APPROOT.'setup/feature_removal/ModelReflectionSerializer.php';
|
||||
|
||||
class SetupAudit
|
||||
{
|
||||
//file used when present to trigger audit exception when testing specific setups
|
||||
public const GETISSUE_ERROR_MSG_FILE_FORTESTONLY = '.setup_audit_error_msg.txt';
|
||||
|
||||
private string $sEnvBeforeExtensionRemoval;
|
||||
private string $sEnvAfterExtensionRemoval;
|
||||
|
||||
private array $aClassesBeforeRemoval;
|
||||
private array $aClassesAfterRemoval;
|
||||
private array $aRemovedClasses;
|
||||
private array $aFinalClassesRemoved;
|
||||
|
||||
public function __construct(string $sEnvBeforeExtensionRemoval, string $sEnvAfterExtensionRemoval = DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV)
|
||||
{
|
||||
$this->sEnvBeforeExtensionRemoval = $sEnvBeforeExtensionRemoval;
|
||||
$this->sEnvAfterExtensionRemoval = $sEnvAfterExtensionRemoval;
|
||||
|
||||
$sCurrentEnvt = MetaModel::GetEnvironment();
|
||||
if ($sCurrentEnvt === $this->sEnvBeforeExtensionRemoval) {
|
||||
$this->aClassesBeforeRemoval = MetaModel::GetClasses();
|
||||
} else {
|
||||
$this->aClassesBeforeRemoval = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvBeforeExtensionRemoval);
|
||||
}
|
||||
|
||||
if ($sCurrentEnvt === $this->sEnvAfterExtensionRemoval) {
|
||||
$this->aClassesAfterRemoval = MetaModel::GetClasses();
|
||||
} else {
|
||||
$this->aClassesAfterRemoval = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvAfterExtensionRemoval);
|
||||
}
|
||||
|
||||
$this->aRemovedClasses = [];
|
||||
$this->aFinalClassesRemoved = [];
|
||||
}
|
||||
|
||||
/*public function SetSelectedExtensions(Config $oConfig, array $aSelectedExtensions)
|
||||
{
|
||||
$oExtensionsMap = new \iTopExtensionsMap();
|
||||
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
|
||||
|
||||
sort($aSelectedExtensions);
|
||||
$this->aExtensionToRemove = $oExtensionsMap->GetMissingExtensions($aSelectedExtensions);
|
||||
sort($this->aExtensionToRemove);
|
||||
\SetupLog::Info(__METHOD__, null, ['aExtensionToRemove' => $this->aExtensionToRemove]);
|
||||
}*/
|
||||
|
||||
public function GetRemovedClasses(): array
|
||||
{
|
||||
if (count($this->aRemovedClasses) == 0) {
|
||||
if (count($this->aClassesBeforeRemoval) == 0) {
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
if (count($this->aClassesAfterRemoval) == 0) {
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
$aExtensionsNames = array_diff($this->aClassesBeforeRemoval, $this->aClassesAfterRemoval);
|
||||
$this->aRemovedClasses = [];
|
||||
$aClasses = array_values($aExtensionsNames);
|
||||
sort($aClasses);
|
||||
|
||||
foreach ($aClasses as $i => $sClass) {
|
||||
$this->aRemovedClasses[] = $sClass;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
/** test only: return file path that force audit error being raised
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetErrorMessageFilePathForTestOnly(): string
|
||||
{
|
||||
return APPROOT."/data/".self::GETISSUE_ERROR_MSG_FILE_FORTESTONLY;
|
||||
}
|
||||
|
||||
public function GetIssues(bool $bThrowExceptionAtFirstIssue = false): array
|
||||
{
|
||||
$sErrorMessageFilePath = self::GetErrorMessageFilePathForTestOnly();
|
||||
if ($bThrowExceptionAtFirstIssue && is_file($sErrorMessageFilePath)) {
|
||||
$sMsg = file_get_contents($sErrorMessageFilePath);
|
||||
throw new \Exception($sMsg);
|
||||
}
|
||||
|
||||
$this->aFinalClassesRemoved = [];
|
||||
|
||||
foreach ($this->GetRemovedClasses() as $sClass) {
|
||||
if (MetaModel::IsAbstract($sClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!MetaModel::IsStandaloneClass($sClass)) {
|
||||
$iCount = $this->Count($sClass);
|
||||
$this->aFinalClassesRemoved[$sClass] = $iCount;
|
||||
if ($bThrowExceptionAtFirstIssue && $iCount > 0) {
|
||||
//setup envt: should raise issue ASAP
|
||||
throw new \Exception($sClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->aFinalClassesRemoved;
|
||||
}
|
||||
|
||||
private function Count($sClass): int
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT $sClass", []);
|
||||
$oSearch->AllowAllData();
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
|
||||
return $oSet->Count();
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once(dirname(__DIR__, 2).'/approot.inc.php');
|
||||
require_once(APPROOT.'application/application.inc.php');
|
||||
$sEnv = null;
|
||||
if (isset($argv)) {
|
||||
foreach ($argv as $iArg => $sArg) {
|
||||
if (preg_match('/^--env=(.*)$/', $sArg, $aMatches)) {
|
||||
$sEnv = $aMatches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($sEnv)) {
|
||||
echo "No environment provided (--env) to read datamodel.";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$sConfFile = utils::GetConfigFilePath($sEnv);
|
||||
|
||||
try {
|
||||
MetaModel::Startup($sConfFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
} catch (\Throwable $e) {
|
||||
echo $e->getMessage();
|
||||
echo $e->getTraceAsString();
|
||||
\SetupLog::Error(
|
||||
"Cannot read model from provided environment",
|
||||
null,
|
||||
[
|
||||
'env' => $sEnv,
|
||||
'error' => $e->getMessage(),
|
||||
'stack' => $e->getTraceAsString(),
|
||||
]
|
||||
);
|
||||
echo "Cannot read model from provided environment";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$aClasses = MetaModel::GetClasses();
|
||||
|
||||
echo json_encode($aClasses);
|
||||
@@ -120,6 +120,10 @@ class ModuleDiscovery
|
||||
if (is_null($aArgs) || ! is_array($aArgs)) {
|
||||
throw new ModuleFileReaderException("Error parsing module file args", 0, null, $sFilePath);
|
||||
}
|
||||
if (!array_key_exists('itop_version', $aArgs)) {
|
||||
// Assume 1.0.2
|
||||
$aArgs['itop_version'] = '1.0.2';
|
||||
}
|
||||
foreach (array_keys(self::$m_aModuleArgs) as $sArgName) {
|
||||
if (!array_key_exists($sArgName, $aArgs)) {
|
||||
throw new Exception("Module '$sId': missing argument '$sArgName'");
|
||||
|
||||
@@ -32,7 +32,6 @@ require_once APPROOT."setup/modulediscovery.class.inc.php";
|
||||
require_once APPROOT.'setup/modelfactory.class.inc.php';
|
||||
require_once APPROOT.'setup/compiler.class.inc.php';
|
||||
require_once APPROOT.'setup/extensionsmap.class.inc.php';
|
||||
require_once APPROOT.'setup/AnalyzeInstallation.php';
|
||||
|
||||
define('MODULE_ACTION_OPTIONAL', 1);
|
||||
define('MODULE_ACTION_MANDATORY', 2);
|
||||
@@ -62,23 +61,7 @@ class RunTimeEnvironment
|
||||
* Extensions map of the source environment
|
||||
* @var iTopExtensionsMap
|
||||
*/
|
||||
protected ?iTopExtensionsMap $oExtensionsMap;
|
||||
|
||||
protected function GetExtensionMap(): ?iTopExtensionsMap
|
||||
{
|
||||
return $this->oExtensionsMap;
|
||||
}
|
||||
|
||||
public function InitExtensionMap($aExtraDirs, $oSourceConfig)
|
||||
{
|
||||
// Actually read the modules available for the target environment,
|
||||
// but get the selection from the source environment and finally
|
||||
// mark as (automatically) chosen alll the "remote" modules present in the
|
||||
// target environment (data/<target-env>-modules)
|
||||
// The actual choices will be recorded by RecordInstallation below
|
||||
$this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv, $aExtraDirs);
|
||||
$this->oExtensionsMap->LoadChoicesFromDatabase($oSourceConfig);
|
||||
}
|
||||
protected $oExtensionsMap;
|
||||
|
||||
/**
|
||||
* Toolset for building a run-time environment
|
||||
@@ -162,12 +145,12 @@ class RunTimeEnvironment
|
||||
* @return array Array with the following format:
|
||||
* array =>
|
||||
* 'iTop' => array(
|
||||
* 'installed_version' => ... (could be empty in case of a fresh install)
|
||||
* 'available_version => ...
|
||||
* 'version_db' => ... (could be empty in case of a fresh install)
|
||||
* 'version_code => ...
|
||||
* )
|
||||
* <module_name> => array(
|
||||
* 'installed_version' => ...
|
||||
* 'available_version' => ...
|
||||
* 'version_db' => ...
|
||||
* 'version_code' => ...
|
||||
* 'install' => array(
|
||||
* 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY
|
||||
* 'message' => ...
|
||||
@@ -185,7 +168,137 @@ class RunTimeEnvironment
|
||||
*/
|
||||
public function AnalyzeInstallation($oConfig, $modulesPath, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
|
||||
{
|
||||
return AnalyzeInstallation::GetInstance()->AnalyzeInstallation($oConfig, $modulesPath, $bAbortOnMissingDependency, $aModulesToLoad);
|
||||
$aRes = [
|
||||
ROOT_MODULE => [
|
||||
'version_db' => '',
|
||||
'name_db' => '',
|
||||
'version_code' => ITOP_VERSION_FULL,
|
||||
'name_code' => ITOP_APPLICATION,
|
||||
],
|
||||
];
|
||||
|
||||
$aDirs = is_array($modulesPath) ? $modulesPath : [$modulesPath];
|
||||
$aModules = ModuleDiscovery::GetAvailableModules($aDirs, $bAbortOnMissingDependency, $aModulesToLoad);
|
||||
foreach ($aModules as $sModuleId => $aModuleInfo) {
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
if ($sModuleName == '') {
|
||||
throw new Exception("Missing name for the module: '$sModuleId'");
|
||||
}
|
||||
if ($sModuleVersion == '') {
|
||||
// The version must not be empty (it will be used as a criteria to determine wether a module has been installed or not)
|
||||
//throw new Exception("Missing version for the module: '$sModuleId'");
|
||||
$sModuleVersion = '1.0.0';
|
||||
}
|
||||
|
||||
$sModuleAppVersion = $aModuleInfo['itop_version'];
|
||||
$aModuleInfo['version_db'] = '';
|
||||
$aModuleInfo['version_code'] = $sModuleVersion;
|
||||
|
||||
if (!in_array($sModuleAppVersion, ['1.0.0', '1.0.1', '1.0.2'])) {
|
||||
// This module is NOT compatible with the current version
|
||||
$aModuleInfo['install'] = [
|
||||
'flag' => MODULE_ACTION_IMPOSSIBLE,
|
||||
'message' => 'the module is not compatible with the current version of the application',
|
||||
];
|
||||
} elseif ($aModuleInfo['mandatory']) {
|
||||
$aModuleInfo['install'] = [
|
||||
'flag' => MODULE_ACTION_MANDATORY,
|
||||
'message' => 'the module is part of the application',
|
||||
];
|
||||
} else {
|
||||
$aModuleInfo['install'] = [
|
||||
'flag' => MODULE_ACTION_OPTIONAL,
|
||||
'message' => '',
|
||||
];
|
||||
}
|
||||
$aRes[$sModuleName] = $aModuleInfo;
|
||||
}
|
||||
|
||||
try {
|
||||
$aSelectInstall = [];
|
||||
if (! is_null($oConfig)) {
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
$aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install");
|
||||
}
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
}
|
||||
|
||||
// Build the list of installed module (get the latest installation)
|
||||
//
|
||||
$aInstallByModule = []; // array of <module> => array ('installed' => timestamp, 'version' => <version>)
|
||||
$iRootId = 0;
|
||||
foreach ($aSelectInstall as $aInstall) {
|
||||
if (($aInstall['parent_id'] == 0) && ($aInstall['name'] != 'datamodel')) {
|
||||
// Root module, what is its ID ?
|
||||
$iId = (int) $aInstall['id'];
|
||||
if ($iId > $iRootId) {
|
||||
$iRootId = $iId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aSelectInstall as $aInstall) {
|
||||
//$aInstall['comment']; // unsused
|
||||
$iInstalled = strtotime($aInstall['installed']);
|
||||
$sModuleName = $aInstall['name'];
|
||||
$sModuleVersion = $aInstall['version'];
|
||||
if ($sModuleVersion == '') {
|
||||
// Though the version cannot be empty in iTop 2.0, it used to be possible
|
||||
// therefore we have to put something here or the module will not be considered
|
||||
// as being installed
|
||||
$sModuleVersion = '0.0.0';
|
||||
}
|
||||
|
||||
if ($aInstall['parent_id'] == 0) {
|
||||
$sModuleName = ROOT_MODULE;
|
||||
} elseif ($aInstall['parent_id'] != $iRootId) {
|
||||
// Skip all modules belonging to previous installations
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($sModuleName, $aInstallByModule)) {
|
||||
if ($iInstalled < $aInstallByModule[$sModuleName]['installed']) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($aInstall['parent_id'] == 0) {
|
||||
$aRes[$sModuleName]['version_db'] = $sModuleVersion;
|
||||
$aRes[$sModuleName]['name_db'] = $aInstall['name'];
|
||||
}
|
||||
|
||||
$aInstallByModule[$sModuleName]['installed'] = $iInstalled;
|
||||
$aInstallByModule[$sModuleName]['version'] = $sModuleVersion;
|
||||
}
|
||||
|
||||
// Adjust the list of proposed modules
|
||||
//
|
||||
foreach ($aInstallByModule as $sModuleName => $aModuleDB) {
|
||||
if ($sModuleName == ROOT_MODULE) {
|
||||
continue;
|
||||
} // Skip the main module
|
||||
|
||||
if (!array_key_exists($sModuleName, $aRes)) {
|
||||
// A module was installed, it is not proposed in the new build... skip
|
||||
continue;
|
||||
}
|
||||
$aRes[$sModuleName]['version_db'] = $aModuleDB['version'];
|
||||
|
||||
if ($aRes[$sModuleName]['install']['flag'] == MODULE_ACTION_MANDATORY) {
|
||||
$aRes[$sModuleName]['uninstall'] = [
|
||||
'flag' => MODULE_ACTION_IMPOSSIBLE,
|
||||
'message' => 'the module is part of the application',
|
||||
];
|
||||
} else {
|
||||
$aRes[$sModuleName]['uninstall'] = [
|
||||
'flag' => MODULE_ACTION_OPTIONAL,
|
||||
'message' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,7 +344,6 @@ class RunTimeEnvironment
|
||||
*/
|
||||
protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir)
|
||||
{
|
||||
\SetupLog::Info(__METHOD__);
|
||||
$sSourceDirFull = APPROOT.$sSourceDir;
|
||||
if (!is_dir($sSourceDirFull)) {
|
||||
throw new Exception("The source directory '$sSourceDirFull' does not exist (or could not be read)");
|
||||
@@ -248,29 +360,30 @@ class RunTimeEnvironment
|
||||
$aExtraDirs = $this->GetExtraDirsToScan($aDirsToCompile);
|
||||
$aDirsToCompile = array_merge($aDirsToCompile, $aExtraDirs);
|
||||
|
||||
$aRet = [];
|
||||
|
||||
// Determine the installed modules and extensions
|
||||
//
|
||||
$oSourceConfig = new Config(APPCONF.$sSourceEnv.'/'.ITOP_CONFIG_FILE);
|
||||
$aAvailableModules = $this->AnalyzeInstallation($oSourceConfig, $aDirsToCompile);
|
||||
$oSourceEnv = new RunTimeEnvironment($sSourceEnv);
|
||||
$aAvailableModules = $oSourceEnv->AnalyzeInstallation($oSourceConfig, $aDirsToCompile);
|
||||
|
||||
// Actually read the modules available for the target environment,
|
||||
// but get the selection from the source environment and finally
|
||||
// mark as (automatically) chosen all the "remote" modules present in the
|
||||
// mark as (automatically) chosen alll the "remote" modules present in the
|
||||
// target environment (data/<target-env>-modules)
|
||||
// The actual choices will be recorded by RecordInstallation below
|
||||
$this->InitExtensionMap($aExtraDirs, $oSourceConfig);
|
||||
$this->GetExtensionMap()->LoadChoicesFromDatabase($oSourceConfig);
|
||||
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
|
||||
$this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv, $aExtraDirs);
|
||||
$this->oExtensionsMap->LoadChoicesFromDatabase($oSourceConfig);
|
||||
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
if ($this->IsExtensionSelected($oExtension)) {
|
||||
$this->GetExtensionMap()->MarkAsChosen($oExtension->sCode);
|
||||
$this->oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Do load the required modules
|
||||
//
|
||||
$oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries');
|
||||
|
||||
$aRet = [];
|
||||
$aRet[$oDictModule->GetName()] = $oDictModule;
|
||||
|
||||
$oFactory = new ModelFactory($aDirsToCompile);
|
||||
@@ -288,9 +401,10 @@ class RunTimeEnvironment
|
||||
$aModules = $oFactory->FindModules();
|
||||
foreach ($aModules as $oModule) {
|
||||
$sModule = $oModule->GetName();
|
||||
$bIsExtra = $this->GetExtensionMap()->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE);
|
||||
$sModuleRootDir = $oModule->GetRootDir();
|
||||
$bIsExtra = $this->oExtensionsMap->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE);
|
||||
if (array_key_exists($sModule, $aAvailableModules)) {
|
||||
if (($aAvailableModules[$sModule]['installed_version'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) { //Extra modules are always unless they are 'AutoSelect'
|
||||
if (($aAvailableModules[$sModule]['version_db'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) { //Extra modules are always unless they are 'AutoSelect'
|
||||
$aRet[$oModule->GetName()] = $oModule;
|
||||
}
|
||||
}
|
||||
@@ -534,7 +648,7 @@ class RunTimeEnvironment
|
||||
$oInstallRec->Set('comment', json_encode($aData));
|
||||
$oInstallRec->Set('parent_id', 0); // root module
|
||||
$oInstallRec->Set('installed', $iInstallationTime);
|
||||
$oInstallRec->DBInsertNoReload();
|
||||
$iMainItopRecord = $oInstallRec->DBInsertNoReload();
|
||||
|
||||
// Record main installation
|
||||
$oInstallRec = new ModuleInstallation();
|
||||
@@ -547,6 +661,7 @@ class RunTimeEnvironment
|
||||
|
||||
// Record installed modules and extensions
|
||||
//
|
||||
$aAvailableExtensions = [];
|
||||
$aAvailableModules = $this->AnalyzeInstallation($oConfig, $this->GetBuildDir());
|
||||
foreach ($aSelectedModuleCodes as $sModuleId) {
|
||||
if (!array_key_exists($sModuleId, $aAvailableModules)) {
|
||||
@@ -554,7 +669,7 @@ class RunTimeEnvironment
|
||||
}
|
||||
$aModuleData = $aAvailableModules[$sModuleId];
|
||||
$sName = $sModuleId;
|
||||
$sVersion = $aModuleData['available_version'];
|
||||
$sVersion = $aModuleData['version_code'];
|
||||
$sUninstallable = $aModuleData['uninstallable'] ?? 'yes';
|
||||
$aComments = [];
|
||||
$aComments[] = $sShortComment;
|
||||
@@ -587,17 +702,16 @@ class RunTimeEnvironment
|
||||
$oInstallRec->DBInsertNoReload();
|
||||
}
|
||||
|
||||
if ($this->GetExtensionMap()) {
|
||||
if ($this->oExtensionsMap) {
|
||||
// Mark as chosen the selected extensions code passed to us
|
||||
|
||||
// Note: some other extensions may already be marked as chosen
|
||||
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
|
||||
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
if (in_array($oExtension->sCode, $aSelectedExtensionCodes)) {
|
||||
$this->GetExtensionMap()->MarkAsChosen($oExtension->sCode);
|
||||
$this->oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->GetExtensionMap()->GetChoices() as $oExtension) {
|
||||
foreach ($this->oExtensionsMap->GetChoices() as $oExtension) {
|
||||
$oInstallRec = new ExtensionInstallation();
|
||||
$oInstallRec->Set('code', $oExtension->sCode);
|
||||
$oInstallRec->Set('label', $oExtension->sLabel);
|
||||
@@ -625,7 +739,9 @@ class RunTimeEnvironment
|
||||
public function GetApplicationVersion(Config $oConfig)
|
||||
{
|
||||
try {
|
||||
$aSelectInstall = ModuleInstallationService::GetInstance()->ReadFromDB($oConfig);
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
$sSQLQuery = "SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install";
|
||||
$aSelectInstall = CMDBSource::QueryToArray($sSQLQuery);
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
$this->log_error('Can not connect to the database: host: '.$oConfig->Get('db_host').', user:'.$oConfig->Get('db_user').', pwd:'.$oConfig->Get('db_pwd').', db name:'.$oConfig->Get('db_name'));
|
||||
@@ -859,7 +975,7 @@ class RunTimeEnvironment
|
||||
{
|
||||
foreach ($aAvailableModules as $sModuleId => $aModule) {
|
||||
if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules)) {
|
||||
$aArgs = [MetaModel::GetConfig(), $aModule['installed_version'], $aModule['available_version']];
|
||||
$aArgs = [MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code']];
|
||||
RunTimeEnvironment::CallInstallerHandler($aAvailableModules[$sModuleId], $sHandlerName, $aArgs);
|
||||
}
|
||||
}
|
||||
@@ -923,7 +1039,7 @@ class RunTimeEnvironment
|
||||
$sRelativePath = 'env-'.$this->sTargetEnv.'/'.basename($aModule['root_dir']);
|
||||
// Load data only for selected AND newly installed modules
|
||||
if (in_array($sModuleId, $aSelectedModules)) {
|
||||
if ($aModule['installed_version'] != '') {
|
||||
if ($aModule['version_db'] != '') {
|
||||
// Simulate the load of the previously loaded XML files to get the mapping of the keys
|
||||
if ($bSampleData) {
|
||||
$aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
|
||||
@@ -1555,8 +1555,17 @@ JS
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public static function GetConfig($oWizard)
|
||||
/**
|
||||
* @param \WizardController $oWizard
|
||||
* @param bool $bAbortOnMissingDependency ...
|
||||
* @param array $aModulesToLoad List of modules to search for, defaults to all if ommitted
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
|
||||
{
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
$oConfig = new Config();
|
||||
$sSourceDir = $oWizard->GetParameter('source_dir', '');
|
||||
|
||||
@@ -1571,25 +1580,7 @@ JS
|
||||
$aParamValues = $oWizard->GetParamForConfigArray();
|
||||
$aParamValues['source_dir'] = $sRelativeSourceDir;
|
||||
$oConfig->UpdateFromParams($aParamValues, null);
|
||||
|
||||
return $oConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WizardController $oWizard
|
||||
* @param bool $bAbortOnMissingDependency ...
|
||||
* @param array $aModulesToLoad List of modules to search for, defaults to all if ommitted
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
|
||||
{
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
|
||||
$oConfig = self::GetConfig($oWizard);
|
||||
|
||||
$aDirsToScan = [$oWizard->GetParameter('source_dir', '')];
|
||||
$aDirsToScan = [$sSourceDir];
|
||||
|
||||
if (is_dir(APPROOT.'extensions')) {
|
||||
$aDirsToScan[] = APPROOT.'extensions';
|
||||
|
||||
@@ -50,7 +50,6 @@ require_once(APPROOT.'setup/applicationinstaller.class.inc.php');
|
||||
require_once(APPROOT.'setup/parameters.class.inc.php');
|
||||
require_once(APPROOT.'core/mutex.class.inc.php');
|
||||
require_once(APPROOT.'setup/extensionsmap.class.inc.php');
|
||||
require_once APPROOT.'setup/feature_removal/SetupAudit.php';
|
||||
|
||||
/**
|
||||
* First step of the iTop Installation Wizard: Welcome screen, requirements
|
||||
@@ -1368,52 +1367,6 @@ class WizStepModulesChoice extends WizardStep
|
||||
return ['WizStepModulesChoice', 'WizStepSummary'];
|
||||
}
|
||||
|
||||
public function GetAddedAndRemovedExtensions($aSelectedExtensions)
|
||||
{
|
||||
$aExtensionsAdded = [];
|
||||
$aExtensionsRemoved = [];
|
||||
$aExtensionsNotUninstallable = [];
|
||||
foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) {
|
||||
/* @var \iTopExtension $oExtension */
|
||||
$bSelected = in_array($oExtension->sCode, $aSelectedExtensions);
|
||||
if ($oExtension->bInstalled && !$bSelected) {
|
||||
$aExtensionsRemoved[$oExtension->sCode] = $oExtension->sLabel;
|
||||
if (!$oExtension->CanBeUninstalled()) {
|
||||
$aExtensionsNotUninstallable[$oExtension->sCode] = true;
|
||||
}
|
||||
} elseif (!$oExtension->bInstalled && $bSelected) {
|
||||
$aExtensionsAdded[$oExtension->sCode] = $oExtension->sLabel;
|
||||
}
|
||||
}
|
||||
|
||||
$sExtensionsAdded = '';
|
||||
if (count($aExtensionsAdded) > 0) {
|
||||
$sExtensionsAdded = '<ul>';
|
||||
foreach ($aExtensionsAdded as $sExtensionCode) {
|
||||
$sExtensionsAdded .= '<li>'.$sExtensionCode.'</li>';
|
||||
}
|
||||
$sExtensionsAdded .= '</ul>';
|
||||
} else {
|
||||
$sExtensionsAdded = '<ul><li>No extension added.</li></ul>';
|
||||
}
|
||||
|
||||
$sExtensionsRemoved = '';
|
||||
if (count($aExtensionsRemoved) > 0) {
|
||||
$sExtensionsRemoved = '<ul>';
|
||||
foreach ($aExtensionsRemoved as $sCode => $sExtensionCode) {
|
||||
$sForcedUninstall = '';
|
||||
if (isset($aExtensionsNotUninstallable[$sCode])) {
|
||||
$sForcedUninstall = ' (forced uninstallation)';
|
||||
}
|
||||
$sExtensionsRemoved .= '<li>'.$sExtensionCode.$sForcedUninstall.'</li>';
|
||||
}
|
||||
$sExtensionsRemoved .= '</ul>';
|
||||
} else {
|
||||
$sExtensionsRemoved = '<ul><li>No extension removed.</li></ul>';
|
||||
}
|
||||
return [$sExtensionsAdded, $sExtensionsRemoved];
|
||||
}
|
||||
|
||||
public function ProcessParams($bMoveForward = true)
|
||||
{
|
||||
// Accumulates the selected modules:
|
||||
@@ -1443,14 +1396,9 @@ class WizStepModulesChoice extends WizardStep
|
||||
if (class_exists('CreateITILProfilesInstaller')) {
|
||||
$this->oWizard->SetParameter('old_addon', true);
|
||||
}
|
||||
|
||||
[$sExtensionsAdded, $sExtensionsRemoved] = $this->GetAddedAndRemovedExtensions($aExtensions);
|
||||
|
||||
$this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules)));
|
||||
$this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions));
|
||||
$this->oWizard->SetParameter('display_choices', $sDisplayChoices);
|
||||
$this->oWizard->SetParameter('extensions_added', $sExtensionsAdded);
|
||||
$this->oWizard->SetParameter('extensions_removed', $sExtensionsRemoved);
|
||||
return ['class' => 'WizStepSummary', 'state' => ''];
|
||||
}
|
||||
|
||||
@@ -1613,7 +1561,7 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
$aAlternatives = $aInfo['alternatives'] ?? [];
|
||||
$aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : [];
|
||||
$sChoiceName = null;
|
||||
foreach ($aAlternatives as $index => $aChoice) {
|
||||
$sChoiceId = $sParentId.self::$SEP.$index;
|
||||
@@ -1657,7 +1605,7 @@ EOF
|
||||
if ($this->bUpgrade) {
|
||||
// In upgrade mode, the defaults are the installed modules
|
||||
foreach ($aChoice['modules'] as $sModuleId) {
|
||||
if ($aModules[$sModuleId]['installed_version'] != '') {
|
||||
if ($aModules[$sModuleId]['version_db'] != '') {
|
||||
// A module corresponding to this choice is installed
|
||||
$aScores[$sChoiceId][$sModuleId] = true;
|
||||
}
|
||||
@@ -1715,7 +1663,7 @@ EOF
|
||||
}
|
||||
if (array_key_exists('modules', $aChoice)) {
|
||||
foreach ($aChoice['modules'] as $sModuleId) {
|
||||
if ($aModules[$sModuleId]['installed_version'] != '') {
|
||||
if ($aModules[$sModuleId]['version_db'] != '') {
|
||||
// A module corresponding to this choice is installed, increase the score of this choice
|
||||
if (!isset($aScores[$sChoiceId])) {
|
||||
$aScores[$sChoiceId] = [];
|
||||
@@ -2004,47 +1952,10 @@ EOF
|
||||
return '<i class="setup-extension--icon '.$sDecorationClass.'" data-tooltip-content="'.$sResult.'"></i>';
|
||||
}
|
||||
|
||||
public function ComputeChoiceFlags(array $aChoice, string $sChoiceId, array $aSelectedComponents, bool $bAllDisabled, bool $bDisableUninstallCheck, bool $bUpgradeMode)
|
||||
{
|
||||
$oITopExtension = $this->oExtensionsMap->GetFromExtensionCode($aChoice['extension_code']);
|
||||
$bCanBeUninstalled = isset($aChoice['uninstallable']) ? $aChoice['uninstallable'] === true || $aChoice['uninstallable'] === 'yes' : $oITopExtension->CanBeUninstalled();
|
||||
$bSelected = isset($aSelectedComponents[$sChoiceId]) && ($aSelectedComponents[$sChoiceId] == $sChoiceId);
|
||||
$bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || $bUpgradeMode && $oITopExtension->bInstalled && !$bCanBeUninstalled && !$bDisableUninstallCheck;
|
||||
|
||||
$bMissingFromDisk = isset($aChoice['missing']) && $aChoice['missing'] === true;
|
||||
$bInstalled = $bMissingFromDisk || $oITopExtension->bInstalled;
|
||||
$bDisabled = $bMandatory || $bAllDisabled || $bMissingFromDisk;
|
||||
$bChecked = $bMandatory || $bSelected;
|
||||
|
||||
if (isset($aChoice['sub_options'])) {
|
||||
$aOptions = $aChoice['sub_options']['options'] ?? [];
|
||||
foreach ($aOptions as $index => $aSubChoice) {
|
||||
$sSubChoiceId = $sChoiceId.self::$SEP.$index;
|
||||
$aSubFlags = $this->ComputeChoiceFlags($aSubChoice, $sSubChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $bUpgradeMode);
|
||||
if ($aSubFlags['checked']) {
|
||||
$bChecked = true;
|
||||
if ($aSubFlags['disabled']) {
|
||||
//If some sub options are enabled and cannot be disabled, this choice should also cannot be disabled since it would disable all its sub options
|
||||
$bDisabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'uninstallable' => $bCanBeUninstalled,
|
||||
'missing' => $bMissingFromDisk,
|
||||
'installed' => $bInstalled,
|
||||
'disabled' => $bDisabled,
|
||||
'checked' => $bChecked,
|
||||
];
|
||||
}
|
||||
|
||||
protected function DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults, $sParentId = '', $bAllDisabled = false)
|
||||
{
|
||||
$aOptions = $aStepInfo['options'] ?? [];
|
||||
$aAlternatives = $aStepInfo['alternatives'] ?? [];
|
||||
$aOptions = isset($aStepInfo['options']) ? $aStepInfo['options'] : [];
|
||||
$aAlternatives = isset($aStepInfo['alternatives']) ? $aStepInfo['alternatives'] : [];
|
||||
|
||||
$bDisableUninstallCheck = (bool)$this->oWizard->GetParameter('force-uninstall', false);
|
||||
|
||||
@@ -2052,33 +1963,43 @@ EOF
|
||||
$sChoiceId = $sParentId.self::$SEP.$index;
|
||||
$sDataId = 'data-id="'.utils::EscapeHtml($aChoice['extension_code']).'"';
|
||||
$sId = utils::EscapeHtml($aChoice['extension_code']);
|
||||
$aFlags = static::ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $this->bUpgrade);
|
||||
$bIsDefault = array_key_exists($sChoiceId, $aDefaults);
|
||||
|
||||
$oITopExtension = $this->oExtensionsMap->GetFromExtensionCode($aChoice['extension_code']);
|
||||
$bCanBeUninstalled = isset($aChoice['uninstallable']) ? $aChoice['uninstallable'] : $oITopExtension->CanBeUninstalled();
|
||||
$bSelected = isset($aSelectedComponents[$sChoiceId]) && ($aSelectedComponents[$sChoiceId] == $sChoiceId);
|
||||
$bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || $this->bUpgrade && $bIsDefault && !$bCanBeUninstalled && !$bDisableUninstallCheck;
|
||||
;
|
||||
$bMissingFromDisk = isset($aChoice['missing']) && $aChoice['missing'] === true;
|
||||
$bInstalled = $bMissingFromDisk || $oITopExtension->bInstalled;
|
||||
$bDisabled = $bMandatory || $bAllDisabled || $bMissingFromDisk;
|
||||
$bChecked = $bMandatory || $bSelected;
|
||||
|
||||
$sTooltip = '';
|
||||
$sUnremovable = '';
|
||||
if ($aFlags['missing']) {
|
||||
if ($bMissingFromDisk) {
|
||||
$sTooltip .= '<span class="setup-extension-tag removed">source removed</span>';
|
||||
}
|
||||
if ($aFlags['installed']) {
|
||||
if ($bInstalled) {
|
||||
$sTooltip .= '<span class="setup-extension-tag checked installed">installed</span>';
|
||||
$sTooltip .= '<span class="setup-extension-tag unchecked tobeuninstalled">to be uninstalled</span>';
|
||||
} else {
|
||||
$sTooltip .= '<span class="setup-extension-tag checked tobeinstalled">to be installed</span>';
|
||||
$sTooltip .= '<span class="setup-extension-tag unchecked notinstalled">not installed</span>';
|
||||
}
|
||||
if (!$aFlags['uninstallable']) {
|
||||
if (!$bCanBeUninstalled) {
|
||||
$sTooltip .= '<span class="setup-extension-tag notuninstallable">cannot be uninstalled</span>';
|
||||
}
|
||||
if ($aFlags['disabled'] && !$aFlags['checked'] && !$aFlags['uninstallable'] && !$bDisableUninstallCheck) {
|
||||
if ($bDisabled && !$bChecked && !$bCanBeUninstalled && !$bDisableUninstallCheck) {
|
||||
$this->bCanMoveForward = false;//Disable "Next"
|
||||
}
|
||||
$sChecked = $aFlags['checked'] ? ' checked ' : '';
|
||||
$sDisabled = $aFlags['disabled'] ? ' disabled data-disabled="disabled" ' : '';
|
||||
$sMissingModule = $aFlags['missing'] ? 'setup-extension--missing' : '';
|
||||
$sChecked = $bChecked ? ' checked ' : '';
|
||||
$sDisabled = $bDisabled ? ' disabled data-disabled="disabled" ' : '';
|
||||
$sMissingModule = $bMissingFromDisk ? 'setup-extension--missing' : '';
|
||||
|
||||
$sHiddenInput = $aFlags['disabled'] && $aFlags['checked'] ? '<input type="hidden" name="choice['.$sChoiceId.']" value="'.$sChoiceId.'"/>' : '';
|
||||
$sHiddenInput = $bDisabled && $bChecked ? '<input type="hidden" name="choice['.$sChoiceId.']" value="'.$sChoiceId.'"/>' : '';
|
||||
$oPage->add('<div class="choice '.$sMissingModule.'" '.$sDataId.'><input class="wiz-choice '.$sUnremovable.'" id="'.$sId.'" name="choice['.$sChoiceId.']" type="checkbox" value="'.$sChoiceId.'" '.$sDisabled.$sChecked.'/>'.$sHiddenInput.' ');
|
||||
$this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $aFlags['disabled'], $sTooltip);
|
||||
$this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled, $sTooltip);
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
$sChoiceName = null;
|
||||
@@ -2113,6 +2034,7 @@ EOF
|
||||
$sChoiceId = $sParentId.self::$SEP.$index;
|
||||
$sDataId = 'data-id="'.utils::EscapeHtml($aChoice['extension_code']).'"';
|
||||
$sId = utils::EscapeHtml($aChoice['extension_code']);
|
||||
|
||||
if ($sChoiceName == null) {
|
||||
$sChoiceName = $sChoiceId; // All radios share the same name
|
||||
}
|
||||
@@ -2192,18 +2114,6 @@ class WizStepSummary extends WizardStep
|
||||
$this->bDependencyCheck = true;
|
||||
try {
|
||||
SetupUtils::AnalyzeInstallation($this->oWizard, true, $aSelectedModules);
|
||||
|
||||
/*$sInstallMode = utils::ReadParam('install_mode');
|
||||
\SetupLog::Info(__METHOD__, null, ['$sInstallMode' => $sInstallMode]);
|
||||
//if ($sInstallMode === "upgrade") {
|
||||
$aExtensions = json_decode($this->oWizard->GetParameter('selected_extensions'), true);
|
||||
$oSetupAudit = new SetupAudit([]);
|
||||
|
||||
$oConfig = SetupUtils::GetConfig($this->oWizard);
|
||||
$oSetupAudit->SetSelectedExtensions($oConfig, $aExtensions);
|
||||
//$oSetupAudit->AuditExtensionsCleanupRules(true);
|
||||
//}
|
||||
*/
|
||||
} catch (MissingDependencyException $e) {
|
||||
$this->bDependencyCheck = false;
|
||||
$this->sDependencyIssue = $e->getHtmlDesc();
|
||||
@@ -2268,14 +2178,6 @@ class WizStepSummary extends WizardStep
|
||||
|
||||
$oPage->add('<fieldset id="summary"><legend>Installation Parameters</legend>');
|
||||
$oPage->add('<div id="params_summary">');
|
||||
|
||||
$oPage->add('<div class="closed"><span class="title ibo-setup-summary-title">Extensions to be installed</span>');
|
||||
$oPage->add($this->oWizard->GetParameter('extensions_added'));
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div class="closed"><span class="title ibo-setup-summary-title">Extensions to be uninstalled</span>');
|
||||
$oPage->add($this->oWizard->GetParameter('extensions_removed'));
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('<div class="closed"><span class="title ibo-setup-summary-title">Database Parameters</span><ul>');
|
||||
$oPage->add('<li>Server Name: '.$aInstallParams['database']['server'].'</li>');
|
||||
$oPage->add('<li>DB User Name: '.$aInstallParams['database']['user'].'</li>');
|
||||
|
||||
@@ -1019,10 +1019,10 @@ EOF
|
||||
if ($sModuleId == '_Root_') {
|
||||
continue;
|
||||
}
|
||||
if ($aModuleData['installed_version'] == '') {
|
||||
if ($aModuleData['version_db'] == '') {
|
||||
continue;
|
||||
}
|
||||
$oPage->add('InstalledModule/'.$sModuleId.': '.$aModuleData['installed_version']."\n");
|
||||
$oPage->add('InstalledModule/'.$sModuleId.': '.$aModuleData['version_db']."\n");
|
||||
}
|
||||
|
||||
$oPage->add('===== end =====');
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
# PHP static analysis
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Usages](#usages)
|
||||
- [Analysing a package](#analysing-a-package)
|
||||
- [Analysing a module](#analysing-a-module)
|
||||
- [Configuration](#configuration)
|
||||
- [Adjust local configuration to your needs](#adjust-local-configuration-to-your-needs)
|
||||
- [Adjust configuration for a particular CI repository / job](#adjust-configuration-for-a-particular-ci-repository--job)
|
||||
|
||||
## Installation
|
||||
- Install dependencies by running `composer install` in this folder
|
||||
- You should be all set! 🚀
|
||||
|
||||
## Usages
|
||||
### Analysing a package
|
||||
_Do this if you want to analyse the whole iTop package (iTop core, extensions, third-party libs, ...)_
|
||||
|
||||
- Make sure you ran a setup on your iTop as it will analyse the `env-production` folder
|
||||
- Open a prompt in your iTop folder
|
||||
- Run the following command
|
||||
```bash
|
||||
tests/php-static-analysis/vendor/bin/phpstan analyse \
|
||||
--configuration ./tests/php-static-analysis/config/for-package.dist.neon \
|
||||
--error-format raw
|
||||
```
|
||||
|
||||
You will then have an output like this listing all errors:
|
||||
```bash
|
||||
tests/php-static-analysis/vendor/bin/phpstan analyse \
|
||||
--configuration ./tests/php-static-analysis/config/for-package.dist.neon \
|
||||
--error-format raw
|
||||
|
||||
1049/1049 [============================] 100%
|
||||
|
||||
<ITOP>\addons\userrights\userrightsprofile.class.inc.php:552:Call to static method InitSharedClassProperties() on an unknown class SharedObject.
|
||||
<ITOP>\addons\userrights\userrightsprofile.db.class.inc.php:927:Call to static method GetSharedClassProperties() on an unknown class SharedObject.
|
||||
<ITOP>\addons\userrights\userrightsprojection.class.inc.php:722:Access to an undefined property UserRightsProjection::$m_aClassProjs.
|
||||
<ITOP>\application\applicationextension.inc.php:295:Method AbstractPreferencesExtension::ApplyPreferences() should return bool but return statement is missing.
|
||||
<ITOP>\application\cmdbabstract.class.inc.php:1010:Class utils referenced with incorrect case: Utils.
|
||||
[...]
|
||||
```
|
||||
|
||||
### Analysing a module
|
||||
_Do this if you only want to analyse one or more modules within this iTop but not the whole package_
|
||||
|
||||
- Make sure you ran a setup on your iTop as it will analyse the `env-production` folder
|
||||
- Open a prompt in your iTop folder
|
||||
- Run the following command
|
||||
```
|
||||
tests/php-static-analysis/vendor/bin/phpstan analyse \
|
||||
--configuration ./tests/php-static-analysis/config/for-module.dist.neon \
|
||||
--error-format raw \
|
||||
env-production/<MODULE_CODE_1> [env-production/<MODULE_CODE_2> ...]
|
||||
```
|
||||
|
||||
You will then have an output like this listing all errors:
|
||||
```
|
||||
tests/php-static-analysis/vendor/bin/phpstan analyse \
|
||||
--configuration ./tests/php-static-analysis/config/for-module.dist.neon \
|
||||
--error-format raw \
|
||||
env-production/authent-ldap env-production/itop-oauth-client
|
||||
|
||||
49/49 [============================] 100%
|
||||
|
||||
<ITOP>\env-production\authent-ldap\model.authent-ldap.php:79:Undefined variable: $hDS
|
||||
<ITOP>\env-production\authent-ldap\model.authent-ldap.php:80:Undefined variable: $name
|
||||
<ITOP>\env-production\authent-ldap\model.authent-ldap.php:80:Undefined variable: $value
|
||||
<ITOP>\env-production\itop-oauth-client\vendor\composer\InstalledVersions.php:105:Parameter $parser of method Composer\InstalledVersions::satisfies() has invalid type Composer\Semver\VersionParser.
|
||||
[...]
|
||||
```
|
||||
|
||||
## Configuration
|
||||
### Adjust local configuration to your needs
|
||||
#### Define which PHP version to run the analysis for
|
||||
The way we configured PHPStan in this project changes how it will find the PHP version to run the analysis for. \
|
||||
By default PHPStan check the information from the composer.json file, but we changed that (via the `config/php-includes/set-php-version-from-process.php` include) so it used the PHP
|
||||
version currently ran by the CLI.
|
||||
|
||||
So all you have to do is either:
|
||||
- Prepend your command line with the path of the executable of the desired PHP version
|
||||
- Change the default PHP interpreter in your IDE settings
|
||||
|
||||
#### Change some parameters for a local run
|
||||
If you want to change some particular settings (eg. the memory limit, the rules level, ...) for a local run of the analysis you have 2 choices.
|
||||
|
||||
##### Method 1: CLI parameter
|
||||
For most parameters there is a good chance you can just add the parameter and its value in your command, which will override the one defined in the configuration file. \
|
||||
Below are some example, but your can find the complete reference [here](https://phpstan.org/user-guide/command-line-usage).
|
||||
|
||||
```bash
|
||||
--memory-limit 1G
|
||||
--level 5
|
||||
--error-format raw
|
||||
[...]
|
||||
```
|
||||
|
||||
**Pros** Quick and easy to try different parameters \
|
||||
**Cons** Parameters aren't saved, so you'll have to remember them and put them again next time
|
||||
|
||||
##### Method 2: Configuration file
|
||||
Crafting your own configuration file gives you the ability to fine tune any parameters, it's way more powerful but can also quickly lead to crashes if you mess with the symbols discovery (classes, ...). \
|
||||
But mostly it can be saved, shared, re-used; which is it's main purpose.
|
||||
|
||||
It is recommended that you create your configuration file from scratch and that you include the `base.dist.neon` so you are bootstrapped for the symbols discovery. Then you can override any parameter. \
|
||||
Check [the documentation](https://phpstan.org/config-reference#multiple-files) for more information.
|
||||
|
||||
```neon
|
||||
includes:
|
||||
- base.dist.neon
|
||||
|
||||
parameters:
|
||||
# Override parameters here
|
||||
```
|
||||
|
||||
#### Analyse only one (or some) folder(s) quicker
|
||||
It's pretty easy and good news you don't need to create a new configuration file or change an existing one. \
|
||||
Just adapt and use command lines from the [usages section](#usages) and add the folders you want to analyse at the end of the command, exactly like when analysing modules.
|
||||
|
||||
For example if you want to analyse just `<ITOP>/setup` and `<ITOP>/sources`, use something like:
|
||||
```
|
||||
tests/php-static-analysis/vendor/bin/phpstan analyse \
|
||||
--configuration ./tests/php-static-analysis/config/for-package.dist.neon \
|
||||
--error-format raw \
|
||||
setup sources
|
||||
```
|
||||
|
||||
### Adjust configuration for a particular CI repository / job
|
||||
TODO
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"require": {
|
||||
"phpstan/phpstan": "^2.1"
|
||||
}
|
||||
}
|
||||
72
tests/php-static-analysis/composer.lock
generated
72
tests/php-static-analysis/composer.lock
generated
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "cc6d7580a5e98236d68d8b91de9ddebb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.33",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f",
|
||||
"reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan-shim": "*"
|
||||
},
|
||||
"bin": [
|
||||
"phpstan",
|
||||
"phpstan.phar"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"keywords": [
|
||||
"dev",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://phpstan.org/user-guide/getting-started",
|
||||
"forum": "https://github.com/phpstan/phpstan/discussions",
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"security": "https://github.com/phpstan/phpstan/security/policy",
|
||||
"source": "https://github.com/phpstan/phpstan-src"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ondrejmirtes",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-05T10:24:31+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
## Disclaimer
|
||||
DON'T modify the following files without knowledge and discussing with the team:
|
||||
- base.dist.neon
|
||||
- for-package.dist.neon
|
||||
- for-module.dist.neon
|
||||
|
||||
## Purpose of these files
|
||||
### base.dist.neon
|
||||
This configuration file contains the common parameters for all analysis, whereas it is a package, a module or something specific. Among others:
|
||||
- Rules level for analysis
|
||||
- PHP version to compare
|
||||
- Necessary files for autoloaders discovery and such
|
||||
- ...
|
||||
|
||||
This file should not be modified for your specific needs, you should always include it and override the desired parameters. \
|
||||
See how it is done in `for-package.dist.neon` and `for-module.dist.neon` or on the documentation [here](https://phpstan.org/config-reference#multiple-files).
|
||||
|
||||
### for-package.dist.neon
|
||||
This configuration file contains the parameters to analyse a package (iTop core, modules, third-party libs).
|
||||
|
||||
### for-module.dist.neon
|
||||
This configuration file contains the parameters to analyse one or more modules only.
|
||||
|
||||
## How / when can I modify these files?
|
||||
**You CAN'T!** \
|
||||
Well, unless there is a good reason and you talked about it with the team. But you should never modify them for a specific need on your local environment.
|
||||
|
||||
- If you have a particular need for your local environment (eg. increase memory limit, change rules levels, analyse only a specific folder), check the [Configuration section](../#configuration) of the main README.md.
|
||||
- If you feel like there is need for an adjustment in the default configurations, discuss it with th team and make a PR.
|
||||
@@ -1,40 +0,0 @@
|
||||
includes:
|
||||
- php-includes/set-php-version-from-process.php # Workaround to set PHP version to the on running the CLI
|
||||
# for an explanation of the baseline concept, see: https://phpstan.org/user-guide/baseline
|
||||
#baseline HERE DO NOT REMOVE FOR CI
|
||||
|
||||
parameters:
|
||||
level: 0
|
||||
#phpVersion: null # Explicitly commented as we rather use the detected version from the above include (`php-includes/target-php-version.php`)
|
||||
editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' # Open in PHPStorm as it's Combodo's default IDE
|
||||
bootstrapFiles:
|
||||
- ../../../approot.inc.php
|
||||
- ../../../bootstrap.inc.php
|
||||
|
||||
scanFiles:
|
||||
# Files necessary as they contain some declarations (constants, classes, functions, ...)
|
||||
- ../../../approot.inc.php
|
||||
- ../../../bootstrap.inc.php
|
||||
excludePaths:
|
||||
analyse:
|
||||
# For third-party libs we should analyse them in a dedicated configuration as we can't improve / clean them which would
|
||||
# prevent us from raising the rules level as we improve / clean our codebase
|
||||
- ../../../lib # Irrelevant as we only want to analyze our codebase
|
||||
- ../../../node_modules # Irrelevant as we only want to analyze our codebase
|
||||
analyseAndScan:
|
||||
# This file generates "unignorable errors" for the baseline due to its format, so we don't have any other choice than to exclude it.
|
||||
# But mind that it will prevent PHPStan from warning us about PHP syntax errors in this file.
|
||||
- ../../../core/oql/build/PHP/Lempar.php
|
||||
|
||||
#- ../../../data # Left and commented on purpose to show that we want to analyse the generated cache files
|
||||
|
||||
# Note 1: We can't analyse these folders as if a PHP file requires another PHP element declared in an XML file, it won't find it. So we rely only on `env-production`
|
||||
# Note 2: Only the options selected during the setup will be analysed correctly in `env-production`. For unselected options, we still want to ignore them during the analysis as they would only give a false sentiment of security as their XML PHP classes / snippets / etc would not be tested.
|
||||
- ../../../data/production-modules (?) # Irrelevent as it will already be in `env-production` (for local run only, not useful in the CI)
|
||||
- ../../../datamodels # Irrelevent as it will already be in `env-production`
|
||||
- ../../../extensions # Irrelevent as it will already be in `env-production` (for local run only, not useful in the CI)
|
||||
- ../../../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 (?) # Exlclude toolkit for now
|
||||
@@ -1,15 +0,0 @@
|
||||
includes:
|
||||
- base.dist.neon
|
||||
|
||||
parameters:
|
||||
paths:
|
||||
# We just want to analyse the module folder(s), either:
|
||||
# - Create your own `for-module.neon` file, include this one and override this parameter (see https://phpstan.org/config-reference#multiple-files)
|
||||
# - Pass the module folder(s) in the commande line (see https://phpstan.org/config-reference#analysed-files)
|
||||
scanDirectories:
|
||||
# Unlike for `for-package.dist.neon`, here we need to scan all the folders to discover symbols, but we only want to analyse the module folder.
|
||||
# We initially thought of doing it through the `excludePaths` param. by excluding everything but the module folder, but it doesn't seem to be possible, because it uses the `fnmatch()` function.
|
||||
# As a workaround, we list here all the folders to scan.
|
||||
#
|
||||
# Scan the whole project and rely on the `excludePaths` param. to filter the unnecessary
|
||||
- ../../..
|
||||
@@ -1,7 +0,0 @@
|
||||
includes:
|
||||
- base.dist.neon
|
||||
|
||||
parameters:
|
||||
paths:
|
||||
# We want to analyse almost the whole project, so we do a negative selection between the `paths` and `excludePaths` (see base.dist.neon) parameters
|
||||
- ../../../
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is only here to allow setting a specific PHP version to run the analysis for without
|
||||
* having to explicitly set it in the .neon file. This is the best way we found so far.
|
||||
*
|
||||
* @link https://phpstan.org/config-reference#phpversion
|
||||
*
|
||||
* Usage: Uses the CLI PHP version by default, which would work fine for
|
||||
* - The CI as the docker image has the target PHP version in both CLI and web
|
||||
* - The developer's IDE as PHPStorm also has a default PHP version configured which can be changed on the fly
|
||||
*/
|
||||
|
||||
// Default PHP version to analyse is the one running in CLI
|
||||
$config = [];
|
||||
$config['parameters']['phpVersion'] = PHP_VERSION_ID;
|
||||
|
||||
return $config;
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
Documentation on creating and maintaining tests in iTop.
|
||||
|
||||
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### PHPUnit configuration file
|
||||
@@ -75,8 +78,7 @@ Example :
|
||||
$oTagData->DBDelete();
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> When the condition is met the test is finished and following code will be ignored !
|
||||
Warning : when the condition is met the test is finished and following code will be ignored !
|
||||
|
||||
Another way to do is using try/catch blocks, for example :
|
||||
```php
|
||||
|
||||
@@ -28,14 +28,14 @@ class AjaxPageTest extends ItopDataTestCase
|
||||
$iLastCompilation = filemtime(APPROOT.'env-production');
|
||||
|
||||
// When
|
||||
$sOutput = $this->CallItopUri(
|
||||
"pages/exec.php?exec_module=itop-hub-connector&exec_page=ajax.php",
|
||||
$sOutput = $this->CallItopUrl(
|
||||
"/pages/exec.php?exec_module=itop-hub-connector&exec_page=ajax.php",
|
||||
[
|
||||
'auth_user' => $sLogin,
|
||||
'auth_pwd' => self::AUTHENTICATION_PASSWORD,
|
||||
'operation' => "compile",
|
||||
'authent' => self::AUTHENTICATION_TOKEN,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
// Then
|
||||
@@ -53,4 +53,26 @@ class AjaxPageTest extends ItopDataTestCase
|
||||
clearstatcache();
|
||||
$this->assertGreaterThan($iLastCompilation, filemtime(APPROOT.'env-production'), 'The env-production directory should have been rebuilt');
|
||||
}
|
||||
|
||||
protected function CallItopUrl($sUri, ?array $aPostFields = null, bool $bXDebugEnabled = false)
|
||||
{
|
||||
$ch = curl_init();
|
||||
if ($bXDebugEnabled) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, 'XDEBUG_SESSION=phpstorm');
|
||||
}
|
||||
|
||||
$sUrl = \MetaModel::GetConfig()->Get('app_root_url')."/$sUri";
|
||||
var_dump($sUrl);
|
||||
curl_setopt($ch, CURLOPT_URL, $sUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);// set post data to true
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
$sOutput = curl_exec($ch);
|
||||
//echo "$sUrl error code:".curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
return $sOutput;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -25,15 +24,19 @@
|
||||
require_once('../../../approot.inc.php');
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
|
||||
|
||||
$sEnvironment = MetaModel::GetEnvironmentId();
|
||||
$aEntries = [];
|
||||
$aEntries = array();
|
||||
$aCacheUserData = apc_cache_info_compat();
|
||||
if (is_array($aCacheUserData) && isset($aCacheUserData['cache_list'])) {
|
||||
if (is_array($aCacheUserData) && isset($aCacheUserData['cache_list']))
|
||||
{
|
||||
$sPrefix = 'itop-'.$sEnvironment.'-query-cache-';
|
||||
|
||||
foreach ($aCacheUserData['cache_list'] as $i => $aEntry) {
|
||||
foreach($aCacheUserData['cache_list'] as $i => $aEntry)
|
||||
{
|
||||
$sEntryKey = array_key_exists('info', $aEntry) ? $aEntry['info'] : $aEntry['key'];
|
||||
if (strpos($sEntryKey, $sPrefix) === 0) {
|
||||
if (strpos($sEntryKey, $sPrefix) === 0)
|
||||
{
|
||||
$aEntries[] = $sEntryKey;
|
||||
}
|
||||
}
|
||||
@@ -41,39 +44,52 @@ if (is_array($aCacheUserData) && isset($aCacheUserData['cache_list'])) {
|
||||
|
||||
echo "<pre>";
|
||||
|
||||
if (empty($aEntries)) {
|
||||
if (empty($aEntries))
|
||||
{
|
||||
echo "No Data";
|
||||
return;
|
||||
}
|
||||
|
||||
$sKey = $aEntries[0];
|
||||
$result = apc_fetch($sKey);
|
||||
if (!is_object($result)) {
|
||||
if (!is_object($result))
|
||||
{
|
||||
return;
|
||||
}
|
||||
$oSQLQuery = $result;
|
||||
|
||||
echo "NB Tables before;NB Tables after;";
|
||||
foreach ($oSQLQuery->m_aContextData as $sField => $oValue) {
|
||||
foreach($oSQLQuery->m_aContextData as $sField => $oValue)
|
||||
{
|
||||
echo $sField.';';
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
sort($aEntries);
|
||||
|
||||
foreach ($aEntries as $sKey) {
|
||||
foreach($aEntries as $sKey)
|
||||
{
|
||||
$result = apc_fetch($sKey);
|
||||
if (is_object($result)) {
|
||||
if (is_object($result))
|
||||
{
|
||||
$oSQLQuery = $result;
|
||||
if (isset($oSQLQuery->m_aContextData)) {
|
||||
if (isset($oSQLQuery->m_aContextData))
|
||||
{
|
||||
echo $oSQLQuery->m_iOriginalTableCount.";".$oSQLQuery->CountTables().';';
|
||||
foreach ($oSQLQuery->m_aContextData as $oValue) {
|
||||
if (is_array($oValue)) {
|
||||
foreach($oSQLQuery->m_aContextData as $oValue)
|
||||
{
|
||||
if (is_array($oValue))
|
||||
{
|
||||
$sVal = json_encode($oValue);
|
||||
} else {
|
||||
if (empty($oValue)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (empty($oValue))
|
||||
{
|
||||
$sVal = '';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sVal = $oValue;
|
||||
}
|
||||
}
|
||||
@@ -85,3 +101,4 @@ foreach ($aEntries as $sKey) {
|
||||
}
|
||||
|
||||
echo "</pre>";
|
||||
|
||||
|
||||
@@ -54,20 +54,10 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
|
||||
*/
|
||||
abstract public function GetDatamodelDeltaAbsPath(): string;
|
||||
|
||||
/**
|
||||
* @return array<string, string> : dict extensions folders by their code
|
||||
*/
|
||||
public function GetAdditionalFeaturePaths(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
static::LoadRequiredItopFiles();
|
||||
if (is_null($this->oEnvironment)) {
|
||||
$this->oEnvironment = new UnitTestRunTimeEnvironment($this->GetTestEnvironment());
|
||||
}
|
||||
$this->oEnvironment = new UnitTestRunTimeEnvironment('production', $this->GetTestEnvironment());
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
@@ -133,6 +123,7 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
|
||||
// Note: To improve performances, we compile all XML deltas from test cases derived from this class and make a single environment where everything will be ran at once.
|
||||
// This requires XML deltas to be compatible, but it is a known and accepted trade-off. See PR #457
|
||||
if (false === $this->IsEnvironmentReady()) {
|
||||
|
||||
$this->debug("Preparing custom environment '$sTestEnv' with the following datamodel files:");
|
||||
foreach ($this->oEnvironment->GetCustomDatamodelFiles() as $sCustomDatamodelFile) {
|
||||
$this->debug(" - $sCustomDatamodelFile");
|
||||
@@ -164,33 +155,24 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
|
||||
$oTestConfig->ChangeModulesPath($sSourceEnv, $sTestEnv);
|
||||
// - Switch DB name to a dedicated one so we don't mess with the original one
|
||||
$sTestEnvSanitizedForDBName = preg_replace('/[^\d\w]/', '', $sTestEnv);
|
||||
$sPreviousDB = $oTestConfig->Get('db_name');
|
||||
$sNewDB = $sPreviousDB.'_'.$sTestEnvSanitizedForDBName;
|
||||
$oTestConfig->Set('db_name', $sNewDB);
|
||||
$oTestConfig->Set('db_name', $oTestConfig->Get('db_name').'_'.$sTestEnvSanitizedForDBName);
|
||||
|
||||
// - Compile env. based on the existing 'production' env.
|
||||
//$oEnvironment = new UnitTestRunTimeEnvironment($sSourceEnv, $sTestEnv);
|
||||
$this->oEnvironment->WriteConfigFileSafe($oTestConfig);
|
||||
$this->oEnvironment->CompileFrom($sSourceEnv);
|
||||
$oEnvironment = new UnitTestRunTimeEnvironment($sSourceEnv, $sTestEnv);
|
||||
$oEnvironment->WriteConfigFileSafe($oTestConfig);
|
||||
$oEnvironment->CompileFrom($sSourceEnv);
|
||||
|
||||
// - Force re-creating a fresh DB
|
||||
CMDBSource::InitFromConfig($oTestConfig);
|
||||
if (CMDBSource::IsDB($sNewDB)) {
|
||||
if (CMDBSource::IsDB($oTestConfig->Get('db_name'))) {
|
||||
CMDBSource::DropDB();
|
||||
}
|
||||
CMDBSource::CreateDB($sNewDB);
|
||||
CMDBSource::CreateDB($oTestConfig->Get('db_name'));
|
||||
MetaModel::Startup($sConfFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sTestEnv);
|
||||
// N°7446 For some reason we need to create the DB schema before starting the MM, then only we can create the tables.
|
||||
MetaModel::DBCreate();
|
||||
|
||||
// Make sure that runtime environment is complete
|
||||
// RunTimeEnvironment::AnalyzeInstallation would not return core modules otherwise...
|
||||
CMDBSource::DropTable("priv_module_install");
|
||||
CMDBSource::Query("CREATE TABLE $sNewDB.priv_module_install SELECT * FROM $sPreviousDB.priv_module_install");
|
||||
|
||||
$this->debug("Custom environment '$sTestEnv' is ready!");
|
||||
} else {
|
||||
$this->debug("Custom environment '$sTestEnv' READY BUILT:");
|
||||
}
|
||||
|
||||
parent::PrepareEnvironment();
|
||||
|
||||
@@ -18,7 +18,6 @@ use ArchivedObjectException;
|
||||
use CMDBObject;
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
use Config;
|
||||
use Contact;
|
||||
use CoreException;
|
||||
use CoreUnexpectedValue;
|
||||
@@ -71,9 +70,6 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
private $aCreatedObjects = [];
|
||||
private $aEventListeners = [];
|
||||
|
||||
protected ?string $sConfigTmpBackupFile = null;
|
||||
protected ?Config $oiTopConfig = null;
|
||||
|
||||
/**
|
||||
* @var bool When testing with silo, there are some cache we need to update on tearDown. Doing it all the time will cost too much, so it's opt-in !
|
||||
* @see tearDown
|
||||
@@ -128,8 +124,6 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
\IssueLog::Error($this->getName());
|
||||
|
||||
$this->PrepareEnvironment();
|
||||
|
||||
if (static::USE_TRANSACTION) {
|
||||
@@ -196,8 +190,6 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
|
||||
CMDBObject::SetCurrentChange(null);
|
||||
|
||||
$this->RestoreConfiguration();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
@@ -1525,35 +1517,4 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
$oObject->Set($sStopwatchAttCode, $oStopwatch);
|
||||
}
|
||||
|
||||
protected function BackupConfiguration(): void
|
||||
{
|
||||
$sConfigPath = MetaModel::GetConfig()->GetLoadedFile();
|
||||
clearstatcache();
|
||||
echo sprintf("rights via ls on %s:\n %s \n", $sConfigPath, exec("ls -al $sConfigPath"));
|
||||
$sFilePermOutput = substr(sprintf('%o', fileperms('/etc/passwd')), -4);
|
||||
echo sprintf("rights via fileperms on %s:\n %s \n", $sConfigPath, $sFilePermOutput);
|
||||
|
||||
$this->sConfigTmpBackupFile = tempnam(sys_get_temp_dir(), "config_");
|
||||
MetaModel::GetConfig()->WriteToFile($this->sConfigTmpBackupFile);
|
||||
$this->oiTopConfig = new Config($sConfigPath);
|
||||
}
|
||||
|
||||
protected function RestoreConfiguration(): void
|
||||
{
|
||||
if (is_null($this->sConfigTmpBackupFile) || ! is_file($this->sConfigTmpBackupFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_null($this->oiTopConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//put config back
|
||||
$sConfigPath = $this->oiTopConfig->GetLoadedFile();
|
||||
@chmod($sConfigPath, 0770);
|
||||
$oConfig = new Config($this->sConfigTmpBackupFile);
|
||||
$oConfig->WriteToFile($sConfigPath);
|
||||
@chmod($sConfigPath, 0440);
|
||||
@unlink($this->sConfigTmpBackupFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
use CMDBSource;
|
||||
use DateTime;
|
||||
use DeprecatedCallsLog;
|
||||
use MySQLTransactionNotClosedException;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use ReflectionMethod;
|
||||
use SetupUtils;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
@@ -28,7 +29,6 @@ use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
abstract class ItopTestCase extends KernelTestCase
|
||||
{
|
||||
public const TEST_LOG_DIR = 'test';
|
||||
protected array $aFileToClean = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
@@ -37,7 +37,7 @@ abstract class ItopTestCase extends KernelTestCase
|
||||
public const DISABLE_DEPRECATEDCALLSLOG_ERRORHANDLER = true;
|
||||
public static $DEBUG_UNIT_TEST = false;
|
||||
protected static $aBackupStaticProperties = [];
|
||||
public ?array $aLastCurlGetInfo = null;
|
||||
|
||||
/**
|
||||
* @link https://docs.phpunit.de/en/9.6/annotations.html#preserveglobalstate PHPUnit `preserveGlobalState` annotation documentation
|
||||
*
|
||||
@@ -175,15 +175,6 @@ abstract class ItopTestCase extends KernelTestCase
|
||||
}
|
||||
throw new MySQLTransactionNotClosedException('Some DB transactions were opened but not closed ! Fix the code by adding ROLLBACK or COMMIT statements !', []);
|
||||
}
|
||||
|
||||
foreach ($this->aFileToClean as $sPath) {
|
||||
if (is_file($sPath)) {
|
||||
@unlink($sPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
SetupUtils::tidydir($sPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -640,62 +631,4 @@ abstract class ItopTestCase extends KernelTestCase
|
||||
fclose($handle);
|
||||
return array_reverse($aLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sUrl
|
||||
* @param array|null $aPostFields
|
||||
* @param array|null $aCurlOptions
|
||||
* @param $bXDebugEnabled
|
||||
* @return string
|
||||
*/
|
||||
protected function CallUrl($sUrl, ?array $aPostFields = [], ?array $aCurlOptions = [], $bXDebugEnabled = false): string
|
||||
{
|
||||
$ch = curl_init();
|
||||
if ($bXDebugEnabled) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, "XDEBUG_SESSION=phpstorm");
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $sUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);// set post data to true
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
// Force disable of certificate check as most of dev / test env have a self-signed certificate
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt_array($ch, $aCurlOptions);
|
||||
if ($this->IsArrayOfArray($aPostFields)) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aPostFields));
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields);
|
||||
}
|
||||
|
||||
$sOutput = curl_exec($ch);
|
||||
|
||||
$info = curl_getinfo($ch);
|
||||
$this->aLastCurlGetInfo = $info;
|
||||
$sErrorMsg = curl_error($ch);
|
||||
$iErrorCode = curl_errno($ch);
|
||||
curl_close($ch);
|
||||
|
||||
\IssueLog::Info(__METHOD__, null, ['url' => $sUrl, 'error' => $sErrorMsg, 'error_code' => $iErrorCode, 'post_fields' => $aPostFields, 'info' => $info]);
|
||||
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
private function IsArrayOfArray(array $aStruct): bool
|
||||
{
|
||||
foreach ($aStruct as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function CallItopUri(string $sUri, ?array $aPostFields = [], ?array $aCurlOptions = [], $bXDebugEnabled = false): string
|
||||
{
|
||||
$sUrl = \MetaModel::GetConfig()->Get('app_root_url')."/$sUri";
|
||||
|
||||
return $this->CallUrl($sUrl, $aPostFields, $aCurlOptions, $bXDebugEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,25 +26,26 @@ use utils;
|
||||
*/
|
||||
class UnitTestRunTimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
/**
|
||||
* @var false
|
||||
*/
|
||||
public bool $bUseDelta = true;
|
||||
|
||||
/**
|
||||
* @var true
|
||||
*/
|
||||
public bool $bUseAdditionalFeatures = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $aCustomDatamodelFiles = null;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @var string
|
||||
*/
|
||||
protected $aAdditionExtensionFoldersByCode = null;
|
||||
protected $sSourceEnv;
|
||||
|
||||
public function __construct($sSourceEnv, $sTargetEnv)
|
||||
{
|
||||
parent::__construct($sTargetEnv);
|
||||
$this->sSourceEnv = $sSourceEnv;
|
||||
}
|
||||
|
||||
public function GetEnvironment(): string
|
||||
{
|
||||
return $this->sFinalEnv;
|
||||
}
|
||||
|
||||
public function CompileFrom($sSourceEnv, $bUseSymLinks = null)
|
||||
{
|
||||
@@ -55,15 +56,6 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment
|
||||
|
||||
SetupUtils::copydir(APPROOT.'/data/'.$sSourceEnv.'-modules', $sDestModulesDir, $bUseSymLinks);
|
||||
|
||||
if ($this->bUseAdditionalFeatures) {
|
||||
foreach ($this->GetExtensionFoldersToAdd() as $sExtensionCode => $sFolderPath) {
|
||||
\SetupLog::Info("ExtensionFoldersToAdd: $sExtensionCode => $sFolderPath");
|
||||
$sFolderName = basename($sFolderPath);
|
||||
@mkdir($sDestModulesDir.DIRECTORY_SEPARATOR.$sFolderName);
|
||||
SetupUtils::copydir($sFolderPath, $sDestModulesDir.DIRECTORY_SEPARATOR.$sFolderName, $bUseSymLinks);
|
||||
}
|
||||
}
|
||||
|
||||
parent::CompileFrom($sSourceEnv, $bUseSymLinks);
|
||||
}
|
||||
|
||||
@@ -102,43 +94,23 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment
|
||||
*/
|
||||
protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir)
|
||||
{
|
||||
\SetupLog::Info(__METHOD__);
|
||||
$aRet = parent::GetMFModulesToCompile($sSourceEnv, $sSourceDir);
|
||||
|
||||
if ($this->bUseDelta) {
|
||||
foreach ($this->GetCustomDatamodelFiles() as $sDeltaFile) {
|
||||
$sDeltaId = preg_replace('/[^\d\w]/', '', $sDeltaFile);
|
||||
$sDeltaName = basename($sDeltaFile);
|
||||
$sDeltaDir = dirname($sDeltaFile);
|
||||
$oDelta = new MFCoreModule($sDeltaName, "$sDeltaDir/$sDeltaName", $sDeltaFile);
|
||||
$aRet[$sDeltaId] = $oDelta;
|
||||
}
|
||||
foreach ($this->GetCustomDatamodelFiles() as $sDeltaFile) {
|
||||
$sDeltaId = preg_replace('/[^\d\w]/', '', $sDeltaFile);
|
||||
$sDeltaName = basename($sDeltaFile);
|
||||
$sDeltaDir = dirname($sDeltaFile);
|
||||
$oDelta = new MFCoreModule($sDeltaName, "$sDeltaDir/$sDeltaName", $sDeltaFile);
|
||||
$aRet[$sDeltaId] = $oDelta;
|
||||
}
|
||||
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
public function GetExtensionFoldersToAdd(): array
|
||||
public function GetCustomDatamodelFiles()
|
||||
{
|
||||
if (is_null($this->aAdditionExtensionFoldersByCode)) {
|
||||
$this->InitViaItopCustomDatamodelTestCaseClasses();
|
||||
if (!is_null($this->aCustomDatamodelFiles)) {
|
||||
return $this->aCustomDatamodelFiles;
|
||||
}
|
||||
|
||||
return $this->aAdditionExtensionFoldersByCode;
|
||||
}
|
||||
|
||||
public function GetCustomDatamodelFiles(): array
|
||||
{
|
||||
if (is_null($this->aCustomDatamodelFiles)) {
|
||||
$this->InitViaItopCustomDatamodelTestCaseClasses();
|
||||
}
|
||||
|
||||
return $this->aCustomDatamodelFiles;
|
||||
}
|
||||
|
||||
public function InitViaItopCustomDatamodelTestCaseClasses()
|
||||
{
|
||||
$this->aAdditionExtensionFoldersByCode = [];
|
||||
$this->aCustomDatamodelFiles = [];
|
||||
|
||||
// Search for the PHP files implementing the method GetDatamodelDeltaAbsPath
|
||||
@@ -197,19 +169,16 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment
|
||||
continue;
|
||||
}
|
||||
$sDeltaFile = $oTestClassInstance->GetDatamodelDeltaAbsPath();
|
||||
if (strlen($sDeltaFile) > 0) {
|
||||
if (!is_file($sDeltaFile)) {
|
||||
throw new \Exception("Unknown delta file: $sDeltaFile, from test class '$sClass'");
|
||||
}
|
||||
if (!in_array($sDeltaFile, $this->aCustomDatamodelFiles)) {
|
||||
$this->aCustomDatamodelFiles[] = $sDeltaFile;
|
||||
}
|
||||
if (!is_file($sDeltaFile)) {
|
||||
throw new \Exception("Unknown delta file: $sDeltaFile, from test class '$sClass'");
|
||||
}
|
||||
if (!in_array($sDeltaFile, $this->aCustomDatamodelFiles)) {
|
||||
$this->aCustomDatamodelFiles[] = $sDeltaFile;
|
||||
}
|
||||
|
||||
$aExtensionsPaths = $oTestClassInstance->GetAdditionalFeaturePaths();
|
||||
$this->aAdditionExtensionFoldersByCode = array_merge($this->aAdditionExtensionFoldersByCode, $aExtensionsPaths);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->aCustomDatamodelFiles;
|
||||
}
|
||||
|
||||
private function FindFilesModifiedAfter(float $fReferenceTimestamp, string $sPathToScan, array &$aModifiedFiles)
|
||||
|
||||
63
tests/php-unit-tests/unitary-tests/application/LoginTest.php
Normal file
63
tests/php-unit-tests/unitary-tests/application/LoginTest.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
|
||||
class LoginTest extends ItopDataTestCase
|
||||
{
|
||||
protected $sConfigTmpBackupFile;
|
||||
protected $sConfigPath;
|
||||
protected $sLoginMode;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
clearstatcache();
|
||||
|
||||
// The test consists in requesting UI.php from outside iTop with a specific configuration
|
||||
// Hence the configuration file must be tweaked on disk (and restored)
|
||||
$this->sConfigPath = MetaModel::GetConfig()->GetLoadedFile();
|
||||
$this->sConfigTmpBackupFile = tempnam(sys_get_temp_dir(), "config_");
|
||||
file_put_contents($this->sConfigTmpBackupFile, file_get_contents($this->sConfigPath));
|
||||
|
||||
$oConfig = new \Config($this->sConfigPath);
|
||||
$this->sLoginMode = "unimplemented_loginmode";
|
||||
$oConfig->AddAllowedLoginTypes($this->sLoginMode);
|
||||
|
||||
@chmod($this->sConfigPath, 0770);
|
||||
$oConfig->WriteToFile();
|
||||
@chmod($this->sConfigPath, 0444);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
if (! is_null($this->sConfigTmpBackupFile) && is_file($this->sConfigTmpBackupFile)) {
|
||||
//put config back
|
||||
@chmod($this->sConfigPath, 0770);
|
||||
file_put_contents($this->sConfigPath, file_get_contents($this->sConfigTmpBackupFile));
|
||||
@chmod($this->sConfigPath, 0444);
|
||||
@unlink($this->sConfigTmpBackupFile);
|
||||
}
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
protected function CallItopUrlByCurl($sUri, ?array $aPostFields = [])
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
$sUrl = MetaModel::GetConfig()->Get('app_root_url')."/$sUri";
|
||||
curl_setopt($ch, CURLOPT_URL, $sUrl);
|
||||
if (0 !== sizeof($aPostFields)) {
|
||||
curl_setopt($ch, CURLOPT_POST, 1);// set post data to true
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$sOutput = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
return $sOutput;
|
||||
}
|
||||
}
|
||||
@@ -143,12 +143,34 @@ class QueryTest extends ItopDataTestCase
|
||||
{
|
||||
// compute request url
|
||||
$url = $oQuery->GetExportUrl();
|
||||
$aCurlOptions = [
|
||||
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
|
||||
CURLOPT_USERPWD => self::USER.':'.self::PASSWORD,
|
||||
];
|
||||
|
||||
return $this->CallUrl($url, [], $aCurlOptions);
|
||||
// open curl
|
||||
$curl = curl_init();
|
||||
|
||||
// curl options
|
||||
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
curl_setopt($curl, CURLOPT_USERPWD, self::USER.':'.self::PASSWORD);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
// Force disable of certificate check as most of dev / test env have a self-signed certificate
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
|
||||
// execute curl
|
||||
$result = curl_exec($curl);
|
||||
if (curl_errno($curl)) {
|
||||
$info = curl_getinfo($curl);
|
||||
var_export($info);
|
||||
var_dump([
|
||||
'url' => $url,
|
||||
'app_root_url:' => MetaModel::GetConfig()->Get('app_root_url'),
|
||||
'GetAbsoluteUrlAppRoot:' => \utils::GetAbsoluteUrlAppRoot(),
|
||||
]);
|
||||
}
|
||||
// close curl
|
||||
curl_close($curl);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
|
||||
@@ -7,26 +7,30 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
$MySettings = [
|
||||
$MySettings = array(
|
||||
|
||||
|
||||
|
||||
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
|
||||
// default: ''
|
||||
'app_root_url' => 'http://%server(SERVER_NAME)?:localhost%/itop/iTop/',
|
||||
|
||||
];
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Modules specific settings
|
||||
*
|
||||
*/
|
||||
$MyModuleSettings = [
|
||||
];
|
||||
$MyModuleSettings = array(
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Data model modules to be loaded. Names are specified as relative paths
|
||||
*
|
||||
*/
|
||||
$MyModules = [
|
||||
];
|
||||
$MyModules = array(
|
||||
);
|
||||
?>
|
||||
@@ -7,26 +7,30 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
$MySettings = [
|
||||
$MySettings = array(
|
||||
|
||||
|
||||
|
||||
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
|
||||
// default: ''
|
||||
'app_root_url' => 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/itop/iTop/',
|
||||
'app_root_url' => 'http://' . (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost') . '/itop/iTop/',
|
||||
|
||||
];
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Modules specific settings
|
||||
*
|
||||
*/
|
||||
$MyModuleSettings = [
|
||||
];
|
||||
$MyModuleSettings = array(
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* Data model modules to be loaded. Names are specified as relative paths
|
||||
*
|
||||
*/
|
||||
$MyModules = [
|
||||
];
|
||||
$MyModules = array(
|
||||
);
|
||||
?>
|
||||
@@ -1,164 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup;
|
||||
|
||||
use AnalyzeInstallation;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use ModuleInstallationService;
|
||||
|
||||
class AnalyzeInstallationTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('setup/AnalyzeInstallation.php');
|
||||
$this->RequireOnceItopFile('setup/ModuleInstallationService.php');
|
||||
$this->RequireOnceItopFile('setup/modulediscovery.class.inc.php');
|
||||
$this->RequireOnceItopFile('setup/runtimeenv.class.inc.php');
|
||||
}
|
||||
|
||||
public static function AnalyzeInstallationProvider()
|
||||
{
|
||||
//$aModules = json_decode(file_get_contents(__DIR__.'/ressources/priv_modules.json'), true);
|
||||
$aAnalyzeInstallationOutput = json_decode(file_get_contents(__DIR__.'/ressources/analyze_installation_output.json'), true);
|
||||
$aAvailableModules = json_decode(file_get_contents(__DIR__.'/ressources/available_modules.json'), true);
|
||||
return [
|
||||
'new modules not in DB setup history' => [
|
||||
'aAvailableModules' => [
|
||||
'mandatory_module/1.0.0' => [
|
||||
"mandatory" => true,
|
||||
"ga" => "bu",
|
||||
],
|
||||
'optional_module/6.6.6' => [
|
||||
"mandatory" => false,
|
||||
"zo" => "meu",
|
||||
],
|
||||
],
|
||||
'aInstalledModules' => [],
|
||||
'expected' => [
|
||||
'_Root_' => [
|
||||
'installed_version' => '',
|
||||
'available_version' => 'ITOP_VERSION_FULL',
|
||||
'name_code' => 'ITOP_APPLICATION',
|
||||
],
|
||||
'mandatory_module' => [
|
||||
"mandatory" => true,
|
||||
'installed_version' => '',
|
||||
'available_version' => '1.0.0',
|
||||
'install' => [
|
||||
'flag' => 2,
|
||||
'message' => 'the module is part of the application',
|
||||
],
|
||||
"ga" => "bu",
|
||||
],
|
||||
'optional_module' => [
|
||||
"mandatory" => false,
|
||||
'installed_version' => '',
|
||||
'available_version' => '6.6.6',
|
||||
"zo" => "meu",
|
||||
'install' => [
|
||||
'flag' => 1,
|
||||
'message' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'new modules ALREADY in DB setup history' => [
|
||||
'aAvailableModules' => [
|
||||
'mandatory_module/1.0.0' => [
|
||||
"mandatory" => true,
|
||||
"ga" => "bu",
|
||||
],
|
||||
'optional_module/6.6.6' => [
|
||||
"mandatory" => false,
|
||||
"zo" => "meu",
|
||||
],
|
||||
],
|
||||
'aInstalledModules' => json_decode(file_get_contents(__DIR__.'/ressources/priv_modules_simpleusecase.json'), true),
|
||||
'expected' => [
|
||||
'_Root_' => [
|
||||
'installed_version' => '3.3.0-dev-svn',
|
||||
'available_version' => 'ITOP_VERSION_FULL',
|
||||
'name_code' => 'ITOP_APPLICATION',
|
||||
],
|
||||
'mandatory_module' => [
|
||||
"mandatory" => true,
|
||||
'installed_version' => '3.3.0',
|
||||
'available_version' => '1.0.0',
|
||||
"ga" => "bu",
|
||||
'install' => [
|
||||
'flag' => 2,
|
||||
'message' => 'the module is part of the application',
|
||||
],
|
||||
'uninstall' => [
|
||||
'flag' => 3,
|
||||
'message' => 'the module is part of the application',
|
||||
],
|
||||
],
|
||||
'optional_module' => [
|
||||
"mandatory" => false,
|
||||
'installed_version' => '3.3.0',
|
||||
'available_version' => '6.6.6',
|
||||
"zo" => "meu",
|
||||
'install' => [
|
||||
'flag' => 1,
|
||||
'message' => '',
|
||||
],
|
||||
'uninstall' => [
|
||||
'flag' => 1,
|
||||
'message' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'dummyfirst installation' => [
|
||||
'aAvailableModules' => [],
|
||||
'aInstalledModules' => [],
|
||||
'expected' => [
|
||||
'_Root_' => [
|
||||
'installed_version' => '',
|
||||
'available_version' => 'ITOP_VERSION_FULL',
|
||||
'name_code' => 'ITOP_APPLICATION',
|
||||
],
|
||||
],
|
||||
],
|
||||
'dummy 2nd installation' => [
|
||||
'aAvailableModules' => [],
|
||||
'aInstalledModules' => json_decode(file_get_contents(__DIR__.'/ressources/priv_modules2.json'), true),
|
||||
'expected' => [
|
||||
'_Root_' => [
|
||||
'installed_version' => '3.3.0-dev-svn',
|
||||
'available_version' => 'ITOP_VERSION_FULL',
|
||||
'name_code' => 'ITOP_APPLICATION',
|
||||
],
|
||||
],
|
||||
],
|
||||
'real_case' => [
|
||||
'aAvailableModules' => $aAvailableModules,
|
||||
'aInstalledModules' => json_decode(file_get_contents(__DIR__.'/ressources/priv_modules2.json'), true),
|
||||
'expected' => $aAnalyzeInstallationOutput,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider AnalyzeInstallationProvider
|
||||
*/
|
||||
public function testAnalyzeInstallation($aAvailableModules, $aInstalledModules, $expected)
|
||||
{
|
||||
$sContent = str_replace(['ITOP_VERSION_FULL', 'ITOP_APPLICATION'], [ITOP_VERSION_FULL, ITOP_APPLICATION], json_encode($expected));
|
||||
$expected = json_decode($sContent, true);
|
||||
|
||||
$this->SetNonPublicProperty(AnalyzeInstallation::GetInstance(), "aAvailableModules", $aAvailableModules);
|
||||
//$aModules = json_decode(file_get_contents(__DIR__.'/ressources/priv_modules2.json'), true);
|
||||
$this->SetNonPublicProperty(ModuleInstallationService::GetInstance(), "aSelectInstall", $aInstalledModules);
|
||||
|
||||
$oConfig = $this->createMock(\Config::class);
|
||||
|
||||
$modulesPath = [
|
||||
APPROOT.'extensions',
|
||||
];
|
||||
$aModules = AnalyzeInstallation::GetInstance()->AnalyzeInstallation($oConfig, $modulesPath, false, null);
|
||||
$this->assertEquals($expected, $aModules);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
class WizStepModulesChoiceFake extends WizStepModulesChoice
|
||||
{
|
||||
public function __construct(WizardController $oWizard, $sCurrentState)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function setExtensionMap(iTopExtensionsMap $oMap)
|
||||
{
|
||||
$this->oExtensionsMap = $oMap;
|
||||
}
|
||||
}
|
||||
@@ -1,355 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Integration;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use ItopExtensionsMap;
|
||||
use iTopExtensionsMapFake;
|
||||
use ModuleDiscovery;
|
||||
use WizardController;
|
||||
|
||||
class WizStepModulesChoiceTest extends ItopTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('/setup/unattended-install/InstallationFileService.php');
|
||||
require_once __DIR__.'/iTopExtensionsMapFake.php';
|
||||
require_once __DIR__.'/WizStepModulesChoiceFake.php';
|
||||
|
||||
$this->oStep = new \WizStepModulesChoiceFake(new WizardController('', ''), '');
|
||||
ModuleDiscovery::ResetCache();
|
||||
}
|
||||
|
||||
public function ProviderComputeChoiceFlags()
|
||||
{
|
||||
return [
|
||||
'selected but not installed extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => false,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => true,
|
||||
],
|
||||
'aSelected' => ['_0' => '_0'],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => true,
|
||||
'missing' => false,
|
||||
'installed' => false,
|
||||
'disabled' => false,
|
||||
'checked' => true,
|
||||
],
|
||||
],
|
||||
'not selected, not installed extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => true,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => true,
|
||||
],
|
||||
'aSelected' => [],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => true,
|
||||
'missing' => false,
|
||||
'installed' => false,
|
||||
'disabled' => false,
|
||||
'checked' => false,
|
||||
],
|
||||
],
|
||||
'installed extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => true,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => true,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => true,
|
||||
],
|
||||
'aSelected' => [],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => true,
|
||||
'missing' => false,
|
||||
'installed' => true,
|
||||
'disabled' => false,
|
||||
'checked' => false,
|
||||
],
|
||||
],
|
||||
'installed non uninstallable extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => true,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => true,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => false,
|
||||
],
|
||||
'aSelected' => [],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => false,
|
||||
'missing' => false,
|
||||
'installed' => true,
|
||||
'disabled' => true,
|
||||
'checked' => true,
|
||||
],
|
||||
],
|
||||
'mandatory extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => true,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => true,
|
||||
'uninstallable' => true,
|
||||
],
|
||||
'aSelected' => [],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => true,
|
||||
'missing' => false,
|
||||
'installed' => false,
|
||||
'disabled' => true,
|
||||
'checked' => true,
|
||||
],
|
||||
],
|
||||
'optional sub extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
'itop-ext1-1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => true,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => true,
|
||||
'sub_options' => [
|
||||
'options' => [
|
||||
[
|
||||
'extension_code' => 'itop-ext1-1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'aSelected' => [],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => true,
|
||||
'missing' => false,
|
||||
'installed' => false,
|
||||
'disabled' => false,
|
||||
'checked' => false,
|
||||
],
|
||||
],
|
||||
'mandatory sub extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
'itop-ext1-1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => true,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => true,
|
||||
'sub_options' => [
|
||||
'options' => [
|
||||
[
|
||||
'extension_code' => 'itop-ext1-1',
|
||||
'mandatory' => true,
|
||||
'uninstallable' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'aSelected' => [],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => true,
|
||||
'missing' => false,
|
||||
'installed' => false,
|
||||
'disabled' => true,
|
||||
'checked' => true,
|
||||
],
|
||||
],
|
||||
'non uninstallable sub extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => true,
|
||||
],
|
||||
'itop-ext1-1' => [
|
||||
'installed' => true,
|
||||
],
|
||||
],
|
||||
'bUpgrade' => true,
|
||||
'bDisableUninstallCheck' => false,
|
||||
'sChoiceId' => '_0',
|
||||
'aStepInfo' => [
|
||||
'extension_code' => 'itop-ext1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => true,
|
||||
'sub_options' => [
|
||||
'options' => [
|
||||
[
|
||||
'extension_code' => 'itop-ext1-1',
|
||||
'mandatory' => false,
|
||||
'uninstallable' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'aSelected' => [],
|
||||
'aExpectedFlags' => [
|
||||
'uninstallable' => true,
|
||||
'missing' => false,
|
||||
'installed' => true,
|
||||
'disabled' => true,
|
||||
'checked' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ProviderComputeChoiceFlags
|
||||
*/
|
||||
public function testComputeChoiceFlags($aExtensions, $bUpgrade, $bDisableUninstallCheck, $sChoiceId, $aStepInfo, $aSelected, $aExpectedFlags)
|
||||
{
|
||||
$this->oStep->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensions));
|
||||
$aFlags = $this->oStep->ComputeChoiceFlags($aStepInfo, $sChoiceId, $aSelected, false, $bDisableUninstallCheck, $bUpgrade);
|
||||
$this->assertEquals($aExpectedFlags, $aFlags);
|
||||
}
|
||||
|
||||
public function ProviderGetAddedAndRemovedExtensions()
|
||||
{
|
||||
return [
|
||||
'no extensions' => [
|
||||
'aExtensions' => [],
|
||||
|
||||
'aSelected' => [],
|
||||
'sExpectedAddedList' => '<ul><li>No extension added.</li></ul>',
|
||||
'sExpectedRemovedList' => '<ul><li>No extension removed.</li></ul>',
|
||||
],
|
||||
'no extensions selected' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
],
|
||||
'aSelected' => [],
|
||||
'sExpectedAddedList' => '<ul><li>No extension added.</li></ul>',
|
||||
'sExpectedRemovedList' => '<ul><li>No extension removed.</li></ul>',
|
||||
],
|
||||
'no extensions removed' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => true,
|
||||
],
|
||||
],
|
||||
'aSelected' => ['itop-ext1'],
|
||||
'sExpectedAddedList' => '<ul><li>No extension added.</li></ul>',
|
||||
'sExpectedRemovedList' => '<ul><li>No extension removed.</li></ul>',
|
||||
],
|
||||
'One added extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
],
|
||||
'aSelected' => ['itop-ext1'],
|
||||
'sExpectedAddedList' => '<ul><li>itop-ext1</li></ul>',
|
||||
'sExpectedRemovedList' => '<ul><li>No extension removed.</li></ul>',
|
||||
],
|
||||
'One removed extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => true,
|
||||
],
|
||||
],
|
||||
'aSelected' => [],
|
||||
'sExpectedAddedList' => '<ul><li>No extension added.</li></ul>',
|
||||
'sExpectedRemovedList' => '<ul><li>itop-ext1</li></ul>',
|
||||
],
|
||||
'Forced removed extension' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext1' => [
|
||||
'installed' => true,
|
||||
'uninstallable' => false,
|
||||
],
|
||||
],
|
||||
'aSelected' => [],
|
||||
'sExpectedAddedList' => '<ul><li>No extension added.</li></ul>',
|
||||
'sExpectedRemovedList' => '<ul><li>itop-ext1 (forced uninstallation)</li></ul>',
|
||||
],
|
||||
'added and removed extensions' => [
|
||||
'aExtensions' => [
|
||||
'itop-ext-added1' => [
|
||||
'installed' => false,
|
||||
],
|
||||
'itop-ext-added2' => [
|
||||
'installed' => false,
|
||||
],
|
||||
'itop-ext-removed1' => [
|
||||
'installed' => true,
|
||||
],
|
||||
'itop-ext-removed2' => [
|
||||
'installed' => true,
|
||||
],
|
||||
],
|
||||
'aSelected' => ['itop-ext-added1', 'itop-ext-added2'],
|
||||
'sExpectedAddedList' => '<ul><li>itop-ext-added1</li><li>itop-ext-added2</li></ul>',
|
||||
'sExpectedRemovedList' => '<ul><li>itop-ext-removed1</li><li>itop-ext-removed2</li></ul>',
|
||||
],
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ProviderGetAddedAndRemovedExtensions
|
||||
*/
|
||||
public function testGetAddedAndRemovedExtensions($aExtensions, $aSelectedExtensions, $sExpectedAddedList, $sExpectedRemovedList)
|
||||
{
|
||||
$this->oStep->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensions));
|
||||
[$sAddedList, $sRemovedList] = $this->oStep->GetAddedAndRemovedExtensions($aSelectedExtensions);
|
||||
$this->assertEquals($sExpectedAddedList, $sAddedList);
|
||||
$this->assertEquals($sExpectedRemovedList, $sRemovedList);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup\FeatureRemoval;
|
||||
|
||||
use Combodo\iTop\Setup\FeatureRemoval\ModelReflectionSerializer;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
|
||||
class ModelSerializationTest extends ItopDataTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php');
|
||||
}
|
||||
|
||||
public function testGetModelFromEnvironment()
|
||||
{
|
||||
$aModel = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->GetTestEnvironment());
|
||||
$this->assertEqualsCanonicalizing(MetaModel::GetClasses(), $aModel);
|
||||
}
|
||||
|
||||
public function testGetModelFromEnvironmentFailure()
|
||||
{
|
||||
$this->expectException(\CoreException::class);
|
||||
$this->expectExceptionMessage("Cannot get classes");
|
||||
ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment('gabuzomeu');
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup\FeatureRemoval;
|
||||
|
||||
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
|
||||
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
|
||||
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
|
||||
use Combodo\iTop\Test\UnitTest\Service\UnitTestRunTimeEnvironment;
|
||||
use Exception;
|
||||
|
||||
class SetupAuditTest extends ItopCustomDatamodelTestCase
|
||||
{
|
||||
public const ENVT = 'php-unit-extensionremoval-tests';
|
||||
|
||||
public function GetDatamodelDeltaAbsPath(): string
|
||||
{
|
||||
//no delta: empty path provided
|
||||
return "";
|
||||
}
|
||||
|
||||
public function GetAdditionalFeaturePaths(): array
|
||||
{
|
||||
$aFeaturePaths = [];
|
||||
foreach (glob(__DIR__."/additional_features/*", GLOB_ONLYDIR) as $aFeaturePath) {
|
||||
$sCode = basename($aFeaturePath);
|
||||
$aFeaturePaths[$sCode] = $aFeaturePath;
|
||||
}
|
||||
|
||||
return $aFeaturePaths;
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
static::LoadRequiredItopFiles();
|
||||
$this->oEnvironment = new UnitTestRunTimeEnvironment(self::ENVT);
|
||||
$this->oEnvironment->bUseDelta = false;
|
||||
$this->oEnvironment->bUseAdditionalFeatures = true;
|
||||
parent::setUp();
|
||||
|
||||
$this->RequireOnceItopFile('/setup/feature_removal/SetupAudit.php');
|
||||
$this->RequireOnceItopFile('/setup/feature_removal/DryRemovalRuntimeEnvironment.php');
|
||||
}
|
||||
|
||||
public function GetTestEnvironment(): string
|
||||
{
|
||||
return self::ENVT;
|
||||
}
|
||||
|
||||
public function testComputeDryRemoval()
|
||||
{
|
||||
$oDryRemovalRuntimeEnvt = new DryRemovalRuntimeEnvironment();
|
||||
$oDryRemovalRuntimeEnvt->Prepare($this->GetTestEnvironment(), ['nominal_ext1', 'finalclass_ext2']);
|
||||
$oDryRemovalRuntimeEnvt->CompileFrom($this->GetTestEnvironment());
|
||||
|
||||
$oSetupAudit = new SetupAudit(\MetaModel::GetEnvironment());
|
||||
|
||||
$expected = [
|
||||
"Feature1Module1MyClass",
|
||||
"FinalClassFeature2Module1MyClass",
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation",
|
||||
];
|
||||
$this->assertEqualsCanonicalizing($expected, $oSetupAudit->GetRemovedClasses());
|
||||
|
||||
$expected = [
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation" => 0,
|
||||
];
|
||||
$this->assertEqualsCanonicalizing($expected, $oSetupAudit->GetIssues());
|
||||
}
|
||||
|
||||
public function testGetIssues()
|
||||
{
|
||||
$sUID = "AuditExtensionsCleanupRules_".uniqid();
|
||||
$oOrg = $this->CreateOrganization($sUID);
|
||||
$this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
|
||||
|
||||
$oSetupAudit = new SetupAudit(\MetaModel::GetEnvironment());
|
||||
$aRemovedClasses = [
|
||||
"Feature1Module1MyClass",
|
||||
"FinalClassFeature1Module1MyClass",
|
||||
"FinalClassFeature1Module1MyFinalClassFromLocation",
|
||||
"FinalClassFeature2Module1MyClass",
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation",
|
||||
];
|
||||
|
||||
//avoid setup dry computation
|
||||
$this->SetNonPublicProperty($oSetupAudit, 'aRemovedClasses', $aRemovedClasses);
|
||||
|
||||
$expected = [
|
||||
"FinalClassFeature1Module1MyFinalClassFromLocation" => 1,
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation" => 0,
|
||||
];
|
||||
$this->assertEqualsCanonicalizing($expected, $oSetupAudit->GetIssues());
|
||||
}
|
||||
|
||||
public function testAuditExtensionsCleanupRulesFailASAP()
|
||||
{
|
||||
$sUID = "AuditExtensionsCleanupRules_".uniqid();
|
||||
$oOrg = $this->CreateOrganization($sUID);
|
||||
$this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
|
||||
$this->createObject('FinalClassFeature2Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
|
||||
|
||||
$oSetupAudit = new SetupAudit(\MetaModel::GetEnvironment());
|
||||
$aRemovedClasses = [
|
||||
"Feature1Module1MyClass",
|
||||
"FinalClassFeature1Module1MyClass",
|
||||
"FinalClassFeature1Module1MyFinalClassFromLocation",
|
||||
"FinalClassFeature2Module1MyClass",
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation",
|
||||
];
|
||||
|
||||
//avoid setup dry computation
|
||||
$this->SetNonPublicProperty($oSetupAudit, 'aRemovedClasses', $aRemovedClasses);
|
||||
|
||||
$this->expectException(Exception::class);
|
||||
$this->expectExceptionMessage('FinalClassFeature1Module1MyFinalClassFromLocation');
|
||||
$oSetupAudit->GetIssues(true);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension format="1.0">
|
||||
<extension_code>finalclass_ext1</extension_code>
|
||||
<company>Combodo SARL</company>
|
||||
<author><![CDATA[Odain]]></author>
|
||||
<label><![CDATA[Ext For Test]]></label>
|
||||
<description><![CDATA[Ext For Test]]></description>
|
||||
<version>6.6.6</version>
|
||||
<modules type="array">
|
||||
<module>
|
||||
<id>finalclass_ext1_module1</id>
|
||||
<version>tags/6.6.6</version>
|
||||
</module>
|
||||
</modules>
|
||||
<release_date>2023-07-19</release_date>
|
||||
<version_description><![CDATA[
|
||||
]]></version_description>
|
||||
<itop_version_min>3.2.0</itop_version_min>
|
||||
<status></status>
|
||||
<mandatory>false</mandatory>
|
||||
<more_info_url></more_info_url>
|
||||
</extension>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
|
||||
<classes>
|
||||
<class id="FinalClassFeature1Module1MyFinalClassFromLocation" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>FinalClassFeature1Module1MyFinalClassFromLocation</db_table>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name2"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="name2"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<order>
|
||||
<columns>
|
||||
<column id="name2" ascending="false"/>
|
||||
</columns>
|
||||
</order>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name2" xsi:type="AttributeString">
|
||||
<sql>name2</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation/>
|
||||
<parent>Location</parent>
|
||||
</class>
|
||||
<class id="FinalClassFeature1Module1MyClass" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>FinalClassFeature1Module1MyClass</db_table>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<order>
|
||||
<columns>
|
||||
<column id="name" ascending="false"/>
|
||||
</columns>
|
||||
</order>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<validation_pattern/>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation/>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
</class>
|
||||
</classes>
|
||||
<menus/>
|
||||
<user_rights/>
|
||||
<module_parameters/>
|
||||
</itop_design>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
//// PHP Data Model definition file
|
||||
//
|
||||
//// WARNING - WARNING - WARNING
|
||||
//// DO NOT EDIT THIS FILE (unless you know what you are doing)
|
||||
////
|
||||
//// If you use supply a datamodel.xxxx.xml file with your module
|
||||
//// the this file WILL BE overwritten by the compilation of the
|
||||
//// module (during the setup) if the datamodel.xxxx.xml file
|
||||
//// contains the definition of new classes or menus.
|
||||
////
|
||||
//// The recommended way to define new classes (for iTop 2.0) is via the XML definition.
|
||||
//// This file remains in the module's template only for the cases where there is:
|
||||
//// - either no new class or menu defined in the XML file
|
||||
//// - or no XML file at all supplied by the module
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'finalclass_ext1_module1/6.6.6',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Ext For Test',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-structure/3.2.0',
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => '',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'model.finalclass_ext1_module1.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' => [// Module specific settings go here, if any
|
||||
],
|
||||
]
|
||||
);
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension format="1.0">
|
||||
<extension_code>finalclass_ext2</extension_code>
|
||||
<company>Combodo SARL</company>
|
||||
<author><![CDATA[Odain]]></author>
|
||||
<label><![CDATA[Ext For Test]]></label>
|
||||
<description><![CDATA[Ext For Test]]></description>
|
||||
<version>6.6.6</version>
|
||||
<modules type="array">
|
||||
<module>
|
||||
<id>finalclass_ext2_module1</id>
|
||||
<version>tags/6.6.6</version>
|
||||
</module>
|
||||
</modules>
|
||||
<release_date>2023-07-19</release_date>
|
||||
<version_description><![CDATA[
|
||||
]]></version_description>
|
||||
<itop_version_min>3.2.0</itop_version_min>
|
||||
<status></status>
|
||||
<mandatory>false</mandatory>
|
||||
<more_info_url></more_info_url>
|
||||
</extension>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
|
||||
<classes>
|
||||
<class id="FinalClassFeature2Module1MyFinalClassFromLocation" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>FinalClassFeature2Module1MyFinalClassFromLocation</db_table>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name2"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="name2"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<order>
|
||||
<columns>
|
||||
<column id="name2" ascending="false"/>
|
||||
</columns>
|
||||
</order>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name2" xsi:type="AttributeString">
|
||||
<sql>name2</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation/>
|
||||
<parent>Location</parent>
|
||||
</class>
|
||||
<class id="FinalClassFeature2Module1MyClass" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>FinalClassFeature2Module1MyClass</db_table>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<order>
|
||||
<columns>
|
||||
<column id="name" ascending="false"/>
|
||||
</columns>
|
||||
</order>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<validation_pattern/>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation/>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
</class>
|
||||
</classes>
|
||||
<menus/>
|
||||
<user_rights/>
|
||||
<module_parameters/>
|
||||
</itop_design>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
//// PHP Data Model definition file
|
||||
//
|
||||
//// WARNING - WARNING - WARNING
|
||||
//// DO NOT EDIT THIS FILE (unless you know what you are doing)
|
||||
////
|
||||
//// If you use supply a datamodel.xxxx.xml file with your module
|
||||
//// the this file WILL BE overwritten by the compilation of the
|
||||
//// module (during the setup) if the datamodel.xxxx.xml file
|
||||
//// contains the definition of new classes or menus.
|
||||
////
|
||||
//// The recommended way to define new classes (for iTop 2.0) is via the XML definition.
|
||||
//// This file remains in the module's template only for the cases where there is:
|
||||
//// - either no new class or menu defined in the XML file
|
||||
//// - or no XML file at all supplied by the module
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'finalclass_ext2_module1/6.6.6',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Ext For Test',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-structure/3.2.0',
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => '',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'model.finalclass_ext2_module1.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' => [// Module specific settings go here, if any
|
||||
],
|
||||
]
|
||||
);
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension format="1.0">
|
||||
<extension_code>nominal_ext1</extension_code>
|
||||
<company>Combodo SARL</company>
|
||||
<author><![CDATA[Odain]]></author>
|
||||
<label><![CDATA[Ext For Test]]></label>
|
||||
<description><![CDATA[Ext For Test]]></description>
|
||||
<version>6.6.6</version>
|
||||
<modules type="array">
|
||||
<module>
|
||||
<id>nominal_ext1_module1</id>
|
||||
<version>tags/6.6.6</version>
|
||||
</module>
|
||||
</modules>
|
||||
<release_date>2023-07-19</release_date>
|
||||
<version_description><![CDATA[
|
||||
]]></version_description>
|
||||
<itop_version_min>3.2.0</itop_version_min>
|
||||
<status></status>
|
||||
<mandatory>false</mandatory>
|
||||
<more_info_url></more_info_url>
|
||||
</extension>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
|
||||
<classes>
|
||||
<class id="Feature1Module1MyClass" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>Feature1Module1MyClass</db_table>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<order>
|
||||
<columns>
|
||||
<column id="name" ascending="false"/>
|
||||
</columns>
|
||||
</order>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<validation_pattern/>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation/>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
</class>
|
||||
</classes>
|
||||
<menus/>
|
||||
<user_rights/>
|
||||
<module_parameters/>
|
||||
</itop_design>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
//// PHP Data Model definition file
|
||||
//
|
||||
//// WARNING - WARNING - WARNING
|
||||
//// DO NOT EDIT THIS FILE (unless you know what you are doing)
|
||||
////
|
||||
//// If you use supply a datamodel.xxxx.xml file with your module
|
||||
//// the this file WILL BE overwritten by the compilation of the
|
||||
//// module (during the setup) if the datamodel.xxxx.xml file
|
||||
//// contains the definition of new classes or menus.
|
||||
////
|
||||
//// The recommended way to define new classes (for iTop 2.0) is via the XML definition.
|
||||
//// This file remains in the module's template only for the cases where there is:
|
||||
//// - either no new class or menu defined in the XML file
|
||||
//// - or no XML file at all supplied by the module
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
class iTopExtensionsMapFake extends iTopExtensionsMap
|
||||
{
|
||||
public function __construct($sFromEnvironment = 'production', $aExtraDirs = [])
|
||||
{
|
||||
$this->aExtensions = [];
|
||||
$this->aExtensionsByCode = [];
|
||||
$this->aScannedDirs = [];
|
||||
}
|
||||
|
||||
public static function createFromArray($aExtensions)
|
||||
{
|
||||
$oMap = new static();
|
||||
|
||||
foreach ($aExtensions as $sCode => $aExtension) {
|
||||
$oExtension = new iTopExtension();
|
||||
$oExtension->sCode = $sCode;
|
||||
$oExtension->sLabel = $sCode;
|
||||
$oExtension->bInstalled = $aExtension['installed'];
|
||||
$oExtension->aModules = $aExtension['modules'] ?? [];
|
||||
$oExtension->bCanBeUninstalled = $aExtension['uninstallable'] ?? null;
|
||||
$oExtension->sVersion = $aExtension['version'] ?? '1.0.0';
|
||||
$oExtension->aModuleInfo = [];
|
||||
$oMap->AddExtension($oExtension);
|
||||
}
|
||||
return $oMap;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,642 +0,0 @@
|
||||
[
|
||||
{
|
||||
"0": "330",
|
||||
"id": "330",
|
||||
"1": "iTop",
|
||||
"name": "iTop",
|
||||
"2": "3.3.0-dev-svn",
|
||||
"version": "3.3.0-dev-svn",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nBuilt on $WCNOW$",
|
||||
"comment": "Done by the setup program\nBuilt on $WCNOW$",
|
||||
"5": "0",
|
||||
"parent_id": "0",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "331",
|
||||
"id": "331",
|
||||
"1": "authent-cas",
|
||||
"name": "authent-cas",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nVisible (during the setup)",
|
||||
"comment": "Done by the setup program\nMandatory\nVisible (during the setup)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "332",
|
||||
"id": "332",
|
||||
"1": "authent-external",
|
||||
"name": "authent-external",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "333",
|
||||
"id": "333",
|
||||
"1": "authent-ldap",
|
||||
"name": "authent-ldap",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "334",
|
||||
"id": "334",
|
||||
"1": "authent-local",
|
||||
"name": "authent-local",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nVisible (during the setup)",
|
||||
"comment": "Done by the setup program\nMandatory\nVisible (during the setup)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "335",
|
||||
"id": "335",
|
||||
"1": "combodo-backoffice-darkmoon-theme",
|
||||
"name": "combodo-backoffice-darkmoon-theme",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "336",
|
||||
"id": "336",
|
||||
"1": "combodo-backoffice-fullmoon-high-contrast-theme",
|
||||
"name": "combodo-backoffice-fullmoon-high-contrast-theme",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "337",
|
||||
"id": "337",
|
||||
"1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme",
|
||||
"name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "338",
|
||||
"id": "338",
|
||||
"1": "combodo-backoffice-fullmoon-tritanopia-theme",
|
||||
"name": "combodo-backoffice-fullmoon-tritanopia-theme",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "339",
|
||||
"id": "339",
|
||||
"1": "itop-backup",
|
||||
"name": "itop-backup",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "340",
|
||||
"id": "340",
|
||||
"1": "itop-config",
|
||||
"name": "itop-config",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "341",
|
||||
"id": "341",
|
||||
"1": "itop-files-information",
|
||||
"name": "itop-files-information",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "342",
|
||||
"id": "342",
|
||||
"1": "itop-portal-base",
|
||||
"name": "itop-portal-base",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "343",
|
||||
"id": "343",
|
||||
"1": "itop-profiles-itil",
|
||||
"name": "itop-profiles-itil",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "344",
|
||||
"id": "344",
|
||||
"1": "itop-sla-computation",
|
||||
"name": "itop-sla-computation",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "345",
|
||||
"id": "345",
|
||||
"1": "itop-structure",
|
||||
"name": "itop-structure",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "346",
|
||||
"id": "346",
|
||||
"1": "itop-welcome-itil",
|
||||
"name": "itop-welcome-itil",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"comment": "Done by the setup program\nMandatory\nHidden (selected automatically)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "347",
|
||||
"id": "347",
|
||||
"1": "itop-config-mgmt",
|
||||
"name": "itop-config-mgmt",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "348",
|
||||
"id": "348",
|
||||
"1": "itop-attachments",
|
||||
"name": "itop-attachments",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "349",
|
||||
"id": "349",
|
||||
"1": "itop-tickets",
|
||||
"name": "itop-tickets",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "350",
|
||||
"id": "350",
|
||||
"1": "combodo-db-tools",
|
||||
"name": "combodo-db-tools",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "351",
|
||||
"id": "351",
|
||||
"1": "itop-core-update",
|
||||
"name": "itop-core-update",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "352",
|
||||
"id": "352",
|
||||
"1": "itop-hub-connector",
|
||||
"name": "itop-hub-connector",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "353",
|
||||
"id": "353",
|
||||
"1": "itop-oauth-client",
|
||||
"name": "itop-oauth-client",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "354",
|
||||
"id": "354",
|
||||
"1": "itop-themes-compat",
|
||||
"name": "itop-themes-compat",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "355",
|
||||
"id": "355",
|
||||
"1": "itop-datacenter-mgmt",
|
||||
"name": "itop-datacenter-mgmt",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "356",
|
||||
"id": "356",
|
||||
"1": "itop-endusers-devices",
|
||||
"name": "itop-endusers-devices",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "357",
|
||||
"id": "357",
|
||||
"1": "itop-storage-mgmt",
|
||||
"name": "itop-storage-mgmt",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "358",
|
||||
"id": "358",
|
||||
"1": "itop-virtualization-mgmt",
|
||||
"name": "itop-virtualization-mgmt",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "359",
|
||||
"id": "359",
|
||||
"1": "itop-bridge-cmdb-ticket",
|
||||
"name": "itop-bridge-cmdb-ticket",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "360",
|
||||
"id": "360",
|
||||
"1": "itop-bridge-virtualization-storage",
|
||||
"name": "itop-bridge-virtualization-storage",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "361",
|
||||
"id": "361",
|
||||
"1": "itop-service-mgmt",
|
||||
"name": "itop-service-mgmt",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "362",
|
||||
"id": "362",
|
||||
"1": "itop-bridge-cmdb-services",
|
||||
"name": "itop-bridge-cmdb-services",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "363",
|
||||
"id": "363",
|
||||
"1": "itop-bridge-datacenter-mgmt-services",
|
||||
"name": "itop-bridge-datacenter-mgmt-services",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "364",
|
||||
"id": "364",
|
||||
"1": "itop-bridge-endusers-devices-services",
|
||||
"name": "itop-bridge-endusers-devices-services",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "365",
|
||||
"id": "365",
|
||||
"1": "itop-bridge-storage-mgmt-services",
|
||||
"name": "itop-bridge-storage-mgmt-services",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "366",
|
||||
"id": "366",
|
||||
"1": "itop-bridge-virtualization-mgmt-services",
|
||||
"name": "itop-bridge-virtualization-mgmt-services",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0",
|
||||
"comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "367",
|
||||
"id": "367",
|
||||
"1": "itop-request-mgmt",
|
||||
"name": "itop-request-mgmt",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "368",
|
||||
"id": "368",
|
||||
"1": "itop-portal",
|
||||
"name": "itop-portal",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "369",
|
||||
"id": "369",
|
||||
"1": "itop-change-mgmt",
|
||||
"name": "itop-change-mgmt",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
}
|
||||
]
|
||||
@@ -1,50 +0,0 @@
|
||||
[
|
||||
{
|
||||
"0": "330",
|
||||
"id": "330",
|
||||
"1": "iTop",
|
||||
"name": "iTop",
|
||||
"2": "3.3.0-dev-svn",
|
||||
"version": "3.3.0-dev-svn",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nBuilt on $WCNOW$",
|
||||
"comment": "Done by the setup program\nBuilt on $WCNOW$",
|
||||
"5": "0",
|
||||
"parent_id": "0",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "331",
|
||||
"id": "331",
|
||||
"1": "mandatory_module",
|
||||
"name": "mandatory_module",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nMandatory\nVisible (during the setup)",
|
||||
"comment": "Done by the setup program\nMandatory\nVisible (during the setup)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "yes"
|
||||
},
|
||||
{
|
||||
"0": "332",
|
||||
"id": "332",
|
||||
"1": "optional_module",
|
||||
"name": "optional_module",
|
||||
"2": "3.3.0",
|
||||
"version": "3.3.0",
|
||||
"3": "2025-11-10 11:50:12",
|
||||
"installed": "2025-11-10 11:50:12",
|
||||
"4": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"comment": "Done by the setup program\nOptional\nVisible (during the setup)",
|
||||
"5": "330",
|
||||
"parent_id": "330",
|
||||
"6": "yes",
|
||||
"uninstallable": "no"
|
||||
}
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
@@ -12,8 +12,10 @@ class CliResetSessionTest extends ItopDataTestCase
|
||||
public const USE_TRANSACTION = false;
|
||||
|
||||
private $sCookieFile = "";
|
||||
private $sUrl;
|
||||
private $sLogin;
|
||||
private $sPassword = "Iuytrez9876543ç_è-(";
|
||||
protected $sConfigTmpBackupFile;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
@@ -22,13 +24,16 @@ class CliResetSessionTest extends ItopDataTestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->BackupConfiguration();
|
||||
$this->sConfigTmpBackupFile = tempnam(sys_get_temp_dir(), "config_");
|
||||
MetaModel::GetConfig()->WriteToFile($this->sConfigTmpBackupFile);
|
||||
|
||||
$this->sLogin = "rest-user-".date('dmYHis');
|
||||
$this->CreateTestOrganization();
|
||||
|
||||
$this->sCookieFile = tempnam(sys_get_temp_dir(), 'jsondata_');
|
||||
|
||||
$this->sUrl = \MetaModel::GetConfig()->Get('app_root_url');
|
||||
|
||||
$oRestProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", ['name' => 'REST Services User'], true);
|
||||
$oAdminProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", ['name' => 'Administrator'], true);
|
||||
|
||||
@@ -42,6 +47,16 @@ class CliResetSessionTest extends ItopDataTestCase
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
if (! is_null($this->sConfigTmpBackupFile) && is_file($this->sConfigTmpBackupFile)) {
|
||||
//put config back
|
||||
$sConfigPath = MetaModel::GetConfig()->GetLoadedFile();
|
||||
@chmod($sConfigPath, 0770);
|
||||
$oConfig = new Config($this->sConfigTmpBackupFile);
|
||||
$oConfig->WriteToFile($sConfigPath);
|
||||
@chmod($sConfigPath, 0444);
|
||||
unlink($this->sConfigTmpBackupFile);
|
||||
}
|
||||
|
||||
if (!empty($this->sCookieFile)) {
|
||||
unlink($this->sCookieFile);
|
||||
}
|
||||
@@ -135,18 +150,26 @@ class CliResetSessionTest extends ItopDataTestCase
|
||||
*/
|
||||
private function SendHTTPRequestWithCookies($sUri, $aPostFields, $sForcedLoginMode = null): string
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_COOKIEJAR, $this->sCookieFile);
|
||||
curl_setopt($ch, CURLOPT_COOKIEFILE, $this->sCookieFile);
|
||||
|
||||
$sUrl = "$this->sUrl/$sUri";
|
||||
if (!is_null($sForcedLoginMode)) {
|
||||
$sUri .= "?login_mode=$sForcedLoginMode";
|
||||
$sUrl .= "?login_mode=$sForcedLoginMode";
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_URL, $sUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);// set post data to true
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
||||
// Force disable of certificate check as most of dev / test env have a self-signed certificate
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
|
||||
$aCurlOptions = [
|
||||
CURLOPT_COOKIEJAR => $this->sCookieFile,
|
||||
CURLOPT_COOKIEFILE => $this->sCookieFile,
|
||||
CURLOPT_HEADER => 1,
|
||||
];
|
||||
|
||||
$sResponse = $this->CallItopUri($sUri, $aPostFields, $aCurlOptions);
|
||||
var_dump($this->aLastCurlGetInfo);
|
||||
$sResponse = curl_exec($ch);
|
||||
/** $sResponse example
|
||||
* "HTTP/1.1 200 OK
|
||||
Date: Wed, 07 Jun 2023 05:00:40 GMT
|
||||
@@ -154,15 +177,16 @@ class CliResetSessionTest extends ItopDataTestCase
|
||||
Set-Cookie: itop-2e83d2e9b00e354fdc528621cac532ac=q7ldcjq0rvbn33ccr9q8u8e953; path=/
|
||||
*/
|
||||
//var_dump($sResponse);
|
||||
$iHeaderSize = $this->aLastCurlGetInfo['header_size'] ?? 0;
|
||||
$iHeaderSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$sBody = substr($sResponse, $iHeaderSize);
|
||||
|
||||
//$iHttpCode = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
|
||||
if (preg_match('/HTTP.* (\d*) /', $sResponse, $aMatches)) {
|
||||
$sHttpCode = $aMatches[1];
|
||||
} else {
|
||||
$sHttpCode = $this->aLastCurlGetInfo['http_code'] ?? -1;
|
||||
$sHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
$this->assertEquals(200, $sHttpCode, "The test logic assumes that the HTTP request is correctly handled");
|
||||
return $sBody;
|
||||
|
||||
@@ -17,6 +17,7 @@ class RestTest extends ItopDataTestCase
|
||||
public const USE_TRANSACTION = false;
|
||||
public const CREATE_TEST_ORG = false;
|
||||
|
||||
private static $sUrl;
|
||||
private static $sLogin;
|
||||
private static $sPassword = "Iuytrez9876543ç_è-(";
|
||||
|
||||
@@ -43,6 +44,7 @@ class RestTest extends ItopDataTestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
static::$sUrl = MetaModel::GetConfig()->Get('app_root_url');
|
||||
static::$sLogin = "rest-user-".date('dmYHis');
|
||||
|
||||
$this->CreateTestOrganization();
|
||||
@@ -94,6 +96,7 @@ class RestTest extends ItopDataTestCase
|
||||
|
||||
public function testPostJSONDataAsCurlFile()
|
||||
{
|
||||
$sCallbackName = 'fooCallback';
|
||||
$sJsonData = '{"operation": "list_operations"}';
|
||||
|
||||
// Test regular JSON result
|
||||
@@ -294,7 +297,16 @@ JSON;
|
||||
$aPostFields['callback'] = $sCallbackName;
|
||||
}
|
||||
|
||||
$sJson = $this->CallItopUri('webservices/rest.php', $aPostFields);
|
||||
curl_setopt($ch, CURLOPT_URL, static::$sUrl."/webservices/rest.php");
|
||||
curl_setopt($ch, CURLOPT_POST, 1);// set post data to true
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
// Force disable of certificate check as most of dev / test env have a self-signed certificate
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
|
||||
$sJson = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if (!is_null($sTmpFile)) {
|
||||
unlink($sTmpFile);
|
||||
|
||||
Reference in New Issue
Block a user