mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 07:12:26 +02:00
Merge branch 'develop' into feature/uninstallation
This commit is contained in:
15
.github/workflows/action.yml
vendored
15
.github/workflows/action.yml
vendored
@@ -1,9 +1,13 @@
|
|||||||
name: Add PRs to Combodo PRs Dashboard
|
name: Add PRs to Combodo PRs Dashboard
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
|
issues:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
add-to-project:
|
add-to-project:
|
||||||
@@ -31,23 +35,22 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/labels \
|
https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels \
|
||||||
-d '{"labels":["internal"]}'
|
-d '{"labels":["internal"]}'
|
||||||
|
|
||||||
- name: Set PR author as assignee if member of the organization
|
- name: Set PR author as assignee if member of the organization
|
||||||
if: env.is_member == 'true'
|
if: env.is_member == 'true' && github.event_name == 'pull_request'
|
||||||
run: |
|
run: |
|
||||||
curl -L \
|
curl -L \
|
||||||
-X POST \
|
-X POST \
|
||||||
-H "Accept: application/vnd.github+json" \
|
-H "Accept: application/vnd.github+json" \
|
||||||
-H "Authorization: Bearer ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
-H "Authorization: Bearer ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||||
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/assignees \
|
https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/assignees \
|
||||||
-d '{"assignees":["${{ github.event.pull_request.user.login }}"]}'
|
-d '{"assignees":["${{ github.event.pull_request.user.login }}"]}'
|
||||||
env:
|
env:
|
||||||
is_member: ${{ env.is_member }}
|
is_member: ${{ env.is_member }}
|
||||||
|
|
||||||
- name: Add PR to the appropriate project
|
- name: Add PR to the appropriate project
|
||||||
uses: actions/add-to-project@v1.0.2
|
uses: actions/add-to-project@v2
|
||||||
with:
|
with:
|
||||||
project-url: ${{ env.project_url }}
|
project-url: ${{ env.project_url }}
|
||||||
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
||||||
|
|||||||
@@ -658,6 +658,16 @@ abstract class User extends cmdbAbstractObject
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow a user to be impersonated by another one (generally an administrator) in order to troubleshoot rights issues.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function CanBeImpersonated(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1063,6 +1073,9 @@ class UserRights
|
|||||||
$oUser = self::FindUser($sLogin);
|
$oUser = self::FindUser($sLogin);
|
||||||
if ($oUser) {
|
if ($oUser) {
|
||||||
$bRet = true;
|
$bRet = true;
|
||||||
|
if (!$oUser->CanBeImpersonated()) {
|
||||||
|
throw new Exception($oUser->GetName().' cannot be impersonated');
|
||||||
|
}
|
||||||
if (is_null(self::$m_oRealUser)) {
|
if (is_null(self::$m_oRealUser)) {
|
||||||
// First impersonation
|
// First impersonation
|
||||||
self::$m_oRealUser = self::$m_oUser;
|
self::$m_oRealUser = self::$m_oUser;
|
||||||
|
|||||||
@@ -54,6 +54,15 @@
|
|||||||
</modules>
|
</modules>
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
</choice>
|
</choice>
|
||||||
|
<choice>
|
||||||
|
<extension_code>itop-flow-map</extension_code>
|
||||||
|
<title>Application Data Flows</title>
|
||||||
|
<description>Modelize flows between your applications, with impacts analysis</description>
|
||||||
|
<modules type="array">
|
||||||
|
<module>itop-flow-map</module>
|
||||||
|
</modules>
|
||||||
|
<default>true</default>
|
||||||
|
</choice>
|
||||||
<choice>
|
<choice>
|
||||||
<extension_code>itop-config-mgmt-storage</extension_code>
|
<extension_code>itop-config-mgmt-storage</extension_code>
|
||||||
<title>Storage Devices</title>
|
<title>Storage Devices</title>
|
||||||
@@ -80,11 +89,20 @@
|
|||||||
<modules type="array">
|
<modules type="array">
|
||||||
<module>itop-container-mgmt</module>
|
<module>itop-container-mgmt</module>
|
||||||
</modules>
|
</modules>
|
||||||
<default>false</default>
|
<default>true</default>
|
||||||
</choice>
|
</choice>
|
||||||
</options>
|
</options>
|
||||||
</sub_options>
|
</sub_options>
|
||||||
</choice>
|
</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>
|
</options>
|
||||||
</step>
|
</step>
|
||||||
<step>
|
<step>
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ Dict::Add('EN US', 'English', 'English', [
|
|||||||
|
|
||||||
Dict::Add('EN US', 'English', 'English', [
|
Dict::Add('EN US', 'English', 'English', [
|
||||||
'Class:Rack' => 'Rack',
|
'Class:Rack' => 'Rack',
|
||||||
'Class:Rack+' => 'A physical cabinet for Datacenter Devices and Chassis.',
|
'Class:Rack+' => 'A physical cabinet for Datacenter Devices and Enclosures.',
|
||||||
'Class:Rack/ComplementaryName' => '%1$s - %2$s',
|
'Class:Rack/ComplementaryName' => '%1$s - %2$s',
|
||||||
'Class:Rack/Attribute:nb_u' => 'Rack units',
|
'Class:Rack/Attribute:nb_u' => 'Rack units',
|
||||||
'Class:Rack/Attribute:nb_u+' => '',
|
'Class:Rack/Attribute:nb_u+' => '',
|
||||||
|
|||||||
@@ -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>
|
||||||
750
datamodels/2.x/itop-flow-map/datamodel.itop-flow-map.xml
Normal file
750
datamodels/2.x/itop-flow-map/datamodel.itop-flow-map.xml
Normal file
@@ -0,0 +1,750 @@
|
|||||||
|
<?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="dataflowtype_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>
|
||||||
|
<neighbour id="contact ">
|
||||||
|
<attribute>contacts_list</attribute>
|
||||||
|
<direction>down</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="if_exists">
|
||||||
|
<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_if_not_exists"/>
|
||||||
|
</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 |
50
datamodels/2.x/itop-flow-map/module.itop-flow-map.php
Normal file
50
datamodels/2.x/itop-flow-map/module.itop-flow-map.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
//
|
||||||
|
// iTop module definition file
|
||||||
|
//
|
||||||
|
|
||||||
|
SetupWebPage::AddModule(
|
||||||
|
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||||
|
'itop-flow-map/3.3.0',
|
||||||
|
[
|
||||||
|
// Identification
|
||||||
|
//
|
||||||
|
'label' => 'Applications data flows',
|
||||||
|
'category' => 'business',
|
||||||
|
|
||||||
|
// Setup
|
||||||
|
//
|
||||||
|
'dependencies' => [
|
||||||
|
'itop-config-mgmt/3.2.0',
|
||||||
|
],
|
||||||
|
'mandatory' => false,
|
||||||
|
'visible' => true,
|
||||||
|
|
||||||
|
// Components
|
||||||
|
//
|
||||||
|
'datamodel' => [
|
||||||
|
|
||||||
|
],
|
||||||
|
'webservice' => [
|
||||||
|
|
||||||
|
],
|
||||||
|
'data.struct' => [
|
||||||
|
'data/en_us.data.itop-flow-map.xml',
|
||||||
|
],
|
||||||
|
'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
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
@@ -153,8 +153,12 @@ class Extension
|
|||||||
return twig_array_filter($oTwigEnv, $array, $arrow);
|
return twig_array_filter($oTwigEnv, $array, $arrow);
|
||||||
}, ['needs_environment' => true]);
|
}, ['needs_environment' => true]);
|
||||||
|
|
||||||
// @since 3.3.0 N°8579
|
/**
|
||||||
// Filter to remove spaces between HTML tags, overwrite the deprecated core "spaceless" filter
|
* Filter to remove spaces between HTML tags, overwrite the deprecated core "spaceless" filter
|
||||||
|
* Usage in twig: {% apply spaceless %}some html{% endapply %}
|
||||||
|
*
|
||||||
|
* @since 3.2.3 3.3.0 N°8579
|
||||||
|
*/
|
||||||
$aFilters[] = new TwigFilter('spaceless', function (?string $content) {
|
$aFilters[] = new TwigFilter('spaceless', function (?string $content) {
|
||||||
return trim(preg_replace('/>\s+</', '><', $content ?? ''));
|
return trim(preg_replace('/>\s+</', '><', $content ?? ''));
|
||||||
}, ['is_safe' => ['html']]);
|
}, ['is_safe' => ['html']]);
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ use Symfony\Component\CssSelector\Exception\ParseException;
|
|||||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||||
use Symfony\Component\Mailer\Transport;
|
use Symfony\Component\Mailer\Transport;
|
||||||
use Symfony\Component\Mailer\Mailer;
|
use Symfony\Component\Mailer\Mailer;
|
||||||
|
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
|
||||||
use Symfony\Component\Mime\Email as SymfonyEmail;
|
use Symfony\Component\Mime\Email as SymfonyEmail;
|
||||||
|
use Symfony\Component\Mime\HtmlToTextConverter\DefaultHtmlToTextConverter;
|
||||||
use Symfony\Component\Mime\Part\DataPart;
|
use Symfony\Component\Mime\Part\DataPart;
|
||||||
use Symfony\Component\Mime\Part\Multipart\RelatedPart;
|
use Symfony\Component\Mime\Part\Multipart\RelatedPart;
|
||||||
use Symfony\Component\Mime\Part\Multipart\MixedPart;
|
use Symfony\Component\Mime\Part\Multipart\MixedPart;
|
||||||
@@ -183,18 +185,7 @@ class EMailSymfony extends Email
|
|||||||
$sDsn = sprintf('smtp://%s%s@%s%s', $sDsnUser, $sDsnPassword, $sDsnPort, $sEncQuery);
|
$sDsn = sprintf('smtp://%s%s@%s%s', $sDsnUser, $sDsnPassword, $sDsnPort, $sEncQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
$oTransport = Transport::fromDsn($sDsn);
|
$oTransport = $this->CreateSmtpTransport($sDsn, $bVerifyPeer);
|
||||||
|
|
||||||
// Handle peer verification
|
|
||||||
$oStream = $oTransport->getStream();
|
|
||||||
$aOptions = $oStream->getStreamOptions();
|
|
||||||
if (!$bVerifyPeer && array_key_exists('ssl', $aOptions)) {
|
|
||||||
// Disable verification
|
|
||||||
$aOptions['ssl']['verify_peer'] = false;
|
|
||||||
$aOptions['ssl']['verify_peer_name'] = false;
|
|
||||||
$aOptions['ssl']['allow_self_signed'] = true;
|
|
||||||
}
|
|
||||||
$oStream->setStreamOptions($aOptions);
|
|
||||||
|
|
||||||
$oMailer = new Mailer($oTransport);
|
$oMailer = new Mailer($oTransport);
|
||||||
break;
|
break;
|
||||||
@@ -260,6 +251,36 @@ class EMailSymfony extends Email
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build and configure an SMTP transport from a DSN string.
|
||||||
|
*
|
||||||
|
* Extracted from {@see SendSynchronous} to make SSL option handling independently testable.
|
||||||
|
* When $bVerifyPeer is false, the ssl stream context options must be written unconditionally:
|
||||||
|
* with STARTTLS the connection starts unencrypted, so the 'ssl' key is absent from the stream
|
||||||
|
* options at construction time and only used later when stream_socket_enable_crypto() is called.
|
||||||
|
*
|
||||||
|
* @param string $sDsn Full Symfony Mailer DSN (smtp:// or smtps://)
|
||||||
|
* @param bool $bVerifyPeer Whether to verify the peer SSL certificate
|
||||||
|
*
|
||||||
|
* @return \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport
|
||||||
|
*/
|
||||||
|
protected function CreateSmtpTransport(string $sDsn, bool $bVerifyPeer): EsmtpTransport
|
||||||
|
{
|
||||||
|
/** @var EsmtpTransport $oTransport */
|
||||||
|
$oTransport = Transport::fromDsn($sDsn);
|
||||||
|
|
||||||
|
$oStream = $oTransport->getStream();
|
||||||
|
$aOptions = $oStream->getStreamOptions();
|
||||||
|
if (!$bVerifyPeer) {
|
||||||
|
$aOptions['ssl']['verify_peer'] = false;
|
||||||
|
$aOptions['ssl']['verify_peer_name'] = false;
|
||||||
|
$aOptions['ssl']['allow_self_signed'] = true;
|
||||||
|
}
|
||||||
|
$oStream->setStreamOptions($aOptions);
|
||||||
|
|
||||||
|
return $oTransport;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reprocess the body of the message (if it is an HTML message)
|
* Reprocess the body of the message (if it is an HTML message)
|
||||||
* to replace the URL of images based on attachments by a link
|
* to replace the URL of images based on attachments by a link
|
||||||
@@ -416,13 +437,13 @@ class EMailSymfony extends Email
|
|||||||
|
|
||||||
$this->m_aData['body'] = ['body' => $sBody, 'mimeType' => $sMimeType];
|
$this->m_aData['body'] = ['body' => $sBody, 'mimeType' => $sMimeType];
|
||||||
|
|
||||||
$oTextPart = new TextPart(strip_tags($sBody), 'utf-8', 'plain', 'base64');
|
|
||||||
|
|
||||||
// Embed inline images and store them in attachments (so BuildSymfonyMessageFromInternal can pick them)
|
// Embed inline images and store them in attachments (so BuildSymfonyMessageFromInternal can pick them)
|
||||||
if ($sPrimaryMimeType === 'text/html') {
|
if ($sPrimaryMimeType === 'text/html') {
|
||||||
$aAdditionalParts = $this->EmbedInlineImages($sBody);
|
$aAdditionalParts = $this->EmbedInlineImages($sBody);
|
||||||
|
$oTextPart = new TextPart((new DefaultHtmlToTextConverter())->convert($sBody, 'utf-8'), 'utf-8', 'plain', 'base64');
|
||||||
$oHtmlPart = new TextPart($sBody, 'utf-8', 'html', 'base64');
|
$oHtmlPart = new TextPart($sBody, 'utf-8', 'html', 'base64');
|
||||||
$oAlternativePart = new AlternativePart($oHtmlPart, $oTextPart);
|
// It's important de order parts from least prefered to most prefered as per RFC 2046 {@see https://www.rfc-editor.org/rfc/rfc2046.html#section-5.1.4}
|
||||||
|
$oAlternativePart = new AlternativePart($oTextPart, $oHtmlPart);
|
||||||
// Default root part is the HTML body
|
// Default root part is the HTML body
|
||||||
$oRootPart = $oAlternativePart;
|
$oRootPart = $oAlternativePart;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Combodo\iTop\Core\Email\EMailSymfony;
|
||||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
|
||||||
|
use Symfony\Component\Mime\Part\DataPart;
|
||||||
|
use Symfony\Component\Mime\Part\Multipart\AlternativePart;
|
||||||
|
use Symfony\Component\Mime\Part\Multipart\RelatedPart;
|
||||||
|
use Symfony\Component\Mime\Part\TextPart;
|
||||||
|
|
||||||
class EmailSymfonyTest extends ItopTestCase
|
class EmailSymfonyTest extends ItopTestCase
|
||||||
{
|
{
|
||||||
@@ -135,4 +141,221 @@ HTML;
|
|||||||
|
|
||||||
$this->assertSame($sExpectedBody, $sActualBody);
|
$this->assertSame($sExpectedBody, $sActualBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parts of the AlternativePart produced by SetBody() for an HTML email.
|
||||||
|
*
|
||||||
|
* Handles both the simple case (AlternativePart at root) and the inline-images case
|
||||||
|
* where the root is a RelatedPart whose first child is the AlternativePart.
|
||||||
|
*
|
||||||
|
* @return AbstractPart[]
|
||||||
|
*/
|
||||||
|
private function GetAlternativePartsFromHtmlEmail(EMailSymfony $oEmail): array
|
||||||
|
{
|
||||||
|
$oSymfonyMessage = $this->GetNonPublicProperty($oEmail, 'm_oMessage');
|
||||||
|
$oBody = $oSymfonyMessage->getBody();
|
||||||
|
|
||||||
|
// With inline images the root is a RelatedPart; the AlternativePart is its first child.
|
||||||
|
if ($oBody instanceof RelatedPart) {
|
||||||
|
$oBody = $oBody->getParts()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertInstanceOf(AlternativePart::class, $oBody, 'Body should be a multipart/alternative for HTML emails');
|
||||||
|
|
||||||
|
return $oBody->getParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RFC 2046 §5.1.4: parts in multipart/alternative must be ordered from least to most preferred.
|
||||||
|
* Email clients display the last part they support, so text/plain must come first and text/html last.
|
||||||
|
*
|
||||||
|
* @see https://www.rfc-editor.org/rfc/rfc2046.html#section-5.1.4
|
||||||
|
* @covers \Combodo\iTop\Core\Email\EmailSymfony::SetBody()
|
||||||
|
* @since N°9574
|
||||||
|
*/
|
||||||
|
public function testSetBodyAlternativePartOrderForHtmlEmailIsPlainThenHtml(): void
|
||||||
|
{
|
||||||
|
$oEmail = new EMailSymfony();
|
||||||
|
$oEmail->SetBody('<p>Hello there!</p>', 'text/html');
|
||||||
|
|
||||||
|
[$oFirstPart, $oSecondPart] = $this->GetAlternativePartsFromHtmlEmail($oEmail);
|
||||||
|
|
||||||
|
$this->assertSame('plain', $oFirstPart->getMediaSubtype(), 'First part must be text/plain (least preferred per RFC 2046)');
|
||||||
|
$this->assertSame('html', $oSecondPart->getMediaSubtype(), 'Last part must be text/html (most preferred per RFC 2046)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideSetBodyPlainTextDoesNotContainCss
|
||||||
|
*
|
||||||
|
* @covers \Combodo\iTop\Core\Email\EmailSymfony::SetBody()
|
||||||
|
* @since N°9574
|
||||||
|
*/
|
||||||
|
public function testSetBodyPlainTextDoesNotContainCss(string $sHtml, ?string $sCustomStyles): void
|
||||||
|
{
|
||||||
|
$oEmail = new EMailSymfony();
|
||||||
|
$oEmail->SetBody($sHtml, 'text/html', $sCustomStyles);
|
||||||
|
|
||||||
|
// We locate the plain text part by subtype to be order-agnostic and isolate this assertion from the order bug.
|
||||||
|
$aParts = $this->GetAlternativePartsFromHtmlEmail($oEmail);
|
||||||
|
$oPlainPart = null;
|
||||||
|
foreach ($aParts as $oPart) {
|
||||||
|
if ($oPart instanceof TextPart && $oPart->getMediaSubtype() === 'plain') {
|
||||||
|
$oPlainPart = $oPart;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->assertNotNull($oPlainPart, 'No text/plain part found in the message');
|
||||||
|
|
||||||
|
$sPlainText = $oPlainPart->getBody();
|
||||||
|
|
||||||
|
$this->assertStringNotContainsString('<style>', $sPlainText, 'Style tag must not appear in plain text');
|
||||||
|
$this->assertStringNotContainsString('color:', $sPlainText, 'CSS color rule must not appear in plain text');
|
||||||
|
$this->assertStringNotContainsString('font-size:', $sPlainText, 'CSS font-size rule must not appear in plain text');
|
||||||
|
$this->assertStringNotContainsString('@media', $sPlainText, 'CSS @media rule must not appear in plain text');
|
||||||
|
$this->assertStringContainsString('Hello there!', $sPlainText, 'Actual content must be preserved in plain text');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTML part must contain the body content and the CSS inlined by Emogrifier.
|
||||||
|
* This guards against regressions where the wrong body (e.g. the plain-text version)
|
||||||
|
* would end up in the HTML part.
|
||||||
|
*
|
||||||
|
* @covers \Combodo\iTop\Core\Email\EmailSymfony::SetBody()
|
||||||
|
* @since N°9574
|
||||||
|
*/
|
||||||
|
public function testSetBodyHtmlPartContainsBodyAndInlinedCss(): void
|
||||||
|
{
|
||||||
|
$oEmail = new EMailSymfony();
|
||||||
|
$oEmail->SetBody('<html><body><p>Hello there!</p></body></html>', 'text/html', 'p { color: red; }');
|
||||||
|
|
||||||
|
$aParts = $this->GetAlternativePartsFromHtmlEmail($oEmail);
|
||||||
|
|
||||||
|
$oHtmlPart = null;
|
||||||
|
foreach ($aParts as $oPart) {
|
||||||
|
if ($oPart instanceof TextPart && $oPart->getMediaSubtype() === 'html') {
|
||||||
|
$oHtmlPart = $oPart;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->assertNotNull($oHtmlPart, 'No text/html part found in the message');
|
||||||
|
|
||||||
|
$sHtmlContent = $oHtmlPart->getBody();
|
||||||
|
$this->assertStringContainsString('Hello there!', $sHtmlContent, 'HTML part must preserve the original text content');
|
||||||
|
$this->assertStringContainsString('color: red', $sHtmlContent, 'HTML part must contain the CSS inlined by Emogrifier');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* With inline images, SetBody() wraps the AlternativePart in a RelatedPart.
|
||||||
|
* The AlternativePart must still be correctly ordered (plain first, HTML last)
|
||||||
|
* and the plain-text part must not contain CSS.
|
||||||
|
*
|
||||||
|
* @see https://www.rfc-editor.org/rfc/rfc2046.html#section-5.1.4
|
||||||
|
* @covers \Combodo\iTop\Core\Email\EmailSymfony::SetBody()
|
||||||
|
* @since N°9574
|
||||||
|
*/
|
||||||
|
public function testSetBodyWithInlineImagesHasCorrectPartStructure(): void
|
||||||
|
{
|
||||||
|
// Anonymous subclass so we can inject a fake inline image part without a real inline image in DB
|
||||||
|
$oEmail = new class () extends EMailSymfony {
|
||||||
|
protected function EmbedInlineImages(string &$sBody): array
|
||||||
|
{
|
||||||
|
return [new DataPart('fake-image-data', 'image.png', 'image/png')];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$oEmail->SetBody('<html><head><style>p { color: red; }</style></head><body><p>Hello there!</p></body></html>', 'text/html');
|
||||||
|
|
||||||
|
$oSymfonyMessage = $this->GetNonPublicProperty($oEmail, 'm_oMessage');
|
||||||
|
$oBody = $oSymfonyMessage->getBody();
|
||||||
|
|
||||||
|
// Root must be a RelatedPart when inline images are present
|
||||||
|
$this->assertInstanceOf(RelatedPart::class, $oBody, 'Root part must be multipart/related when inline images are present');
|
||||||
|
|
||||||
|
// The AlternativePart must be the first child of the RelatedPart
|
||||||
|
$aRelatedParts = $oBody->getParts();
|
||||||
|
$this->assertInstanceOf(AlternativePart::class, $aRelatedParts[0], 'First child of RelatedPart must be the AlternativePart');
|
||||||
|
|
||||||
|
// Order and CSS checks are delegated to the shared helper, which now handles RelatedPart
|
||||||
|
[$oFirstPart, $oSecondPart] = $this->GetAlternativePartsFromHtmlEmail($oEmail);
|
||||||
|
$this->assertSame('plain', $oFirstPart->getMediaSubtype(), 'First part must be text/plain (least preferred per RFC 2046)');
|
||||||
|
$this->assertSame('html', $oSecondPart->getMediaSubtype(), 'Last part must be text/html (most preferred per RFC 2046)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideSetBodyPlainTextDoesNotContainCss(): array
|
||||||
|
{
|
||||||
|
$sCustomStyles = 'p { color: blue; font-size: 14px; }';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'<style> tag in HTML, no custom styles' => [
|
||||||
|
'<html><head><style>body { color: red; font-size: 12px; } @media print { p { color: black; } }</style></head><body><p>Hello there!</p></body></html>',
|
||||||
|
null,
|
||||||
|
],
|
||||||
|
'<style> tag in HTML with custom styles' => [
|
||||||
|
'<html><head><style>body { color: red; font-size: 12px; } @media print { p { color: black; } }</style></head><body><p>Hello there!</p></body></html>',
|
||||||
|
$sCustomStyles,
|
||||||
|
],
|
||||||
|
'custom styles only, no <style> tag' => [
|
||||||
|
'<html><body><p>Hello there!</p></body></html>',
|
||||||
|
$sCustomStyles,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideCreateSmtpTransportSslOptions
|
||||||
|
*/
|
||||||
|
public function testCreateSmtpTransportSslOptions(string $sDsn, bool $bVerifyPeer, array $aExpectedSslOptions): void
|
||||||
|
{
|
||||||
|
$oEmail = new EMailSymfony();
|
||||||
|
/** @var EsmtpTransport $oTransport */
|
||||||
|
$oTransport = $this->InvokeNonPublicMethod(EMailSymfony::class, 'CreateSmtpTransport', $oEmail, [$sDsn, $bVerifyPeer]);
|
||||||
|
|
||||||
|
$aActualSslOptions = $oTransport->getStream()->getStreamOptions()['ssl'] ?? [];
|
||||||
|
|
||||||
|
$this->assertSame($aExpectedSslOptions, $aActualSslOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideCreateSmtpTransportSslOptions(): array
|
||||||
|
{
|
||||||
|
$aDisabledVerification = [
|
||||||
|
'verify_peer' => false,
|
||||||
|
'verify_peer_name' => false,
|
||||||
|
'allow_self_signed' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
return [
|
||||||
|
// Regression scenario (N°9584): STARTTLS starts the connection unencrypted, so the 'ssl' key
|
||||||
|
// is absent from stream options at construction time. verify_peer=false must still be applied.
|
||||||
|
'STARTTLS, verify_peer=false' => [
|
||||||
|
'smtp://localhost:587?encryption=starttls',
|
||||||
|
false,
|
||||||
|
$aDisabledVerification,
|
||||||
|
],
|
||||||
|
'implicit TLS (smtps), verify_peer=false' => [
|
||||||
|
'smtps://localhost:465',
|
||||||
|
false,
|
||||||
|
$aDisabledVerification,
|
||||||
|
],
|
||||||
|
'plain SMTP, verify_peer=false' => [
|
||||||
|
'smtp://localhost:25',
|
||||||
|
false,
|
||||||
|
$aDisabledVerification,
|
||||||
|
],
|
||||||
|
// Default behavior: verify_peer=true must leave stream options untouched (empty).
|
||||||
|
'STARTTLS, verify_peer=true (default)' => [
|
||||||
|
'smtp://localhost:587?encryption=starttls',
|
||||||
|
true,
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
'implicit TLS (smtps), verify_peer=true (default)' => [
|
||||||
|
'smtps://localhost:465',
|
||||||
|
true,
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
'plain SMTP, verify_peer=true (default)' => [
|
||||||
|
'smtp://localhost:25',
|
||||||
|
true,
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user