diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index e97e8e243..87a74a8fd 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -3269,10 +3269,13 @@ class AttributeClassState extends AttributeString $sClass = $oHostObj->Get($sTargetClass); $aAllowedStates = array(); - $aValues = MetaModel::EnumStates($sClass); - foreach(array_keys($aValues) as $sState) + foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) { - $aAllowedStates[$sState] = $sState.' ('.MetaModel::GetStateLabel($sClass, $sState).')'; + $aValues = MetaModel::EnumStates($sChildClass); + foreach (array_keys($aValues) as $sState) + { + $aAllowedStates[$sState] = $sState.' ('.MetaModel::GetStateLabel($sChildClass, $sState).')'; + } } return $aAllowedStates; } @@ -3291,9 +3294,15 @@ class AttributeClassState extends AttributeString { $sTargetClass = $this->Get('class_field'); $sClass = $oHostObject->Get($sTargetClass); - - $sHTML = ''.$sValue.''; - return $sHTML; + foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) + { + $aValues = MetaModel::EnumStates($sChildClass); + if (in_array($sValue, $aValues)) + { + $sHTML = ''.$sValue.''; + return $sHTML; + } + } } return $sValue; diff --git a/core/restservices.class.inc.php b/core/restservices.class.inc.php index 2ec01292c..c052799c5 100644 --- a/core/restservices.class.inc.php +++ b/core/restservices.class.inc.php @@ -257,13 +257,14 @@ class CoreServices implements iRestServiceProvider */ public function ListOperations($sVersion) { + // 1.4 - iTop 2.5.2, 2.6.1, 2.7.0, Verb 'core/get': added pagination parameters limit and page // 1.3 - iTop 2.2.0, Verb 'get_related': added the options 'redundancy' and 'direction' to take into account the redundancy in the impact analysis // 1.2 - was documented in the wiki but never released ! Same as 1.3 // 1.1 - In the reply, objects have a 'key' entry so that it is no more necessary to split class::key programmaticaly // 1.0 - Initial implementation in iTop 2.0.1 // $aOps = array(); - if (in_array($sVersion, array('1.0', '1.1', '1.2', '1.3'))) + if (in_array($sVersion, array('1.0', '1.1', '1.2', '1.3', '1.4'))) { $aOps[] = array( 'verb' => 'core/create', @@ -299,9 +300,16 @@ class CoreServices implements iRestServiceProvider /** * Enumerate services delivered by this class + * * @param string $sVersion The version (e.g. 1.0) supported by the services + * @param string $sVerb + * @param $aParams + * * @return RestResult The standardized result structure (at least a message) - * @throws Exception in case of internal failure. + * @throws \CoreException + * @throws \CoreUnexpectedValue + * @throws \SimpleGraphException + * @throws \Exception */ public function ExecOperation($sVersion, $sVerb, $aParams) { diff --git a/datamodels/2.x/itop-config/config.php b/datamodels/2.x/itop-config/config.php index ead77a7ea..7e9f9231b 100644 --- a/datamodels/2.x/itop-config/config.php +++ b/datamodels/2.x/itop-config/config.php @@ -42,7 +42,6 @@ function TestConfig($sContents, $oP) eval('if(0){'.trim($sSafeContent).'}'); $sNoise = trim(ob_get_contents()); ob_end_clean(); - CheckDBPasswordInNewConfig($sSafeContent); } catch (Error $e) { @@ -78,17 +77,17 @@ function TestConfig($sContents, $oP) /** * @param $sSafeContent * - * @throws \Exception + * @return bool */ -function CheckDBPasswordInNewConfig($sSafeContent) +function DBPasswordInNewConfigIsOk($sSafeContent) { $bIsWindows = (array_key_exists('WINDIR', $_SERVER) || array_key_exists('windir', $_SERVER)); if ($bIsWindows && (preg_match("@'db_pwd' => '[^%!\"]+',@U", $sSafeContent) === 0)) { - // Unsupported Password - throw new Exception("On Windows, database password must not contain %, ! or \" character (backups won't work)..."); + return false; } + return true; } ///////////////////////////////////////////////////////////////////// @@ -179,7 +178,14 @@ try @unlink($sTmpFile); @chmod($sConfigFile, 0444); // Read-only - $oP->p('
'.Dict::S('config-saved').'
'); + if (DBPasswordInNewConfigIsOk($sConfig)) + { + $oP->p('
'.Dict::S('config-saved').'
'); + } + else + { + $oP->p('
'.Dict::S('config-saved-warning-db-password').'
'); + } $sOriginalConfig = str_replace("\r\n", "\n", file_get_contents($sConfigFile)); } catch (Exception $e) diff --git a/datamodels/2.x/itop-config/en.dict.itop-config.php b/datamodels/2.x/itop-config/en.dict.itop-config.php index c6bfb0161..322b723d9 100644 --- a/datamodels/2.x/itop-config/en.dict.itop-config.php +++ b/datamodels/2.x/itop-config/en.dict.itop-config.php @@ -35,4 +35,5 @@ Dict::Add('EN US', 'English', 'English', array( 'config-reverted' => 'The configuration has been reverted.', 'config-parse-error' => 'Line %2$d: %1$s.
The file has NOT been updated.', 'config-current-line' => 'Editing line: %1$s', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.', )); diff --git a/datamodels/2.x/itop-config/fr.dict.itop-config.php b/datamodels/2.x/itop-config/fr.dict.itop-config.php index 3757a3221..88adb0ec4 100644 --- a/datamodels/2.x/itop-config/fr.dict.itop-config.php +++ b/datamodels/2.x/itop-config/fr.dict.itop-config.php @@ -19,4 +19,5 @@ Dict::Add('FR FR', 'French', 'Français', array( 'config-reverted' => 'Vos modifications ont été écrasées par la version enregistrée.', 'config-parse-error' => 'Ligne %2$d: %1$s.
Le fichier n\'a PAS été modifié.', 'config-current-line' => 'Ligne en édition : %1$s', + 'config-saved-warning-db-password' => 'Configuration enregistrée. Les sauvegardes ne fonctionneront pas à cause du format du pot de passe de la base.', )); diff --git a/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php index 6b087f76d..304dac157 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php @@ -1163,10 +1163,30 @@ class ObjectFormManager extends FormManager } elseif ($oAttDef->GetEditClass() === 'CustomFields') { - if (!empty($value['template_data']) && !empty($value['user_data'])) + // We don't update attribute as ormCustomField comparaison is not working as excepted. + // When several templates available, "template_id" is not sent by the portal has it is a read-only select input + // therefore, the TemplateFieldsHandler::CompareValues() doesn't work. + // This use case works in the console as it always send all fields, even hidden and read-only. + + // Different templates + if( isset($value['template_id']) + && ($value['template_id'] != $value['current_template_id']) ) { $this->oObject->Set($sAttCode, $value); } + // Same template, different fields + elseif(isset($value['template_id'], $value['template_data']) + && ($value['template_id'] == $value['current_template_id']) + && ($value['template_data'] != $value['current_template_data']) ) + { + $this->oObject->Set($sAttCode, $value); + } + // Update of current values + elseif(isset($value['user_data'])) + { + $this->oObject->Set($sAttCode, $value); + } + // Else don't update! Otherwise we might loose current value } else { diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index 49acc5b77..b71c42ec3 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -408,7 +408,7 @@ Dict::Add('FR FR', 'French', 'Français', array( 'UI:ClickToCreateNew' => 'Créer un nouvel objet de type %1$s', 'UI:SearchFor_Class' => 'Rechercher des objets de type %1$s', 'UI:NoObjectToDisplay' => 'Aucun objet à afficher.', - 'UI:Error:SaveFailed' => 'L\'objet ne peux pas être sauvé : ', + 'UI:Error:SaveFailed' => 'L\'objet ne peut pas être sauvé : ', 'UI:Error:MandatoryTemplateParameter_object_id' => 'Le paramètre object_id est obligatoire quand link_attr est spécifié. Vérifiez la définition du modèle.', 'UI:Error:MandatoryTemplateParameter_target_attr' => 'Le paramètre taarget_attr est obligatoire quand link_attr est spécifié. Vérifiez la définition du modèle.', 'UI:Error:MandatoryTemplateParameter_group_by' => 'Le paramètre group_by est obligatoire. Vérifiez la définition du modèle.', @@ -773,7 +773,7 @@ Dict::Add('FR FR', 'French', 'Français', array( 'UI:Delete:_Name_Class_Deleted' => ' %2$s %1$s supprimé.', 'UI:Delete:ConfirmDeletionOf_Name' => 'Suppression de %1$s', 'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => 'Suppression de %1$d objets de type %2$s', - 'UI:Delete:CannotDeleteBecause' => 'Ne peux pas être supprimé: %1$s', + 'UI:Delete:CannotDeleteBecause' => 'Ne peut pas être supprimé: %1$s', 'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Devrait être supprimé automatiquement, mais cela n\'est pas possible: %1$s', 'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Doit être supprimé manuellement, mais cela n\'est pas possible: %1$s', 'UI:Delete:WillBeDeletedAutomatically' => 'Sera supprimé automatiquement', diff --git a/js/jquery.tablesorter.pager.js b/js/jquery.tablesorter.pager.js index ec618fc3c..bb1a56228 100644 --- a/js/jquery.tablesorter.pager.js +++ b/js/jquery.tablesorter.pager.js @@ -90,7 +90,7 @@ function sprintf(format, etc) { function checkAll(table, pager, value) { // Mark all the displayed items as check or unchecked depending on the value - $(table).find(':checkbox[name^=selectObj]:not([disabled]').each(function (index, element) { + $(table).find(':checkbox[name^=selectObj]:not([disabled])').each(function (index, element) { var $currentCheckbox = $(this); $currentCheckbox.prop('checked', value); $currentLine = $currentCheckbox.closest("tr"); diff --git a/setup/setuputils.class.inc.php b/setup/setuputils.class.inc.php index ab3892245..874116d17 100644 --- a/setup/setuputils.class.inc.php +++ b/setup/setuputils.class.inc.php @@ -1306,9 +1306,8 @@ EOF $bIsWindows = (array_key_exists('WINDIR', $_SERVER) || array_key_exists('windir', $_SERVER)); if ($bIsWindows && (preg_match('@([%!"])@',$sDBPwd) > 0)) { - // Unsuported Password, disable the "Next" button - $oPage->add_ready_script('$("#wiz_form").data("db_connection", "error");'); - $oPage->add_ready_script('$("#db_info").html(" On Windows, database password must not contain %, ! or " character");'); + // Unsuported Password, warn the user + $oPage->add_ready_script('$("#db_info").html(" On Windows, the backup won\'t work because database password contains %, ! or " character");'); } else { diff --git a/webservices/rest.php b/webservices/rest.php index 0b5843efd..aca4a56ba 100644 --- a/webservices/rest.php +++ b/webservices/rest.php @@ -83,7 +83,7 @@ class RestResultListOperations extends RestResult $this->operations[] = array( 'verb' => $sVerb, 'description' => $sDescription, - 'extension' => $sServiceProviderClass + 'extension' => $sServiceProviderClass, ); } } @@ -96,7 +96,7 @@ if (!function_exists('json_last_error_msg')) { JSON_ERROR_STATE_MISMATCH => 'State mismatch (invalid or malformed JSON)', JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded', JSON_ERROR_SYNTAX => 'Syntax error', - JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded' + JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded', ); $error = json_last_error(); @@ -186,6 +186,7 @@ try } $aOpToRestService = array(); // verb => $oRestServiceProvider + /** @var iRestServiceProvider $oRestSP */ foreach ($aProviders as $oRestSP) { $aOperations = $oRestSP->ListOperations($sVersion); diff --git a/webservices/webservices.basic.php b/webservices/webservices.basic.php index af469aa9d..54c187825 100644 --- a/webservices/webservices.basic.php +++ b/webservices/webservices.basic.php @@ -36,8 +36,8 @@ class BasicServices extends WebServicesBase /** * Get the server version (TODO: get it dynamically, where ?) - * - * @return WebServiceResult + * + * @return string WebServiceResult */ static public function GetVersion() {