mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-11 20:14:14 +01:00
Compare commits
131 Commits
feature/77
...
feature/87
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26561ed831 | ||
|
|
b35dca7150 | ||
|
|
781be345b8 | ||
|
|
4895f953eb | ||
|
|
19bbf6759b | ||
|
|
c4ba1564ec | ||
|
|
9fb06bc00a | ||
|
|
74e430bdba | ||
|
|
e71e686509 | ||
|
|
be3ef66f03 | ||
|
|
d336090fbd | ||
|
|
69725ee1b4 | ||
|
|
1437eff77d | ||
|
|
5ddcd278de | ||
|
|
cbda1a452c | ||
|
|
64f5e0c037 | ||
|
|
f6664862b5 | ||
|
|
ab691c3ae6 | ||
|
|
2b976797dc | ||
|
|
862da59e8b | ||
|
|
5a9d3fee48 | ||
|
|
8e43a69f88 | ||
|
|
db3933aa71 | ||
|
|
f0629724ea | ||
|
|
9b6d321ab0 | ||
|
|
329191aa47 | ||
|
|
6915df1409 | ||
|
|
fd68558d1c | ||
|
|
bd9129dee2 | ||
|
|
fe34a6f9c3 | ||
|
|
24aec0d08d | ||
|
|
a287527d29 | ||
|
|
a42b061f19 | ||
|
|
c4d7c89553 | ||
|
|
5b58e40fc9 | ||
|
|
2b21556c76 | ||
|
|
77626f8159 | ||
|
|
bb6248a6e7 | ||
|
|
130d98aa3f | ||
|
|
00c590232a | ||
|
|
97828225db | ||
|
|
03e59c9749 | ||
|
|
985a49dc9f | ||
|
|
adae35ccc4 | ||
|
|
f0c9629f5f | ||
|
|
4e96b297c2 | ||
|
|
ae620c6663 | ||
|
|
b5c51a2983 | ||
|
|
3b2d845c00 | ||
|
|
36c545a6c4 | ||
|
|
5ecb4936f0 | ||
|
|
af2c3b02bc | ||
|
|
cfc933b92b | ||
|
|
0582ae1038 | ||
|
|
13c18b611c | ||
|
|
8d2e0761e0 | ||
|
|
1e15eb1161 | ||
|
|
7df59427cb | ||
|
|
d647d92acf | ||
|
|
693e40b9c7 | ||
|
|
c3c2135ecc | ||
|
|
63e473e6d0 | ||
|
|
3a3f5736c0 | ||
|
|
0996e8fae0 | ||
|
|
43bd621731 | ||
|
|
d1e91087b9 | ||
|
|
73cb58a131 | ||
|
|
d1fde89129 | ||
|
|
1f4b96798a | ||
|
|
9768ffb19d | ||
|
|
e55bbf728b | ||
|
|
5f2604c610 | ||
|
|
57b3610100 | ||
|
|
9f3b8ec964 | ||
|
|
193c980057 | ||
|
|
fdfe9224c3 | ||
|
|
774fe22ece | ||
|
|
27b0f64328 | ||
|
|
8ad4670a2f | ||
|
|
f2e682c07c | ||
|
|
83973d102f | ||
|
|
85e28931f5 | ||
|
|
d33ca81198 | ||
|
|
1ef4462517 | ||
|
|
a2b0ad6c11 | ||
|
|
7844c9ffd0 | ||
|
|
1c45a4c49e | ||
|
|
8f47ca00a7 | ||
|
|
f9a1b444ab | ||
|
|
3b38dac8c6 | ||
|
|
3d46fe6ef1 | ||
|
|
4dba47798c | ||
|
|
9480c4053d | ||
|
|
b967fb7f20 | ||
|
|
9ea197148c | ||
|
|
49a7f3118d | ||
|
|
195038c941 | ||
|
|
bf80b5dca2 | ||
|
|
09afcb229c | ||
|
|
92f843f676 | ||
|
|
3df4ddc696 | ||
|
|
d552727c55 | ||
|
|
1fe401c102 | ||
|
|
a4b0b6e855 | ||
|
|
9a8d87e2b5 | ||
|
|
545028d68a | ||
|
|
6cb08ba361 | ||
|
|
b3cd79605d | ||
|
|
f9db405343 | ||
|
|
4f1f144c51 | ||
|
|
ef8ade5d20 | ||
|
|
cef4a52081 | ||
|
|
dc9fb2d693 | ||
|
|
e9ffbe5b09 | ||
|
|
9c792a601f | ||
|
|
cda6c1dfa8 | ||
|
|
0b242d872a | ||
|
|
c144c80663 | ||
|
|
d9261b8342 | ||
|
|
385302c44c | ||
|
|
b563f113d0 | ||
|
|
715d9d3b1c | ||
|
|
7a6c2bc6a4 | ||
|
|
8919184ef9 | ||
|
|
7bfaebe4db | ||
|
|
8e10cf9b72 | ||
|
|
9f3d7d2c36 | ||
|
|
ae980e365d | ||
|
|
a2b01b3ed4 | ||
|
|
9cdc707bc5 | ||
|
|
76178c16b8 |
@@ -16,5 +16,5 @@ require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.domain.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.rule.class.inc.php');
|
||||
require_once(APPROOT.'/application/query.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstallation/moduleinstallation.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
@@ -24,7 +24,7 @@ MetaModel::IncludeModule('application/user.dashboard.class.inc.php');
|
||||
MetaModel::IncludeModule('application/audit.rule.class.inc.php');
|
||||
MetaModel::IncludeModule('application/audit.domain.class.inc.php');
|
||||
MetaModel::IncludeModule('application/query.class.inc.php');
|
||||
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
|
||||
MetaModel::IncludeModule('setup/moduleinstallation/moduleinstallation.class.inc.php');
|
||||
|
||||
MetaModel::IncludeModule('core/event.class.inc.php');
|
||||
MetaModel::IncludeModule('core/action.class.inc.php');
|
||||
|
||||
@@ -2418,6 +2418,7 @@ class Config
|
||||
public function SetAllowedLoginTypes($aAllowedLoginTypes)
|
||||
{
|
||||
$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
|
||||
$this->Set('allowed_login_types', implode('|', $aAllowedLoginTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2684,14 +2685,13 @@ class Config
|
||||
*
|
||||
* @param array $aParamValues
|
||||
* @param ?string $sModulesDir
|
||||
* @param bool $bPreserveModuleSettings
|
||||
*
|
||||
* @return void The current object is modified directly
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false)
|
||||
public function UpdateFromParams($aParamValues, $sModulesDir = null)
|
||||
{
|
||||
if (isset($aParamValues['application_path'])) {
|
||||
$this->Set('app_root_url', $aParamValues['application_path']);
|
||||
@@ -2739,7 +2739,10 @@ class Config
|
||||
} else {
|
||||
$aSelectedModules = null;
|
||||
}
|
||||
$this->UpdateIncludes($sModulesDir, $aSelectedModules);
|
||||
|
||||
if (! is_null($sModulesDir)) {
|
||||
$this->UpdateIncludes($sModulesDir, $aSelectedModules);
|
||||
}
|
||||
|
||||
if (isset($aParamValues['source_dir'])) {
|
||||
$this->Set('source_dir', $aParamValues['source_dir']);
|
||||
@@ -2757,17 +2760,13 @@ class Config
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function UpdateIncludes($sModulesDir, $aSelectedModules = null)
|
||||
public function UpdateIncludes(string $sModulesDir, $aSelectedModules = null)
|
||||
{
|
||||
if ($sModulesDir === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the arrays below with default values for the application...
|
||||
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
|
||||
$aAddOns = $oEmptyConfig->GetAddOns();
|
||||
|
||||
$aModules = ModuleDiscovery::GetAvailableModules([APPROOT.$sModulesDir]);
|
||||
$aModules = ModuleDiscovery::GetModulesOrderedByDependencies([APPROOT.$sModulesDir]);
|
||||
foreach ($aModules as $sModuleId => $aModuleInfo) {
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules)) {
|
||||
|
||||
@@ -5108,8 +5108,8 @@ abstract class DBObject implements iDisplay
|
||||
protected function GetReferencingObjectsForDeletion($bAllowAllData = false)
|
||||
{
|
||||
$aDependentObjects = [];
|
||||
$aRererencingMe = MetaModel::EnumReferencingClasses(get_class($this));
|
||||
foreach ($aRererencingMe as $sRemoteClass => $aExtKeys) {
|
||||
$aReferencingMe = MetaModel::EnumReferencingClasses(get_class($this));
|
||||
foreach ($aReferencingMe as $sRemoteClass => $aExtKeys) {
|
||||
/** @var \AttributeExternalKey $oExtKeyAttDef */
|
||||
foreach ($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef) {
|
||||
// skip if external key doesn't require the deletion cascading
|
||||
|
||||
@@ -22,6 +22,8 @@ use Combodo\iTop\Application\EventRegister\ApplicationEvents;
|
||||
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
||||
use Combodo\iTop\Service\Events\EventData;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
use Combodo\iTop\Setup\ModuleDependency\Module;
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader;
|
||||
|
||||
require_once APPROOT.'core/modulehandler.class.inc.php';
|
||||
require_once APPROOT.'core/querymodifier.class.inc.php';
|
||||
@@ -462,6 +464,43 @@ abstract class MetaModel
|
||||
return call_user_func([$sClass, 'GetClassDescription'], $sClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final public static function GetModuleName($sClass)
|
||||
{
|
||||
try {
|
||||
$oReflectionClass = new ReflectionClass($sClass);
|
||||
$sDir = realpath(dirname($oReflectionClass->getFileName()));
|
||||
$sApproot = realpath(APPROOT);
|
||||
while (($sDir !== $sApproot) && (str_contains($sDir, $sApproot))) {
|
||||
$aFiles = glob("$sDir/module.*.php");
|
||||
if (count($aFiles) > 1) {
|
||||
return 'core';
|
||||
}
|
||||
|
||||
if (count($aFiles) == 0) {
|
||||
$sDir = realpath(dirname($sDir));
|
||||
continue;
|
||||
}
|
||||
|
||||
$sModuleFilePath = $aFiles[0];
|
||||
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath);
|
||||
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
|
||||
list($sModuleName, ) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
|
||||
return $sModuleName;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new CoreException("Cannot find class module", ['class' => $sClass], '', $e);
|
||||
}
|
||||
|
||||
return 'core';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
|
||||
@@ -22,4 +22,5 @@
|
||||
@import "medallion-with-blocklist";
|
||||
@import "field-badge-within-datatable";
|
||||
@import "jquery-blockui-within-dialog";
|
||||
@import "jquery-blockui-within-datatable";
|
||||
@import "jquery-blockui-within-datatable";
|
||||
@import "badge-with-badge";
|
||||
10
css/backoffice/blocks-integrations/_badge-with-badge.scss
Normal file
10
css/backoffice/blocks-integrations/_badge-with-badge.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-badge--spacing-left--with-same-block: $ibo-spacing-200 !default;
|
||||
|
||||
.ibo-badge + .ibo-badge {
|
||||
margin-left: $ibo-badge--spacing-left--with-same-block;
|
||||
}
|
||||
@@ -33,4 +33,5 @@
|
||||
@import "field-badge";
|
||||
@import "file-select";
|
||||
@import "medallion-icon";
|
||||
@import "toast";
|
||||
@import "toast";
|
||||
@import "badge";
|
||||
41
css/backoffice/components/_badge.scss
Normal file
41
css/backoffice/components/_badge.scss
Normal file
@@ -0,0 +1,41 @@
|
||||
$ibo-badge--padding-x : $ibo-spacing-200 !default;
|
||||
$ibo-badge--padding-y : $ibo-spacing-100 !default;
|
||||
$ibo-badge--border-radius : $ibo-border-radius-400 !default;
|
||||
|
||||
$ibo-badge-colors: (
|
||||
'primary': ($ibo-color-primary-100, $ibo-color-primary-900),
|
||||
'secondary': ($ibo-color-secondary-100, $ibo-color-secondary-900),
|
||||
'neutral': ($ibo-color-secondary-100, $ibo-color-secondary-900),
|
||||
'information': ($ibo-color-information-100, $ibo-color-information-900),
|
||||
'success': ($ibo-color-success-100, $ibo-color-success-900),
|
||||
'failure': ($ibo-color-danger-100, $ibo-color-danger-900),
|
||||
'warning': ($ibo-color-warning-100,$ibo-color-warning-900),
|
||||
'danger': ($ibo-color-danger-100,$ibo-color-danger-900),
|
||||
'grey' : ($ibo-color-grey-100, $ibo-color-grey-900),
|
||||
'blue-grey': ($ibo-color-blue-grey-100, $ibo-color-blue-grey-900),
|
||||
'blue': ($ibo-color-blue-100, $ibo-color-blue-900),
|
||||
'cyan': ($ibo-color-cyan-100, $ibo-color-cyan-900),
|
||||
'green': ($ibo-color-green-100, $ibo-color-green-900),
|
||||
'orange' : ($ibo-color-orange-100, $ibo-color-orange-900),
|
||||
'red': ($ibo-color-red-100, $ibo-color-red-900),
|
||||
'pink': ($ibo-color-pink-100, $ibo-color-pink-900),
|
||||
) !default;
|
||||
|
||||
|
||||
|
||||
.ibo-badge {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
padding : $ibo-badge--padding-y $ibo-badge--padding-x;
|
||||
border-radius : $ibo-badge--border-radius;
|
||||
@extend %ibo-font-ral-med-50;
|
||||
|
||||
@each $sColor, $aColorValues in $ibo-badge-colors {
|
||||
$bg-color: nth($aColorValues, 1);
|
||||
$text-color: nth($aColorValues, 2);
|
||||
&.ibo-is-#{$sColor} {
|
||||
background-color: $bg-color;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ $ibo-toggler--wrapper--height: 20px !default;
|
||||
|
||||
$ibo-toggler--slider--border-radius: $ibo-border-radius-900 !default;
|
||||
$ibo-toggler--slider--background-color: $ibo-color-secondary-600 !default;
|
||||
$ibo-toggler--slider--disabled--background-color: $ibo-color-secondary-200 !default;
|
||||
|
||||
$ibo-toggler--slider--before--left: 3px !default;
|
||||
$ibo-toggler--slider--before--bottom: 3px !default;
|
||||
@@ -17,6 +18,7 @@ $ibo-toggler--slider--before--border-radius: $ibo-border-radius-full !default;
|
||||
$ibo-toggler--slider--before--background-color: $ibo-color-grey-100 !default;
|
||||
|
||||
$ibo-toggler--slider--checked--background-color: $ibo-color-primary-600 !default;
|
||||
$ibo-toggler--slider--checked-disabled--background-color: $ibo-color-primary-200 !default;
|
||||
$ibo-toggler--slider--focus--box-shadow: 0 0 1px $ibo-color-primary-600 !default;
|
||||
|
||||
$ibo-toggler--label--margin-left: 4px !default;
|
||||
@@ -61,6 +63,13 @@ $ibo-toggler--label--margin-left: 4px !default;
|
||||
background-color: $ibo-toggler--slider--checked--background-color;
|
||||
}
|
||||
|
||||
.ibo-toggler--wrapper input:disabled + .ibo-toggler--slider {
|
||||
background-color: $ibo-toggler--slider--disabled--background-color;
|
||||
}
|
||||
.ibo-toggler--wrapper input:checked:disabled + .ibo-toggler--slider {
|
||||
background-color: $ibo-toggler--slider--checked-disabled--background-color;
|
||||
}
|
||||
|
||||
input:focus + .ibo-toggler--slider {
|
||||
box-shadow: $ibo-toggler--slider--focus--box-shadow;
|
||||
}
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
@import "wizard-container/wizard-container";
|
||||
@import "object/all";
|
||||
@import "activity-panel/all";
|
||||
@import "extension/all";
|
||||
1
css/backoffice/layout/extension/_all.scss
Normal file
1
css/backoffice/layout/extension/_all.scss
Normal file
@@ -0,0 +1 @@
|
||||
@import "extension-details";
|
||||
54
css/backoffice/layout/extension/_extension-details.scss
Normal file
54
css/backoffice/layout/extension/_extension-details.scss
Normal file
@@ -0,0 +1,54 @@
|
||||
$ibo-extension-details--information--metadata--padding: $ibo-spacing-200 !default;
|
||||
$ibo-extension-details--information--metadata--delimiter: "-" !default;
|
||||
$ibo-extension-details--information--metadata--color: $ibo-color-grey-700 !default;
|
||||
$ibo-extension-details--actions--button--padding-y: 3px !default;
|
||||
$ibo-extension-details--actions--button--padding-x: $ibo-button--padding-x !default;
|
||||
|
||||
.ibo-extension-details {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ibo-extension-details--information {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ibo-extension-details--actions {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ibo-extension-details--information--label {
|
||||
@extend %ibo-font-ral-med-150;
|
||||
}
|
||||
|
||||
.ibo-extension-details--information--metadata {
|
||||
@extend %ibo-font-ral-med-100;
|
||||
color: $ibo-extension-details--information--metadata--color;
|
||||
}
|
||||
|
||||
.ibo-extension-details--information--description {
|
||||
@extend %ibo-font-ral-med-100;
|
||||
}
|
||||
|
||||
.ibo-extension-details--information--metadata span + span:before {
|
||||
content: $ibo-extension-details--information--metadata--delimiter;
|
||||
padding-left: $ibo-extension-details--information--metadata--padding;
|
||||
padding-right: $ibo-extension-details--information--metadata--padding;
|
||||
}
|
||||
|
||||
.ibo-extension-details:has(input:checked) .ibo-badge.unchecked, .ibo-extension-details:has(input:not(:checked)) .ibo-badge.checked {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ibo-extension-details--actions > button {
|
||||
padding: $ibo-extension-details--actions--button--padding-y $ibo-extension-details--actions--button--padding-x;
|
||||
}
|
||||
|
||||
.ibo-extension-details--actions:has(.toggler-install:not(:disabled)) .ibo-popover-menu--section a[data-resource-id="force_uninstall"] {
|
||||
display: none;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -522,10 +522,12 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-setup-summary-title {
|
||||
font-size: $ibo-font-size-150;
|
||||
.ibo-setup-summary-title, .ibo-setup-summary-title:visited, .ibo-setup-summary-title:hover {
|
||||
font-size: $ibo-font-size-150;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
#ibo-setup-licenses--components-list {
|
||||
background-color: $ibo-color-white-200;
|
||||
padding: 12px;
|
||||
@@ -605,6 +607,7 @@ body {
|
||||
color:#a00000;
|
||||
}
|
||||
.setup-extension-tag {
|
||||
display: inline-flex;
|
||||
background-color: grey;
|
||||
border-radius: 8px;
|
||||
padding-left: 3px;
|
||||
@@ -681,9 +684,6 @@ body {
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
}
|
||||
#installation_progress {
|
||||
display: none;
|
||||
}
|
||||
#fresh_content{
|
||||
border: 0;
|
||||
min-height: 300px;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* CSS of the template page
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Javascript file loaded in template page
|
||||
*/
|
||||
|
||||
17
datamodels/2.x/combodo-data-feature-removal/composer.json
Normal file
17
datamodels/2.x/combodo-data-feature-removal/composer.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"config": {
|
||||
"classmap-authoritative": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Combodo\\iTop\\DataFeatureRemoval\\": "src",
|
||||
"": "src/NoNamespace"
|
||||
}
|
||||
},
|
||||
"name": "combodo/combodo-data-feature-removal",
|
||||
"type": "itop-extension",
|
||||
"description": "iTop Data Feature Removal",
|
||||
"require": {
|
||||
"composer-runtime-api": "^2.0"
|
||||
}
|
||||
}
|
||||
20
datamodels/2.x/combodo-data-feature-removal/composer.lock
generated
Normal file
20
datamodels/2.x/combodo-data-feature-removal/composer.lock
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"_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": "b862a55cbf5448fb99f0905a4db6529b",
|
||||
"packages": [],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"composer-runtime-api": "^2.0"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
||||
<menus>
|
||||
<menu id="DataFeatureRemovalMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>30</rank>
|
||||
<parent>SystemTools</parent>
|
||||
<url>$pages/exec.php?exec_module=combodo-data-feature-removal&exec_page=index.php&c[menu]=DataFeatureRemovalMenu</url>
|
||||
<enable_admin_only>1</enable_admin_only>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'Menu:DataFeatureRemovalMenu' => 'Features Removal',
|
||||
'combodo-data-feature-removal/Operation:Main/Title' => 'Features Removal',
|
||||
|
||||
'DataFeatureRemoval:Main:Title' => 'Features Removal',
|
||||
'DataFeatureRemoval:Main:SubTitle' => 'Prepare features you want to enable/disable in a future setup',
|
||||
'DataFeatureRemoval:Failure:Title' => 'Feature dry removal errors',
|
||||
'DataFeatureRemoval:Helper:Title' => 'Enable or disable features that are installed in your iTop.',
|
||||
'DataFeatureRemoval:Helper:Desc1' => 'It will prepare the setup step that proceeds to feature enabling or disabling.',
|
||||
'DataFeatureRemoval:Helper:Desc2' => 'Analyze if there are any data or dependency preventing you from enabling/disabling a feature.',
|
||||
|
||||
'DataFeatureRemoval:Features:Title' => 'Features',
|
||||
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
|
||||
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
|
||||
|
||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Deletion plan',
|
||||
'DataFeatureRemoval:DeletionPlan:SubTitle' => 'Database tables to clean before continuing',
|
||||
'DataFeatureRemoval:DoDeletion:Title' => 'Do deletion',
|
||||
'DataFeatureRemoval:DoDeletion:SubTitle' => 'Remove all the entries from the database',
|
||||
|
||||
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Element to remove',
|
||||
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Feature name',
|
||||
'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence',
|
||||
|
||||
'UI:Button:Analyze' => 'Analyze',
|
||||
'UI:Button:ModifyChoices' => 'Modify Choices',
|
||||
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
|
||||
'UI:Button:PlanDeletion' => 'Prepare deletion plan',
|
||||
'UI:Button:DoDeletion' => 'Delete data',
|
||||
'UI:Button:BackToMain' => 'Back to Feature Removal',
|
||||
'UI:Button:Setup' => 'Back to setup',
|
||||
|
||||
'UI:Action:ForceUninstall' => 'Force uninstall',
|
||||
'UI:Action:MoreInfo' => 'More information',
|
||||
|
||||
'DataFeatureRemoval:Table:Empty' => 'No data to remove',
|
||||
|
||||
'DataFeatureRemoval:Column:Class' => 'Class',
|
||||
'DataFeatureRemoval:Column:DeleteCount' => 'Entries to delete',
|
||||
'DataFeatureRemoval:Column:UpdateCount' => 'Entries to update',
|
||||
'DataFeatureRemoval:Column:Issue' => 'Issue',
|
||||
|
||||
'DataFeatureRemoval:Column:DeletedCount' => 'Deleted entries',
|
||||
'DataFeatureRemoval:Column:UpdatedCount' => 'Updated entries',
|
||||
]);
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*/
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Menu:DataFeatureRemovalMenu' => 'Features Removal',
|
||||
'combodo-data-feature-removal/Operation:Main/Title' => 'Features Removal',
|
||||
|
||||
'DataFeatureRemoval:Main:Title' => 'Features Removal',
|
||||
'DataFeatureRemoval:Main:SubTitle' => 'Prepare features you want to enable/disable in a future setup',
|
||||
'DataFeatureRemoval:Failure:Title' => 'Feature dry removal errors',
|
||||
'DataFeatureRemoval:Helper:Title' => 'Enable or disable features that are installed in your iTop.',
|
||||
'DataFeatureRemoval:Helper:Desc1' => 'It will prepare the setup step that proceeds to feature enabling or disabling.',
|
||||
'DataFeatureRemoval:Helper:Desc2' => 'Analyze if there are any data or dependency preventing you from enabling/disabling a feature.',
|
||||
|
||||
'DataFeatureRemoval:Features:Title' => 'Features',
|
||||
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
|
||||
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
|
||||
|
||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Deletion plan',
|
||||
'DataFeatureRemoval:DeletionPlan:SubTitle' => 'Database tables to clean before continuing',
|
||||
'DataFeatureRemoval:DoDeletion:Title' => 'Do deletion',
|
||||
'DataFeatureRemoval:DoDeletion:SubTitle' => 'Remove all the entries from the database',
|
||||
|
||||
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Element to remove',
|
||||
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Feature name',
|
||||
'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence',
|
||||
|
||||
'UI:Button:Analyze' => 'Analyze',
|
||||
'UI:Button:ModifyChoices' => 'Modify Choices',
|
||||
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
|
||||
'UI:Button:PlanDeletion' => 'Prepare deletion plan',
|
||||
'UI:Button:DoDeletion' => 'Delete data',
|
||||
'UI:Button:BackToMain' => 'Back to Feature Removal',
|
||||
'UI:Button:Setup' => 'Back to setup',
|
||||
|
||||
'UI:Action:ForceUninstall' => 'Force uninstall',
|
||||
'UI:Action:MoreInfo' => 'More information',
|
||||
|
||||
'DataFeatureRemoval:Table:Empty' => 'No data to remove',
|
||||
|
||||
'DataFeatureRemoval:Column:Class' => 'Class',
|
||||
'DataFeatureRemoval:Column:DeleteCount' => 'Entries to delete',
|
||||
'DataFeatureRemoval:Column:UpdateCount' => 'Entries to update',
|
||||
'DataFeatureRemoval:Column:Issue' => 'Issue',
|
||||
|
||||
'DataFeatureRemoval:Column:DeletedCount' => 'Deleted entries',
|
||||
'DataFeatureRemoval:Column:UpdatedCount' => 'Updated entries',
|
||||
]);
|
||||
20
datamodels/2.x/combodo-data-feature-removal/index.php
Normal file
20
datamodels/2.x/combodo-data-feature-removal/index.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval;
|
||||
|
||||
use Combodo\iTop\DataFeatureRemoval\Controller\DataFeatureRemovalController;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalLog;
|
||||
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
|
||||
DataFeatureRemovalLog::Enable();
|
||||
|
||||
$oController = new DataFeatureRemovalController(MODULESROOT.DataFeatureRemovalHelper::MODULE_NAME.'/templates', DataFeatureRemovalHelper::MODULE_NAME);
|
||||
$oController->SetDefaultOperation('Main');
|
||||
$oController->HandleOperation();
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
// PHP Data Model definition file
|
||||
|
||||
// WARNING - WARNING - WARNING
|
||||
// DO NOT EDIT THIS FILE (unless you know what you are doing)
|
||||
//
|
||||
// If you provide a datamodel.xxxx.xml file with your module,
|
||||
// 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 and later) 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,36 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 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
|
||||
'itop-flow-map/3.3.0',
|
||||
'combodo-data-feature-removal/3.3.0',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Map applications data flows',
|
||||
'label' => 'iTop Data Feature Removal',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-config-mgmt/3.2.0',
|
||||
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'mandatory' => true,
|
||||
'visible' => false,
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
|
||||
],
|
||||
'webservice' => [
|
||||
|
||||
'vendor/autoload.php',
|
||||
'model.combodo-data-feature-removal.php', // Contains the PHP code generated by the "compilation" of datamodel.combodo-data-feature-removal.xml
|
||||
],
|
||||
'webservice' => [],
|
||||
'data.struct' => [
|
||||
'data/en_us.data.itop-flow-map.xml',
|
||||
// add your 'structure' definition XML files here,
|
||||
],
|
||||
'data.sample' => [
|
||||
// add your sample data XML files here,
|
||||
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Controller;
|
||||
|
||||
require_once APPROOT.'setup/feature_removal/SetupAudit.php';
|
||||
require_once APPROOT.'setup/feature_removal/DryRemovalRuntimeEnvironment.php';
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Controller\Controller;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
||||
use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService;
|
||||
use Combodo\iTop\DataFeatureRemoval\Service\DeletionPlanService;
|
||||
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
|
||||
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
|
||||
class DataFeatureRemovalController extends Controller
|
||||
{
|
||||
private array $aSelectedExtensionsForCheck = [];
|
||||
private array $aCountClassesToCleanup = [];
|
||||
private array $aAnalysisDataTable = [];
|
||||
|
||||
public function OperationMain($sErrorMessage = null): void
|
||||
{
|
||||
$aParams = [];
|
||||
|
||||
$this->ReadRemovedExtensions();
|
||||
$this->AddAnalyzeParams();
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['aExtensions'] = $this->GetExtensionsTable();
|
||||
$aParams['aAnalysisDataTable'] = $this->aAnalysisDataTable;
|
||||
$aParams['aClasses'] = array_keys($this->aCountClassesToCleanup);
|
||||
$aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage;
|
||||
$aParams['bHasData'] = count($aParams['aClasses']) > 0;
|
||||
$aParams['sSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup';
|
||||
|
||||
$this->AddLinkedStylesheet(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/css/DataFeatureRemoval.css');
|
||||
$this->AddLinkedScript(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/js/DataFeatureRemoval.js');
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
public function AddAnalyzeParams(): void
|
||||
{
|
||||
$aData = [];
|
||||
$aColumns = [];
|
||||
foreach ($this->aCountClassesToCleanup as $sClass => $iCount) {
|
||||
$sModuleName = MetaModel::GetModuleName($sClass);
|
||||
$aExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetIncludingExtensions($sModuleName);
|
||||
$sExtensions = implode(' ', $aExtensions);
|
||||
$aColumns = ['ClassName','FeatureName','Occurrence'];
|
||||
$aData[] = [
|
||||
<<<HTML
|
||||
<label>$sClass</label>
|
||||
HTML,
|
||||
<<<HTML
|
||||
<label title="$sModuleName">$sExtensions</label>
|
||||
HTML,
|
||||
<<<HTML
|
||||
<label>$iCount</label>
|
||||
HTML,
|
||||
];
|
||||
}
|
||||
|
||||
$this->aAnalysisDataTable = $this->GetTableData('Analysis', $aColumns, $aData);
|
||||
}
|
||||
|
||||
public function OperationAnalyze(): void
|
||||
{
|
||||
$this->ReadRemovedExtensions();
|
||||
|
||||
$this->m_sOperation = 'Main';
|
||||
|
||||
try {
|
||||
if (count($this->aSelectedExtensionsForCheck) > 0) {
|
||||
$this->Analyze();
|
||||
}
|
||||
$this->OperationMain();
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error(__METHOD__, null, ['stack' => $e->getTraceAsString(), 'exception' => $e->getMessage()]);
|
||||
$this->OperationMain($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function Analyze(): void
|
||||
{
|
||||
$sSourceEnv = MetaModel::GetEnvironment();
|
||||
$oDryRemovalRuntimeEnvironment = new DryRemovalRuntimeEnvironment();
|
||||
$oDryRemovalRuntimeEnvironment->Prepare($sSourceEnv, $this->aSelectedExtensionsForCheck);
|
||||
$oDryRemovalRuntimeEnvironment->CompileFrom($sSourceEnv);
|
||||
|
||||
$oSetupAudit = new SetupAudit($sSourceEnv, DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV);
|
||||
$aGetRemovedClasses = $oSetupAudit->GetIssues();
|
||||
IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
|
||||
$this->aCountClassesToCleanup = $aGetRemovedClasses;
|
||||
}
|
||||
|
||||
public function OperationDeletionPlan(): void
|
||||
{
|
||||
$aParams = [];
|
||||
$this->ValidateTransactionId();
|
||||
|
||||
$aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
|
||||
$aDeletionPlanSummaryEntities = DeletionPlanService::GetInstance()->GetDeletionPlanSummary($aClasses);
|
||||
$aColumns = ['Class', 'DeleteCount' , 'UpdateCount', 'Issue'];
|
||||
$aRows = [];
|
||||
foreach ($aDeletionPlanSummaryEntities as $oDeletionPlanSummaryEntity) {
|
||||
$aRows[] = [
|
||||
$oDeletionPlanSummaryEntity->sClass,
|
||||
$oDeletionPlanSummaryEntity->iDeleteCount,
|
||||
$oDeletionPlanSummaryEntity->iUpdateCount,
|
||||
$oDeletionPlanSummaryEntity->sIssue ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['aDeletionPlanSummary'] = $this->GetTableData('Extensions', $aColumns, $aRows);
|
||||
$aParams['aClasses'] = $aClasses;
|
||||
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationDoDeletion(): void
|
||||
{
|
||||
$aParams = [];
|
||||
$this->ValidateTransactionId();
|
||||
|
||||
$aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
|
||||
$aDeletionExecutionSummary = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses);
|
||||
$aColumns = ['Class', 'DeletedCount' , 'UpdatedCount'];
|
||||
$aRows = [];
|
||||
foreach ($aDeletionExecutionSummary as $oDeletionExecutionSummaryEntity) {
|
||||
$aRows[] = [
|
||||
$oDeletionExecutionSummaryEntity->sClass,
|
||||
$oDeletionExecutionSummaryEntity->iDeleteCount,
|
||||
$oDeletionExecutionSummaryEntity->iUpdateCount,
|
||||
];
|
||||
}
|
||||
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['aDeletionExecutionSummary'] = $this->GetTableData('Extensions', $aColumns, $aRows);
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get installed extensions from disk
|
||||
*
|
||||
* @return array structure for twig datatable
|
||||
*/
|
||||
private function GetExtensionsTable(): array
|
||||
{
|
||||
$aExtensions = [];
|
||||
$aColumns = ['', 'Version', 'Name', 'Code'];
|
||||
|
||||
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
|
||||
/** @var \iTopExtension $oExtension */
|
||||
|
||||
$sChecked = '';
|
||||
$sDisabledHtml = '';
|
||||
if ($oExtension->bRemovedFromDisk) {
|
||||
$sDisabledHtml = 'disabled=""';
|
||||
$sChecked = 'checked';
|
||||
} elseif (in_array($sCode, $this->aSelectedExtensionsForCheck)) {
|
||||
$sChecked = 'checked';
|
||||
}
|
||||
|
||||
$sLabel = $oExtension->sLabel;
|
||||
$sVersion = $oExtension->sVersion;
|
||||
$sIdEnable = "aExtensions[$sCode][enable]";
|
||||
|
||||
$aExtensions[] = [
|
||||
<<<HTML
|
||||
<input type="checkbox" $sDisabledHtml class="extension_check" $sChecked id="$sIdEnable" name="$sIdEnable"/>
|
||||
HTML,
|
||||
<<<HTML
|
||||
<label>$sVersion</label>
|
||||
HTML,
|
||||
<<<HTML
|
||||
<label for="$sIdEnable">$sLabel</label>
|
||||
HTML,
|
||||
<<<HTML
|
||||
<label for="$sIdEnable">$sCode</label>
|
||||
HTML,
|
||||
];
|
||||
}
|
||||
|
||||
return $this->GetTableData('Extensions', $aColumns, $aExtensions);
|
||||
}
|
||||
|
||||
private function GetTableData(string $sTableName, array $aColumns, array $aData): array
|
||||
{
|
||||
if (empty($aData)) {
|
||||
return [
|
||||
'Type' => 'Table',
|
||||
'Columns' => [['label' => '']],
|
||||
'Data' => [[ Dict::S('DataFeatureRemoval:Table:Empty')]],
|
||||
];
|
||||
}
|
||||
|
||||
$aNewColumns = [];
|
||||
foreach ($aColumns as $sColumn) {
|
||||
$aNewColumns[] = ['label' => Dict::S("DataFeatureRemoval:Table:$sTableName:$sColumn", Dict::S("DataFeatureRemoval:Column:$sColumn", $sColumn))];
|
||||
}
|
||||
$aColumns = $aNewColumns;
|
||||
|
||||
return [
|
||||
'Type' => 'Table',
|
||||
'Columns' => $aColumns,
|
||||
'Data' => $aData,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException
|
||||
*/
|
||||
private function ValidateTransactionId(): void
|
||||
{
|
||||
if (empty($_POST)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', null, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
|
||||
IssueLog::Debug(__FUNCTION__.": Transaction [$sTransactionId]");
|
||||
if (empty($sTransactionId) || !utils::IsTransactionValid($sTransactionId, false)) {
|
||||
throw new DataFeatureRemovalException(Dict::S("iTopUpdate:Error:InvalidToken"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function ReadRemovedExtensions(): void
|
||||
{
|
||||
if (count($this->aSelectedExtensionsForCheck) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aExtensions', []);
|
||||
IssueLog::Error(__METHOD__, null, $aSelectedExtensionsFromUI);
|
||||
foreach ($aSelectedExtensionsFromUI as $sCode => $aData) {
|
||||
$sValue = $aData['enable'] ?? 'off';
|
||||
if (($sValue) === 'on') {
|
||||
$this->aSelectedExtensionsForCheck[] = $sCode;
|
||||
}
|
||||
}
|
||||
|
||||
// Add source removed to check
|
||||
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
|
||||
if ($oExtension->bRemovedFromDisk) {
|
||||
$this->aSelectedExtensionsForCheck[] = $sCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Entity;
|
||||
|
||||
class DeletionPlanSummaryEntity
|
||||
{
|
||||
public string $sClass;
|
||||
|
||||
/**
|
||||
* @var int : DEL_MANUAL|DEL_AUTO|DEL_SILENT|DEL_MOVEUP|DEL_NONE
|
||||
* @see \AttributeDefinition DEL_xxx
|
||||
*/
|
||||
public int $iMode = 0;
|
||||
public ?string $sIssue = null;
|
||||
public int $iUpdateCount = 0;
|
||||
public int $iDeleteCount = 0;
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*/
|
||||
public function __construct(string $sClass)
|
||||
{
|
||||
$this->sClass = $sClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Helper;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class DataFeatureRemovalException extends Exception
|
||||
{
|
||||
public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null, array $aContext = [])
|
||||
{
|
||||
if (!is_null($previous)) {
|
||||
$sStack = $previous->getTraceAsString();
|
||||
$sError = $previous->getMessage();
|
||||
} else {
|
||||
$sStack = $this->getTraceAsString();
|
||||
$sError = '';
|
||||
}
|
||||
|
||||
$aContext['error'] = $sError;
|
||||
$aContext['stack'] = $sStack;
|
||||
DataFeatureRemovalLog::Error($message, null, $aContext);
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Helper;
|
||||
|
||||
class DataFeatureRemovalHelper
|
||||
{
|
||||
public const MODULE_NAME = 'combodo-data-feature-removal';
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Helper;
|
||||
|
||||
use LogAPI;
|
||||
|
||||
class DataFeatureRemovalLog extends LogAPI
|
||||
{
|
||||
public const CHANNEL_DEFAULT = 'DataFeatureRemoval';
|
||||
|
||||
protected static $m_oFileLog = null;
|
||||
|
||||
public static function Enable($sTargetFile = null)
|
||||
{
|
||||
if (empty($sTargetFile)) {
|
||||
$sTargetFile = APPROOT.'log/error.log';
|
||||
}
|
||||
parent::Enable($sTargetFile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Service;
|
||||
|
||||
use iTopExtension;
|
||||
use iTopExtensionsMap;
|
||||
use MetaModel;
|
||||
|
||||
class DataFeatureRemoverExtensionService
|
||||
{
|
||||
private static DataFeatureRemoverExtensionService $oInstance;
|
||||
|
||||
private array $aSelectedExtensions = [];
|
||||
private array $aItopExtensions = [];
|
||||
private array $aIncludingExtensionsByModuleName = [];
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): DataFeatureRemoverExtensionService
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new DataFeatureRemoverExtensionService();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?DataFeatureRemoverExtensionService $oInstance): void
|
||||
{
|
||||
self::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sModuleName
|
||||
*
|
||||
* @return array
|
||||
* @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException
|
||||
*/
|
||||
public function GetIncludingExtensions(string $sModuleName): array
|
||||
{
|
||||
if (count($this->aIncludingExtensionsByModuleName) === 0) {
|
||||
foreach ($this->ReadiTopExtensions() as $oExtension) {
|
||||
$aModuleNames = $oExtension->aModules;
|
||||
if (is_array($aModuleNames) && count($aModuleNames) > 0) {
|
||||
foreach ($aModuleNames as $sModule) {
|
||||
$aExtensions = $this->aIncludingExtensionsByModuleName[$sModule] ?? [];
|
||||
$aExtensions[] = $oExtension->sLabel.'/'.$oExtension->sVersion;
|
||||
$this->aIncludingExtensionsByModuleName[$sModule] = $aExtensions;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->aIncludingExtensionsByModuleName[$sModuleName] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iTopExtension[]
|
||||
*/
|
||||
public function ReadItopExtensions(): array
|
||||
{
|
||||
if (count($this->aItopExtensions) === 0) {
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
$oExtensionsMap->LoadInstalledExtensionsFromDatabase(MetaModel::GetConfig());
|
||||
$this->aItopExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(true);
|
||||
|
||||
uasort($this->aItopExtensions, function (iTopExtension $oiTopExtension1, iTopExtension $oiTopExtension2) {
|
||||
return strcmp($oiTopExtension1->sLabel, $oiTopExtension2->sLabel);
|
||||
});
|
||||
}
|
||||
|
||||
return $this->aItopExtensions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Service;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
||||
use DBObjectSearch;
|
||||
use DeletionPlan;
|
||||
use MetaModel;
|
||||
|
||||
class DeletionPlanService
|
||||
{
|
||||
private static DeletionPlanService $oInstance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): DeletionPlanService
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new DeletionPlanService();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?DeletionPlanService $oInstance): void
|
||||
{
|
||||
self::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|null $aClasses
|
||||
*
|
||||
* @return array<\Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity>
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function GetDeletionPlanSummary(?array $aClasses): array
|
||||
{
|
||||
$aSummary = [];
|
||||
if (is_null($aClasses)) {
|
||||
return $aSummary;
|
||||
}
|
||||
|
||||
$oDeletionPlan = $this->GetDeletionPlan($aClasses);
|
||||
|
||||
foreach ($oDeletionPlan->ListUpdates() as $sClass => $aUpdates) {
|
||||
$oDeletionPlanSummaryEntity = new DeletionPlanSummaryEntity($sClass);
|
||||
$oDeletionPlanSummaryEntity->iUpdateCount = count($aUpdates);
|
||||
$aSummary[$sClass] = $oDeletionPlanSummaryEntity;
|
||||
}
|
||||
|
||||
foreach ($oDeletionPlan->ListDeletes() as $sClass => $aDeletes) {
|
||||
$oDeletionPlanSummaryEntity = $aSummary[$sClass] ?? new DeletionPlanSummaryEntity($sClass);
|
||||
$oDeletionPlanSummaryEntity->iDeleteCount = count($aDeletes);
|
||||
|
||||
$aDelete = array_shift($aDeletes);
|
||||
$oDeletionPlanSummaryEntity->iMode = $aDelete['mode'];
|
||||
$oDeletionPlanSummaryEntity->sIssue = $aDelete['issue'] ?? null;
|
||||
|
||||
$aSummary[$sClass] = $oDeletionPlanSummaryEntity;
|
||||
}
|
||||
|
||||
return $aSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return \DBObject[]
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function GetAllObjects(string $sClass): array
|
||||
{
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oFilter->AllowAllData();
|
||||
$oSet = new \DBObjectSet($oFilter);
|
||||
return $oSet->ToArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aClasses
|
||||
*
|
||||
* @return array<\Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity>
|
||||
* @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function ExecuteDeletionPlan(array $aClasses): array
|
||||
{
|
||||
$oDeletionPlan = $this->GetDeletionPlan($aClasses);
|
||||
|
||||
if (count($oDeletionPlan->GetIssues()) > 0) {
|
||||
throw new DataFeatureRemovalException("Deletion Plan cannot be executed due to issues");
|
||||
}
|
||||
|
||||
$aSummary = [];
|
||||
foreach ($oDeletionPlan->ListUpdates() as $sClass => $aToUpdate) {
|
||||
$oDeletionPlanSummaryEntity = $aSummary[$sClass] ?? new DeletionPlanSummaryEntity($sClass);
|
||||
|
||||
foreach ($aToUpdate as $aData) {
|
||||
$oToUpdate = $aData['to_reset'];
|
||||
/** @var \DBObject $oToUpdate */
|
||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef) {
|
||||
$oToUpdate->Set($sRemoteExtKey, 0);
|
||||
$oToUpdate->DBUpdate();
|
||||
$oDeletionPlanSummaryEntity->iUpdateCount++;
|
||||
}
|
||||
}
|
||||
|
||||
$aSummary[$sClass] = $oDeletionPlanSummaryEntity;
|
||||
}
|
||||
|
||||
foreach ($oDeletionPlan->ListDeletes() as $sClass => $aDeletes) {
|
||||
$oDeletionPlanSummaryEntity = $aSummary[$sClass] ?? new DeletionPlanSummaryEntity($sClass);
|
||||
|
||||
foreach ($aDeletes as $sId => $aDelete) {
|
||||
// Delete any existing change tracking about the current object
|
||||
$oFilter = new DBObjectSearch('CMDBChangeOp');
|
||||
$oFilter->AddCondition('objclass', $sClass, '=');
|
||||
$oFilter->AddCondition('objkey', $sId, '=');
|
||||
MetaModel::PurgeData($oFilter);
|
||||
|
||||
// Delete the entry
|
||||
$aClassesToRemove = array_merge(MetaModel::EnumChildClasses($sClass, ENUM_PARENT_CLASSES_ALL), MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_EXCLUDELEAF, false));
|
||||
foreach ($aClassesToRemove as $sParentClass) {
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData("SELECT $sParentClass WHERE id=:id");
|
||||
$sQuery = $oFilter->MakeDeleteQuery(['id' => $sId]);
|
||||
CMDBSource::DeleteFrom($sQuery);
|
||||
}
|
||||
|
||||
$oDeletionPlanSummaryEntity->iDeleteCount++;
|
||||
}
|
||||
|
||||
$aSummary[$sClass] = $oDeletionPlanSummaryEntity;
|
||||
}
|
||||
|
||||
return $aSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aClasses
|
||||
*
|
||||
* @return \DeletionPlan
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function GetDeletionPlan(array $aClasses): DeletionPlan
|
||||
{
|
||||
$oDeletionPlan = new DeletionPlan();
|
||||
foreach ($aClasses as $sClass) {
|
||||
$aObjects = $this->GetAllObjects($sClass);
|
||||
foreach ($aObjects as $oObject) {
|
||||
$oObject->CheckToDelete($oDeletionPlan);
|
||||
}
|
||||
}
|
||||
|
||||
return $oDeletionPlan;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{# @copyright Copyright (C) 2010-2026 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:DeletionPlan:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:DeletionPlan:SubTitle'|dict_s } %}
|
||||
{% UIDataTable ForForm { sRef:'aDeletionPlanSummary', aColumns:aDeletionPlanSummary.Columns, aData:aDeletionPlanSummary.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIPanel %}
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden { sName:'operation', sValue:'DoDeletion'} %}
|
||||
{% for sKey, sClass in aClasses %}
|
||||
{% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %}
|
||||
{% endfor %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden { sName:'operation', sValue:'Main'} %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:BackToMain'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
@@ -0,0 +1,14 @@
|
||||
{# @copyright Copyright (C) 2010-2026 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:DoDeletion:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:DoDeletion:SubTitle'|dict_s } %}
|
||||
{% UIDataTable ForForm { sRef:'aDeletionExecutionSummary', aColumns:aDeletionExecutionSummary.Columns, aData:aDeletionExecutionSummary.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIPanel %}
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden { sName:'operation', sValue:'Main'} %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:BackToMain'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
@@ -0,0 +1,19 @@
|
||||
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
{% if bHasData %}
|
||||
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Analysis:SubTitle'|dict_format(rule_count) } %}
|
||||
{% UIDataTable ForForm { sRef:'aAnalysisDataTable', aColumns:aAnalysisDataTable.Columns, aData:aAnalysisDataTable.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIPanel %}
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden { sName:'operation', sValue:'DeletionPlan'} %}
|
||||
{% for sKey, sClass in aClasses %}
|
||||
{% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %}
|
||||
{% endfor %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:PlanDeletion'|dict_s, sName:'btn_plandeletion', sId:'btn_plandeletion', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
{% endif %}
|
||||
@@ -0,0 +1,16 @@
|
||||
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden {sName:'operation', sValue:'Analyze'} %}
|
||||
{% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %}
|
||||
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Features:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aExtensions', aColumns:aExtensions.Columns, aData:aExtensions.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Analyze'|dict_s, sName:'btn_apply', sId:'btn_apply', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
@@ -0,0 +1,35 @@
|
||||
{# @copyright Copyright (C) 2010-2025 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
{# Usable variables: #}
|
||||
{# * sTitle => page title #}
|
||||
{# * sMessage => success message #}
|
||||
{# * sError => error message #}
|
||||
|
||||
{# DataFeatureRemoval #}
|
||||
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Main:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Main:SubTitle'|dict_s } %}
|
||||
|
||||
{% UIAlert ForInformation { sTitle:'DataFeatureRemoval:Helper:Title'|dict_s } %}
|
||||
{{ 'DataFeatureRemoval:Helper:Desc1'|dict_s }}<BR>
|
||||
{{ 'DataFeatureRemoval:Helper:Desc2'|dict_s }}
|
||||
{% EndUIAlert %}
|
||||
|
||||
{% if null != DataFeatureRemovalErrorMessage %}
|
||||
<div id="feature_removal_error_msg_div" style="display:block">
|
||||
{% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %}
|
||||
{% EndUIAlert %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% include 'Features.html.twig' %}
|
||||
{% include 'ExtensionRemovalData.html.twig' %}
|
||||
|
||||
{% if not bHasData %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
<a href="{{ sSetupUrl }}">
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:false} %}
|
||||
</a>
|
||||
{% EndUIToolbar %}
|
||||
{% endif %}
|
||||
{% EndUIPanel %}
|
||||
22
datamodels/2.x/combodo-data-feature-removal/vendor/autoload.php
vendored
Normal file
22
datamodels/2.x/combodo-data-feature-removal/vendor/autoload.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException($err);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464::getLoader();
|
||||
579
datamodels/2.x/combodo-data-feature-removal/vendor/composer/ClassLoader.php
vendored
Normal file
579
datamodels/2.x/combodo-data-feature-removal/vendor/composer/ClassLoader.php
vendored
Normal file
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
21
datamodels/2.x/combodo-data-feature-removal/vendor/composer/LICENSE
vendored
Normal file
21
datamodels/2.x/combodo-data-feature-removal/vendor/composer/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
17
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_classmap.php
vendored
Normal file
17
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_classmap.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Controller\\DataFeatureRemovalController' => $baseDir . '/src/Controller/DataFeatureRemovalController.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DeletionPlanSummaryEntity' => $baseDir . '/src/Entity/DeletionPlanSummaryEntity.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => $baseDir . '/src/Helper/DataFeatureRemovalException.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => $baseDir . '/src/Helper/DataFeatureRemovalHelper.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => $baseDir . '/src/Helper/DataFeatureRemovalLog.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => $baseDir . '/src/Service/DataFeatureRemoverExtensionService.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DeletionPlanService' => $baseDir . '/src/Service/DeletionPlanService.php',
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
);
|
||||
9
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_namespaces.php
vendored
Normal file
9
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_namespaces.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
11
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_psr4.php
vendored
Normal file
11
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_psr4.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\' => array($baseDir . '/src'),
|
||||
'' => array($baseDir . '/src/NoNamespace'),
|
||||
);
|
||||
37
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_real.php
vendored
Normal file
37
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_real.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit4f96a7199e2c0d90e547333758b26464::getInitializer($loader));
|
||||
|
||||
$loader->setClassMapAuthoritative(true);
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
48
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_static.php
vendored
Normal file
48
datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_static.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit4f96a7199e2c0d90e547333758b26464
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'C' =>
|
||||
array (
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\' => 32,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $fallbackDirsPsr4 = array (
|
||||
0 => __DIR__ . '/../..' . '/src/NoNamespace',
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Controller\\DataFeatureRemovalController' => __DIR__ . '/../..' . '/src/Controller/DataFeatureRemovalController.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DeletionPlanSummaryEntity' => __DIR__ . '/../..' . '/src/Entity/DeletionPlanSummaryEntity.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalException.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalHelper.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalLog.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => __DIR__ . '/../..' . '/src/Service/DataFeatureRemoverExtensionService.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DeletionPlanService' => __DIR__ . '/../..' . '/src/Service/DeletionPlanService.php',
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$prefixDirsPsr4;
|
||||
$loader->fallbackDirsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$fallbackDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ namespace Combodo\iTop\DBTools\Service;
|
||||
use CMDBSource;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use IssueLog;
|
||||
|
||||
class DBToolsUtils
|
||||
{
|
||||
|
||||
@@ -72,15 +72,6 @@
|
||||
</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,18 +323,38 @@
|
||||
<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>
|
||||
@@ -6897,14 +6917,29 @@
|
||||
<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>
|
||||
|
||||
@@ -92,7 +92,7 @@ final class CoreUpdater
|
||||
$sFinalEnv = 'production';
|
||||
$oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, false);
|
||||
$oRuntimeEnv->CheckDirectories($sFinalEnv);
|
||||
$oRuntimeEnv->CompileFrom('production');
|
||||
$oRuntimeEnv->CompileFrom($sFinalEnv);
|
||||
|
||||
$oRuntimeEnv->Rollback();
|
||||
|
||||
@@ -155,21 +155,13 @@ final class CoreUpdater
|
||||
APPROOT.'extensions',
|
||||
];
|
||||
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $aDirsToScanForModules);
|
||||
$aSelectedModules = [];
|
||||
foreach ($aAvailableModules as $sModuleId => $aModule) {
|
||||
if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) {
|
||||
continue;
|
||||
} else {
|
||||
$aSelectedModules[] = $sModuleId;
|
||||
}
|
||||
}
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'BeforeDatabaseCreation');
|
||||
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseCreation');
|
||||
$oRuntimeEnv->UpdatePredefinedObjects();
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
|
||||
$oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/);
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad');
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseSetup');
|
||||
$oRuntimeEnv->LoadData($aAvailableModules, false /* no sample data*/);
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDataLoad');
|
||||
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
// Default choices = as before
|
||||
@@ -187,7 +179,7 @@ final class CoreUpdater
|
||||
$oRuntimeEnv->RecordInstallation(
|
||||
$oConfig,
|
||||
$sDataModelVersion,
|
||||
$aSelectedModules,
|
||||
array_keys($aAvailableModules),
|
||||
$aSelectedExtensionCodes,
|
||||
'Done by the iTop Core Updater'
|
||||
);
|
||||
|
||||
@@ -135,7 +135,7 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment
|
||||
$aAvailableModules[$oModule->GetName()] = $oModule;
|
||||
}
|
||||
// TODO check the auto-selected modules here
|
||||
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
|
||||
if ($oExtension->bMarkedAsChosen) {
|
||||
foreach ($oExtension->aModules as $sModuleName) {
|
||||
if (!isset($aRet[$sModuleName]) && isset($aAvailableModules[$sModuleName])) {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,747 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,96 +0,0 @@
|
||||
<?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',
|
||||
*/
|
||||
]);
|
||||
@@ -1,96 +0,0 @@
|
||||
<?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',
|
||||
*/
|
||||
]);
|
||||
@@ -1 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -24,129 +24,13 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\JsonPage;
|
||||
use Combodo\iTop\HubConnector\Controller\HubController;
|
||||
|
||||
require_once(APPROOT.'application/utils.inc.php');
|
||||
require_once(APPROOT.'core/log.class.inc.php');
|
||||
IssueLog::Enable(APPROOT.'log/error.log');
|
||||
|
||||
require_once(APPROOT.'setup/runtimeenv.class.inc.php');
|
||||
require_once(APPROOT.'setup/backup.class.inc.php');
|
||||
require_once(APPROOT.'core/mutex.class.inc.php');
|
||||
require_once(APPROOT.'core/dict.class.inc.php');
|
||||
require_once(APPROOT.'setup/xmldataloader.class.inc.php');
|
||||
require_once(__DIR__.'/hubruntimeenvironment.class.inc.php');
|
||||
|
||||
/**
|
||||
* Overload of DBBackup to handle logging
|
||||
*/
|
||||
class DBBackupWithErrorReporting extends DBBackup
|
||||
{
|
||||
protected $aInfos = [];
|
||||
|
||||
protected $aErrors = [];
|
||||
|
||||
protected function LogInfo($sMsg)
|
||||
{
|
||||
$aInfos[] = $sMsg;
|
||||
}
|
||||
|
||||
protected function LogError($sMsg)
|
||||
{
|
||||
IssueLog::Error($sMsg);
|
||||
$aErrors[] = $sMsg;
|
||||
}
|
||||
|
||||
public function GetInfos()
|
||||
{
|
||||
return $this->aInfos;
|
||||
}
|
||||
|
||||
public function GetErrors()
|
||||
{
|
||||
return $this->aErrors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $sTargetFile
|
||||
* @throws Exception
|
||||
* @return DBBackupWithErrorReporting
|
||||
*/
|
||||
function DoBackup($sTargetFile)
|
||||
{
|
||||
// Make sure the target directory exists
|
||||
$sBackupDir = dirname($sTargetFile);
|
||||
SetupUtils::builddir($sBackupDir);
|
||||
|
||||
$oBackup = new DBBackupWithErrorReporting();
|
||||
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
|
||||
$sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE;
|
||||
|
||||
$oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
|
||||
$oMutex->Lock();
|
||||
try {
|
||||
$oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile);
|
||||
} catch (Exception $e) {
|
||||
$oMutex->Unlock();
|
||||
throw $e;
|
||||
}
|
||||
$oMutex->Unlock();
|
||||
return $oBackup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the status of the current ajax execution (as a JSON structure)
|
||||
*
|
||||
* @param string $sMessage
|
||||
* @param bool $bSuccess
|
||||
* @param number $iErrorCode
|
||||
* @param array $aMoreFields
|
||||
* Extra fields to pass to the caller, if needed
|
||||
*/
|
||||
function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = [])
|
||||
{
|
||||
// Do not use AjaxPage during setup phases, because it uses InterfaceDiscovery in Twig compilation
|
||||
$oPage = new JsonPage();
|
||||
$aResult = [
|
||||
'code' => $iErrorCode,
|
||||
'message' => $sMessage,
|
||||
'fields' => $aMoreFields,
|
||||
];
|
||||
$oPage->SetData($aResult);
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
$oPage->output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to output the status of a successful execution
|
||||
*
|
||||
* @param string $sMessage
|
||||
* @param array $aMoreFields
|
||||
* Extra fields to pass to the caller, if needed
|
||||
*/
|
||||
function ReportSuccess($sMessage, $aMoreFields = [])
|
||||
{
|
||||
ReportStatus($sMessage, true, 0, $aMoreFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to output the status of a failed execution
|
||||
*
|
||||
* @param string $sMessage
|
||||
* @param number $iErrorCode
|
||||
* @param array $aMoreFields
|
||||
* Extra fields to pass to the caller, if needed
|
||||
*/
|
||||
function ReportError($sMessage, $iErrorCode, $aMoreFields = [])
|
||||
{
|
||||
if ($iErrorCode == 0) {
|
||||
// 0 means no error, so change it if no meaningful error code is supplied
|
||||
$iErrorCode = -1;
|
||||
}
|
||||
ReportStatus($sMessage, false, $iErrorCode, $aMoreFields);
|
||||
}
|
||||
require_once(__DIR__.'/src/Controller/HubController.php');
|
||||
|
||||
try {
|
||||
SetupUtils::ExitMaintenanceMode(false); // Reset maintenance mode in case of problem
|
||||
@@ -183,7 +67,7 @@ try {
|
||||
foreach ($aChecks as $oCheckResult) {
|
||||
if ($oCheckResult->iSeverity == CheckResult::ERROR) {
|
||||
$bFailed = true;
|
||||
ReportError($oCheckResult->sLabel, -2);
|
||||
HubController::GetInstance()->ReportError($oCheckResult->sLabel, -2);
|
||||
}
|
||||
}
|
||||
if (!$bFailed) {
|
||||
@@ -191,169 +75,27 @@ try {
|
||||
$fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath);
|
||||
if ($fFreeSpace !== false) {
|
||||
$sMessage = Dict::Format('iTopHub:BackupFreeDiskSpaceIn', SetupUtils::HumanReadableSize($fFreeSpace), dirname($sDBBackupPath));
|
||||
ReportSuccess($sMessage);
|
||||
HubController::GetInstance()->ReportSuccess($sMessage);
|
||||
} else {
|
||||
ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1);
|
||||
HubController::GetInstance()->ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'do_backup':
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
|
||||
|
||||
try {
|
||||
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
|
||||
}
|
||||
SetupLog::Info('Backup starts...');
|
||||
set_time_limit(0);
|
||||
$sBackupPath = APPROOT.'/data/backups/manual/backup-';
|
||||
$iSuffix = 1;
|
||||
$sSuffix = '';
|
||||
// Generate a unique name...
|
||||
do {
|
||||
$sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix;
|
||||
$sSuffix = '-'.$iSuffix;
|
||||
$iSuffix++ ;
|
||||
} while (file_exists($sBackupFile));
|
||||
|
||||
$oBackup = DoBackup($sBackupFile);
|
||||
$aErrors = $oBackup->GetErrors();
|
||||
if (count($aErrors) > 0) {
|
||||
SetupLog::Error('Backup failed.');
|
||||
SetupLog::Error(implode("\n", $aErrors));
|
||||
ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors);
|
||||
} else {
|
||||
SetupLog::Info('Backup successfully completed.');
|
||||
ReportSuccess(Dict::S('iTopHub:BackupOk'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
SetupLog::Error($e->getMessage());
|
||||
ReportError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
HubController::GetInstance()->LaunchBackup();
|
||||
break;
|
||||
|
||||
case 'compile':
|
||||
SetupLog::Info('Deployment starts...');
|
||||
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
|
||||
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
|
||||
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
|
||||
}
|
||||
// First step: prepare the datamodel, if it fails, roll-back
|
||||
$aSelectedExtensionCodes = utils::ReadParam('extension_codes', []);
|
||||
$aSelectedExtensionDirs = utils::ReadParam('extension_dirs', []);
|
||||
|
||||
$oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build
|
||||
$oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs);
|
||||
|
||||
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
|
||||
if ($oConfig->Get('demo_mode')) {
|
||||
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
|
||||
}
|
||||
|
||||
$aSelectModules = $oRuntimeEnv->CompileFrom('production', false); // WARNING symlinks does not seem to be compatible with manual Commit
|
||||
|
||||
$oRuntimeEnv->UpdateIncludes($oConfig);
|
||||
|
||||
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
|
||||
|
||||
// Safety check: check the inter dependencies, will throw an exception in case of inconsistency
|
||||
$oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
|
||||
|
||||
$oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected
|
||||
|
||||
// Everything seems Ok so far, commit in env-production!
|
||||
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
|
||||
$oRuntimeEnv->Commit();
|
||||
|
||||
// Report the success in a way that will be detected by the ajax caller
|
||||
SetupLog::Info('Compilation completed...');
|
||||
ReportSuccess('Ok'); // No access to Dict::S here
|
||||
HubController::GetInstance()->LaunchCompile();
|
||||
break;
|
||||
|
||||
case 'move_to_production':
|
||||
// Second step: update the schema and the data
|
||||
// Everything happening below is based on env-production
|
||||
$oRuntimeEnv = new RunTimeEnvironment('production', true);
|
||||
|
||||
try {
|
||||
SetupLog::Info('Move to production starts...');
|
||||
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
|
||||
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
|
||||
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
|
||||
}
|
||||
unlink(utils::GetDataPath().'hub/compile_authent');
|
||||
// Load the "production" config file to clone & update it
|
||||
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
|
||||
SetupUtils::EnterReadOnlyMode($oConfig);
|
||||
|
||||
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
|
||||
|
||||
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
|
||||
|
||||
$aSelectedModules = [];
|
||||
foreach ($aAvailableModules as $sModuleId => $aModule) {
|
||||
if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) {
|
||||
continue;
|
||||
} else {
|
||||
$aSelectedModules[] = $sModuleId;
|
||||
}
|
||||
}
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
|
||||
|
||||
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
|
||||
|
||||
$oRuntimeEnv->UpdatePredefinedObjects();
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
|
||||
|
||||
$oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/);
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad');
|
||||
|
||||
// Record the installation so that the "about box" knows about the installed modules
|
||||
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
|
||||
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
|
||||
// Default choices = as before
|
||||
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
|
||||
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
// Plus all "remote" extensions
|
||||
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) {
|
||||
$oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
$aSelectedExtensionCodes = [];
|
||||
foreach ($oExtensionsMap->GetChoices() as $oExtension) {
|
||||
$aSelectedExtensionCodes[] = $oExtension->sCode;
|
||||
}
|
||||
$aSelectedExtensions = $oExtensionsMap->GetChoices();
|
||||
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules, $aSelectedExtensionCodes, 'Done by the iTop Hub Connector');
|
||||
|
||||
// Report the success in a way that will be detected by the ajax caller
|
||||
SetupLog::Info('Deployment successfully completed.');
|
||||
ReportSuccess(Dict::S('iTopHub:CompiledOK'));
|
||||
} catch (Exception $e) {
|
||||
if (file_exists(utils::GetDataPath().'hub/compile_authent')) {
|
||||
unlink(utils::GetDataPath().'hub/compile_authent');
|
||||
}
|
||||
// Note: at this point, the dictionnary is not necessarily loaded
|
||||
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
|
||||
SetupLog::Error('Debug trace: '.$e->getTraceAsString());
|
||||
ReportError($e->getMessage(), $e->getCode());
|
||||
} finally {
|
||||
SetupUtils::ExitReadOnlyMode();
|
||||
}
|
||||
HubController::GetInstance()->LaunchDeploy();
|
||||
break;
|
||||
|
||||
default:
|
||||
ReportError("Invalid operation: '$sOperation'", -1);
|
||||
HubController::GetInstance()->ReportError("Invalid operation: '$sOperation'", -1);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
|
||||
@@ -361,5 +103,5 @@ try {
|
||||
|
||||
utils::PopArchiveMode();
|
||||
|
||||
ReportError($e->getMessage(), $e->getCode());
|
||||
HubController::GetInstance()->ReportError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
@@ -186,9 +186,7 @@ function collect_configuration()
|
||||
|
||||
// iTop modules
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
$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");
|
||||
$aInstalledModules = ModuleInstallationRepository::GetInstance()->ReadFromDB($oConfig);
|
||||
|
||||
foreach ($aInstalledModules as $aDBInfo) {
|
||||
$aConfiguration['itop_modules'][$aDBInfo['name']] = $aDBInfo['version'];
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\HubConnector\Controller;
|
||||
|
||||
use Combodo\iTop\Application\WebPage\JsonPage;
|
||||
use Combodo\iTop\HubConnector\Model\DBBackupWithErrorReporting;
|
||||
use Combodo\iTop\HubConnector\setup\HubRunTimeEnvironment;
|
||||
use Config;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use iTopExtension;
|
||||
use iTopExtensionsMap;
|
||||
use iTopMutex;
|
||||
use LoginWebPage;
|
||||
use MetaModel;
|
||||
use MFCompiler;
|
||||
use RunTimeEnvironment;
|
||||
use SecurityException;
|
||||
use SetupLog;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
|
||||
require_once(APPROOT.'setup/runtimeenv.class.inc.php');
|
||||
require_once(APPROOT.'setup/backup.class.inc.php');
|
||||
require_once(APPROOT.'core/mutex.class.inc.php');
|
||||
require_once(APPROOT.'core/dict.class.inc.php');
|
||||
require_once(APPROOT.'setup/xmldataloader.class.inc.php');
|
||||
require_once(__DIR__.'/../setup/hubruntimeenvironment.class.inc.php');
|
||||
|
||||
class HubController
|
||||
{
|
||||
private static HubController $oInstance;
|
||||
protected $bOutputHeaders = false;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): HubController
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new HubController();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?HubController $oInstance): void
|
||||
{
|
||||
self::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
public function LaunchBackup()
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
|
||||
|
||||
try {
|
||||
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
|
||||
}
|
||||
SetupLog::Info('Backup starts...');
|
||||
set_time_limit(0);
|
||||
$sBackupPath = APPROOT.'/data/backups/manual/backup-';
|
||||
$iSuffix = 1;
|
||||
$sSuffix = '';
|
||||
// Generate a unique name...
|
||||
do {
|
||||
$sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix;
|
||||
$sSuffix = '-'.$iSuffix;
|
||||
$iSuffix++ ;
|
||||
} while (file_exists($sBackupFile));
|
||||
|
||||
$oBackup = $this->DoBackup($sBackupFile);
|
||||
$aErrors = $oBackup->GetErrors();
|
||||
if (count($aErrors) > 0) {
|
||||
SetupLog::Error('Backup failed.');
|
||||
SetupLog::Error(implode("\n", $aErrors));
|
||||
$this->ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors);
|
||||
} else {
|
||||
SetupLog::Info('Backup successfully completed.');
|
||||
$this->ReportSuccess(Dict::S('iTopHub:BackupOk'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
SetupLog::Error($e->getMessage());
|
||||
$this->ReportError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $sTargetFile
|
||||
* @throws Exception
|
||||
* @return DBBackupWithErrorReporting
|
||||
*/
|
||||
public function DoBackup($sTargetFile): DBBackupWithErrorReporting
|
||||
{
|
||||
// Make sure the target directory exists
|
||||
$sBackupDir = dirname($sTargetFile);
|
||||
SetupUtils::builddir($sBackupDir);
|
||||
|
||||
$oBackup = new DBBackupWithErrorReporting();
|
||||
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
|
||||
$sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE;
|
||||
|
||||
$oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
|
||||
$oMutex->Lock();
|
||||
try {
|
||||
$oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile);
|
||||
} catch (Exception $e) {
|
||||
$oMutex->Unlock();
|
||||
throw $e;
|
||||
}
|
||||
$oMutex->Unlock();
|
||||
return $oBackup;
|
||||
}
|
||||
|
||||
public function LaunchCompile()
|
||||
{
|
||||
SetupLog::Info('Deployment starts...');
|
||||
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
|
||||
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
|
||||
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
|
||||
}
|
||||
// First step: prepare the datamodel, if it fails, roll-back
|
||||
$aSelectedExtensionCodes = utils::ReadParam('extension_codes', []);
|
||||
$aSelectedExtensionDirs = utils::ReadParam('extension_dirs', []);
|
||||
|
||||
$oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build
|
||||
$oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs);
|
||||
|
||||
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
|
||||
if ($oConfig->Get('demo_mode')) {
|
||||
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
|
||||
}
|
||||
|
||||
$aSelectModules = $oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit
|
||||
|
||||
$oRuntimeEnv->UpdateIncludes($oConfig);
|
||||
|
||||
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
|
||||
|
||||
// Safety check: check the inter dependencies, will throw an exception in case of inconsistency
|
||||
$oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
|
||||
|
||||
$oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected
|
||||
|
||||
// Everything seems Ok so far, commit in env-production!
|
||||
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
|
||||
$oRuntimeEnv->Commit();
|
||||
|
||||
// Report the success in a way that will be detected by the ajax caller
|
||||
SetupLog::Info('Compilation completed...');
|
||||
|
||||
$this->ReportSuccess('Ok'); // No access to Dict::S here
|
||||
}
|
||||
|
||||
public function LaunchDeploy()
|
||||
{
|
||||
// Second step: update the schema and the data
|
||||
// Everything happening below is based on env-production
|
||||
$oRuntimeEnv = new RunTimeEnvironment('production', true);
|
||||
|
||||
try {
|
||||
SetupLog::Info('Move to production starts...');
|
||||
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
|
||||
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
|
||||
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
|
||||
}
|
||||
unlink(utils::GetDataPath().'hub/compile_authent');
|
||||
// Load the "production" config file to clone & update it
|
||||
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
|
||||
SetupUtils::EnterReadOnlyMode($oConfig);
|
||||
|
||||
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
|
||||
|
||||
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'BeforeDatabaseCreation');
|
||||
|
||||
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseCreation');
|
||||
|
||||
$oRuntimeEnv->UpdatePredefinedObjects();
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseSetup');
|
||||
|
||||
$oRuntimeEnv->LoadData($aAvailableModules, false /* no sample data*/);
|
||||
|
||||
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDataLoad');
|
||||
|
||||
// Record the installation so that the "about box" knows about the installed modules
|
||||
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
|
||||
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
|
||||
// Default choices = as before
|
||||
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
|
||||
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
// Plus all "remote" extensions
|
||||
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) {
|
||||
$oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
$aSelectedExtensionCodes = [];
|
||||
foreach ($oExtensionsMap->GetChoices() as $oExtension) {
|
||||
$aSelectedExtensionCodes[] = $oExtension->sCode;
|
||||
}
|
||||
$aSelectedExtensions = $oExtensionsMap->GetChoices();
|
||||
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, array_keys($aAvailableModules), $aSelectedExtensionCodes, 'Done by the iTop Hub Connector');
|
||||
|
||||
// Report the success in a way that will be detected by the ajax caller
|
||||
SetupLog::Info('Deployment successfully completed.');
|
||||
$this->ReportSuccess(Dict::S('iTopHub:CompiledOK'));
|
||||
} catch (Exception $e) {
|
||||
if (file_exists(utils::GetDataPath().'hub/compile_authent')) {
|
||||
unlink(utils::GetDataPath().'hub/compile_authent');
|
||||
}
|
||||
// Note: at this point, the dictionnary is not necessarily loaded
|
||||
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
|
||||
SetupLog::Error('Debug trace: '.$e->getTraceAsString());
|
||||
$this->ReportError($e->getMessage(), $e->getCode());
|
||||
} finally {
|
||||
SetupUtils::ExitReadOnlyMode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the status of the current ajax execution (as a JSON structure)
|
||||
*
|
||||
* @param string $sMessage
|
||||
* @param bool $bSuccess
|
||||
* @param number $iErrorCode
|
||||
* @param array $aMoreFields
|
||||
* Extra fields to pass to the caller, if needed
|
||||
*/
|
||||
public function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = [])
|
||||
{
|
||||
// Do not use AjaxPage during setup phases, because it uses InterfaceDiscovery in Twig compilation
|
||||
$this->oLastJsonPage = new JsonPage();
|
||||
$this->oLastJsonPage->SetOutputHeaders($this->bOutputHeaders);
|
||||
$aResult = [
|
||||
'code' => $iErrorCode,
|
||||
'message' => $sMessage,
|
||||
'fields' => $aMoreFields,
|
||||
];
|
||||
$this->oLastJsonPage->SetData($aResult);
|
||||
$this->oLastJsonPage->SetOutputDataOnly(true);
|
||||
$this->oLastJsonPage->output();
|
||||
}
|
||||
|
||||
private ?JsonPage $oLastJsonPage = null;
|
||||
|
||||
public function GetLastJsonPage(): ?JsonPage
|
||||
{
|
||||
return $this->oLastJsonPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to output the status of a successful execution
|
||||
*
|
||||
* @param string $sMessage
|
||||
* @param array $aMoreFields
|
||||
* Extra fields to pass to the caller, if needed
|
||||
*/
|
||||
public function ReportSuccess($sMessage, $aMoreFields = [])
|
||||
{
|
||||
$this->ReportStatus($sMessage, true, 0, $aMoreFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to output the status of a failed execution
|
||||
*
|
||||
* @param string $sMessage
|
||||
* @param number $iErrorCode
|
||||
* @param array $aMoreFields
|
||||
* Extra fields to pass to the caller, if needed
|
||||
*/
|
||||
public function ReportError($sMessage, $iErrorCode, $aMoreFields = [])
|
||||
{
|
||||
if ($iErrorCode == 0) {
|
||||
// 0 means no error, so change it if no meaningful error code is supplied
|
||||
$iErrorCode = -1;
|
||||
}
|
||||
$this->ReportStatus($sMessage, false, $iErrorCode, $aMoreFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dont print headers for testing purpose mainly
|
||||
* @param bool bOutputHeaders
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function SetOutputHeaders(bool $bOutputHeaders): void
|
||||
{
|
||||
$this->bOutputHeaders = $bOutputHeaders;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\HubConnector\Model;
|
||||
|
||||
use DBBackup;
|
||||
use IssueLog;
|
||||
|
||||
/**
|
||||
* Overload of DBBackup to handle logging
|
||||
*/
|
||||
class DBBackupWithErrorReporting extends DBBackup
|
||||
{
|
||||
protected $aInfos = [];
|
||||
|
||||
protected $aErrors = [];
|
||||
|
||||
protected function LogInfo($sMsg)
|
||||
{
|
||||
$this->aInfos[] = $sMsg;
|
||||
}
|
||||
|
||||
protected function LogError($sMsg)
|
||||
{
|
||||
IssueLog::Error($sMsg);
|
||||
$this->aErrors[] = $sMsg;
|
||||
}
|
||||
|
||||
public function GetInfos(): array
|
||||
{
|
||||
return $this->aInfos;
|
||||
}
|
||||
|
||||
public function GetErrors(): array
|
||||
{
|
||||
return $this->aErrors;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\HubConnector\setup;
|
||||
|
||||
use Config;
|
||||
use Exception;
|
||||
use RunTimeEnvironment;
|
||||
use SetupUtils;
|
||||
|
||||
class HubRunTimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $sEnvironment
|
||||
* @param string $bAutoCommit
|
||||
*/
|
||||
@@ -24,6 +32,7 @@ class HubRunTimeEnvironment extends RunTimeEnvironment
|
||||
|
||||
/**
|
||||
* Update the includes for the target environment
|
||||
*
|
||||
* @param Config $oConfig
|
||||
*/
|
||||
public function UpdateIncludes(Config $oConfig)
|
||||
@@ -33,7 +42,9 @@ class HubRunTimeEnvironment extends RunTimeEnvironment
|
||||
|
||||
/**
|
||||
* Move an extension (path to folder of this extension) to the target environment
|
||||
*
|
||||
* @param string $sExtensionDirectory The folder of the extension
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function MoveExtension($sExtensionDirectory)
|
||||
@@ -57,8 +68,10 @@ class HubRunTimeEnvironment extends RunTimeEnvironment
|
||||
|
||||
/**
|
||||
* Move the selected extensions located in the given directory in data/<target-env>-modules
|
||||
*
|
||||
* @param string $sDownloadedExtensionsDir The directory to scan
|
||||
* @param string[] $aSelectedExtensionDirs The list of folders to move
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function MoveSelectedExtensions($sDownloadedExtensionsDir, $aSelectedExtensionDirs)
|
||||
@@ -76,6 +76,9 @@
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -176,17 +179,32 @@
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
</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="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="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>
|
||||
@@ -1133,6 +1151,9 @@ 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">
|
||||
@@ -1184,17 +1205,32 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
</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="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="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>
|
||||
@@ -1537,6 +1573,9 @@ 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">
|
||||
@@ -1585,17 +1624,32 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
</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="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="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,6 +76,9 @@
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<obsolescence>
|
||||
<condition><![CDATA[status='obsolete']]></condition>
|
||||
</obsolescence>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
@@ -176,17 +179,32 @@
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
</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="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="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>
|
||||
@@ -1122,6 +1140,9 @@ 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">
|
||||
@@ -1173,17 +1194,32 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
</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="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="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>
|
||||
@@ -1548,6 +1584,9 @@ 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">
|
||||
@@ -1596,17 +1635,32 @@ public function PrefillSearchForm(&$aContextParam)
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="production">
|
||||
<code>production</code>
|
||||
<rank>20</rank>
|
||||
</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="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="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,14 +1486,29 @@
|
||||
<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>
|
||||
|
||||
@@ -12,8 +12,7 @@ SetupWebPage::AddModule(
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-structure/2.7.1',
|
||||
'itop-portal/3.0.0', // module_design_itop_design->module_designs->itop-portal
|
||||
'itop-structure/2.7.1 || itop-portal/3.0.0', // itop-portal : module_design_itop_design->module_designs->itop-portal
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
|
||||
@@ -43,18 +43,38 @@
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installé',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'va être installé',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'pas installé',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'va être désinstallé',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'non désinstallable',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'supprimé du disque',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'À propos de %1$s',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'Plus d\'informations',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Forcer la désinstallation',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license https://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
'UI:Layout:ExtensionsDetails:BadgeInstalled' => 'installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~',
|
||||
'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
]);
|
||||
@@ -26,23 +26,12 @@ 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
|
||||
*/
|
||||
@@ -320,24 +309,6 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,9 +325,7 @@ 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')) {
|
||||
@@ -364,14 +333,11 @@ class InstalledVersions
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,8 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\AbstractUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/AbstractUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\Alert' => $baseDir . '/sources/Application/UI/Base/Component/Alert/Alert.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\AlertUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Alert/AlertUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\Badge' => $baseDir . '/sources/Application/UI/Base/Component/Badge/Badge.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\BadgeUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Badge/BadgeUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Breadcrumbs\\Breadcrumbs' => $baseDir . '/sources/Application/UI/Base/Component/Breadcrumbs/Breadcrumbs.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroup' => $baseDir . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroup.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroupUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroupUIBlockFactory.php',
|
||||
@@ -268,6 +270,8 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetails' => $baseDir . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetails.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetailsUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php',
|
||||
|
||||
@@ -537,6 +537,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\AbstractUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/AbstractUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\Alert' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Alert/Alert.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\AlertUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Alert/AlertUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\Badge' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Badge/Badge.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\BadgeUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Badge/BadgeUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Breadcrumbs\\Breadcrumbs' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Breadcrumbs/Breadcrumbs.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroup' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroup.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroupUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroupUIBlockFactory.php',
|
||||
@@ -649,6 +651,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetails' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetails.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetailsUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'name' => 'combodo/itop',
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => '19d062aa830b6d6c7d17ac4046fc9ee2c5e3fab1',
|
||||
'reference' => '469afdb2f9aea1b6e078a2a5bb12f09a969d60e0',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -22,7 +22,7 @@
|
||||
'combodo/itop' => array(
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => '19d062aa830b6d6c7d17ac4046fc9ee2c5e3fab1',
|
||||
'reference' => '469afdb2f9aea1b6e078a2a5bb12f09a969d60e0',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
||||
14
setup/SetupDBBackup.php
Normal file
14
setup/SetupDBBackup.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
class SetupDBBackup extends DBBackup
|
||||
{
|
||||
protected function LogInfo($sMsg)
|
||||
{
|
||||
SetupLog::Ok('Info - '.$sMsg);
|
||||
}
|
||||
|
||||
protected function LogError($sMsg)
|
||||
{
|
||||
SetupLog::Ok('Error - '.$sMsg);
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
$sOperation = Utils::ReadParam('operation', '');
|
||||
$sOperation = utils::ReadParam('operation', '');
|
||||
try {
|
||||
SetupUtils::CheckSetupToken();
|
||||
|
||||
@@ -138,8 +138,7 @@ try {
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
|
||||
require_once(APPROOT.'/setup/wizardsteps.class.inc.php');
|
||||
require_once(APPROOT.'/setup/wizardsteps_autoload.php');
|
||||
|
||||
$sClass = utils::ReadParam('step_class', '');
|
||||
$sState = utils::ReadParam('step_state', '');
|
||||
@@ -164,7 +163,7 @@ try {
|
||||
break;
|
||||
|
||||
case 'toggle_use_symbolic_links':
|
||||
$sUseSymbolicLinks = Utils::ReadParam('bUseSymbolicLinks', false);
|
||||
$sUseSymbolicLinks = utils::ReadParam('bUseSymbolicLinks', false);
|
||||
$bUseSymbolicLinks = ($sUseSymbolicLinks === 'true');
|
||||
MFCompiler::SetUseSymbolicLinksFlag($bUseSymbolicLinks);
|
||||
echo "toggle useSymbolicLinks flag : $bUseSymbolicLinks";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,8 +21,8 @@
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\DesignElement;
|
||||
use Combodo\iTop\DesignDocument;
|
||||
use Combodo\iTop\DesignElement;
|
||||
|
||||
require_once(APPROOT.'setup/setuputils.class.inc.php');
|
||||
require_once(APPROOT.'setup/modelfactory.class.inc.php');
|
||||
@@ -278,7 +278,7 @@ class MFCompiler
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function Compile($sTargetDir, $oP = null, $bUseSymbolicLinks = null, $bSkipTempDir = false)
|
||||
public function Compile($sTargetDir, $oP = null, $bUseSymbolicLinks = null, $bSkipTempDir = false, $bEnterMaintenanceMode = true)
|
||||
{
|
||||
if (is_null($bUseSymbolicLinks)) {
|
||||
$bUseSymbolicLinks = false;
|
||||
@@ -297,8 +297,7 @@ class MFCompiler
|
||||
} else {
|
||||
$oConfig = null;
|
||||
}
|
||||
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) {
|
||||
|
||||
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
|
||||
SetupUtils::EnterMaintenanceMode($oConfig);
|
||||
}
|
||||
if ($bUseSymbolicLinks || $bSkipTempDir) {
|
||||
@@ -321,7 +320,7 @@ class MFCompiler
|
||||
// Cleanup the temporary directory
|
||||
SetupUtils::rrmdir($sTempTargetDir);
|
||||
}
|
||||
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) {
|
||||
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
|
||||
SetupUtils::ExitMaintenanceMode();
|
||||
}
|
||||
throw $e;
|
||||
@@ -331,7 +330,7 @@ class MFCompiler
|
||||
// Move the results to the target directory
|
||||
SetupUtils::movedir($sTempTargetDir, $sFinalTargetDir);
|
||||
}
|
||||
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) {
|
||||
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
|
||||
SetupUtils::ExitMaintenanceMode();
|
||||
}
|
||||
|
||||
@@ -3357,6 +3356,8 @@ EOF;
|
||||
|
||||
$bDataXmlPrecompiledFileExists = false;
|
||||
clearstatcache();
|
||||
|
||||
$iDataXmlFileLastModified = 0;
|
||||
if (!empty($sPrecompiledFileUri)) {
|
||||
$sDataXmlProvidedPrecompiledFile = $sTempTargetDir.DIRECTORY_SEPARATOR.$sPrecompiledFileUri;
|
||||
$bDataXmlPrecompiledFileExists = file_exists($sDataXmlProvidedPrecompiledFile) ;
|
||||
|
||||
@@ -34,7 +34,7 @@ require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
|
||||
|
||||
$sOperation = Utils::ReadParam('operation', 'step1');
|
||||
$sOperation = utils::ReadParam('operation', 'step1');
|
||||
$oP = new SetupPage('iTop email test utility');
|
||||
|
||||
// Although this page doesn't expose sensitive info, with it we can send multiple emails
|
||||
@@ -208,7 +208,7 @@ function DisplayStep2(SetupPage $oP, $sFrom, $sTo)
|
||||
$oP->add("<p>Sending an email to '".htmlentities($sTo, ENT_QUOTES, 'utf-8')."'... (From: '".htmlentities($sFrom, ENT_QUOTES, 'utf-8')."')</p>\n");
|
||||
$oP->add("<form method=\"post\">\n");
|
||||
|
||||
$oEmail = new Email();
|
||||
$oEmail = new EMail();
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetSubject("Test iTop");
|
||||
@@ -256,8 +256,8 @@ try {
|
||||
|
||||
case 'step2':
|
||||
$oP->no_cache();
|
||||
$sTo = Utils::ReadParam('to', '', false, 'raw_data');
|
||||
$sFrom = Utils::ReadParam('from', '', false, 'raw_data');
|
||||
$sTo = utils::ReadParam('to', '', false, 'raw_data');
|
||||
$sFrom = utils::ReadParam('from', '', false, 'raw_data');
|
||||
DisplayStep2($oP, $sFrom, $sTo);
|
||||
break;
|
||||
|
||||
|
||||
@@ -3,143 +3,11 @@
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader;
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException;
|
||||
|
||||
require_once(APPROOT.'/setup/itopextension.class.inc.php');
|
||||
require_once(APPROOT.'/setup/parameters.class.inc.php');
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
require_once(APPROOT.'/setup/modulediscovery.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
/**
|
||||
* Basic helper class to describe an extension, with some characteristics and a list of modules
|
||||
*/
|
||||
class iTopExtension
|
||||
{
|
||||
public const SOURCE_WIZARD = 'datamodels';
|
||||
public const SOURCE_MANUAL = 'extensions';
|
||||
public const SOURCE_REMOTE = 'data';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sCode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sVersion;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sInstalledVersion;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sLabel;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sDescription;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sSource;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bMandatory;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sMoreInfoUrl;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bMarkedAsChosen;
|
||||
/**
|
||||
* If null, check if at least one module cannot be uninstalled
|
||||
* @var bool|null
|
||||
*/
|
||||
public ?bool $bCanBeUninstalled = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bVisible;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $aModules;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $aModuleVersion;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $aModuleInfo;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sSourceDir;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $aMissingDependencies;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public bool $bInstalled = false;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public bool $bRemovedFromDisk = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->sCode = '';
|
||||
$this->sLabel = '';
|
||||
$this->sDescription = '';
|
||||
$this->sSource = self::SOURCE_WIZARD;
|
||||
$this->bMandatory = false;
|
||||
$this->sMoreInfoUrl = '';
|
||||
$this->bMarkedAsChosen = false;
|
||||
$this->sVersion = ITOP_VERSION;
|
||||
$this->sInstalledVersion = '';
|
||||
$this->aModules = [];
|
||||
$this->aModuleVersion = [];
|
||||
$this->aModuleInfo = [];
|
||||
$this->sSourceDir = '';
|
||||
$this->bVisible = true;
|
||||
$this->aMissingDependencies = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.3.0
|
||||
* @return bool
|
||||
*/
|
||||
public function CanBeUninstalled(): bool
|
||||
{
|
||||
if (!is_null($this->bCanBeUninstalled)) {
|
||||
return $this->bCanBeUninstalled;
|
||||
}
|
||||
foreach ($this->aModuleInfo as $sModuleCode => $aModuleInfo) {
|
||||
$this->bCanBeUninstalled = $aModuleInfo['uninstallable'] === 'yes';
|
||||
return $this->bCanBeUninstalled;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to discover all available extensions on a given iTop system
|
||||
@@ -148,32 +16,38 @@ class iTopExtensionsMap
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
* @var array $aExtensions
|
||||
*/
|
||||
protected $aExtensions;
|
||||
/**
|
||||
* The list of all currently installed extensions
|
||||
* @var array|null
|
||||
* @var array $aInstalledExtensions
|
||||
*/
|
||||
protected ?array $aInstalledExtensions = null;
|
||||
protected array $aInstalledExtensions;
|
||||
|
||||
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($sFromEnvironment);
|
||||
$this->CheckDependencies();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,8 +58,10 @@ class iTopExtensionsMap
|
||||
*/
|
||||
protected function ScanDisk($sEnvironment)
|
||||
{
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x') && !$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) {
|
||||
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->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);
|
||||
}
|
||||
}
|
||||
@@ -261,6 +137,7 @@ 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
|
||||
@@ -270,6 +147,22 @@ 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]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,12 +173,28 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function GetFromExtensionCode(string $sExtensionCode): ?iTopExtension
|
||||
{
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode === $sExtensionCode) {
|
||||
return $oExtension;
|
||||
return $this->aExtensionsByCode[$sExtensionCode] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $aExtensionCodes
|
||||
* @return void
|
||||
*/
|
||||
public function DeclareExtensionAsRemoved(array $aExtensionCodes): void
|
||||
{
|
||||
$aRemovedExtension = [];
|
||||
foreach ($aExtensionCodes as $sCode) {
|
||||
/** @var \iTopExtension $oExtension */
|
||||
$oExtension = $this->GetFromExtensionCode($sCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$aRemovedExtension [] = $oExtension;
|
||||
\IssueLog::Info(__METHOD__.": remove extension locally", null, ['extension_code' => $oExtension->sCode]);
|
||||
} else {
|
||||
\IssueLog::Warning(__METHOD__." cannot find extensions", null, ['code' => $sCode]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
ModuleDiscovery::DeclareRemovedExtensions($aRemovedExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,19 +255,15 @@ 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';
|
||||
|
||||
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
|
||||
$oExtension = null;
|
||||
if ($sParentExtensionId !== null) {
|
||||
$oExtension = $this->aExtensions[$sParentExtensionId] ?? null;
|
||||
}
|
||||
|
||||
if (is_null($oExtension)) {
|
||||
// Not already inside an 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
|
||||
@@ -382,6 +287,13 @@ 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);
|
||||
@@ -403,10 +315,9 @@ 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($sFromEnvironment)
|
||||
protected function CheckDependencies()
|
||||
{
|
||||
$aSearchDirs = [];
|
||||
|
||||
@@ -418,7 +329,7 @@ class iTopExtensionsMap
|
||||
$aSearchDirs = array_merge($aSearchDirs, $this->aScannedDirs);
|
||||
|
||||
try {
|
||||
$aAllModules = ModuleDiscovery::GetAvailableModules($aSearchDirs, true);
|
||||
ModuleDiscovery::GetModulesOrderedByDependencies($aSearchDirs, true);
|
||||
} catch (MissingDependencyException $e) {
|
||||
// Some modules have missing dependencies
|
||||
// Let's check what is the impact at the "extensions" level
|
||||
@@ -458,6 +369,75 @@ class iTopExtensionsMap
|
||||
return array_merge($this->aInstalledExtensions ?? [], $this->aExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bKeepMissingDependencyExtensions
|
||||
*
|
||||
* @return array<\iTopExtension>>
|
||||
*/
|
||||
|
||||
public function GetAllExtensionsToDisplayInSetup(bool $bKeepMissingDependencyExtensions = false, bool $bRemoteExtensionsShouldBeMandatory = true): array
|
||||
{
|
||||
$aRes = [];
|
||||
foreach ($this->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) {
|
||||
/** @var \iTopExtension $oExtension */
|
||||
if ($oExtension->sSource !== iTopExtension::SOURCE_WIZARD && $oExtension->bVisible) {
|
||||
if ($bKeepMissingDependencyExtensions || count($oExtension->aMissingDependencies) == 0) {
|
||||
if (!$oExtension->bMandatory && $bRemoteExtensionsShouldBeMandatory) {
|
||||
$oExtension->bMandatory = ($oExtension->sSource === iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
$aRes[$oExtension->sCode] = $oExtension;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function GetAllExtensionsOptionInfo(bool $bRemoteExtensionsShouldBeMandatory = true): array
|
||||
{
|
||||
$aRes = [];
|
||||
foreach ($this->GetAllExtensionsToDisplayInSetup(false, $bRemoteExtensionsShouldBeMandatory) as $sCode => $oExtension) {
|
||||
$aRes[] = [
|
||||
'extension_code' => $oExtension->sCode,
|
||||
'title' => $oExtension->sLabel,
|
||||
'description' => $oExtension->sDescription,
|
||||
'more_info' => $oExtension->sMoreInfoUrl,
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory,
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
'uninstallable' => $oExtension->CanBeUninstalled(),
|
||||
'missing' => $oExtension->bRemovedFromDisk,
|
||||
];
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
protected function GetExtensionSourceLabel($sSource)
|
||||
{
|
||||
$sDecorationClass = '';
|
||||
switch ($sSource) {
|
||||
case iTopExtension::SOURCE_MANUAL:
|
||||
$sResult = 'Local extensions folder';
|
||||
$sDecorationClass = 'fas fa-folder';
|
||||
break;
|
||||
|
||||
case iTopExtension::SOURCE_REMOTE:
|
||||
$sResult = (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer';
|
||||
$sDecorationClass = (ITOP_APPLICATION == 'iTop') ? 'fc fc-chameleon-icon' : 'fa pencil-ruler';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sResult = '';
|
||||
}
|
||||
if ($sResult == '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<i class="setup-extension--icon '.$sDecorationClass.'" data-tooltip-content="'.$sResult.'"></i>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the given extension as chosen
|
||||
* @param string $sExtensionCode The code of the extension (code without version number)
|
||||
@@ -466,11 +446,17 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function MarkAsChosen($sExtensionCode, $bMark = true)
|
||||
{
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode == $sExtensionCode) {
|
||||
$oExtension->bMarkedAsChosen = $bMark;
|
||||
break;
|
||||
}
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,11 +467,11 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function IsMarkedAsChosen($sExtensionCode)
|
||||
{
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode == $sExtensionCode) {
|
||||
return $oExtension->bMarkedAsChosen;
|
||||
}
|
||||
$oExtension = $this->GetFromExtensionCode($sExtensionCode);
|
||||
if (!is_null($oExtension)) {
|
||||
return $oExtension->bMarkedAsChosen;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -497,11 +483,9 @@ class iTopExtensionsMap
|
||||
*/
|
||||
protected function SetInstalledVersion($sExtensionCode, $sInstalledVersion)
|
||||
{
|
||||
foreach ($this->aExtensions as $oExtension) {
|
||||
if ($oExtension->sCode == $sExtensionCode) {
|
||||
$oExtension->sInstalledVersion = $sInstalledVersion;
|
||||
break;
|
||||
}
|
||||
$oExtension = $this->GetFromExtensionCode($sExtensionCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$oExtension->sInstalledVersion = $sInstalledVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,14 +511,19 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function LoadChoicesFromDatabase(Config $oConfig)
|
||||
{
|
||||
foreach ($this->LoadInstalledExtensionsFromDatabase($oConfig) as $oExtension) {
|
||||
$aLoadInstalledExtensionsFromDatabase = $this->LoadInstalledExtensionsFromDatabase($oConfig);
|
||||
if (false === $aLoadInstalledExtensionsFromDatabase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($aLoadInstalledExtensionsFromDatabase as $oExtension) {
|
||||
$this->MarkAsChosen($oExtension->sCode);
|
||||
$this->SetInstalledVersion($oExtension->sCode, $oExtension->sVersion);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function LoadInstalledExtensionsFromDatabase(Config $oConfig): array|false
|
||||
public function LoadInstalledExtensionsFromDatabase(Config $oConfig): array|false
|
||||
{
|
||||
try {
|
||||
if (CMDBSource::DBName() === null) {
|
||||
@@ -577,6 +566,27 @@ class iTopExtensionsMap
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetChoicesFromDatabase(Config $oConfig): array|false
|
||||
{
|
||||
try {
|
||||
if (CMDBSource::DBName() === null) {
|
||||
CMDBSource::InitFromConfig($oConfig);
|
||||
}
|
||||
$sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->Get('db_subname')."priv_extension_install");
|
||||
$aDBInfo = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_extension_install WHERE installed = '".$sLatestInstallationDate."'");
|
||||
|
||||
$aChoices = [];
|
||||
foreach ($aDBInfo as $aExtensionInfo) {
|
||||
$aChoices[] = $aExtensionInfo['code'];
|
||||
}
|
||||
|
||||
return $aChoices;
|
||||
} catch (MySQLException $e) {
|
||||
// No database or erroneous information
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the given module name is "chosen" since it is part of a "chosen" extension (in the specified source dir)
|
||||
* @param string $sModuleNameToFind
|
||||
@@ -585,8 +595,6 @@ class iTopExtensionsMap
|
||||
*/
|
||||
public function ModuleIsChosenAsPartOfAnExtension($sModuleNameToFind, $sInSourceOnly = iTopExtension::SOURCE_REMOTE)
|
||||
{
|
||||
$bChosen = false;
|
||||
|
||||
foreach ($this->GetAllExtensions() as $oExtension) {
|
||||
if (($oExtension->sSource == $sInSourceOnly) &&
|
||||
($oExtension->bMarkedAsChosen == true) &&
|
||||
|
||||
105
setup/feature_removal/AbstractSetupAudit.php
Normal file
105
setup/feature_removal/AbstractSetupAudit.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use ContextTag;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use SetupLog;
|
||||
|
||||
require_once APPROOT.'setup/feature_removal/ModelReflectionSerializer.php';
|
||||
|
||||
abstract class AbstractSetupAudit
|
||||
{
|
||||
protected bool $bClassesInitialized = false;
|
||||
protected array $aClassesBefore = [];
|
||||
protected array $aClassesAfter = [];
|
||||
protected array $aRemovedClasses = [];
|
||||
protected array $aFinalClassesToCleanup = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
abstract public function ComputeClasses(): void;
|
||||
|
||||
public function GetRemovedClasses(): array
|
||||
{
|
||||
$this->ComputeClasses();
|
||||
|
||||
if (count($this->aRemovedClasses) == 0) {
|
||||
if (count($this->aClassesBefore) == 0) {
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
if (count($this->aClassesAfter) == 0) {
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
$aExtensionsNames = array_diff($this->aClassesBefore, $this->aClassesAfter);
|
||||
$this->aRemovedClasses = [];
|
||||
$aClasses = array_values($aExtensionsNames);
|
||||
sort($aClasses);
|
||||
|
||||
foreach ($aClasses as $i => $sClass) {
|
||||
$this->aRemovedClasses[] = $sClass;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
public function GetIssues(bool $bStopDataCheckAtFirstIssue = false): array
|
||||
{
|
||||
$this->aFinalClassesToCleanup = [];
|
||||
|
||||
foreach ($this->GetRemovedClasses() as $sClass) {
|
||||
if (MetaModel::IsAbstract($sClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!MetaModel::IsStandaloneClass($sClass)) {
|
||||
$iCount = $this->Count($sClass);
|
||||
$this->aFinalClassesToCleanup[$sClass] = $iCount;
|
||||
if ($bStopDataCheckAtFirstIssue && $iCount > 0) {
|
||||
//setup envt: should raise issue ASAP
|
||||
$this->LogInfoWithProperLogger("Setup audit found data to cleanup", null, $this->aFinalClassesToCleanup);
|
||||
return $this->aFinalClassesToCleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->LogInfoWithProperLogger("Setup audit found data to cleanup", null, ['data_to_cleanup' => $this->aFinalClassesToCleanup]);
|
||||
return $this->aFinalClassesToCleanup;
|
||||
}
|
||||
|
||||
public function GetDataToCleanupCount(): int
|
||||
{
|
||||
$res = 0;
|
||||
foreach ($this->aFinalClassesToCleanup as $sClass => $iCount) {
|
||||
$res += $iCount;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
private function Count($sClass): int
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT $sClass", []);
|
||||
$oSearch->AllowAllData();
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
|
||||
return $oSet->Count();
|
||||
}
|
||||
|
||||
//could be shared with others in log APIs ?
|
||||
private function LogInfoWithProperLogger($sMessage, $sChannel = null, $aContext = []): void
|
||||
{
|
||||
if (ContextTag::Check(ContextTag::TAG_SETUP)) {
|
||||
SetupLog::Info($sMessage, $sChannel, $aContext);
|
||||
} else {
|
||||
IssueLog::Info($sMessage, $sChannel, $aContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
104
setup/feature_removal/DryRemovalRuntimeEnvironment.php
Normal file
104
setup/feature_removal/DryRemovalRuntimeEnvironment.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use Combodo\iTop\Setup\ModuleDependency\Module;
|
||||
use Config;
|
||||
use InstallationChoicesToModuleConverter;
|
||||
use iTopExtensionsMap;
|
||||
use MetaModel;
|
||||
use ModuleDiscovery;
|
||||
use RunTimeEnvironment;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
|
||||
class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
public const DRY_REMOVAL_AUDIT_ENV = "extension-removal";
|
||||
|
||||
protected array $aExtensionsByCode;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
$this->Cleanup();
|
||||
SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sEnv-modules");
|
||||
|
||||
$this->DeclareExtensionAsRemoved($aExtensionCodesToRemove);
|
||||
|
||||
$oDryRemovalConfig = clone(MetaModel::GetConfig());
|
||||
$oDryRemovalConfig->ChangeModulesPath($sSourceEnv, $this->sFinalEnv);
|
||||
$this->WriteConfigFileSafe($oDryRemovalConfig);
|
||||
|
||||
$sSourceDir = $oDryRemovalConfig->Get('source_dir');
|
||||
$aSearchDirs = $this->GetExtraDirsToCompile($sSourceDir);
|
||||
|
||||
$aModulesToLoad = $this->GetModulesToLoad($sSourceEnv, $aSearchDirs);
|
||||
|
||||
try {
|
||||
ModuleDiscovery::GetModulesOrderedByDependencies($aSearchDirs, true, $aModulesToLoad);
|
||||
} catch (\MissingDependencyException $e) {
|
||||
\IssueLog::Error("Cannot prepare setup due to dependency issue", null, ['msg' => $e->getMessage(), 'modules_to_load' => $aModulesToLoad]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function DeclareExtensionAsRemoved(array $aExtensionCodes): void
|
||||
{
|
||||
$oExtensionsMap = new iTopExtensionsMap($this->sFinalEnv);
|
||||
$oExtensionsMap->DeclareExtensionAsRemoved($aExtensionCodes);
|
||||
}
|
||||
|
||||
private function GetModulesToLoad(string $sSourceEnv, $aSearchDirs): array
|
||||
{
|
||||
$oSourceConfig = new Config(utils::GetConfigFilePath($sSourceEnv));
|
||||
$aChoices = iTopExtensionsMap::GetChoicesFromDatabase($oSourceConfig);
|
||||
$sSourceDir = $oSourceConfig->Get('source_dir');
|
||||
|
||||
$sInstallFilePath = APPROOT.$sSourceDir.'/installation.xml';
|
||||
if (! is_file($sInstallFilePath)) {
|
||||
$sInstallFilePath = null;
|
||||
}
|
||||
|
||||
$aModuleIdsToLoad = InstallationChoicesToModuleConverter::GetInstance()->GetModules($aChoices, $aSearchDirs, $sInstallFilePath);
|
||||
$aModulesToLoad = [];
|
||||
foreach ($aModuleIdsToLoad as $sModuleId) {
|
||||
$oModule = new Module($sModuleId);
|
||||
$sModuleName = $oModule->GetModuleName();
|
||||
$aModulesToLoad[] = $sModuleName;
|
||||
}
|
||||
return $aModulesToLoad;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
40
setup/feature_removal/InplaceSetupAudit.php
Normal file
40
setup/feature_removal/InplaceSetupAudit.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use MetaModel;
|
||||
|
||||
require_once __DIR__.'/AbstractSetupAudit.php';
|
||||
require_once APPROOT.'setup/feature_removal/ModelReflectionSerializer.php';
|
||||
|
||||
class InplaceSetupAudit extends AbstractSetupAudit
|
||||
{
|
||||
//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 $sEnvAfter;
|
||||
|
||||
public function __construct(array $aClassesBefore, string $sEnvAfter)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->aClassesBefore = $aClassesBefore;
|
||||
$this->sEnvAfter = $sEnvAfter;
|
||||
}
|
||||
|
||||
public function ComputeClasses(): void
|
||||
{
|
||||
if ($this->bClassesInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sCurrentEnvt = MetaModel::GetEnvironment();
|
||||
|
||||
if ($sCurrentEnvt === $this->sEnvAfter) {
|
||||
$this->aClassesAfter = MetaModel::GetClasses();
|
||||
} else {
|
||||
$this->aClassesAfter = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvAfter);
|
||||
}
|
||||
|
||||
$this->bClassesInitialized = true;
|
||||
}
|
||||
}
|
||||
86
setup/feature_removal/ModelReflectionSerializer.php
Normal file
86
setup/feature_removal/ModelReflectionSerializer.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use ContextTag;
|
||||
use CoreException;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use SetupLog;
|
||||
use utils;
|
||||
|
||||
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]);
|
||||
|
||||
$sCurrentEnvt = MetaModel::GetEnvironment();
|
||||
if ($sCurrentEnvt === $sEnv) {
|
||||
$aClasses = MetaModel::GetClasses();
|
||||
if (count($aClasses) === 0) {
|
||||
//MetaModel not started yet
|
||||
$sConfFile = utils::GetConfigFilePath($sEnv);
|
||||
|
||||
MetaModel::Startup($sConfFile, false /* $bModelOnly */, false /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
$aClasses = MetaModel::GetClasses();
|
||||
}
|
||||
return $aClasses;
|
||||
}
|
||||
|
||||
$sPHPExec = trim(utils::GetConfig()->Get('php_path'));
|
||||
$sOutput = "";
|
||||
$iRes = 0;
|
||||
|
||||
$sCommandLine = sprintf("$sPHPExec %s/get_model_reflection.php --env=%s", __DIR__, escapeshellarg($sEnv));
|
||||
exec($sCommandLine, $sOutput, $iRes);
|
||||
if ($iRes != 0) {
|
||||
$this->LogErrorWithProperLogger("Cannot get classes", null, ['env' => $sEnv, 'code' => $iRes, "output" => $sOutput]);
|
||||
throw new CoreException("Cannot get classes from env ".$sEnv);
|
||||
}
|
||||
|
||||
$aClasses = json_decode($sOutput[0] ?? null, true);
|
||||
if (false === $aClasses) {
|
||||
$this->LogErrorWithProperLogger("Invalid JSON", null, ['env' => $sEnv, "output" => $sOutput]);
|
||||
throw new Exception("cannot get classes");
|
||||
}
|
||||
|
||||
if (!is_array($aClasses)) {
|
||||
$this->LogErrorWithProperLogger("not an array", null, ['env' => $sEnv, "classes" => $aClasses, "output" => $sOutput]);
|
||||
throw new Exception("cannot get classes from $sEnv");
|
||||
}
|
||||
|
||||
return $aClasses;
|
||||
}
|
||||
|
||||
//could be shared with others in log APIs ?
|
||||
private function LogErrorWithProperLogger($sMessage, $sChannel = null, $aContext = []): void
|
||||
{
|
||||
if (ContextTag::Check(ContextTag::TAG_SETUP)) {
|
||||
SetupLog::Error($sMessage, $sChannel, $aContext);
|
||||
} else {
|
||||
IssueLog::Error($sMessage, $sChannel, $aContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
setup/feature_removal/SetupAudit.php
Normal file
60
setup/feature_removal/SetupAudit.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
require_once __DIR__.'/AbstractSetupAudit.php';
|
||||
require_once APPROOT.'setup/feature_removal/ModelReflectionSerializer.php';
|
||||
|
||||
class SetupAudit extends AbstractSetupAudit
|
||||
{
|
||||
//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 $sEnvBefore;
|
||||
private string $sEnvAfter;
|
||||
|
||||
public function __construct(string $sEnvBefore, string $sEnvAfter)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->sEnvBefore = $sEnvBefore;
|
||||
$this->sEnvAfter = $sEnvAfter;
|
||||
}
|
||||
|
||||
public function ComputeClasses(): void
|
||||
{
|
||||
if ($this->bClassesInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->aClassesBefore = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvBefore);
|
||||
$this->aClassesAfter = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvAfter);
|
||||
|
||||
$this->bClassesInitialized = true;
|
||||
}
|
||||
|
||||
public function GetRemovedClasses(): array
|
||||
{
|
||||
$this->ComputeClasses();
|
||||
|
||||
if (count($this->aRemovedClasses) == 0) {
|
||||
if (count($this->aClassesBefore) == 0) {
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
if (count($this->aClassesAfter) == 0) {
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
$aExtensionsNames = array_diff($this->aClassesBefore, $this->aClassesAfter);
|
||||
$this->aRemovedClasses = [];
|
||||
$aClasses = array_values($aExtensionsNames);
|
||||
sort($aClasses);
|
||||
|
||||
foreach ($aClasses as $i => $sClass) {
|
||||
$this->aRemovedClasses[] = $sClass;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
}
|
||||
41
setup/feature_removal/get_model_reflection.php
Normal file
41
setup/feature_removal/get_model_reflection.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?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 */, false /* $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);
|
||||
144
setup/itopextension.class.inc.php
Normal file
144
setup/itopextension.class.inc.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader;
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException;
|
||||
|
||||
require_once(APPROOT.'/setup/parameters.class.inc.php');
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
require_once(APPROOT.'/setup/modulediscovery.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
|
||||
/**
|
||||
* Basic helper class to describe an extension, with some characteristics and a list of modules
|
||||
*/
|
||||
class iTopExtension
|
||||
{
|
||||
public const SOURCE_WIZARD = 'datamodels';
|
||||
public const SOURCE_MANUAL = 'extensions';
|
||||
public const SOURCE_REMOTE = 'data';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sCode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sVersion;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sInstalledVersion;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sLabel;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sDescription;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sSource;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bMandatory;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sMoreInfoUrl;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bMarkedAsChosen;
|
||||
/**
|
||||
* If null, check if at least one module cannot be uninstalled
|
||||
* @var bool|null
|
||||
*/
|
||||
public ?bool $bCanBeUninstalled = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bVisible;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $aModules;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $aModuleVersion;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $aModuleInfo;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sSourceDir;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $aMissingDependencies;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public bool $bInstalled = false;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public bool $bRemovedFromDisk = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->sCode = '';
|
||||
$this->sLabel = '';
|
||||
$this->sDescription = '';
|
||||
$this->sSource = self::SOURCE_WIZARD;
|
||||
$this->bMandatory = false;
|
||||
$this->sMoreInfoUrl = '';
|
||||
$this->bMarkedAsChosen = false;
|
||||
$this->sVersion = ITOP_VERSION;
|
||||
$this->sInstalledVersion = '';
|
||||
$this->aModules = [];
|
||||
$this->aModuleVersion = [];
|
||||
$this->aModuleInfo = [];
|
||||
$this->sSourceDir = '';
|
||||
$this->bVisible = true;
|
||||
$this->aMissingDependencies = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.3.0
|
||||
* @return bool
|
||||
*/
|
||||
public function CanBeUninstalled(): bool
|
||||
{
|
||||
if (!is_null($this->bCanBeUninstalled)) {
|
||||
return $this->bCanBeUninstalled;
|
||||
}
|
||||
foreach ($this->aModuleInfo as $sModuleCode => $aModuleInfo) {
|
||||
if ($aModuleInfo['uninstallable'] !== 'yes') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1801,7 +1801,7 @@ EOF
|
||||
*/
|
||||
public function FindModules()
|
||||
{
|
||||
$aAvailableModules = ModuleDiscovery::GetAvailableModules($this->aRootDirs);
|
||||
$aAvailableModules = ModuleDiscovery::GetModulesOrderedByDependencies($this->aRootDirs);
|
||||
$aResult = [];
|
||||
foreach ($aAvailableModules as $sId => $aModule) {
|
||||
$oModule = new MFModule($sId, $aModule['root_dir'], $aModule['label'], isset($aModule['auto_select']));
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Combodo\iTop\Setup\ModuleDependency;
|
||||
require_once(APPROOT.'/setup/runtimeenv.class.inc.php');
|
||||
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
use ModuleFileReaderException;
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException;
|
||||
use RunTimeEnvironment;
|
||||
|
||||
/**
|
||||
@@ -61,19 +61,19 @@ class DependencyExpression
|
||||
}
|
||||
}
|
||||
|
||||
private static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator
|
||||
public static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator
|
||||
{
|
||||
if (!isset(static::$oPhpExpressionEvaluator)) {
|
||||
static::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST);
|
||||
if (!isset(self::$oPhpExpressionEvaluator)) {
|
||||
self::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST);
|
||||
}
|
||||
|
||||
return static::$oPhpExpressionEvaluator;
|
||||
return self::$oPhpExpressionEvaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return module names potentially required by current dependency
|
||||
*
|
||||
* @return array
|
||||
* @return array<string>
|
||||
*/
|
||||
public function GetRemainingModuleNamesToResolve(): array
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user