Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design

# Conflicts:
#	webservices/import.php
This commit is contained in:
Pierre Goiffon
2020-09-18 10:48:34 +02:00
31 changed files with 1387 additions and 1224 deletions

View File

@@ -13,7 +13,7 @@ ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_visual_guides = 140
ij_visual_guides = 80,120
ij_wrap_on_typing = true
[*.css]
@@ -22,7 +22,8 @@ ij_smart_tabs = true
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_brace_placement = 0
ij_css_brace_placement = end_of_line
ij_css_enforce_quotes_on_format = false
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
@@ -33,15 +34,16 @@ ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_value_alignment = 0
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align
[*.scss]
indent_style = tab
ij_smart_tabs = true
ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
ij_scss_blank_lines_between_blocks = 1
ij_scss_brace_placement = 0
ij_scss_enforce_quotes_on_format = false
ij_scss_hex_color_long_format = false
ij_scss_hex_color_lower_case = false
ij_scss_hex_color_short_format = false
@@ -52,12 +54,15 @@ ij_scss_keep_single_line_blocks = false
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0
[*.twig]
indent_style = tab
ij_smart_tabs = true
ij_wrap_on_typing = false
ij_twig_keep_indents_on_empty_lines = false
ij_twig_spaces_inside_comments_delimiters = true
ij_twig_spaces_inside_delimiters = true
ij_twig_spaces_inside_variable_delimiters = true
@@ -69,212 +74,37 @@ ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ctp,*.phtml,*.module,*.php,*.php5,*.php4,*.hphp,*.inc}]
indent_style = tab
ij_continuation_indent_size = 4
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]
indent_size = 2
tab_width = 2
ij_smart_tabs = true
ij_wrap_on_typing = false
ij_php_align_assignments = false
ij_php_align_class_constants = false
ij_php_align_group_field_declarations = false
ij_php_align_inline_comments = false
ij_php_align_key_value_pairs = false
ij_php_align_multiline_array_initializer_expression = false
ij_php_align_multiline_binary_operation = false
ij_php_align_multiline_chained_methods = false
ij_php_align_multiline_extends_list = false
ij_php_align_multiline_for = true
ij_php_align_multiline_parameters = false
ij_php_align_multiline_parameters_in_calls = false
ij_php_align_multiline_ternary_operation = false
ij_php_align_phpdoc_comments = false
ij_php_align_phpdoc_param_names = false
ij_php_api_weight = 1
ij_php_array_initializer_new_line_after_left_brace = true
ij_php_array_initializer_right_brace_on_new_line = true
ij_php_array_initializer_wrap = on_every_item
ij_php_assignment_wrap = off
ij_php_author_weight = 7
ij_php_binary_operation_sign_on_next_line = false
ij_php_binary_operation_wrap = off
ij_php_blank_lines_after_class_header = 0
ij_php_blank_lines_after_function = 1
ij_php_blank_lines_after_imports = 1
ij_php_blank_lines_after_opening_tag = 0
ij_php_blank_lines_after_package = 1
ij_php_blank_lines_around_class = 1
ij_php_blank_lines_around_constants = 0
ij_php_blank_lines_around_field = 0
ij_php_blank_lines_around_method = 1
ij_php_blank_lines_before_class_end = 0
ij_php_blank_lines_before_imports = 1
ij_php_blank_lines_before_method_body = 0
ij_php_blank_lines_before_package = 1
ij_php_blank_lines_before_return_statement = 1
ij_php_block_brace_style = end_of_line
ij_php_call_parameters_new_line_after_left_paren = false
ij_php_call_parameters_right_paren_on_new_line = false
ij_php_call_parameters_wrap = normal
ij_php_catch_on_new_line = false
ij_php_category_weight = 28
ij_php_class_brace_style = end_of_line
ij_php_comma_after_last_array_element = true
ij_php_concat_spaces = false
ij_php_copyright_weight = 28
ij_php_deprecated_weight = 28
ij_php_do_while_brace_force = always
ij_php_else_if_style = as_is
ij_php_else_on_new_line = true
ij_php_example_weight = 3
ij_php_extends_keyword_wrap = off
ij_php_extends_list_wrap = off
ij_php_fields_default_visibility = private
ij_php_filesource_weight = 28
ij_php_finally_on_new_line = false
ij_php_for_brace_force = always
ij_php_for_statement_new_line_after_left_paren = false
ij_php_for_statement_right_paren_on_new_line = false
ij_php_for_statement_wrap = off
ij_php_force_short_declaration_array_style = false
ij_php_global_weight = 28
ij_php_group_use_wrap = on_every_item
ij_php_if_brace_force = always
ij_php_if_lparen_on_next_line = false
ij_php_if_rparen_on_next_line = false
ij_php_ignore_weight = 28
ij_php_import_sorting = alphabetic
ij_php_indent_break_from_case = true
ij_php_indent_case_from_switch = true
ij_php_indent_code_in_php_tags = false
ij_php_internal_weight = 0
ij_php_keep_blank_lines_after_lbrace = 2
ij_php_keep_blank_lines_before_right_brace = 2
ij_php_keep_blank_lines_in_code = 2
ij_php_keep_blank_lines_in_declarations = 2
ij_php_keep_control_statement_in_one_line = true
ij_php_keep_first_column_comment = true
ij_php_keep_indents_on_empty_lines = false
ij_php_keep_line_breaks = true
ij_php_keep_rparen_and_lbrace_on_one_line = true
ij_php_keep_simple_methods_in_one_line = false
ij_php_lambda_brace_style = end_of_line
ij_php_license_weight = 28
ij_php_line_comment_add_space = false
ij_php_line_comment_at_first_column = true
ij_php_link_weight = 28
ij_php_lower_case_boolean_const = true
ij_php_lower_case_null_const = true
ij_php_method_brace_style = end_of_line
ij_php_method_call_chain_wrap = off
ij_php_method_parameters_new_line_after_left_paren = true
ij_php_method_parameters_right_paren_on_new_line = true
ij_php_method_parameters_wrap = normal
ij_php_method_weight = 28
ij_php_modifier_list_wrap = false
ij_php_multiline_chained_calls_semicolon_on_new_line = false
ij_php_namespace_brace_style = 1
ij_php_null_type_position = in_the_end
ij_php_package_weight = 28
ij_php_param_weight = 4
ij_php_parentheses_expression_new_line_after_left_paren = false
ij_php_parentheses_expression_right_paren_on_new_line = false
ij_php_phpdoc_blank_line_before_tags = true
ij_php_phpdoc_blank_lines_around_parameters = true
ij_php_phpdoc_keep_blank_lines = true
ij_php_phpdoc_param_spaces_between_name_and_description = 1
ij_php_phpdoc_param_spaces_between_tag_and_type = 1
ij_php_phpdoc_param_spaces_between_type_and_name = 1
ij_php_phpdoc_use_fqcn = true
ij_php_phpdoc_wrap_long_lines = true
ij_php_place_assignment_sign_on_next_line = false
ij_php_place_parens_for_constructor = 0
ij_php_property_read_weight = 28
ij_php_property_weight = 28
ij_php_property_write_weight = 28
ij_php_return_type_on_new_line = false
ij_php_return_weight = 5
ij_php_see_weight = 2
ij_php_since_weight = 28
ij_php_sort_phpdoc_elements = true
ij_php_space_after_colon = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_after_comma = true
ij_php_space_after_for_semicolon = true
ij_php_space_after_quest = true
ij_php_space_after_type_cast = false
ij_php_space_after_unary_not = false
ij_php_space_before_array_initializer_left_brace = false
ij_php_space_before_catch_keyword = true
ij_php_space_before_catch_left_brace = true
ij_php_space_before_catch_parentheses = true
ij_php_space_before_class_left_brace = true
ij_php_space_before_closure_left_parenthesis = true
ij_php_space_before_colon = true
ij_php_space_before_colon_in_return_type = false
ij_php_space_before_comma = false
ij_php_space_before_do_left_brace = true
ij_php_space_before_else_keyword = true
ij_php_space_before_else_left_brace = true
ij_php_space_before_finally_keyword = true
ij_php_space_before_finally_left_brace = true
ij_php_space_before_for_left_brace = true
ij_php_space_before_for_parentheses = true
ij_php_space_before_for_semicolon = false
ij_php_space_before_if_left_brace = true
ij_php_space_before_if_parentheses = true
ij_php_space_before_method_call_parentheses = false
ij_php_space_before_method_left_brace = true
ij_php_space_before_method_parentheses = false
ij_php_space_before_quest = true
ij_php_space_before_switch_left_brace = true
ij_php_space_before_switch_parentheses = true
ij_php_space_before_try_left_brace = true
ij_php_space_before_unary_not = false
ij_php_space_before_while_keyword = true
ij_php_space_before_while_left_brace = true
ij_php_space_before_while_parentheses = true
ij_php_space_between_ternary_quest_and_colon = false
ij_php_spaces_around_additive_operators = true
ij_php_spaces_around_arrow = false
ij_php_spaces_around_assignment_in_declare = false
ij_php_spaces_around_assignment_operators = true
ij_php_spaces_around_bitwise_operators = true
ij_php_spaces_around_equality_operators = true
ij_php_spaces_around_logical_operators = true
ij_php_spaces_around_multiplicative_operators = true
ij_php_spaces_around_null_coalesce_operator = true
ij_php_spaces_around_relational_operators = true
ij_php_spaces_around_shift_operators = true
ij_php_spaces_around_unary_operator = false
ij_php_spaces_around_var_within_brackets = false
ij_php_spaces_within_array_initializer_braces = false
ij_php_spaces_within_brackets = false
ij_php_spaces_within_catch_parentheses = false
ij_php_spaces_within_for_parentheses = false
ij_php_spaces_within_if_parentheses = false
ij_php_spaces_within_method_call_parentheses = false
ij_php_spaces_within_method_parentheses = false
ij_php_spaces_within_parentheses = false
ij_php_spaces_within_short_echo_tags = true
ij_php_spaces_within_switch_parentheses = false
ij_php_spaces_within_while_parentheses = false
ij_php_special_else_if_treatment = false
ij_php_subpackage_weight = 28
ij_php_ternary_operation_signs_on_next_line = false
ij_php_ternary_operation_wrap = off
ij_php_throws_weight = 6
ij_php_todo_weight = 28
ij_php_unknown_tag_weight = 28
ij_php_upper_case_boolean_const = false
ij_php_upper_case_null_const = false
ij_php_uses_weight = 28
ij_php_var_weight = 28
ij_php_variable_naming_style = mixed
ij_php_version_weight = 28
ij_php_while_brace_force = always
ij_php_while_on_new_line = false
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = false
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = true
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal
[{*.js,*.cjs}]
[{*.bash,*.sh,*.zsh}]
indent_size = 2
tab_width = 2
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{*.cjs,*.js}]
indent_style = tab
ij_continuation_indent_size = 4
ij_smart_tabs = true
@@ -296,13 +126,13 @@ ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**/*,@angular/material,@angular/material/typings/**
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = end_of_line
ij_javascript_block_brace_style = next_line
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
@@ -310,7 +140,7 @@ ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = always
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = true
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
@@ -318,7 +148,7 @@ ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = always
ij_javascript_for_brace_force = never
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
@@ -354,6 +184,9 @@ ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_explicit_types_function_expression_returns = false
ij_javascript_prefer_explicit_types_function_returns = false
ij_javascript_prefer_explicit_types_vars_fields = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
@@ -434,11 +267,237 @@ ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = always
ij_javascript_while_brace_force = never
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.sht,*.html,*.shtm,*.shtml,*.htm,*.ng}]
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
indent_style = tab
ij_continuation_indent_size = 4
ij_smart_tabs = true
ij_wrap_on_typing = false
ij_php_align_assignments = false
ij_php_align_class_constants = false
ij_php_align_group_field_declarations = false
ij_php_align_inline_comments = false
ij_php_align_key_value_pairs = false
ij_php_align_multiline_array_initializer_expression = false
ij_php_align_multiline_binary_operation = false
ij_php_align_multiline_chained_methods = false
ij_php_align_multiline_extends_list = false
ij_php_align_multiline_for = true
ij_php_align_multiline_parameters = false
ij_php_align_multiline_parameters_in_calls = false
ij_php_align_multiline_ternary_operation = false
ij_php_align_phpdoc_comments = false
ij_php_align_phpdoc_param_names = false
ij_php_anonymous_brace_style = end_of_line
ij_php_api_weight = 1
ij_php_array_initializer_new_line_after_left_brace = true
ij_php_array_initializer_right_brace_on_new_line = true
ij_php_array_initializer_wrap = on_every_item
ij_php_assignment_wrap = off
ij_php_author_weight = 8
ij_php_binary_operation_sign_on_next_line = false
ij_php_binary_operation_wrap = off
ij_php_blank_lines_after_class_header = 0
ij_php_blank_lines_after_function = 1
ij_php_blank_lines_after_imports = 1
ij_php_blank_lines_after_opening_tag = 0
ij_php_blank_lines_after_package = 1
ij_php_blank_lines_around_class = 1
ij_php_blank_lines_around_constants = 0
ij_php_blank_lines_around_field = 0
ij_php_blank_lines_around_method = 1
ij_php_blank_lines_before_class_end = 0
ij_php_blank_lines_before_imports = 1
ij_php_blank_lines_before_method_body = 0
ij_php_blank_lines_before_package = 1
ij_php_blank_lines_before_return_statement = 1
ij_php_blank_lines_between_imports = 0
ij_php_block_brace_style = end_of_line
ij_php_call_parameters_new_line_after_left_paren = false
ij_php_call_parameters_right_paren_on_new_line = false
ij_php_call_parameters_wrap = normal
ij_php_catch_on_new_line = true
ij_php_category_weight = 28
ij_php_class_brace_style = next_line
ij_php_comma_after_last_array_element = true
ij_php_concat_spaces = false
ij_php_copyright_weight = 28
ij_php_deprecated_weight = 2
ij_php_do_while_brace_force = always
ij_php_else_if_style = as_is
ij_php_else_on_new_line = false
ij_php_example_weight = 4
ij_php_extends_keyword_wrap = off
ij_php_extends_list_wrap = off
ij_php_fields_default_visibility = private
ij_php_filesource_weight = 28
ij_php_finally_on_new_line = true
ij_php_for_brace_force = always
ij_php_for_statement_new_line_after_left_paren = false
ij_php_for_statement_right_paren_on_new_line = false
ij_php_for_statement_wrap = off
ij_php_force_short_declaration_array_style = false
ij_php_getters_setters_naming_style = camel_case
ij_php_getters_setters_order_style = getters_first
ij_php_global_weight = 28
ij_php_group_use_wrap = on_every_item
ij_php_if_brace_force = always
ij_php_if_lparen_on_next_line = false
ij_php_if_rparen_on_next_line = false
ij_php_ignore_weight = 28
ij_php_import_sorting = alphabetic
ij_php_indent_break_from_case = true
ij_php_indent_case_from_switch = true
ij_php_indent_code_in_php_tags = false
ij_php_internal_weight = 0
ij_php_keep_blank_lines_after_lbrace = 2
ij_php_keep_blank_lines_before_right_brace = 2
ij_php_keep_blank_lines_in_code = 2
ij_php_keep_blank_lines_in_declarations = 2
ij_php_keep_control_statement_in_one_line = true
ij_php_keep_first_column_comment = true
ij_php_keep_indents_on_empty_lines = false
ij_php_keep_line_breaks = true
ij_php_keep_rparen_and_lbrace_on_one_line = true
ij_php_keep_simple_classes_in_one_line = false
ij_php_keep_simple_methods_in_one_line = false
ij_php_lambda_brace_style = end_of_line
ij_php_license_weight = 28
ij_php_line_comment_add_space = false
ij_php_line_comment_at_first_column = true
ij_php_link_weight = 28
ij_php_lower_case_boolean_const = true
ij_php_lower_case_keywords = true
ij_php_lower_case_null_const = true
ij_php_method_brace_style = next_line
ij_php_method_call_chain_wrap = off
ij_php_method_parameters_new_line_after_left_paren = true
ij_php_method_parameters_right_paren_on_new_line = true
ij_php_method_parameters_wrap = normal
ij_php_method_weight = 28
ij_php_modifier_list_wrap = false
ij_php_multiline_chained_calls_semicolon_on_new_line = false
ij_php_namespace_brace_style = 1
ij_php_new_line_after_php_opening_tag = false
ij_php_null_type_position = in_the_end
ij_php_package_weight = 28
ij_php_param_weight = 5
ij_php_parentheses_expression_new_line_after_left_paren = false
ij_php_parentheses_expression_right_paren_on_new_line = false
ij_php_phpdoc_blank_line_before_tags = true
ij_php_phpdoc_blank_lines_around_parameters = true
ij_php_phpdoc_keep_blank_lines = true
ij_php_phpdoc_param_spaces_between_name_and_description = 1
ij_php_phpdoc_param_spaces_between_tag_and_type = 1
ij_php_phpdoc_param_spaces_between_type_and_name = 1
ij_php_phpdoc_use_fqcn = true
ij_php_phpdoc_wrap_long_lines = true
ij_php_place_assignment_sign_on_next_line = false
ij_php_place_parens_for_constructor = 0
ij_php_property_read_weight = 28
ij_php_property_weight = 28
ij_php_property_write_weight = 28
ij_php_return_type_on_new_line = false
ij_php_return_weight = 6
ij_php_see_weight = 3
ij_php_since_weight = 28
ij_php_sort_phpdoc_elements = true
ij_php_space_after_colon = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_after_comma = true
ij_php_space_after_for_semicolon = true
ij_php_space_after_quest = true
ij_php_space_after_type_cast = false
ij_php_space_after_unary_not = false
ij_php_space_before_array_initializer_left_brace = false
ij_php_space_before_catch_keyword = true
ij_php_space_before_catch_left_brace = true
ij_php_space_before_catch_parentheses = true
ij_php_space_before_class_left_brace = true
ij_php_space_before_closure_left_parenthesis = true
ij_php_space_before_colon = true
ij_php_space_before_colon_in_return_type = false
ij_php_space_before_comma = false
ij_php_space_before_do_left_brace = true
ij_php_space_before_else_keyword = true
ij_php_space_before_else_left_brace = true
ij_php_space_before_finally_keyword = true
ij_php_space_before_finally_left_brace = true
ij_php_space_before_for_left_brace = true
ij_php_space_before_for_parentheses = true
ij_php_space_before_for_semicolon = false
ij_php_space_before_if_left_brace = true
ij_php_space_before_if_parentheses = true
ij_php_space_before_method_call_parentheses = false
ij_php_space_before_method_left_brace = true
ij_php_space_before_method_parentheses = false
ij_php_space_before_quest = true
ij_php_space_before_short_closure_left_parenthesis = false
ij_php_space_before_switch_left_brace = true
ij_php_space_before_switch_parentheses = true
ij_php_space_before_try_left_brace = true
ij_php_space_before_unary_not = false
ij_php_space_before_while_keyword = true
ij_php_space_before_while_left_brace = true
ij_php_space_before_while_parentheses = true
ij_php_space_between_ternary_quest_and_colon = false
ij_php_spaces_around_additive_operators = true
ij_php_spaces_around_arrow = false
ij_php_spaces_around_assignment_in_declare = false
ij_php_spaces_around_assignment_operators = true
ij_php_spaces_around_bitwise_operators = true
ij_php_spaces_around_equality_operators = true
ij_php_spaces_around_logical_operators = true
ij_php_spaces_around_multiplicative_operators = true
ij_php_spaces_around_null_coalesce_operator = true
ij_php_spaces_around_relational_operators = true
ij_php_spaces_around_shift_operators = true
ij_php_spaces_around_unary_operator = false
ij_php_spaces_around_var_within_brackets = false
ij_php_spaces_within_array_initializer_braces = false
ij_php_spaces_within_brackets = false
ij_php_spaces_within_catch_parentheses = false
ij_php_spaces_within_for_parentheses = false
ij_php_spaces_within_if_parentheses = false
ij_php_spaces_within_method_call_parentheses = false
ij_php_spaces_within_method_parentheses = false
ij_php_spaces_within_parentheses = false
ij_php_spaces_within_short_echo_tags = true
ij_php_spaces_within_switch_parentheses = false
ij_php_spaces_within_while_parentheses = false
ij_php_special_else_if_treatment = true
ij_php_subpackage_weight = 28
ij_php_ternary_operation_signs_on_next_line = false
ij_php_ternary_operation_wrap = off
ij_php_throws_weight = 7
ij_php_todo_weight = 28
ij_php_unknown_tag_weight = 28
ij_php_upper_case_boolean_const = false
ij_php_upper_case_null_const = false
ij_php_uses_weight = 28
ij_php_var_weight = 28
ij_php_variable_naming_style = mixed
ij_php_version_weight = 28
ij_php_while_brace_force = always
ij_php_while_on_new_line = false
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
indent_style = tab
ij_smart_tabs = true
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
@@ -460,44 +519,18 @@ ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_quote_style = none
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
ij_html_uniform_ident = false
[{*.yml,*.yaml}]
[{*.yaml,*.yml}]
indent_size = 2
ij_continuation_indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
[{*.zsh,*.sh,*.bash}]
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{.babelrc,.stylelintrc,.eslintrc,jest.config,*.json,*.jsb3,*.jsb2,*.bowerrc}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{phpunit.xml.dist,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.jhm,*.tld,*.fxml,*.wsdl,*.jrxml,*.xml,*.jnlp}]
indent_size = 2
indent_style = tab
tab_width = 2
ij_smart_tabs = true
ij_xml_block_comment_at_first_column = true
ij_xml_keep_indents_on_empty_lines = false
ij_xml_line_comment_at_first_column = true
ij_yaml_space_before_colon = true
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true

View File

@@ -1020,19 +1020,19 @@ class utils
throw new Exception("The path to php must not be empty. Please set a value for 'php_path' in your configuration file.");
}
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
$sParamFile = self::GetParamSourceFile('auth_user');
if (is_null($sParamFile))
{
if (!isset($aArguments['auth_user'])) {
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
$aArguments['auth_user'] = $sAuthUser;
}
if (!isset($aArguments['auth_pwd'])) {
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
$aArguments['auth_pwd'] = $sAuthPwd;
}
else
{
if (!isset($aArguments['param_file'])) {
$sParamFile = self::ReadParam('param_file', '', 'raw_data');
$aArguments['param_file'] = $sParamFile;
}
$aArgs = array();
foreach($aArguments as $sName => $value)
{

View File

@@ -188,7 +188,9 @@ class ActionEmail extends ActionNotification
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values"=>null, "sql"=>"test_recipient", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("from_label", array("allowed_values"=>null, "sql"=>"from_label", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", array("allowed_values"=>null, "sql"=>"reply_to_label", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
@@ -198,7 +200,7 @@ class ActionEmail extends ActionNotification
// Display lists
// - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list'));
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'from_label', 'reply_to', 'reply_to_label', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list'));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject'));
// Search criteria
@@ -371,10 +373,12 @@ class ActionEmail extends ActionNotification
$sTo = $this->FindRecipients('to', $aContextArgs);
$sCC = $this->FindRecipients('cc', $aContextArgs);
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
$sFromLabel = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
$sReplyToLabel = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
@@ -397,7 +401,7 @@ class ActionEmail extends ActionNotification
if (isset($sTo)) $oLog->Set('to', $sTo);
if (isset($sCC)) $oLog->Set('cc', $sCC);
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sFrom)) $oLog->Set('from', empty($sFromLabel) ? $sFrom : "$sFromLabel <$sFrom>");
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
}
@@ -417,15 +421,15 @@ class ActionEmail extends ActionNotification
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= empty($sFromLabel) ? "<li>From: $sFrom</li>\n": "<li>From: $sFromLabel &lt;$sFrom&gt;</li>\n";
$sTestBody .= empty($sReplyToLabel) ? "<li>Reply-To: $sReplyTo</li>\n": "<li>Reply-To: $sReplyToLabel &lt;$sReplyTo&gt;</li>\n";
$sTestBody .= "<li>References: $sReference</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody, 'text/html', $sStyles);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
@@ -436,8 +440,8 @@ class ActionEmail extends ActionNotification
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
$oEmail->SetRecipientReplyTo($sReplyTo, $sReplyToLabel);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}

View File

@@ -846,13 +846,17 @@ abstract class DBObject implements iDisplay
}
/**
* @see \DBObject::ListPreviousValuesForUpdatedAttributes() to get previous values anywhere in the CRUD stack
* @see https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Asequence_crud iTop CRUD stack documentation
*
* @param string $sAttCode
*
* @return mixed|null the value as it was before changed with {@see DBObject::Set()}.
* Returns null if the attribute wasn't changed.
* Values are reset during {@see DBObject::DBUpdate()}
*
* @see DBObject::$m_aOrigValues
* @throws CoreException if the attribute is unknown for the current object
* @uses DBObject::$m_aOrigValues
*/
public function GetOriginal($sAttCode)
{
@@ -2365,14 +2369,16 @@ abstract class DBObject implements iDisplay
return $aDelta;
}
/**
* @api
* @api-advanced
*
* @return array attname => currentvalue List the attributes that have been changed using {@see DBObject::Set()}. Reset during {@see DBObject::DBUpdate()}
* @uses m_aCurrValues
* @see \DBObject::ListPreviousValuesForUpdatedAttributes()
* @throws Exception
/**
* @api
* @api-advanced
*
* @see \DBObject::ListPreviousValuesForUpdatedAttributes() to get previous values anywhere in the CRUD stack
* @see https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Asequence_crud iTop CRUD stack documentation
* @return array attname => currentvalue List the attributes that have been changed using {@see DBObject::Set()}.
* Reset during {@see DBObject::DBUpdate()}
* @throws Exception
* @uses m_aCurrValues
*/
public function ListChanges()
{
@@ -2392,10 +2398,10 @@ abstract class DBObject implements iDisplay
*
* To get values that were set to the changed fields, simply use {@link \DBObject::Get()}
*
* @see \DBObject::ListChanges() old method, but using data that are reset during DBObject::DBUpdate
* @return array attname => value : value that was present before the last {@see DBObject::Set()} call.
* This array is set at the beginning of {@see DBObject::DBpdate()} using {@see DBObject::InitPreviousValuesForUpdatedAttributes()}.
* @uses m_aPreviousValuesForUpdatedAttributes
* @see \DBObject::ListChanges()
* @since 2.7.0 N°2293
*/
public function ListPreviousValuesForUpdatedAttributes()

View File

@@ -100,7 +100,7 @@ class EMail
}
if (array_key_exists('reply_to', $aData))
{
$oMessage->SetRecipientReplyTo($aData['reply_to']);
$oMessage->SetRecipientReplyTo($aData['reply_to']['address'], $aData['reply_to']['label']);
}
if (array_key_exists('to', $aData))
{
@@ -465,10 +465,14 @@ class EMail
}
}
public function SetRecipientReplyTo($sAddress)
public function SetRecipientReplyTo($sAddress, $sLabel = '')
{
$this->m_aData['reply_to'] = $sAddress;
if (!empty($sAddress))
$this->m_aData['reply_to'] = array('address' => $sAddress, 'label' => $sLabel);
if ($sLabel != '')
{
$this->m_oMessage->setReplyTo(array($sAddress => $sLabel));
}
else if (!empty($sAddress))
{
$this->m_oMessage->setReplyTo($sAddress);
}

View File

@@ -507,10 +507,14 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Adresát pro test',
'Class:ActionEmail/Attribute:test_recipient+' => 'Cílová adresa pro případ, kdy je stav nastaven na "Testování"',
'Class:ActionEmail/Attribute:from' => 'Odesílatel',
'Class:ActionEmail/Attribute:from+' => '',
'Class:ActionEmail/Attribute:reply_to' => 'Odpověď na',
'Class:ActionEmail/Attribute:reply_to+' => '',
'Class:ActionEmail/Attribute:from' => 'Odesílatel~~',
'Class:ActionEmail/Attribute:from+' => '~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Odpověď na~~',
'Class:ActionEmail/Attribute:reply_to+' => '~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'To',
'Class:ActionEmail/Attribute:to+' => 'Adresát',
'Class:ActionEmail/Attribute:cc' => 'Cc',

View File

@@ -505,10 +505,14 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Test modtager',
'Class:ActionEmail/Attribute:test_recipient+' => '',
'Class:ActionEmail/Attribute:from' => 'Fra',
'Class:ActionEmail/Attribute:from+' => 'Afsender af emailen',
'Class:ActionEmail/Attribute:reply_to' => 'Svar til',
'Class:ActionEmail/Attribute:reply_to+' => 'Svar sendes til',
'Class:ActionEmail/Attribute:from' => 'Fra~~',
'Class:ActionEmail/Attribute:from+' => 'Afsender af emailen~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Svar til~~',
'Class:ActionEmail/Attribute:reply_to+' => 'Svar sendes til~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'Til',
'Class:ActionEmail/Attribute:to+' => 'Modtager af emailen',
'Class:ActionEmail/Attribute:cc' => 'Cc',

View File

@@ -504,10 +504,14 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Testempfänger',
'Class:ActionEmail/Attribute:test_recipient+' => 'Empfänger im Fall eines "Test"-Status',
'Class:ActionEmail/Attribute:from' => 'Von',
'Class:ActionEmail/Attribute:from+' => 'Wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:reply_to' => 'Antworten an',
'Class:ActionEmail/Attribute:from' => 'Von (E-Mail)',
'Class:ActionEmail/Attribute:from+' => 'Absenderad­res­se wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:from_label' => 'Von (Label)',
'Class:ActionEmail/Attribute:from_label+' => 'Absendername wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:reply_to' => 'Antworten an (E-Mail)',
'Class:ActionEmail/Attribute:reply_to+' => 'Wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:reply_to_label' => 'Antworten an (Label)',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:to' => 'An',
'Class:ActionEmail/Attribute:to+' => 'Empfänger der Nachricht',
'Class:ActionEmail/Attribute:cc' => 'Kopie an',

View File

@@ -508,11 +508,15 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:ActionEmail' => 'Email notification',
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Test recipient',
'Class:ActionEmail/Attribute:test_recipient+' => 'Detination in case status is set to "Test"',
'Class:ActionEmail/Attribute:from' => 'From',
'Class:ActionEmail/Attribute:from+' => 'Will be sent into the email header',
'Class:ActionEmail/Attribute:reply_to' => 'Reply to',
'Class:ActionEmail/Attribute:reply_to+' => 'Will be sent into the email header',
'Class:ActionEmail/Attribute:test_recipient+' => 'Destination in case status is set to "Test"',
'Class:ActionEmail/Attribute:from' => 'From (email)',
'Class:ActionEmail/Attribute:from+' => 'Sender email address will be sent into the email header',
'Class:ActionEmail/Attribute:from_label' => 'From (label)',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header',
'Class:ActionEmail/Attribute:reply_to' => 'Reply to (email)',
'Class:ActionEmail/Attribute:reply_to+' => 'Reply to email address Will be sent into the email header',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header',
'Class:ActionEmail/Attribute:to' => 'To',
'Class:ActionEmail/Attribute:to+' => 'Destination of the email',
'Class:ActionEmail/Attribute:cc' => 'Cc',

View File

@@ -505,10 +505,14 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
'Class:ActionEmail+' => 'Notificación por Correo Electrónico',
'Class:ActionEmail/Attribute:test_recipient' => 'Destinatario de Prueba',
'Class:ActionEmail/Attribute:test_recipient+' => 'Destinatario en caso que el Estatus sea "En pruebas"',
'Class:ActionEmail/Attribute:from' => 'Remitente',
'Class:ActionEmail/Attribute:from+' => 'Será enviando en el encabezado del Correo Electrónico',
'Class:ActionEmail/Attribute:reply_to' => 'Responder a',
'Class:ActionEmail/Attribute:reply_to+' => 'Será enviando en el encabezado del Correo Electrónico',
'Class:ActionEmail/Attribute:from' => 'Remitente~~',
'Class:ActionEmail/Attribute:from+' => 'Será enviando en el encabezado del Correo Electrónico~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Responder a~~',
'Class:ActionEmail/Attribute:reply_to+' => 'Será enviando en el encabezado del Correo Electrónico~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'Para',
'Class:ActionEmail/Attribute:to+' => 'Destinatario del Correo Electrónico',
'Class:ActionEmail/Attribute:cc' => 'CC',

View File

@@ -503,10 +503,14 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Destinataire de test',
'Class:ActionEmail/Attribute:test_recipient+' => '',
'Class:ActionEmail/Attribute:from' => 'De',
'Class:ActionEmail/Attribute:from+' => '',
'Class:ActionEmail/Attribute:reply_to' => 'Répondre à',
'Class:ActionEmail/Attribute:reply_to+' => '',
'Class:ActionEmail/Attribute:from' => 'De~~',
'Class:ActionEmail/Attribute:from+' => '~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Répondre à~~',
'Class:ActionEmail/Attribute:reply_to+' => '~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'A',
'Class:ActionEmail/Attribute:to+' => '',
'Class:ActionEmail/Attribute:cc' => 'Copie',

View File

@@ -503,10 +503,14 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Teszt címzett',
'Class:ActionEmail/Attribute:test_recipient+' => '',
'Class:ActionEmail/Attribute:from' => 'Feladó',
'Class:ActionEmail/Attribute:from+' => '',
'Class:ActionEmail/Attribute:reply_to' => 'Válasz',
'Class:ActionEmail/Attribute:reply_to+' => '',
'Class:ActionEmail/Attribute:from' => 'Feladó~~',
'Class:ActionEmail/Attribute:from+' => '~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Válasz~~',
'Class:ActionEmail/Attribute:reply_to+' => '~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'Címzett',
'Class:ActionEmail/Attribute:to+' => '',
'Class:ActionEmail/Attribute:cc' => 'Másolatot kap',

View File

@@ -505,10 +505,14 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Test destinatario',
'Class:ActionEmail/Attribute:test_recipient+' => '',
'Class:ActionEmail/Attribute:from' => 'Da',
'Class:ActionEmail/Attribute:from+' => '',
'Class:ActionEmail/Attribute:reply_to' => 'Rispondi A',
'Class:ActionEmail/Attribute:reply_to+' => '',
'Class:ActionEmail/Attribute:from' => 'Da~~',
'Class:ActionEmail/Attribute:from+' => '~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Rispondi A~~',
'Class:ActionEmail/Attribute:reply_to+' => '~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'A',
'Class:ActionEmail/Attribute:to+' => 'Destinatario dell\'email',
'Class:ActionEmail/Attribute:cc' => 'Cc',

View File

@@ -503,10 +503,14 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'テストレシピ',
'Class:ActionEmail/Attribute:test_recipient+' => '状態がテストの場合の宛先',
'Class:ActionEmail/Attribute:from' => 'From',
'Class:ActionEmail/Attribute:from+' => '電子メールのヘッダーに挿入されます',
'Class:ActionEmail/Attribute:reply_to' => 'Reply to',
'Class:ActionEmail/Attribute:reply_to+' => '電子メールのヘッダーに挿入されます',
'Class:ActionEmail/Attribute:from' => 'From~~',
'Class:ActionEmail/Attribute:from+' => '電子メールのヘッダーに挿入されます~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Reply to~~',
'Class:ActionEmail/Attribute:reply_to+' => '電子メールのヘッダーに挿入されます~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'To',
'Class:ActionEmail/Attribute:to+' => 'メールの宛先',
'Class:ActionEmail/Attribute:cc' => 'Cc',

View File

@@ -511,10 +511,14 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Testontvanger',
'Class:ActionEmail/Attribute:test_recipient+' => 'Bestemming als de status op "Test" staat',
'Class:ActionEmail/Attribute:from' => 'Van',
'Class:ActionEmail/Attribute:from' => 'Van (e-mail)',
'Class:ActionEmail/Attribute:from+' => 'Wordt gebruikt in de hoofdtekst van de e-mail (headers)',
'Class:ActionEmail/Attribute:reply_to' => 'Antwoord',
'Class:ActionEmail/Attribute:from_label' => 'Van (label)',
'Class:ActionEmail/Attribute:from_label+' => 'Wordt gebruikt in de hoofdtekst van de e-mail (headers)',
'Class:ActionEmail/Attribute:reply_to' => 'Antwoord (e-mail)',
'Class:ActionEmail/Attribute:reply_to+' => 'Wordt gebruikt in de hoofdtekst van de e-mail (headers)',
'Class:ActionEmail/Attribute:reply_to_label' => 'Antwoord (label)',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Wordt gebruikt in de hoofdtekst van de e-mail (headers)',
'Class:ActionEmail/Attribute:to' => 'Aan',
'Class:ActionEmail/Attribute:to+' => 'Bestemming van de e-mail',
'Class:ActionEmail/Attribute:cc' => 'CC',

View File

@@ -505,10 +505,14 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Testar destinatário',
'Class:ActionEmail/Attribute:test_recipient+' => 'Destinatário em caso o estado está definido como "Teste"',
'Class:ActionEmail/Attribute:from' => 'De',
'Class:ActionEmail/Attribute:from+' => 'Será enviado para o cabeçalho de email',
'Class:ActionEmail/Attribute:reply_to' => 'Responder para',
'Class:ActionEmail/Attribute:reply_to+' => 'Será enviado para o cabeçalho de email',
'Class:ActionEmail/Attribute:from' => 'De~~',
'Class:ActionEmail/Attribute:from+' => 'Será enviado para o cabeçalho de email~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Responder para~~',
'Class:ActionEmail/Attribute:reply_to+' => 'Será enviado para o cabeçalho de email~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'Para',
'Class:ActionEmail/Attribute:to+' => 'Destinatário para o email',
'Class:ActionEmail/Attribute:cc' => 'CC',

View File

@@ -492,10 +492,14 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Тестовый получатель',
'Class:ActionEmail/Attribute:test_recipient+' => 'Получатель, если уведомление в статусе "Тест"',
'Class:ActionEmail/Attribute:from' => 'От',
'Class:ActionEmail/Attribute:from+' => 'Будет отправлено в заголовке email',
'Class:ActionEmail/Attribute:reply_to' => 'Ответить на',
'Class:ActionEmail/Attribute:reply_to+' => 'Будет отправлено в заголовке email',
'Class:ActionEmail/Attribute:from' => 'От~~',
'Class:ActionEmail/Attribute:from+' => 'Будет отправлено в заголовке email~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Ответить на~~',
'Class:ActionEmail/Attribute:reply_to+' => 'Будет отправлено в заголовке email~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'Кому',
'Class:ActionEmail/Attribute:to+' => 'Получатель email',
'Class:ActionEmail/Attribute:cc' => 'Копия',

View File

@@ -502,10 +502,14 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Testovací príjemca',
'Class:ActionEmail/Attribute:test_recipient+' => '',
'Class:ActionEmail/Attribute:from' => 'Od',
'Class:ActionEmail/Attribute:from+' => '',
'Class:ActionEmail/Attribute:reply_to' => 'Odpoveď na',
'Class:ActionEmail/Attribute:reply_to+' => '',
'Class:ActionEmail/Attribute:from' => 'Od~~',
'Class:ActionEmail/Attribute:from+' => '~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Odpoveď na~~',
'Class:ActionEmail/Attribute:reply_to+' => '~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'Komu',
'Class:ActionEmail/Attribute:to+' => '',
'Class:ActionEmail/Attribute:cc' => 'Kópia',

View File

@@ -513,10 +513,14 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Test alıcısı',
'Class:ActionEmail/Attribute:test_recipient+' => 'Durumu "Test" olması durumundaki alıcı',
'Class:ActionEmail/Attribute:from' => 'Kimden',
'Class:ActionEmail/Attribute:from+' => 'e-posta başlığında gönderilecek',
'Class:ActionEmail/Attribute:reply_to' => 'Yanıtla',
'Class:ActionEmail/Attribute:reply_to+' => 'e-posta başlığında gönderilecek',
'Class:ActionEmail/Attribute:from' => 'Kimden~~',
'Class:ActionEmail/Attribute:from+' => 'e-posta başlığında gönderilecek~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => 'Yanıtla~~',
'Class:ActionEmail/Attribute:reply_to+' => 'e-posta başlığında gönderilecek~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => 'Kime',
'Class:ActionEmail/Attribute:to+' => 'E-posta alıcısı',
'Class:ActionEmail/Attribute:cc' => 'Kopya',

View File

@@ -504,10 +504,14 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => '测试收件人',
'Class:ActionEmail/Attribute:test_recipient+' => 'Detination in case status is set to "Test"',
'Class:ActionEmail/Attribute:from' => '发件人',
'Class:ActionEmail/Attribute:from+' => 'Will be sent into the email header',
'Class:ActionEmail/Attribute:reply_to' => '回复到',
'Class:ActionEmail/Attribute:reply_to+' => 'Will be sent into the email header',
'Class:ActionEmail/Attribute:from' => '发件人~~',
'Class:ActionEmail/Attribute:from+' => 'Will be sent into the email header~~',
'Class:ActionEmail/Attribute:from_label' => 'From (label)~~',
'Class:ActionEmail/Attribute:from_label+' => 'Sender display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to' => '回复到~~',
'Class:ActionEmail/Attribute:reply_to+' => 'Will be sent into the email header~~',
'Class:ActionEmail/Attribute:reply_to_label' => 'Reply to (label)~~',
'Class:ActionEmail/Attribute:reply_to_label+' => 'Reply to display name will be sent into the email header~~',
'Class:ActionEmail/Attribute:to' => '收件人',
'Class:ActionEmail/Attribute:to+' => 'Destination of the email',
'Class:ActionEmail/Attribute:cc' => '抄送',

View File

@@ -231,6 +231,8 @@
css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
if (opts.onOverlayClick)
opts.overlayCSS.cursor = 'pointer';
if (opts.enableValidation)
opts.overlayCSS.cursor = 'not-allowed';
themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
msg = msg === undefined ? opts.message : msg;
@@ -292,7 +294,12 @@
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
}
else {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
if (opts.enableValidation) {
s = '<div class="blockUI blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
}
else{
s = '<div class="blockUI '+opts.blockMsgClass+' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
}
}
lyr3 = $(s);

View File

@@ -90,7 +90,7 @@ $(document).ready(function () {
/**
* Our custom handlers chould run only if clicking on somewhere without event already attached !
* Our custom handlers should run only if clicking on somewhere without event already attached !
* @param $eventTarget
* @returns {boolean} true if our custom handler shouldn't be run
*/
@@ -101,12 +101,18 @@ $(document).ready(function () {
if ($eventTarget.is("a, button")) {
return true;
}
if ($eventTarget.is(".fas, i.fa")) { // Font Awesome buttons
return true;
}
if ($eventTarget.parent().is('a, button')) {
return true;
}
if ($eventTarget.is("input, select, option")) {
return true;
}
if ($eventTarget.parent().is(".selectize-control,.selectize-input")) {
return true;
}
if ($eventTarget.is("img")) { // too hard to determine if an event handler is attached so excluding all !
return true;
}

View File

@@ -388,13 +388,12 @@ function ToggleField(value, field_id) {
*/
function BlockField(field_id, bBlocked) {
if (bBlocked) {
$('#'+field_id).block({message: ' ** disabled ** '});
$('#'+field_id).block({message: ' ** disabled ** ', enableValidation : true});
}
else {
$('#'+field_id).unblock();
}
}
/**
* Updates (enables/disables) a "duration" field
*/

View File

@@ -22,19 +22,18 @@
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CheckResult
{
class CheckResult {
// Severity levels
const ERROR = 0;
const WARNING = 1;
const INFO = 2;
const TRACE = 3; // for log purposes : replace old SetupLog::Log calls
public $iSeverity;
public $sLabel;
public $sDescription;
public function __construct($iSeverity, $sLabel, $sDescription = '')
{
public function __construct($iSeverity, $sLabel, $sDescription = '') {
$this->iSeverity = $iSeverity;
$this->sLabel = $sLabel;
$this->sDescription = $sDescription;
@@ -44,28 +43,29 @@ class CheckResult
* @return string
* @since 2.8.0 N°2214
*/
public function __toString()
{
public function __toString(): string {
$sPrintDesc = (empty($this->sDescription)) ? '' : " ({$this->sDescription})";
return "{$this->sLabel}$sPrintDesc";
}
/**
* @param \CheckResult[] $aResults
* @param string[] $aCheckResultSeverities list of CheckResult object severities to keep
*
* @return \CheckResult[] only elements that are error (iSeverity===ERROR)
* @return \CheckResult[] only elements that have one of the passed severity
*
* @since 2.8.0 N°2214
*/
public static function KeepOnlyErrors($aResults)
{
public static function FilterCheckResultArray(array $aResults, array $aCheckResultSeverities): array {
return array_filter($aResults,
static function ($v)
{
if ($v->iSeverity === CheckResult::ERROR) {
static function ($v) use ($aCheckResultSeverities) {
if (in_array($v->iSeverity, $aCheckResultSeverities, true)) {
return $v;
}
},
}
return false;
},
ARRAY_FILTER_USE_BOTH);
}
@@ -77,9 +77,8 @@ class CheckResult
*
* @since 2.8.0 N°2214
*/
public static function FromObjectsToStrings($aResults)
{
return array_map(function ($value) {
public static function FromObjectsToStrings(array $aResults): array {
return array_map(static function ($value) {
return $value->__toString();
}, $aResults);
}
@@ -117,16 +116,27 @@ class SetupUtils
* <li>...
* </ul>
*
* @internal SetupPage $oP The page used only for its 'log' method
* @return CheckResult[]
*
* @uses SetupPage $oP The page used only for its 'log' method
* @uses utils::IsModeCLI() to disable following checks :
* <ul>
* <li>php.ini option : file_uploads
* <li>Temp upload dir valid
* <li>php.ini option : upload_max_filesize
* <li>php.ini option : max_file_uploads
* <li>php.ini option : upload_max_filesize, post_max_size
* <li>php.ini option : session.save_handler
* </ul>
*
* @since 2.8.0 N°2214 disable some checks when in CLI mode
* @since 2.8.0 N°2214 replace SetupLog::Ok calls by CheckResult::TRACE
*/
public static function CheckPhpAndExtensions()
{
public static function CheckPhpAndExtensions() {
$aResult = array();
// For log file(s)
if (!is_dir(APPROOT.'log'))
{
if (!is_dir(APPROOT.'log')) {
@mkdir(APPROOT.'log');
}
@@ -220,74 +230,74 @@ class SetupUtils
{
$sPhpIniFile = php_ini_loaded_file();
// Other included/scanned files
if ($sFileList = php_ini_scanned_files())
{
if (strlen($sFileList) > 0)
{
if ($sFileList = php_ini_scanned_files()) {
if (strlen($sFileList) > 0) {
$aFiles = explode(',', $sFileList);
foreach ($aFiles as $sFile)
{
foreach ($aFiles as $sFile) {
$sPhpIniFile .= ', '.trim($sFile);
}
}
}
SetupLog::Ok("Info - php.ini file(s): '$sPhpIniFile'");
$aResult[] = new CheckResult(CheckResult::TRACE, "Info - php.ini file(s): '$sPhpIniFile'");
}
if (!ini_get('file_uploads'))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "Files upload is not allowed on this server (file_uploads = ".ini_get('file_uploads').").");
if (!utils::IsModeCLI() && !ini_get('file_uploads')) {
$aResult[] = new CheckResult(CheckResult::ERROR,
"Files upload is not allowed on this server (file_uploads = ".ini_get('file_uploads').").");
}
$sUploadTmpDir = self::GetUploadTmpDir();
if (empty($sUploadTmpDir))
{
$sUploadTmpDir = '/tmp';
$aResult[] = new CheckResult(CheckResult::WARNING, "Temporary directory for files upload is not defined (upload_tmp_dir), assuming that $sUploadTmpDir is used.");
}
// check that the upload directory is indeed writable from PHP
if (!empty($sUploadTmpDir))
{
if (!file_exists($sUploadTmpDir))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "Temporary directory for files upload ($sUploadTmpDir) does not exist or cannot be read by PHP.");
if (!utils::IsModeCLI()) {
$sUploadTmpDir = self::GetUploadTmpDir();
if (empty($sUploadTmpDir)) {
$sUploadTmpDir = '/tmp';
$aResult[] = new CheckResult(CheckResult::WARNING,
"Temporary directory for files upload is not defined (upload_tmp_dir), assuming that $sUploadTmpDir is used.");
}
else if (!is_writable($sUploadTmpDir))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "Temporary directory for files upload ($sUploadTmpDir) is not writable.");
}
else
{
SetupLog::Ok("Info - Temporary directory for files upload ($sUploadTmpDir) is writable.");
// check that the upload directory is indeed writable from PHP
if (!empty($sUploadTmpDir)) {
if (!file_exists($sUploadTmpDir)) {
$aResult[] = new CheckResult(CheckResult::ERROR,
"Temporary directory for files upload ($sUploadTmpDir) does not exist or cannot be read by PHP.");
}
else {
if (!is_writable($sUploadTmpDir)) {
$aResult[] = new CheckResult(CheckResult::ERROR,
"Temporary directory for files upload ($sUploadTmpDir) is not writable.");
}
else {
$aResult[] = new CheckResult(CheckResult::TRACE,
"Info - Temporary directory for files upload ($sUploadTmpDir) is writable.");
}
}
}
}
if (!ini_get('upload_max_filesize'))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "File upload is not allowed on this server (upload_max_filesize = ".ini_get('upload_max_filesize').").");
if (!utils::IsModeCLI() && !ini_get('upload_max_filesize')) {
$aResult[] = new CheckResult(CheckResult::ERROR,
"File upload is not allowed on this server (upload_max_filesize = ".ini_get('upload_max_filesize').").");
}
$iMaxFileUploads = ini_get('max_file_uploads');
if (!empty($iMaxFileUploads) && ($iMaxFileUploads < 1))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "File upload is not allowed on this server (max_file_uploads = ".ini_get('max_file_uploads').").");
if (!utils::IsModeCLI() && !empty($iMaxFileUploads) && ($iMaxFileUploads < 1)) {
$aResult[] = new CheckResult(CheckResult::ERROR,
"File upload is not allowed on this server (max_file_uploads = ".ini_get('max_file_uploads').").");
}
$iMaxUploadSize = utils::ConvertToBytes(ini_get('upload_max_filesize'));
$iMaxPostSize = utils::ConvertToBytes(ini_get('post_max_size'));
if (!utils::IsModeCLI()) {
$iMaxUploadSize = utils::ConvertToBytes(ini_get('upload_max_filesize'));
$iMaxPostSize = utils::ConvertToBytes(ini_get('post_max_size'));
if ($iMaxPostSize <= $iMaxUploadSize)
{
$aResult[] = new CheckResult(CheckResult::WARNING, "post_max_size (".ini_get('post_max_size').") in php.ini should be strictly greater than upload_max_filesize (".ini_get('upload_max_filesize').") otherwise you cannot upload files of the maximum size.");
if ($iMaxPostSize <= $iMaxUploadSize) {
$aResult[] = new CheckResult(CheckResult::WARNING,
"post_max_size (".ini_get('post_max_size').") in php.ini should be strictly greater than upload_max_filesize (".ini_get('upload_max_filesize').") otherwise you cannot upload files of the maximum size.");
}
$aResult[] = new CheckResult(CheckResult::TRACE, "Info - upload_max_filesize: ".ini_get('upload_max_filesize'));
$aResult[] = new CheckResult(CheckResult::TRACE, "Info - post_max_size: ".ini_get('post_max_size'));
$aResult[] = new CheckResult(CheckResult::TRACE, "Info - max_file_uploads: ".ini_get('max_file_uploads'));
}
SetupLog::Ok("Info - upload_max_filesize: ".ini_get('upload_max_filesize'));
SetupLog::Ok("Info - post_max_size: ".ini_get('post_max_size'));
SetupLog::Ok("Info - max_file_uploads: ".ini_get('max_file_uploads'));
// Check some more ini settings here, needed for file upload
$sMemoryLimit = trim(ini_get('memory_limit'));
if (empty($sMemoryLimit))
@@ -302,13 +312,12 @@ class SetupUtils
// Check that the limit will allow us to load the data
//
$iMemoryLimit = utils::ConvertToBytes($sMemoryLimit);
if (!utils::IsMemoryLimitOk($iMemoryLimit, self::MIN_MEMORY_LIMIT))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "memory_limit ($iMemoryLimit) is too small, the minimum value to run the application is ".self::MIN_MEMORY_LIMIT.".");
if (!utils::IsMemoryLimitOk($iMemoryLimit, self::MIN_MEMORY_LIMIT)) {
$aResult[] = new CheckResult(CheckResult::ERROR,
"memory_limit ($iMemoryLimit) is too small, the minimum value to run the application is ".self::MIN_MEMORY_LIMIT.".");
}
else
{
SetupLog::Ok("Info - memory_limit is $iMemoryLimit, ok.");
else {
$aResult[] = new CheckResult(CheckResult::TRACE, "Info - memory_limit is $iMemoryLimit, ok.");
}
}
@@ -326,13 +335,12 @@ class SetupUtils
$aOk[] = "Suhosin extension detected (version $sSuhosinVersion).";
$iGetMaxValueLength = ini_get('suhosin.get.max_value_length');
if ($iGetMaxValueLength < self::SUHOSIN_GET_MAX_VALUE_LENGTH)
{
$aResult[] = new CheckResult(CheckResult::WARNING, "suhosin.get.max_value_length ($iGetMaxValueLength) is too small, the minimum value recommended to run the application is ".self::SUHOSIN_GET_MAX_VALUE_LENGTH.".");
if ($iGetMaxValueLength < self::SUHOSIN_GET_MAX_VALUE_LENGTH) {
$aResult[] = new CheckResult(CheckResult::WARNING,
"suhosin.get.max_value_length ($iGetMaxValueLength) is too small, the minimum value recommended to run the application is ".self::SUHOSIN_GET_MAX_VALUE_LENGTH.".");
}
else
{
SetupLog::Ok("Info - suhosin.get.max_value_length = $iGetMaxValueLength, ok.");
else {
$aResult[] = new CheckResult(CheckResult::TRACE, "Info - suhosin.get.max_value_length = $iGetMaxValueLength, ok.");
}
}
@@ -340,79 +348,80 @@ class SetupUtils
{
$sPhpIniFile = php_ini_loaded_file();
// Other included/scanned files
if ($sFileList = php_ini_scanned_files())
{
if (strlen($sFileList) > 0)
{
if ($sFileList = php_ini_scanned_files()) {
if (strlen($sFileList) > 0) {
$aFiles = explode(',', $sFileList);
foreach ($aFiles as $sFile)
{
foreach ($aFiles as $sFile) {
$sPhpIniFile .= ', '.trim($sFile);
}
}
}
$aResult[] = new CheckResult(CheckResult::INFO, "Loaded php.ini files: $sPhpIniFile");
$aResult[] = new CheckResult(CheckResult::INFO, "Loaded php.ini files: $sPhpIniFile");
}
// Check the configuration of the sessions persistence, since this is critical for the authentication
if (ini_get('session.save_handler') == 'files')
{
$sSavePath = ini_get('session.save_path');
SetupLog::Ok("Info - session.save_path is: '$sSavePath'.");
if (!utils::IsModeCLI()) {
if (ini_get('session.save_handler') == 'files') {
$sSavePath = ini_get('session.save_path');
$aResult[] = new CheckResult(CheckResult::TRACE, "Info - session.save_path is: '$sSavePath'.");
// According to the PHP documentation, the format can be /path/where/to_save_sessions or "N;/path/where/to_save_sessions" or "N;MODE;/path/where/to_save_sessions"
$sSavePath = ltrim(rtrim($sSavePath, '"'), '"'); // remove surrounding quotes (if any)
// According to the PHP documentation, the format can be /path/where/to_save_sessions or "N;/path/where/to_save_sessions" or "N;MODE;/path/where/to_save_sessions"
$sSavePath = ltrim(rtrim($sSavePath, '"'), '"'); // remove surrounding quotes (if any)
if (!empty($sSavePath))
{
if (($iPos = strrpos($sSavePath, ';', 0)) !== false)
{
// The actual path is after the last semicolon
$sSavePath = substr($sSavePath, $iPos+1);
if (!empty($sSavePath)) {
if (($iPos = strrpos($sSavePath, ';', 0)) !== false) {
// The actual path is after the last semicolon
$sSavePath = substr($sSavePath, $iPos + 1);
}
if (!is_writable($sSavePath)) {
$aResult[] = new CheckResult(CheckResult::ERROR,
"The value for session.save_path ($sSavePath) is not writable for the web server. Make sure that PHP can actually save session variables. (Refer to the PHP documentation: http://php.net/manual/en/session.configuration.php#ini.session.save-path)");
}
else {
$aResult[] = new CheckResult(CheckResult::INFO,
"The value for session.save_path ($sSavePath) is writable for the web server.");
}
}
if (!is_writable($sSavePath))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "The value for session.save_path ($sSavePath) is not writable for the web server. Make sure that PHP can actually save session variables. (Refer to the PHP documentation: http://php.net/manual/en/session.configuration.php#ini.session.save-path)");
}
else
{
$aResult[] = new CheckResult(CheckResult::INFO, "The value for session.save_path ($sSavePath) is writable for the web server.");
else {
$aResult[] = new CheckResult(CheckResult::WARNING,
"Empty path for session.save_path. Make sure that PHP can actually save session variables. (Refer to the PHP documentation: http://php.net/manual/en/session.configuration.php#ini.session.save-path)");
}
}
else
{
$aResult[] = new CheckResult(CheckResult::WARNING, "Empty path for session.save_path. Make sure that PHP can actually save session variables. (Refer to the PHP documentation: http://php.net/manual/en/session.configuration.php#ini.session.save-path)");
else {
$aResult[] = new CheckResult(CheckResult::INFO,
"session.save_handler is: '".ini_get('session.save_handler')."' (different from 'files').");
}
}
else
{
$aResult[] = new CheckResult(CheckResult::INFO, "session.save_handler is: '".ini_get('session.save_handler')."' (different from 'files').");
}
return $aResult;
}
/**
* Call the platform checks. If those checks return CheckResult::ERROR, then output and log them, then exit. Otherwise just return.
*
* @param \CLIPage $oCliPage
* @param int $iExitCode
*
* @since 2.8.0 N°2214
* @uses CheckPhpAndExtensions
* @uses \CheckResult::FilterCheckResultArray()
* @uses \CLIPage::output()
* @uses \IssueLog::Error()
* @uses \exit()
*
* @since 2.8.0 N°2214 Add PHP version checks in CLI scripts
*/
public static function CheckPhpAndExtensionsForCli($oCliPage, $iExitCode = -1)
{
public static function CheckPhpAndExtensionsForCli($oCliPage, $iExitCode = -1) {
$aPhpCheckResults = self::CheckPhpAndExtensions();
$aPhpCheckErrors = CheckResult::KeepOnlyErrors($aPhpCheckResults);
if (empty($aPhpCheckErrors))
{
$aPhpCheckErrors = CheckResult::FilterCheckResultArray($aPhpCheckResults, [CheckResult::ERROR]);
if (empty($aPhpCheckErrors)) {
return;
}
$sMessageTitle = 'Error: PHP minimum requirements are not met !';
$oCliPage->p($sMessageTitle);
$aPhpCheckErrorsForPrint = CheckResult::FromObjectsToStrings($aPhpCheckErrors);
foreach ($aPhpCheckErrorsForPrint as $sError)
{
foreach ($aPhpCheckErrorsForPrint as $sError) {
$oCliPage->p(' * '.$sError);
}
$oCliPage->output();
@@ -426,23 +435,21 @@ class SetupUtils
/**
* @param CheckResult[] $aResult checks log
*
* @since 2.8.0 N°2214 replace SetupLog::Log calls by CheckResult::TRACE
*/
private static function CheckPhpVersion(&$aResult)
{
SetupLog::Ok('Info - CheckPHPVersion');
private static function CheckPhpVersion(array &$aResult) {
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - CheckPHPVersion');
$sPhpVersion = phpversion();
if (version_compare($sPhpVersion, self::PHP_MIN_VERSION, '>='))
{
if (version_compare($sPhpVersion, self::PHP_MIN_VERSION, '>=')) {
$aResult[] = new CheckResult(CheckResult::INFO,
"The current PHP Version (".$sPhpVersion.") is greater than the minimum version required to run ".ITOP_APPLICATION.", which is (".self::PHP_MIN_VERSION.")");
$sPhpNextMinVersion = self::PHP_NEXT_MIN_VERSION; // mandatory before PHP 5.5 (arbitrary expressions), keeping compat because we're in the setup !
if (!empty($sPhpNextMinVersion))
{
if (version_compare($sPhpVersion, self::PHP_NEXT_MIN_VERSION, '>='))
{
if (!empty($sPhpNextMinVersion)) {
if (version_compare($sPhpVersion, self::PHP_NEXT_MIN_VERSION, '>=')) {
$aResult[] = new CheckResult(CheckResult::INFO,
"The current PHP Version (".$sPhpVersion.") is greater than the minimum version required to run next ".ITOP_APPLICATION." release, which is (".self::PHP_NEXT_MIN_VERSION.")");
}
@@ -468,30 +475,28 @@ class SetupUtils
/**
* Check that the selected modules meet their dependencies
*
* @param $sSourceDir
* @param $sExtensionDir
* @param $aSelectedModules
*
* @return array
*
* @since 2.8.0 N°2214 replace SetupLog::Log calls by CheckResult::TRACE
*/
public static function CheckSelectedModules($sSourceDir, $sExtensionDir, $aSelectedModules)
{
public static function CheckSelectedModules($sSourceDir, $sExtensionDir, $aSelectedModules) {
$aResult = array();
SetupLog::Ok('Info - CheckSelectedModules');
$aDirsToScan = array(APPROOT.$sSourceDir);
$sExtensionsPath = APPROOT.$sExtensionDir;
if (is_dir($sExtensionsPath))
{
if (is_dir($sExtensionsPath)) {
// if the extensions dir exists, scan it for additional modules as well
$aDirsToScan[] = $sExtensionsPath;
}
require_once(APPROOT.'setup/modulediscovery.class.inc.php');
try
{
try {
ModuleDiscovery::GetAvailableModules($aDirsToScan, true, $aSelectedModules);
}
catch(Exception $e)
{
} catch (Exception $e) {
$aResult[] = new CheckResult(CheckResult::ERROR, $e->getMessage());
}
return $aResult;
@@ -499,25 +504,25 @@ class SetupUtils
/**
* Check that the backup could be executed
*
* @param $sDBBackupPath
* @param $sMySQLBinDir
* @return array An array of CheckResults objects
* @internal param Page $oP The page used only for its 'log' method
*
* @return \CheckResult[] An array of CheckResults objects
*
* @since 2.8.0 N°2214 replace SetupLog::Log calls by CheckResult::TRACE
*/
public static function CheckBackupPrerequisites($sDBBackupPath, $sMySQLBinDir = null)
{
public static function CheckBackupPrerequisites($sDBBackupPath, $sMySQLBinDir = null) {
$aResult = array();
SetupLog::Ok('Info - CheckBackupPrerequisites');
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - CheckBackupPrerequisites');
// zip extension
//
if (!extension_loaded('phar'))
{
if (!extension_loaded('phar')) {
$sMissingExtensionLink = "<a href=\"http://www.php.net/manual/en/book.phar.php\" target=\"_blank\">zip</a>";
$aResult[] = new CheckResult(CheckResult::ERROR, "Missing PHP extension: phar", $sMissingExtensionLink);
}
if (!extension_loaded('zlib'))
{
if (!extension_loaded('zlib')) {
$sMissingExtensionLink = "<a href=\"http://www.php.net/manual/en/book.zlib.php\" target=\"_blank\">zip</a>";
$aResult[] = new CheckResult(CheckResult::ERROR, "Missing PHP extension: zlib", $sMissingExtensionLink);
}
@@ -525,25 +530,21 @@ class SetupUtils
// availability of exec()
//
$aDisabled = explode(', ', ini_get('disable_functions'));
SetupLog::Ok('Info - PHP functions disabled: '.implode(', ', $aDisabled));
if (in_array('exec', $aDisabled))
{
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - PHP functions disabled: '.implode(', ', $aDisabled));
if (in_array('exec', $aDisabled)) {
$aResult[] = new CheckResult(CheckResult::ERROR, "The PHP exec() function has been disabled on this server");
}
// availability of mysqldump
if (empty($sMySQLBinDir) && null != MetaModel::GetConfig())
{
if (empty($sMySQLBinDir) && null != MetaModel::GetConfig()) {
$sMySQLBinDir = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', '');
}
if (empty($sMySQLBinDir))
{
if (empty($sMySQLBinDir)) {
$sMySQLDump = 'mysqldump';
}
else
{
SetupLog::Ok('Info - Found mysql_bindir: '.$sMySQLBinDir);
else {
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - Found mysql_bindir: '.$sMySQLBinDir);
$sMySQLDump = '"'.$sMySQLBinDir.'/mysqldump"';
}
$sCommand = "$sMySQLDump -V 2>&1";
@@ -555,27 +556,25 @@ class SetupUtils
{
$aResult[] = new CheckResult(CheckResult::INFO, "mysqldump is present: Ok.");
}
elseif ($iRetCode == 1)
{
elseif ($iRetCode == 1) {
// Unfortunately $aOutput is not really usable since we don't know its encoding (character set)
$aResult[] = new CheckResult(CheckResult::ERROR, "mysqldump could not be found. Please make sure it is installed and in the path.");
$aResult[] = new CheckResult(CheckResult::ERROR,
"mysqldump could not be found. Please make sure it is installed and in the path.");
}
else
{
else {
// Unfortunately $aOutput is not really usable since we don't know its encoding (character set)
$aResult[] = new CheckResult(CheckResult::ERROR, "mysqldump could not be executed (retcode=$iRetCode): Please make sure it is installed and " . (empty($sMySQLBinDir) ? "in the path" : "located at : $sMySQLDump"));
$aResult[] = new CheckResult(CheckResult::ERROR,
"mysqldump could not be executed (retcode=$iRetCode): Please make sure it is installed and ".(empty($sMySQLBinDir) ? "in the path" : "located at : $sMySQLDump"));
}
foreach($aOutput as $sLine)
{
SetupLog::Ok('Info - mysqldump -V said: '.$sLine);
foreach ($aOutput as $sLine) {
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - mysqldump -V said: '.$sLine);
}
// create and test destination location
//
$sDestDir = dirname($sDBBackupPath);
setuputils::builddir($sDestDir);
if (!is_dir($sDestDir))
{
if (!is_dir($sDestDir)) {
$aResult[] = new CheckResult(CheckResult::ERROR, "$sDestDir does not exist and could not be created.");
}
@@ -590,27 +589,29 @@ class SetupUtils
/**
* Check that graphviz can be launched
* @param $sGraphvizPath
* @return CheckResult The result of the check
* @internal param string $GraphvizPath The path where graphviz' dot program is installed
*
* @param string $sGraphvizPath The path where graphviz' dot program is installed
*
* @return CheckResult[] The result of the check AS CheckResult::INFO or CheckResult::WARNING, plus debug traces as some
* CheckResult::TRACE
*
* @since 2.8.0 N°2214 replace SetupLog::Log calls by CheckResult::TRACE
*/
public static function CheckGraphviz($sGraphvizPath)
{
$oResult = null;
SetupLog::Ok('Info - CheckGraphviz');
public static function CheckGraphviz($sGraphvizPath) {
$aResult = [];
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - CheckGraphviz');
// availability of exec()
//
$aDisabled = explode(', ', ini_get('disable_functions'));
SetupLog::Ok('Info - PHP functions disabled: '.implode(', ', $aDisabled));
if (in_array('exec', $aDisabled))
{
$aResult[] = new CheckResult(CheckResult::ERROR, "The PHP exec() function has been disabled on this server");
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - PHP functions disabled: '.implode(', ', $aDisabled));
if (in_array('exec', $aDisabled)) {
$aResult[] = new CheckResult(CheckResult::ERROR,
self::GetStringForJsonEncode('The PHP exec() function has been disabled on this server', 'Could not find Graphviz\' dot'));
}
// availability of dot / dot.exe
if (empty($sGraphvizPath))
{
if (empty($sGraphvizPath)) {
$sGraphvizPath = 'dot';
}
$sCommand = "\"$sGraphvizPath\" -V 2>&1";
@@ -618,47 +619,69 @@ class SetupUtils
$aOutput = array();
$iRetCode = 0;
exec($sCommand, $aOutput, $iRetCode);
if ($iRetCode == 0)
{
$oResult = new CheckResult(CheckResult::INFO, "dot is present: ".$aOutput[0]);
}
elseif ($iRetCode == 1)
{
$oResult = new CheckResult(CheckResult::WARNING, "dot could not be found: ".implode(' ', $aOutput)." - Please make sure it is installed and in the path.");
}
else
{
$oResult = new CheckResult(CheckResult::WARNING, "dot could not be executed (retcode=$iRetCode): Please make sure it is installed and in the path");
}
foreach($aOutput as $sLine)
{
SetupLog::Ok('Info - '.$sGraphvizPath.' -V said: '.$sLine);
if ($iRetCode == 0) {
$aResult[] = new CheckResult(CheckResult::INFO,
self::GetStringForJsonEncode("dot is present: ".$aOutput[0], 'Graphviz\' dot found'));
} elseif ($iRetCode == 1) {
$aResult[] = new CheckResult(CheckResult::WARNING,
self::GetStringForJsonEncode(
"dot could not be found: ".implode(' ', $aOutput)." - Please make sure it is installed and in the path.",
'Could not find Graphviz\' dot'
)
);
} else {
$aResult[] = new CheckResult(CheckResult::WARNING,
self::GetStringForJsonEncode(
"dot could not be executed (retcode=$iRetCode): Please make sure it is installed and in the path",
'Could not find Graphviz\' dot'
)
);
}
return $oResult;
foreach ($aOutput as $sLine) {
$aResult[] = new CheckResult(CheckResult::TRACE, 'Info - '.$sGraphvizPath.' -V said: '.$sLine);
}
return $aResult;
}
/**
* This was introduced as on Windows certain messages are not returned correctly :(
*
* @param string $sValue
* @param string $sFallbackValue
*
* @return string
*
* @since 2.8.0
*/
private static function GetStringForJsonEncode(string $sValue, string $sFallbackValue): string {
return (json_encode($sValue) !== false)
? $sValue
: $sFallbackValue;
}
/**
* Helper function to retrieve the system's temporary directory
* Emulates sys_get_temp_dir if needed (PHP < 5.2.1)
*
* @return string Path to the system's temp directory
*/
public static function GetTmpDir()
{
public static function GetTmpDir() {
return realpath(sys_get_temp_dir());
}
/**
* Helper function to retrieve the directory where files are to be uploaded
*
* @return string Path to the temp directory used for uploading files
*/
public static function GetUploadTmpDir()
{
public static function GetUploadTmpDir() {
$sPath = ini_get('upload_tmp_dir');
if (empty($sPath))
{
if (empty($sPath)) {
$sPath = self::GetTmpDir();
}
return $sPath;
}
@@ -679,30 +702,25 @@ class SetupUtils
/**
* Helper to recursively cleanup a directory
*
* @param $dir
*
* @throws Exception
*/
public static function tidydir($dir)
{
if ((strlen(trim($dir)) == 0) || ($dir == '/') || ($dir == '\\'))
{
public static function tidydir(string $dir): void {
if ((strlen(trim($dir)) == 0) || ($dir == '/') || ($dir == '\\')) {
throw new Exception("Attempting to delete directory: '$dir'");
}
$aFiles = scandir($dir); // Warning glob('.*') does not seem to return the broken symbolic links, thus leaving a non-empty directory
if ($aFiles !== false)
{
foreach($aFiles as $file)
{
if (($file != '.') && ($file != '..'))
{
if(is_dir($dir.'/'.$file))
{
if ($aFiles !== false) {
foreach ($aFiles as $file) {
if (($file != '.') && ($file != '..')) {
if (is_dir($dir.'/'.$file)) {
self::tidydir($dir.'/'.$file);
self::rmdir_safe($dir.'/'.$file);
}
else
{
else {
if (!unlink($dir.'/'.$file))
{
SetupLog::Ok("Warning - FAILED to remove file '$dir/$file'");
@@ -2076,28 +2094,28 @@ JS
*
* @throws \SecurityException
*/
public final static function CheckSetupToken($bRemoveToken = false)
{
public final static function CheckSetupToken($bRemoveToken = false) {
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
$sTokenFile = APPROOT.'data/setup/authent';
if (!file_exists($sTokenFile) || $sAuthent !== file_get_contents($sTokenFile))
{
if (!file_exists($sTokenFile) || $sAuthent !== file_get_contents($sTokenFile)) {
throw new SecurityException('Setup operations are not allowed outside of the setup');
}
if ($bRemoveToken)
{
if ($bRemoveToken) {
@unlink($sTokenFile);
}
}
private final static function Log($sText)
{
if (class_exists('SetupPage'))
{
/**
* @param string $sText
*
* @since 2.7.0 N°2240 Maintenance mode
* @since 2.8.0 N°2522 uses SetupLog instead of SetupPage (but still uses SetupPage for setup/console detection)
*/
private static function Log($sText) {
if (class_exists('SetupPage')) {
SetupLog::Ok($sText);
}
else
{
else {
IssueLog::Info($sText);
}
}
@@ -2105,8 +2123,7 @@ JS
/**
* @return string[]
*/
public static function GetPHPMandatoryExtensions(): array
{
public static function GetPHPMandatoryExtensions() {
return [
'mysqli',
'iconv',
@@ -2128,14 +2145,13 @@ JS
/**
* @return array
*/
public static function GetPHPOptionalExtensions(): array
{
public static function GetPHPOptionalExtensions() {
$aOptionalExtensions = [
'mcrypt, sodium or openssl' => [
'mcrypt' => 'Strong encryption will not be used.',
'sodium' => 'Strong encryption will not be used.',
'openssl' => 'Strong encryption will not be used.',
],
'mcrypt' => 'Strong encryption will not be used.',
'sodium' => 'Strong encryption will not be used.',
'openssl' => 'Strong encryption will not be used.',
],
'ldap' => 'LDAP authentication will be disabled.',
'mbstring' => 'For CryptEngine implementations, trace in Mail to ticket automation', // N°2891
];

View File

@@ -106,17 +106,21 @@ EOF
switch($oCheckResult->iSeverity)
{
case CheckResult::ERROR:
$aErrors[] = $oCheckResult->sLabel;
$this->bCanMoveForward = false;
break;
$aErrors[] = $oCheckResult->sLabel;
$this->bCanMoveForward = false;
break;
case CheckResult::WARNING:
$aWarnings[] = $oCheckResult->sLabel;
break;
$aWarnings[] = $oCheckResult->sLabel;
break;
case CheckResult::INFO:
$aInfo[] = $oCheckResult->sLabel;
break;
$aInfo[] = $oCheckResult->sLabel;
break;
case CheckResult::TRACE:
SetupLog::Ok($oCheckResult->sLabel);
break;
}
}
$sStyle = 'style="display:none;max-height:196px;overflow:auto;"';
@@ -287,16 +291,18 @@ HTML
$aBackupChecks = SetupUtils::CheckBackupPrerequisites($sDBBackupPath, $sMySQLBinDir);
$bCanBackup = true;
$sMySQLDumpMessage = '';
foreach($aBackupChecks as $oCheck)
{
if ($oCheck->iSeverity == CheckResult::ERROR)
{
$bCanBackup = false;
$sMySQLDumpMessage .= '<div class="message message-error"><span class="message-title">Error:</span>'.$oCheck->sLabel.'</div>';
}
else
{
$sMySQLDumpMessage .= '<div class="message message-valid"><span class="message-title">Success:</span>'.$oCheck->sLabel.'</div>';
foreach ($aBackupChecks as $oCheck) {
switch ($oCheck->iSeverity) {
case CheckResult::ERROR:
$bCanBackup = false;
$sMySQLDumpMessage .= '<div class="message message-error"><span class="message-title">Error:</span>'.$oCheck->sLabel.'</div>';
break;
case CheckResult::TRACE:
SetupLog::Ok($oCheck->sLabel);
break;
default:
$sMySQLDumpMessage .= '<div class="message message-valid"><span class="message-title">Success:</span>'.$oCheck->sLabel.'</div>';
break;
}
}
$sChecked = ($bCanBackup && $bDBBackup) ? ' checked ' : '';
@@ -1033,38 +1039,48 @@ EOF
);
}
public function AsyncAction(WebPage $oPage, $sCode, $aParameters)
{
switch($sCode)
{
public function AsyncAction(WebPage $oPage, $sCode, $aParameters) {
switch ($sCode) {
case 'check_graphviz':
$sGraphvizPath = $aParameters['graphviz_path'];
$oCheck = SetupUtils::CheckGraphviz($sGraphvizPath);
$sMessage = json_encode($oCheck->sLabel);
switch($oCheck->iSeverity)
{
case CheckResult::INFO:
$sStatus = 'ok';
$sInfoExplanation = (json_encode($oCheck->sLabel) !== false) ? $oCheck->sLabel : 'Graphviz\' dot found';
$sMessage = json_encode('<div class="message message-valid">'.$sInfoExplanation.'</div>');
$sGraphvizPath = $aParameters['graphviz_path'];
$aCheck = SetupUtils::CheckGraphviz($sGraphvizPath);
break;
// N°2214 logging TRACE results
$aTraceCheck = CheckResult::FilterCheckResultArray($aCheck, [CheckResult::TRACE]);
foreach ($aTraceCheck as $oTraceCheck) {
SetupLog::Ok($oTraceCheck->sLabel);
}
default:
case CheckResult::ERROR:
case CheckResult::WARNING:
$sStatus = 'ko';
$sErrorExplanation = (json_encode($oCheck->sLabel) !== false) ? $oCheck->sLabel : 'Could not find Graphviz\' dot';
$sMessage = json_encode('<div class="message message-error">'.$sErrorExplanation.'</div>');
$aNonTraceCheck = array_diff($aCheck, $aTraceCheck);
foreach ($aNonTraceCheck as $oCheck) {
switch ($oCheck->iSeverity) {
case CheckResult::INFO:
$sStatus = 'ok';
$sInfoExplanation = $oCheck->sLabel;
$sMessage = json_encode('<div class="message message-valid">'.$sInfoExplanation.'</div>');
}
$oPage->add_ready_script(
<<<EOF
break;
default:
case CheckResult::ERROR:
case CheckResult::WARNING:
$sStatus = 'ko';
$sErrorExplanation = $oCheck->sLabel;
$sMessage = json_encode('<div class="message message-error">'.$sErrorExplanation.'</div>');
break;
}
if ($oCheck->iSeverity !== CheckResult::TRACE) {
$oPage->add_ready_script(
<<<JS
$("#graphviz_status").html($sMessage);
$('#btn_next').attr('data-graphviz', '$sStatus');
EOF
);
break;
JS
);
}
}
break;
}
}
@@ -1167,32 +1183,39 @@ EOF
switch($sCode)
{
case 'check_graphviz':
$sGraphvizPath = $aParameters['graphviz_path'];
$oCheck = SetupUtils::CheckGraphviz($sGraphvizPath);
$sMessage = json_encode($oCheck->sLabel);
switch($oCheck->iSeverity)
{
case CheckResult::INFO:
$sStatus = 'ok';
$sInfoExplanation = (json_encode($oCheck->sLabel) !== false) ? $oCheck->sLabel : 'Graphviz\' dot found';
$sMessage = json_encode('<div class="message message-valid">'.$sInfoExplanation.'</div>');
$sGraphvizPath = $aParameters['graphviz_path'];
$aCheck = SetupUtils::CheckGraphviz($sGraphvizPath);
break;
// N°2214 logging TRACE results
$aTraceCheck = CheckResult::FilterCheckResultArray($aCheck, [CheckResult::TRACE]);
foreach ($aTraceCheck as $oTraceCheck) {
SetupLog::Ok($oTraceCheck->sLabel);
}
default:
case CheckResult::ERROR:
case CheckResult::WARNING:
$sStatus = 'ko';
$sErrorExplanation = (json_encode($oCheck->sLabel) !== false) ? $oCheck->sLabel : 'Could not find Graphviz\' dot';
$sMessage = json_encode('<div class="message message-error">'.$sErrorExplanation.'</div>');
$aNonTraceCheck = array_diff($aCheck, $aTraceCheck);
foreach ($aNonTraceCheck as $oCheck) {
switch ($oCheck->iSeverity) {
case CheckResult::INFO:
$sStatus = 'ok';
$sInfoExplanation = $oCheck->sLabel;
$sMessage = json_encode('<div class="message message-valid">'.$sInfoExplanation.'</div>');
break;
}
$oPage->add_ready_script(
<<<EOF
default:
case CheckResult::ERROR:
case CheckResult::WARNING:
$sStatus = 'ko';
$sErrorExplanation = $oCheck->sLabel;
$sMessage = json_encode('<div class="message message-error">'.$sErrorExplanation.'</div>');
break;
}
$oPage->add_ready_script(
<<<JS
$("#graphviz_status").html($sMessage);
$('#btn_next').attr('data-graphviz', '$sStatus');
EOF
);
JS
);
}
break;
}
}

View File

@@ -42,7 +42,7 @@ function UsageAndExit($oP)
if ($bModeCLI)
{
$oP->p("USAGE:\n");
$oP->p("php -q synchro_exec.php --auth_user=<login> --auth_pwd=<password> --data_sources=<comma_separated_list_of_data_sources> [max_chunk_size=<limit the count of replica loaded in a single pass>]\n");
$oP->p("php -q synchro_exec.php --auth_user=<login> --auth_pwd=<password> --data_sources=<comma_separated_list_of_data_sources> [--max_chunk_size=<limit the count of replica loaded in a single pass>] [--simulate=<If set to 1, then the synchro will not be executed, but the expected report will be produced>]\n");
}
else
{
@@ -89,12 +89,8 @@ catch(Exception $e)
if (utils::IsModeCLI())
{
// Next steps:
// specific arguments: 'csvfile'
//
$sAuthUser = ReadMandatoryParam($oP, 'auth_user', 'raw_data');
$sAuthPwd = ReadMandatoryParam($oP, 'auth_pwd', 'raw_data');
$sDataSourcesList = ReadMandatoryParam($oP, 'data_sources', 'raw_data'); // May contain commas
if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd))
{
UserRights::Login($sAuthUser); // Login & set the user's language
@@ -110,16 +106,15 @@ else
{
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
$sDataSourcesList = utils::ReadParam('data_sources', null, true, 'raw_data');
if ($sDataSourcesList == null)
{
UsageAndExit($oP);
}
}
$bSimulate = (utils::ReadParam('simulate', '0', true) == '1');
$sDataSourcesList = ReadMandatoryParam($oP, 'data_sources', 'raw_data'); // May contain commas
if ($sDataSourcesList == null)
{
UsageAndExit($oP);
}
foreach(explode(',', $sDataSourcesList) as $iSDS)

View File

@@ -156,27 +156,16 @@ $aPageParams = array
function UsageAndExit($oP)
{
global $aPageParams;
$bModeCLI = utils::IsModeCLI();
$sMode = utils::IsModeCLI() ? 'cli' : 'http';
$oP->p("USAGE:\n");
foreach ($aPageParams as $sParam => $aParamData)
{
$aModes = explode(',', $aParamData['modes']);
if ($bModeCLI)
if (in_array($sMode, $aModes, false))
{
if (in_array('cli', $aModes, false))
{
$sDesc = $aParamData['description'].', '.($aParamData['mandatory'] ? 'mandatory' : 'optional, defaults to ['.$aParamData['default'].']');
$oP->p("$sParam = $sDesc");
}
}
else
{
if (in_array('http', $aModes, false))
{
$sDesc = $aParamData['description'].', '.($aParamData['mandatory'] ? 'mandatory' : 'optional, defaults to ['.$aParamData['default'].']');
$oP->p("$sParam = $sDesc");
}
$sDesc = $aParamData['description'].', '.($aParamData['mandatory'] ? 'mandatory' : 'optional, defaults to ['.$aParamData['default'].']');
$oP->p("$sParam = $sDesc");
}
}
$oP->output();
@@ -523,11 +512,7 @@ try
$aValues = array(); // Used to build the insert query
foreach ($aRow as $iCol => $value)
{
if ($value === null) // Source CSV: "<NULL>"
{
$aValues[] = null;
}
elseif ($aIsDateToTransform[$iCol] !== false)
if ($aIsDateToTransform[$iCol] !== false)
{
$bDateOnly = false;
$sFormat = $sDateTimeFormat;
@@ -539,7 +524,7 @@ try
$sDate = ChangeDateFormat($value, $sFormat, $bDateOnly);
if ($sDate === false)
{
$aValues[] = CMDBSource::Quote('');
$aValues[] = '';
if ($sOutput === 'details')
{
$oP->add("$iRow: Wrong format for {$aIsDateToTransform[$iCol]} column $iCol: '$value' does not match the expected format: '$sFormat' (column skipped)\n");
@@ -547,15 +532,15 @@ try
}
else
{
$aValues[] = CMDBSource::Quote($sDate);
$aValues[] = $sDate;
}
}
else
{
$aValues[] = CMDBSource::Quote($value);
$aValues[] = $value;
}
}
$sValues = implode(', ', $aValues);
$sValues = implode(', ', CMDBSource::Quote($aValues));
$sInsert = "INSERT INTO `$sTable` ($sInsertColumns) VALUES ($sValues)";
try
{

View File

@@ -0,0 +1,568 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
* This file is part of iTop.
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Test\UnitTest\Synchro;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use DBObjectSet;
use DBSearch;
use DBObjectSearch;
use Exception;
use MetaModel;
use SynchroDataSource;
use utils;
use UserLocal;
class DataSynchroTest extends ItopDataTestCase
{
protected const AUTH_USER = 'DataSynchroTest';
protected const AUTH_PWD = 'sdf234(-fgh;,dfgDFG';
protected function setUp()
{
parent::setUp();
// Create the login account if it does not exist yet
$oSearch = DBSearch::FromOQL('SELECT User WHERE login = "'.static::AUTH_USER.'"');
$oSet = new DBObjectSet($oSearch);
if ($oSet->Count() == 0)
{
$oProfileSearch = DBSearch::FromOQL('SELECT URP_Profiles WHERE name LIKE "administrator"');
$oProfileSet = new DBObjectSet($oProfileSearch);
$oAdminProfile = $oProfileSet->fetch();
$oUser = MetaModel::NewObject('UserLocal', array(
'login' => static::AUTH_USER,
'password' => static::AUTH_PWD,
'expiration' => UserLocal::EXPIRE_NEVER,
));
$oProfiles = $oUser->Get('profile_list');
$oProfiles->AddItem(MetaModel::NewObject('URP_UserProfile', array(
'profileid' => $oAdminProfile->GetKey()
)));
$oUser->Set('profile_list', $oProfiles);
$oUser->DBInsertNoReload();
}
}
protected function ExecSynchroImport($aParams)
{
$aParams['auth_user'] = static::AUTH_USER;
$aParams['auth_pwd'] = static::AUTH_PWD;
return utils::ExecITopScript('synchro/synchro_import.php', $aParams);
}
/**
* Run a series of data synchronization through the REST API
*
* @dataProvider SynchroScenariosProvider
*
* @param $sDescription
* @param $sTargetClass
* @param $aSourceProperties
* @param $aSourceData
* @param $aTargetData
* @param $aAttributes
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \DictExceptionMissingString
* @throws \MySQLException
* @throws \OQLException
* @throws \Exception
*/
public function testSynchroImportPage($sDescription, $sTargetClass, $aSourceProperties, $aSourceData, $aTargetData, $aAttributes)
{
$sClass = $sTargetClass;
$aTargetAttributes = array_shift($aTargetData);
$aSourceAttributes = array_shift($aSourceData);
if (count($aSourceData) + 1 != count($aTargetData))
{
throw new Exception("Target data must contain exactly ".(count($aSourceData) + 1)." items, found ".count($aTargetData));
}
// Create the data source
//
$oDataSource = new SynchroDataSource();
$oDataSource->Set('name', 'Test data sync '.time());
$oDataSource->Set('description', 'unit test - created automatically');
$oDataSource->Set('status', 'production');
$oDataSource->Set('user_id', 0);
$oDataSource->Set('scope_class', $sClass);
foreach ($aSourceProperties as $sProperty => $value)
{
$oDataSource->Set($sProperty, $value);
}
$iDataSourceId = $oDataSource->DBInsert();
$oAttributeSet = $oDataSource->Get('attribute_list');
while ($oAttribute = $oAttributeSet->Fetch())
{
if (array_key_exists($oAttribute->Get('attcode'), $aAttributes))
{
$aAttribInfo = $aAttributes[$oAttribute->Get('attcode')];
if (array_key_exists('reconciliation_attcode', $aAttribInfo))
{
$oAttribute->Set('reconciliation_attcode', $aAttribInfo['reconciliation_attcode']);
}
$oAttribute->Set('update', $aAttribInfo['do_update']);
$oAttribute->Set('reconcile', $aAttribInfo['do_reconcile']);
}
else
{
$oAttribute->Set('update', false);
$oAttribute->Set('reconcile', false);
}
$oAttribute->DBUpdate();
}
// Prepare list of prefixes -> make sure objects are unique with regard to the reconciliation scheme
$aPrefixes = array(); // attcode => prefix
foreach($aSourceAttributes as $iDummy => $sAttCode)
{
$aPrefixes[$sAttCode] = ''; // init with something
}
foreach($aAttributes as $sAttCode => $aAttribInfo)
{
if (isset($aAttribInfo['automatic_prefix']) && $aAttribInfo['automatic_prefix'])
{
$aPrefixes[$sAttCode] = 'TEST_'.$iDataSourceId.'_';
}
}
// List existing objects (to be ignored in the analysis
//
$oAllObjects = new DBObjectSet(new DBObjectSearch($sClass));
$aExisting = $oAllObjects->ToArray(true);
$sExistingIds = implode(', ', array_keys($aExisting));
// Create the initial object list
//
$aInitialTarget = $aTargetData[0];
foreach($aInitialTarget as $aObjFields)
{
$oNewTarget = MetaModel::NewObject($sClass);
foreach($aTargetAttributes as $iAtt => $sAttCode)
{
$oNewTarget->Set($sAttCode, $aPrefixes[$sAttCode].$aObjFields[$iAtt]);
}
$oNewTarget->DBInsertNoReload();
}
foreach($aTargetData as $iRow => $aExpectedObjects)
{
// Check the status (while ignoring existing objects)
//
if (empty($sExistingIds))
{
$oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass"));
}
else
{
$oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass WHERE id NOT IN($sExistingIds)"));
}
$aFound = $oObjects->ToArray();
$aErrors_Unexpected = array();
foreach($aFound as $iObj => $oObj)
{
// Is this object in the expected objects list
$bFoundMatch = false;
foreach($aExpectedObjects as $iExp => $aValues)
{
$bDoesMatch = true;
foreach($aTargetAttributes as $iCol => $sAttCode)
{
if ($oObj->Get($sAttCode) != $aPrefixes[$sAttCode].$aValues[$iCol])
{
$bDoesMatch = false;
break;
}
}
if ($bDoesMatch)
{
$bFoundMatch = true;
unset($aExpectedObjects[$iExp]);
break;
}
}
if (!$bFoundMatch)
{
$aObjDesc = array();
foreach($aTargetAttributes as $iCol => $sAttCode)
{
$aObjDesc[$sAttCode] = $oObj->Get($sAttCode);
}
$aErrors_Unexpected[get_class($oObj).'::'.$oObj->GetKey()] = $aObjDesc;
}
}
// Display the current status
//
$aErrors = array();
if (count($aErrors_Unexpected) > 0) {
$aErrors[] = "Unexpected objects found in iTop DB after step $iRow (starting at 0):\n".print_r($aErrors_Unexpected, true);
}
if (count($aExpectedObjects) > 0) {
$aErrors[] = "Expected objects NOT found in iTop DB after step $iRow (starting at 0)\n".print_r($aExpectedObjects, true);
}
if (count($aErrors) > 0) {
static::fail(implode("\n", $aErrors));
}
else {
static::assertTrue(true);
}
// If not on the final row, run a data exchange sequence
//
if (array_key_exists($iRow, $aSourceData))
{
$aToBeLoaded = $aSourceData[$iRow];
// First line
$sCsvData = implode(';', $aSourceAttributes)."\n";
$sTextQualifier = '"';
foreach($aToBeLoaded as $aDataRow)
{
$aFinalData = array();
foreach($aDataRow as $iCol => $value)
{
$sAttCode = $aSourceAttributes[$iCol];
$sRawValue = $aPrefixes[$sAttCode].$value;
$sFrom = array("\r\n", $sTextQualifier);
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
$sCSVValue = $sTextQualifier.str_replace($sFrom, $sTo, (string)$sRawValue).$sTextQualifier;
$aFinalData[] = $sCSVValue;
}
$sCsvData .= implode(';', $aFinalData)."\n";
}
$sCSVTmpFile = tempnam(sys_get_temp_dir(), "CSV");
file_put_contents($sCSVTmpFile, $sCsvData);
$aParams = array(
'csvfile' => $sCSVTmpFile,
'data_source_id' => $iDataSourceId,
'separator' => ';',
'simulate' => 0,
'output' => 'details',
);
list($iRetCode, $aOutputLines) = static::ExecSynchroImport($aParams);
unlink($sCSVTmpFile);
// Report the load results
//
if (strlen($sCsvData) > 5000)
{
$sCsvDataViewable = 'INPUT TOO LONG TO BE DISPLAYED ('.strlen($sCsvData).")\n".substr($sCsvData, 0, 500)."\n... TO BE CONTINUED";
}
else
{
$sCsvDataViewable = $sCsvData;
}
echo "Input Data:\n";
echo $sCsvDataViewable;
echo "\n";
$sResultsViewable = '| '.implode("\n| ", $aOutputLines);
echo "Results:\n";
echo $sResultsViewable;
echo "\n";
if ($iRetCode != 0)
{
static::fail("Execution of synchro_import failing with code '$iRetCode', see error.log for more details");
}
if (stripos($sResultsViewable, 'exception') !== false)
{
self::fail('Encountered an Exception during the last import/synchro');
}
}
}
}
public function SynchroScenariosProvider()
{
$aTestCases = array();
$aTestCases['Load user logins'] = array(
'desc' => 'Load user logins',
'target_class' => 'UserLocal',
'source_properties' => array(
'full_load_periodicity' => 3600, // should be ignored in this case
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'delete',
'delete_policy_update' => '',
'delete_policy_retention' => 0,
),
'source_data' => array(
array('primary_key', 'login', 'password', 'profile_list'),
array(
array('user_A', 'login_A', 'password_A', 'profileid:10;reason:he/she is managing services'),
),
),
'target_data' => array(
array('login'),
array(
// Initial state
),
array(
array('login_A'),
),
),
'attributes' => array(
'login' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id (for unit testing)
),
'password' => array(
'do_reconcile' => false,
'do_update' => true,
),
'profile_list' => array(
'do_reconcile' => false,
'do_update' => true,
),
)
);
$aTestCases['Simple scenario with delete option (and extkey given as org/name)'] = array(
'desc' => 'Simple scenario with delete option (and extkey given as org/name)',
'target_class' => 'ApplicationSolution',
'source_properties' => array(
'full_load_periodicity' => 1,
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'delete',
'delete_policy_update' => '',
'delete_policy_retention' => 0,
),
'source_data' => array(
array('primary_key', 'org_id', 'name', 'status'),
array(
array('obj_A', '<NULL>', 'obj_A', 'active'), // org_id unchanged
array('obj_B', '_DUMMY_', 'obj_B', 'active'), // error, '_DUMMY_' unknown
array('obj_C', 'SOMECODE', 'obj_C', 'active'),
array('obj_D', 'SOMECODE', 'obj_D', 'active'),
array('obj_E', 'SOMECODE', 'obj_E', 'active'),
),
array(
array('obj_D', 'SOMECODE', 'obj_D', 'inactive'),
array('obj_E', 'SOMECODE', 'obj_E', '<NULL>'),
),
),
'target_data' => array(
array('org_id', 'name', 'status'),
array(
// Initial state
array(2, 'obj_A', 'active'),
array(2, 'obj_B', 'active'),
),
array(
array(2, 'obj_A', 'active'),
array(2, 'obj_B', 'active'),
array(1, 'obj_C', 'active'),
array(1, 'obj_D', 'active'),
array(1, 'obj_E', 'active'),
),
array(
array(2, 'obj_A', 'active'),
array(2, 'obj_B', 'active'),
array(1, 'obj_D', 'inactive'),
array(1, 'obj_E', 'active'),
),
),
'attributes' => array(
'org_id' => array(
'do_reconcile' => false,
'do_update' => true,
'reconciliation_attcode' => 'code',
),
'name' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id
),
'status' => array(
'do_reconcile' => false,
'do_update' => true,
),
),
);
$aTestCases['Update then delete with retention (to complete with manual testing) and reconciliation on org/name'] = array(
'desc' => 'Update then delete with retention (to complete with manual testing) and reconciliation on org/name',
'target_class' => 'ApplicationSolution',
'source_properties' => array(
'full_load_periodicity' => 0,
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'update_then_delete',
'delete_policy_update' => 'status:inactive',
'delete_policy_retention' => 15,
),
'source_data' => array(
array('primary_key', 'org_id', 'name', 'status'),
array(
array('obj_A', 'Demo', 'obj_A', 'active'),
),
array(
),
),
'target_data' => array(
array('org_id', 'name', 'status'),
array(
// Initial state
),
array(
array(3, 'obj_A', 'active'),
),
array(
array(3, 'obj_A', 'inactive'),
// deleted !
),
),
'attributes' => array(
'org_id' => array(
'do_reconcile' => true,
'do_update' => true,
'reconciliation_attcode' => 'name',
),
'name' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id
),
'status' => array(
'do_reconcile' => false,
'do_update' => true,
),
),
);
$aTestCases['Simple scenario loading a few ApplicationSolution'] = array(
'desc' => 'Simple scenario loading a few ApplicationSolution',
'target_class' => 'ApplicationSolution',
'source_properties' => array(
'full_load_periodicity' => 0,
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'update',
'delete_policy_update' => 'status:inactive',
'delete_policy_retention' => 0,
),
'source_data' => array(
array('primary_key', 'org_id', 'name', 'status'),
array(
array('obj_A', 2, 'obj_A', 'active'),
array('obj_B', 2, 'obj_B', 'inactive'),
array('obj_C', 2, 'obj_C', 'inactive'),
),
array(
array('obj_A', 2, 'obj_A', 'active'),
array('obj_B', 2, 'obj_B', 'inactive'),
array('obj_C', 2, 'obj_C', 'inactive'),
),
array(
array('obj_A', 2, 'obj_A', 'active'),
array('obj_C', 2, 'obj_C', 'inactive'),
array('obj_D', 2, 'obj_D', 'inactive'),
),
array(
array('obj_C', 2, 'obj_C', 'active'),
),
array(
array('obj_C', 2, 'obj_C', 'active'),
),
),
'target_data' => array(
array('org_id', 'name', 'status'),
array(
// Initial state
array(2, 'obj_A', 'inactive'),
array(2, 'obj_B', 'active'),
array(2, 'obj_B', 'inactive'),
),
array(
array(2, 'obj_A', 'active'),
array(2, 'obj_B', 'active'),
array(2, 'obj_B', 'inactive'),
array(2, 'obj_C', 'inactive'),
),
array(
array(2, 'obj_A', 'active'),
array(2, 'obj_B', 'active'),
array(2, 'obj_B', 'inactive'),
array(2, 'obj_C', 'inactive'),
),
array(
array(2, 'obj_A', 'active'),
array(2, 'obj_B', 'active'),
array(2, 'obj_B', 'inactive'),
array(2, 'obj_C', 'inactive'),
array(2, 'obj_D', 'inactive'),
),
array(
array(2, 'obj_A', 'inactive'),
array(2, 'obj_B', 'active'),
array(2, 'obj_B', 'inactive'),
array(2, 'obj_C', 'active'),
array(2, 'obj_D', 'inactive'),
),
array(
array(2, 'obj_A', 'inactive'),
array(2, 'obj_B', 'active'),
array(2, 'obj_B', 'inactive'),
array(2, 'obj_C', 'active'),
array(2, 'obj_D', 'inactive'),
),
),
'attributes' => array(
'org_id' => array(
'do_reconcile' => false,
'do_update' => true,
),
'name' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id
),
'status' => array(
'do_reconcile' => false,
'do_update' => true,
),
),
);
return $aTestCases;
}
}

View File

@@ -1414,546 +1414,6 @@ class TestImportRESTMassive extends TestImportREST
}
}
///////////////////////////////////////////////////////////////////////////
// Test data exchange
///////////////////////////////////////////////////////////////////////////
class TestDataExchange extends TestBizModel
{
static public function GetName()
{
return 'Data exchange';
}
static public function GetDescription()
{
return 'Test REST services: synchro_import and synchro_exec';
}
protected function DoExecScenario($aSingleScenario)
{
echo "<div style=\"padding: 10;\">\n";
echo "<h3 style=\"background-color: #ddddff; padding: 10;\">{$aSingleScenario['desc']}</h3>\n";
$sClass = $aSingleScenario['target_class'];
$aTargetData = $aSingleScenario['target_data'];
$aSourceData = $aSingleScenario['source_data'];
$aTargetAttributes = array_shift($aTargetData);
$aSourceAttributes = array_shift($aSourceData);
if (count($aSourceData) + 1 != count($aTargetData))
{
throw new Exception("Target data must contain exactly ".(count($aSourceData) + 1)." items, found ".count($aTargetData));
}
// Create the data source
//
$oDataSource = new SynchroDataSource();
$oDataSource->Set('name', 'Test data sync '.time());
$oDataSource->Set('description', 'unit test - created automatically');
$oDataSource->Set('status', 'production');
$oDataSource->Set('user_id', 0);
$oDataSource->Set('scope_class', $sClass);
$oDataSource->Set('scope_restriction', '');
$oDataSource->Set('full_load_periodicity', $aSingleScenario['full_load_periodicity']);
$oDataSource->Set('reconciliation_policy', $aSingleScenario['reconciliation_policy']);
$oDataSource->Set('action_on_zero', $aSingleScenario['action_on_zero']);
$oDataSource->Set('action_on_one', $aSingleScenario['action_on_one']);
$oDataSource->Set('action_on_multiple', $aSingleScenario['action_on_multiple']);
$oDataSource->Set('delete_policy', $aSingleScenario['delete_policy']);
$oDataSource->Set('delete_policy_update', $aSingleScenario['delete_policy_update']);
$oDataSource->Set('delete_policy_retention', $aSingleScenario['delete_policy_retention']);
$iDataSourceId = $this->ObjectToDB($oDataSource, true /* reload */);
$oAttributeSet = $oDataSource->Get('attribute_list');
while ($oAttribute = $oAttributeSet->Fetch())
{
if (array_key_exists($oAttribute->Get('attcode'), $aSingleScenario['attributes']))
{
$aAttribInfo = $aSingleScenario['attributes'][$oAttribute->Get('attcode')];
if (array_key_exists('reconciliation_attcode', $aAttribInfo))
{
$oAttribute->Set('reconciliation_attcode', $aAttribInfo['reconciliation_attcode']);
}
$oAttribute->Set('update', $aAttribInfo['do_update']);
$oAttribute->Set('reconcile', $aAttribInfo['do_reconcile']);
}
else
{
$oAttribute->Set('update', false);
$oAttribute->Set('reconcile', false);
}
$this->UpdateObjectInDB($oAttribute);
}
// Prepare list of prefixes -> make sure objects are unique with regard to the reconciliation scheme
$aPrefixes = array(); // attcode => prefix
foreach($aSourceAttributes as $iDummy => $sAttCode)
{
$aPrefixes[$sAttCode] = ''; // init with something
}
foreach($aSingleScenario['attributes'] as $sAttCode => $aAttribInfo)
{
if (isset($aAttribInfo['automatic_prefix']) && $aAttribInfo['automatic_prefix'])
{
$aPrefixes[$sAttCode] = 'TEST_'.$iDataSourceId.'_';
}
}
// List existing objects (to be ignored in the analysis
//
$oAllObjects = new DBObjectSet(new DBObjectSearch($sClass));
$aExisting = $oAllObjects->ToArray(true);
$sExistingIds = implode(', ', array_keys($aExisting));
// Create the initial object list
//
$aInitialTarget = $aTargetData[0];
foreach($aInitialTarget as $aObjFields)
{
$oNewTarget = MetaModel::NewObject($sClass);
foreach($aTargetAttributes as $iAtt => $sAttCode)
{
$oNewTarget->Set($sAttCode, $aPrefixes[$sAttCode].$aObjFields[$iAtt]);
}
$this->ObjectToDB($oNewTarget);
}
foreach($aTargetData as $iRow => $aExpectedObjects)
{
sleep(2);
// Check the status (while ignoring existing objects)
//
if (empty($sExistingIds))
{
$oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass"));
}
else
{
$oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass WHERE id NOT IN($sExistingIds)"));
}
$aFound = $oObjects->ToArray();
$aErrors_Unexpected = array();
foreach($aFound as $iObj => $oObj)
{
// Is this object in the expected objects list
$bFoundMatch = false;
foreach($aExpectedObjects as $iExp => $aValues)
{
$bDoesMatch = true;
foreach($aTargetAttributes as $iCol => $sAttCode)
{
if ($oObj->Get($sAttCode) != $aPrefixes[$sAttCode].$aValues[$iCol])
{
$bDoesMatch = false;
break;
}
}
if ($bDoesMatch)
{
$bFoundMatch = true;
unset($aExpectedObjects[$iExp]);
break;
}
}
if (!$bFoundMatch)
{
$aErrors_Unexpected[] = $oObj->GetKey();
}
}
// Display the current status
//
echo "<p>Status at step $iRow</p>\n";
$aCurrentDataSet = array();
foreach($aFound as $iObj => $oObj)
{
$aObjDesc = array(
'Status' => (in_array($iObj, $aErrors_Unexpected) ? 'unexpected' : 'ok'),
'Object' => $oObj->GetHyperLink()
);
foreach($aTargetAttributes as $iCol => $sAttCode)
{
$aObjDesc[$sAttCode] = $oObj->Get($sAttCode);
}
$aCurrentDataSet[] = $aObjDesc;
}
if (count($aExpectedObjects) > 0)
{
foreach($aExpectedObjects as $iExp => $aValues)
{
$aObjDesc = array(
'Status' => 'missing',
'Object' => 'n/a'
);
foreach($aTargetAttributes as $iCol => $sAttCode)
{
$aObjDesc[$sAttCode] = $aPrefixes[$sAttCode].$aValues[$iCol];
}
$aCurrentDataSet[] = $aObjDesc;
}
}
echo MyHelpers::make_table_from_assoc_array($aCurrentDataSet);
if ((count($aErrors_Unexpected) > 0) || (count($aExpectedObjects) > 0))
{
throw new UnitTestException("The current status in iTop does not match the expectations");
}
// If not on the final row, run a data exchange sequence
//
if (array_key_exists($iRow, $aSourceData))
{
$aToBeLoaded = $aSourceData[$iRow];
$sCsvData = implode(';', $aSourceAttributes)."\n";
foreach($aToBeLoaded as $aDataRow)
{
$aFinalData = array();
foreach($aDataRow as $iCol => $value)
{
if (is_null($value))
{
$aFinalData[] = '<NULL>';
}
else
{
$sAttCode = $aSourceAttributes[$iCol];
$aFinalData[] = $aPrefixes[$sAttCode].$value;
}
}
$sCsvData .= implode(';', $aFinalData)."\n";
}
$aPostData = array('csvdata' => $sCsvData);
$aImportArgs = array(
'data_source_id' => $iDataSourceId,
'separator' => ';',
'simulate' => 0,
'output' => 'details',
);
$aGetParams = array();
$aGetParamReport = array();
foreach($aImportArgs as $sArg => $sValue)
{
$aGetParams[] = $sArg.'='.urlencode($sValue);
$aGetParamReport[] = $sArg.'='.$sValue;
}
$sGetParams = implode('&', $aGetParams);
$sLogin = isset($aSingleScenario['login']) ? $aSingleScenario['login'] : 'admin';
$sPassword = isset($aSingleScenario['password']) ? $aSingleScenario['password'] : 'admin';
$sRes = self::DoPostRequestAuth('../synchro/synchro_import.php?'.$sGetParams, $aPostData, $sLogin, $sPassword);
// Report the load results
//
if (strlen($sCsvData) > 5000)
{
$sCsvDataViewable = 'INPUT TOO LONG TO BE DISPLAYED ('.strlen($sCsvData).")\n".substr($sCsvData, 0, 500)."\n... TO BE CONTINUED";
}
else
{
$sCsvDataViewable = $sCsvData;
}
$sCsvDataViewable = htmlentities($sCsvDataViewable, ENT_QUOTES, 'UTF-8');
echo "<div style=\"\">\n";
echo " <pre class=\"vardump\">$sCsvDataViewable</pre>\n";
echo "</div>\n";
echo "<pre class=\"vardump\" style=\"clear: both; padding: 15; background-color: black; color: green;\">$sRes</pre>\n";
if (stripos($sRes, 'exception') !== false)
{
throw new UnitTestException('Encountered an Exception during the last import/synchro');
}
}
}
return;
echo "</div>\n";
}
protected function DoExecute()
{
/*
$aScenarios = array(
array(
'desc' => 'Load user logins',
'login' => 'admin',
'password' => 'admin',
'target_class' => 'UserLocal',
'full_load_periodicity' => 3600, // should be ignored in this case
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'delete',
'delete_policy_update' => '',
'delete_policy_retention' => 0,
'source_data' => array(
array('primary_key', 'login', 'password', 'profile_list'),
array(
array('user_A', 'login_A', 'password_A', 'profileid:10;reason:he/she is managing services'),
),
),
'target_data' => array(
array('login'),
array(
// Initial state
),
array(
array('login_A'),
),
),
'attributes' => array(
'login' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id (for unit testing)
),
'password' => array(
'do_reconcile' => false,
'do_update' => true,
),
'profile_list' => array(
'do_reconcile' => false,
'do_update' => true,
),
),
),
);
*/
$aScenarios = array(
array(
'desc' => 'Simple scenario with delete option (and extkey given as org/name)',
'login' => 'admin',
'password' => 'admin',
'target_class' => 'ApplicationSolution',
'full_load_periodicity' => 3600, // should be ignored in this case
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'delete',
'delete_policy_update' => '',
'delete_policy_retention' => 0,
'source_data' => array(
array('primary_key', 'org_id', 'name', 'status'),
array(
array('obj_A', null, 'obj_A', 'production'), // org_id unchanged
array('obj_B', '_DUMMY_', 'obj_B', 'production'), // error, '_DUMMY_' unknown
array('obj_C', 'SOMECODE', 'obj_C', 'production'),
array('obj_D', null, 'obj_D', 'production'),
array('obj_E', '_DUMMY_', 'obj_E', 'production'),
),
array(
),
array(
),
),
'target_data' => array(
array('org_id', 'name', 'status'),
array(
// Initial state
array(2, 'obj_A', 'production'),
array(2, 'obj_B', 'production'),
),
array(
array(2, 'obj_A', 'production'),
array(2, 'obj_B', 'production'),
array(1, 'obj_C', 'production'),
),
array(
array(2, 'obj_A', 'production'),
array(2, 'obj_B', 'production'),
// deleted !
),
// The only diff here is into the log
array(
array(2, 'obj_A', 'production'),
array(2, 'obj_B', 'production'),
// deleted !
),
),
'attributes' => array(
'org_id' => array(
'do_reconcile' => false,
'do_update' => true,
'reconciliation_attcode' => 'code',
),
'name' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id
),
'status' => array(
'do_reconcile' => false,
'do_update' => true,
),
),
),
// );
// $aXXXXScenarios = array(
array(
'desc' => 'Update then delete with retention (to complete with manual testing) and reconciliation on org/name',
'login' => 'admin',
'password' => 'admin',
'target_class' => 'ApplicationSolution',
'full_load_periodicity' => 3600,
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'update_then_delete',
'delete_policy_update' => 'status:obsolete',
'delete_policy_retention' => 15,
'source_data' => array(
array('primary_key', 'org_id', 'name', 'status'),
array(
array('obj_A', 'Demo', 'obj_A', 'production'),
),
array(
),
),
'target_data' => array(
array('org_id', 'name', 'status'),
array(
// Initial state
),
array(
array(2, 'obj_A', 'production'),
),
array(
array(2, 'obj_A', 'obsolete'),
// deleted !
),
),
'attributes' => array(
'org_id' => array(
'do_reconcile' => true,
'do_update' => true,
'reconciliation_attcode' => 'name',
),
'name' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id
),
'status' => array(
'do_reconcile' => false,
'do_update' => true,
),
),
),
//);
//$aXXScenarios = array(
array(
'desc' => 'Simple scenario loading a few ApplicationSolution',
'login' => 'admin',
'password' => 'admin',
'target_class' => 'ApplicationSolution',
'full_load_periodicity' => 3600,
'reconciliation_policy' => 'use_attributes',
'action_on_zero' => 'create',
'action_on_one' => 'update',
'action_on_multiple' => 'error',
'delete_policy' => 'update',
'delete_policy_update' => 'status:obsolete',
'delete_policy_retention' => 0,
'source_data' => array(
array('primary_key', 'org_id', 'name', 'status'),
array(
array('obj_A', 2, 'obj_A', 'production'),
array('obj_B', 2, 'obj_B', 'implementation'),
array('obj_C', 2, 'obj_C', 'implementation'),
),
array(
array('obj_A', 2, 'obj_A', 'production'),
array('obj_B', 2, 'obj_B', 'implementation'),
array('obj_C', 2, 'obj_C', 'implementation'),
),
array(
array('obj_A', 2, 'obj_A', 'production'),
array('obj_C', 2, 'obj_C', 'implementation'),
array('obj_D', 2, 'obj_D', 'implementation'),
),
array(
array('obj_C', 2, 'obj_C', 'production'),
),
array(
array('obj_C', 2, 'obj_C', 'production'),
),
),
'target_data' => array(
array('org_id', 'name', 'status'),
array(
// Initial state
array(2, 'obj_A', 'implementation'),
array(2, 'obj_B', 'production'),
array(2, 'obj_B', 'implementation'),
),
array(
array(2, 'obj_A', 'production'),
array(2, 'obj_B', 'production'),
array(2, 'obj_B', 'implementation'),
array(2, 'obj_C', 'implementation'),
),
array(
array(2, 'obj_A', 'production'),
array(2, 'obj_B', 'production'),
array(2, 'obj_B', 'implementation'),
array(2, 'obj_C', 'implementation'),
),
array(
array(2, 'obj_A', 'production'),
array(2, 'obj_B', 'production'),
array(2, 'obj_B', 'implementation'),
array(2, 'obj_C', 'implementation'),
array(2, 'obj_D', 'implementation'),
),
array(
array(2, 'obj_A', 'obsolete'),
array(2, 'obj_B', 'production'),
array(2, 'obj_B', 'implementation'),
array(2, 'obj_C', 'production'),
array(2, 'obj_D', 'obsolete'),
),
array(
array(2, 'obj_A', 'obsolete'),
array(2, 'obj_B', 'production'),
array(2, 'obj_B', 'implementation'),
array(2, 'obj_C', 'production'),
array(2, 'obj_D', 'obsolete'),
),
),
'attributes' => array(
'org_id' => array(
'do_reconcile' => false,
'do_update' => true,
),
'name' => array(
'do_reconcile' => true,
'do_update' => true,
'automatic_prefix' => true, // unique id
),
'status' => array(
'do_reconcile' => false,
'do_update' => true,
),
),
),
);
foreach ($aScenarios as $aSingleScenario)
{
$this->DoExecScenario($aSingleScenario);
}
}
}
///////////////////////////////////////////////////////////////////////////
// Test SOAP services
///////////////////////////////////////////////////////////////////////////

View File

@@ -340,11 +340,9 @@ function CronExec($oP, $bVerbose, $bDebug=false)
/**
* @param \WebPage $oP
*/
function CheckMaintenanceMode(Page $oP): void
{
function CheckMaintenanceMode(Page $oP) {
// Verify files instead of reloading the full config each time
if (file_exists(MAINTENANCE_MODE_FILE) || file_exists(READONLY_MODE_FILE))
{
if (file_exists(MAINTENANCE_MODE_FILE) || file_exists(READONLY_MODE_FILE)) {
$oP->p("Maintenance detected, exiting");
exit(EXIT_CODE_ERROR);
}

View File

@@ -30,7 +30,6 @@
if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
require_once(__DIR__.'/../approot.inc.php');
require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'/setup/setuppage.class.inc.php');
require_once(APPROOT.'/application/startup.inc.php');