├── .editorconfig ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── lint-check.yml │ └── lint-fixer.yml ├── LICENSE ├── README.md ├── composer.json ├── config └── notifex.php ├── migrations ├── 2018_07_11_140701_create_error_notifications_table.php └── 2019_03_12_140701_delete_error_notifications_table.php ├── resources └── views │ ├── body.blade.php │ ├── raw.blade.php │ └── subject.blade.php └── src ├── Abstracts └── JobAbstract.php ├── Console └── TestException.php ├── Exceptions └── NotifexTestException.php ├── Facades ├── App.php └── Http.php ├── Interfaces └── JobInterface.php ├── Jobs ├── ExampleJob.php ├── JiraJob.php └── SlackJob.php ├── Mail └── ExceptionEmail.php ├── Notifications └── SlackNotify.php ├── ServiceProvider.php ├── Services ├── Email.php ├── ExceptionHandler.php └── NotifyException.php ├── Support ├── App.php └── Http.php └── Traits └── JobsConfiguration.php /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = lf 4 | indent_size = 4 5 | indent_style = space 6 | insert_final_newline = true 7 | max_line_length = 180 8 | tab_width = 4 9 | trim_trailing_whitespace = false 10 | ij_continuation_indent_size = 8 11 | ij_formatter_off_tag = @formatter:off 12 | ij_formatter_on_tag = @formatter:on 13 | ij_formatter_tags_enabled = true 14 | ij_smart_tabs = false 15 | ij_visual_guides = none 16 | ij_wrap_on_typing = false 17 | 18 | [*.blade.php] 19 | ij_continuation_indent_size = 4 20 | ij_blade_keep_indents_on_empty_lines = false 21 | 22 | [*.css] 23 | ij_css_align_closing_brace_with_properties = false 24 | ij_css_blank_lines_around_nested_selector = 1 25 | ij_css_blank_lines_between_blocks = 1 26 | ij_css_block_comment_add_space = true 27 | ij_css_brace_placement = end_of_line 28 | ij_css_enforce_quotes_on_format = true 29 | ij_css_hex_color_long_format = true 30 | ij_css_hex_color_lower_case = false 31 | ij_css_hex_color_short_format = false 32 | ij_css_hex_color_upper_case = true 33 | ij_css_keep_blank_lines_in_code = 1 34 | ij_css_keep_indents_on_empty_lines = false 35 | ij_css_keep_single_line_blocks = false 36 | 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 37 | ij_css_space_after_colon = true 38 | ij_css_space_before_opening_brace = true 39 | ij_css_use_double_quotes = true 40 | ij_css_value_alignment = do_not_align 41 | 42 | [*.haml] 43 | indent_size = 2 44 | ij_haml_keep_indents_on_empty_lines = false 45 | 46 | [*.less] 47 | indent_size = 2 48 | ij_less_align_closing_brace_with_properties = false 49 | ij_less_blank_lines_around_nested_selector = 1 50 | ij_less_blank_lines_between_blocks = 1 51 | ij_less_block_comment_add_space = false 52 | ij_less_brace_placement = 0 53 | ij_less_enforce_quotes_on_format = false 54 | ij_less_hex_color_long_format = true 55 | ij_less_hex_color_lower_case = false 56 | ij_less_hex_color_short_format = false 57 | ij_less_hex_color_upper_case = true 58 | ij_less_keep_blank_lines_in_code = 2 59 | ij_less_keep_indents_on_empty_lines = false 60 | ij_less_keep_single_line_blocks = false 61 | ij_less_line_comment_add_space = false 62 | ij_less_line_comment_at_first_column = false 63 | 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 64 | ij_less_space_after_colon = true 65 | ij_less_space_before_opening_brace = true 66 | ij_less_use_double_quotes = true 67 | ij_less_value_alignment = 0 68 | 69 | [*.sass] 70 | indent_size = 2 71 | ij_sass_align_closing_brace_with_properties = false 72 | ij_sass_blank_lines_around_nested_selector = 1 73 | ij_sass_blank_lines_between_blocks = 1 74 | ij_sass_brace_placement = 0 75 | ij_sass_enforce_quotes_on_format = false 76 | ij_sass_hex_color_long_format = false 77 | ij_sass_hex_color_lower_case = false 78 | ij_sass_hex_color_short_format = false 79 | ij_sass_hex_color_upper_case = false 80 | ij_sass_keep_blank_lines_in_code = 2 81 | ij_sass_keep_indents_on_empty_lines = false 82 | ij_sass_keep_single_line_blocks = false 83 | ij_sass_line_comment_add_space = false 84 | ij_sass_line_comment_at_first_column = false 85 | 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 86 | ij_sass_space_after_colon = true 87 | ij_sass_space_before_opening_brace = true 88 | ij_sass_use_double_quotes = true 89 | ij_sass_value_alignment = 0 90 | 91 | [*.scss] 92 | ij_scss_align_closing_brace_with_properties = false 93 | ij_scss_blank_lines_around_nested_selector = 1 94 | ij_scss_blank_lines_between_blocks = 1 95 | ij_scss_block_comment_add_space = true 96 | ij_scss_brace_placement = 0 97 | ij_scss_enforce_quotes_on_format = true 98 | ij_scss_hex_color_long_format = true 99 | ij_scss_hex_color_lower_case = false 100 | ij_scss_hex_color_short_format = false 101 | ij_scss_hex_color_upper_case = true 102 | ij_scss_keep_blank_lines_in_code = 1 103 | ij_scss_keep_indents_on_empty_lines = false 104 | ij_scss_keep_single_line_blocks = false 105 | ij_scss_line_comment_add_space = false 106 | ij_scss_line_comment_at_first_column = false 107 | 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 108 | ij_scss_space_after_colon = true 109 | ij_scss_space_before_opening_brace = true 110 | ij_scss_use_double_quotes = true 111 | ij_scss_value_alignment = 0 112 | 113 | [*.twig] 114 | ij_twig_keep_indents_on_empty_lines = false 115 | ij_twig_spaces_inside_comments_delimiters = true 116 | ij_twig_spaces_inside_delimiters = true 117 | ij_twig_spaces_inside_variable_delimiters = true 118 | 119 | [*.vue] 120 | ij_continuation_indent_size = 4 121 | ij_vue_indent_children_of_top_level = template 122 | ij_vue_interpolation_new_line_after_start_delimiter = true 123 | ij_vue_interpolation_new_line_before_end_delimiter = true 124 | ij_vue_interpolation_wrap = off 125 | ij_vue_keep_indents_on_empty_lines = false 126 | ij_vue_spaces_within_interpolation_expressions = true 127 | 128 | [.editorconfig] 129 | ij_editorconfig_align_group_field_declarations = false 130 | ij_editorconfig_space_after_colon = false 131 | ij_editorconfig_space_after_comma = true 132 | ij_editorconfig_space_before_colon = false 133 | ij_editorconfig_space_before_comma = false 134 | ij_editorconfig_spaces_around_assignment_operators = true 135 | 136 | [{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}] 137 | ij_xml_align_attributes = true 138 | ij_xml_align_text = false 139 | ij_xml_attribute_wrap = normal 140 | ij_xml_block_comment_add_space = true 141 | ij_xml_block_comment_at_first_column = true 142 | ij_xml_keep_blank_lines = 2 143 | ij_xml_keep_indents_on_empty_lines = false 144 | ij_xml_keep_line_breaks = true 145 | ij_xml_keep_line_breaks_in_text = true 146 | ij_xml_keep_whitespaces = false 147 | ij_xml_keep_whitespaces_around_cdata = preserve 148 | ij_xml_keep_whitespaces_inside_cdata = false 149 | ij_xml_line_comment_at_first_column = true 150 | ij_xml_space_after_tag_name = false 151 | ij_xml_space_around_equals_in_attribute = false 152 | ij_xml_space_inside_empty_tag = true 153 | ij_xml_text_wrap = normal 154 | 155 | [{*.ats,*.cts,*.mts,*.ts}] 156 | ij_continuation_indent_size = 4 157 | ij_typescript_align_imports = false 158 | ij_typescript_align_multiline_array_initializer_expression = false 159 | ij_typescript_align_multiline_binary_operation = false 160 | ij_typescript_align_multiline_chained_methods = false 161 | ij_typescript_align_multiline_extends_list = false 162 | ij_typescript_align_multiline_for = true 163 | ij_typescript_align_multiline_parameters = true 164 | ij_typescript_align_multiline_parameters_in_calls = false 165 | ij_typescript_align_multiline_ternary_operation = false 166 | ij_typescript_align_object_properties = 0 167 | ij_typescript_align_union_types = false 168 | ij_typescript_align_var_statements = 0 169 | ij_typescript_array_initializer_new_line_after_left_brace = false 170 | ij_typescript_array_initializer_right_brace_on_new_line = false 171 | ij_typescript_array_initializer_wrap = off 172 | ij_typescript_assignment_wrap = off 173 | ij_typescript_binary_operation_sign_on_next_line = false 174 | ij_typescript_binary_operation_wrap = off 175 | ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** 176 | ij_typescript_blank_lines_after_imports = 1 177 | ij_typescript_blank_lines_around_class = 1 178 | ij_typescript_blank_lines_around_field = 0 179 | ij_typescript_blank_lines_around_field_in_interface = 0 180 | ij_typescript_blank_lines_around_function = 1 181 | ij_typescript_blank_lines_around_method = 1 182 | ij_typescript_blank_lines_around_method_in_interface = 1 183 | ij_typescript_block_brace_style = end_of_line 184 | ij_typescript_block_comment_add_space = false 185 | ij_typescript_block_comment_at_first_column = true 186 | ij_typescript_call_parameters_new_line_after_left_paren = false 187 | ij_typescript_call_parameters_right_paren_on_new_line = false 188 | ij_typescript_call_parameters_wrap = off 189 | ij_typescript_catch_on_new_line = false 190 | ij_typescript_chained_call_dot_on_new_line = true 191 | ij_typescript_class_brace_style = next_line 192 | ij_typescript_comma_on_new_line = false 193 | ij_typescript_do_while_brace_force = never 194 | ij_typescript_else_on_new_line = false 195 | ij_typescript_enforce_trailing_comma = remove 196 | ij_typescript_enum_constants_wrap = on_every_item 197 | ij_typescript_extends_keyword_wrap = off 198 | ij_typescript_extends_list_wrap = off 199 | ij_typescript_field_prefix = _ 200 | ij_typescript_file_name_style = relaxed 201 | ij_typescript_finally_on_new_line = false 202 | ij_typescript_for_brace_force = never 203 | ij_typescript_for_statement_new_line_after_left_paren = false 204 | ij_typescript_for_statement_right_paren_on_new_line = false 205 | ij_typescript_for_statement_wrap = off 206 | ij_typescript_force_quote_style = true 207 | ij_typescript_force_semicolon_style = true 208 | ij_typescript_function_expression_brace_style = end_of_line 209 | ij_typescript_if_brace_force = never 210 | ij_typescript_import_merge_members = global 211 | ij_typescript_import_prefer_absolute_path = global 212 | ij_typescript_import_sort_members = true 213 | ij_typescript_import_sort_module_name = false 214 | ij_typescript_import_use_node_resolution = true 215 | ij_typescript_imports_wrap = on_every_item 216 | ij_typescript_indent_case_from_switch = true 217 | ij_typescript_indent_chained_calls = true 218 | ij_typescript_indent_package_children = 0 219 | ij_typescript_jsdoc_include_types = false 220 | ij_typescript_jsx_attribute_value = braces 221 | ij_typescript_keep_blank_lines_in_code = 1 222 | ij_typescript_keep_first_column_comment = true 223 | ij_typescript_keep_indents_on_empty_lines = false 224 | ij_typescript_keep_line_breaks = true 225 | ij_typescript_keep_simple_blocks_in_one_line = false 226 | ij_typescript_keep_simple_methods_in_one_line = false 227 | ij_typescript_line_comment_add_space = true 228 | ij_typescript_line_comment_at_first_column = false 229 | ij_typescript_method_brace_style = next_line 230 | ij_typescript_method_call_chain_wrap = off 231 | ij_typescript_method_parameters_new_line_after_left_paren = false 232 | ij_typescript_method_parameters_right_paren_on_new_line = false 233 | ij_typescript_method_parameters_wrap = off 234 | ij_typescript_object_literal_wrap = on_every_item 235 | ij_typescript_parentheses_expression_new_line_after_left_paren = false 236 | ij_typescript_parentheses_expression_right_paren_on_new_line = false 237 | ij_typescript_place_assignment_sign_on_next_line = false 238 | ij_typescript_prefer_as_type_cast = false 239 | ij_typescript_prefer_explicit_types_function_expression_returns = false 240 | ij_typescript_prefer_explicit_types_function_returns = false 241 | ij_typescript_prefer_explicit_types_vars_fields = false 242 | ij_typescript_prefer_parameters_wrap = false 243 | ij_typescript_reformat_c_style_comments = false 244 | ij_typescript_space_after_colon = true 245 | ij_typescript_space_after_comma = true 246 | ij_typescript_space_after_dots_in_rest_parameter = false 247 | ij_typescript_space_after_generator_mult = true 248 | ij_typescript_space_after_property_colon = true 249 | ij_typescript_space_after_quest = true 250 | ij_typescript_space_after_type_colon = true 251 | ij_typescript_space_after_unary_not = true 252 | ij_typescript_space_before_async_arrow_lparen = true 253 | ij_typescript_space_before_catch_keyword = true 254 | ij_typescript_space_before_catch_left_brace = true 255 | ij_typescript_space_before_catch_parentheses = true 256 | ij_typescript_space_before_class_lbrace = true 257 | ij_typescript_space_before_class_left_brace = true 258 | ij_typescript_space_before_colon = true 259 | ij_typescript_space_before_comma = false 260 | ij_typescript_space_before_do_left_brace = true 261 | ij_typescript_space_before_else_keyword = true 262 | ij_typescript_space_before_else_left_brace = true 263 | ij_typescript_space_before_finally_keyword = true 264 | ij_typescript_space_before_finally_left_brace = true 265 | ij_typescript_space_before_for_left_brace = true 266 | ij_typescript_space_before_for_parentheses = true 267 | ij_typescript_space_before_for_semicolon = false 268 | ij_typescript_space_before_function_left_parenth = true 269 | ij_typescript_space_before_generator_mult = false 270 | ij_typescript_space_before_if_left_brace = true 271 | ij_typescript_space_before_if_parentheses = true 272 | ij_typescript_space_before_method_call_parentheses = false 273 | ij_typescript_space_before_method_left_brace = true 274 | ij_typescript_space_before_method_parentheses = false 275 | ij_typescript_space_before_property_colon = false 276 | ij_typescript_space_before_quest = true 277 | ij_typescript_space_before_switch_left_brace = true 278 | ij_typescript_space_before_switch_parentheses = true 279 | ij_typescript_space_before_try_left_brace = true 280 | ij_typescript_space_before_type_colon = false 281 | ij_typescript_space_before_unary_not = false 282 | ij_typescript_space_before_while_keyword = true 283 | ij_typescript_space_before_while_left_brace = true 284 | ij_typescript_space_before_while_parentheses = true 285 | ij_typescript_spaces_around_additive_operators = true 286 | ij_typescript_spaces_around_arrow_function_operator = true 287 | ij_typescript_spaces_around_assignment_operators = true 288 | ij_typescript_spaces_around_bitwise_operators = true 289 | ij_typescript_spaces_around_equality_operators = true 290 | ij_typescript_spaces_around_logical_operators = true 291 | ij_typescript_spaces_around_multiplicative_operators = true 292 | ij_typescript_spaces_around_relational_operators = true 293 | ij_typescript_spaces_around_shift_operators = true 294 | ij_typescript_spaces_around_unary_operator = false 295 | ij_typescript_spaces_within_array_initializer_brackets = false 296 | ij_typescript_spaces_within_brackets = false 297 | ij_typescript_spaces_within_catch_parentheses = false 298 | ij_typescript_spaces_within_for_parentheses = false 299 | ij_typescript_spaces_within_if_parentheses = false 300 | ij_typescript_spaces_within_imports = true 301 | ij_typescript_spaces_within_interpolation_expressions = true 302 | ij_typescript_spaces_within_method_call_parentheses = false 303 | ij_typescript_spaces_within_method_parentheses = false 304 | ij_typescript_spaces_within_object_literal_braces = true 305 | ij_typescript_spaces_within_object_type_braces = true 306 | ij_typescript_spaces_within_parentheses = false 307 | ij_typescript_spaces_within_switch_parentheses = false 308 | ij_typescript_spaces_within_type_assertion = false 309 | ij_typescript_spaces_within_union_types = true 310 | ij_typescript_spaces_within_while_parentheses = false 311 | ij_typescript_special_else_if_treatment = true 312 | ij_typescript_ternary_operation_signs_on_next_line = false 313 | ij_typescript_ternary_operation_wrap = off 314 | ij_typescript_union_types_wrap = on_every_item 315 | ij_typescript_use_chained_calls_group_indents = false 316 | ij_typescript_use_double_quotes = false 317 | ij_typescript_use_explicit_js_extension = auto 318 | ij_typescript_use_path_mapping = always 319 | ij_typescript_use_public_modifier = false 320 | ij_typescript_use_semicolon_after_statement = false 321 | ij_typescript_var_declaration_wrap = normal 322 | ij_typescript_while_brace_force = never 323 | ij_typescript_while_on_new_line = false 324 | ij_typescript_wrap_comments = false 325 | 326 | [{*.bash,*.sh,*.zsh}] 327 | ij_shell_binary_ops_start_line = false 328 | ij_shell_keep_column_alignment_padding = false 329 | ij_shell_minify_program = false 330 | ij_shell_redirect_followed_by_space = false 331 | ij_shell_switch_cases_indented = false 332 | ij_shell_use_unix_line_separator = true 333 | 334 | [{*.cjs,*.js}] 335 | ij_continuation_indent_size = 4 336 | ij_javascript_align_imports = false 337 | ij_javascript_align_multiline_array_initializer_expression = false 338 | ij_javascript_align_multiline_binary_operation = false 339 | ij_javascript_align_multiline_chained_methods = false 340 | ij_javascript_align_multiline_extends_list = false 341 | ij_javascript_align_multiline_for = true 342 | ij_javascript_align_multiline_parameters = true 343 | ij_javascript_align_multiline_parameters_in_calls = false 344 | ij_javascript_align_multiline_ternary_operation = false 345 | ij_javascript_align_object_properties = 0 346 | ij_javascript_align_union_types = false 347 | ij_javascript_align_var_statements = 1 348 | ij_javascript_array_initializer_new_line_after_left_brace = true 349 | ij_javascript_array_initializer_right_brace_on_new_line = true 350 | ij_javascript_array_initializer_wrap = on_every_item 351 | ij_javascript_assignment_wrap = off 352 | ij_javascript_binary_operation_sign_on_next_line = false 353 | ij_javascript_binary_operation_wrap = off 354 | ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** 355 | ij_javascript_blank_lines_after_imports = 1 356 | ij_javascript_blank_lines_around_class = 1 357 | ij_javascript_blank_lines_around_field = 0 358 | ij_javascript_blank_lines_around_function = 1 359 | ij_javascript_blank_lines_around_method = 1 360 | ij_javascript_block_brace_style = end_of_line 361 | ij_javascript_block_comment_add_space = false 362 | ij_javascript_block_comment_at_first_column = true 363 | ij_javascript_call_parameters_new_line_after_left_paren = false 364 | ij_javascript_call_parameters_right_paren_on_new_line = false 365 | ij_javascript_call_parameters_wrap = off 366 | ij_javascript_catch_on_new_line = false 367 | ij_javascript_chained_call_dot_on_new_line = true 368 | ij_javascript_class_brace_style = next_line 369 | ij_javascript_comma_on_new_line = false 370 | ij_javascript_do_while_brace_force = never 371 | ij_javascript_else_on_new_line = false 372 | ij_javascript_enforce_trailing_comma = remove 373 | ij_javascript_extends_keyword_wrap = off 374 | ij_javascript_extends_list_wrap = off 375 | ij_javascript_field_prefix = _ 376 | ij_javascript_file_name_style = lisp_case 377 | ij_javascript_finally_on_new_line = false 378 | ij_javascript_for_brace_force = never 379 | ij_javascript_for_statement_new_line_after_left_paren = false 380 | ij_javascript_for_statement_right_paren_on_new_line = false 381 | ij_javascript_for_statement_wrap = off 382 | ij_javascript_force_quote_style = true 383 | ij_javascript_force_semicolon_style = true 384 | ij_javascript_function_expression_brace_style = end_of_line 385 | ij_javascript_if_brace_force = never 386 | ij_javascript_import_merge_members = global 387 | ij_javascript_import_prefer_absolute_path = true 388 | ij_javascript_import_sort_members = true 389 | ij_javascript_import_sort_module_name = false 390 | ij_javascript_import_use_node_resolution = true 391 | ij_javascript_imports_wrap = on_every_item 392 | ij_javascript_indent_case_from_switch = true 393 | ij_javascript_indent_chained_calls = true 394 | ij_javascript_indent_package_children = 0 395 | ij_javascript_jsx_attribute_value = braces 396 | ij_javascript_keep_blank_lines_in_code = 1 397 | ij_javascript_keep_first_column_comment = true 398 | ij_javascript_keep_indents_on_empty_lines = false 399 | ij_javascript_keep_line_breaks = true 400 | ij_javascript_keep_simple_blocks_in_one_line = false 401 | ij_javascript_keep_simple_methods_in_one_line = false 402 | ij_javascript_line_comment_add_space = false 403 | ij_javascript_line_comment_at_first_column = false 404 | ij_javascript_method_brace_style = end_of_line 405 | ij_javascript_method_call_chain_wrap = off 406 | ij_javascript_method_parameters_new_line_after_left_paren = false 407 | ij_javascript_method_parameters_right_paren_on_new_line = false 408 | ij_javascript_method_parameters_wrap = off 409 | ij_javascript_object_literal_wrap = on_every_item 410 | ij_javascript_parentheses_expression_new_line_after_left_paren = false 411 | ij_javascript_parentheses_expression_right_paren_on_new_line = false 412 | ij_javascript_place_assignment_sign_on_next_line = false 413 | ij_javascript_prefer_as_type_cast = false 414 | ij_javascript_prefer_explicit_types_function_expression_returns = false 415 | ij_javascript_prefer_explicit_types_function_returns = false 416 | ij_javascript_prefer_explicit_types_vars_fields = false 417 | ij_javascript_prefer_parameters_wrap = false 418 | ij_javascript_reformat_c_style_comments = false 419 | ij_javascript_space_after_colon = true 420 | ij_javascript_space_after_comma = true 421 | ij_javascript_space_after_dots_in_rest_parameter = false 422 | ij_javascript_space_after_generator_mult = true 423 | ij_javascript_space_after_property_colon = true 424 | ij_javascript_space_after_quest = true 425 | ij_javascript_space_after_type_colon = true 426 | ij_javascript_space_after_unary_not = true 427 | ij_javascript_space_before_async_arrow_lparen = true 428 | ij_javascript_space_before_catch_keyword = true 429 | ij_javascript_space_before_catch_left_brace = true 430 | ij_javascript_space_before_catch_parentheses = true 431 | ij_javascript_space_before_class_lbrace = true 432 | ij_javascript_space_before_class_left_brace = true 433 | ij_javascript_space_before_colon = true 434 | ij_javascript_space_before_comma = false 435 | ij_javascript_space_before_do_left_brace = true 436 | ij_javascript_space_before_else_keyword = true 437 | ij_javascript_space_before_else_left_brace = true 438 | ij_javascript_space_before_finally_keyword = true 439 | ij_javascript_space_before_finally_left_brace = true 440 | ij_javascript_space_before_for_left_brace = true 441 | ij_javascript_space_before_for_parentheses = true 442 | ij_javascript_space_before_for_semicolon = false 443 | ij_javascript_space_before_function_left_parenth = true 444 | ij_javascript_space_before_generator_mult = false 445 | ij_javascript_space_before_if_left_brace = true 446 | ij_javascript_space_before_if_parentheses = true 447 | ij_javascript_space_before_method_call_parentheses = false 448 | ij_javascript_space_before_method_left_brace = true 449 | ij_javascript_space_before_method_parentheses = false 450 | ij_javascript_space_before_property_colon = false 451 | ij_javascript_space_before_quest = true 452 | ij_javascript_space_before_switch_left_brace = true 453 | ij_javascript_space_before_switch_parentheses = true 454 | ij_javascript_space_before_try_left_brace = true 455 | ij_javascript_space_before_type_colon = false 456 | ij_javascript_space_before_unary_not = false 457 | ij_javascript_space_before_while_keyword = true 458 | ij_javascript_space_before_while_left_brace = true 459 | ij_javascript_space_before_while_parentheses = true 460 | ij_javascript_spaces_around_additive_operators = true 461 | ij_javascript_spaces_around_arrow_function_operator = true 462 | ij_javascript_spaces_around_assignment_operators = true 463 | ij_javascript_spaces_around_bitwise_operators = true 464 | ij_javascript_spaces_around_equality_operators = true 465 | ij_javascript_spaces_around_logical_operators = true 466 | ij_javascript_spaces_around_multiplicative_operators = true 467 | ij_javascript_spaces_around_relational_operators = true 468 | ij_javascript_spaces_around_shift_operators = true 469 | ij_javascript_spaces_around_unary_operator = false 470 | ij_javascript_spaces_within_array_initializer_brackets = false 471 | ij_javascript_spaces_within_brackets = false 472 | ij_javascript_spaces_within_catch_parentheses = false 473 | ij_javascript_spaces_within_for_parentheses = false 474 | ij_javascript_spaces_within_if_parentheses = false 475 | ij_javascript_spaces_within_imports = true 476 | ij_javascript_spaces_within_interpolation_expressions = true 477 | ij_javascript_spaces_within_method_call_parentheses = false 478 | ij_javascript_spaces_within_method_parentheses = false 479 | ij_javascript_spaces_within_object_literal_braces = true 480 | ij_javascript_spaces_within_object_type_braces = true 481 | ij_javascript_spaces_within_parentheses = false 482 | ij_javascript_spaces_within_switch_parentheses = false 483 | ij_javascript_spaces_within_type_assertion = false 484 | ij_javascript_spaces_within_union_types = true 485 | ij_javascript_spaces_within_while_parentheses = false 486 | ij_javascript_special_else_if_treatment = true 487 | ij_javascript_ternary_operation_signs_on_next_line = false 488 | ij_javascript_ternary_operation_wrap = off 489 | ij_javascript_union_types_wrap = on_every_item 490 | ij_javascript_use_chained_calls_group_indents = false 491 | ij_javascript_use_double_quotes = false 492 | ij_javascript_use_explicit_js_extension = auto 493 | ij_javascript_use_path_mapping = always 494 | ij_javascript_use_public_modifier = false 495 | ij_javascript_use_semicolon_after_statement = false 496 | ij_javascript_var_declaration_wrap = on_every_item 497 | ij_javascript_while_brace_force = never 498 | ij_javascript_while_on_new_line = false 499 | ij_javascript_wrap_comments = false 500 | 501 | [{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}] 502 | ij_continuation_indent_size = 4 503 | ij_php_align_assignments = true 504 | ij_php_align_class_constants = false 505 | ij_php_align_group_field_declarations = false 506 | ij_php_align_inline_comments = true 507 | ij_php_align_key_value_pairs = true 508 | ij_php_align_match_arm_bodies = true 509 | ij_php_align_multiline_array_initializer_expression = true 510 | ij_php_align_multiline_binary_operation = false 511 | ij_php_align_multiline_chained_methods = false 512 | ij_php_align_multiline_extends_list = true 513 | ij_php_align_multiline_for = false 514 | ij_php_align_multiline_parameters = true 515 | ij_php_align_multiline_parameters_in_calls = false 516 | ij_php_align_multiline_ternary_operation = false 517 | ij_php_align_named_arguments = true 518 | ij_php_align_phpdoc_comments = false 519 | ij_php_align_phpdoc_param_names = false 520 | ij_php_anonymous_brace_style = next_line 521 | ij_php_api_weight = 28 522 | ij_php_array_initializer_new_line_after_left_brace = true 523 | ij_php_array_initializer_right_brace_on_new_line = true 524 | ij_php_array_initializer_wrap = on_every_item 525 | ij_php_assignment_wrap = on_every_item 526 | ij_php_attributes_wrap = split_into_lines 527 | ij_php_author_weight = 3 528 | ij_php_binary_operation_sign_on_next_line = true 529 | ij_php_binary_operation_wrap = on_every_item 530 | ij_php_blank_lines_after_class_header = 0 531 | ij_php_blank_lines_after_function = 1 532 | ij_php_blank_lines_after_imports = 1 533 | ij_php_blank_lines_after_opening_tag = 1 534 | ij_php_blank_lines_after_package = 1 535 | ij_php_blank_lines_around_class = 1 536 | ij_php_blank_lines_around_constants = 1 537 | ij_php_blank_lines_around_field = 1 538 | ij_php_blank_lines_around_method = 1 539 | ij_php_blank_lines_before_class_end = 0 540 | ij_php_blank_lines_before_imports = 1 541 | ij_php_blank_lines_before_method_body = 0 542 | ij_php_blank_lines_before_package = 1 543 | ij_php_blank_lines_before_return_statement = 1 544 | ij_php_blank_lines_between_imports = 1 545 | ij_php_block_brace_style = end_of_line 546 | ij_php_call_parameters_new_line_after_left_paren = false 547 | ij_php_call_parameters_right_paren_on_new_line = false 548 | ij_php_call_parameters_wrap = on_every_item 549 | ij_php_catch_on_new_line = true 550 | ij_php_category_weight = 28 551 | ij_php_class_brace_style = next_line 552 | ij_php_comma_after_last_argument = false 553 | ij_php_comma_after_last_array_element = true 554 | ij_php_comma_after_last_closure_use_var = false 555 | ij_php_comma_after_last_parameter = false 556 | ij_php_concat_spaces = true 557 | ij_php_copyright_weight = 4 558 | ij_php_deprecated_weight = 0 559 | ij_php_do_while_brace_force = always 560 | ij_php_else_if_style = combine 561 | ij_php_else_on_new_line = true 562 | ij_php_example_weight = 28 563 | ij_php_extends_keyword_wrap = normal 564 | ij_php_extends_list_wrap = off 565 | ij_php_fields_default_visibility = protected 566 | ij_php_filesource_weight = 28 567 | ij_php_finally_on_new_line = true 568 | ij_php_for_brace_force = always 569 | ij_php_for_statement_new_line_after_left_paren = false 570 | ij_php_for_statement_right_paren_on_new_line = false 571 | ij_php_for_statement_wrap = normal 572 | ij_php_force_empty_methods_in_one_line = false 573 | ij_php_force_short_declaration_array_style = true 574 | ij_php_getters_setters_naming_style = camel_case 575 | ij_php_getters_setters_order_style = getters_first 576 | ij_php_global_weight = 28 577 | ij_php_group_use_wrap = on_every_item 578 | ij_php_if_brace_force = always 579 | ij_php_if_lparen_on_next_line = true 580 | ij_php_if_rparen_on_next_line = true 581 | ij_php_ignore_weight = 28 582 | ij_php_import_sorting = alphabetic 583 | ij_php_indent_break_from_case = true 584 | ij_php_indent_case_from_switch = true 585 | ij_php_indent_code_in_php_tags = false 586 | ij_php_internal_weight = 1 587 | ij_php_keep_blank_lines_after_lbrace = 1 588 | ij_php_keep_blank_lines_before_right_brace = 0 589 | ij_php_keep_blank_lines_in_code = 1 590 | ij_php_keep_blank_lines_in_declarations = 0 591 | ij_php_keep_control_statement_in_one_line = true 592 | ij_php_keep_first_column_comment = false 593 | ij_php_keep_indents_on_empty_lines = false 594 | ij_php_keep_line_breaks = true 595 | ij_php_keep_rparen_and_lbrace_on_one_line = true 596 | ij_php_keep_simple_classes_in_one_line = true 597 | ij_php_keep_simple_methods_in_one_line = false 598 | ij_php_lambda_brace_style = end_of_line 599 | ij_php_license_weight = 5 600 | ij_php_line_comment_add_space = false 601 | ij_php_line_comment_at_first_column = false 602 | ij_php_link_weight = 7 603 | ij_php_lower_case_boolean_const = true 604 | ij_php_lower_case_keywords = true 605 | ij_php_lower_case_null_const = true 606 | ij_php_method_brace_style = next_line 607 | ij_php_method_call_chain_wrap = on_every_item 608 | ij_php_method_parameters_new_line_after_left_paren = true 609 | ij_php_method_parameters_right_paren_on_new_line = true 610 | ij_php_method_parameters_wrap = on_every_item 611 | ij_php_method_weight = 13 612 | ij_php_modifier_list_wrap = false 613 | ij_php_multiline_chained_calls_semicolon_on_new_line = false 614 | ij_php_namespace_brace_style = 2 615 | ij_php_new_line_after_php_opening_tag = true 616 | ij_php_null_type_position = in_the_end 617 | ij_php_package_weight = 28 618 | ij_php_param_weight = 9 619 | ij_php_parameters_attributes_wrap = split_into_lines 620 | ij_php_parentheses_expression_new_line_after_left_paren = false 621 | ij_php_parentheses_expression_right_paren_on_new_line = false 622 | ij_php_phpdoc_blank_line_before_tags = true 623 | ij_php_phpdoc_blank_lines_around_parameters = true 624 | ij_php_phpdoc_keep_blank_lines = true 625 | ij_php_phpdoc_param_spaces_between_name_and_description = 1 626 | ij_php_phpdoc_param_spaces_between_tag_and_type = 1 627 | ij_php_phpdoc_param_spaces_between_type_and_name = 1 628 | ij_php_phpdoc_use_fqcn = true 629 | ij_php_phpdoc_wrap_long_lines = true 630 | ij_php_place_assignment_sign_on_next_line = false 631 | ij_php_place_parens_for_constructor = 0 632 | ij_php_property_read_weight = 11 633 | ij_php_property_weight = 10 634 | ij_php_property_write_weight = 12 635 | ij_php_return_type_on_new_line = false 636 | ij_php_return_weight = 15 637 | ij_php_see_weight = 6 638 | ij_php_since_weight = 2 639 | ij_php_sort_phpdoc_elements = true 640 | ij_php_space_after_colon = true 641 | ij_php_space_after_colon_in_enum_backed_type = true 642 | ij_php_space_after_colon_in_named_argument = true 643 | ij_php_space_after_colon_in_return_type = true 644 | ij_php_space_after_comma = true 645 | ij_php_space_after_for_semicolon = true 646 | ij_php_space_after_quest = true 647 | ij_php_space_after_type_cast = true 648 | ij_php_space_after_unary_not = true 649 | ij_php_space_before_array_initializer_left_brace = true 650 | ij_php_space_before_catch_keyword = true 651 | ij_php_space_before_catch_left_brace = true 652 | ij_php_space_before_catch_parentheses = true 653 | ij_php_space_before_class_left_brace = true 654 | ij_php_space_before_closure_left_parenthesis = true 655 | ij_php_space_before_colon = true 656 | ij_php_space_before_colon_in_enum_backed_type = false 657 | ij_php_space_before_colon_in_named_argument = false 658 | ij_php_space_before_colon_in_return_type = false 659 | ij_php_space_before_comma = false 660 | ij_php_space_before_do_left_brace = true 661 | ij_php_space_before_else_keyword = true 662 | ij_php_space_before_else_left_brace = true 663 | ij_php_space_before_finally_keyword = true 664 | ij_php_space_before_finally_left_brace = true 665 | ij_php_space_before_for_left_brace = true 666 | ij_php_space_before_for_parentheses = true 667 | ij_php_space_before_for_semicolon = false 668 | ij_php_space_before_if_left_brace = true 669 | ij_php_space_before_if_parentheses = true 670 | ij_php_space_before_method_call_parentheses = false 671 | ij_php_space_before_method_left_brace = true 672 | ij_php_space_before_method_parentheses = false 673 | ij_php_space_before_quest = true 674 | ij_php_space_before_short_closure_left_parenthesis = true 675 | ij_php_space_before_switch_left_brace = true 676 | ij_php_space_before_switch_parentheses = true 677 | ij_php_space_before_try_left_brace = true 678 | ij_php_space_before_unary_not = false 679 | ij_php_space_before_while_keyword = true 680 | ij_php_space_before_while_left_brace = true 681 | ij_php_space_before_while_parentheses = true 682 | ij_php_space_between_ternary_quest_and_colon = false 683 | ij_php_spaces_around_additive_operators = true 684 | ij_php_spaces_around_arrow = false 685 | ij_php_spaces_around_assignment_in_declare = false 686 | ij_php_spaces_around_assignment_operators = true 687 | ij_php_spaces_around_bitwise_operators = true 688 | ij_php_spaces_around_equality_operators = true 689 | ij_php_spaces_around_logical_operators = true 690 | ij_php_spaces_around_multiplicative_operators = true 691 | ij_php_spaces_around_null_coalesce_operator = true 692 | ij_php_spaces_around_pipe_in_union_type = false 693 | ij_php_spaces_around_relational_operators = true 694 | ij_php_spaces_around_shift_operators = true 695 | ij_php_spaces_around_unary_operator = false 696 | ij_php_spaces_around_var_within_brackets = false 697 | ij_php_spaces_within_array_initializer_braces = false 698 | ij_php_spaces_within_brackets = false 699 | ij_php_spaces_within_catch_parentheses = false 700 | ij_php_spaces_within_for_parentheses = false 701 | ij_php_spaces_within_if_parentheses = false 702 | ij_php_spaces_within_method_call_parentheses = false 703 | ij_php_spaces_within_method_parentheses = false 704 | ij_php_spaces_within_parentheses = false 705 | ij_php_spaces_within_short_echo_tags = true 706 | ij_php_spaces_within_switch_parentheses = false 707 | ij_php_spaces_within_while_parentheses = false 708 | ij_php_special_else_if_treatment = false 709 | ij_php_subpackage_weight = 28 710 | ij_php_ternary_operation_signs_on_next_line = true 711 | ij_php_ternary_operation_wrap = on_every_item 712 | ij_php_throws_weight = 14 713 | ij_php_todo_weight = 28 714 | ij_php_treat_multiline_arrays_and_lambdas_multiline = false 715 | ij_php_unknown_tag_weight = 28 716 | ij_php_upper_case_boolean_const = false 717 | ij_php_upper_case_null_const = false 718 | ij_php_uses_weight = 28 719 | ij_php_var_weight = 28 720 | ij_php_variable_naming_style = snake_case 721 | ij_php_version_weight = 8 722 | ij_php_while_brace_force = always 723 | ij_php_while_on_new_line = true 724 | 725 | [{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}] 726 | ij_continuation_indent_size = 4 727 | ij_json_array_wrapping = on_every_item 728 | ij_json_keep_blank_lines_in_code = 1 729 | ij_json_keep_indents_on_empty_lines = false 730 | ij_json_keep_line_breaks = true 731 | ij_json_keep_trailing_comma = false 732 | ij_json_object_wrapping = on_every_item 733 | ij_json_property_alignment = do_not_align 734 | ij_json_space_after_colon = true 735 | ij_json_space_after_comma = true 736 | ij_json_space_before_colon = false 737 | ij_json_space_before_comma = false 738 | ij_json_spaces_within_braces = true 739 | ij_json_spaces_within_brackets = false 740 | ij_json_wrap_long_lines = false 741 | 742 | [{*.htm,*.html,*.sht,*.shtm,*.shtml}] 743 | ij_continuation_indent_size = 4 744 | ij_visual_guides = 160 745 | ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 746 | ij_html_align_attributes = false 747 | ij_html_align_text = false 748 | ij_html_attribute_wrap = on_every_item 749 | ij_html_block_comment_add_space = false 750 | ij_html_block_comment_at_first_column = true 751 | ij_html_do_not_align_children_of_min_lines = 0 752 | ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p 753 | ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot 754 | ij_html_enforce_quotes = true 755 | 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 756 | ij_html_keep_blank_lines = 2 757 | ij_html_keep_indents_on_empty_lines = false 758 | ij_html_keep_line_breaks = true 759 | ij_html_keep_line_breaks_in_text = true 760 | ij_html_keep_whitespaces = false 761 | ij_html_keep_whitespaces_inside = span,pre,textarea 762 | ij_html_line_comment_at_first_column = true 763 | ij_html_new_line_after_last_attribute = never 764 | ij_html_new_line_before_first_attribute = when_multiline 765 | ij_html_quote_style = double 766 | ij_html_remove_new_line_before_tags = br 767 | ij_html_space_after_tag_name = false 768 | ij_html_space_around_equality_in_attribute = false 769 | ij_html_space_inside_empty_tag = true 770 | ij_html_text_wrap = off 771 | 772 | [{*.markdown,*.md}] 773 | ij_markdown_force_one_space_after_blockquote_symbol = true 774 | ij_markdown_force_one_space_after_header_symbol = true 775 | ij_markdown_force_one_space_after_list_bullet = true 776 | ij_markdown_force_one_space_between_words = true 777 | ij_markdown_insert_quote_arrows_on_wrap = true 778 | ij_markdown_keep_indents_on_empty_lines = false 779 | ij_markdown_keep_line_breaks_inside_text_blocks = true 780 | ij_markdown_max_lines_around_block_elements = 1 781 | ij_markdown_max_lines_around_header = 1 782 | ij_markdown_max_lines_between_paragraphs = 1 783 | ij_markdown_min_lines_around_block_elements = 1 784 | ij_markdown_min_lines_around_header = 2 785 | ij_markdown_min_lines_between_paragraphs = 1 786 | ij_markdown_wrap_text_if_long = true 787 | ij_markdown_wrap_text_inside_blockquotes = true 788 | 789 | [{*.yaml,*.yml}] 790 | ij_yaml_align_values_properties = do_not_align 791 | ij_yaml_autoinsert_sequence_marker = true 792 | ij_yaml_block_mapping_on_new_line = false 793 | ij_yaml_indent_sequence_value = true 794 | ij_yaml_keep_indents_on_empty_lines = false 795 | ij_yaml_keep_line_breaks = true 796 | ij_yaml_sequence_on_new_line = true 797 | ij_yaml_space_before_colon = false 798 | ij_yaml_spaces_within_braces = true 799 | ij_yaml_spaces_within_brackets = true 800 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: TheDragonCode 2 | open_collective: dragon-code 3 | custom: [ "https://boosty.to/dragon-code", "https://yoomoney.ru/to/410012608840929" ] 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - 4 | package-ecosystem: github-actions 5 | directory: / 6 | schedule: 7 | interval: daily 8 | -------------------------------------------------------------------------------- /.github/workflows/lint-check.yml: -------------------------------------------------------------------------------- 1 | name: "Code-Style Check" 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | check: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v3 12 | 13 | - name: Checking PHP Syntax 14 | uses: TheDragonCode/codestyler@v2.6.2 15 | -------------------------------------------------------------------------------- /.github/workflows/lint-fixer.yml: -------------------------------------------------------------------------------- 1 | name: "Code-Style Fixer" 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | fix: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v3 14 | 15 | - name: Checking PHP Syntax 16 | uses: TheDragonCode/codestyler@v2.6.2 17 | with: 18 | github_token: ${{ secrets.COMPOSER_TOKEN }} 19 | fix: true 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Andrey Helldar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notifex 2 | 3 | Laravel Notify Exceptions 4 | 5 |

6 | Total Downloads 7 | Latest Stable Version 8 | Latest Unstable Version 9 | License 10 |

11 | 12 | > You can use both [official plugins](https://laravel.com/docs/10.x/notifications) from the Laravel team and [plugins](https://laravel-notification-channels.com/) from the [community](https://laravel-notification-channels.com/). 13 | > 14 | > Of course, you can also create your own. 15 | 16 | 17 | ## Installation 18 | 19 | To get the latest version of `Notifex`, simply require the project using [Composer](https://getcomposer.org): 20 | 21 | ``` 22 | composer require dragon-code/notify-exceptions 23 | ``` 24 | 25 | Instead, you may of course manually update your `require` block and run `composer update`: 26 | 27 | ```json 28 | { 29 | "require": { 30 | "dragon-code/notify-exceptions": "^4.0" 31 | } 32 | } 33 | ``` 34 | 35 | You can also publish the config file to change implementations (ie. interface to specific class): 36 | 37 | ``` 38 | php artisan vendor:publish --provider="DragonCode\Notifex\ServiceProvider" 39 | ``` 40 | 41 | And call `php artisan migrate` command from console. 42 | 43 | Now you can use the `app('notifex')` method. 44 | 45 | ### Upgrade from `andrey-helldar/notify-exceptions` 46 | 47 | 1. Replace `"andrey-helldar/notify-exceptions": "^3.0"` with `"dragon-code/notify-exceptions": "^4.0"` in the `composer.json` file; 48 | 3. Replace `Helldar\Notifex` namespace prefix with `DragonCode\Notifex`; 49 | 4. Call the `composer update` console command. 50 | 51 | ## Configuration 52 | 53 | ### Ingore bots 54 | 55 | By default, the package does not respond to errors created in the process of search bots. 56 | 57 | To enable error messages from bots, change the setting `ignore_bots` in [config/notifex.php](config/notifex.php) file. 58 | 59 | By default, false. 60 | 61 | 62 | ### Email 63 | 64 | See [configuration](config/notifex.php) file. 65 | 66 | Example email message: 67 | 68 | ![email-message](https://user-images.githubusercontent.com/10347617/53572196-c003c700-3b7b-11e9-93e0-bff5aab01078.png) 69 | 70 | 71 | ### Jira 72 | 73 | If you need to create issues in the Jira, then you need to install the package [lesstif/php-jira-rest-client](https://github.com/lesstif/php-jira-rest-client): 74 | 75 | ```bash 76 | composer require lesstif/php-jira-rest-client 77 | ``` 78 | 79 | ![2018-10-10_23-32-57](https://user-images.githubusercontent.com/10347617/46765597-187b1a80-cce8-11e8-91c4-ca2fffad88ff.png) 80 | 81 | 82 | ### Slack 83 | 84 | If you need to send messages in the Slack channel, then you need to install the 85 | package [laravel/slack-notification-channel](https://packagist.org/packages/laravel/slack-notification-channel): 86 | 87 | ```bash 88 | composer require laravel/slack-notification-channel 89 | ``` 90 | 91 | ### Your notification services 92 | 93 | You can easily connect your notification services. To do this, in block `jobs` of file `config/notifex.php`, add a call to its job: 94 | 95 | ```php 96 | \DragonCode\Notifex\Jobs\ExampleJob::class 97 | ``` 98 | 99 | If you need to pass any parameters to your job, you can use an associative entry, where the key is the link to the job class, and the values are the parameters: 100 | 101 | ```php 102 | \DragonCode\Notifex\Jobs\ExampleJob::class => [ 103 | 'host' => env('EXAMPLE_HOST'), // http://127.0.0.1:8080 104 | 'user' => env('EXAMPLE_USER'), // 'foo' 105 | 'password' => env('EXAMPLE_PASS'), // 'bar' 106 | 'other_key' => env('EXAMPLE_OTHER_KEY'), // 12345 107 | ], 108 | ``` 109 | 110 | Your job should inherit from the abstract class `DragonCode\Notifex\Abstracts\JobAbstract`. This will help to correctly create a class for work. 111 | 112 | To get the values of the settings you need to use the method `getConfig($class, $key)`: 113 | 114 | ```php 115 | $host = $this->getConfig(get_class(), 'host'); 116 | $user = $this->getConfig(get_class(), 'user'); 117 | $password = $this->getConfig(get_class(), 'password'); 118 | $other_key = $this->getConfig(get_class(), 'other_key'); 119 | 120 | // or add `config(string $key)` method: 121 | 122 | private function config(string $key) 123 | { 124 | return $this->getConfig(get_class(), $key); 125 | } 126 | 127 | $host = $this->config('host'); 128 | $user = $this->config('user'); 129 | $password = $this->config('password'); 130 | $other_key = $this->config('other_key'); 131 | ``` 132 | 133 | Examples of completed classes can be found here: 134 | 135 | * [ExampleJob](src/Jobs/ExampleJob.php) 136 | * [JiraJob](src/Jobs/JiraJob.php) 137 | 138 | It is worth noting that standard jobs of Laravel are used for the call: 139 | 140 | ```bash 141 | php artisan make:job 142 | ``` 143 | 144 | They should remove the call interface `ShouldQueue` and extend the class: 145 | 146 | ```php 147 | // before 148 | use Illuminate\Contracts\Queue\ShouldQueue; 149 | 150 | class ExampleJob implements ShouldQueue {} 151 | 152 | // after 153 | use DragonCode\Notifex\Abstracts\JobAbstract; 154 | 155 | class ExampleJob extends JobAbstract {} 156 | ``` 157 | 158 | As the abstract class includes a call of all necessary classes and interfaces. 159 | 160 | It's all! Enjoy 😊 161 | 162 | 163 | ## Using 164 | 165 | Add exception capturing to `app/Exceptions/Handler.php`: 166 | 167 | ```php 168 | public function report(Throwable $exception) 169 | { 170 | parent::report($exception); 171 | 172 | if (app()->bound('notifex') && $this->shouldReport($exception)) { 173 | app('notifex')->send($exception); 174 | } 175 | } 176 | ``` 177 | 178 | or just use in your code: 179 | 180 | ```php 181 | try { 182 | $foo = $bar 183 | } catch(\Exception $exception) { 184 | app('notifex')->send($exception); 185 | } 186 | ``` 187 | 188 | #### **IMPORTANT!** 189 | 190 | To realize the possibility of saving an object to a database table, this object is processed before serialization. Due to the peculiarities of linking objects in PHP, serialization 191 | does not support the `Throwable` interface, and therefore, if you call method `app('notifex')->send($exception)` before processing a variable, the application may cause an 192 | error `Expected array for frame 0`. 193 | 194 | To avoid this, use method `parent::report($exception)` strictly **before** sending notifications. 195 | 196 | 197 | ## Test message 198 | 199 | To verivy that Notifex is configured correctly and our integration is working, use `notifex:test` command: 200 | 201 | ``` 202 | php artisan notifex:test 203 | ``` 204 | 205 | A `DragonCode\Notifex\Exceptions\NotifexTestException` class will be thrown and captured by Notifex. The captured exception will appear in your configured email immediately. 206 | 207 | 208 | ## Support 209 | 210 | The package out of the box supports sending notifications to the following services: 211 | 212 | * **Email** _(default, enabled)_ 213 | * **Slack** _(default, disabled)_ 214 | * **Jira** _(default, disabled)_ 215 | 216 | ## License 217 | 218 | This package is licensed under the [MIT License](LICENSE). 219 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dragon-code/notify-exceptions", 3 | "description": "Notify the site administrator of any errors through various channels of communication.", 4 | "license": "MIT", 5 | "type": "library", 6 | "keywords": [ 7 | "notify exceptions", 8 | "notifex", 9 | "laravel", 10 | "exceptions", 11 | "slack", 12 | "email", 13 | "jira" 14 | ], 15 | "authors": [ 16 | { 17 | "name": "Andrey Helldar", 18 | "email": "helldar@dragon-code.pro", 19 | "homepage": "https://github.com/andrey-helldar" 20 | } 21 | ], 22 | "support": { 23 | "issues": "https://github.com/andrey-helldar/notify-exceptions/issues", 24 | "source": "https://github.com/andrey-helldar/notify-exceptions" 25 | }, 26 | "funding": [ 27 | { 28 | "type": "github", 29 | "url": "https://github.com/sponsors/TheDragonCode" 30 | }, 31 | { 32 | "type": "open_collective", 33 | "url": "https://opencollective.com/dragon-code" 34 | }, 35 | { 36 | "type": "boosty", 37 | "url": "https://boosty.to/dragon-code" 38 | }, 39 | { 40 | "type": "yoomoney", 41 | "url": "https://yoomoney.ru/to/410012608840929" 42 | } 43 | ], 44 | "require": { 45 | "php": "^7.2.5 || ^8.0", 46 | "guzzlehttp/guzzle": "^7.0", 47 | "illuminate/bus": "^7.0 || ^8.0 || ^9.0", 48 | "illuminate/console": "^7.0 || ^8.0 || ^9.0", 49 | "illuminate/contracts": "^7.0 || ^8.0 || ^9.0", 50 | "illuminate/notifications": "^7.0 || ^8.0 || ^9.0", 51 | "illuminate/queue": "^7.0 || ^8.0 || ^9.0", 52 | "illuminate/support": "^7.0 || ^8.0 || ^9.0", 53 | "illuminate/view": "^7.0 || ^8.0 || ^9.0", 54 | "jaybizzle/crawler-detect": "^1.2", 55 | "symfony/debug": "^4.0", 56 | "symfony/http-kernel": "^4.0 || ^5.0 || ^6.0" 57 | }, 58 | "require-dev": { 59 | "laravel/slack-notification-channel": "^2.0", 60 | "lesstif/php-jira-rest-client": "^2.1" 61 | }, 62 | "conflict": { 63 | "andrey-helldar/notify-exceptions": "*" 64 | }, 65 | "suggest": { 66 | "laravel/slack-notification-channel": "Slack Notification Channel for Laravel", 67 | "lesstif/php-jira-rest-client": "PHP classes interact Jira with the REST API.", 68 | "symfony/thanks": "Give thanks (in the form of a GitHub) to your fellow PHP package maintainers" 69 | }, 70 | "minimum-stability": "stable", 71 | "prefer-stable": true, 72 | "autoload": { 73 | "psr-4": { 74 | "DragonCode\\Notifex\\": "src" 75 | } 76 | }, 77 | "config": { 78 | "allow-plugins": { 79 | "dragon-code/codestyler": true, 80 | "ergebnis/composer-normalize": true, 81 | "friendsofphp/php-cs-fixer": true 82 | }, 83 | "preferred-install": "dist", 84 | "sort-packages": true 85 | }, 86 | "extra": { 87 | "laravel": { 88 | "providers": [ 89 | "DragonCode\\Notifex\\ServiceProvider" 90 | ] 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /config/notifex.php: -------------------------------------------------------------------------------- 1 | env('NOTIFEX_ENABLED', true), 7 | 8 | // Specifies the name of the queue into which to write an error event for dispatch. 9 | 10 | 'queue' => env('NOTIFEX_QUEUE', 'default'), 11 | 12 | // Determines whether to ignore messages from bots. 13 | 14 | 'ignore_bots' => true, 15 | // Determination of settings and status of sending to email. 16 | 17 | 'email' => [ 18 | // Determines if sending to email is allowed. 19 | 20 | 'enabled' => env('NOTIFEX_EMAIL_ENABLED', true), 21 | 22 | // Sets the sender's address. 23 | 24 | 'from' => env('NOTIFEX_EMAIL_FROM', 'example@example.com'), 25 | 26 | // Sets the recipient's address. 27 | 28 | 'to' => env('NOTIFEX_EMAIL_TO', 'example@example.com'), 29 | ], 30 | 31 | 'slack' => [ 32 | // Determines if sending to slack channel is allowed. 33 | 34 | 'enabled' => env('NOTIFEX_SLACK_ENABLED', false), 35 | 36 | // Sets the webhook address for sending a message. 37 | 38 | 'webhook' => env('NOTIFEX_SLACK_WEBHOOK'), 39 | 40 | /* 41 | * If specified, the name will be used, otherwise by default. 42 | * 43 | * Available: 44 | * ['Ghost', ':ghost:'] 45 | * ['Ghost'] 46 | * null 47 | * 48 | * By default, null 49 | */ 50 | 51 | 'from' => null, 52 | 53 | /* 54 | * If specified, notifications will be sent to the channel. 55 | * 56 | * By default, null. 57 | */ 58 | 59 | 'to' => null, 60 | ], 61 | 62 | 'jobs' => [ 63 | // \DragonCode\Notifex\Jobs\JiraJob::class => [ 64 | // 'enabled' => env('NOTIFEX_JIRA_ENABLED', false), 65 | // 66 | // 'host' => env('NOTIFEX_JIRA_HOST'), 67 | // 'user' => env('NOTIFEX_JIRA_USER'), 68 | // 'password' => env('NOTIFEX_JIRA_PASSWORD'), 69 | // 70 | // 'project_key' => env('NOTIFEX_JIRA_PROJECT_KEY'), 71 | // 'issue_type' => env('NOTIFEX_JIRA_ISSUE_TYPE', 'Bug'), 72 | // 'priority_name' => env('NOTIFEX_JIRA_PRIORITY_NAME', 'Critical'), 73 | //], 74 | // 75 | // @see \DragonCode\Notifex\Jobs\ExampleJob 76 | // \DragonCode\Notifex\Jobs\ExampleJob::class => [ 77 | // 'host' => env('EXAMPLE_HOST'), // http://127.0.0.1:8080 78 | // 'user' => env('EXAMPLE_USER'), // 'foo' 79 | // 'password' => env('EXAMPLE_PASS'), // 'bar' 80 | // 'other_key' => env('EXAMPLE_OTHER_KEY'), // 12345 81 | //], 82 | ], 83 | ]; 84 | -------------------------------------------------------------------------------- /migrations/2018_07_11_140701_create_error_notifications_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('id'); 13 | 14 | $table->string('parent'); 15 | $table->longText('exception'); 16 | 17 | $table->timestamps(); 18 | }); 19 | } 20 | 21 | public function down() 22 | { 23 | Schema::dropIfExists('error_notifications'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /migrations/2019_03_12_140701_delete_error_notifications_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('id'); 18 | 19 | $table->string('parent'); 20 | $table->longText('exception'); 21 | 22 | $table->timestamps(); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /resources/views/body.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 54 | 55 | 56 | 57 | {!! $content !!} 58 | 59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
URI{{ app('request')->url() }}
Full URI{{ app('request')->fullUrl() }}
Client IP{{ app('request')->getClientIp() ?? '127.0.0.1' }}
User ID{{ auth()->user()->id ?? 'Guest' }}
78 |
79 | 80 |
81 | 82 | @foreach(app('request')->all() as $key => $value) 83 | 84 | 85 | 86 | 87 | @endforeach 88 |
{{ $key }}{{ $value }}
89 |
90 | 91 |
92 | 🕐 {{ date('l, jS \of F Y h:i:s a') }} {{ date_default_timezone_get() }} 93 |
94 | 95 | 96 | -------------------------------------------------------------------------------- /resources/views/raw.blade.php: -------------------------------------------------------------------------------- 1 | {!! $content !!} 2 | -------------------------------------------------------------------------------- /resources/views/subject.blade.php: -------------------------------------------------------------------------------- 1 | [notifex] | {{ $environment }} | {{ $host }} | {{ class_basename($exception) }} 2 | -------------------------------------------------------------------------------- /src/Abstracts/JobAbstract.php: -------------------------------------------------------------------------------- 1 | classname = $classname; 38 | $this->message = $message; 39 | $this->file = $file; 40 | $this->line = $line; 41 | $this->trace_as_string = $trace_as_string; 42 | } 43 | 44 | protected function getConfig(string $class, string $key) 45 | { 46 | return Config::get(sprintf('notifex.jobs.%s.%s', $class, $key)); 47 | } 48 | 49 | protected function environment(): string 50 | { 51 | return App::environment(); 52 | } 53 | 54 | protected function classname(): string 55 | { 56 | return class_basename($this->classname); 57 | } 58 | 59 | protected function host(): string 60 | { 61 | return Http::host(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Console/TestException.php: -------------------------------------------------------------------------------- 1 | send( 19 | $this->getException() 20 | ); 21 | 22 | $this->info('Notifex is working fine ✅'); 23 | } 24 | catch (NotifexTestException $e) { 25 | $this->consoleApp()->renderThrowable($e, $this->output); 26 | } 27 | } 28 | 29 | protected function getException(): NotifexTestException 30 | { 31 | return new NotifexTestException(); 32 | } 33 | 34 | protected function consoleApp(): ConsoleApplication 35 | { 36 | return new ConsoleApplication(); 37 | } 38 | 39 | protected function send(NotifexTestException $e): void 40 | { 41 | app('notifex')->send($e); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Exceptions/NotifexTestException.php: -------------------------------------------------------------------------------- 1 | config('host'); 12 | $user = $this->config('user'); 13 | $password = $this->config('password'); 14 | $other_key = $this->config('other_key'); 15 | 16 | // Your actions. 17 | // 18 | // $classname = $this->classname; 19 | // $class_basename = class_basename($this->classname); 20 | // $message = $this->message; 21 | // $file = $this->file; 22 | // $line = $this->line; 23 | // $trace_as_string = $this->trace_as_string; 24 | } 25 | 26 | protected function config(string $key) 27 | { 28 | return $this->getConfig( 29 | $this->getClass(), 30 | $key 31 | ); 32 | } 33 | 34 | protected function getClass(): string 35 | { 36 | return get_class(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Jobs/JiraJob.php: -------------------------------------------------------------------------------- 1 | getIssueField(); 21 | $service = $this->getIssueService(); 22 | 23 | $field 24 | ->setProjectKey($this->config('project_key')) 25 | ->setIssueType($this->config('issue_type')) 26 | ->setPriorityName($this->config('priority_name')) 27 | ->setSummary($this->title()) 28 | ->setDescription($this->description()) 29 | ->addLabel($this->host()) 30 | ->addLabel($this->environment()) 31 | ->addLabel($this->classname()); 32 | 33 | $service->create($field); 34 | } 35 | 36 | protected function title(): string 37 | { 38 | return sprintf('%s | %s | %s', $this->environment(), $this->host(), $this->classname()); 39 | } 40 | 41 | protected function description(): string 42 | { 43 | return implode(PHP_EOL, [ 44 | sprintf('*%s*', $this->message), 45 | sprintf('_%s:%s_', $this->file, $this->line), 46 | sprintf('{code:bash}%s{code}', $this->trace_as_string), 47 | ]); 48 | } 49 | 50 | protected function getJiraConfiguration(): ArrayConfiguration 51 | { 52 | return new ArrayConfiguration([ 53 | 'jiraHost' => $this->config('host'), 54 | 'jiraUser' => $this->config('user'), 55 | 'jiraPassword' => $this->config('password'), 56 | ]); 57 | } 58 | 59 | protected function config(string $key) 60 | { 61 | return $this->getConfig(get_class(), $key); 62 | } 63 | 64 | protected function getIssueField(): IssueField 65 | { 66 | return new IssueField(); 67 | } 68 | 69 | /** 70 | * @throws \JiraRestApi\JiraException 71 | * 72 | * @return \JiraRestApi\Issue\IssueService 73 | */ 74 | protected function getIssueService(): IssueService 75 | { 76 | return new IssueService( 77 | $this->getJiraConfiguration() 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Jobs/SlackJob.php: -------------------------------------------------------------------------------- 1 | notify( 13 | $this->getSlackNotify() 14 | ); 15 | } 16 | 17 | /** 18 | * Route notifications for the Slack channel. 19 | * 20 | * @param \Illuminate\Notifications\Notification $notification 21 | * 22 | * @return string 23 | */ 24 | public function routeNotificationForSlack($notification): ?string 25 | { 26 | return $this->getConfig(get_class(), 'webhook'); 27 | } 28 | 29 | protected function title(): string 30 | { 31 | return implode(PHP_EOL, [ 32 | sprintf('*%s | %s | %s*', $this->environment(), $this->host(), $this->classname()), 33 | sprintf('`%s:%s`', $this->file, $this->line), 34 | ]); 35 | } 36 | 37 | protected function getSlackNotify(): SlackNotify 38 | { 39 | return new SlackNotify($this->title(), $this->message, $this->trace_as_string); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Mail/ExceptionEmail.php: -------------------------------------------------------------------------------- 1 | subject = $subject; 21 | $this->content = $content; 22 | $this->queue = $this->getQueueName(); 23 | } 24 | 25 | public function build() 26 | { 27 | $this->setMailTo(); 28 | $this->setMailFrom(); 29 | 30 | return $this->view('notifex::raw') 31 | ->with('content', $this->content); 32 | } 33 | 34 | protected function setMailTo(): void 35 | { 36 | $this->to( 37 | Config::get('notifex.email.to') 38 | ); 39 | } 40 | 41 | protected function setMailFrom(): void 42 | { 43 | $this->from( 44 | Config::get('notifex.email.from') 45 | ); 46 | } 47 | 48 | protected function getQueueName(): string 49 | { 50 | return Config::get('notifex.queue', 'default'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Notifications/SlackNotify.php: -------------------------------------------------------------------------------- 1 | title = $title; 24 | $this->message = $message; 25 | $this->trace_as_string = $trace_as_string; 26 | } 27 | 28 | /** 29 | * Get the notification's delivery channels. 30 | * 31 | * @param mixed $notifiable 32 | * 33 | * @return array 34 | */ 35 | public function via($notifiable) 36 | { 37 | return ['slack']; 38 | } 39 | 40 | /** 41 | * Get the Slack representation of the notification. 42 | * 43 | * @param $notifiable 44 | * 45 | * @return \Illuminate\Notifications\Messages\SlackMessage 46 | */ 47 | public function toSlack($notifiable) 48 | { 49 | return $this->prepareMessage($this->message()) 50 | ->error() 51 | ->content($this->title) 52 | ->attachment(function (SlackAttachment $attachment) { 53 | $attachment 54 | ->title($this->message) 55 | ->content($this->trace_as_string) 56 | ->footer($this->appName()) 57 | ->timestamp($this->currentTime()); 58 | }); 59 | } 60 | 61 | protected function message(): SlackMessage 62 | { 63 | return new SlackMessage(); 64 | } 65 | 66 | protected function prepareMessage(SlackMessage $message): SlackMessage 67 | { 68 | $this->from($message); 69 | $this->to($message); 70 | 71 | return $message; 72 | } 73 | 74 | protected function appName(): string 75 | { 76 | return App::name(); 77 | } 78 | 79 | protected function from(SlackMessage $message) 80 | { 81 | if ($from = Config::get('notifex.slack.from')) { 82 | if (count($from) === 2) { 83 | [$username, $icon] = $from; 84 | } 85 | elseif (count($from) === 1) { 86 | [$username] = $from; 87 | } 88 | 89 | if ($username ?? false) { 90 | $message->from($username, $icon ?? null); 91 | } 92 | } 93 | } 94 | 95 | protected function to(SlackMessage $message) 96 | { 97 | if ($to = Config::get('notifex.slack.to')) { 98 | $channel = ltrim($to, '#'); 99 | 100 | $message->to('#' . $channel); 101 | } 102 | } 103 | 104 | protected function currentTime(): DateTimeInterface 105 | { 106 | return Carbon::now(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(self::VIEWS_PATH, 'notifex'); 21 | 22 | if ($this->app->runningInConsole()) { 23 | $this->publishes([ 24 | self::CONFIG_PATH => $this->app->configPath('notifex.php'), 25 | ], 'config'); 26 | 27 | $this->publishes([ 28 | self::VIEWS_PATH => $this->app->resourcePath('views/vendor/notifex'), 29 | ], 'notifex-views'); 30 | 31 | $this->loadMigrationsFrom(__DIR__ . '/../migrations'); 32 | 33 | $this->commands([ 34 | TestException::class, 35 | ]); 36 | } 37 | } 38 | 39 | /** 40 | * Register bindings in the container. 41 | */ 42 | public function register() 43 | { 44 | $this->mergeConfigFrom(self::CONFIG_PATH, 'notifex'); 45 | 46 | $this->app->singleton('notifex', NotifyException::class); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | * 52 | * @return array 53 | */ 54 | public function provides() 55 | { 56 | return ['notifex']; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Services/Email.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 18 | $this->exception = $exception; 19 | 20 | $this->send( 21 | $this->getException() 22 | ); 23 | } 24 | 25 | protected function subject(): string 26 | { 27 | return $this->handler->convertExceptionToString($this->exception); 28 | } 29 | 30 | protected function content(): string 31 | { 32 | return $this->handler->convertExceptionToHtml($this->exception); 33 | } 34 | 35 | protected function getException(): ExceptionEmail 36 | { 37 | return new ExceptionEmail($this->subject(), $this->content()); 38 | } 39 | 40 | protected function send(ExceptionEmail $e): void 41 | { 42 | Mail::send($e); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Services/ExceptionHandler.php: -------------------------------------------------------------------------------- 1 | view = $view; 30 | } 31 | 32 | /** 33 | * Create a string for the given exception. 34 | * 35 | * @param Throwable $exception 36 | * 37 | * @return string 38 | */ 39 | public function convertExceptionToString(Throwable $exception) 40 | { 41 | $environment = $this->environment(); 42 | $host = $this->host(); 43 | 44 | return $this->view 45 | ->make('notifex::subject', compact('exception', 'environment', 'host')) 46 | ->render(); 47 | } 48 | 49 | /** 50 | * Create a html for the given exception. 51 | * 52 | * @param Throwable $exception 53 | * 54 | * @return string 55 | */ 56 | public function convertExceptionToHtml(Throwable $exception) 57 | { 58 | $flat = $this->getFlattenedException($exception); 59 | $handler = new SymfonyExceptionHandler(); 60 | 61 | return $this->decorate($handler->getContent($flat), $handler->getStylesheet($flat), $flat); 62 | } 63 | 64 | /** 65 | * Converts the Exception in a PHP Exception to be able to serialize it. 66 | * 67 | * @param Throwable $exception 68 | * 69 | * @return \Symfony\Component\Debug\Exception\FlattenException 70 | */ 71 | protected function getFlattenedException(Throwable $exception) 72 | { 73 | if (! $exception instanceof FlattenException) { 74 | $exception = FlattenException::createFromThrowable($exception); 75 | } 76 | 77 | return $exception; 78 | } 79 | 80 | /** 81 | * Get the html response content. 82 | * 83 | * @param string $content 84 | * @param string $css 85 | * @param Exception|Throwable $exception 86 | * 87 | * @return string 88 | */ 89 | protected function decorate($content, $css, $exception) 90 | { 91 | return $this->view 92 | ->make('notifex::body', compact('content', 'css', 'exception')) 93 | ->render(); 94 | } 95 | 96 | protected function environment(): string 97 | { 98 | return App::environment(); 99 | } 100 | 101 | protected function host(): string 102 | { 103 | return Http::host(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Services/NotifyException.php: -------------------------------------------------------------------------------- 1 | queue = Config::get('notifex.queue', 'default'); 29 | 30 | $this->handler = $handler; 31 | } 32 | 33 | /** 34 | * @param Throwable $exception 35 | */ 36 | public function send(Throwable $exception) 37 | { 38 | try { 39 | if ($this->isIgnoreBots() || ! $this->isEnabled()) { 40 | return; 41 | } 42 | 43 | $this->exception = $exception; 44 | 45 | $this->sendEmail(); 46 | $this->sendJobs(); 47 | } 48 | catch (Throwable $exception) { 49 | $this->log($exception, __FUNCTION__); 50 | } 51 | } 52 | 53 | protected function sendEmail() 54 | { 55 | try { 56 | if (Config::get('notifex.email.enabled', true)) { 57 | new Email($this->handler, $this->exception); 58 | } 59 | } 60 | catch (Throwable $exception) { 61 | $this->log($exception, __FUNCTION__); 62 | } 63 | } 64 | 65 | protected function sendJobs() 66 | { 67 | try { 68 | $jobs = (array) Config::get('notifex.jobs', []); 69 | 70 | if (! count($jobs)) { 71 | return; 72 | } 73 | 74 | $classname = (string) get_class($this->exception); 75 | $message = (string) $this->exception->getMessage(); 76 | $file = (string) $this->exception->getFile(); 77 | $line = (int) $this->exception->getLine(); 78 | $trace_as_string = (string) $this->exception->getTraceAsString(); 79 | 80 | foreach ($jobs as $job => $params) { 81 | try { 82 | if ($params['enabled'] ?? true) { 83 | $job = is_numeric($job) ? $params : $job; 84 | 85 | dispatch(new $job($classname, $message, $file, $line, $trace_as_string)) 86 | ->onQueue($this->queue); 87 | } 88 | } 89 | catch (Throwable $exception) { 90 | $this->log($exception, __FUNCTION__); 91 | } 92 | } 93 | } 94 | catch (Throwable $exception) { 95 | $this->log($exception, __FUNCTION__); 96 | } 97 | } 98 | 99 | protected function isIgnoreBots(): bool 100 | { 101 | $ignore_bots = Config::get('notifex.ignore_bots', true); 102 | 103 | if (! $ignore_bots) { 104 | return false; 105 | } 106 | 107 | $crawler = new CrawlerDetect(); 108 | 109 | return $crawler->isCrawler($this->userAgent()); 110 | } 111 | 112 | protected function isEnabled() 113 | { 114 | $enabled = Config::get('notifex.enabled', true); 115 | $email = Config::get('notifex.email.enabled', true); 116 | 117 | $jobs = array_filter(Config::get('notifex.jobs', []), function ($item) { 118 | return $item['enabled'] ?? false; 119 | }); 120 | 121 | return $enabled && ($email || count($jobs) > 0); 122 | } 123 | 124 | protected function userAgent(): ?string 125 | { 126 | return Http::userAgent(); 127 | } 128 | 129 | protected function log(Throwable $exception, string $function_name) 130 | { 131 | Log::error(sprintf( 132 | 'Exception thrown in %s::%s when capturing an exception', 133 | get_class(), 134 | $function_name 135 | )); 136 | 137 | Log::error($exception); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/Support/App.php: -------------------------------------------------------------------------------- 1 | url(), PHP_URL_HOST); 12 | } 13 | 14 | public function url(): string 15 | { 16 | return app('request')->url() ?? Config::get('app.url') ?: 'http://localhost'; 17 | } 18 | 19 | public function userAgent(): ?string 20 | { 21 | return app('request')->userAgent() ?? null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Traits/JobsConfiguration.php: -------------------------------------------------------------------------------- 1 |