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 @@ -1987,9 +2033,12 @@ 10 - @@ -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 - @@ -3436,6 +3522,9 @@ 10 + + 20 + 20 @@ -3622,9 +3711,12 @@ 10 - @@ -3800,6 +3892,11 @@ 128 true + + end_of_support + + true + SoftwareInstance software_id @@ -3855,13 +3952,21 @@ + + + + 10 + + + 10 + - 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 - @@ -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 - @@ -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 - 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); + } } /**