diff --git a/.dockerignore b/.dockerignore index e23a3f5..f9ff432 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,8 +4,6 @@ .vscode/ .gradle/ .settings/ -/src/test/java/test/* -/src/test/resources/test/* #build /build/ diff --git a/.editorconfig b/.editorconfig index ee8e124..424d5bf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,3 @@ -root = true - [*] charset = utf-8 end_of_line = lf @@ -11,11 +9,50 @@ tab_width = 4 ij_continuation_indent_size = 8 ij_formatter_off_tag = @formatter:off ij_formatter_on_tag = @formatter:on -ij_formatter_tags_enabled = false +ij_formatter_tags_enabled = true ij_smart_tabs = false -ij_visual_guides = none +ij_visual_guides = ij_wrap_on_typing = false +[*.conf] +ij_smart_tabs = true +ij_hocon_keep_blank_lines_before_right_brace = 2 +ij_hocon_keep_indents_on_empty_lines = true +ij_hocon_keep_line_breaks = true +ij_hocon_space_after_colon = true +ij_hocon_space_after_comma = true +ij_hocon_space_before_colon = true +ij_hocon_space_before_comma = false +ij_hocon_spaces_within_braces = false +ij_hocon_spaces_within_brackets = false +ij_hocon_spaces_within_method_call_parentheses = false + +[*.css] +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_block_comment_add_space = false +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 = true +ij_css_hex_color_short_format = false +ij_css_hex_color_upper_case = false +ij_css_keep_blank_lines_in_code = 2 +ij_css_keep_indents_on_empty_lines = true +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_use_double_quotes = true +ij_css_value_alignment = do_not_align + +[*.feature] +indent_size = 2 +indent_style = space +ij_gherkin_keep_indents_on_empty_lines = false + [*.java] ij_java_align_consecutive_assignments = false ij_java_align_consecutive_variable_declarations = false @@ -25,6 +62,7 @@ ij_java_align_multiline_array_initializer_expression = false ij_java_align_multiline_assignment = true ij_java_align_multiline_binary_operation = false ij_java_align_multiline_chained_methods = false +ij_java_align_multiline_deconstruction_list_components = true ij_java_align_multiline_extends_list = false ij_java_align_multiline_for = false ij_java_align_multiline_method_parentheses = false @@ -38,6 +76,7 @@ ij_java_align_multiline_text_blocks = false ij_java_align_multiline_throws_list = false ij_java_align_subsequent_simple_methods = false ij_java_align_throws_keyword = true +ij_java_align_types_in_multi_catch = true ij_java_annotation_parameter_wrap = off ij_java_array_initializer_new_line_after_left_brace = true ij_java_array_initializer_right_brace_on_new_line = true @@ -64,7 +103,7 @@ ij_java_blank_lines_before_package = 0 ij_java_block_brace_style = end_of_line ij_java_block_comment_add_space = false ij_java_block_comment_at_first_column = true -ij_java_builder_methods = none +ij_java_builder_methods = ij_java_call_parameters_new_line_after_left_paren = true ij_java_call_parameters_right_paren_on_new_line = true ij_java_call_parameters_wrap = normal @@ -74,8 +113,10 @@ ij_java_class_annotation_wrap = split_into_lines ij_java_class_brace_style = end_of_line ij_java_class_count_to_use_import_on_demand = 5 ij_java_class_names_in_javadoc = 1 +ij_java_deconstruction_list_wrap = normal ij_java_do_not_indent_top_level_class_members = false ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_not_wrap_after_single_annotation_in_parameter = false ij_java_do_while_brace_force = never ij_java_doc_add_blank_line_after_description = true ij_java_doc_add_blank_line_after_param_comments = false @@ -96,18 +137,31 @@ ij_java_doc_param_description_on_new_line = false ij_java_doc_preserve_line_breaks = true ij_java_doc_use_throws_not_exception_tag = true ij_java_else_on_new_line = false +ij_java_entity_dd_prefix = ij_java_entity_dd_suffix = EJB +ij_java_entity_eb_prefix = ij_java_entity_eb_suffix = Bean +ij_java_entity_hi_prefix = ij_java_entity_hi_suffix = Home ij_java_entity_lhi_prefix = Local ij_java_entity_lhi_suffix = Home ij_java_entity_li_prefix = Local +ij_java_entity_li_suffix = ij_java_entity_pk_class = java.lang.String +ij_java_entity_ri_prefix = +ij_java_entity_ri_suffix = +ij_java_entity_vo_prefix = ij_java_entity_vo_suffix = VO ij_java_enum_constants_wrap = on_every_item ij_java_extends_keyword_wrap = normal ij_java_extends_list_wrap = off ij_java_field_annotation_wrap = normal +ij_java_field_name_prefix = +ij_java_field_name_suffix = +ij_java_filter_class_prefix = +ij_java_filter_class_suffix = +ij_java_filter_dd_prefix = +ij_java_filter_dd_suffix = ij_java_finally_on_new_line = false ij_java_for_brace_force = if_multiline ij_java_for_statement_new_line_after_left_paren = true @@ -139,8 +193,15 @@ ij_java_label_indent_size = 0 ij_java_lambda_brace_style = end_of_line ij_java_layout_static_imports_separately = true ij_java_line_comment_add_space = false +ij_java_line_comment_add_space_on_reformat = false ij_java_line_comment_at_first_column = true +ij_java_listener_class_prefix = +ij_java_listener_class_suffix = +ij_java_local_variable_name_prefix = +ij_java_local_variable_name_suffix = +ij_java_message_dd_prefix = ij_java_message_dd_suffix = EJB +ij_java_message_eb_prefix = ij_java_message_eb_suffix = Bean ij_java_method_annotation_wrap = split_into_lines ij_java_method_brace_style = end_of_line @@ -149,16 +210,22 @@ ij_java_method_parameters_new_line_after_left_paren = true ij_java_method_parameters_right_paren_on_new_line = true ij_java_method_parameters_wrap = normal ij_java_modifier_list_wrap = false +ij_java_multi_catch_types_wrap = normal ij_java_names_count_to_use_import_on_demand = 3 +ij_java_new_line_after_lparen_in_annotation = false +ij_java_new_line_after_lparen_in_deconstruction_pattern = true ij_java_new_line_after_lparen_in_record_header = false ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* ij_java_parameter_annotation_wrap = normal +ij_java_parameter_name_prefix = +ij_java_parameter_name_suffix = ij_java_parentheses_expression_new_line_after_left_paren = false ij_java_parentheses_expression_right_paren_on_new_line = false ij_java_place_assignment_sign_on_next_line = false ij_java_prefer_longer_names = true ij_java_prefer_parameters_wrap = false ij_java_record_components_wrap = normal +ij_java_repeat_annotations = ij_java_repeat_synchronized = true ij_java_replace_instanceof_and_cast = false ij_java_replace_null_check = true @@ -166,13 +233,26 @@ ij_java_replace_sum_lambda_with_method_ref = true ij_java_resource_list_new_line_after_left_paren = true ij_java_resource_list_right_paren_on_new_line = true ij_java_resource_list_wrap = normal +ij_java_rparen_on_new_line_in_annotation = false +ij_java_rparen_on_new_line_in_deconstruction_pattern = true ij_java_rparen_on_new_line_in_record_header = false +ij_java_servlet_class_prefix = +ij_java_servlet_class_suffix = +ij_java_servlet_dd_prefix = +ij_java_servlet_dd_suffix = +ij_java_session_dd_prefix = ij_java_session_dd_suffix = EJB +ij_java_session_eb_prefix = ij_java_session_eb_suffix = Bean +ij_java_session_hi_prefix = ij_java_session_hi_suffix = Home ij_java_session_lhi_prefix = Local ij_java_session_lhi_suffix = Home ij_java_session_li_prefix = Local +ij_java_session_li_suffix = +ij_java_session_ri_prefix = +ij_java_session_ri_suffix = +ij_java_session_si_prefix = ij_java_session_si_suffix = Service ij_java_space_after_closing_angle_bracket_in_type_argument = false ij_java_space_after_colon = true @@ -191,6 +271,7 @@ ij_java_space_before_class_left_brace = true ij_java_space_before_colon = true ij_java_space_before_colon_in_foreach = true ij_java_space_before_comma = false +ij_java_space_before_deconstruction_list = false ij_java_space_before_do_left_brace = true ij_java_space_before_else_keyword = true ij_java_space_before_else_left_brace = true @@ -221,6 +302,7 @@ ij_java_space_within_empty_array_initializer_braces = false ij_java_space_within_empty_method_call_parentheses = false ij_java_space_within_empty_method_parentheses = false ij_java_spaces_around_additive_operators = true +ij_java_spaces_around_annotation_eq = true ij_java_spaces_around_assignment_operators = true ij_java_spaces_around_bitwise_operators = true ij_java_spaces_around_equality_operators = true @@ -239,6 +321,7 @@ ij_java_spaces_within_braces = false ij_java_spaces_within_brackets = false ij_java_spaces_within_cast_parentheses = false ij_java_spaces_within_catch_parentheses = false +ij_java_spaces_within_deconstruction_list = false ij_java_spaces_within_for_parentheses = false ij_java_spaces_within_if_parentheses = false ij_java_spaces_within_method_call_parentheses = false @@ -250,9 +333,13 @@ ij_java_spaces_within_synchronized_parentheses = false ij_java_spaces_within_try_parentheses = false ij_java_spaces_within_while_parentheses = false ij_java_special_else_if_treatment = true +ij_java_static_field_name_prefix = +ij_java_static_field_name_suffix = +ij_java_subclass_name_prefix = ij_java_subclass_name_suffix = Impl ij_java_ternary_operation_signs_on_next_line = false ij_java_ternary_operation_wrap = on_every_item +ij_java_test_name_prefix = ij_java_test_name_suffix = Test ij_java_throws_keyword_wrap = normal ij_java_throws_list_wrap = off @@ -268,6 +355,303 @@ ij_java_wrap_comments = false ij_java_wrap_first_method_in_call_chain = true ij_java_wrap_long_lines = false +[*.less] +indent_size = 2 +indent_style = space +ij_less_align_closing_brace_with_properties = false +ij_less_blank_lines_around_nested_selector = 1 +ij_less_blank_lines_between_blocks = 1 +ij_less_block_comment_add_space = false +ij_less_brace_placement = 0 +ij_less_enforce_quotes_on_format = false +ij_less_hex_color_long_format = false +ij_less_hex_color_lower_case = false +ij_less_hex_color_short_format = false +ij_less_hex_color_upper_case = false +ij_less_keep_blank_lines_in_code = 2 +ij_less_keep_indents_on_empty_lines = false +ij_less_keep_single_line_blocks = false +ij_less_line_comment_add_space = false +ij_less_line_comment_at_first_column = false +ij_less_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_less_space_after_colon = true +ij_less_space_before_opening_brace = true +ij_less_use_double_quotes = true +ij_less_value_alignment = 0 + +[*.proto] +indent_size = 2 +indent_style = space +tab_width = 2 +ij_continuation_indent_size = 4 +ij_protobuf_keep_blank_lines_in_code = 2 +ij_protobuf_keep_indents_on_empty_lines = false +ij_protobuf_keep_line_breaks = true +ij_protobuf_space_after_comma = true +ij_protobuf_space_before_comma = false +ij_protobuf_spaces_around_assignment_operators = true +ij_protobuf_spaces_within_braces = false +ij_protobuf_spaces_within_brackets = false + +[*.sass] +indent_size = 2 +indent_style = space +ij_sass_align_closing_brace_with_properties = false +ij_sass_blank_lines_around_nested_selector = 1 +ij_sass_blank_lines_between_blocks = 1 +ij_sass_brace_placement = 0 +ij_sass_enforce_quotes_on_format = false +ij_sass_hex_color_long_format = false +ij_sass_hex_color_lower_case = false +ij_sass_hex_color_short_format = false +ij_sass_hex_color_upper_case = false +ij_sass_keep_blank_lines_in_code = 2 +ij_sass_keep_indents_on_empty_lines = false +ij_sass_keep_single_line_blocks = false +ij_sass_line_comment_add_space = false +ij_sass_line_comment_at_first_column = false +ij_sass_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_sass_space_after_colon = true +ij_sass_space_before_opening_brace = true +ij_sass_use_double_quotes = true +ij_sass_value_alignment = 0 + +[*.scala] +ij_continuation_indent_size = 4 +ij_smart_tabs = true +ij_scala_align_composite_pattern = true +ij_scala_align_extends_with = 0 +ij_scala_align_group_field_declarations = false +ij_scala_align_if_else = false +ij_scala_align_in_columns_case_branch = false +ij_scala_align_multiline_binary_operation = false +ij_scala_align_multiline_chained_methods = false +ij_scala_align_multiline_for = true +ij_scala_align_multiline_parameters = false +ij_scala_align_multiline_parameters_in_calls = false +ij_scala_align_multiline_parenthesized_expression = false +ij_scala_align_parameter_types_in_multiline_declarations = 0 +ij_scala_align_tuple_elements = false +ij_scala_alternate_continuation_indent_for_params = 4 +ij_scala_binary_operation_wrap = off +ij_scala_blank_lines_after_anonymous_class_header = 0 +ij_scala_blank_lines_after_class_header = 0 +ij_scala_blank_lines_after_imports = 1 +ij_scala_blank_lines_after_package = 1 +ij_scala_blank_lines_around_class = 1 +ij_scala_blank_lines_around_class_in_inner_scopes = 0 +ij_scala_blank_lines_around_field = 0 +ij_scala_blank_lines_around_field_in_inner_scopes = 0 +ij_scala_blank_lines_around_field_in_interface = 0 +ij_scala_blank_lines_around_method = 1 +ij_scala_blank_lines_around_method_in_inner_scopes = 1 +ij_scala_blank_lines_around_method_in_interface = 1 +ij_scala_blank_lines_before_class_end = 0 +ij_scala_blank_lines_before_imports = 1 +ij_scala_blank_lines_before_method_body = 0 +ij_scala_blank_lines_before_package = 0 +ij_scala_block_brace_style = end_of_line +ij_scala_block_comment_add_space = false +ij_scala_block_comment_at_first_column = true +ij_scala_call_parameters_new_line_after_lparen = 0 +ij_scala_call_parameters_right_paren_on_new_line = false +ij_scala_call_parameters_wrap = off +ij_scala_case_clause_brace_force = never +ij_scala_catch_on_new_line = false +ij_scala_class_annotation_wrap = split_into_lines +ij_scala_class_brace_style = end_of_line +ij_scala_closure_brace_force = never +ij_scala_do_not_align_block_expr_params = true +ij_scala_do_not_indent_case_clause_body = false +ij_scala_do_not_indent_tuples_close_brace = true +ij_scala_do_while_brace_force = never +ij_scala_else_on_new_line = false +ij_scala_enable_scaladoc_formatting = true +ij_scala_enforce_functional_syntax_for_unit = true +ij_scala_extends_keyword_wrap = off +ij_scala_extends_list_wrap = off +ij_scala_field_annotation_wrap = split_into_lines +ij_scala_finally_brace_force = never +ij_scala_finally_on_new_line = false +ij_scala_for_brace_force = never +ij_scala_for_statement_wrap = off +ij_scala_formatter = 0 +ij_scala_if_brace_force = never +ij_scala_implicit_value_class_prefix = +ij_scala_implicit_value_class_suffix = Ops +ij_scala_indent_braced_function_args = true +ij_scala_indent_case_from_switch = true +ij_scala_indent_fewer_braces_in_method_call_chains = false +ij_scala_indent_first_parameter = true +ij_scala_indent_first_parameter_clause = false +ij_scala_indent_type_arguments = true +ij_scala_indent_type_parameters = true +ij_scala_indent_yield_after_one_line_enumerators = true +ij_scala_keep_blank_lines_before_right_brace = 2 +ij_scala_keep_blank_lines_in_code = 2 +ij_scala_keep_blank_lines_in_declarations = 2 +ij_scala_keep_comments_on_same_line = true +ij_scala_keep_first_column_comment = false +ij_scala_keep_indents_on_empty_lines = true +ij_scala_keep_line_breaks = true +ij_scala_keep_one_line_lambdas_in_arg_list = false +ij_scala_keep_simple_blocks_in_one_line = false +ij_scala_keep_simple_methods_in_one_line = false +ij_scala_keep_xml_formatting = false +ij_scala_line_comment_add_space = false +ij_scala_line_comment_at_first_column = true +ij_scala_method_annotation_wrap = split_into_lines +ij_scala_method_brace_force = never +ij_scala_method_brace_style = end_of_line +ij_scala_method_call_chain_wrap = off +ij_scala_method_parameters_new_line_after_left_paren = true +ij_scala_method_parameters_right_paren_on_new_line = true +ij_scala_method_parameters_wrap = off +ij_scala_modifier_list_wrap = false +ij_scala_multiline_string_align_dangling_closing_quotes = false +ij_scala_multiline_string_closing_quotes_on_new_line = true +ij_scala_multiline_string_insert_margin_on_enter = true +ij_scala_multiline_string_margin_char = | +ij_scala_multiline_string_margin_indent = 2 +ij_scala_multiline_string_opening_quotes_on_new_line = true +ij_scala_multiline_string_process_margin_on_copy_paste = true +ij_scala_new_line_after_case_clause_arrow_when_multiline_body = false +ij_scala_newline_after_annotations = false +ij_scala_not_continuation_indent_for_params = false +ij_scala_parameter_annotation_wrap = off +ij_scala_parentheses_expression_new_line_after_left_paren = false +ij_scala_parentheses_expression_right_paren_on_new_line = false +ij_scala_place_closure_parameters_on_new_line = false +ij_scala_place_self_type_on_new_line = true +ij_scala_prefer_parameters_wrap = false +ij_scala_preserve_space_after_method_declaration_name = false +ij_scala_reformat_on_compile = false +ij_scala_replace_case_arrow_with_unicode_char = false +ij_scala_replace_for_generator_arrow_with_unicode_char = false +ij_scala_replace_lambda_with_greek_letter = false +ij_scala_replace_map_arrow_with_unicode_char = false +ij_scala_scalafmt_config_path = +ij_scala_scalafmt_fallback_to_default_settings = false +ij_scala_scalafmt_reformat_on_files_save = false +ij_scala_scalafmt_show_invalid_code_warnings = true +ij_scala_scalafmt_use_intellij_formatter_for_range_format = true +ij_scala_sd_align_exception_comments = true +ij_scala_sd_align_list_item_content = true +ij_scala_sd_align_other_tags_comments = true +ij_scala_sd_align_parameters_comments = true +ij_scala_sd_align_return_comments = true +ij_scala_sd_blank_line_after_parameters_comments = false +ij_scala_sd_blank_line_after_return_comments = false +ij_scala_sd_blank_line_before_parameters = false +ij_scala_sd_blank_line_before_tags = true +ij_scala_sd_blank_line_between_parameters = false +ij_scala_sd_keep_blank_lines_between_tags = true +ij_scala_sd_preserve_spaces_in_tags = false +ij_scala_space_after_comma = true +ij_scala_space_after_for_semicolon = true +ij_scala_space_after_modifiers_constructor = true +ij_scala_space_after_type_colon = true +ij_scala_space_before_brace_method_call = true +ij_scala_space_before_class_left_brace = true +ij_scala_space_before_for_parentheses = true +ij_scala_space_before_if_parentheses = true +ij_scala_space_before_infix_like_method_parentheses = false +ij_scala_space_before_infix_method_call_parentheses = false +ij_scala_space_before_infix_operator_like_method_call_parentheses = false +ij_scala_space_before_method_call_parentheses = false +ij_scala_space_before_method_left_brace = true +ij_scala_space_before_method_parentheses = true +ij_scala_space_before_type_colon = false +ij_scala_space_before_type_parameter_in_def_list = false +ij_scala_space_before_type_parameter_leading_context_bound_colon = false +ij_scala_space_before_type_parameter_leading_context_bound_colon_hk = true +ij_scala_space_before_type_parameter_list = false +ij_scala_space_before_type_parameter_rest_context_bound_colons = true +ij_scala_space_before_while_parentheses = true +ij_scala_space_inside_closure_braces = true +ij_scala_space_inside_self_type_braces = true +ij_scala_space_within_empty_method_call_parentheses = false +ij_scala_spaces_around_at_in_patterns = false +ij_scala_spaces_in_imports = false +ij_scala_spaces_in_one_line_blocks = false +ij_scala_spaces_within_brackets = false +ij_scala_spaces_within_for_parentheses = false +ij_scala_spaces_within_if_parentheses = false +ij_scala_spaces_within_method_call_parentheses = false +ij_scala_spaces_within_method_parentheses = false +ij_scala_spaces_within_parentheses = false +ij_scala_spaces_within_while_parentheses = false +ij_scala_special_else_if_treatment = true +ij_scala_trailing_comma_arg_list_enabled = true +ij_scala_trailing_comma_import_selector_enabled = false +ij_scala_trailing_comma_mode = trailing_comma_keep +ij_scala_trailing_comma_params_enabled = true +ij_scala_trailing_comma_pattern_arg_list_enabled = false +ij_scala_trailing_comma_tuple_enabled = false +ij_scala_trailing_comma_tuple_type_enabled = false +ij_scala_trailing_comma_type_params_enabled = false +ij_scala_try_brace_force = never +ij_scala_type_annotation_exclude_constant = true +ij_scala_type_annotation_exclude_in_dialect_sources = true +ij_scala_type_annotation_exclude_in_test_sources = false +ij_scala_type_annotation_exclude_member_of_anonymous_class = false +ij_scala_type_annotation_exclude_member_of_private_class = false +ij_scala_type_annotation_exclude_when_type_is_stable = true +ij_scala_type_annotation_function_parameter = false +ij_scala_type_annotation_implicit_modifier = true +ij_scala_type_annotation_local_definition = false +ij_scala_type_annotation_private_member = false +ij_scala_type_annotation_protected_member = true +ij_scala_type_annotation_public_member = true +ij_scala_type_annotation_structural_type = true +ij_scala_type_annotation_underscore_parameter = false +ij_scala_type_annotation_unit_type = true +ij_scala_use_alternate_continuation_indent_for_params = false +ij_scala_use_scala3_indentation_based_syntax = true +ij_scala_use_scaladoc2_formatting = true +ij_scala_variable_annotation_wrap = off +ij_scala_while_brace_force = never +ij_scala_while_on_new_line = false +ij_scala_wrap_before_with_keyword = false +ij_scala_wrap_first_method_in_call_chain = false +ij_scala_wrap_long_lines = false + +[*.scss] +indent_size = 2 +indent_style = space +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_block_comment_add_space = false +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 +ij_scss_hex_color_upper_case = false +ij_scss_keep_blank_lines_in_code = 2 +ij_scss_keep_indents_on_empty_lines = false +ij_scss_keep_single_line_blocks = false +ij_scss_line_comment_add_space = false +ij_scss_line_comment_at_first_column = 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 + +[*.vue] +indent_size = 2 +indent_style = space +tab_width = 2 +ij_continuation_indent_size = 4 +ij_vue_indent_children_of_top_level = template +ij_vue_interpolation_new_line_after_start_delimiter = true +ij_vue_interpolation_new_line_before_end_delimiter = true +ij_vue_interpolation_wrap = off +ij_vue_keep_indents_on_empty_lines = false +ij_vue_spaces_within_interpolation_expressions = true + [.editorconfig] ij_editorconfig_align_group_field_declarations = false ij_editorconfig_space_after_colon = false @@ -276,7 +660,7 @@ ij_editorconfig_space_before_colon = false ij_editorconfig_space_before_comma = false ij_editorconfig_spaces_around_assignment_operators = true -[{*.ant,*.fxml,*.isc,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdd,*.wsdl,*.xjb,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] +[{*.ant,*.fxml,*.isc,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] ij_smart_tabs = true ij_xml_align_attributes = false ij_xml_align_text = false @@ -297,7 +681,367 @@ ij_xml_space_inside_empty_tag = true ij_xml_text_wrap = normal ij_xml_use_custom_settings = false -[{*.gant,*.groovy,*.gson,*.gy}] +[{*.ats,*.cts,*.mts,*.ts}] +ij_continuation_indent_size = 4 +ij_smart_tabs = true +ij_typescript_align_imports = false +ij_typescript_align_multiline_array_initializer_expression = false +ij_typescript_align_multiline_binary_operation = false +ij_typescript_align_multiline_chained_methods = false +ij_typescript_align_multiline_extends_list = false +ij_typescript_align_multiline_for = false +ij_typescript_align_multiline_parameters = false +ij_typescript_align_multiline_parameters_in_calls = false +ij_typescript_align_multiline_ternary_operation = false +ij_typescript_align_object_properties = 0 +ij_typescript_align_union_types = false +ij_typescript_align_var_statements = 0 +ij_typescript_array_initializer_new_line_after_left_brace = false +ij_typescript_array_initializer_right_brace_on_new_line = false +ij_typescript_array_initializer_wrap = off +ij_typescript_assignment_wrap = off +ij_typescript_binary_operation_sign_on_next_line = false +ij_typescript_binary_operation_wrap = off +ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_typescript_blank_lines_after_imports = 1 +ij_typescript_blank_lines_around_class = 1 +ij_typescript_blank_lines_around_field = 0 +ij_typescript_blank_lines_around_field_in_interface = 0 +ij_typescript_blank_lines_around_function = 1 +ij_typescript_blank_lines_around_method = 1 +ij_typescript_blank_lines_around_method_in_interface = 1 +ij_typescript_block_brace_style = end_of_line +ij_typescript_block_comment_add_space = false +ij_typescript_block_comment_at_first_column = true +ij_typescript_call_parameters_new_line_after_left_paren = true +ij_typescript_call_parameters_right_paren_on_new_line = true +ij_typescript_call_parameters_wrap = normal +ij_typescript_catch_on_new_line = false +ij_typescript_chained_call_dot_on_new_line = true +ij_typescript_class_brace_style = end_of_line +ij_typescript_comma_on_new_line = false +ij_typescript_do_while_brace_force = never +ij_typescript_else_on_new_line = false +ij_typescript_enforce_trailing_comma = keep +ij_typescript_enum_constants_wrap = on_every_item +ij_typescript_extends_keyword_wrap = off +ij_typescript_extends_list_wrap = off +ij_typescript_field_prefix = _ +ij_typescript_file_name_style = relaxed +ij_typescript_finally_on_new_line = false +ij_typescript_for_brace_force = never +ij_typescript_for_statement_new_line_after_left_paren = true +ij_typescript_for_statement_right_paren_on_new_line = true +ij_typescript_for_statement_wrap = on_every_item +ij_typescript_force_quote_style = false +ij_typescript_force_semicolon_style = false +ij_typescript_function_expression_brace_style = end_of_line +ij_typescript_if_brace_force = never +ij_typescript_import_merge_members = global +ij_typescript_import_prefer_absolute_path = global +ij_typescript_import_sort_members = true +ij_typescript_import_sort_module_name = false +ij_typescript_import_use_node_resolution = true +ij_typescript_imports_wrap = on_every_item +ij_typescript_indent_case_from_switch = true +ij_typescript_indent_chained_calls = false +ij_typescript_indent_package_children = 0 +ij_typescript_jsdoc_include_types = false +ij_typescript_jsx_attribute_value = braces +ij_typescript_keep_blank_lines_in_code = 2 +ij_typescript_keep_first_column_comment = false +ij_typescript_keep_indents_on_empty_lines = true +ij_typescript_keep_line_breaks = true +ij_typescript_keep_simple_blocks_in_one_line = false +ij_typescript_keep_simple_methods_in_one_line = false +ij_typescript_line_comment_add_space = true +ij_typescript_line_comment_at_first_column = false +ij_typescript_method_brace_style = end_of_line +ij_typescript_method_call_chain_wrap = off +ij_typescript_method_parameters_new_line_after_left_paren = true +ij_typescript_method_parameters_right_paren_on_new_line = true +ij_typescript_method_parameters_wrap = on_every_item +ij_typescript_object_literal_wrap = on_every_item +ij_typescript_object_types_wrap = on_every_item +ij_typescript_parentheses_expression_new_line_after_left_paren = true +ij_typescript_parentheses_expression_right_paren_on_new_line = true +ij_typescript_place_assignment_sign_on_next_line = false +ij_typescript_prefer_as_type_cast = false +ij_typescript_prefer_explicit_types_function_expression_returns = false +ij_typescript_prefer_explicit_types_function_returns = false +ij_typescript_prefer_explicit_types_vars_fields = false +ij_typescript_prefer_parameters_wrap = false +ij_typescript_property_prefix = +ij_typescript_reformat_c_style_comments = false +ij_typescript_space_after_colon = true +ij_typescript_space_after_comma = true +ij_typescript_space_after_dots_in_rest_parameter = false +ij_typescript_space_after_generator_mult = true +ij_typescript_space_after_property_colon = true +ij_typescript_space_after_quest = true +ij_typescript_space_after_type_colon = true +ij_typescript_space_after_unary_not = false +ij_typescript_space_before_async_arrow_lparen = true +ij_typescript_space_before_catch_keyword = true +ij_typescript_space_before_catch_left_brace = true +ij_typescript_space_before_catch_parentheses = true +ij_typescript_space_before_class_lbrace = true +ij_typescript_space_before_class_left_brace = true +ij_typescript_space_before_colon = true +ij_typescript_space_before_comma = false +ij_typescript_space_before_do_left_brace = true +ij_typescript_space_before_else_keyword = true +ij_typescript_space_before_else_left_brace = true +ij_typescript_space_before_finally_keyword = true +ij_typescript_space_before_finally_left_brace = true +ij_typescript_space_before_for_left_brace = true +ij_typescript_space_before_for_parentheses = true +ij_typescript_space_before_for_semicolon = false +ij_typescript_space_before_function_left_parenth = true +ij_typescript_space_before_generator_mult = false +ij_typescript_space_before_if_left_brace = true +ij_typescript_space_before_if_parentheses = true +ij_typescript_space_before_method_call_parentheses = false +ij_typescript_space_before_method_left_brace = true +ij_typescript_space_before_method_parentheses = true +ij_typescript_space_before_property_colon = false +ij_typescript_space_before_quest = true +ij_typescript_space_before_switch_left_brace = true +ij_typescript_space_before_switch_parentheses = true +ij_typescript_space_before_try_left_brace = true +ij_typescript_space_before_type_colon = false +ij_typescript_space_before_unary_not = false +ij_typescript_space_before_while_keyword = true +ij_typescript_space_before_while_left_brace = true +ij_typescript_space_before_while_parentheses = true +ij_typescript_spaces_around_additive_operators = true +ij_typescript_spaces_around_arrow_function_operator = true +ij_typescript_spaces_around_assignment_operators = true +ij_typescript_spaces_around_bitwise_operators = true +ij_typescript_spaces_around_equality_operators = true +ij_typescript_spaces_around_logical_operators = true +ij_typescript_spaces_around_multiplicative_operators = true +ij_typescript_spaces_around_relational_operators = true +ij_typescript_spaces_around_shift_operators = true +ij_typescript_spaces_around_unary_operator = false +ij_typescript_spaces_within_array_initializer_brackets = false +ij_typescript_spaces_within_brackets = false +ij_typescript_spaces_within_catch_parentheses = false +ij_typescript_spaces_within_for_parentheses = false +ij_typescript_spaces_within_if_parentheses = false +ij_typescript_spaces_within_imports = false +ij_typescript_spaces_within_interpolation_expressions = false +ij_typescript_spaces_within_method_call_parentheses = false +ij_typescript_spaces_within_method_parentheses = false +ij_typescript_spaces_within_object_literal_braces = false +ij_typescript_spaces_within_object_type_braces = false +ij_typescript_spaces_within_parentheses = false +ij_typescript_spaces_within_switch_parentheses = false +ij_typescript_spaces_within_type_assertion = false +ij_typescript_spaces_within_union_types = true +ij_typescript_spaces_within_while_parentheses = false +ij_typescript_special_else_if_treatment = true +ij_typescript_ternary_operation_signs_on_next_line = false +ij_typescript_ternary_operation_wrap = off +ij_typescript_union_types_wrap = on_every_item +ij_typescript_use_chained_calls_group_indents = false +ij_typescript_use_double_quotes = true +ij_typescript_use_explicit_js_extension = auto +ij_typescript_use_path_mapping = always +ij_typescript_use_public_modifier = false +ij_typescript_use_semicolon_after_statement = true +ij_typescript_var_declaration_wrap = normal +ij_typescript_while_brace_force = never +ij_typescript_while_on_new_line = false +ij_typescript_wrap_comments = false + +[{*.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 = true +ij_shell_use_unix_line_separator = true + +[{*.cjs,*.js}] +ij_continuation_indent_size = 4 +ij_javascript_align_imports = false +ij_javascript_align_multiline_array_initializer_expression = false +ij_javascript_align_multiline_binary_operation = false +ij_javascript_align_multiline_chained_methods = false +ij_javascript_align_multiline_extends_list = false +ij_javascript_align_multiline_for = true +ij_javascript_align_multiline_parameters = true +ij_javascript_align_multiline_parameters_in_calls = false +ij_javascript_align_multiline_ternary_operation = false +ij_javascript_align_object_properties = 0 +ij_javascript_align_union_types = false +ij_javascript_align_var_statements = 0 +ij_javascript_array_initializer_new_line_after_left_brace = true +ij_javascript_array_initializer_right_brace_on_new_line = true +ij_javascript_array_initializer_wrap = on_every_item +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/**,**/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_comment_add_space = false +ij_javascript_block_comment_at_first_column = true +ij_javascript_call_parameters_new_line_after_left_paren = true +ij_javascript_call_parameters_right_paren_on_new_line = true +ij_javascript_call_parameters_wrap = on_every_item +ij_javascript_catch_on_new_line = false +ij_javascript_chained_call_dot_on_new_line = false +ij_javascript_class_brace_style = end_of_line +ij_javascript_comma_on_new_line = false +ij_javascript_do_while_brace_force = never +ij_javascript_else_on_new_line = false +ij_javascript_enforce_trailing_comma = remove +ij_javascript_extends_keyword_wrap = off +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 = if_multiline +ij_javascript_for_statement_new_line_after_left_paren = true +ij_javascript_for_statement_right_paren_on_new_line = true +ij_javascript_for_statement_wrap = on_every_item +ij_javascript_force_quote_style = false +ij_javascript_force_semicolon_style = false +ij_javascript_function_expression_brace_style = end_of_line +ij_javascript_if_brace_force = never +ij_javascript_import_merge_members = global +ij_javascript_import_prefer_absolute_path = global +ij_javascript_import_sort_members = true +ij_javascript_import_sort_module_name = false +ij_javascript_import_use_node_resolution = true +ij_javascript_imports_wrap = on_every_item +ij_javascript_indent_case_from_switch = true +ij_javascript_indent_chained_calls = false +ij_javascript_indent_package_children = 0 +ij_javascript_jsx_attribute_value = braces +ij_javascript_keep_blank_lines_in_code = 2 +ij_javascript_keep_first_column_comment = true +ij_javascript_keep_indents_on_empty_lines = true +ij_javascript_keep_line_breaks = true +ij_javascript_keep_simple_blocks_in_one_line = false +ij_javascript_keep_simple_methods_in_one_line = false +ij_javascript_line_comment_add_space = true +ij_javascript_line_comment_at_first_column = false +ij_javascript_method_brace_style = end_of_line +ij_javascript_method_call_chain_wrap = off +ij_javascript_method_parameters_new_line_after_left_paren = true +ij_javascript_method_parameters_right_paren_on_new_line = true +ij_javascript_method_parameters_wrap = on_every_item +ij_javascript_object_literal_wrap = on_every_item +ij_javascript_object_types_wrap = on_every_item +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_property_prefix = +ij_javascript_reformat_c_style_comments = true +ij_javascript_space_after_colon = true +ij_javascript_space_after_comma = true +ij_javascript_space_after_dots_in_rest_parameter = false +ij_javascript_space_after_generator_mult = true +ij_javascript_space_after_property_colon = true +ij_javascript_space_after_quest = true +ij_javascript_space_after_type_colon = true +ij_javascript_space_after_unary_not = false +ij_javascript_space_before_async_arrow_lparen = true +ij_javascript_space_before_catch_keyword = true +ij_javascript_space_before_catch_left_brace = true +ij_javascript_space_before_catch_parentheses = true +ij_javascript_space_before_class_lbrace = true +ij_javascript_space_before_class_left_brace = true +ij_javascript_space_before_colon = true +ij_javascript_space_before_comma = false +ij_javascript_space_before_do_left_brace = true +ij_javascript_space_before_else_keyword = true +ij_javascript_space_before_else_left_brace = true +ij_javascript_space_before_finally_keyword = true +ij_javascript_space_before_finally_left_brace = true +ij_javascript_space_before_for_left_brace = true +ij_javascript_space_before_for_parentheses = true +ij_javascript_space_before_for_semicolon = false +ij_javascript_space_before_function_left_parenth = true +ij_javascript_space_before_generator_mult = true +ij_javascript_space_before_if_left_brace = true +ij_javascript_space_before_if_parentheses = true +ij_javascript_space_before_method_call_parentheses = false +ij_javascript_space_before_method_left_brace = true +ij_javascript_space_before_method_parentheses = true +ij_javascript_space_before_property_colon = false +ij_javascript_space_before_quest = true +ij_javascript_space_before_switch_left_brace = true +ij_javascript_space_before_switch_parentheses = true +ij_javascript_space_before_try_left_brace = true +ij_javascript_space_before_type_colon = false +ij_javascript_space_before_unary_not = false +ij_javascript_space_before_while_keyword = true +ij_javascript_space_before_while_left_brace = true +ij_javascript_space_before_while_parentheses = true +ij_javascript_spaces_around_additive_operators = true +ij_javascript_spaces_around_arrow_function_operator = true +ij_javascript_spaces_around_assignment_operators = true +ij_javascript_spaces_around_bitwise_operators = true +ij_javascript_spaces_around_equality_operators = true +ij_javascript_spaces_around_logical_operators = true +ij_javascript_spaces_around_multiplicative_operators = true +ij_javascript_spaces_around_relational_operators = true +ij_javascript_spaces_around_shift_operators = true +ij_javascript_spaces_around_unary_operator = false +ij_javascript_spaces_within_array_initializer_brackets = false +ij_javascript_spaces_within_brackets = false +ij_javascript_spaces_within_catch_parentheses = false +ij_javascript_spaces_within_for_parentheses = false +ij_javascript_spaces_within_if_parentheses = false +ij_javascript_spaces_within_imports = false +ij_javascript_spaces_within_interpolation_expressions = false +ij_javascript_spaces_within_method_call_parentheses = false +ij_javascript_spaces_within_method_parentheses = false +ij_javascript_spaces_within_object_literal_braces = false +ij_javascript_spaces_within_object_type_braces = true +ij_javascript_spaces_within_parentheses = false +ij_javascript_spaces_within_switch_parentheses = false +ij_javascript_spaces_within_type_assertion = false +ij_javascript_spaces_within_union_types = true +ij_javascript_spaces_within_while_parentheses = false +ij_javascript_special_else_if_treatment = true +ij_javascript_ternary_operation_signs_on_next_line = false +ij_javascript_ternary_operation_wrap = on_every_item +ij_javascript_union_types_wrap = on_every_item +ij_javascript_use_chained_calls_group_indents = false +ij_javascript_use_double_quotes = false +ij_javascript_use_explicit_js_extension = auto +ij_javascript_use_path_mapping = always +ij_javascript_use_public_modifier = false +ij_javascript_use_semicolon_after_statement = false +ij_javascript_var_declaration_wrap = normal +ij_javascript_while_brace_force = never +ij_javascript_while_on_new_line = false +ij_javascript_wrap_comments = false + +[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.tesc,*.tese,*.vert,*.vsh}] +ij_glsl_keep_indents_on_empty_lines = true + +[{*.ft,*.vm,*.vsl}] +ij_smart_tabs = true +ij_vtl_keep_indents_on_empty_lines = true + +[{*.gant,*.groovy,*.gy}] ij_smart_tabs = true ij_groovy_align_group_field_declarations = false ij_groovy_align_multiline_array_initializer_expression = false @@ -344,6 +1088,7 @@ ij_groovy_class_brace_style = end_of_line ij_groovy_class_count_to_use_import_on_demand = 5 ij_groovy_do_while_brace_force = never ij_groovy_else_on_new_line = true +ij_groovy_enable_groovydoc_formatting = true ij_groovy_enum_constants_wrap = on_every_item ij_groovy_extends_keyword_wrap = normal ij_groovy_extends_list_wrap = off @@ -353,6 +1098,12 @@ ij_groovy_for_brace_force = never ij_groovy_for_statement_new_line_after_left_paren = true ij_groovy_for_statement_right_paren_on_new_line = true ij_groovy_for_statement_wrap = on_every_item +ij_groovy_ginq_general_clause_wrap_policy = 2 +ij_groovy_ginq_having_wrap_policy = 1 +ij_groovy_ginq_indent_having_clause = true +ij_groovy_ginq_indent_on_clause = true +ij_groovy_ginq_on_wrap_policy = 1 +ij_groovy_ginq_space_after_keyword = true ij_groovy_if_brace_force = never ij_groovy_import_annotation_wrap = 2 ij_groovy_imports_layout = *,|,javax.**,java.**,|,$* @@ -376,6 +1127,7 @@ ij_groovy_label_indent_size = 0 ij_groovy_lambda_brace_style = end_of_line ij_groovy_layout_static_imports_separately = true ij_groovy_line_comment_add_space = false +ij_groovy_line_comment_add_space_on_reformat = false ij_groovy_line_comment_at_first_column = true ij_groovy_method_annotation_wrap = split_into_lines ij_groovy_method_brace_style = end_of_line @@ -481,6 +1233,109 @@ ij_groovy_while_on_new_line = false ij_groovy_wrap_chain_calls_after_dot = false ij_groovy_wrap_long_lines = false +[{*.gradle.kts,*.kt,*.kts,*.main.kts,*.space.kts}] +ij_smart_tabs = true +ij_kotlin_align_in_columns_case_branch = false +ij_kotlin_align_multiline_binary_operation = false +ij_kotlin_align_multiline_extends_list = false +ij_kotlin_align_multiline_method_parentheses = false +ij_kotlin_align_multiline_parameters = true +ij_kotlin_align_multiline_parameters_in_calls = true +ij_kotlin_allow_trailing_comma = false +ij_kotlin_allow_trailing_comma_on_call_site = false +ij_kotlin_assignment_wrap = normal +ij_kotlin_blank_lines_after_class_header = 1 +ij_kotlin_blank_lines_around_block_when_branches = 0 +ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 +ij_kotlin_block_comment_add_space = false +ij_kotlin_block_comment_at_first_column = true +ij_kotlin_call_parameters_new_line_after_left_paren = true +ij_kotlin_call_parameters_right_paren_on_new_line = true +ij_kotlin_call_parameters_wrap = on_every_item +ij_kotlin_catch_on_new_line = false +ij_kotlin_class_annotation_wrap = split_into_lines +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +ij_kotlin_continuation_indent_for_chained_calls = false +ij_kotlin_continuation_indent_for_expression_bodies = false +ij_kotlin_continuation_indent_in_argument_lists = false +ij_kotlin_continuation_indent_in_elvis = false +ij_kotlin_continuation_indent_in_if_conditions = false +ij_kotlin_continuation_indent_in_parameter_lists = false +ij_kotlin_continuation_indent_in_supertype_lists = false +ij_kotlin_else_on_new_line = false +ij_kotlin_enum_constants_wrap = on_every_item +ij_kotlin_extends_list_wrap = on_every_item +ij_kotlin_field_annotation_wrap = split_into_lines +ij_kotlin_finally_on_new_line = false +ij_kotlin_if_rparen_on_new_line = true +ij_kotlin_import_nested_classes = false +ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ +ij_kotlin_insert_whitespaces_in_simple_one_line_method = true +ij_kotlin_keep_blank_lines_before_right_brace = 2 +ij_kotlin_keep_blank_lines_in_code = 2 +ij_kotlin_keep_blank_lines_in_declarations = 2 +ij_kotlin_keep_first_column_comment = false +ij_kotlin_keep_indents_on_empty_lines = true +ij_kotlin_keep_line_breaks = true +ij_kotlin_lbrace_on_next_line = false +ij_kotlin_line_break_after_multiline_when_entry = true +ij_kotlin_line_comment_add_space = false +ij_kotlin_line_comment_add_space_on_reformat = false +ij_kotlin_line_comment_at_first_column = true +ij_kotlin_method_annotation_wrap = split_into_lines +ij_kotlin_method_call_chain_wrap = on_every_item +ij_kotlin_method_parameters_new_line_after_left_paren = true +ij_kotlin_method_parameters_right_paren_on_new_line = true +ij_kotlin_method_parameters_wrap = on_every_item +ij_kotlin_name_count_to_use_star_import = 5 +ij_kotlin_name_count_to_use_star_import_for_members = 3 +ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.** +ij_kotlin_parameter_annotation_wrap = off +ij_kotlin_space_after_comma = true +ij_kotlin_space_after_extend_colon = true +ij_kotlin_space_after_type_colon = true +ij_kotlin_space_before_catch_parentheses = true +ij_kotlin_space_before_comma = false +ij_kotlin_space_before_extend_colon = true +ij_kotlin_space_before_for_parentheses = true +ij_kotlin_space_before_if_parentheses = true +ij_kotlin_space_before_lambda_arrow = true +ij_kotlin_space_before_type_colon = false +ij_kotlin_space_before_when_parentheses = true +ij_kotlin_space_before_while_parentheses = true +ij_kotlin_spaces_around_additive_operators = true +ij_kotlin_spaces_around_assignment_operators = true +ij_kotlin_spaces_around_equality_operators = true +ij_kotlin_spaces_around_function_type_arrow = true +ij_kotlin_spaces_around_logical_operators = true +ij_kotlin_spaces_around_multiplicative_operators = true +ij_kotlin_spaces_around_range = false +ij_kotlin_spaces_around_relational_operators = true +ij_kotlin_spaces_around_unary_operator = false +ij_kotlin_spaces_around_when_arrow = true +ij_kotlin_variable_annotation_wrap = off +ij_kotlin_while_on_new_line = false +ij_kotlin_wrap_elvis_expressions = 1 +ij_kotlin_wrap_expression_body_functions = 1 +ij_kotlin_wrap_first_method_in_call_chain = false + +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.conf,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config,mcmod.info,meatball_from_mutton.json,pack.mcmeta}] +ij_smart_tabs = true +ij_json_array_wrapping = split_into_lines +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = true +ij_json_keep_line_breaks = true +ij_json_keep_trailing_comma = false +ij_json_object_wrapping = split_into_lines +ij_json_property_alignment = do_not_align +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = false +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,*.ng,*.sht,*.shtm,*.shtml}] ij_smart_tabs = true ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 @@ -491,7 +1346,7 @@ ij_html_block_comment_add_space = false ij_html_block_comment_at_first_column = true ij_html_do_not_align_children_of_min_lines = 0 ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p -ij_html_do_not_indent_children_of_tags = none +ij_html_do_not_indent_children_of_tags = ij_html_enforce_quotes = false ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var ij_html_keep_blank_lines = 0 @@ -510,19 +1365,56 @@ ij_html_space_around_equality_in_attribute = false ij_html_space_inside_empty_tag = true ij_html_text_wrap = off +[{*.http,*.rest}] +indent_size = 0 +ij_continuation_indent_size = 4 +ij_http-request_call_parameters_wrap = normal +ij_http-request_method_parameters_wrap = split_into_lines +ij_http-request_space_before_comma = true +ij_http-request_spaces_around_assignment_operators = true + +[{*.jsf,*.jsp,*.jspf,*.tag,*.tagf,*.xjsp}] +ij_smart_tabs = true +ij_jsp_jsp_prefer_comma_separated_import_list = false +ij_jsp_keep_indents_on_empty_lines = true + +[{*.jspx,*.tagx}] +ij_smart_tabs = true +ij_jspx_keep_indents_on_empty_lines = true + [{*.markdown,*.md}] ij_smart_tabs = true ij_markdown_force_one_space_after_blockquote_symbol = true ij_markdown_force_one_space_after_header_symbol = true ij_markdown_force_one_space_after_list_bullet = true ij_markdown_force_one_space_between_words = true +ij_markdown_format_tables = true +ij_markdown_insert_quote_arrows_on_wrap = true ij_markdown_keep_indents_on_empty_lines = true +ij_markdown_keep_line_breaks_inside_text_blocks = true ij_markdown_max_lines_around_block_elements = 1 ij_markdown_max_lines_around_header = 1 ij_markdown_max_lines_between_paragraphs = 1 ij_markdown_min_lines_around_block_elements = 1 ij_markdown_min_lines_around_header = 1 ij_markdown_min_lines_between_paragraphs = 1 +ij_markdown_wrap_text_if_long = true +ij_markdown_wrap_text_inside_blockquotes = true + +[{*.pb,*.textproto}] +indent_size = 2 +indent_style = space +tab_width = 2 +ij_continuation_indent_size = 4 +ij_prototext_keep_blank_lines_in_code = 2 +ij_prototext_keep_indents_on_empty_lines = false +ij_prototext_keep_line_breaks = true +ij_prototext_space_after_colon = true +ij_prototext_space_after_comma = true +ij_prototext_space_before_colon = false +ij_prototext_space_before_comma = false +ij_prototext_spaces_within_braces = true +ij_prototext_spaces_within_brackets = false [{*.properties,spring.handlers,spring.schemas}] ij_properties_align_group_field_declarations = false @@ -530,3 +1422,23 @@ ij_properties_keep_blank_lines = true ij_properties_key_value_delimiter = equals ij_properties_spaces_around_key_value_delimiter = true +[{*.qute.htm,*.qute.html,*.qute.json,*.qute.txt,*.qute.yaml,*.qute.yml}] +indent_style = space +ij_qute_keep_indents_on_empty_lines = false + +[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}] +indent_style = space +ij_toml_keep_indents_on_empty_lines = false + +[{*.yaml,*.yml}] +indent_size = 2 +ij_yaml_align_values_properties = do_not_align +ij_yaml_autoinsert_sequence_marker = true +ij_yaml_block_mapping_on_new_line = false +ij_yaml_indent_sequence_value = true +ij_yaml_keep_indents_on_empty_lines = true +ij_yaml_keep_line_breaks = true +ij_yaml_sequence_on_new_line = false +ij_yaml_space_before_colon = false +ij_yaml_spaces_within_braces = true +ij_yaml_spaces_within_brackets = true diff --git a/.gitignore b/.gitignore index e23a3f5..f9ff432 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ .vscode/ .gradle/ .settings/ -/src/test/java/test/* -/src/test/resources/test/* #build /build/ diff --git a/build.gradle b/build.gradle index f0041ee..deb0e57 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id 'java-library' id 'application' id 'maven-publish' + id "io.github.ysohda.scalatest" version "0.32.1" id 'com.github.johnrengelman.shadow' version '8.1.1' id 'com.github.gmazzo.buildconfig' version '4.1.2' id 'org.ajoberstar.grgit' version '5.2.0' @@ -84,8 +85,10 @@ dependencies { implementation "com.squareup.okhttp3:okhttp:${lib_okhttp_v}" implementation "com.google.code.gson:gson:${lib_gson_v}" - testImplementation platform("org.junit:junit-bom:${lib_junit_v}") - testImplementation "org.junit.jupiter:junit-jupiter" + testImplementation "org.scalatest:scalatest_$proj_scala_api:${lib_scalatest_v}" + testImplementation "org.scalatest:scalatest-freespec_$proj_scala_api:${lib_scalatest_v}" + testRuntimeOnly "org.scala-lang.modules:scala-xml_$proj_scala_api:${lib_scalamodule_xml_v}" + testRuntimeOnly 'com.vladsch.flexmark:flexmark-all:0.64.6' // for generating HTML report // required by gradle-scalatest plugin } @@ -108,14 +111,18 @@ tasks.withType(ScalaCompile).configureEach { scalaCompileOptions.additionalParameters.add "-language:postfixOps" // scalaCompileOptions.additionalParameters.add("-Yexplicit-nulls") - +// scalaCompileOptions.additionalParameters.add "-language:experimental.saferExceptions" + } +tasks.withType(Javadoc).configureEach { + options.encoding = proj_file_encoding.name() +} + +//tasks.withType(ScalaDoc).configureEach { +//} + test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } } application { @@ -152,7 +159,7 @@ shadowJar { } -@SuppressWarnings("all") +@SuppressWarnings('GrMethodMayBeStatic') boolean isCleanBuild () { if (grgit == null) return false Set changes = grgit.status().unstaged.allChanges + grgit.status().staged.allChanges diff --git a/gradle.properties b/gradle.properties index 9ce1455..1a9ee69 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,13 +8,14 @@ MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s VERSION = 1.0.0-RC4 USE_DELTA = true -VERSION_DELTA = scalaport3 +VERSION_DELTA = scalaport4 CODENAME = beiping # dependencies lib_spotbugs_v = 4.7.3 +lib_scalamodule_xml_v = 2.2.0 lib_messiva_v = 0.1.1 lib_resourcetools_v = 0.2.2 @@ -24,4 +25,4 @@ lib_javatelegramapi_v = 6.2.0 lib_okhttp_v = 4.11.0 lib_gson_v = 2.10.1 -lib_junit_v = 5.10.0 +lib_scalatest_v = 3.2.17 diff --git a/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java b/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java deleted file mode 100644 index a7df8bc..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java +++ /dev/null @@ -1,98 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -import java.util.HashMap; -import java.util.Map; - -public class BiliTool { - - private static final long V_CONV_XOR = 177451812L; - private static final long V_CONV_ADD = 8728348608L; - private static final char[] BV_TABLE = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF".toCharArray(); - private static final int TABLE_INT = BV_TABLE.length; - private static final Map BV_TABLE_REVERSED = new HashMap<>(); - static { for (int i = 0; i < BV_TABLE.length; i++) BV_TABLE_REVERSED.put(BV_TABLE[i], i); } - private static final char[] BV_TEMPLATE = "1 4 1 7 ".toCharArray(); - private static final int[] BV_TEMPLATE_FILTER = new int[]{9, 8, 1, 6, 2, 4}; - - public static class IllegalFormatException extends RuntimeException { - - private IllegalFormatException (String bv, String reason) { - super("`%s` is not a valid 10 digits base58 BV id: %s".formatted(bv, reason)); - } - - private IllegalFormatException (String bv, int length) { - this(bv, "length is %d.".formatted(length)); - } - - private IllegalFormatException (String bv, char c, int location) { - this(bv, "char `%s` is not in base58 char table (in position %d)".formatted(c, location)); - } - - } - - /** - * Convert a Bilibili AV video id format to BV id format. - *

- * the AV id is a number; the BV id is a special base58 number, it shows as String in programming.
- * eg:
- * while the link {@code https://www.bilibili.com/video/BV17x411w7KC/} - * shows the same with {@code https://www.bilibili.com/video/av170001/}, - * the AV id is {@code 170001}, the BV id is {@code 17x411w7KC} - *

- * for now , the BV id has 10 digits. - * the method available while the av-id < 2^27, while it theoretically available when the av-id < 2^30. - *

- * this method allows input only 10 digits base58 BV id, if the input is not formatted by this method, it will throw - * an Exception. - * - * @see mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」? - * - * @param bv the BV id, a string in (a special) base58 number format, without "BV" prefix. - * @return the AV id corresponding to this bv id in Bilibili, formatted as a number. - * @throws IllegalFormatException if the input BV id is not the 10 digits base58 String. - */ - @Nonnegative - public static long toAv (@Nonnull String bv) throws IllegalFormatException { - long av = 0; - if (bv.length() != 10) - throw new IllegalFormatException(bv, bv.length()); - for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) { - final Integer tableToken = BV_TABLE_REVERSED.get(bv.charAt(BV_TEMPLATE_FILTER[i])); - if (tableToken == null) - throw new IllegalFormatException(bv, bv.charAt(BV_TEMPLATE_FILTER[i]), BV_TEMPLATE_FILTER[i]); - av += tableToken * Math.pow(TABLE_INT,i); - } - return (av-V_CONV_ADD)^V_CONV_XOR; - } - - /** - * Convert a Bilibili BV video id format to AV id format. - *

- * the AV id is a number; the BV id is a special base58 number, it shows as String in programming.
- * eg:
- * while the link {@code https://www.bilibili.com/video/BV17x411w7KC/} - * shows the same with {@code https://www.bilibili.com/video/av170001/}, - * the AV id is {@code 170001}, the BV id is {@code 17x411w7KC} - *

- * for now , the BV id has 10 digits. - * the method available while the av-id < 2^27, while it theoretically available when the av-id < 2^30. - * - * @see mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」? - * - * @param av the (base10) AV id. - * @return the AV id corresponding to this bv id in Bilibili, - * as a (special) base 58 number format without "BV" prefix. - */ - @Nonnull - public static String toBv (@Nonnegative long av) { - av = (av^V_CONV_XOR)+V_CONV_ADD; - final char[] bv = BV_TEMPLATE.clone(); - for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) { - bv[BV_TEMPLATE_FILTER[i]] = BV_TABLE[(int)(Math.floor(av/(Math.pow(TABLE_INT, i)))%TABLE_INT)]; - } - return String.copyValueOf(bv); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java deleted file mode 100644 index 907cdd5..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java +++ /dev/null @@ -1,61 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; - -/** - * 进行简单类型转换等工作的类. - */ -public class CommonConvert { - - /** - * 将字节数组转换成 hex 字符串. - * @param b 字节数组 - * @return String 格式的字节数组的 hex 值(每个字节当中没有分隔符) - * @see #byteToHex(byte) - */ - @Nonnull - public static String byteArrayToHex(@Nonnull byte[] b){ - StringBuilder sb = new StringBuilder(); - for (byte value : b) { - sb.append(byteToHex(value)); - } - return sb.toString(); - } - - /** - * 将一个字节转换成十六进制 hex 字符串. - * @param b 字节值 - * @return String 格式的字节的 hex 值(小写) - */ - @Nonnull - public static String byteToHex(byte b) { - final String hex = Integer.toHexString(b & 0xff); - return hex.length()<2?"0"+hex:hex; - } - - /** - * 将一个字符串数组按照一定规则连接. - *

- * 连接的方式类似于"数据1+分隔符+数据2+分隔符+...+数据n-1+分隔符+数据n" - * - * @param array 需要进行连接的字符串数组,数组中每一个元素会是一个数据 - * @param connector 在每两个传入数据中插入的分隔符 - * @param startIndex 从传入的数据组中的哪一个位置开始(第一个元素的位置是 {@code 0}) - * @param stopIndex 从传入的数据组中的哪一个位置停止(元素位置计算方式同上) - * @return 连接好的字符串 - */ - @Nonnull - public static String stringsConnecting ( - @Nonnull String[] array, @Nonnull String connector, @Nonnegative int startIndex, @Nonnegative int stopIndex - ) { - final StringBuilder builder = new StringBuilder(); - for (int i = startIndex; i < stopIndex; i++) { - builder.append(array[i]); - builder.append(connector); - } - builder.append(array[stopIndex]); - return builder.toString(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java deleted file mode 100644 index 0e9c35d..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java +++ /dev/null @@ -1,144 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnull; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Base64; - -/** - * 用于数据加密或编解码的工具类. - *

- * 出于 java std 中 Base64 的 {@link Base64.Encoder encode}/{@link Base64.Decoder decode} 十分好用,在此不再进行包装。 - */ -public class CommonEncrypt { - - /** - * 在使用加密算法处理字符串时默认会使用的字符串编码. - *

- * Morny 使用 UTF-8 编码因为这是一般而言加解密工具的默认行为 - */ - public static final Charset ENCRYPT_STANDARD_CHARSET = StandardCharsets.UTF_8; - - @Nonnull - private static byte[] hashAsJavaMessageDigest(String algorithm, @Nonnull byte[] data) { - try { - return MessageDigest.getInstance(algorithm).digest(data); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException(e); - } - } - - /** - * 取得数据的 md5 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 md5 散列值 - */ - @Nonnull - public static byte[] hashMd5 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("md5", data); - } - - /** - * 取得一个字符串的 md5 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 md5 散列值 - */ - @Nonnull - public static byte[] hashMd5 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - /** - * 取得数据的 sha1 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 sha1 散列值 - */ - @Nonnull - public static byte[] hashSha1 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("sha1", data); - } - - /** - * 取得一个字符串的 sha1 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 sha1 散列值 - */ - @Nonnull - public static byte[] hashSha1 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - /** - * 取得数据的 sha256 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 sha256 散列值 - */ - @Nonnull - public static byte[] hashSha256 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("sha256", data); - } - - /** - * 取得一个字符串的 sha256 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 sha256 散列值 - */ - @Nonnull - public static byte[] hashSha256 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - /** - * 取得数据的 sha512 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 sha512 散列值 - */ - @Nonnull - public static byte[] hashSha512 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("md5", data); - } - - /** - * 取得一个字符串的 sha512 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 sha512 散列值 - */ - @Nonnull - public static byte[] hashSha512 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - @Nonnull - public static String base64FilenameLint (String inputName) { - if (inputName.endsWith(".b64")) { - return inputName.substring(0, inputName.length()-".b64".length()); - } else if (inputName.endsWith(".b64.txt")) { - return inputName.substring(0, inputName.length()-".b64.txt".length()); - } else if (inputName.endsWith(".base64")) { - return inputName.substring(0, inputName.length()-".base64".length()); - } else if (inputName.endsWith(".base64.txt")) { - return inputName.substring(0, inputName.length()-".base64.txt".length()); - } else { - return inputName; - } - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java deleted file mode 100644 index 0598ba6..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java +++ /dev/null @@ -1,30 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; - -public class CommonFormat { - - public static final String DATE_TIME_PATTERN_FULL_MILLIS = "yyyy-MM-dd HH:mm:ss:SSS"; - - public static String formatDate (long timestamp, int utcOffset) { - return DateTimeFormatter.ofPattern(DATE_TIME_PATTERN_FULL_MILLIS).format(LocalDateTime.ofInstant( - Instant.ofEpochMilli(timestamp), - ZoneId.ofOffset("UTC", ZoneOffset.ofHours(utcOffset)) - )); - } - - public static String formatDuration (long duration) { - StringBuilder sb = new StringBuilder(); - if (duration > 1000 * 60 * 60 * 24) sb.append(duration / (1000*60*60*24)).append("d "); - if (duration > 1000 * 60 * 60) sb.append(duration / (1000*60*60) % 24).append("h "); - if (duration > 1000 * 60) sb.append(duration / (1000*60) % 60).append("min "); - if (duration > 1000) sb.append(duration / 1000 % 60).append("s "); - sb.append(duration % 1000).append("ms"); - return sb.toString(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java deleted file mode 100644 index 22c9812..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java +++ /dev/null @@ -1,44 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnegative; -import java.util.concurrent.ThreadLocalRandom; - -public class CommonRandom { - - /** - * 通过 {@link ThreadLocalRandom} 以指定的一定几率返回 true. - * @param probability 一个正整数,决定在样本空间中有多大的可能性为 true。 - * @param base 一个正整数,决定样本空间有多大。 - * @return 有 {@code base} 分之 {@code probability} 的几率,返回值为 {@link true}. - * 如果 {@code probability} 大于 {@code base},也就是为 true 的可能性大于 100%,则会永远为 true。 - * @throws IllegalArgumentException - * 当参数 base 或是 probability 不为正整数时 - * @since 1.0.0-RC3.2 - */ - public static boolean probabilityTrue (@Nonnegative int probability, @Nonnegative int base) { - if (probability < 1) throw new IllegalArgumentException("the probability must be a positive value!"); - if (base < 1) throw new IllegalArgumentException("the probability base must be a positive value!"); - return probability > ThreadLocalRandom.current().nextInt(base); - } - - /** - * 以一定几率返回 true. - * @return {@code probabilityIn} 分之 {@link 1} 的几率为 {@link true}. - * @see #probabilityTrue(int, int) - * @since 1.0.0-RC3.2 - */ - public static boolean probabilityTrue (@Nonnegative int probabilityIn) { - return (probabilityTrue(1, probabilityIn)); - } - - /** - * 通过 {@link ThreadLocalRandom} 实现的随机 boolean 取值. - * @return 随机的 {@link true} 或 {@link false},各占(近似)一半可能性. - * @see ThreadLocalRandom#nextBoolean() - * @since 1.0.0-RC3.2 - */ - public static boolean iif () { - return ThreadLocalRandom.current().nextBoolean(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java b/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java deleted file mode 100644 index 57ff657..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnull; -import java.io.FileInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class FileUtils { - - @Nonnull - public static String getMD5Three (@Nonnull String path) throws IOException, NoSuchAlgorithmException { - final BigInteger bi; - final byte[] buffer = new byte[8192]; - int len; - final MessageDigest md = MessageDigest.getInstance("MD5"); - final FileInputStream fis = new FileInputStream(path); - while ((len = fis.read(buffer)) != -1) { - md.update(buffer, 0, len); - } - fis.close(); - final byte[] b = md.digest(); - bi = new BigInteger(1, b); - return bi.toString(16); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java b/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java deleted file mode 100644 index fb6b32a..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java +++ /dev/null @@ -1,13 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import okhttp3.MediaType; - -public class OkHttpPublic { - - public static class MediaTypes { - - public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java b/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java deleted file mode 100644 index 2bf2e8e..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnull; -import java.util.ArrayList; - -public class UniversalCommand { - - @Nonnull - public static String[] format (@Nonnull String com) { - - final ArrayList arr = new ArrayList<>(); - - final StringBuilder tmp = new StringBuilder(); - final char[] coma = com.toCharArray(); - for (int i = 0; i < coma.length; i++) { - if (coma[i] == ' ') { - if (!tmp.toString().equals("")) { arr.add(tmp.toString()); } - tmp.setLength(0); - } else if (coma[i] == '"') { - while (true) { - i++; - if (i >= coma.length) { - break; - } else if (coma[i] == '"') { - break; - } else if (coma[i] == '\\' && i+1 < coma.length && (coma[i+1] == '"' || coma[i+1] == '\\')) { - i++; - tmp.append(coma[i]); - } else { - tmp.append(coma[i]); - } - } - } else if (coma[i] == '\\' && i+1 < coma.length && (coma[i+1] == ' ' || coma[i+1] == '"' || coma[i+1] == '\\')) { - i++; - tmp.append(coma[i]); - } else { - tmp.append(coma[i]); - } - } - if (!tmp.toString().equals("")) { arr.add(tmp.toString()); } - tmp.setLength(0); - - final String[] out = new String[arr.size()]; - arr.toArray(out); - return out; - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java deleted file mode 100644 index a62a3c9..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java +++ /dev/null @@ -1,66 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi; - -import cc.sukazyo.cono.morny.util.UniversalCommand; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Arrays; - -public class InputCommand { - - - private final String target; - private final String command; - private final String[] args; - - private InputCommand (@Nullable String target, @Nonnull String command, @Nonnull String[] args) { - this.target = target; - this.command = command; - this.args = args; - } - - public InputCommand (@Nonnull String[] inputArray) { - this(parseInputArray(inputArray)); - } - - public InputCommand (@Nonnull String input) { - this(UniversalCommand.format(input)); - } - - public InputCommand (@Nonnull InputCommand source) { - this(source.target, source.command, source.args); - } - - public static InputCommand parseInputArray (@Nonnull String[] inputArray) { - final String[] cx = inputArray[0].split("@", 2); - final String[] args = new String[inputArray.length-1]; - System.arraycopy(inputArray, 1, args, 0, inputArray.length - 1); - return new InputCommand(cx.length == 1 ? null : cx[1], cx[0], args); - } - - @Nullable - public String getTarget () { - return target; - } - - @Nonnull - public String getCommand () { - return command; - } - - @Nonnull - public String[] getArgs () { - return args; - } - - public boolean hasArgs () { - return args.length != 0; - } - - @Override - @Nonnull - public String toString() { - return String.format("{{%s}@{%s}#{%s}}", command, target, Arrays.toString(args)); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java deleted file mode 100644 index ae3efa3..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java +++ /dev/null @@ -1,7 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi; - -public class Standardize { - - public static final int CHANNEL_SPEAKER_MAGIC_ID = 136817688; - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java deleted file mode 100644 index 368d3b9..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java +++ /dev/null @@ -1,35 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.event; - -import com.pengrad.telegrambot.response.BaseResponse; - -public class EventRuntimeException extends RuntimeException { - - public EventRuntimeException () { - super(); - } - - public EventRuntimeException (String message) { - super(message); - } - - public static class ActionFailed extends EventRuntimeException { - - private final BaseResponse response; - - public ActionFailed (BaseResponse response) { - super(); - this.response = response; - } - - public ActionFailed (String message, BaseResponse response) { - super(message); - this.response = response; - } - - public BaseResponse getResponse() { - return response; - } - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java deleted file mode 100644 index 06703a4..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java +++ /dev/null @@ -1,15 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import javax.annotation.Nonnull; - -public class MsgEscape { - - @Nonnull - public static String escapeHtml (@Nonnull String raw) { - raw = raw.replaceAll("&", "&"); - raw = raw.replaceAll("<", "<"); - raw = raw.replaceAll(">", ">"); - return raw; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java deleted file mode 100644 index b046f30..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import cc.sukazyo.cono.morny.util.CommonConvert; -import cc.sukazyo.cono.morny.util.CommonEncrypt; - -import javax.annotation.Nonnull; - -public class NamedUtils { - - public static String inlineIds (@Nonnull String tag) { - return inlineIds(tag, ""); - } - - public static String inlineIds (@Nonnull String tag, @Nonnull String taggedData) { - return CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(tag+taggedData)); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java deleted file mode 100644 index 027f515..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java +++ /dev/null @@ -1,21 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.Chat; -import com.pengrad.telegrambot.model.Message; -import com.pengrad.telegrambot.model.User; - -public class TGToString { - - public static TGToStringFromChat as (Chat chat) { - return new TGToStringFromChat(chat); - } - - public static TGToStringFromUser as (User user) { - return new TGToStringFromUser(user); - } - - public static TGToStringFromMessage as (Message message) { - return new TGToStringFromMessage(message); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java deleted file mode 100644 index e327279..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java +++ /dev/null @@ -1,60 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.Chat; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class TGToStringFromChat { - - - public static final long MASK_BOTAPI_ID = -1000000000000L; - - private final Chat data; - - public TGToStringFromChat(Chat chat) { - this.data = chat; - } - - public String toStringFullNameId() { - if (data.title() == null) { - throw new IllegalArgumentException("Cannot format private chat to group Name+Id format."); - } - return (data.username() == null) ? - (String.format("%s [%d]", data.title(), data.id())) : - (String.format("%s {%s}[%d]", data.title(), data.username(), data.id())); - } - - @Nonnull - public String getSafeName () { - if (data.type() == Chat.Type.Private) - return data.firstName() + (data.lastName()==null ? "" : " "+data.lastName()); - else return data.title(); - } - - @Nullable - public String getSafeLinkHTML () { - if (data.username() == null) { - if (data.type() == Chat.Type.Private) - // language=html - return String.format("@[u:%d]", data.id(), data.id()); - // language=html - else return String.format("@[c/%d]", id_tdLib(), id_tdLib()); - } else return "@"+data.username(); - } - - public long id_tdLib () { - return data.id() < 0 ? Math.abs(data.id() - MASK_BOTAPI_ID) : data.id(); - } - - @Nonnull - public String getTypeTag () { - return switch (data.type()) { - case Private -> "🔒"; - case group -> "💭"; - case supergroup -> "💬"; - case channel -> "📢"; - }; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java deleted file mode 100644 index 08b2d94..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java +++ /dev/null @@ -1,27 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.Message; - -import javax.annotation.Nonnull; - -public class TGToStringFromMessage extends TGToString { - - @Nonnull - private final Message message; - - public TGToStringFromMessage (@Nonnull Message message) { this.message = message; } - - @Nonnull - public String getSenderFirstNameRefHtml () { - return message.senderChat()==null ? TGToString.as(message.from()).firstnameRefHtml() : String.format( - "%s", - message.senderChat().id(), - MsgEscape.escapeHtml(message.senderChat().title()) - ); - } - - public long getSenderId () { - return message.senderChat()==null ? message.from().id() : message.senderChat().id(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java deleted file mode 100644 index fa41d3c..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.User; - -public class TGToStringFromUser { - - private final User data; - - public TGToStringFromUser (User user) { - this.data = user; - } - - public String fullname () { - return data.firstName() + (data.lastName()==null ? "" : " "+data.lastName()); - } - - public String fullnameRefHtml () { - return String.format( - "%s", - data.id(), - MsgEscape.escapeHtml(fullname()) - ); - } - - public String fullnameRefMarkdown () { - return String.format( - "[%s](tg://user?id=%d)", - fullname(), - data.id() - ); - } - - public String firstnameRefHtml () { - return String.format( - "%s", - data.id(), - MsgEscape.escapeHtml(data.firstName()) - ); - } - - public String firstnameRefMarkdown () { - return String.format( - "[%s](tg://user?id=%d)", - data.firstName(), - data.id() - ); - } - - public String toStringLogTag () { - return (data.username()==null ? fullname()+" " : "@"+data.username()) + "[" + data.id() + "]"; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java deleted file mode 100644 index e1703e4..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java +++ /dev/null @@ -1,85 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.User; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - -public class TelegramUserInformation { - - public static final String DC_QUERY_SOURCE_SITE = "https://t.me/"; - public static final Pattern DC_QUERY_PROCESSOR_REGEX = Pattern.compile("(cdn[1-9]).tele(sco.pe|gram-cdn.org)"); - - private static final OkHttpClient httpClient = new OkHttpClient(); - - @Nullable - public static String getDataCenterFromUsername (String username) { - final Request request = new Request.Builder().url(DC_QUERY_SOURCE_SITE + username).build(); - try (Response response = httpClient.newCall(request).execute()) { - final ResponseBody body = response.body(); - if (body == null) return "empty upstream response"; - final Matcher matcher = DC_QUERY_PROCESSOR_REGEX.matcher(body.string()); - if (matcher.find()) { - return matcher.group(1); - } - } catch (IOException e) { - return e.getMessage(); - } - return null; - } - - public static String informationOutputHTML (User user) { - - final StringBuilder userInformation = new StringBuilder(); - userInformation.append(String.format( - """ - userid : - - %d""", - user.id() - )); - if (user.username() == null) { - userInformation.append("\nusername : null\ndatacenter : null"); - } else { - userInformation.append(String.format( - """ - - username : - - %s""", - escapeHtml(user.username()) - )); - // 依赖 username 的 datacenter 查询 - final String dataCenter = getDataCenterFromUsername(user.username()); - if (dataCenter == null) { userInformation.append("\ndatacenter : null"); } - else { userInformation.append(String.format("\ndatacenter : %s", escapeHtml(dataCenter))); } - } - userInformation.append(String.format( - """ - - display name : - - %s%s""", - escapeHtml(user.firstName()), - user.lastName()==null ? "" : String.format("\n- %s", escapeHtml(user.lastName())) - )); - if (user.languageCode() != null) { - userInformation.append(String.format( - """ - - language-code : - - %s""", - escapeHtml(user.languageCode()) - )); - } - - return userInformation.toString(); - - } - -} diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala index 6bfad74..1860236 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala @@ -2,11 +2,11 @@ package cc.sukazyo.cono.morny import cc.sukazyo.cono.morny.bot.command.MornyCommands import cc.sukazyo.cono.morny.daemon.MornyDaemons -import cc.sukazyo.cono.morny.util.tgapi.ExtraAction import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} import cc.sukazyo.cono.morny.MornyCoeur.THREAD_MORNY_EXIT import cc.sukazyo.cono.morny.bot.api.TelegramUpdatesListener import cc.sukazyo.cono.morny.bot.event.MornyEventListeners +import cc.sukazyo.cono.morny.util.tgapi.ExtraAction import com.pengrad.telegrambot.TelegramBot import com.pengrad.telegrambot.request.GetMe diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala index 69fb74f..7e052eb 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala @@ -1,13 +1,13 @@ package cc.sukazyo.cono.morny import cc.sukazyo.cono.morny.internal.BuildConfigField +import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} +import cc.sukazyo.cono.morny.daemon.MornyReport import cc.sukazyo.cono.morny.util.FileUtils import java.io.IOException import java.net.URISyntaxException import java.security.NoSuchAlgorithmException -import Log.{exceptionLog, logger} -import cc.sukazyo.cono.morny.daemon.MornyReport object MornySystem { diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala index 9eed851..98b7852 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala @@ -1,9 +1,9 @@ package cc.sukazyo.cono.morny.bot.api import cc.sukazyo.cono.morny.Log -import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} import cc.sukazyo.cono.morny.daemon.MornyReport +import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException import com.google.gson.GsonBuilder import com.pengrad.telegrambot.model.Update @@ -65,7 +65,7 @@ object EventListenerManager { case actionFailed: EventRuntimeException.ActionFailed => errorMessage ++= "\ntg-api action: response track: " errorMessage ++= (GsonBuilder().setPrettyPrinting().create().toJson( - actionFailed.getResponse + actionFailed.response ) indent 4) ++= "\n" case _ => logger error errorMessage.toString diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala index 975c47b..f1faef6 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala @@ -4,10 +4,10 @@ import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.daemon.MornyReport import cc.sukazyo.cono.morny.data.TelegramStickers -import cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex +import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.CommonEncrypt import cc.sukazyo.cono.morny.util.CommonEncrypt.* -import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex import com.pengrad.telegrambot.model.{PhotoSize, Update} import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{GetFile, SendDocument, SendMessage, SendSticker} @@ -16,6 +16,7 @@ import java.io.IOException import java.util.Base64 import scala.language.postfixOps +/** Provides Telegram Command __`/encrypt`__. */ object Encryptor extends ITelegramCommand { override val name: String = "encrypt" @@ -25,12 +26,20 @@ object Encryptor extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - val args = command.getArgs + val args = command.args + // show a simple help page if ((args isEmpty) || ((args(0) equals "l") && (args.length == 1))) echoHelp(event.message.chat.id, event.message.messageId) return + // for mod-params: + // mod-params is the args belongs to the encrypt algorithm. + // due to the algorithm is defined in the 1st (array(0)) arg, + // so the mod-params is which defined since the 2nd arg. also + // due to there's only one mod-param yet (it is uppercase), + // so the algorithm will be and must be in the 2nd arg. + /** inner function: is input `arg` means mod-param ''uppercase'' */ def _is_mod_u(arg: String): Boolean = if (arg equalsIgnoreCase "uppercase") return true if (arg equalsIgnoreCase "u") return true @@ -46,13 +55,21 @@ object Encryptor extends ITelegramCommand { return } else false - trait XEncryptable { val asByteArray: Array[Byte] } - case class XFile (data: Array[Byte], name: String) extends XEncryptable { + // BLOCK: get input + // for now, only support getting data from replied message, and + // this message CAN ONLY have texts or an universal file: if the + // universal files are not only one, only the first one can be get. + // - do NOT SUPPORT telegram inline image/video/autio yet + // - do NOT SUPPORT multi-file yet + // todo: support inline image/video/audio file and multi-files. + /** inner trait: the encryptable data abstract */ + trait XEncryptable { /** standards data to [[Array]]`[`[[Byte]]`]` for processing */ val asByteArray: Array[Byte] } + /** inner class: the [[XEncryptable]] implementation of binary([[Array]]`[`[[Byte]]`]`) data (file or something) */ + case class XFile (data: Array[Byte], name: String) extends XEncryptable: val asByteArray: Array[Byte] = data - } - case class XText (data: String) extends XEncryptable { + /** inner class: the [[XEncryptable]] implementation of [[String]] data */ + case class XText (data: String) extends XEncryptable: val asByteArray: Array[Byte] = data getBytes CommonEncrypt.ENCRYPT_STANDARD_CHARSET - } val input: XEncryptable = val _r = event.message.replyToMessage if ((_r ne null) && (_r.document ne null)) { @@ -73,9 +90,10 @@ object Encryptor extends ITelegramCommand { _photo_origin = size _photo_size = _size if (_photo_origin eq null) throw IllegalArgumentException("no photo from api.") + import cc.sukazyo.cono.morny.util.UseRandom.rand_id XFile( MornyCoeur.account getFileContent (MornyCoeur.extra exec GetFile(_photo_origin.fileId)).file, - s"photo${byteArrayToHex(hashMd5(System.currentTimeMillis toString)) substring 32-12 toUpperCase}.png" + s"photo$rand_id.png" ) } catch case e: IOException => @@ -95,19 +113,26 @@ object Encryptor extends ITelegramCommand { ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) return } + // END BLOCK: get input - + // BLOCK: encrypt + /** inner class: encrypt result implementation of text-like (can be described as [[String]]). */ trait EXTextLike { val text: String } + /** inner class: encrypt result implementation of a file */ case class EXFile (result: Array[Byte], resultName: String) - case class EXText (result: String) extends EXTextLike { override val text:String = result } - case class EXHash (result: String) extends EXTextLike { override val text:String = result } + /** inner class: [[EXTextLike]] implementation of just normal text */ + case class EXText (text: String) extends EXTextLike + /** inner class: [[EXTextLike]] implementation of a special type: hash value */ + case class EXHash (text: String) extends EXTextLike + /** generate encrypt result by making normal encrypt: output type == input type */ def genResult_encrypt (source: XEncryptable, processor: Array[Byte]=>Array[Byte], filenameProcessor: String=>String): EXFile|EXText = { source match case x_file: XFile => EXFile(processor(x_file asByteArray), filenameProcessor(x_file.name)) - case x: XText => EXText(String(processor(x asByteArray), ENCRYPT_STANDARD_CHARSET)) + case x: XText => EXText(String(processor(x asByteArray), CommonEncrypt.ENCRYPT_STANDARD_CHARSET)) } + /** generate encrypt result by making hash: output type == hash value */ def genResult_hash (source: XEncryptable, processor: Array[Byte]=>Array[Byte]): EXHash = - val hashed = byteArrayToHex(processor(source asByteArray)) + val hashed = processor(source asByteArray) toHex; EXHash(if mod_uppercase then hashed toUpperCase else hashed) val result: EXHash|EXFile|EXText = args(0) match case "base64" | "b64" | "base64url" | "base64u" | "b64u" => @@ -126,24 +151,26 @@ object Encryptor extends ITelegramCommand { try { genResult_encrypt( input, _tool_b64d.decode, - CommonEncrypt.base64FilenameLint + CommonEncrypt.lint_base64FileName ) } catch case _: IllegalArgumentException => MornyCoeur.extra exec SendSticker( event.message.chat.id, TelegramStickers ID_404 // todo: is here better erro notify? ).replyToMessageId(event.message.messageId) return - case "md5" => genResult_hash(input, hashMd5) - case "sha1" => genResult_hash(input, hashSha1) - case "sha256" => genResult_hash(input, hashSha256) - case "sha512" => genResult_hash(input, hashSha512) + case "md5" => genResult_hash(input, MD5) + case "sha1" => genResult_hash(input, SHA1) + case "sha256" => genResult_hash(input, SHA256) + case "sha512" => genResult_hash(input, SHA512) case _ => MornyCoeur.extra exec SendSticker( event.message.chat.id, TelegramStickers ID_404 ).replyToMessageId(event.message.messageId) return; + // END BLOCK: encrypt + // output result match case _file: EXFile => MornyCoeur.extra exec SendDocument( @@ -151,7 +178,7 @@ object Encryptor extends ITelegramCommand { _file.result ).fileName(_file.resultName).replyToMessageId(event.message.messageId) case _text: EXTextLike => - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( event.message.chat.id, s"

${h(_text.text)}
" @@ -159,6 +186,30 @@ object Encryptor extends ITelegramCommand { } + /** echo help to a specific message in a specific chat. + * + * === the help message === + * The first paragraph lists available encrypt algorithms and its alias, + * each line have one algorithm where the first name highlighted is the + * main name and following is aliases separated with `,`. + * with the separator `---`, the second paragraph lists available mods + * for algorithms, displays with the same rule of algorithms, with an extra + * italic text following describes its usage environment. + * + * when output to telegram just like: + *
+ * '''__base64__''', b64
+ * '''__base64url__''', base64u, b64u
+ * '''__base64decode__''', base64d, b64d
+ * '''__base64url-decode__''', base64ud, b64ud
+ * '''__sha1__'''
+ * '''__sha256__'''
+ * '''__sha512__'''
+ * '''__md5__'''
+ * ---
+ * '''__uppercase__''', upper, u ''(sha1/sha256/sha512/md5 only)'' + *
+ */ private def echoHelp(chat: Long, replyTo: Int): Unit = MornyCoeur.extra exec SendMessage( chat, diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala index 5a6d9e8..963c80a 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala @@ -1,10 +1,10 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.event.OnEventHackHandle +import cc.sukazyo.cono.morny.bot.event.OnEventHackHandle.{registerHack, HackType} +import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.Update -import OnEventHackHandle.{HackType, registerHack} -import cc.sukazyo.cono.morny.data.TelegramStickers import com.pengrad.telegrambot.request.SendSticker import scala.language.postfixOps @@ -18,7 +18,7 @@ object EventHack extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - val x_mode = if (command.hasArgs) command.getArgs()(0) else "" + val x_mode = if (command.args nonEmpty) command.args(0) else "" def done_ok = MornyCoeur.extra exec SendSticker( diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala index 7799e06..78013bd 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala @@ -18,7 +18,7 @@ object GetUsernameAndId extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - val args = command.getArgs + val args = command.args if (args.length > 1) MornyCoeur.extra exec SendMessage( @@ -59,7 +59,7 @@ object GetUsernameAndId extends ITelegramCommand { MornyCoeur.extra exec SendMessage( event.message.chat.id, - TelegramUserInformation informationOutputHTML user + TelegramUserInformation getFormattedInformation user ).replyToMessageId(event.message.messageId()).parseMode(ParseMode HTML) } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala index b49f50d..a5d17b6 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala @@ -31,15 +31,15 @@ object IP186Query { private def query (using event: Update, command: InputCommand): Unit = { val target: String|Null = - if (command.getArgs isEmpty) + if (command.args isEmpty) if event.message.replyToMessage eq null then null else event.message.replyToMessage.text - else if (command.getArgs.length > 1) + else if (command.args.length > 1) MornyCoeur.extra exec SendMessage( event.message.chat.id, "[Unavailable] Too much arguments." ).replyToMessageId(event.message.messageId) return - else command.getArgs()(0) + else command.args(0) if (target eq null) MornyCoeur.extra exec new SendMessage( @@ -48,14 +48,15 @@ object IP186Query { ).replyToMessageId(event.message.messageId) return; + + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h try { - val response = command.getCommand match + val response = command.command match case Subs.IP.cmd => IP186QueryHandler.query_ip(target) case Subs.WHOIS.cmd => IP186QueryHandler.query_whoisPretty(target) - case _ => throw IllegalArgumentException(s"Unknown 186-IP query method ${command.getCommand}") + case _ => throw IllegalArgumentException(s"Unknown 186-IP query method ${command.command}") - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( event.message.chat.id, s"""${h(response.url)} @@ -64,7 +65,6 @@ object IP186Query { ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) } catch case e: Exception => - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h MornyCoeur.extra exec new SendMessage( event.message().chat().id(), s"""[Exception] in query: diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala index a6fbdf8..4776d68 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala @@ -1,9 +1,9 @@ package cc.sukazyo.cono.morny.bot.command -import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.{BotCommand, DeleteMyCommands, Update} import com.pengrad.telegrambot.request.{SendSticker, SetMyCommands} @@ -60,14 +60,14 @@ object MornyCommands { ) def execute (using command: InputCommand, event: Update): Boolean = { - if (commands contains command.getCommand) - commands(command.getCommand) execute; + if (commands contains command.command) + commands(command.command) execute; true else nonCommandExecutable } private def nonCommandExecutable (using command: InputCommand, event: Update): Boolean = { - if command.getTarget eq null then false + if command.target eq null then false else MornyCoeur.extra exec SendSticker( event.message.chat.id, diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala index ea310dc..80c4519 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala @@ -1,8 +1,8 @@ package cc.sukazyo.cono.morny.bot.command -import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.command.ICommandAlias.ListedAlias import cc.sukazyo.cono.morny.data.TelegramStickers +import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.request.SendSticker diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala index f9c46bb..516ddd7 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala @@ -3,8 +3,8 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.{BuildConfig, MornyAbout, MornyCoeur, MornySystem} import cc.sukazyo.cono.morny.data.{TelegramImages, TelegramStickers} import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{SendMessage, SendPhoto, SendSticker} @@ -30,12 +30,12 @@ object MornyInformation extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - if (!command.hasArgs) { + if (command.args isEmpty) { echoInfo(event.message.chat.id, event.message.messageId) return } - val action: String = command.getArgs()(0) + val action: String = command.args(0) action match { case s if s startsWith Subs.STICKERS => echoStickers @@ -94,13 +94,13 @@ object MornyInformation extends ITelegramCommand { private def echoStickers (using command: InputCommand, event: Update): Unit = { val mid: String|Null = - if (command.getArgs()(0) == Subs.STICKERS) { - if (command.getArgs.length == 1) "" - else if (command.getArgs.length == 2) command.getArgs()(1) + if (command.args(0) == Subs.STICKERS) { + if (command.args.length == 1) "" + else if (command.args.length == 2) command.args(1) else null - } else if (command.getArgs.length == 1) { - if ((command.getArgs()(0) startsWith s"${Subs.STICKERS}.") || (command.getArgs()(0) startsWith s"${Subs.STICKERS}#")) { - command.getArgs()(0) substring Subs.STICKERS.length+1 + } else if (command.args.length == 1) { + if ((command.args(0) startsWith s"${Subs.STICKERS}.") || (command.args(0) startsWith s"${Subs.STICKERS}#")) { + command.args(0) substring Subs.STICKERS.length+1 } else null } else null if (mid == null) echo404 diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala index 6f44f16..cad2acf 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala @@ -1,4 +1,5 @@ package cc.sukazyo.cono.morny.bot.command + import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.Update diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala index bb69c48..8800c9f 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala @@ -1,15 +1,15 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.bot.command.ICommandAlias.HiddenAlias -import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.data.TelegramStickers -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.daemon.MornyReport +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.request.SendSticker import scala.language.postfixOps -import cc.sukazyo.cono.morny.Log.logger -import cc.sukazyo.cono.morny.daemon.MornyReport object MornyManagers { @@ -30,7 +30,7 @@ object MornyManagers { event.message.chat.id, TelegramStickers ID_EXIT ).replyToMessageId(event.message.messageId) - logger info s"Morny exited by user ${(TGToString as user) toStringLogTag}" + logger info s"Morny exited by user ${user toLogTag}" MornyCoeur.exit(0, user) } else { @@ -39,7 +39,7 @@ object MornyManagers { event.message.chat.id, TelegramStickers ID_403 ).replyToMessageId(event.message.messageId) - logger info s"403 exit caught from user ${(TGToString as user) toStringLogTag}" + logger info s"403 exit caught from user ${user toLogTag}" MornyReport.unauthenticatedAction("/exit", user) } @@ -61,7 +61,7 @@ object MornyManagers { if (MornyCoeur.trusted isTrusted user.id) { - logger info s"call save from command by ${(TGToString as user) toStringLogTag}" + logger info s"call save from command by ${user toLogTag}" MornyCoeur.callSaveData() MornyCoeur.extra exec SendSticker( event.message.chat.id, @@ -74,7 +74,7 @@ object MornyManagers { event.message.chat.id, TelegramStickers ID_403 ).replyToMessageId(event.message.messageId) - logger info s"403 save caught from user ${(TGToString as user) toStringLogTag}" + logger info s"403 save caught from user ${user toLogTag}" MornyReport.unauthenticatedAction("/save", user) } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala index 23fa2fa..327d7df 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala @@ -1,9 +1,9 @@ package cc.sukazyo.cono.morny.bot.command -import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import com.pengrad.telegrambot.model.Update import cc.sukazyo.cono.morny.data.MornyJrrp import cc.sukazyo.cono.morny.MornyCoeur -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.SendMessage @@ -24,11 +24,11 @@ object MornyOldJrrp extends ITelegramCommand { case a if a > 30 => ";" case _ => "..." - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( event.message.chat.id, // language=html - f"${(TGToString as user) fullnameRefHtml} 在(utc的)今天的运气指数是———— $jrrp%.2f%%${h(ending)}" + f"${user.fullnameRefHTML} 在(utc的)今天的运气指数是———— $jrrp%.2f%%${h(ending)}" ).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML) } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala index 80c0c46..4d7e343 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala @@ -2,8 +2,8 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.data.{NbnhhshQuery, TelegramStickers} +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{SendMessage, SendSticker} @@ -25,11 +25,10 @@ object Nbnhhsh extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { val queryTarget: String|Null = - import cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting if (event.message.replyToMessage != null && event.message.replyToMessage.text != null) event.message.replyToMessage.text - else if command hasArgs then - stringsConnecting(command.getArgs, " ", 0, command.getArgs.length-1) + else if command.args nonEmpty then + command.args mkString " " else null if (queryTarget == null) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala index 0e249d4..8696bb8 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala @@ -2,7 +2,8 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue +import cc.sukazyo.cono.morny.util.UseMath.over +import cc.sukazyo.cono.morny.util.UseRandom.* import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.request.SendMessage @@ -13,7 +14,7 @@ object 私わね extends ISimpleCommand { override def execute (using command: InputCommand, event: Update): Unit = { - if (probabilityTrue(521)) { + if ((1 over 521) chance_is true) { val text = "/打假" MornyCoeur.extra exec new SendMessage( event.message.chat.id, diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala index 68ad75c..a8d16b3 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala @@ -3,9 +3,9 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.api.EventListener import cc.sukazyo.cono.morny.data.TelegramStickers -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString -import com.pengrad.telegrambot.model.request.ParseMode +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* import com.pengrad.telegrambot.model.{Chat, Message, Update, User} +import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{ForwardMessage, GetChat, SendMessage, SendSticker} import scala.language.postfixOps @@ -44,7 +44,7 @@ object OnCallMe extends EventListener { MornyCoeur.extra exec SendMessage( me, s"""request $itemHTML - |from ${(TGToString as user) fullnameRefHtml}${if extra == null then "" else "\n"+extra}""" + |from ${user.fullnameRefHTML}${if extra == null then "" else "\n"+extra}""" .stripMargin ).parseMode(ParseMode HTML) @@ -59,7 +59,7 @@ object OnCallMe extends EventListener { lastDinnerData.forwardFromMessageId ) import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h def lastDinner_dateMillis: Long = lastDinnerData.forwardDate longValue; MornyCoeur.extra exec SendMessage( req.from.id, diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala index d4bb8ca..1065a29 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala @@ -3,7 +3,6 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.bot.api.EventListener import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.data.TelegramStickers -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString import com.pengrad.telegrambot.model.{Chat, Message, MessageEntity, Update} import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{GetChat, SendMessage, SendSticker} @@ -108,11 +107,11 @@ object OnCallMsgSend extends EventListener { val targetChatResponse = MornyCoeur.account execute GetChat(messageToSend.targetId) if (targetChatResponse isOk) { def getChatDescriptionHTML (chat: Chat): String = - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h - val _c = TGToString as chat + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h // language=html s"""${h(chat.id toString)}@${h(chat.`type`.name)}${if (chat.`type` != Chat.Type.Private) ":::" else ""} - |${_c getTypeTag} ${h(_c getSafeName)} ${_c getSafeLinkHTML}""" + |${chat.typeTag} ${h(chat.safe_name)} ${chat.safe_linkHTML}""" .stripMargin MornyCoeur.extra exec SendMessage( update.message.chat.id, diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala index d618ddc..121b3ef 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala @@ -1,8 +1,6 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.bot.api.EventListener - -import scala.collection.mutable import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur import com.google.gson.GsonBuilder @@ -10,6 +8,7 @@ import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.SendMessage +import scala.collection.mutable import scala.language.postfixOps object OnEventHackHandle extends EventListener { @@ -39,7 +38,7 @@ object OnEventHackHandle extends EventListener { else if hackers contains "[[]]" then (hackers remove "[[]]")get else return false logger debug s"hacked event by $x" - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( x.from_chat, // language=html diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala index 825f2d5..601cafc 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala @@ -15,8 +15,9 @@ object OnQuestionMarkReply extends EventListener { if event.message.text eq null then return false - import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue - if !probabilityTrue(8) then return false + import cc.sukazyo.cono.morny.util.UseMath.over + import cc.sukazyo.cono.morny.util.UseRandom.chance_is + if (1 over 8) chance_is false then return false for (c <- event.message.text toCharArray) if !(QUESTION_MARKS contains c) then return false diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala index b82a66a..a2ef6ea 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala @@ -1,11 +1,11 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.bot.api.EventListener -import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import com.pengrad.telegrambot.model.{Message, Update} import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.command.MornyCommands +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.{Message, Update} object OnTelegramCommand extends EventListener { @@ -19,10 +19,10 @@ object OnTelegramCommand extends EventListener { if !_isCommandMessage(update.message) then return false val inputCommand = InputCommand(update.message.text drop 1) - if (!(inputCommand.getCommand matches "^\\w+$")) + if (!(inputCommand.command matches "^\\w+$")) logger debug "not command" false - else if ((inputCommand.getTarget ne null) && (inputCommand.getTarget ne MornyCoeur.username)) + else if ((inputCommand.target ne null) && (inputCommand.target ne MornyCoeur.username)) logger debug "not morny command" false else diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala index 1657169..df18cb7 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala @@ -17,13 +17,13 @@ object OnUserRandom extends EventListener { if update.message.text == null then return false if update.message.text startsWith "/" then return false - import cc.sukazyo.cono.morny.util.CommonRandom.iif + import cc.sukazyo.cono.morny.util.UseRandom.rand_half val query = update.message.text substring 1 val result: String|Null = query match case USER_OR_QUERY(_con1, _con2) => - if iif then _con1 else _con2 + if rand_half then _con1 else _con2 case USER_IF_QUERY(_con) => - (if iif then "不" else "") + _con + (if rand_half then "不" else "") + _con case _ => null if result == null then return false diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala index 9447a91..1778dfc 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala @@ -2,9 +2,9 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.UniversalCommand -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.SendMessage @@ -22,7 +22,7 @@ object OnUserSlashAction extends EventListener { if (text startsWith "/") { - val actions = UniversalCommand format text + val actions = UniversalCommand(text) actions(0) = actions(0) substring 1 actions(0) @@ -51,11 +51,11 @@ object OnUserSlashAction extends EventListener { MornyCoeur.extra exec SendMessage( update.message.chat.id, "%s %s%s %s %s!".format( - (TGToString as origin) getSenderFirstNameRefHtml, + origin.sender_firstnameRefHTML, h(v_verb), if hasObject then "" else "了", if (origin == target) - s"自己" - else (TGToString as target) getSenderFirstNameRefHtml, + s"自己" + else origin.sender_firstnameRefHTML, if hasObject then h(v_object+" ") else "" ) ).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala index 6275c2e..b6066e0 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala @@ -1,6 +1,6 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode} @@ -18,9 +18,9 @@ object MyInformation extends ITelegramQuery { List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX), TITLE, + inlineQueryId(ID_PREFIX), TITLE, new InputTextMessageContent( - TelegramUserInformation informationOutputHTML event.inlineQuery.from + TelegramUserInformation getFormattedInformation event.inlineQuery.from ).parseMode(ParseMode HTML) )).isPersonal(true).cacheTime(10) ) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala index aec52f6..4fe13c8 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala @@ -1,5 +1,5 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent} @@ -16,7 +16,7 @@ object RawText extends ITelegramQuery { List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX, event.inlineQuery.query), TITLE, + inlineQueryId(ID_PREFIX, event.inlineQuery.query), TITLE, InputTextMessageContent(event.inlineQuery.query) )) ) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala index bc1a4e7..7b2f750 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala @@ -1,8 +1,8 @@ package cc.sukazyo.cono.morny.bot.query import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.BiliTool -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode} @@ -60,11 +60,11 @@ object ShareToolBilibili extends ITelegramQuery { List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av, + inlineQueryId(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av, InputTextMessageContent(SHARE_FORMAT_HTML.format(link_av, id_av)).parseMode(ParseMode HTML) )), InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_BILI_BV + bv), TITLE_BILI_BV + bv, + inlineQueryId(ID_PREFIX_BILI_BV + bv), TITLE_BILI_BV + bv, InputTextMessageContent(SHARE_FORMAT_HTML.format(link_bv, id_bv)).parseMode(ParseMode HTML) )) ) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala index ffc7f0e..572c32e 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala @@ -1,10 +1,9 @@ package cc.sukazyo.cono.morny.bot.query +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.InlineQueryResultArticle -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds - import scala.language.postfixOps import scala.util.matching.Regex @@ -25,11 +24,11 @@ object ShareToolTwitter extends ITelegramQuery { case REGEX_TWEET_LINK(_1, _2, _) => List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX, + inlineQueryId(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX, s"https://vxtwitter.com/$_2" )), InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_VX_COMBINED+event.inlineQuery.query), TITLE_VX_COMBINED, + inlineQueryId(ID_PREFIX_VX_COMBINED+event.inlineQuery.query), TITLE_VX_COMBINED, s"https://c.vxtwitter.com/$_2" )) ) diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala index cba4ccf..9591fb1 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala @@ -1,16 +1,16 @@ package cc.sukazyo.cono.morny.daemon import cc.sukazyo.cono.morny.{MornyCoeur, MornyConfig} -import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException -import com.pengrad.telegrambot.request.{BaseRequest, SendMessage} -import com.pengrad.telegrambot.response.BaseResponse import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} import cc.sukazyo.cono.morny.bot.command.MornyInformation +import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import com.google.gson.GsonBuilder import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.model.User -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import com.pengrad.telegrambot.request.{BaseRequest, SendMessage} +import com.pengrad.telegrambot.response.BaseResponse object MornyReport { @@ -25,7 +25,7 @@ object MornyReport { s"""cannot execute report to telegram: |${exceptionLog(e) indent 4} | tg-api response: - |${(e.getResponse toString) indent 4}""" + |${(e.response toString) indent 4}""" .stripMargin } } @@ -36,7 +36,7 @@ object MornyReport { case api: EventRuntimeException.ActionFailed => // language=html "\n\ntg-api error:\n
%s
" - .formatted(GsonBuilder().setPrettyPrinting().create.toJson(api.getResponse)) + .formatted(GsonBuilder().setPrettyPrinting().create.toJson(api.response)) case _ => "" executeReport(SendMessage( MornyCoeur.config.reportToChat, @@ -55,7 +55,7 @@ object MornyReport { // language=html s"""▌User unauthenticated action |action: ${h(action)} - |by user ${(TGToString as user) fullnameRefHtml}""" + |by user ${user.fullnameRefHTML}""" .stripMargin ).parseMode(ParseMode HTML)) } @@ -105,7 +105,7 @@ object MornyReport { def onMornyExit (causedBy: AnyRef|Null): Unit = { if unsupported then return val causedTag = causedBy match - case u: User => (TGToString as u) fullnameRefHtml + case u: User => u.fullnameRefHTML case n if n == null => "UNKNOWN reason" case a: AnyRef => /*language=html*/ s"${h(a.toString)}" executeReport(SendMessage( diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala index 87f3364..d6ec709 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala @@ -10,8 +10,8 @@ object MornyJrrp { jrrp_v_xmomi(user.id, timestamp/(1000*60*60*24)) * 100.0 private def jrrp_v_xmomi (identifier: Long, dayStamp: Long): Double = - import cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex - import cc.sukazyo.cono.morny.util.CommonEncrypt.hashMd5 - (java.lang.Long parseLong byteArrayToHex(hashMd5(s"$identifier@$dayStamp")).substring(0, 4)) / (0xffff toDouble) + import cc.sukazyo.cono.morny.util.CommonEncrypt.MD5 + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + (java.lang.Long parseLong MD5(s"$identifier@$dayStamp").toHex.substring(0, 4)) / (0xffff toDouble) } diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/BiliTool.scala b/src/main/scala/cc/sukazyo/cono/morny/util/BiliTool.scala new file mode 100644 index 0000000..37a2473 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/BiliTool.scala @@ -0,0 +1,119 @@ +package cc.sukazyo.cono.morny.util + +import cc.sukazyo.cono.morny.util.UseMath.** + +import scala.collection.mutable + +/** Utils about $Bilibili + * + * contains utils: + * - av/BV converting: + * - [[toAv]] + * - [[toBv]] + * + * @define Bilibili [[https://bilibili.com Bilibili]] + * + * @define AvBvFormat + * === About AV/BV id format === + * the AV id is a number; the BV id is a special 10 digits base58 number, it shows as String + * in programming. + * + * e.g. while the link ''`https://www.bilibili.com/video/BV17x411w7KC/`'' shows + * the same with ''`https://www.bilibili.com/video/av170001/`'', the AV id + * is __`170001`__, the BV id is __`BV17x411w7KC`__. + * + * @define AvBvSeeAlso [[https://www.zhihu.com/question/381784377/answer/1099438784 mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」?]] + * @todo Maybe make a class `AV`/`BV` and implement the parse in the class + */ +object BiliTool { + + private val V_CONV_XOR = 177451812L + private val V_CONV_ADD = 8728348608L + + private val BV_TABLE = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF" + private val TABLE_INT = BV_TABLE.length + private val BV_TABLE_REVERSED = + val mapping = mutable.HashMap.empty[Char, Int] + for (i <- BV_TABLE.indices) mapping += (BV_TABLE(i) -> i) + mapping.toMap + private val BV_TEMPLATE = "1 4 1 7 " + private val BV_TEMPLATE_FILTER = Array(9, 8, 1, 6, 2, 4) + + /** Error of illegal BV id. + * + * @constructor Build a error with illegal BV details. + * @param bv the source illegal BV id. + * @param reason why it is illegal. + */ + class IllegalFormatException private (bv: String, reason: String) + extends RuntimeException (s"`$bv is not a valid 10 digits base58 BV id: $reason`") { + + /** Error of illegal BV id, where the reason is the BV id is not 10 digits. + * + * @param bv the source of illegal BV id. + * @param length the length of the illegal BV id. + */ + def this (bv: String, length: Int) = + this(bv, s"given length is $length") + + /** Error of illegal BV id, where the reason is the BV id contains non [[BV_TABLE base58 character]]. + * + * @param bv the source of illegal BV id. + * @param c the illegal character + * @param location the index of the illegal character in the illegal BV id. + */ + def this (bv: String, c: Char, location: Int) = + this(bv, s"char `$c` is not in base58 char table (in position $location)") + } + + /** Convert an AV video id format to BV video id format for $Bilibili + * + * $AvBvFormat + * + * this method '''available while the __av-id < 2^27^__''', while it theoretically + * available when the av-id < 2^30^. Meanwhile some digits of the BV id is a fixed + * value (like the [[BV_TEMPLATE]] shows) -- input __bv__ can do not follow the format, + * but it will almost certainly gives a wrong AV id (because the fixed number is not + * processed at all!) + * + * @see $AvBvSeeAlso + * + * @param bv a BV id, which should be exactly 10 digits and all chars should be + * a legal base58 char (which means can be found in [[BV_TABLE]]). + * otherwise, an [[IllegalFormatException]] will be thrown. + * @return an AV id which will shows the save video of input __bv__ in $Bilibili + * @throws IllegalFormatException when the input __bv__ is not a legal 10 digits base58 + * formatted BV id. + */ + @throws[IllegalFormatException] + def toAv (bv: String): Long = { + var av = 0L + if (bv.length != 10) throw IllegalFormatException(bv, bv.length) + for (i <- BV_TEMPLATE_FILTER.indices) { + val _get = BV_TEMPLATE_FILTER(i) + val tableToken = BV_TABLE_REVERSED get bv(_get) + if tableToken isEmpty then throw IllegalFormatException(bv, bv(_get), _get) + av = av + (tableToken.get * (TABLE_INT**i).toLong) + } + (av - V_CONV_ADD) ^ V_CONV_XOR + } + + /** Convert an AV video format to a BV video format for $Bilibili. + * + * this method '''available while the __av-id < 2^27^__''', while it theoretically + * available when the av-id < 2^30^. + * + * @param av an AV id. + * @return a BV id which will shows the save video of input __av__ in $Bilibili + */ + def toBv (av: Long): String = { + val _av = (av^V_CONV_XOR)+V_CONV_ADD + val bv = Array(BV_TEMPLATE:_*) + for (i <- BV_TEMPLATE_FILTER.indices) { + import Math.{floor, pow} + bv(BV_TEMPLATE_FILTER(i)) = BV_TABLE( (floor(_av/(TABLE_INT**i)) % TABLE_INT) toInt ) + } + String copyValueOf bv + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/CommonEncrypt.scala b/src/main/scala/cc/sukazyo/cono/morny/util/CommonEncrypt.scala new file mode 100644 index 0000000..740e048 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/CommonEncrypt.scala @@ -0,0 +1,98 @@ +package cc.sukazyo.cono.morny.util + +import java.nio.charset.{Charset, StandardCharsets} +import java.security.{MessageDigest, NoSuchAlgorithmException} + +/** Provides some re-encapsulated algorithm function, and some standard values in encrypting, + * and some normalized utils in processing something in encrypting. + * + * currently there's: + * - standard value: + * - [[ENCRYPT_STANDARD_CHARSET]] the standard [[Charset]] to parse between [[String]] + * and [[Bin]] in encrypting. + * - algorithm encapsulations: + * - [[MD5]] (MD5 Message-Digest Algorithm) + * - [[SHA1]] (Secure Hash Algorithm 1) + * - [[SHA256]] (Secure Hash Algorithm 2: 256bit) + * - [[SHA512]] (Secure Hash Algorithm 2: 512bit) + * - normalized utils + * - [[lint_base64FileName]] remove the .base64 file-extension for base64 text file + * + * @define WhenString2Bin + * [[String]] will encoded to [[Bin]] using [[Charset]] [[ENCRYPT_STANDARD_CHARSET]] + * + * @todo some tests + */ +object CommonEncrypt { + + /** the [[Charset]] should use when converting between [[String]] + * and [[Bin]] in encrypting */ + val ENCRYPT_STANDARD_CHARSET: Charset = StandardCharsets.UTF_8 + + /** the alias of [[Array]]`[`[[Byte]]`]`. + * means the binary data. + */ + //noinspection ScalaWeakerAccess + type Bin = Array[Byte] + + private def hash (data: Bin)(using algorithm: String): Bin = + try { + MessageDigest.getInstance(algorithm) digest data + } catch case n: NoSuchAlgorithmException => + throw IllegalStateException(n) + + /** the [[https://en.wikipedia.org/wiki/MD5 MD5]] hash value of input [[Bin]] `data`. */ + def MD5(data: Bin): Bin = hash(data)(using "md5") + /** the [[https://en.wikipedia.org/wiki/MD5 MD5]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def MD5 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "md5") + + /** the [[https://en.wikipedia.org/wiki/SHA-1 SHA-1]] hash value of input [[Bin]] `data`. */ + def SHA1 (data: Bin): Bin = hash(data)(using "sha1") + /** the [[https://en.wikipedia.org/wiki/SHA-1 SHA-1]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def SHA1 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "sha1") + + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/256]] hash value of input [[Bin]] `data`. */ + def SHA256 (data: Bin): Bin = hash(data)(using "sha256") + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/256]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def SHA256 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "sha256") + + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/512]] hash value of input [[Bin]] `data`. */ + def SHA512 (data: Bin): Bin = hash(data)(using "sha512") + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/512]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def SHA512 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "sha512") + + /** Try get the filename before it got encrypted. + * + * It assumes the base64 encrypted file should keep the original file, and plus + * a file-extension shows the file is base64 encrypted. + * + * Actually, the file will try find the following file-extension and drop it: + * - `.b64` + * - `.64.txt` + * - `.base64` + * - `.base64.txt` + * if none of those found, it will do no process anymore. + * + * @param encrypted the file fullname (means filename with file-extension) of base64 encrypted file. + * @return the file fullname removed the base64 file extension. + */ + def lint_base64FileName (encrypted: String): String = encrypted match + case i if i endsWith ".b64" => i dropRight ".b64".length + case ix if ix endsWith ".b64.txt" => ix dropRight ".b64.txt".length + case l if l endsWith ".base64" => l dropRight ".base64".length + case lx if lx endsWith ".base64.txt" => lx dropRight ".base64.txt".length + case u => u + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/CommonFormat.scala b/src/main/scala/cc/sukazyo/cono/morny/util/CommonFormat.scala new file mode 100644 index 0000000..0ab5d36 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/CommonFormat.scala @@ -0,0 +1,76 @@ +package cc.sukazyo.cono.morny.util + +import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset} +import java.time.format.DateTimeFormatter + +/** Some formatting (convert some data to some standard output type) + * methods normalized based on Morny's usage + * + * contains: + * - [[DATE_TIME_PATTERN_FULL_MILLIS]] the standard date-time-millis [[String]] pattern format + * - [[formatDate]] convert UTC time millis (and hour-offset time zone) + * to normalized date-time-millis [[String]] + * - [[formatDuration]] convert millis duration to normalized duration [[String]] + * + */ +object CommonFormat { + + /** the standard date-time-millis [[String]] pattern format that Morny in use. + * + * pattern string is pattern of [[DateTimeFormatter]]. + */ + //noinspection ScalaWeakerAccess + val DATE_TIME_PATTERN_FULL_MILLIS = "yyyy-MM-dd HH:mm:ss:SSS" + + /** the formatted date-time-millis [[String]]. + * + * time is formatted by pattern [[DATE_TIME_PATTERN_FULL_MILLIS]]. + * + * @param timestamp millis timestamp. timestamp should be UTC alignment. + * + * @param utcOffset the hour offset of the time zone, the time-zone controls + * which local time describe will use. + * + * for example, timestamp [[0]] describes 1970-1-1 00:00:00 in + * UTC+0, so, use the `timestamp` `0` and `utfOffset` `0` will + * returns `"1970-1-1 00:00:00:000"`; however, at the same time, + * in UTC+8, the local time is 1970-1-1 08:00:00:000, so use + * the `timestamp` `0` and the `utcOffset` `8` will returns + * `"1970-1-1 08:00:00:000"` + * + * @return the time-zone local date-time-millis [[String]] describes the timestamp. + */ + def formatDate (timestamp: Long, utcOffset: Int): String = + DateTimeFormatter.ofPattern(DATE_TIME_PATTERN_FULL_MILLIS).format( + LocalDateTime.ofInstant( + Instant.ofEpochMilli(timestamp), + ZoneId.ofOffset("UTC", ZoneOffset.ofHours(utcOffset)) + ) + ) + + /** human readable [[String]] that describes the millis duration. + * + * {{{ + * scala> formatDuration(10) + * val res0: String = 10ms + * + * scala> formatDuration(3000001) + * val res1: String = 50min 0s 1ms + * + * scala> formatDuration(94179047901720L) + * val res2: String = 1090035d 6h 38min 21s 720ms + * }}} + * + * @param duration time duration, in milliseconds + * @return time duration, human readable + */ + def formatDuration (duration: Long): String = + val sb = new StringBuilder() + if (duration > 1000 * 60 * 60 * 24) sb ++= (duration / (1000 * 60 * 60 * 24)).toString ++= "d " + if (duration > 1000 * 60 * 60) sb ++= (duration / (1000 * 60 * 60) % 24).toString ++= "h " + if (duration > 1000 * 60) sb ++= (duration / (1000 * 60) % 60).toString ++= "min " + if (duration > 1000) sb ++= (duration / 1000 % 60).toString ++= "s " + sb ++= (duration % 1000).toString ++= "ms" + sb toString + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/ConvertByteHex.scala b/src/main/scala/cc/sukazyo/cono/morny/util/ConvertByteHex.scala new file mode 100644 index 0000000..0d469d4 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/ConvertByteHex.scala @@ -0,0 +1,55 @@ +package cc.sukazyo.cono.morny.util + +/** Added the [[toHex]] method to [[Byte]] and [[Array]]`[`[[Byte]]`]`. + * + * the [[toHex]] method will takes [[Byte]] as a binary byte and convert + * it to the hex [[String]] that can describe the binary byte. there are + * always 2 digits unsigned hex number. + * + * for example, byte `0` is binary `0000 0000`, it will be converted to + * `"00"`, and the byte `-1` is binary `1111 1111` which corresponding + * `"ff"`. + * {{{ + * scala> 0.toByte.toHex + * val res6: String = 00 + * + * scala> 15.toByte.toHex + * val res10: String = 0f + * + * scala> -1.toByte.toHex + * val res7: String = ff + * }}} + * + * while converting byte array, the order is: the 1st element of the array + * will be put most forward, then the following added to the tail of hex string. + * {{{ + * scala> Array[Byte](0, 1, 2, 3).toHex + * val res5: String = 00010203 + * }}} + * + */ +object ConvertByteHex { + + extension (b: Byte) { + + /** convert the binary of the [[Byte]] contains to hex string. + * @see [[ConvertByteHex]] + */ + def toHex: String = (b >> 4 & 0xf).toHexString + (b & 0xf).toHexString + + } + + extension (data: Array[Byte]) { + + /** convert the binary of the [[Array]]`[`[[Byte]]`]` contains to hex string. + * + * @see [[ConvertByteHex]] + */ + def toHex: String = + val sb = StringBuilder() + for (b <- data) sb ++= (b toHex) + sb toString + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/FileUtils.scala b/src/main/scala/cc/sukazyo/cono/morny/util/FileUtils.scala new file mode 100644 index 0000000..f1e146b --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/FileUtils.scala @@ -0,0 +1,28 @@ +package cc.sukazyo.cono.morny.util + +import java.io.{FileInputStream, IOException} +import java.security.{MessageDigest, NoSuchAlgorithmException} +import scala.util.Using + +/** + * @todo docs + * @todo some tests? + */ +object FileUtils { + + @throws[IOException|NoSuchAlgorithmException] + def getMD5Three (path: String): String = { + val buffer = Array.ofDim[Byte](8192) + var len = 0 + val algo = MessageDigest.getInstance("MD5") + Using (FileInputStream(path)) { stream => + len = stream.read(buffer) + while (len != -1) + algo update (buffer, 0, len) + len = stream.read(buffer) + } + import ConvertByteHex.toHex + algo.digest toHex + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala b/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala new file mode 100644 index 0000000..fd7d19e --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala @@ -0,0 +1,13 @@ +package cc.sukazyo.cono.morny.util + +import okhttp3.MediaType + +/** some public values of [[okhttp3]] */ +object OkHttpPublic { + + /** predefined [[okhttp3]] [[MediaType]]s */ + object MediaTypes: + /** [[MediaType]] of [[https://en.wikipedia.org/wiki/JSON JSON]]. using encoding ''UTF-8'' */ + val JSON: MediaType = MediaType.get("application/json; charset=utf-8") + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala new file mode 100644 index 0000000..65a1e87 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala @@ -0,0 +1,75 @@ +package cc.sukazyo.cono.morny.util + +import scala.collection.mutable.ArrayBuffer +import scala.util.boundary + +/** + * @todo docs + * @todo maybe there can have some encapsulation + */ +object UniversalCommand { + + def apply (input: String): Array[String] = { + + val builder = ArrayBuffer.empty[String] + + extension (c: Char) { + private inline def isUnsupported: Boolean = + (c == '\n') || (c == '\r') + private inline def isSeparator: Boolean = + c == ' ' + private inline def isQuote: Boolean = + (c == '\'') || (c == '"') + private inline def isEscapeChar: Boolean = + c == '\\' + private inline def escapableInQuote: Boolean = + c.isQuote || c.isEscapeChar + private inline def escapable: Boolean = + c.escapableInQuote || c.isSeparator + } + + var arg = StringBuilder() + var i = 0 + while (i < input.length) { + if (input(i) isSeparator) { + if (arg nonEmpty) builder += arg.toString + arg = arg.empty + } else if (input(i) isQuote) { + val _inside_tag = input(i) + var _inside = true + boundary { while (_inside) { + i=i+1 + if (i >= input.length) throw IllegalArgumentException("UniversalCommand: unclosed quoted text") + if (input(i) == _inside_tag) + boundary.break() + else if (input(i) isUnsupported) + throw IllegalArgumentException("UniversalCommand: unsupported new-line") + else if (input(i) isQuote) + throw IllegalArgumentException("UniversalCommand: mixed \" and ' used") + else if (input(i) isEscapeChar) + if (i+1 >= input.length) throw IllegalArgumentException("UniversalCommand: \\ in the end") + if (input(i+1) escapableInQuote) + i=i+1 + arg += input(i) + else + arg += input(i) + }} + } else if (input(i) isUnsupported) { + throw IllegalArgumentException("UniversalCommand: unsupported new-line") + } else if (input(i) isEscapeChar) { + if (i + 1 >= input.length) throw IllegalArgumentException("UniversalCommand: \\ in the end") + if (input(i+1) escapable) + i=i+1 + arg += input(i) + } else { + arg += input(i) + } + i = i + 1 + } + if (arg nonEmpty) builder += arg.toString + + builder toArray + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UseMath.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UseMath.scala new file mode 100644 index 0000000..5f11c38 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UseMath.scala @@ -0,0 +1,19 @@ +package cc.sukazyo.cono.morny.util + +import scala.annotation.targetName + +/** @todo some tests */ +object UseMath { + + extension (self: Int) { + + def over (other: Int): Double = self.toDouble / other + + } + + extension (self: Int) { + @targetName("pow") + def ** (other: Int): Double = Math.pow(self, other) + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UseRandom.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UseRandom.scala new file mode 100644 index 0000000..b6eb096 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UseRandom.scala @@ -0,0 +1,33 @@ +package cc.sukazyo.cono.morny.util + +import scala.language.implicitConversions +import scala.util.Random + +/** + * @todo some tests maybe? + * @todo use the using clauses to provide random instance + */ +object UseRandom { + + class ChancePossibility[T <: Any] (val one: T) (using possibility: Double) { + def nor[U] (another: U): T|U = + if Random.nextDouble < possibility then one else another + } + + given Conversion[ChancePossibility[Boolean], Boolean] with + def apply(in: ChancePossibility[Boolean]): Boolean = in nor !in.one + + extension (num: Double) { + + def chance_is[T <: Any] (one: T): ChancePossibility[T] = + ChancePossibility(one)(using num) + + } + + def rand_half: Boolean = Random.nextBoolean + + def rand_id: String = + import ConvertByteHex.toHex + Random nextBytes 6 toHex + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/package.scala b/src/main/scala/cc/sukazyo/cono/morny/util/package.scala new file mode 100644 index 0000000..43bf99c --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/package.scala @@ -0,0 +1,22 @@ +package cc.sukazyo.cono.morny + +/** Utils that [[cc.sukazyo.cono.morny]]'s code used. + * + * contains: + * - [[tgapi Telegram API/Utils Extras]] + * - extensions of language standard + * - [[CommonEncrypt]] re-encapsulated some encrypt algorithms, and some normalized while encrypting. + * - [[CommonFormat]] provides some format methods normalized based on Morny usage standard. + * - [[ConvertByteHex]] extensions [[Byte]] and so on, make it easier converting binary data in it to a hex string. + * - [[UseMath]] scala style to make Math function easier to use + * - [[UseRandom]] scala style to use Random to generate something + * - external library extras + * - [[OkHttpPublic]] defines some static value for [[okhttp3]] + * - useful misc utils + * - [[FileUtils]] contains some easy-to-use file action. + * - [[UniversalCommand]] provides a easy way to get an args array from a string input. + * - others + * - [[BiliTool about Bilibili]] + * + */ +package object util {} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java rename to src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/InputCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/InputCommand.scala new file mode 100644 index 0000000..f6c7e26 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/InputCommand.scala @@ -0,0 +1,31 @@ +package cc.sukazyo.cono.morny.util.tgapi + +import cc.sukazyo.cono.morny.util.UniversalCommand + +class InputCommand private ( + val target: String|Null, + val command: String, + val args: Array[String] +) { + + override def toString: String = + s"{{$command}@{$target}#{${args.mkString}}" + +} + +object InputCommand { + + def apply (input: Array[String]): InputCommand = { + val _ex = input(0) split ("@", 2) + val _args = input drop 1 + new InputCommand( + if _ex.length == 1 then null else _ex(1), + _ex(0), + _args + ) + } + + def apply (input: String): InputCommand = + InputCommand(UniversalCommand(input)) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/Standardize.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/Standardize.scala new file mode 100644 index 0000000..2796c02 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/Standardize.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.util.tgapi + +object Standardize { + + val CHANNEL_SPEAKER_MAGIC_ID = 136817688 + + val MASK_BOTAPI_ID: Long = -1000000000000 + +} \ No newline at end of file diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.scala new file mode 100644 index 0000000..b44e7be --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.util.tgapi.event + +import com.pengrad.telegrambot.response.BaseResponse + +class EventRuntimeException (message: String) extends RuntimeException(message) + +object EventRuntimeException { + class ActionFailed (message: String, val response: BaseResponse) extends EventRuntimeException(message) +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/NamingUtils.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/NamingUtils.scala new file mode 100644 index 0000000..c0bc94b --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/NamingUtils.scala @@ -0,0 +1,11 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +import cc.sukazyo.cono.morny.util.CommonEncrypt +import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + +object NamingUtils { + + def inlineQueryId (tag: String, taggedData: String = ""): String = + CommonEncrypt.MD5(tag+taggedData) toHex + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala new file mode 100644 index 0000000..acc0d49 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala @@ -0,0 +1,82 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h +import cc.sukazyo.cono.morny.util.tgapi.Standardize.MASK_BOTAPI_ID +import com.pengrad.telegrambot.model.{Chat, Message, User} +import com.pengrad.telegrambot.model.Chat.Type + +object TelegramFormatter { + + extension (chat: Chat) { + + def safe_name: String = chat.`type` match + case Type.Private => _connectName(chat.firstName, chat.lastName) + case _ => chat.title + + def safe_linkHTML: String = + if (chat.username == null) + chat.`type` match + // language=html + case Type.Private => s"@[u:${chat.id}]" + // language=html + case _ => s"@[c/${chat.id}]" + else s"@${h(chat.username)}" + + def safe_firstnameRefHTML: String = + chat.`type` match + // language=html + case Type.Private => s"${h(chat.firstName)}" + // language=html + case _ => s"${h(chat.title)}" + + def id_tdLib: Long = + if chat.id < 0 then (chat.id - MASK_BOTAPI_ID)abs else chat.id + + def typeTag: String = chat.`type` match + case Type.Private => "🔒" + case Type.group => "💭" + case Type.supergroup => "💬" + case Type.channel => "📢" + + } + + extension (user: User) { + + def fullname: String = _connectName(user.firstName, user.lastName) + + def fullnameRefHTML: String = + // language=html + s"${h(user.fullname)}" + + def firstnameRefHTML: String = + // language=html + s"${h(user.firstName)}" + + def toLogTag: String = + (if (user.username == null) user.fullname + " " else "@" + user.username) + + "[" + user.id + "]" + + } + + extension (m: Message) { + + def sender_id: Long = + if m.senderChat == null then m.from.id else m.senderChat.id + + def sender_firstnameRefHTML: String = + if (m.senderChat == null) + m.from.firstnameRefHTML + else m.senderChat.safe_firstnameRefHTML + + } + + private inline def _link_user (id: Long): String = + s"tg://user?id=$id" + + private inline def _link_chat (id: Long): String = + s"https://t.me/c/$id" + + private inline def _connectName (firstName: String, lastName: String): String = + firstName + (if lastName == null then "" else " " + lastName) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramParseEscape.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramParseEscape.scala new file mode 100644 index 0000000..4b27795 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramParseEscape.scala @@ -0,0 +1,12 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +object TelegramParseEscape { + + def escapeHtml (input: String): String = + var process = input + process = process.replaceAll("&", "&") + process = process.replaceAll("<", "<") + process = process.replaceAll(">", ">") + process + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala new file mode 100644 index 0000000..81d87ee --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala @@ -0,0 +1,67 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +import com.pengrad.telegrambot.model.User +import okhttp3.{OkHttpClient, Request} + +import java.io.IOException +import scala.util.matching.Regex +import scala.util.Using + +object TelegramUserInformation { + + val DC_QUERY_SOURCE_SITE = "https://t.me/" + val DC_QUERY_PROCESSOR_REGEX: Regex = "(cdn[1-9]).tele(sco.pe|gram-cdn.org)"r + + private val httpClient = OkHttpClient() + + @throws[IllegalArgumentException|IOException] + def getDataCenterFromUser (username: String): String = { + val request = Request.Builder().url(DC_QUERY_SOURCE_SITE + username).build + Using (httpClient.newCall(request) execute) { response => + val body = response.body + if body eq null then "" + else DC_QUERY_PROCESSOR_REGEX.findFirstMatchIn(body.string) match + case Some(res) => res.group(1) + case None => "" + } get + } + + def getFormattedInformation (user: User): String = { + import TelegramParseEscape.escapeHtml as h + + val userInfo = StringBuilder() + + userInfo ++= // language=html + s"""userid : + |- ${user.id}""" + .stripMargin + userInfo ++= { + if (user.username eq null) // language=html + s""" + |username : null + |datacenter : not supported""" + .stripMargin + else // language=html + s""" + |username : + |- ${h(user.username)} + |datacenter : + |- ${h(getDataCenterFromUser(user.username))}""" + .stripMargin + } + userInfo ++= // language=html + s""" + |display name : + |- ${h(user.firstName)}${if user.lastName ne null then s"\n- ${h(user.lastName)}" else ""}""" + .stripMargin + if (user.languageCode ne null) userInfo ++= // language=html + s""" + |language-code : + |- ${user.languageCode}""" + .stripMargin + + userInfo toString + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/package.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/package.scala new file mode 100644 index 0000000..d646076 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/package.scala @@ -0,0 +1,4 @@ +package cc.sukazyo.cono.morny.util + +/** @todo docs */ +package object tgapi {} diff --git a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java deleted file mode 100644 index 4a36d44..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.sukazyo.cono.morny; - -import cc.sukazyo.cono.morny.util.UniversalCommand; - -import java.util.*; - -public class MornyCLI { - - public static void main (String[] args) { - - System.out.print("$ java -jar morny-coeur-"+MornySystem.VERSION_FULL()+".jar " ); - String x; - try (Scanner line = new Scanner(System.in)) { x = line.nextLine(); } - ServerMain.main(UniversalCommand.format(x)); - - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java b/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java deleted file mode 100644 index d686ea0..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.sukazyo.cono.morny.daemon; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.Set; - -import static cc.sukazyo.cono.morny.internal.ScalaJavaConv.jSetInteger2simm; - -public class TestMedicationTimer { - - @ParameterizedTest - @CsvSource(textBlock = """ - 2022-11-13T13:14:35.000+08, +08, 2022-11-13T19:00:00+08 - 2022-11-13T13:14:35.174+02, +02, 2022-11-13T19:00:00+02 - 1998-02-01T08:14:35.871+08, +08, 1998-02-01T19:00:00+08 - 2022-11-13T00:00:00.000-01, -01, 2022-11-13T07:00:00-01 - 2022-11-21T19:00:00.000+00, +00, 2022-11-21T21:00:00+00 - 2022-12-31T21:00:00.000+00, +00, 2023-01-01T07:00:00+00 - 2125-11-18T23:45:27.062+00, +00, 2125-11-19T07:00:00+00 - """) - void testCalcNextRoutineTimestamp (ZonedDateTime base, ZoneOffset zoneHour, ZonedDateTime expected) - throws IllegalArgumentException { - final Set at = Set.of(7, 19, 21); - System.out.println("base.toInstant().toEpochMilli() = " + base.toInstant().toEpochMilli()); - Assertions.assertEquals( - expected.toInstant().toEpochMilli(), - MedicationTimer.calcNextRoutineTimestamp(base.toInstant().toEpochMilli(), zoneHour, jSetInteger2simm(at)) - ); - System.out.println(" ok"); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java b/src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java deleted file mode 100644 index 125d9c6..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java +++ /dev/null @@ -1,30 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static cc.sukazyo.cono.morny.util.BiliTool.*; - -public class TestBiliTool { - - private static final String AV_BV_DATA_CSV = """ - 17x411w7KC, 170001 - 1Q541167Qg, 455017605 - 1mK4y1C7Bz, 882584971 - 1T24y197V2, 688730800 - """; - - @ParameterizedTest - @CsvSource(textBlock = AV_BV_DATA_CSV) - void testAvToBv (String bv, int av) { - Assertions.assertEquals(bv, toBv(av)); - } - - @ParameterizedTest - @CsvSource(textBlock = AV_BV_DATA_CSV) - void testBvToAv (String bv, int av) { - Assertions.assertEquals(av, toAv(bv)); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java deleted file mode 100644 index d35e55f..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java +++ /dev/null @@ -1,47 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.EnumSource; - -import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex; -import static cc.sukazyo.cono.morny.util.CommonConvert.byteToHex; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestCommonConvert { - - @ParameterizedTest - @CsvSource(textBlock = """ - 0x00, 00 - 0x01, 01 - 0x20, 20 - 0x77, 77 - -0x60, a0 - 0x0a, 0a - -0x01, ff - -0x05, fb - """ - ) - void testByteToHex(byte source, String expected) { - assertEquals(expected, byteToHex(source)); - } - - public enum TestByteArrayToHexSource { - $1(new T(new byte[]{0x00}, "00")), - $2(new T(new byte[]{(byte)0xff}, "ff")), - $3(new T(new byte[]{(byte)0xc3}, "c3")), - $4(new T(new byte[]{}, "")), - $5(new T(new byte[]{0x30,0x0a,0x00,0x04,(byte)0xb0,0x00}, "300a0004b000")), - $6(new T(new byte[]{0x00,0x00,0x0a,(byte)0xff,(byte)0xfc,(byte)0xab,(byte)0x00,0x04}, "00000afffcab0004")), - $7(new T(new byte[]{0x00,0x7c,0x11,0x28,(byte)0x88,(byte)0xa6,(byte)0xfc,0x30}, "007c112888a6fc30")); - public record T (byte[] raw, String expected) {} - public final T value; - TestByteArrayToHexSource (T value) { this.value = value; } - } - @ParameterizedTest - @EnumSource - void testByteArrayToHex (TestByteArrayToHexSource source) { - assertEquals(source.value.expected, byteArrayToHex(source.value.raw)); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java deleted file mode 100644 index 429b163..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java +++ /dev/null @@ -1,23 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex; -import static cc.sukazyo.cono.morny.util.CommonEncrypt.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestCommonEncrypt { - - @ParameterizedTest - @SuppressWarnings("UnnecessaryStringEscape") - @CsvSource(textBlock = """ - 28be57d368b75051da76c068a6733284, '莲子' - 9644c5cbae223013228cd528817ba4f5, '莲子\n' - d41d8cd98f00b204e9800998ecf8427e, '' - """) - void testHashMd5_String (String md5, String text) { - assertEquals(md5, byteArrayToHex(hashMd5(text))); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java deleted file mode 100644 index d7b67fe..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static cc.sukazyo.cono.morny.util.CommonFormat.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestCommonFormat { - - @ParameterizedTest - @CsvSource(textBlock = """ - 1664646870402, 8, 2022-10-02 01:54:30:402 - 1, 8, 1970-01-01 08:00:00:001 - 0, -1, 1969-12-31 23:00:00:000 - """ - ) - void testFormatDate (long timestamp, int utfOffset, String expectedHumanReadableTime) { - assertEquals(expectedHumanReadableTime, formatDate(timestamp, utfOffset)); - } - - @ParameterizedTest - @CsvSource(textBlock = """ - 100, '100ms' - 3000, '3s 0ms' - 326117522, '3d 18h 35min 17s 522ms' - 53373805, 14h 49min 33s 805ms - """) -// -1, '-1ms' // WARN: maybe sometime an unexpected usage -// -194271974291, '-291ms' // -// """) // - void testFormatDuration (long durationMillis, String humanReadableDuration) { - assertEquals(humanReadableDuration, formatDuration(durationMillis)); - } - -} diff --git a/src/test/scala/cc/sukazyo/cono/morny/MornyCLI.scala b/src/test/scala/cc/sukazyo/cono/morny/MornyCLI.scala new file mode 100644 index 0000000..a5c01f8 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/MornyCLI.scala @@ -0,0 +1,12 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.util.UniversalCommand + +import scala.io.StdIn + +@main def MornyCLI (): Unit = { + + print("$ java -jar morny-coeur-\"+MornySystem.VERSION_FULL+\".jar ") + ServerMain main UniversalCommand(StdIn readLine) + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/MornyTests.scala b/src/test/scala/cc/sukazyo/cono/morny/test/MornyTests.scala new file mode 100644 index 0000000..8d62c60 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/MornyTests.scala @@ -0,0 +1,10 @@ +package cc.sukazyo.cono.morny.test + +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should + +abstract class MornyTests extends AnyFreeSpec with should.Matchers { + + val pending_val = "[not-implemented]" + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/BiliToolTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/BiliToolTest.scala new file mode 100644 index 0000000..1ae8264 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/BiliToolTest.scala @@ -0,0 +1,68 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks + +import scala.util.Random + +class BiliToolTest extends MornyTests with TableDrivenPropertyChecks { + + private val examples = Table( + ("bv", "av"), + ("17x411w7KC", 170001L), + ("1Q541167Qg", 455017605L), + ("1mK4y1C7Bz", 882584971L), + ("1T24y197V2", 688730800L), + ) + + forAll (examples) { (bv, av) => s"while using av$av/BV$bv :" - { + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, toBv} + "av to bv works" in { toBv(av) shouldEqual bv } + "bv to av works" in { toAv(bv) shouldEqual av } + }} + + "BV with unsupported length :" - { + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, IllegalFormatException} + val examples = Table( + "bv", + "12345", + "12345678", + "123456789", +// "1234567890", length 10 which is supported + "1234567890a", + "1234567890ab", + "1234567890abcdef" + ) + forAll(examples) { bv => + s"length ${bv.length} should throws IllegalFormatException" in: + an [IllegalFormatException] should be thrownBy toAv(bv) + } + } + + "BV with special character :" - { + val examples = Table( + ("bv" , "contains_special"), + ("1mK4O1C7Bz", "O"), + ("1m04m1C7Bz", "0"), + ("1mK4O1I7Bz", "I"), + ("1mK4O1C7Bl", "l"), + ("1--4O1C7Bl", "[symbols]") + ) + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, IllegalFormatException} + forAll(examples) { (bv, with_sp) => + s"'$with_sp' should throws IllegalFormatException" in: + an [IllegalFormatException] should be thrownBy toAv(bv) + } + } + + "av/bv converting should be reversible" in { + for (_ <- 1 to 20) { + val rand_av = Random.between(0, 999999999L) + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, toBv} + val my_bv = toBv(rand_av) + toAv(my_bv) shouldEqual rand_av + toBv(toAv(my_bv)) shouldEqual my_bv + } + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonEncryptTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonEncryptTest.scala new file mode 100644 index 0000000..8557661 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonEncryptTest.scala @@ -0,0 +1,33 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks + +class CommonEncryptTest extends MornyTests with TableDrivenPropertyChecks { + + "while doing hash :" - { + + val examples = Table( + ("md5" , "text"), + ("28be57d368b75051da76c068a6733284", "莲子"), + ("9644c5cbae223013228cd528817ba4f5", "莲子\n"), + ("d41d8cd98f00b204e9800998ecf8427e", "") + ) + + import cc.sukazyo.cono.morny.util.CommonEncrypt.MD5 + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + forAll (examples) { (md5, text) => + s"while hashing text \"$text\" :" - { + + s"the MD5 value should be $md5" in { MD5(text).toHex shouldEqual md5 } + + "other algorithms" in pending + + } + } + + s"while hashing binary file $pending_val" in pending + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonFormatTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonFormatTest.scala new file mode 100644 index 0000000..33dac4f --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonFormatTest.scala @@ -0,0 +1,46 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} +import org.scalatest.prop.TableDrivenPropertyChecks + +class CommonFormatTest extends MornyTests with TableDrivenPropertyChecks { + + "while using #formatDate :" - { + + val examples = Table( + ("time_text" , "timestamp", "zone_offset"), + ("2022-10-02 01:54:30:402", 1664646870402L, 8), + ("1970-01-01 08:00:00:001", 1L, 8), + ("1969-12-31 23:00:00:000", 0L, -1), + ) + + forAll(examples) { (time_text, timestamp, zone_offset) => + s"time $time_text in TimeZone($zone_offset) should be UTC timestamp $timestamp" in: + formatDate(timestamp, zone_offset) shouldEqual time_text + } + + } + + "while using #formatDuration :" - { + + val examples = Table( + ("time_millis", "duration_text"), + (100L , "100ms"), + (3000L , "3s 0ms"), + (326117522L , "3d 18h 35min 17s 522ms"), + (53373805L , "14h 49min 33s 805ms"), + (3600001L , "1h 0min 0s 1ms") + ) + + forAll(examples) { (time_millis, duration_text) => + + s"duration ($time_millis) millis should be formatted to '$duration_text'" in: + formatDuration(time_millis) shouldEqual duration_text + 0 should equal (0) + + } + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/ConvertByteHexTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/ConvertByteHexTest.scala new file mode 100644 index 0000000..25aea93 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/ConvertByteHexTest.scala @@ -0,0 +1,45 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks + +class ConvertByteHexTest extends MornyTests with TableDrivenPropertyChecks { + + private val examples_hex = Table( + ("byte" , "hex"), + ( 0x00 toByte, "00"), + ( 0x01 toByte, "01"), + ( 0x20 toByte, "20"), + ( 0x77 toByte, "77"), + (-0x60 toByte, "a0"), + ( 0x0a toByte, "0a"), + (-0x01 toByte, "ff"), + ( 0xfb toByte, "fb"), + ) + + "while using Byte#toHex :" - forAll (examples_hex) ((byte, hex) => { + s"byte ($byte) should be hex '$hex''" in { + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + (byte toHex) shouldEqual hex + } + }) + + private val examples_hexs = Table( + ("bytes", "hex"), + (Array[Byte](0x00), "00"), + (Array[Byte](0xff toByte), "ff"), + (Array[Byte](0xc3 toByte), "c3"), + (Array[Byte](), ""), + (Array[Byte](0x30,0x0a,0x00,0x04,0xb0.toByte,0x00), "300a0004b000"), + (Array[Byte](0x00,0x00,0x0a,0xff.toByte,0xfc.toByte,0xab.toByte,0x00.toByte,0x04), "00000afffcab0004"), + (Array[Byte](0x00,0x7c,0x11,0x28,0x88.toByte,0xa6.toByte,0xfc.toByte,0x30), "007c112888a6fc30"), + ) + + "while using Array[Byte]#toHex :" - forAll(examples_hexs) ((bytes, hex) => { + s"byte array(${bytes mkString ","}) should be hex string $hex" in { + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + (bytes toHex) shouldEqual hex + } + }) + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/FileUtilsTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/FileUtilsTest.scala new file mode 100644 index 0000000..1873d12 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/FileUtilsTest.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests + +class FileUtilsTest extends MornyTests { + + "while getting the MD5 hash of a file :" in pending + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/UniversalCommandTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/UniversalCommandTest.scala new file mode 100644 index 0000000..28a11c5 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/UniversalCommandTest.scala @@ -0,0 +1,75 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableDrivenPropertyChecks + +class UniversalCommandTest extends MornyTests with Matchers with TableDrivenPropertyChecks { + + "while formatting command from String :" - { + + import cc.sukazyo.cono.morny.util.UniversalCommand as Cmd + + raw"args should be separated by (\u0020) ascii-space" in: + Cmd("a b c delta e") shouldEqual Array("a", "b", "c", "delta", "e"); + "args should not be separated by non-ascii spaces" in: + Cmd("tests ダタ セト") shouldEqual Array("tests", "ダタ セト"); + "multiple ascii-spaces should not generate empty arg in middle" in: + Cmd("tests some of data") shouldEqual Array("tests", "some", "of", "data"); + + """texts and ascii-spaces in '' should grouped in one arg""" in: + Cmd("""tests 'data set'""") shouldEqual Array("tests", "data set"); + """texts and ascii-spaces in "" should grouped in one arg""" in : + Cmd("""tests "data set"""") shouldEqual Array("tests", "data set"); + """mixed ' and " should throws IllegalArgumentsException""" in: + an [IllegalArgumentException] should be thrownBy Cmd("""tests "data set' "of it'"""); + "with ' not closed should throws IllegalArgumentException" in: + an [IllegalArgumentException] should be thrownBy Cmd("""use 'it """); + + raw"\ should escape itself" in: + Cmd(raw"input \\data") shouldEqual Array("input", "\\data"); + raw"\ should escape ascii-space, makes it processed as a normal character" in: + Cmd(raw"input data\ set") shouldEqual Array("input", "data set"); + raw"\ should escape ascii-space, makes it can be an arg body" in: + Cmd(raw"input \ some-thing") shouldEqual Array("input", " ", "some-thing"); + raw"""\ should escape "", makes it processed as a normal character""" in : + Cmd(raw"""use \"inputted""") shouldEqual Array("use", "\"inputted"); + raw"\ should escape '', makes it processed as a normal character" in: + Cmd(raw"use \'inputted") shouldEqual Array("use", "'inputted"); + raw"\ should escape itself which inside a quoted scope" in: + Cmd(raw"use 'quoted \\ body'") shouldEqual Array("use", "quoted \\ body"); + raw"""\ should escape " which inside a "" scope""" in: + Cmd(raw"""in "quoted \" body" body""") shouldEqual Array("in", "quoted \" body", "body"); + raw"""\ should escape ' which inside a "" scope""" in : + Cmd(raw"""in "not-quoted \' body" body""") shouldEqual Array("in", "not-quoted ' body", "body"); + raw"""\ should escape ' which inside a '' scope""" in : + Cmd(raw"""in 'quoted \' body' body""") shouldEqual Array("in", "quoted ' body", "body"); + raw"""\ should escape " which inside a ' scope""" in : + Cmd(raw"""in 'not-quoted \" body' body""") shouldEqual Array("in", "not-quoted \" body", "body"); + raw"\ should not escape ascii-space which inside a quoted scope" in: + Cmd(raw"""'quoted \ do not escape' did""") shouldEqual Array(raw"quoted \ do not escape", "did"); + raw"with \ in the end should throws IllegalArgumentException" in: + an [IllegalArgumentException] should be thrownBy Cmd("something error!\\"); + + "with multi-line input should throws IllegalArgumentException" in: + an [IllegalArgumentException] should be thrownBy Cmd("something will\nhave a new line"); + + val example_special_character = Table( + "char", + " ", + "\t", + "\\t", + "\\a", + "/", + "&&", + "\\u1234", + ) + forAll(example_special_character) { char => + s"input with special character ($char) should keep origin like" in { + Cmd(s"$char dataset data[$char]contains parsed") shouldEqual + Array(char, "dataset", s"data[$char]contains", "parsed") + } + } + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/InputCommandTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/InputCommandTest.scala new file mode 100644 index 0000000..3baa038 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/InputCommandTest.scala @@ -0,0 +1,22 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi + +import cc.sukazyo.cono.morny.test.MornyTests + +class InputCommandTest extends MornyTests { + + "while create new InputCommand :" - { + + s"while input is $pending_val:" - { + + s"command should be $pending_val" in pending + s"target should be $pending_val" in pending + + "args array should always exists" in pending + + s"args should parsed to array $pending_val" in pending + + } + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/NamingUtilsTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/NamingUtilsTest.scala new file mode 100644 index 0000000..883d8aa --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/NamingUtilsTest.scala @@ -0,0 +1,27 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests + +class NamingUtilsTest extends MornyTests { + + "while generating inline query result id :" - { + + "while not use no data :" - { + + "(different tag) should return different id" in pending + "(same tag) should return the same id" in pending + + } + + "while use data :" - { + + "(same tag) with (same data) should return the same id" in pending + "(same tag) with (different data) should return different id" in pending + "(different tag) with (same data) should return different id" in pending + "change tag and data position should return different id" in pending + + } + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramFormatterTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramFormatterTest.scala new file mode 100644 index 0000000..1fbd912 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramFormatterTest.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests + +class TelegramFormatterTest extends MornyTests { + + "some test" in pending + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramParseEscapeTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramParseEscapeTest.scala new file mode 100644 index 0000000..eb3f7da --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramParseEscapeTest.scala @@ -0,0 +1,25 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests + +class TelegramParseEscapeTest extends MornyTests { + + "while escape HTML document :" - { + + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h + val any_other = "0ir0Q*%_\"ir[0\"#*I%T\"I{EtjpJGI{\")#W*IT}P%*IH#){#NIJB9-/q{$(Jg'9m]q|MH4j0hq}|+($NR{')}}" + + "& must be escaped" in: + h("a & b") shouldEqual "a & b" + "< and > must be escaped" in: + h("") shouldEqual "<data-error>" + "& and < and > must all be escaped" in: + h(" && ") shouldEqual "<some-a> && <some-b>" + "space and count should be kept" in: + h("\t<<<< \n") shouldEqual "\t<<<< \n" + "any others should kept origin like" in: + h(any_other) shouldEqual any_other + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramUserInformationTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramUserInformationTest.scala new file mode 100644 index 0000000..c839a5b --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramUserInformationTest.scala @@ -0,0 +1,26 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks +import org.scalatest.tagobjects.{Network, Slow} + +class TelegramUserInformationTest extends MornyTests with TableDrivenPropertyChecks { + + private val examples_telegram_cdn = Table( + ("username", "cdn"), + ("Eyre_S", "cdn5"), + ) + + forAll(examples_telegram_cdn) ((username, cdn) => s"while user is @$username :" - { + + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation.* + + s"datacenter should be $cdn" taggedAs (Slow, Network) in: + getDataCenterFromUser(username) shouldEqual cdn + + "formatted data should as expected" in: + pending + + }) + +} diff --git a/src/test/scala/live/LiveMain.scala b/src/test/scala/live/LiveMain.scala new file mode 100644 index 0000000..2b7de09 --- /dev/null +++ b/src/test/scala/live/LiveMain.scala @@ -0,0 +1,9 @@ +package live + +import cc.sukazyo.cono.morny.test.utils.BiliToolTest + +@main def LiveMain (args: String*): Unit = { + + org.scalatest.run(BiliToolTest()) + +}