diff --git a/application/menunode.class.inc.php b/application/menunode.class.inc.php
index eef87d461..9a18deac6 100644
--- a/application/menunode.class.inc.php
+++ b/application/menunode.class.inc.php
@@ -1423,12 +1423,21 @@ class ShortcutMenuNode extends MenuNode
public function GetHyperlink($aExtraParams)
{
$sContext = $this->oShortcut->Get('context');
- $aContext = unserialize($sContext);
- if (isset($aContext['menu'])) {
- unset($aContext['menu']);
- }
- foreach ($aContext as $sArgName => $sArgValue) {
- $aExtraParams[$sArgName] = $sArgValue;
+ try {
+ $aContext = utils::Unserialize($sContext);
+ if (isset($aContext['menu'])) {
+ unset($aContext['menu']);
+ }
+ foreach ($aContext as $sArgName => $sArgValue) {
+ $aExtraParams[$sArgName] = $sArgValue;
+ }
+ } catch (Exception $e) {
+ IssueLog::Warning("User shortcut corrupted, delete the shortcut", LogChannels::CONSOLE, [
+ 'shortcut_name' => $this->oShortcut->GetName(),
+ 'root_cause' => $e->getMessage(),
+ ]);
+ // delete the shortcut
+ $this->oShortcut->DBDelete();
}
return parent::GetHyperlink($aExtraParams);
}
diff --git a/application/utils.inc.php b/application/utils.inc.php
index d824fb01c..d3c2c434d 100644
--- a/application/utils.inc.php
+++ b/application/utils.inc.php
@@ -3146,4 +3146,50 @@ TXT
return $aTrace;
}
+
+ /**
+ * PHP unserialize encapsulation, allow throwing exception when not allowed object class is detected (for security hardening)
+ *
+ * @param string $data data to unserialize
+ * @param array $aOptions PHP @unserialise options
+ * @param bool $bThrowNotAllowedObjectClassException flag to throw exception
+ *
+ * @return mixed PHP @unserialise return
+ * @throws Exception
+ */
+ public static function Unserialize(string $data, array $aOptions = ['allowed_classes' => false], bool $bThrowNotAllowedObjectClassException = true): mixed
+ {
+ $data = unserialize($data, $aOptions);
+
+ if ($bThrowNotAllowedObjectClassException) {
+ try {
+ self::AssertNoIncompleteClassDetected($data);
+ } catch (Exception $e) {
+ throw new CoreException('Unserialization failed because an incomplete class was detected.', [], '', $e);
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Assert that data provided doesn't contain any incomplete class.
+ *
+ * @throws Exception
+ */
+ public static function AssertNoIncompleteClassDetected(mixed $data): void
+ {
+ if (is_object($data)) {
+ if ($data instanceof __PHP_Incomplete_Class) {
+ throw new Exception('__PHP_Incomplete_Class_Name object detected');
+ }
+ foreach (get_object_vars($data) as $property) {
+ self::AssertNoIncompleteClassDetected($property);
+ }
+ } elseif (is_array($data)) {
+ foreach ($data as $value) {
+ self::AssertNoIncompleteClassDetected($value);
+ }
+ }
+ }
}
diff --git a/core/cmdbsource.class.inc.php b/core/cmdbsource.class.inc.php
index 8b17a931d..25ccbd7e1 100644
--- a/core/cmdbsource.class.inc.php
+++ b/core/cmdbsource.class.inc.php
@@ -1579,6 +1579,8 @@ class CMDBSource
if (static::GetDBVendor() === static::ENUM_DB_VENDOR_MYSQL) {
//Mysql 5.7.0 and upper deprecated --ssl and uses --ssl-mode instead
return version_compare(static::GetDBVersion(), '5.7.11', '>=');
+ } elseif (static::GetDBVendor() === static::ENUM_DB_VENDOR_MARIADB) {
+ return version_compare(static::GetDBVersion(), '10.2.6', '>=');
}
return false;
}
diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php
index f86a15a49..cc980e039 100644
--- a/core/userrights.class.inc.php
+++ b/core/userrights.class.inc.php
@@ -1182,7 +1182,7 @@ class UserRights
return self::$m_oUser->GetKey();
} else {
// find the id out of the login string
- $oUser = self::FindUser($sLogin);
+ $oUser = self::FindUser($sLogin, bAllowDisabledUsers: true);
if (is_null($oUser)) {
return null;
}
@@ -1375,7 +1375,7 @@ class UserRights
if (empty($sLogin)) {
$oUser = self::$m_oUser;
} else {
- $oUser = self::FindUser($sLogin);
+ $oUser = self::FindUser($sLogin, bAllowDisabledUsers: true);
}
if (is_null($oUser)) {
return '';
diff --git a/css/backoffice/_shame.scss b/css/backoffice/_shame.scss
index 8b6664258..1f6529f29 100644
--- a/css/backoffice/_shame.scss
+++ b/css/backoffice/_shame.scss
@@ -56,6 +56,8 @@ $ibo-shame--slider--is-round--border-radius: 20px !default;
$ibo-shame--slider--is-round--before--border-radius: 7px !default;
+$ibo-blockquote--color: $ibo-body-text-color !default;
+
// N°2847 - Recolor svg illustrations with iTop's primary color
.ibo-svg-illustration--container > svg *[fill="#6c63ff"]{
fill: $ibo-svg-illustration--fill;
@@ -126,3 +128,11 @@ input:checked + .slider:before {
.slider.round:before {
border-radius: $ibo-shame--slider--is-round--before--border-radius;
}
+
+/*
+ Bulma sets blockquote background color through a variable, it affects ckeditor and html display.
+ This rule is needed harmonize the blockquote text color in both contexts.
+ */
+.ibo-is-html-content blockquote {
+ color: $ibo-blockquote--color;
+}
\ No newline at end of file
diff --git a/css/backoffice/components/input/_input-select.scss b/css/backoffice/components/input/_input-select.scss
index 7bece46e1..6dd1ccb3b 100644
--- a/css/backoffice/components/input/_input-select.scss
+++ b/css/backoffice/components/input/_input-select.scss
@@ -203,8 +203,9 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
}
// N°7982 Default selectize stylesheet override
+// N°9468 Dropdown content needs to be a few pixel shorter than the dropdown itself to avoid double scrollbar
.selectize-dropdown-content{
- max-height: $ibo-input-select-selectize--dropdown--max-height;
+ max-height: calc(#{$ibo-input-select-selectize--dropdown--max-height} - 4px);
}
.selectize-dropdown.ui-menu .ui-state-active {
diff --git a/css/backoffice/vendors/_bulma-variables-overload.scss b/css/backoffice/vendors/_bulma-variables-overload.scss
index 597414d7d..990ca59bb 100644
--- a/css/backoffice/vendors/_bulma-variables-overload.scss
+++ b/css/backoffice/vendors/_bulma-variables-overload.scss
@@ -21,6 +21,7 @@ $text-strong: inherit !default;
* See https://bulma.io/documentation/elements/content/
*/
$content-block-margin-bottom: 0 !default;
+$content-blockquote-background-color: $ibo-color-grey-200 !default;
/* Table: Reset style as much as possible to match rich text editor preview, which is the browser's default stylesheet.
* As there is no way to avoid bulma rules, we simply make them invalid by setting an invalid variable value, the rules will then be ignored by the browser.
diff --git a/datamodels/2.x/combodo-backoffice-darkmoon-theme/scss/scss-variables.scss b/datamodels/2.x/combodo-backoffice-darkmoon-theme/scss/scss-variables.scss
index 02967672f..cce7c8bdd 100644
--- a/datamodels/2.x/combodo-backoffice-darkmoon-theme/scss/scss-variables.scss
+++ b/datamodels/2.x/combodo-backoffice-darkmoon-theme/scss/scss-variables.scss
@@ -76,6 +76,7 @@ $text-strong: inherit !default;
$code: $ibo-color-primary-400 !default;
$code-background: $ibo-color-grey-700 !default;
$pre-background: $ibo-color-grey-600 !default;
+$content-blockquote-background-color: $ibo-color-grey-600 !default;
$ibo-scrollbar--scrollbar-track-background-color: $ibo-color-grey-700 !default;
$ibo-scrollbar--scrollbar-thumb-background-color: $ibo-color-grey-900 !default;
@@ -198,6 +199,7 @@ $ibo-input-select--action-button--color: $ibo-input-select-wrapper--after--color
$ibo-input-select-selectize--item--active--text-color: $ibo-color-grey-100 !default;
$ibo-input-select-selectize--item--active--background-color: $ibo-color-grey-500 !default;
$ibo-input-select--autocomplete-item-image--background-color: $ibo-color-grey-800 !default;
+$ibo-input-date--button--color: $ibo-input-select--action-button--color;
$ibo-vendors-selectize-input--color: $ibo-body-text-color !default;
$ibo-vendors-selectize-input--background-color: $ibo-input--background-color !default;
$ibo-vendors-selectize--input--border-color: $ibo-input--border-color !default;
@@ -245,6 +247,11 @@ $ibo-vendors-datatables--row-highlight--colors:('red': ($ibo-color-red-700),'dan
$ibo-vendors-jqueryui--ui-dialog--background-color: $ibo-color-grey-800 !default;
$ibo-vendors-jqueryui--ui-dialog-titlebar--border-bottom: solid 1px $ibo-color-grey-500 !default;
+$ibo-vendors-jqueryui--ui-datepicker--background-color: $ibo-color-grey-700 !default;
+$ibo-vendors-jqueryui--ui-datepicker-days--color: $ibo-color-primary-200 !default;
+$ibo-vendors-jqueryui--ui-datepicker-days--highlight--background-color: $ibo-color-primary-800 !default;
+$ibo-vendors-jqueryui--ui-datepicker-days--hover--background-color: $ibo-color-primary-500 !default;
+$ibo-vendors-jqueryui--ui-datepicker-days--active--background-color: $ibo-color-primary-700 !default;
diff --git a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml
index b3f381390..55268e086 100755
--- a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml
+++ b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml
@@ -109,6 +109,16 @@
0
0
+
+ lnkGroupToCI
+ ci_id
+ group_id
+ 0
+ 0
+ false
+ SELECT Group WHERE status != 'obsolete'
+ property
+
@@ -386,6 +396,10 @@
model_id
name
+
+ model_id
+ end_of_support
+
asset_number
@@ -907,6 +921,9 @@
-
220
+ -
+ 230
+
@@ -1056,6 +1073,10 @@
iosversion_id
name
+
+ iosversion_id
+ end_of_support
+
ram
@@ -1068,7 +1089,7 @@
-
10
-
-
+
-
10
-
@@ -1131,7 +1152,7 @@
-
20
-
-
+
-
10
-
@@ -1143,6 +1164,12 @@
-
30
+ -
+ 40
+
+ -
+ 50
+
-
@@ -1159,12 +1186,15 @@
- -
+
-
30
-
10
+ -
+ 20
+
@@ -1385,6 +1415,10 @@
osversion_id
name
+
+ osversion_id
+ end_of_support
+
osversion_id]]>
@@ -1451,7 +1485,7 @@
-
120
-
-
+
-
10
-
@@ -1520,7 +1554,7 @@
-
130
-
-
+
-
10
-
@@ -1532,6 +1566,12 @@
-
30
+ -
+ 40
+
+ -
+ 50
+
-
@@ -1548,12 +1588,15 @@
- -
+
-
30
-
10
+ -
+ 20
+
@@ -1794,9 +1837,12 @@
-
10
- -
+
-
20
+ -
+ 30
+
20
@@ -1987,9 +2033,12 @@
-
10
- -
+
-
20
+ -
+ 30
+
20
@@ -2114,6 +2163,10 @@
software_id
name
+
+ software_id
+ end_of_support
+
software_id]]>
@@ -2377,6 +2430,9 @@
-
10
+ -
+ 20
+
10
@@ -2385,6 +2441,9 @@
-
10
+ -
+ 20
+
20
@@ -2561,6 +2620,9 @@
-
10
+ -
+ 20
+
10
@@ -2569,6 +2631,9 @@
-
10
+ -
+ 20
+
20
@@ -2745,6 +2810,9 @@
-
10
+ -
+ 20
+
10
@@ -2753,6 +2821,9 @@
-
10
+ -
+ 20
+
20
@@ -2921,6 +2992,9 @@
-
10
+ -
+ 20
+
10
@@ -2929,6 +3003,9 @@
-
10
+ -
+ 20
+
20
@@ -3084,6 +3161,9 @@
-
10
+ -
+ 20
+
10
@@ -3092,6 +3172,9 @@
-
10
+ -
+ 20
+
20
@@ -3266,9 +3349,12 @@
-
10
- -
+
-
20
+ -
+ 30
+
20
@@ -3436,6 +3522,9 @@
-
10
+ -
+ 20
+
20
@@ -3622,9 +3711,12 @@
-
10
- -
+
-
20
+ -
+ 30
+
20
@@ -3800,6 +3892,11 @@
128
true
+
+ end_of_support
+
+ true
+
SoftwareInstance
software_id
@@ -3855,13 +3952,21 @@
-
+
-
+
+
-
+ 10
+
+
+ 10
+
-
-
20
- 10
+ 20
20
@@ -3891,6 +3996,9 @@
-
30
+ -
+ 40
+
@@ -3917,6 +4025,9 @@
-
20
+ -
+ 30
+
@@ -5028,6 +5139,11 @@
osfamily_id
name
+
+ end_of_support
+
+ true
+
OSPatch
osversion_id
@@ -5044,9 +5160,12 @@
-
20
- -
+
-
30
+ -
+ 40
+
@@ -5056,7 +5175,7 @@
-
+
-
10
@@ -5064,6 +5183,19 @@
-
20
+ -
+ 30
+
+
+
+
+
+ -
+ 20
+
+ -
+ 30
+
@@ -5142,9 +5274,6 @@
- -
- 10
-
-
20
@@ -5320,6 +5449,11 @@
512
true
+
+ end_of_support
+
+ true
+
label
@@ -5402,6 +5536,9 @@
-
20
+ -
+ 25
+
-
30
@@ -5423,17 +5560,33 @@
-
+
-
10
+ -
+ 20
+
+ -
+ 30
+
+ -
+ 40
+
+
+
+
+
-
20
-
30
+ -
+ 40
+
@@ -5465,6 +5618,9 @@
+
+ logo
+
@@ -5568,6 +5724,11 @@
brand_id
name
+
+ end_of_support
+
+ true
+
NetworkDevice
iosversion_id
@@ -5584,9 +5745,12 @@
-
20
- -
+
-
30
+ -
+ 40
+
@@ -5596,7 +5760,7 @@
-
+
-
10
@@ -5604,6 +5768,19 @@
-
20
+ -
+ 30
+
+
+
+
+
+ -
+ 20
+
+ -
+ 30
+
diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php
index d77c8a9f4..1d27ac577 100644
--- a/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php
+++ b/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php
@@ -103,6 +103,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:FunctionalCI/Attribute:business_criticity/Value:medium+' => 'medium',
'Class:FunctionalCI/Attribute:move2production' => 'Move to production date',
'Class:FunctionalCI/Attribute:move2production+' => '',
+ 'Class:FunctionalCI/Attribute:groups_list' => 'Groups',
+ 'Class:FunctionalCI/Attribute:groups_list+' => 'Groups can be used as tags, to document environment, projects (migration, upgrade, security), etc…',
'Class:FunctionalCI/Attribute:contacts_list' => 'Contacts',
'Class:FunctionalCI/Attribute:contacts_list+' => 'All the contacts for this configuration item',
'Class:FunctionalCI/Attribute:documents_list' => 'Documents',
@@ -147,6 +149,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:PhysicalDevice/Attribute:brand_name+' => '',
'Class:PhysicalDevice/Attribute:model_id' => 'Model',
'Class:PhysicalDevice/Attribute:model_id+' => '',
+ 'Class:PhysicalDevice/Attribute:model_end_of_support' => 'Model end of support',
+ 'Class:PhysicalDevice/Attribute:model_end_of_support+' => 'When the hardware model is no more supported by the manufacturer, if this information is documented on the Model.',
'Class:PhysicalDevice/Attribute:model_name' => 'Model name',
'Class:PhysicalDevice/Attribute:model_name+' => '',
'Class:PhysicalDevice/Attribute:asset_number' => 'Asset number',
@@ -295,6 +299,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:NetworkDevice/Attribute:iosversion_id+' => '',
'Class:NetworkDevice/Attribute:iosversion_name' => 'IOS version name',
'Class:NetworkDevice/Attribute:iosversion_name+' => '',
+ 'Class:NetworkDevice/Attribute:ios_end_of_support' => 'IOS end of support',
+ 'Class:NetworkDevice/Attribute:ios_end_of_support+' => 'The date after which the editor no longer provides fixes for this IOS version.',
'Class:NetworkDevice/Attribute:ram' => 'RAM',
'Class:NetworkDevice/Attribute:ram+' => '',
]);
@@ -315,6 +321,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:Server/Attribute:osversion_id+' => '',
'Class:Server/Attribute:osversion_name' => 'OS version name',
'Class:Server/Attribute:osversion_name+' => '',
+ 'Class:Server/Attribute:os_end_of_support' => 'OS end of support',
+ 'Class:Server/Attribute:os_end_of_support+' => 'The date after which the editor ceases to provide patches for this OS version.',
'Class:Server/Attribute:oslicence_id' => 'OS license',
'Class:Server/Attribute:oslicence_id+' => '',
'Class:Server/Attribute:oslicence_name' => 'OS license name',
@@ -391,6 +399,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:PC/Attribute:osversion_id+' => '',
'Class:PC/Attribute:osversion_name' => 'OS version name',
'Class:PC/Attribute:osversion_name+' => '',
+ 'Class:PC/Attribute:os_end_of_support' => 'OS end of support',
+ 'Class:PC/Attribute:os_end_of_support+' => 'The date after which the editor ceases to provide patches for this OS version.',
'Class:PC/Attribute:cpu' => 'CPU',
'Class:PC/Attribute:cpu+' => '',
'Class:PC/Attribute:ram' => 'RAM',
@@ -540,6 +550,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:Software/Attribute:vendor+' => '',
'Class:Software/Attribute:version' => 'Version',
'Class:Software/Attribute:version+' => '',
+ 'Class:Software/Attribute:end_of_support' => 'End of support',
+ 'Class:Software/Attribute:end_of_support+' => 'The date after which the editor ceases to provide patches for this software version.',
'Class:Software/Attribute:documents_list' => 'Documents',
'Class:Software/Attribute:documents_list+' => 'All the documents linked to this software',
'Class:Software/Attribute:logo' => 'Logo',
@@ -579,6 +591,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:SoftwareInstance/Attribute:software_id+' => '',
'Class:SoftwareInstance/Attribute:software_name' => 'Software name',
'Class:SoftwareInstance/Attribute:software_name+' => '',
+ 'Class:SoftwareInstance/Attribute:software_end_of_support' => 'Software end of support',
+ 'Class:SoftwareInstance/Attribute:software_end_of_support+' => 'The date after which the editor ceases to provide patches for this software version.',
'Class:SoftwareInstance/Attribute:softwarelicence_id' => 'Software license',
'Class:SoftwareInstance/Attribute:softwarelicence_id+' => '',
'Class:SoftwareInstance/Attribute:softwarelicence_name' => 'Software license name',
@@ -776,6 +790,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:VirtualMachine/Attribute:osversion_id+' => '',
'Class:VirtualMachine/Attribute:osversion_name' => 'OS version name',
'Class:VirtualMachine/Attribute:osversion_name+' => '',
+ 'Class:VirtualMachine/Attribute:os_end_of_support' => 'OS end of support',
+ 'Class:VirtualMachine/Attribute:os_end_of_support+' => 'When the OS version is no more supported by the vendor, if this information is documented on the OS Version.',
'Class:VirtualMachine/Attribute:oslicence_id' => 'OS license',
'Class:VirtualMachine/Attribute:oslicence_id+' => '',
'Class:VirtualMachine/Attribute:oslicence_name' => 'OS license name',
@@ -1064,6 +1080,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:OSVersion/Attribute:osfamily_id+' => '',
'Class:OSVersion/Attribute:osfamily_name' => 'OS family name',
'Class:OSVersion/Attribute:osfamily_name+' => '',
+ 'Class:OSVersion/Attribute:end_of_support' => 'End of support',
+ 'Class:OSVersion/Attribute:end_of_support+' => 'The date after which the editor ceases to provide patches for this OS version.',
'Class:OSVersion/Attribute:ospatches_list' => 'OS patches',
'Class:OSVersion/Attribute:ospatches_list+' => 'All the OS patches for this OS version',
'Class:OSVersion/UniquenessRule:name_osfamily+' => 'Name must be unique in the OS family',
@@ -1118,6 +1136,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:Model/Attribute:picture+' => '',
'Class:Model/Attribute:type' => 'Device type',
'Class:Model/Attribute:type+' => '',
+ 'Class:Model/Attribute:end_of_support' => 'End of support',
+ 'Class:Model/Attribute:end_of_support+' => 'The date after which the manufacturer ceases to provide patches and support for this model.',
'Class:Model/Attribute:type/Value:PowerSource' => 'Power Source',
'Class:Model/Attribute:type/Value:PowerSource+' => 'Power Source',
'Class:Model/Attribute:type/Value:DiskArray' => 'Disk Array',
@@ -1184,6 +1204,8 @@ Dict::Add('EN US', 'English', 'English', [
'Class:IOSVersion/Attribute:brand_id+' => '',
'Class:IOSVersion/Attribute:brand_name' => 'Brand name',
'Class:IOSVersion/Attribute:brand_name+' => '',
+ 'Class:IOSVersion/Attribute:end_of_support' => 'End of support',
+ 'Class:IOSVersion/Attribute:end_of_support+' => 'The date after which the editor ceases to provide patches for this IOS version.',
'Class:IOSVersion/Attribute:networkdevices_list' => 'Network devices',
'Class:IOSVersion/Attribute:networkdevices_list+' => 'All the network devices running this IOS version',
'Class:IOSVersion/UniquenessRule:name_brand+' => 'Name must be unique in the brand',
diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php
index 63ac04e40..91b0e184a 100644
--- a/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php
+++ b/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php
@@ -87,6 +87,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:FunctionalCI/Attribute:business_criticity/Value:medium+' => 'moyenne',
'Class:FunctionalCI/Attribute:move2production' => 'Date de mise en production',
'Class:FunctionalCI/Attribute:move2production+' => '',
+ 'Class:FunctionalCI/Attribute:groups_list' => 'Groupes',
+ 'Class:FunctionalCI/Attribute:groups_list+' => 'Les groupes sont des sortes d\'étiquettes qui permettent d\'identifier des environnements de travail, l\'appartenance à des projets ou les équipements qui doivent être mise à jour, déplacés, remplacés, etc…',
'Class:FunctionalCI/Attribute:contacts_list' => 'Contacts',
'Class:FunctionalCI/Attribute:contacts_list+' => 'Tous les contacts de cet élément de configuration',
'Class:FunctionalCI/Attribute:documents_list' => 'Documents',
@@ -143,6 +145,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:PhysicalDevice/Attribute:model_id+' => '',
'Class:PhysicalDevice/Attribute:model_name' => 'Nom Modèle',
'Class:PhysicalDevice/Attribute:model_name+' => '',
+ 'Class:PhysicalDevice/Attribute:model_end_of_support' => 'Fin de support du modèle',
+ 'Class:PhysicalDevice/Attribute:model_end_of_support+' => 'Date au delà de laquelle le fabricant ne fournit plus ni correctif, ni pièces de rechange pour ce modèle.',
'Class:PhysicalDevice/Attribute:asset_number' => 'Numéro Asset',
'Class:PhysicalDevice/Attribute:asset_number+' => '',
'Class:PhysicalDevice/Attribute:purchase_date' => 'Date d\'achat',
@@ -312,6 +316,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:NetworkDevice/Attribute:iosversion_id+' => '',
'Class:NetworkDevice/Attribute:iosversion_name' => 'Nom Version IOS',
'Class:NetworkDevice/Attribute:iosversion_name+' => '',
+ 'Class:NetworkDevice/Attribute:ios_end_of_support' => 'Fin de support de l\'IOS',
+ 'Class:NetworkDevice/Attribute:ios_end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version d\'IOS.',
'Class:NetworkDevice/Attribute:ram' => 'RAM',
'Class:NetworkDevice/Attribute:ram+' => '',
]);
@@ -332,6 +338,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:Server/Attribute:osversion_id+' => '',
'Class:Server/Attribute:osversion_name' => 'Nom Version OS',
'Class:Server/Attribute:osversion_name+' => '',
+ 'Class:Server/Attribute:os_end_of_support' => 'Fin de support de l\'OS',
+ 'Class:Server/Attribute:os_end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version d\'OS.',
'Class:Server/Attribute:oslicence_id' => 'Licence OS',
'Class:Server/Attribute:oslicence_id+' => '',
'Class:Server/Attribute:oslicence_name' => 'Nom Licence OS',
@@ -426,6 +434,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:PC/Attribute:osversion_id+' => '',
'Class:PC/Attribute:osversion_name' => 'Nom Version OS',
'Class:PC/Attribute:osversion_name+' => '',
+ 'Class:PC/Attribute:os_end_of_support' => 'Fin de support de l\'OS',
+ 'Class:PC/Attribute:os_end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version d\'OS.',
'Class:PC/Attribute:cpu' => 'CPU',
'Class:PC/Attribute:cpu+' => '',
'Class:PC/Attribute:ram' => 'RAM',
@@ -592,6 +602,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:SoftwareInstance/Attribute:software_id+' => '',
'Class:SoftwareInstance/Attribute:software_name' => 'Nom du logiciel',
'Class:SoftwareInstance/Attribute:software_name+' => '',
+ 'Class:SoftwareInstance/Attribute:software_end_of_support' => 'Fin de support du logiciel',
+ 'Class:SoftwareInstance/Attribute:software_end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version du logiciel.',
'Class:SoftwareInstance/Attribute:softwarelicence_id' => 'Licence logiciel',
'Class:SoftwareInstance/Attribute:softwarelicence_id+' => '',
'Class:SoftwareInstance/Attribute:softwarelicence_name' => 'Nom Licence logiciel',
@@ -819,6 +831,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:VirtualMachine/Attribute:osversion_id+' => '',
'Class:VirtualMachine/Attribute:osversion_name' => 'Nom Version OS',
'Class:VirtualMachine/Attribute:osversion_name+' => '',
+ 'Class:VirtualMachine/Attribute:os_end_of_support' => 'Fin de support de l\'OS',
+ 'Class:VirtualMachine/Attribute:os_end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version d\'OS.',
'Class:VirtualMachine/Attribute:oslicence_id' => 'Licence OS',
'Class:VirtualMachine/Attribute:oslicence_id+' => '',
'Class:VirtualMachine/Attribute:oslicence_name' => 'Nom Licence OS',
@@ -982,6 +996,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:Software/Attribute:vendor+' => '',
'Class:Software/Attribute:version' => 'Version',
'Class:Software/Attribute:version+' => '',
+ 'Class:Software/Attribute:end_of_support' => 'Fin de support',
+ 'Class:Software/Attribute:end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version du logiciel.',
'Class:Software/Attribute:documents_list' => 'Documents',
'Class:Software/Attribute:documents_list+' => 'Tous les documents liés à ce logiciel',
'Class:Software/Attribute:logo' => 'Logo',
@@ -1092,6 +1108,7 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:Licence/Attribute:organization_name+' => 'Common name',
'Class:Licence/Attribute:usage_limit' => 'Limite d\'utilisation',
'Class:Licence/Attribute:usage_limit+' => '',
+ // Incoherent FR specific entries below in this table, wrong class. To be either moved or modified
'Class:Location/Attribute:physicaldevice_list/UI:Links:Create:Button+' => 'Créer un %4$s',
'Class:Location/Attribute:physicaldevice_list/UI:Links:Create:Modal:Title' => 'Ajouter un %4$s à %2$s',
'Class:Location/Attribute:physicaldevice_list/UI:Links:Delete:Button+' => 'Supprimer ce %4$s',
@@ -1197,6 +1214,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:OSVersion/Attribute:osfamily_id+' => '',
'Class:OSVersion/Attribute:osfamily_name' => 'Nom Famille OS',
'Class:OSVersion/Attribute:osfamily_name+' => '',
+ 'Class:OSVersion/Attribute:end_of_support' => 'Fin de support',
+ 'Class:OSVersion/Attribute:end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version.',
'Class:OSVersion/UniquenessRule:name_osfamily+' => 'Le nom doit être unique au sein de cette famille d\'OS',
'Class:OSVersion/UniquenessRule:name_osfamily' => 'cette version d\'OS existe déjà dans cette famille',
'Class:OSVersion/Attribute:ospatches_list' => 'Patchs OS',
@@ -1257,6 +1276,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:Model/Attribute:picture+' => '',
'Class:Model/Attribute:type' => 'Type de matériel',
'Class:Model/Attribute:type+' => '',
+ 'Class:Model/Attribute:end_of_support' => 'Fin de support',
+ 'Class:Model/Attribute:end_of_support+' => 'Date au delà de laquelle le constructeur ne fournit plus ni correctif ni support.',
'Class:Model/Attribute:type/Value:PowerSource' => 'Arrivée électrique',
'Class:Model/Attribute:type/Value:PowerSource+' => 'Arrivée électrique',
'Class:Model/Attribute:type/Value:DiskArray' => 'Baie de disques',
@@ -1335,6 +1356,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:IOSVersion/Attribute:brand_id+' => '',
'Class:IOSVersion/Attribute:brand_name' => 'Nom Marque',
'Class:IOSVersion/Attribute:brand_name+' => '',
+ 'Class:IOSVersion/Attribute:end_of_support' => 'Fin de support',
+ 'Class:IOSVersion/Attribute:end_of_support+' => 'Date au delà de laquelle l\'éditeur ne fournit plus de correctif pour cette version.',
'Class:IOSVersion/UniquenessRule:name_brand+' => 'Le nom doit être unique pour cette marque',
'Class:IOSVersion/UniquenessRule:name_brand' => 'cette version d\'IOS existe déja sur cette marque',
'Class:IOSVersion/Attribute:networkdevices_list' => 'Equipements réseaux',
diff --git a/datamodels/2.x/itop-container-mgmt/datamodel.itop-container-mgmt.xml b/datamodels/2.x/itop-container-mgmt/datamodel.itop-container-mgmt.xml
index d654e81ec..3347fc496 100644
--- a/datamodels/2.x/itop-container-mgmt/datamodel.itop-container-mgmt.xml
+++ b/datamodels/2.x/itop-container-mgmt/datamodel.itop-container-mgmt.xml
@@ -438,9 +438,12 @@
-
10
- -
+
-
20
+ -
+ 30
+
20
@@ -993,6 +996,9 @@
-
10
+ -
+ 20
+
20
@@ -1196,6 +1202,9 @@
-
10
+ -
+ 20
+
20
@@ -1254,6 +1263,16 @@
+
+
+
+
+
+
+ false
+ true
+
+
@@ -1298,6 +1317,16 @@
+
+
+
+
+
+
+ false
+ true
+
+
diff --git a/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml b/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml
index be9652e86..b35689d46 100755
--- a/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml
+++ b/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml
@@ -109,13 +109,16 @@
10
-
- 110
+ 10
-
- 120
+ 20
-
- 130
+ 30
+
+ -
+ 40
@@ -123,7 +126,10 @@
20
-
- 140
+ 10
+
+ -
+ 20
@@ -350,6 +356,9 @@
-
30
+ -
+ 40
+
-
@@ -358,6 +367,9 @@
-
10
+ -
+ 20
+
@@ -565,6 +577,9 @@
-
10
+ -
+ 20
+
@@ -760,6 +775,9 @@
-
30
+ -
+ 40
+
-
@@ -768,6 +786,9 @@
-
10
+ -
+ 20
+
@@ -989,6 +1010,9 @@
-
30
+ -
+ 40
+
-
@@ -997,6 +1021,9 @@
-
10
+ -
+ 20
+
diff --git a/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml b/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml
index 5fa8387ba..1502d05d7 100755
--- a/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml
+++ b/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml
@@ -90,6 +90,9 @@
-
160
+ -
+ 170
+
@@ -253,6 +256,9 @@
-
30
+ -
+ 40
+
-
@@ -261,6 +267,9 @@
-
10
+ -
+ 20
+
@@ -470,6 +479,9 @@
-
30
+ -
+ 40
+
-
@@ -478,6 +490,9 @@
-
10
+ -
+ 20
+
@@ -673,6 +688,9 @@
-
30
+ -
+ 40
+
-
@@ -681,6 +699,9 @@
-
10
+ -
+ 20
+
@@ -869,6 +890,9 @@
-
30
+ -
+ 40
+
-
@@ -877,6 +901,9 @@
-
10
+ -
+ 20
+
@@ -1029,6 +1056,10 @@
osversion_id
name
+
+ osversion_id
+ end_of_support
+
cpu
@@ -1130,6 +1161,12 @@
-
30
+ -
+ 40
+
+ -
+ 50
+
-
@@ -1138,6 +1175,9 @@
-
10
+ -
+ 20
+
@@ -1336,6 +1376,9 @@
-
30
+ -
+ 40
+
-
@@ -1344,6 +1387,9 @@
-
10
+ -
+ 20
+
@@ -1536,6 +1582,9 @@
-
30
+ -
+ 40
+
-
@@ -1544,6 +1593,9 @@
-
10
+ -
+ 20
+
diff --git a/datamodels/2.x/itop-request-mgmt/datamodel.itop-request-mgmt.xml b/datamodels/2.x/itop-request-mgmt/datamodel.itop-request-mgmt.xml
index eb576942a..db1edcb30 100755
--- a/datamodels/2.x/itop-request-mgmt/datamodel.itop-request-mgmt.xml
+++ b/datamodels/2.x/itop-request-mgmt/datamodel.itop-request-mgmt.xml
@@ -151,9 +151,21 @@
incident
+ 10
+
service_request
+ 20
+
request_type
diff --git a/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml b/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml
index 538b989bc..c4b8eb899 100644
--- a/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml
+++ b/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml
@@ -136,6 +136,9 @@
-
30
+ -
+ 40
+
-
@@ -158,6 +161,9 @@
-
10
+ -
+ 20
+
@@ -395,6 +401,9 @@
-
30
+ -
+ 40
+
-
@@ -417,6 +426,9 @@
-
10
+ -
+ 20
+
@@ -654,6 +666,9 @@
-
30
+ -
+ 40
+
-
@@ -676,6 +691,9 @@
-
10
+ -
+ 20
+
@@ -847,7 +865,7 @@
-
100
-
-
+
-
10
-
@@ -873,7 +891,7 @@
- -
+
-
20
-
@@ -901,7 +919,7 @@
-
110
-
-
+
-
10
-
@@ -913,6 +931,9 @@
-
30
+ -
+ 40
+
-
@@ -929,12 +950,15 @@
- -
+
-
30
-
10
+ -
+ 20
+
diff --git a/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml b/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml
index 2633bee89..92fddae5d 100644
--- a/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml
+++ b/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml
@@ -421,6 +421,9 @@
-
10
+ -
+ 20
+
20
@@ -598,6 +601,9 @@
-
10
+ -
+ 20
+
20
@@ -740,6 +746,10 @@
osversion_id
name
+
+ osversion_id
+ end_of_support
+
osversion_id]]>
@@ -802,7 +812,7 @@
-
90
-
-
+
-
10
-
@@ -856,14 +866,20 @@
-
10
+ -
+ 20
+
- -
+
-
20
-
10
+ -
+ 20
+
@@ -1253,9 +1269,12 @@
-
10
- -
+
-
20
+ -
+ 30
+
20
diff --git a/js/extkeywidget.js b/js/extkeywidget.js
index 0fa13781d..7c56a9177 100644
--- a/js/extkeywidget.js
+++ b/js/extkeywidget.js
@@ -120,6 +120,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
this.sFormAttCode = sFormAttCode;
var me = this;
+ const iDropdownContentHeightDifference = 4;
this.Init = function () {
// make sure that the form is clean
@@ -171,7 +172,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
// To avoid dropdown to be cut by the container's overflow hidden rule
dropdownParent: 'body',
onDropdownOpen: function (oDropdownElem) {
- me.UpdateDropdownPosition(this.$control, oDropdownElem);
+ me.UpdateDropdownPosition(this.$control, oDropdownElem, this.$dropdown_content);
},
});
let $selectize = $select[0].selectize; // This stores the selectize object to a variable (with name 'selectize')
@@ -314,13 +315,14 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
};
/**
- * Update the dropdown's position so it always fits in the screen
- *
- * @param {object} oControlElem jQuery object representing the "control" input (= where the user types) of the external key
- * @param {object} oDropdownElem jQuery object representing the results dropdown
- * @return {void}
- */
- this.UpdateDropdownPosition = function (oControlElem, oDropdownElem) {
+ * Update the dropdown's position so it always fits in the screen
+ *
+ * @param {object} oControlElem jQuery object representing the "control" input (= where the user types) of the external key
+ * @param {object} oDropdownElem jQuery object representing the results dropdown
+ * @param {object|undefined} oDropdownContentElem
+ * @return {void}
+ */
+ this.UpdateDropdownPosition = function (oControlElem, oDropdownElem, oDropdownContentElem) {
// First fix width to ensure it's not too long
const fControlWidth = oControlElem.outerWidth();
oDropdownElem.css('width', fControlWidth);
@@ -328,6 +330,13 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
// Then, fix height / position to ensure it's within the viewport
const fWindowHeight = window.innerHeight;
+ // Clear previously set rule so the comparison is done with dropdown real height
+ oDropdownElem.css('max-height', '');
+
+ if(oDropdownContentElem) {
+ oDropdownContentElem.css('max-height', '');
+ }
+
const fControlTopY = oControlElem.offset().top;
const fControlHeight = oControlElem.outerHeight();
@@ -338,14 +347,38 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
if (fDropdownBottomY > fWindowHeight) {
// Set dropdown max-height to 1/3 of the screen, this way we are sure the dropdown will fit in either the top / bottom half of the screen
- oDropdownElem.css('max-height', '30vh');
+ oDropdownElem.css({
+ maxHeight: '30vh',
+ });
fDropdownHeight = oDropdownElem.outerHeight();
- // Position dropdown above input if not enough space on the bottom part of the screen
+ // N°9468 Dropdown content needs to be a few pixel shorter than the dropdown itself to avoid double scrollbar
+ if(oDropdownContentElem) {
+ oDropdownContentElem.css('max-height', `calc(30vh - ${iDropdownContentHeightDifference}px)`);
+ }
+
+ /* Position dropdown above input if not enough space on the bottom part of the screen
+ Doesn't seem to work with selectize as an internal plugin "auto_position" refreshes the top position after
+ this method is called, input set use a custom plugin to avoid fix this issue "plugin_combodo_auto_position"
+ This would need to take the potential 4px difference (iDropdownContentHeightDifference) into account if this is fixed.
+ */
if ((fDropdownTopY / fWindowHeight) > 0.6) {
- oDropdownElem.css('top', fDropdownTopY - fDropdownHeight - fControlHeight);
- }
+ oDropdownElem.css({
+ top: fDropdownTopY - fDropdownHeight - fControlHeight,
+ borderTop: oDropdownElem.css('border-bottom')
+ });
+ }
+ else {
+ oDropdownElem.css({
+ borderTop: 'none'
+ })
+ }
}
+ else {
+ oDropdownElem.css({
+ borderTop: 'none'
+ })
+ }
};
this.ManageScroll = function () {
if ($('#label_'+me.id).scrollParent()[0].tagName != 'HTML') {
diff --git a/js/selectize/plugin_combodo_auto_position.js b/js/selectize/plugin_combodo_auto_position.js
index 7ec695c14..74d073046 100644
--- a/js/selectize/plugin_combodo_auto_position.js
+++ b/js/selectize/plugin_combodo_auto_position.js
@@ -19,10 +19,11 @@ Selectize.define("combodo_auto_position", function (aOptions) {
// Selectize instance
let oSelf = this;
+ const iDropdownContentHeightDifference = 4;
// Plugin options
aOptions = $.extend({
- maxDropDownHeight: 200,
+ maxDropDownHeight: '200px',
},
aOptions
);
@@ -33,28 +34,47 @@ Selectize.define("combodo_auto_position", function (aOptions) {
// Override position dropdown function
oSelf.positionDropdown = (function () {
return function () {
- let iRefHeight = oSelf.$dropdown.outerHeight() < aOptions.maxDropDownHeight ?
- oSelf.$dropdown.outerHeight() : aOptions.maxDropDownHeight;
+ // Clear previously set rules so the comparison is done with dropdown real height
+ oSelf.$dropdown.css({
+ 'max-height': '',
+ });
- if(oSelf.$control.offset().top + oSelf.$control.outerHeight() + iRefHeight > window.innerHeight){
+ oSelf.$dropdown_content.css({
+ 'max-height': '',
+ });
- oSelf.$dropdown.css({
- top: oSelf.$control.offset().top - iRefHeight,
- left: oSelf.$control.offset().left,
+ let iDropdownHeight = oSelf.$dropdown.outerHeight();
+ if(oSelf.$control.offset().top + oSelf.$control.outerHeight() + iDropdownHeight > window.innerHeight){
+
+ // Apply max-height as we are overflowing, that'll allow us to calculate where we should place ourselves later
+ oSelf.$dropdown.css({
+ maxHeight: `${aOptions.maxDropDownHeight}`,
+ })
+
+ iDropdownHeight = oSelf.$dropdown.outerHeight();
+
+ oSelf.$dropdown.css({
+ top: oSelf.$control.offset().top - iDropdownHeight + iDropdownContentHeightDifference, // Content will be shorter, so our real height too
+ left: oSelf.$control.offset().left,
width: oSelf.$wrapper.outerWidth(),
- 'max-height': `${aOptions.maxDropDownHeight}px`,
- 'overflow-y': 'auto',
- 'border-top': '1px solid #d0d0d0',
+ overflowY: 'auto',
+ borderTop : oSelf.$dropdown.css('border-bottom')
});
+
+ // N°9468 Dropdown content needs to be a few pixel shorter than the dropdown itself to avoid double scrollbar
+ oSelf.$dropdown_content.css({
+ 'max-height': `calc(${aOptions.maxDropDownHeight} - ${iDropdownContentHeightDifference}px)`
+ });
+
}
else{
oSelf.$dropdown.css({
top: oSelf.$control.offset().top + oSelf.$control.outerHeight(),
left: oSelf.$control.offset().left,
width: oSelf.$wrapper.outerWidth(),
- 'max-height': `${aOptions.maxDropDownHeight}px`,
- 'overflow-y': 'auto'
- });
+ overflowY: 'auto',
+ borderTop: 'none'
+ });
}
};
}());
diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php
index 6a5d5a220..161f6e2dc 100644
--- a/lib/composer/autoload_classmap.php
+++ b/lib/composer/autoload_classmap.php
@@ -134,6 +134,7 @@ return array(
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => $baseDir . '/sources/Application/Helper/CKEditorHelper.php',
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => $baseDir . '/sources/Application/Helper/ExportHelper.php',
'Combodo\\iTop\\Application\\Helper\\FormHelper' => $baseDir . '/sources/Application/Helper/FormHelper.php',
+ 'Combodo\\iTop\\Application\\Helper\\ImportHelper' => $baseDir . '/sources/Application/Helper/ImportHelper.php',
'Combodo\\iTop\\Application\\Helper\\SearchHelper' => $baseDir . '/sources/Application/Helper/SearchHelper.php',
'Combodo\\iTop\\Application\\Helper\\Session' => $baseDir . '/sources/Application/Helper/Session.php',
'Combodo\\iTop\\Application\\Helper\\WebResourcesHelper' => $baseDir . '/sources/Application/Helper/WebResourcesHelper.php',
diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php
index 88185ee1a..df73dbc35 100644
--- a/lib/composer/autoload_static.php
+++ b/lib/composer/autoload_static.php
@@ -520,6 +520,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/CKEditorHelper.php',
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/ExportHelper.php',
'Combodo\\iTop\\Application\\Helper\\FormHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/FormHelper.php',
+ 'Combodo\\iTop\\Application\\Helper\\ImportHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/ImportHelper.php',
'Combodo\\iTop\\Application\\Helper\\SearchHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/SearchHelper.php',
'Combodo\\iTop\\Application\\Helper\\Session' => __DIR__ . '/../..' . '/sources/Application/Helper/Session.php',
'Combodo\\iTop\\Application\\Helper\\WebResourcesHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/WebResourcesHelper.php',
diff --git a/pages/ajax.csvimport.php b/pages/ajax.csvimport.php
index 5e1e19419..185ed5932 100644
--- a/pages/ajax.csvimport.php
+++ b/pages/ajax.csvimport.php
@@ -5,9 +5,11 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
+use Combodo\iTop\Application\Helper\ImportHelper;
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
+use Combodo\iTop\Application\UI\Base\Component\Input\Select\Select;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\TextArea;
@@ -387,6 +389,14 @@ EOF
}
break;
+ case 'display_classes_select':
+ $oPage = new AjaxPage("");
+ $sClassName = utils::ReadPostedParam('class_name', '', utils::ENUM_SANITIZATION_FILTER_CLASS);
+ $bAdvanced = utils::ReadPostedParam('advanced', 'false');
+ $oClassesSelect = ImportHelper::GetClassesSelectUIBlock('class_name', $sClassName, UR_ACTION_BULK_MODIFY, $bAdvanced === 'true');
+ $oPage->AddSubBlock($oClassesSelect);
+ break;
+
case 'get_csv_template':
$sClassName = utils::ReadParam('class_name');
$sFormat = utils::ReadParam('format', 'csv');
diff --git a/pages/csvimport.php b/pages/csvimport.php
index b033509b1..e68e8aa04 100644
--- a/pages/csvimport.php
+++ b/pages/csvimport.php
@@ -5,6 +5,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
+use Combodo\iTop\Application\Helper\ImportHelper;
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\CollapsibleSection\CollapsibleSectionUIBlockFactory;
@@ -14,7 +15,6 @@ use Combodo\iTop\Application\UI\Base\Component\Form\FormUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\FileSelect\FileSelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
-use Combodo\iTop\Application\UI\Base\Component\Input\Select\Select;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\TextArea;
@@ -30,7 +30,6 @@ use Combodo\iTop\Application\WebPage\AjaxPage;
use Combodo\iTop\Application\WebPage\ErrorPage;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
-use Combodo\iTop\Renderer\BlockRenderer;
use Combodo\iTop\Service\Import\CSVImportPageProcessor;
try {
@@ -52,46 +51,6 @@ try {
$oPage = new iTopWebPage(Dict::S('UI:Title:BulkImport'));
$oPage->SetBreadCrumbEntry('ui-tool-bulkimport', Dict::S('Menu:CSVImportMenu'), Dict::S('UI:Title:BulkImport+'), '', 'fas fa-file-import', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
- /**
- * Helper function to build a select from the list of valid classes for a given action
- *
- * @param string $sName The name of the select in the HTML form
- * @param $sDefaultValue
- * @param integer $iWidthPx The width (in pixels) of the drop-down list
- * @param integer $iActionCode The ActionCode (from UserRights) to check for authorization for the classes
- *
- * @return \Combodo\iTop\Application\UI\Base\Component\Input\Select\
- */
- function GetClassesSelectUIBlock(string $sName, $sDefaultValue, int $iActionCode, bool $bAdvanced = false): Select
- {
- $oSelectBlock = SelectUIBlockFactory::MakeForSelect($sName, 'select_'.$sName);
- $oOption = SelectOptionUIBlockFactory::MakeForSelectOption("", Dict::S('UI:CSVImport:ClassesSelectOne'), false);
- $oSelectBlock->AddSubBlock($oOption);
- $aValidClasses = [];
- $aClassCategories = ['bizmodel', 'addon/authentication'];
- if ($bAdvanced) {
- $aClassCategories[] = 'grant_by_profile';
- }
- if (UserRights::IsAdministrator()) {
- $aClassCategories[] = 'application';
- }
- foreach ($aClassCategories as $sClassCategory) {
- foreach (MetaModel::GetClasses($sClassCategory) as $sClassName) {
- if ((is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode)) &&
- (!MetaModel::IsAbstract($sClassName))) {
- $sDisplayName = ($bAdvanced) ? MetaModel::GetName($sClassName)." ($sClassName)" : MetaModel::GetName($sClassName);
- $aValidClasses[$sDisplayName] = SelectOptionUIBlockFactory::MakeForSelectOption($sClassName, $sDisplayName, ($sClassName == $sDefaultValue));
- }
- }
- }
- ksort($aValidClasses);
- foreach ($aValidClasses as $sValue => $oBlock) {
- $oSelectBlock->AddSubBlock($oBlock);
- }
-
- return $oSelectBlock;
- }
-
/**
* Helper to 'check' an input in an HTML form if the current value equals the value given
*
@@ -330,7 +289,7 @@ try {
$oClassesSelect->AddSubBlock($oDefaultSelect);
$aSynchroUpdate = utils::ReadParam('synchro_update', []);
} else {
- $oClassesSelect = GetClassesSelectUIBlock('class_name', $sClassName, UR_ACTION_BULK_MODIFY, (bool)$bAdvanced);
+ $oClassesSelect = ImportHelper::GetClassesSelectUIBlock('class_name', $sClassName, UR_ACTION_BULK_MODIFY, (bool)$bAdvanced);
}
$oPanel = TitleUIBlockFactory::MakeForPage(Dict::S('UI:Title:CSVImportStep3'));
$oPage->AddSubBlock($oPanel);
@@ -354,11 +313,9 @@ try {
$oAdvancedMode->GetInput()->SetIsChecked(($bAdvanced == 1));
$oAdvancedMode->SetBeforeInput(false);
$oAdvancedMode->GetInput()->AddCSSClass('ibo-input-checkbox');
+ $oAdvancedMode->SetDescription(utils::EscapeHtml(Dict::S('UI:CSVImport:AdvancedMode+')));
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oAdvancedMode));
- $oDivAdvancedHelp = UIContentBlockUIBlockFactory::MakeStandard("advanced_help")->AddCSSClass('ibo-is-hidden');
- $oForm->AddSubBlock($oDivAdvancedHelp);
-
$oDivMapping = UIContentBlockUIBlockFactory::MakeStandard("mapping")->AddCSSClass('mt-5');
$oMessage = AlertUIBlockFactory::MakeForInformation(Dict::S('UI:CSVImport:SelectAClassFirst'))->SetIsClosable(false)->SetIsCollapsible(false);
$oDivMapping->AddSubBlock($oMessage);
@@ -395,7 +352,7 @@ try {
$oPage->add_ready_script(
<<add_script(
- <<AddTab('tabsTemplate', Dict::S('UI:CSVImport:Tab:Templates'));
- $oFieldTemplate = FieldUIBlockFactory::MakeFromObject(Dict::S('UI:CSVImport:PickClassForTemplate'), GetClassesSelectUIBlock('template_class', '', UR_ACTION_BULK_MODIFY));
+ $oFieldTemplate = FieldUIBlockFactory::MakeFromObject(Dict::S('UI:CSVImport:PickClassForTemplate'), ImportHelper::GetClassesSelectUIBlock('template_class', '', UR_ACTION_BULK_MODIFY));
$oTabTemplate->AddSubBlock($oFieldTemplate);
$oDivTemplate = UIContentBlockUIBlockFactory::MakeStandard("template")->AddCSSClass("ibo-is-visible");
$oTabTemplate->AddSubBlock($oDivTemplate);
diff --git a/setup/backup.class.inc.php b/setup/backup.class.inc.php
index feb9f84a8..412c5f785 100644
--- a/setup/backup.class.inc.php
+++ b/setup/backup.class.inc.php
@@ -511,7 +511,7 @@ EOF;
{
$bDbTlsEnabled = $oConfig->Get('db_tls.enabled');
if (!$bDbTlsEnabled) {
- return '';
+ return CMDBSource::IsSslModeDBVersion() ? ' --skip-ssl' : '';
}
$sTlsOptions = '';
// Mysql 5.7.11 and upper deprecated --ssl and uses --ssl-mode instead
diff --git a/sources/Application/Helper/ImportHelper.php b/sources/Application/Helper/ImportHelper.php
new file mode 100644
index 000000000..c6ffd43df
--- /dev/null
+++ b/sources/Application/Helper/ImportHelper.php
@@ -0,0 +1,65 @@
+AddSubBlock($oOption);
+ $aValidClasses = [];
+ $aClassCategories = ['bizmodel', 'addon/authentication'];
+ if ($bAdvanced) {
+ $aClassCategories[] = 'grant_by_profile';
+ }
+ if (UserRights::IsAdministrator()) {
+ $aClassCategories[] = 'application';
+ }
+ foreach ($aClassCategories as $sClassCategory) {
+ foreach (MetaModel::GetClasses($sClassCategory) as $sClassName) {
+ if ((is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode)) &&
+ (!MetaModel::IsAbstract($sClassName))) {
+ $sDisplayName = ($bAdvanced) ? MetaModel::GetName($sClassName)." ($sClassName)" : MetaModel::GetName($sClassName);
+ $aValidClasses[$sDisplayName] = SelectOptionUIBlockFactory::MakeForSelectOption($sClassName, $sDisplayName, ($sClassName == $sDefaultValue));
+ }
+ }
+ }
+ ksort($aValidClasses);
+ foreach ($aValidClasses as $sValue => $oBlock) {
+ $oSelectBlock->AddSubBlock($oBlock);
+ }
+
+ return $oSelectBlock;
+ }
+}
diff --git a/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php b/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php
index 2a4496b11..03ceb31f1 100644
--- a/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php
+++ b/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php
@@ -8,8 +8,13 @@ use AttributeFriendlyName;
use AttributeLinkedSet;
use cmdbAbstract;
use cmdbAbstractObject;
+use CoreException;
use Dict;
+use Exception;
+use IssueLog;
+use LogChannels;
use Metamodel;
+use utils;
/**
* Class DataTableSettings
@@ -130,7 +135,10 @@ class DataTableSettings
*/
public function unserialize($sData)
{
- $aData = unserialize($sData);
+ $aData = utils::Unserialize($sData);
+ if (!is_array($aData)) {
+ throw new CoreException('Wrong data table settings format, expected an array', ['datatable_settings_data' => $aData]);
+ }
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
$this->aColumns = $aData['aColumns'];
foreach ($this->aClassAliases as $sAlias => $sClass) {
@@ -269,7 +277,19 @@ class DataTableSettings
return null;
}
}
- $oSettings->unserialize($pref);
+
+ try {
+ $oSettings->unserialize($pref);
+ } catch (Exception $e) {
+ IssueLog::Warning("User table settings corrupted, back to the default values provided by the data model", LogChannels::CONSOLE, [
+ 'table_id' => $sTableId,
+ 'root_cause' => $e->getMessage(),
+ ]);
+ // unset the preference
+ appUserPreferences::UnsetPref($oSettings->GetPrefsKey($sTableId));
+ // use the default values provided by the data model
+ return null;
+ }
return $oSettings;
}
diff --git a/sources/Core/AttributeDefinition/AttributeCaseLog.php b/sources/Core/AttributeDefinition/AttributeCaseLog.php
index 9dadebba5..376aaeff8 100644
--- a/sources/Core/AttributeDefinition/AttributeCaseLog.php
+++ b/sources/Core/AttributeDefinition/AttributeCaseLog.php
@@ -218,7 +218,7 @@ class AttributeCaseLog extends AttributeLongText
}
if (strlen($sIndex) > 0) {
- $aIndex = unserialize($sIndex);
+ $aIndex = utils::Unserialize($sIndex);
$value = new ormCaseLog($sLog, $aIndex);
} else {
$value = new ormCaseLog($sLog);
diff --git a/templates/base/components/input/set/layout.ready.js.twig b/templates/base/components/input/set/layout.ready.js.twig
index 60c132bb3..ea07bbc34 100644
--- a/templates/base/components/input/set/layout.ready.js.twig
+++ b/templates/base/components/input/set/layout.ready.js.twig
@@ -23,7 +23,7 @@ let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({
},
{# PLUGIN combodo auto position #}
'combodo_auto_position' : {
- maxDropDownHeight: 300, {# in px #}
+ maxDropDownHeight: '30vh', {# same value as external key widget #}
},
{# PLUGIN combodo add button #}
{% if oUIBlock.HasAddOptionButton() %}
diff --git a/tests/php-unit-tests/unitary-tests/application/utilsTest.php b/tests/php-unit-tests/unitary-tests/application/utilsTest.php
index b9b109e0a..593883a31 100644
--- a/tests/php-unit-tests/unitary-tests/application/utilsTest.php
+++ b/tests/php-unit-tests/unitary-tests/application/utilsTest.php
@@ -23,6 +23,7 @@
namespace Combodo\iTop\Test\UnitTest\Application;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
+use CoreException;
use ormDocument;
use utils;
@@ -983,4 +984,21 @@ INI;
unlink($sTmpFileOutsideItop);
}
+
+ public function testUnserialize()
+ {
+ // data to unserialize containing an object
+ $sData = 'a:2:{s:6:"string";s:9:"My string";s:6:"object";O:8:"DateTime":3:{s:4:"date";s:26:"2026-04-13 09:09:23.033175";s:13:"timezone_type";i:3;s:8:"timezone";s:16:"Europe/Amsterdam";}}';
+
+ // allow the DateTime object (no exception triggered)
+ utils::Unserialize($sData, ['allowed_classes' => ['DateTime']]);
+
+ // flag to avoid throwing an exception
+ utils::Unserialize($sData, ['allowed_classes' => false], false);
+
+ // flag to require throwing an exception
+ $this->expectException(CoreException::class);
+ utils::Unserialize($sData);
+
+ }
}
diff --git a/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php b/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
index 5b75d79f8..a04755685 100644
--- a/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
+++ b/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
@@ -45,7 +45,11 @@ class DBBackupTest extends ItopTestCase
$oConfigToTest->Set('db_tls.enabled', false);
$sCliArgsNoTls = DBBackup::GetMysqlCliTlsOptions($oConfigToTest);
- $this->assertEmpty($sCliArgsNoTls);
+ if (CMDBSource::IsSslModeDBVersion()) {
+ $this->assertEquals(' --skip-ssl', $sCliArgsNoTls);
+ } else {
+ $this->assertEmpty($sCliArgsNoTls);
+ }
}
/**