Compare commits
5 Commits
mrb
...
538b1f817e
| Author | SHA1 | Date | |
|---|---|---|---|
| 538b1f817e | |||
| 89790f4fc1 | |||
| 9b7e3ef897 | |||
| ba8d92ea01 | |||
| 603052d7e5 |
229
.editorconfig
229
.editorconfig
@ -1,229 +0,0 @@
|
|||||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
|
||||||
root = true
|
|
||||||
|
|
||||||
# C# files
|
|
||||||
[*.cs]
|
|
||||||
|
|
||||||
#### Core EditorConfig Options ####
|
|
||||||
|
|
||||||
# Indentation and spacing
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
||||||
tab_width = 4
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
end_of_line = crlf
|
|
||||||
insert_final_newline = false
|
|
||||||
|
|
||||||
#### .NET Coding Conventions ####
|
|
||||||
|
|
||||||
# Organize usings
|
|
||||||
dotnet_separate_import_directive_groups = true
|
|
||||||
dotnet_sort_system_directives_first = true
|
|
||||||
file_header_template = unset
|
|
||||||
|
|
||||||
# this. and Me. preferences
|
|
||||||
dotnet_style_qualification_for_event = true
|
|
||||||
dotnet_style_qualification_for_field = true
|
|
||||||
dotnet_style_qualification_for_method = true
|
|
||||||
dotnet_style_qualification_for_property = true
|
|
||||||
|
|
||||||
# Language keywords vs BCL types preferences
|
|
||||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
|
||||||
dotnet_style_predefined_type_for_member_access = true
|
|
||||||
|
|
||||||
# Parentheses preferences
|
|
||||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:error
|
|
||||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:error
|
|
||||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
|
||||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:error
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
dotnet_style_coalesce_expression = false
|
|
||||||
dotnet_style_collection_initializer = true
|
|
||||||
dotnet_style_explicit_tuple_names = true:error
|
|
||||||
dotnet_style_namespace_match_folder = true
|
|
||||||
dotnet_style_null_propagation = true
|
|
||||||
dotnet_style_object_initializer = true
|
|
||||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
|
||||||
dotnet_style_prefer_auto_properties = true
|
|
||||||
dotnet_style_prefer_compound_assignment = true
|
|
||||||
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
|
|
||||||
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
|
|
||||||
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
|
||||||
dotnet_style_prefer_inferred_anonymous_type_member_names = false
|
|
||||||
dotnet_style_prefer_inferred_tuple_names = false
|
|
||||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
|
||||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
|
||||||
dotnet_style_prefer_simplified_interpolation = true
|
|
||||||
|
|
||||||
# Field preferences
|
|
||||||
dotnet_style_readonly_field = true:warning
|
|
||||||
|
|
||||||
# Parameter preferences
|
|
||||||
dotnet_code_quality_unused_parameters = all:error
|
|
||||||
|
|
||||||
# Suppression preferences
|
|
||||||
dotnet_remove_unnecessary_suppression_exclusions = none
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
dotnet_style_allow_multiple_blank_lines_experimental = false:error
|
|
||||||
dotnet_style_allow_statement_immediately_after_block_experimental = false:warning
|
|
||||||
|
|
||||||
#### C# Coding Conventions ####
|
|
||||||
|
|
||||||
# var preferences
|
|
||||||
csharp_style_var_elsewhere = false:error
|
|
||||||
csharp_style_var_for_built_in_types = false:error
|
|
||||||
csharp_style_var_when_type_is_apparent = false:error
|
|
||||||
|
|
||||||
# Expression-bodied members
|
|
||||||
csharp_style_expression_bodied_accessors = false
|
|
||||||
csharp_style_expression_bodied_constructors = false
|
|
||||||
csharp_style_expression_bodied_indexers = false
|
|
||||||
csharp_style_expression_bodied_lambdas = true
|
|
||||||
csharp_style_expression_bodied_local_functions = false
|
|
||||||
csharp_style_expression_bodied_methods = when_on_single_line:suggestion
|
|
||||||
csharp_style_expression_bodied_operators = false
|
|
||||||
csharp_style_expression_bodied_properties = false
|
|
||||||
|
|
||||||
# Pattern matching preferences
|
|
||||||
csharp_style_pattern_matching_over_as_with_null_check = false
|
|
||||||
csharp_style_pattern_matching_over_is_with_cast_check = false
|
|
||||||
csharp_style_prefer_extended_property_pattern = true
|
|
||||||
csharp_style_prefer_not_pattern = true
|
|
||||||
csharp_style_prefer_pattern_matching = true
|
|
||||||
csharp_style_prefer_switch_expression = false
|
|
||||||
|
|
||||||
# Null-checking preferences
|
|
||||||
csharp_style_conditional_delegate_call = false
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
csharp_prefer_static_local_function = false
|
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
|
|
||||||
csharp_style_prefer_readonly_struct = true:warning
|
|
||||||
csharp_style_prefer_readonly_struct_member = true
|
|
||||||
|
|
||||||
# Code-block preferences
|
|
||||||
csharp_prefer_braces = when_multiline:error
|
|
||||||
csharp_prefer_simple_using_statement = false
|
|
||||||
csharp_style_namespace_declarations = file_scoped:error
|
|
||||||
csharp_style_prefer_method_group_conversion = true:suggestion
|
|
||||||
csharp_style_prefer_top_level_statements = true:error
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
csharp_prefer_simple_default_expression = true
|
|
||||||
csharp_style_deconstructed_variable_declaration = false
|
|
||||||
csharp_style_implicit_object_creation_when_type_is_apparent = false
|
|
||||||
csharp_style_inlined_variable_declaration = true
|
|
||||||
csharp_style_prefer_index_operator = false:error
|
|
||||||
csharp_style_prefer_local_over_anonymous_function = true:error
|
|
||||||
csharp_style_prefer_null_check_over_type_check = true
|
|
||||||
csharp_style_prefer_range_operator = false:error
|
|
||||||
csharp_style_prefer_tuple_swap = true
|
|
||||||
csharp_style_prefer_utf8_string_literals = true
|
|
||||||
csharp_style_throw_expression = false
|
|
||||||
csharp_style_unused_value_assignment_preference = unused_local_variable
|
|
||||||
csharp_style_unused_value_expression_statement_preference = unused_local_variable
|
|
||||||
|
|
||||||
# 'using' directive preferences
|
|
||||||
csharp_using_directive_placement = outside_namespace:error
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
|
||||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
|
|
||||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
|
|
||||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:error
|
|
||||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
|
||||||
|
|
||||||
#### C# Formatting Rules ####
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
csharp_new_line_before_catch = false
|
|
||||||
csharp_new_line_before_else = false
|
|
||||||
csharp_new_line_before_finally = false
|
|
||||||
csharp_new_line_before_members_in_anonymous_types = true
|
|
||||||
csharp_new_line_before_members_in_object_initializers = true
|
|
||||||
csharp_new_line_before_open_brace = none
|
|
||||||
csharp_new_line_between_query_expression_clauses = true
|
|
||||||
|
|
||||||
# Indentation preferences
|
|
||||||
csharp_indent_block_contents = true
|
|
||||||
csharp_indent_braces = false
|
|
||||||
csharp_indent_case_contents = true
|
|
||||||
csharp_indent_case_contents_when_block = true
|
|
||||||
csharp_indent_labels = one_less_than_current
|
|
||||||
csharp_indent_switch_labels = true
|
|
||||||
|
|
||||||
# Space preferences
|
|
||||||
csharp_space_after_cast = false
|
|
||||||
csharp_space_after_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_after_comma = true
|
|
||||||
csharp_space_after_dot = false
|
|
||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
|
||||||
csharp_space_after_semicolon_in_for_statement = true
|
|
||||||
csharp_space_around_binary_operators = before_and_after
|
|
||||||
csharp_space_around_declaration_statements = false
|
|
||||||
csharp_space_before_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_before_comma = false
|
|
||||||
csharp_space_before_dot = false
|
|
||||||
csharp_space_before_open_square_brackets = false
|
|
||||||
csharp_space_before_semicolon_in_for_statement = false
|
|
||||||
csharp_space_between_empty_square_brackets = false
|
|
||||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
|
||||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
|
||||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_parentheses = false
|
|
||||||
csharp_space_between_square_brackets = false
|
|
||||||
|
|
||||||
# Wrapping preferences
|
|
||||||
csharp_preserve_single_line_blocks = true
|
|
||||||
csharp_preserve_single_line_statements = true
|
|
||||||
|
|
||||||
#### Naming styles ####
|
|
||||||
|
|
||||||
# Naming rules
|
|
||||||
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
|
||||||
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
# Symbol specifications
|
|
||||||
|
|
||||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
|
||||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.interface.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
|
||||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.types.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
|
||||||
|
|
||||||
# Naming styles
|
|
||||||
|
|
||||||
dotnet_naming_style.pascal_case.required_prefix =
|
|
||||||
dotnet_naming_style.pascal_case.required_suffix =
|
|
||||||
dotnet_naming_style.pascal_case.word_separator =
|
|
||||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
|
||||||
dotnet_naming_style.begins_with_i.required_suffix =
|
|
||||||
dotnet_naming_style.begins_with_i.word_separator =
|
|
||||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
|
||||||
|
|||||||
19
.gitignore
vendored
19
.gitignore
vendored
@ -337,6 +337,23 @@ ASALocalRun/
|
|||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
.vscode
|
|
||||||
|
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
/Fab2ApprovalMKLink/App_Start
|
||||||
|
/Fab2ApprovalMKLink/Controllers
|
||||||
|
/Fab2ApprovalMKLink/DMO
|
||||||
|
/Fab2ApprovalMKLink/Jobs
|
||||||
|
/Fab2ApprovalMKLink/JobSchedules
|
||||||
|
/Fab2ApprovalMKLink/Misc
|
||||||
|
/Fab2ApprovalMKLink/Models
|
||||||
|
/Fab2ApprovalMKLink/PdfGenerator
|
||||||
|
/Fab2ApprovalMKLink/Utilities
|
||||||
|
/Fab2ApprovalMKLink/ViewModels
|
||||||
|
|
||||||
|
/Fab2ApprovalMKLink/.vscode/.UserSecrets
|
||||||
|
/Fab2ApprovalSystem/.vscode/.UserSecrets
|
||||||
|
/Fab2ApprovalTests/.vscode/.UserSecrets
|
||||||
|
/MesaFabApproval.API/.vscode/.UserSecrets
|
||||||
|
/MesaFabApproval.Client/.vscode/.UserSecrets
|
||||||
|
/MesaFabApproval.Shared/.vscode/.UserSecrets
|
||||||
41
.vscode/launch.json
vendored
Normal file
41
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (console) - Fab2ApprovalSystem",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "Fab2ApprovalSystem-build",
|
||||||
|
"program": "${workspaceFolder}/Fab2ApprovalSystem/bin/Debug/net8.0/win-x64/Fab2ApprovalSystem.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (console) - MesaFabApproval.API",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "MesaFabApproval.API-build",
|
||||||
|
"program": "${workspaceFolder}/MesaFabApproval.API/bin/Debug/net8.0/MesaFabApproval.API.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "node Launch Current Opened File",
|
||||||
|
"program": "${file}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
424
.vscode/settings.json
vendored
Normal file
424
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
{
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.wordWrap": "off"
|
||||||
|
},
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": false,
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"cSpell.words": [
|
||||||
|
"abutton",
|
||||||
|
"accessibilities",
|
||||||
|
"accodingly",
|
||||||
|
"acknowledgmentby",
|
||||||
|
"Acks",
|
||||||
|
"actionsheet",
|
||||||
|
"Additonal",
|
||||||
|
"Addtional",
|
||||||
|
"againm",
|
||||||
|
"agendaview",
|
||||||
|
"Antlr",
|
||||||
|
"Appover",
|
||||||
|
"Appprrovers",
|
||||||
|
"Approvalog",
|
||||||
|
"Aprovers",
|
||||||
|
"Aproverslist",
|
||||||
|
"asax",
|
||||||
|
"aspnetmvc",
|
||||||
|
"Assignedto",
|
||||||
|
"Atachments",
|
||||||
|
"Attachemnt",
|
||||||
|
"Attachemnts",
|
||||||
|
"Attchment",
|
||||||
|
"auditee",
|
||||||
|
"Auditee",
|
||||||
|
"Auditees",
|
||||||
|
"automaically",
|
||||||
|
"Autthorized",
|
||||||
|
"beacuase",
|
||||||
|
"beforeunload",
|
||||||
|
"Belguim",
|
||||||
|
"bfound",
|
||||||
|
"bgcolor",
|
||||||
|
"Bies",
|
||||||
|
"binded",
|
||||||
|
"blackbackground",
|
||||||
|
"blackhover",
|
||||||
|
"blackpressed",
|
||||||
|
"blueenergy",
|
||||||
|
"blueopal",
|
||||||
|
"buttongroup",
|
||||||
|
"BYMRB",
|
||||||
|
"bytesgot",
|
||||||
|
"CAID",
|
||||||
|
"casection",
|
||||||
|
"CAXXXX",
|
||||||
|
"CCPCR",
|
||||||
|
"CCPCRB",
|
||||||
|
"cellspacing",
|
||||||
|
"Cheeso's",
|
||||||
|
"chkbx",
|
||||||
|
"Clib",
|
||||||
|
"colorpicker",
|
||||||
|
"columnmenu",
|
||||||
|
"columnsreorder",
|
||||||
|
"columnsresize",
|
||||||
|
"comming",
|
||||||
|
"Containmen",
|
||||||
|
"Copmments",
|
||||||
|
"correctiv",
|
||||||
|
"Correctivet",
|
||||||
|
"Creat",
|
||||||
|
"currentd",
|
||||||
|
"Cyle",
|
||||||
|
"dadada",
|
||||||
|
"darkbluehover",
|
||||||
|
"darkbluepressed",
|
||||||
|
"darkred",
|
||||||
|
"datafields",
|
||||||
|
"datasource",
|
||||||
|
"dataviz",
|
||||||
|
"datepicker",
|
||||||
|
"datetimepicker",
|
||||||
|
"dayview",
|
||||||
|
"Deletet",
|
||||||
|
"Delgation",
|
||||||
|
"DENITED",
|
||||||
|
"Deparmtent",
|
||||||
|
"departmentids",
|
||||||
|
"Descirption",
|
||||||
|
"devprog",
|
||||||
|
"dfeffc",
|
||||||
|
"Disp",
|
||||||
|
"Dispo",
|
||||||
|
"Dispoitio",
|
||||||
|
"Dispos",
|
||||||
|
"Dispositon",
|
||||||
|
"Dispostion",
|
||||||
|
"Dispostions",
|
||||||
|
"dispotypevalidation",
|
||||||
|
"Docbase",
|
||||||
|
"Documentum",
|
||||||
|
"Documetum",
|
||||||
|
"dont",
|
||||||
|
"downlaoded",
|
||||||
|
"draganddrop",
|
||||||
|
"dragcancel",
|
||||||
|
"dropdownlist",
|
||||||
|
"Eamils",
|
||||||
|
"ECNPCRB",
|
||||||
|
"Ecns",
|
||||||
|
"edmx",
|
||||||
|
"EECN",
|
||||||
|
"emai",
|
||||||
|
"emailparams",
|
||||||
|
"Emergrncy",
|
||||||
|
"energyblue",
|
||||||
|
"Eran",
|
||||||
|
"Esql",
|
||||||
|
"ETECN",
|
||||||
|
"EXCELOPENXML",
|
||||||
|
"existinglocation",
|
||||||
|
"Expando",
|
||||||
|
"extrafield",
|
||||||
|
"fadc",
|
||||||
|
"fbec",
|
||||||
|
"fcfdfd",
|
||||||
|
"fdff",
|
||||||
|
"fece",
|
||||||
|
"feeebd",
|
||||||
|
"ffdc",
|
||||||
|
"ffdd",
|
||||||
|
"fieldset",
|
||||||
|
"FILIPE",
|
||||||
|
"filtermenu",
|
||||||
|
"Fldr",
|
||||||
|
"flintstone",
|
||||||
|
"FLOWLOCS",
|
||||||
|
"FMEA",
|
||||||
|
"ftplib",
|
||||||
|
"FTPSPN",
|
||||||
|
"GETDATE",
|
||||||
|
"gitea",
|
||||||
|
"globaldocudms",
|
||||||
|
"glyphicons",
|
||||||
|
"groupable",
|
||||||
|
"Guids",
|
||||||
|
"halflings",
|
||||||
|
"Hexsize",
|
||||||
|
"highcontrast",
|
||||||
|
"Hmac",
|
||||||
|
"holdsteps",
|
||||||
|
"hostspecific",
|
||||||
|
"icenium",
|
||||||
|
"IECN",
|
||||||
|
"imagebrowser",
|
||||||
|
"IMRB",
|
||||||
|
"Infineon",
|
||||||
|
"Insertd",
|
||||||
|
"inverseicons",
|
||||||
|
"IPCRB",
|
||||||
|
"ISADMIN",
|
||||||
|
"islast",
|
||||||
|
"ISNULL",
|
||||||
|
"ITAR",
|
||||||
|
"jquery",
|
||||||
|
"jqueryval",
|
||||||
|
"jqwidgets",
|
||||||
|
"jqxbuttongroup",
|
||||||
|
"jqxbuttons",
|
||||||
|
"jqxcalendar",
|
||||||
|
"jqxchart",
|
||||||
|
"jqxcheckbox",
|
||||||
|
"jqxcolorpicker",
|
||||||
|
"jqxcombobox",
|
||||||
|
"jqxcore",
|
||||||
|
"jqxdata",
|
||||||
|
"jqxdatatable",
|
||||||
|
"jqxdatetimeinput",
|
||||||
|
"jqxdocking",
|
||||||
|
"jqxdockpanel",
|
||||||
|
"jqxdragdrop",
|
||||||
|
"jqxdropdownbutton",
|
||||||
|
"jqxdropdownlist",
|
||||||
|
"jqxexpander",
|
||||||
|
"jqxgauge",
|
||||||
|
"jqxgrid",
|
||||||
|
"jqxinput",
|
||||||
|
"jqxknockout",
|
||||||
|
"jqxlistbox",
|
||||||
|
"jqxlistmenu",
|
||||||
|
"jqxmaskedinput",
|
||||||
|
"jqxmenu",
|
||||||
|
"jqxnavigationbar",
|
||||||
|
"jqxnumberinput",
|
||||||
|
"jqxpanel",
|
||||||
|
"jqxpasswordinput",
|
||||||
|
"jqxprogressbar",
|
||||||
|
"jqxradiobutton",
|
||||||
|
"jqxrangeselector",
|
||||||
|
"jqxrating",
|
||||||
|
"jqxresponse",
|
||||||
|
"jqxscrollbar",
|
||||||
|
"jqxscrollview",
|
||||||
|
"jqxslider",
|
||||||
|
"jqxsplitter",
|
||||||
|
"jqxswitchbutton",
|
||||||
|
"jqxtabs",
|
||||||
|
"jqxtooltip",
|
||||||
|
"jqxtouch",
|
||||||
|
"jqxtree",
|
||||||
|
"jqxtreegrid",
|
||||||
|
"jqxtreemap",
|
||||||
|
"jqxvalidator",
|
||||||
|
"jqxwindow",
|
||||||
|
"kendogridcustom",
|
||||||
|
"kendoui",
|
||||||
|
"labelelement",
|
||||||
|
"labelledby",
|
||||||
|
"Leanred",
|
||||||
|
"lightgray",
|
||||||
|
"linkbutton",
|
||||||
|
"Linq",
|
||||||
|
"Listdiv",
|
||||||
|
"listview",
|
||||||
|
"Lnks",
|
||||||
|
"localfilename",
|
||||||
|
"loclist",
|
||||||
|
"logis",
|
||||||
|
"logtext",
|
||||||
|
"loopmis",
|
||||||
|
"lotdispo",
|
||||||
|
"LOTDISPSITION",
|
||||||
|
"Lotfile",
|
||||||
|
"lotlist",
|
||||||
|
"lotstatusoption",
|
||||||
|
"LTRIM",
|
||||||
|
"MADUREIRA",
|
||||||
|
"mailrelay",
|
||||||
|
"MDTM",
|
||||||
|
"meego",
|
||||||
|
"meetingid",
|
||||||
|
"menubutton",
|
||||||
|
"mesafi",
|
||||||
|
"metroblack",
|
||||||
|
"metrodark",
|
||||||
|
"miliseconds",
|
||||||
|
"modalview",
|
||||||
|
"modernizr",
|
||||||
|
"Modernizr",
|
||||||
|
"monthview",
|
||||||
|
"MRBIs",
|
||||||
|
"Mrbs",
|
||||||
|
"msecs",
|
||||||
|
"multipleextended",
|
||||||
|
"Navigatable",
|
||||||
|
"nbsp",
|
||||||
|
"newbase",
|
||||||
|
"newchange",
|
||||||
|
"newdi",
|
||||||
|
"newfilename",
|
||||||
|
"newsource",
|
||||||
|
"Newtonsoft",
|
||||||
|
"notications",
|
||||||
|
"Notifcation",
|
||||||
|
"Notifyf",
|
||||||
|
"NTLM",
|
||||||
|
"Nullcc",
|
||||||
|
"numerictextbox",
|
||||||
|
"objdata",
|
||||||
|
"OCAP",
|
||||||
|
"occured",
|
||||||
|
"odata",
|
||||||
|
"oldfilename",
|
||||||
|
"OLHOLD",
|
||||||
|
"onclick",
|
||||||
|
"onmousemove",
|
||||||
|
"OPDESC",
|
||||||
|
"OPENQUERY",
|
||||||
|
"Oper",
|
||||||
|
"operationslist",
|
||||||
|
"Orginator",
|
||||||
|
"Originatorname",
|
||||||
|
"Ouellette",
|
||||||
|
"Owin",
|
||||||
|
"pageable",
|
||||||
|
"Pageable",
|
||||||
|
"panelbar",
|
||||||
|
"parentid",
|
||||||
|
"parminput",
|
||||||
|
"parms",
|
||||||
|
"Parms",
|
||||||
|
"particula",
|
||||||
|
"pasv",
|
||||||
|
"PASV",
|
||||||
|
"PATINDEX",
|
||||||
|
"PCRB",
|
||||||
|
"PCRBID",
|
||||||
|
"pcrvalues",
|
||||||
|
"pdbonly",
|
||||||
|
"Preventitive",
|
||||||
|
"preventivet",
|
||||||
|
"Prevetative",
|
||||||
|
"proces",
|
||||||
|
"Processedl",
|
||||||
|
"procs",
|
||||||
|
"productfamilies",
|
||||||
|
"progess",
|
||||||
|
"progressbar",
|
||||||
|
"qrcode",
|
||||||
|
"Quanityt",
|
||||||
|
"rangebar",
|
||||||
|
"Recep",
|
||||||
|
"Recepient",
|
||||||
|
"recieved",
|
||||||
|
"recordlock",
|
||||||
|
"remotefilename",
|
||||||
|
"reorderable",
|
||||||
|
"reportform",
|
||||||
|
"reportslist",
|
||||||
|
"reportslistdiv",
|
||||||
|
"Reqquired",
|
||||||
|
"Reqs",
|
||||||
|
"Requiest",
|
||||||
|
"Responsibles",
|
||||||
|
"RETR",
|
||||||
|
"Revisioing",
|
||||||
|
"Revisioned",
|
||||||
|
"Revison",
|
||||||
|
"rgba",
|
||||||
|
"rkotian",
|
||||||
|
"RNFR",
|
||||||
|
"RNTO",
|
||||||
|
"Roless",
|
||||||
|
"roundbg",
|
||||||
|
"RTRIM",
|
||||||
|
"SAMDB",
|
||||||
|
"scroller",
|
||||||
|
"scrollview",
|
||||||
|
"seleced",
|
||||||
|
"selectionlog",
|
||||||
|
"Selectpart",
|
||||||
|
"sess",
|
||||||
|
"Sfisharepoint",
|
||||||
|
"shinyblack",
|
||||||
|
"showpassword",
|
||||||
|
"SIGNON",
|
||||||
|
"simpleparser",
|
||||||
|
"slddrw",
|
||||||
|
"sldprt",
|
||||||
|
"sortasc",
|
||||||
|
"sortascbutton",
|
||||||
|
"sortdesc",
|
||||||
|
"sortdescbutton",
|
||||||
|
"sortremove",
|
||||||
|
"sparkline",
|
||||||
|
"splitview",
|
||||||
|
"SPNMRB",
|
||||||
|
"SPNPDB",
|
||||||
|
"SSRS",
|
||||||
|
"Sssign",
|
||||||
|
"Staus",
|
||||||
|
"stylesheet",
|
||||||
|
"Submited",
|
||||||
|
"subrole",
|
||||||
|
"subroles",
|
||||||
|
"Succefully",
|
||||||
|
"Succesfully",
|
||||||
|
"sucessfully",
|
||||||
|
"SURP",
|
||||||
|
"Swashbuckle",
|
||||||
|
"SWRN",
|
||||||
|
"tabindex",
|
||||||
|
"tabstrip",
|
||||||
|
"Tahoma",
|
||||||
|
"taskcompleted",
|
||||||
|
"Tasklist",
|
||||||
|
"Taveler",
|
||||||
|
"TECN",
|
||||||
|
"TECNs",
|
||||||
|
"TEMIRWAP",
|
||||||
|
"tempecd",
|
||||||
|
"tempimplement",
|
||||||
|
"templabel",
|
||||||
|
"tempvalue",
|
||||||
|
"TEMSA",
|
||||||
|
"timepicker",
|
||||||
|
"Tobe",
|
||||||
|
"Toplevel",
|
||||||
|
"Totrav",
|
||||||
|
"trainingby",
|
||||||
|
"Traininglist",
|
||||||
|
"traininglistdiv",
|
||||||
|
"transanction",
|
||||||
|
"Trav",
|
||||||
|
"Traveller",
|
||||||
|
"Traverler",
|
||||||
|
"TRAVLELER",
|
||||||
|
"Travler",
|
||||||
|
"TREEVIEW",
|
||||||
|
"trigerred",
|
||||||
|
"ttinclude",
|
||||||
|
"Uhandled",
|
||||||
|
"Updat",
|
||||||
|
"Uplaod",
|
||||||
|
"Upto",
|
||||||
|
"userevents",
|
||||||
|
"userids",
|
||||||
|
"userlist",
|
||||||
|
"Validatable",
|
||||||
|
"valueelement",
|
||||||
|
"Variabls",
|
||||||
|
"Verdana",
|
||||||
|
"vgrid",
|
||||||
|
"viewmodel",
|
||||||
|
"vsdoc",
|
||||||
|
"whethere",
|
||||||
|
"windowsphone",
|
||||||
|
"Winsock",
|
||||||
|
"worlflow"
|
||||||
|
]
|
||||||
|
}
|
||||||
500
.vscode/tasks.json
vendored
Normal file
500
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "MSBuild",
|
||||||
|
"command": "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/MSBuild/Current/Bin/MSBuild.exe",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"/target:Build",
|
||||||
|
"/restore:True",
|
||||||
|
"/p:RestoreSources=https://artifactory.intra.infineon.com/artifactory/api/nuget/ngt-fi-package-main-vir/%3Bhttps://packagemanagement.eu.infineon.com:4430/api/v2/%3Bhttps://api.nuget.org/v3/index.json",
|
||||||
|
"/detailedsummary",
|
||||||
|
"/consoleloggerparameters:PerformanceSummary;ErrorsOnly;",
|
||||||
|
"/property:Configuration=Debug;TargetFrameworkVersion=v4.8",
|
||||||
|
"Fab2ApprovalSystem/Fab2ApprovalSystem.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-User Secrets Init",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-User Secrets Set",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj",
|
||||||
|
"set",
|
||||||
|
"_UserSecretsId",
|
||||||
|
"f2da5035-aba9-4676-9f8d-d6689f84663d"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalMKLink-Publish AOT",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"-r",
|
||||||
|
"win-x64",
|
||||||
|
"-c",
|
||||||
|
"Release",
|
||||||
|
"-p:PublishAot=true",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-User Secrets Init",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-User Secrets Set",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj",
|
||||||
|
"set",
|
||||||
|
"_UserSecretsId",
|
||||||
|
"3942d1fb-d585-40ae-8985-d276d1b94b77"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-testDebug",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-testRelease",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary",
|
||||||
|
"-c",
|
||||||
|
"Release"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Fab2ApprovalTests-Publish AOT",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"-r",
|
||||||
|
"win-x64",
|
||||||
|
"-c",
|
||||||
|
"Release",
|
||||||
|
"-p:PublishAot=true",
|
||||||
|
"${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-User Secrets Init",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-User Secrets Set",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj",
|
||||||
|
"set",
|
||||||
|
"_UserSecretsId",
|
||||||
|
"0b98e1f2-95ed-4edd-8149-58cce51ca059"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-testDebug",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-testRelease",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary",
|
||||||
|
"-c",
|
||||||
|
"Release"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.API-Publish AOT",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"-r",
|
||||||
|
"win-x64",
|
||||||
|
"-c",
|
||||||
|
"Release",
|
||||||
|
"-p:PublishAot=true",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-User Secrets Init",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-testDebug",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-testRelease",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary",
|
||||||
|
"-c",
|
||||||
|
"Release"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "MesaFabApproval.Client-Publish AOT",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"-r",
|
||||||
|
"win-x64",
|
||||||
|
"-c",
|
||||||
|
"Release",
|
||||||
|
"-p:PublishAot=true",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System.Web.Http;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web.Http;
|
|
||||||
|
|
||||||
namespace Fab2ApprovalSystem
|
namespace Fab2ApprovalSystem {
|
||||||
{
|
|
||||||
public static class WebApiConfig
|
public static class WebApiConfig
|
||||||
{
|
{
|
||||||
public static void Register(HttpConfiguration config)
|
public static void Register(HttpConfiguration config)
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
@ -15,8 +14,8 @@ using Fab2ApprovalSystem.DMO;
|
|||||||
using Microsoft.AspNet.Identity.Owin;
|
using Microsoft.AspNet.Identity.Owin;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace Fab2ApprovalSystem.Controllers {
|
namespace Fab2ApprovalSystem.Controllers {
|
||||||
[Authorize]
|
[Authorize]
|
||||||
@ -129,6 +128,86 @@ namespace Fab2ApprovalSystem.Controllers {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<HttpResponseMessage> ExternalAuthSetup(AuthAttempt authAttempt) {
|
||||||
|
try {
|
||||||
|
bool isLoginValid;
|
||||||
|
|
||||||
|
HttpClient httpClient = HttpClientFactory.Create();
|
||||||
|
httpClient.BaseAddress = new Uri(_apiBaseUrl);
|
||||||
|
|
||||||
|
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/refresh");
|
||||||
|
|
||||||
|
request.Content = new StringContent(JsonConvert.SerializeObject(authAttempt),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request);
|
||||||
|
|
||||||
|
if (!httpResponseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception($"The authentication API failed, because {httpResponseMessage.ReasonPhrase}");
|
||||||
|
|
||||||
|
string responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
LoginResult loginResult = JsonConvert.DeserializeObject<LoginResult>(responseContent);
|
||||||
|
|
||||||
|
#if(DEBUG)
|
||||||
|
isLoginValid = true;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#if (!DEBUG)
|
||||||
|
|
||||||
|
bool isIFX = false;
|
||||||
|
//domainProvider = Membership.Providers["NA_ADMembershipProvider"];
|
||||||
|
//isLoginValid = domainProvider.ValidateUser(model.LoginID, model.Password);
|
||||||
|
|
||||||
|
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||||
|
isLoginValid = true;
|
||||||
|
} else {
|
||||||
|
isLoginValid = loginResult.IsAuthenticated;
|
||||||
|
if (isLoginValid) isIFX = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (isLoginValid) {
|
||||||
|
UserAccountDMO userDMO = new UserAccountDMO();
|
||||||
|
LoginModel user = userDMO.GetUser(authAttempt.LoginID);
|
||||||
|
if (user != null) {
|
||||||
|
Session["JWT"] = loginResult.AuthTokens.JwtToken;
|
||||||
|
Session["RefreshToken"] = loginResult.AuthTokens.RefreshToken;
|
||||||
|
|
||||||
|
Session[GlobalVars.SESSION_USERID] = user.UserID;
|
||||||
|
Session[GlobalVars.SESSION_USERNAME] = user.FullName;
|
||||||
|
Session[GlobalVars.IS_ADMIN] = user.IsAdmin;
|
||||||
|
Session[GlobalVars.IS_MANAGER] = user.IsManager;
|
||||||
|
Session[GlobalVars.OOO] = user.OOO;
|
||||||
|
Session[GlobalVars.CAN_CREATE_PARTS_REQUEST] = user.IsAdmin || PartsRequestController.CanCreatePartsRequest(user.UserID);
|
||||||
|
|
||||||
|
FormsAuthentication.SetAuthCookie(user.LoginID, true);
|
||||||
|
|
||||||
|
return new HttpResponseMessage(HttpStatusCode.OK);
|
||||||
|
} else {
|
||||||
|
ModelState.AddModelError("", "The user name does not exist in the DB. Please contact the System Admin");
|
||||||
|
|
||||||
|
return new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ModelState.AddModelError("", "The user name or password provided is incorrect.");
|
||||||
|
|
||||||
|
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Functions.WriteEvent(@User.Identity.Name + " " + ex.InnerException, System.Diagnostics.EventLogEntryType.Error);
|
||||||
|
EventLogDMO.Add(new WinEventLog() { IssueID = 99999, UserID = @User.Identity.Name, DocumentType = "Login", OperationType = "Error", Comments = "Reject - " + ex.Message });
|
||||||
|
ModelState.AddModelError("", ex.Message);
|
||||||
|
|
||||||
|
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GET: /Account/Register
|
// GET: /Account/Register
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public ActionResult Register() {
|
public ActionResult Register() {
|
||||||
|
|||||||
@ -102,53 +102,15 @@ namespace Fab2ApprovalSystem.Controllers
|
|||||||
// GET: /MRB/Edit/5
|
// GET: /MRB/Edit/5
|
||||||
public ActionResult Edit(int issueID)
|
public ActionResult Edit(int issueID)
|
||||||
{
|
{
|
||||||
MRB mrb = new MRB();
|
string jwt = Session["JWT"].ToString();
|
||||||
int isITARCompliant = 1;
|
string encodedJwt = System.Net.WebUtility.UrlEncode(jwt);
|
||||||
ViewBag.Status = "Pending";
|
string refreshToken = Session["RefreshToken"].ToString();
|
||||||
ViewBag.IsApprover = "false";
|
string encodedRefreshToken = System.Net.WebUtility.UrlEncode(refreshToken);
|
||||||
ViewBag.IsCloser = "false";
|
string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ??
|
||||||
|
"https://localhost:7255";
|
||||||
|
string mrbUrl = $"{wasmClientUrl}/redirect?jwt={encodedJwt}&refreshToken={encodedRefreshToken}&redirectPath=/mrb/{issueID}";
|
||||||
|
|
||||||
//ViewBag.IsApproved = "false";
|
return Redirect(mrbUrl);
|
||||||
//ViewBag.IsClosed = "false";
|
|
||||||
PopulateCloseToQDB();
|
|
||||||
mrb = mrbDMO.GetMRBItem(issueID, out isITARCompliant, (int)Session[GlobalVars.SESSION_USERID]);
|
|
||||||
ViewBag.UserList = mrbDMO.GetUserList();
|
|
||||||
|
|
||||||
if (isITARCompliant == 0) // not ITAR Compliant
|
|
||||||
{
|
|
||||||
return View("UnAuthorizedAccess");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mrb.ApprovalStatus == (int)GlobalVars.ApprovalOption.Approved)
|
|
||||||
{
|
|
||||||
//ViewBag.IsApproved = "true";
|
|
||||||
ViewBag.Status = "Approved";
|
|
||||||
}
|
|
||||||
else if (mrb.ApprovalStatus == (int)GlobalVars.ApprovalOption.Closed)
|
|
||||||
{
|
|
||||||
ViewBag.Status = "Closed";
|
|
||||||
//ViewBag.IsClosed = "true";
|
|
||||||
}
|
|
||||||
List<ApproversListViewModel> userList = MiscDMO.GetApproversListByDocument(issueID, mrb.CurrentStep, (int)GlobalVars.DocumentType.MRB);
|
|
||||||
ApproversListViewModel appUser = userList.Find(delegate (ApproversListViewModel al) { return al.UserID == (int)Session[GlobalVars.SESSION_USERID]; });
|
|
||||||
if (appUser != null)
|
|
||||||
{
|
|
||||||
ViewBag.IsApprover = "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// can edit
|
|
||||||
ViewBag.Owners = MiscDMO.GetUserList();
|
|
||||||
ViewBag.Modules = mrbDMO.GetModules();
|
|
||||||
//ViewBag.Dispositions = mrbDMO.GetDispositions();
|
|
||||||
ViewBag.RiskAssessments = mrbDMO.GetRiskAssessments();
|
|
||||||
ViewBag.PartGroups = mrbDMO.GetPartGroups();
|
|
||||||
ViewBag.DispoTypes = mrbDMO.GetDispositions(issueID).Select(d => new { d.DispositionType });
|
|
||||||
|
|
||||||
return View(mrb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -178,39 +140,15 @@ namespace Fab2ApprovalSystem.Controllers
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ActionResult ReadOnly(int issueID)
|
public ActionResult ReadOnly(int issueID)
|
||||||
{
|
{
|
||||||
MRB mrb = new MRB();
|
string jwt = Session["JWT"].ToString();
|
||||||
int isITARCompliant = 1;
|
string encodedJwt = System.Net.WebUtility.UrlEncode(jwt);
|
||||||
|
string refreshToken = Session["RefreshToken"].ToString();
|
||||||
|
string encodedRefreshToken = System.Net.WebUtility.UrlEncode(refreshToken);
|
||||||
|
string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ??
|
||||||
|
"https://localhost:7255";
|
||||||
|
string mrbUrl = $"{wasmClientUrl}/redirect?jwt={encodedJwt}&refreshToken={encodedRefreshToken}&redirectPath=/mrb/{issueID}";
|
||||||
|
|
||||||
|
return Redirect(mrbUrl);
|
||||||
try
|
|
||||||
{
|
|
||||||
if (isITARCompliant == 0) // not ITAR Compliant
|
|
||||||
{
|
|
||||||
return View("UnAuthorizedAccess");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mrb = mrbDMO.GetMRBItem(issueID, out isITARCompliant, (int)Session[GlobalVars.SESSION_USERID]);
|
|
||||||
|
|
||||||
ViewBag.Owners = MiscDMO.GetUserList();
|
|
||||||
ViewBag.Modules = mrbDMO.GetModules();
|
|
||||||
//ViewBag.Dispositions = mrbDMO.GetDispositions();
|
|
||||||
ViewBag.RiskAssessments = mrbDMO.GetRiskAssessments();
|
|
||||||
ViewBag.PartGroups = mrbDMO.GetPartGroups();
|
|
||||||
ViewBag.DispoTypes = mrbDMO.GetDispositions(issueID).Select(d => new { d.DispositionType });
|
|
||||||
}
|
|
||||||
|
|
||||||
return View(mrb);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
string exceptionString = e.Message.ToString().Trim().Length > 500 ? "IssueID=" + issueID.ToString() + " " + e.Message.ToString().Substring(0, 250) : e.Message.ToString();
|
|
||||||
Functions.WriteEvent(@User.Identity.Name + "\r\n ReadOnly Disposition\r\n" + e.Message.ToString(), System.Diagnostics.EventLogEntryType.Error);
|
|
||||||
EventLogDMO.Add(new WinEventLog() { IssueID = issueID, UserID = @User.Identity.Name, DocumentType = "Lot Disposition", OperationType = "Error", Comments = exceptionString });
|
|
||||||
throw new Exception(e.Message);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@ -154,6 +154,10 @@ namespace Fab2ApprovalSystem.DMO
|
|||||||
FabApprovalTrainingEntities db = new FabApprovalTrainingEntities();
|
FabApprovalTrainingEntities db = new FabApprovalTrainingEntities();
|
||||||
var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a;
|
var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a;
|
||||||
|
|
||||||
|
RefreshTrainingData(TrainingID, TrainingData);
|
||||||
|
|
||||||
|
TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a;
|
||||||
|
|
||||||
return TrainingData.ToList();
|
return TrainingData.ToList();
|
||||||
}
|
}
|
||||||
public List<TrainingAssignment> GetTrainingAssignments(int TrainingID)
|
public List<TrainingAssignment> GetTrainingAssignments(int TrainingID)
|
||||||
@ -161,6 +165,10 @@ namespace Fab2ApprovalSystem.DMO
|
|||||||
FabApprovalTrainingEntities db = new FabApprovalTrainingEntities();
|
FabApprovalTrainingEntities db = new FabApprovalTrainingEntities();
|
||||||
var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID && a.Deleted != true select a;
|
var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID && a.Deleted != true select a;
|
||||||
|
|
||||||
|
RefreshTrainingData(TrainingID, TrainingData);
|
||||||
|
|
||||||
|
TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a;
|
||||||
|
|
||||||
return TrainingData.ToList();
|
return TrainingData.ToList();
|
||||||
}
|
}
|
||||||
public List<TrainingAssignment> GetTrainingAssignmentsByUser(int TrainingID, int userID)
|
public List<TrainingAssignment> GetTrainingAssignmentsByUser(int TrainingID, int userID)
|
||||||
@ -452,5 +460,20 @@ namespace Fab2ApprovalSystem.DMO
|
|||||||
return openAssignments;
|
return openAssignments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RefreshTrainingData(int TrainingID, IQueryable<TrainingAssignment> TrainingData)
|
||||||
|
{
|
||||||
|
bool assignmentIsIncomplete = false;
|
||||||
|
UserAccountDMO userAccountDMO = new UserAccountDMO();
|
||||||
|
foreach (TrainingAssignment assignment in TrainingData)
|
||||||
|
{
|
||||||
|
LoginModel userModel = userAccountDMO.GetUserByID(assignment.UserID);
|
||||||
|
if (!userModel.IsActive) UpdateAssignmentStatus(assignment.ID);
|
||||||
|
if (assignment.Deleted != true && (assignment.DateCompleted is null || assignment.DateCompleted > DateTime.Now))
|
||||||
|
assignmentIsIncomplete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!assignmentIsIncomplete)
|
||||||
|
UpdateTrainingStatus(TrainingID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,6 @@ namespace Fab2ApprovalSystem.ViewModels
|
|||||||
public string Originator { get; set; }
|
public string Originator { get; set; }
|
||||||
public DateTime? AssignedDate { get; set; }
|
public DateTime? AssignedDate { get; set; }
|
||||||
public DateTime? DueDate { get; set; }
|
public DateTime? DueDate { get; set; }
|
||||||
public string pcrMesaID { get; set; }
|
public string pcrMesaID { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -227,7 +227,7 @@
|
|||||||
)
|
)
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 col-sm-offset-4" style="color:red;">
|
<div class="col-sm-6 col-sm-offset-4" style="color:red;">
|
||||||
ECN: Qualtiy and Dept. Specific<br />MRB: Quality, Production, Engineering, OPC<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change)
|
ECN: Qualtiy and Dept. Specific<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@ -171,7 +171,7 @@
|
|||||||
)
|
)
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 col-sm-offset-4" style="color:red;">
|
<div class="col-sm-6 col-sm-offset-4" style="color:red;">
|
||||||
ECN: Qualtiy and Dept. Specific<br />MRB: Quality, Production, Engineering, OPC<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change)
|
ECN: Qualtiy and Dept. Specific<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@ -259,7 +259,7 @@
|
|||||||
)
|
)
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 col-sm-offset-4" style="color:red;">
|
<div class="col-sm-6 col-sm-offset-4" style="color:red;">
|
||||||
ECN: Qualtiy and Dept. Specific<br />MRB: Quality, Production, Engineering, OPC<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change)
|
ECN: Qualtiy and Dept. Specific<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@ -83,6 +83,25 @@
|
|||||||
@*<li><a href=@Url.Action("Create", "LotDisposition")>Lot Dispostion</a></li>*@
|
@*<li><a href=@Url.Action("Create", "LotDisposition")>Lot Dispostion</a></li>*@
|
||||||
@*<li><a href=@Url.Action("Create", "MRB")>Create MRB</a></li>*@
|
@*<li><a href=@Url.Action("Create", "MRB")>Create MRB</a></li>*@
|
||||||
<li><a href=@Url.Action("Create", "ECN")>Create ECN/TECN</a></li>
|
<li><a href=@Url.Action("Create", "ECN")>Create ECN/TECN</a></li>
|
||||||
|
@if (!string.IsNullOrWhiteSpace(Session["JWT"].ToString())) {
|
||||||
|
string jwt = Session["JWT"].ToString();
|
||||||
|
string encodedJwt = System.Net.WebUtility.UrlEncode(jwt);
|
||||||
|
string refreshToken = Session["RefreshToken"].ToString();
|
||||||
|
string encodedRefreshToken = System.Net.WebUtility.UrlEncode(refreshToken);
|
||||||
|
string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ??
|
||||||
|
"https://localhost:7255";
|
||||||
|
string mrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/mrb/new";
|
||||||
|
<li><a href="@mrbUrl">Create MRB</a></li>
|
||||||
|
@*string pcrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/pcrb/new";
|
||||||
|
<li><a href="@pcrbUrl">Create PCRB</a></li>*@
|
||||||
|
} else {
|
||||||
|
string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ??
|
||||||
|
"https://localhost:7255";
|
||||||
|
string mrbUrl = wasmClientUrl + "/redirect?redirectPath=/mrb/new";
|
||||||
|
<li><a href="@mrbUrl">Create MRB</a></li>
|
||||||
|
@*string pcrbUrl = wasmClientUrl + "/redirect?redirectPath=/pcrb/new";
|
||||||
|
<li><a href="@pcrbUrl">Create PCRB</a></li>*@
|
||||||
|
}
|
||||||
@*<li><a href=@Url.Action("CreateWorkRequest", "LotTraveler")>Create Special Work Request</a></li>*@
|
@*<li><a href=@Url.Action("CreateWorkRequest", "LotTraveler")>Create Special Work Request</a></li>*@
|
||||||
@*<li><a href=@Url.Action("Create", "ChangeControl")>Create PCR</a></li>*@
|
@*<li><a href=@Url.Action("Create", "ChangeControl")>Create PCR</a></li>*@
|
||||||
<li><a href=@Url.Action("Create", "Audit")>Create Audit</a></li>
|
<li><a href=@Url.Action("Create", "Audit")>Create Audit</a></li>
|
||||||
@ -133,6 +152,8 @@
|
|||||||
"https://localhost:7255";
|
"https://localhost:7255";
|
||||||
string mrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/mrb/all";
|
string mrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/mrb/all";
|
||||||
menu.Add().Text("MRB").Url(mrbUrl);
|
menu.Add().Text("MRB").Url(mrbUrl);
|
||||||
|
//string pcrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/pcrb/all";
|
||||||
|
//menu.Add().Text("PCRB").Url(pcrbUrl);
|
||||||
//menu.Add().Text("Special Work Requests").Action("SpecialWorkRequestList", "Home");
|
//menu.Add().Text("Special Work Requests").Action("SpecialWorkRequestList", "Home");
|
||||||
//menu.Add().Text("PCRB").Action("ChangeControlList", "Home");
|
//menu.Add().Text("PCRB").Action("ChangeControlList", "Home");
|
||||||
//menu.Add().Text("MRB").Action("MRBList", "Home");
|
//menu.Add().Text("MRB").Action("MRBList", "Home");
|
||||||
|
|||||||
@ -132,6 +132,11 @@
|
|||||||
<requestLimits maxAllowedContentLength="1073741824" />
|
<requestLimits maxAllowedContentLength="1073741824" />
|
||||||
</requestFiltering>
|
</requestFiltering>
|
||||||
</security>
|
</security>
|
||||||
|
<httpProtocol>
|
||||||
|
<customHeaders>
|
||||||
|
<add name="Access-Control-Allow-Origin" value="*" />
|
||||||
|
</customHeaders>
|
||||||
|
</httpProtocol>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
<runtime>
|
<runtime>
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
|||||||
260
MesaFabApproval.API/.editorconfig
Normal file
260
MesaFabApproval.API/.editorconfig
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# C# files
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
#### Core EditorConfig Options ####
|
||||||
|
|
||||||
|
# Indentation and spacing
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
end_of_line = crlf
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
#### .NET Coding Conventions ####
|
||||||
|
|
||||||
|
# Organize usings
|
||||||
|
dotnet_separate_import_directive_groups = true
|
||||||
|
dotnet_sort_system_directives_first = true
|
||||||
|
file_header_template = unset
|
||||||
|
|
||||||
|
# this. and Me. preferences
|
||||||
|
dotnet_style_qualification_for_event = true
|
||||||
|
dotnet_style_qualification_for_field = true
|
||||||
|
dotnet_style_qualification_for_method = true
|
||||||
|
dotnet_style_qualification_for_property = true
|
||||||
|
|
||||||
|
# Language keywords vs BCL types preferences
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||||
|
dotnet_style_predefined_type_for_member_access = true
|
||||||
|
|
||||||
|
# Parentheses preferences
|
||||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:error
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:error
|
||||||
|
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:error
|
||||||
|
|
||||||
|
# Modifier preferences
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||||
|
|
||||||
|
# Expression-level preferences
|
||||||
|
dotnet_style_coalesce_expression = false
|
||||||
|
dotnet_style_collection_initializer = true
|
||||||
|
dotnet_style_explicit_tuple_names = true:error
|
||||||
|
dotnet_style_namespace_match_folder = true
|
||||||
|
dotnet_style_null_propagation = true
|
||||||
|
dotnet_style_object_initializer = true
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
dotnet_style_prefer_auto_properties = true
|
||||||
|
dotnet_style_prefer_compound_assignment = true
|
||||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
|
||||||
|
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = false
|
||||||
|
dotnet_style_prefer_inferred_tuple_names = false
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||||
|
dotnet_style_prefer_simplified_interpolation = true
|
||||||
|
|
||||||
|
# Field preferences
|
||||||
|
dotnet_style_readonly_field = true:warning
|
||||||
|
|
||||||
|
# Parameter preferences
|
||||||
|
dotnet_code_quality_unused_parameters = all:error
|
||||||
|
|
||||||
|
# Suppression preferences
|
||||||
|
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
dotnet_style_allow_multiple_blank_lines_experimental = false:error
|
||||||
|
dotnet_style_allow_statement_immediately_after_block_experimental = false:warning
|
||||||
|
|
||||||
|
#### C# Coding Conventions ####
|
||||||
|
|
||||||
|
# var preferences
|
||||||
|
csharp_style_var_elsewhere = false:error
|
||||||
|
csharp_style_var_for_built_in_types = false:error
|
||||||
|
csharp_style_var_when_type_is_apparent = false:error
|
||||||
|
|
||||||
|
# Expression-bodied members
|
||||||
|
csharp_style_expression_bodied_accessors = false
|
||||||
|
csharp_style_expression_bodied_constructors = false
|
||||||
|
csharp_style_expression_bodied_indexers = false
|
||||||
|
csharp_style_expression_bodied_lambdas = true
|
||||||
|
csharp_style_expression_bodied_local_functions = false
|
||||||
|
csharp_style_expression_bodied_methods = when_on_single_line:suggestion
|
||||||
|
csharp_style_expression_bodied_operators = false
|
||||||
|
csharp_style_expression_bodied_properties = false
|
||||||
|
|
||||||
|
# Pattern matching preferences
|
||||||
|
csharp_style_pattern_matching_over_as_with_null_check = false
|
||||||
|
csharp_style_pattern_matching_over_is_with_cast_check = false
|
||||||
|
csharp_style_prefer_extended_property_pattern = true
|
||||||
|
csharp_style_prefer_not_pattern = true
|
||||||
|
csharp_style_prefer_pattern_matching = true
|
||||||
|
csharp_style_prefer_switch_expression = false
|
||||||
|
|
||||||
|
# Null-checking preferences
|
||||||
|
csharp_style_conditional_delegate_call = false
|
||||||
|
|
||||||
|
# Modifier preferences
|
||||||
|
csharp_prefer_static_local_function = false
|
||||||
|
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
|
||||||
|
csharp_style_prefer_readonly_struct = true:warning
|
||||||
|
csharp_style_prefer_readonly_struct_member = true
|
||||||
|
|
||||||
|
# Code-block preferences
|
||||||
|
csharp_prefer_braces = when_multiline:error
|
||||||
|
csharp_prefer_simple_using_statement = false
|
||||||
|
csharp_style_namespace_declarations = file_scoped:error
|
||||||
|
csharp_style_prefer_method_group_conversion = true:suggestion
|
||||||
|
csharp_style_prefer_top_level_statements = true:error
|
||||||
|
|
||||||
|
# Expression-level preferences
|
||||||
|
csharp_prefer_simple_default_expression = true
|
||||||
|
csharp_style_deconstructed_variable_declaration = false
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = false
|
||||||
|
csharp_style_inlined_variable_declaration = true
|
||||||
|
csharp_style_prefer_index_operator = false:error
|
||||||
|
csharp_style_prefer_local_over_anonymous_function = true:error
|
||||||
|
csharp_style_prefer_null_check_over_type_check = true
|
||||||
|
csharp_style_prefer_range_operator = false:error
|
||||||
|
csharp_style_prefer_tuple_swap = true
|
||||||
|
csharp_style_prefer_utf8_string_literals = true
|
||||||
|
csharp_style_throw_expression = false
|
||||||
|
csharp_style_unused_value_assignment_preference = unused_local_variable
|
||||||
|
csharp_style_unused_value_expression_statement_preference = unused_local_variable
|
||||||
|
|
||||||
|
# 'using' directive preferences
|
||||||
|
csharp_using_directive_placement = outside_namespace:error
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
||||||
|
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
|
||||||
|
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
|
||||||
|
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:error
|
||||||
|
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
||||||
|
|
||||||
|
#### C# Formatting Rules ####
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
csharp_new_line_before_catch = false
|
||||||
|
csharp_new_line_before_else = false
|
||||||
|
csharp_new_line_before_finally = false
|
||||||
|
csharp_new_line_before_members_in_anonymous_types = true
|
||||||
|
csharp_new_line_before_members_in_object_initializers = true
|
||||||
|
csharp_new_line_before_open_brace = none
|
||||||
|
csharp_new_line_between_query_expression_clauses = true
|
||||||
|
|
||||||
|
# Indentation preferences
|
||||||
|
csharp_indent_block_contents = true
|
||||||
|
csharp_indent_braces = false
|
||||||
|
csharp_indent_case_contents = true
|
||||||
|
csharp_indent_case_contents_when_block = true
|
||||||
|
csharp_indent_labels = one_less_than_current
|
||||||
|
csharp_indent_switch_labels = true
|
||||||
|
|
||||||
|
# Space preferences
|
||||||
|
csharp_space_after_cast = false
|
||||||
|
csharp_space_after_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_after_comma = true
|
||||||
|
csharp_space_after_dot = false
|
||||||
|
csharp_space_after_keywords_in_control_flow_statements = true
|
||||||
|
csharp_space_after_semicolon_in_for_statement = true
|
||||||
|
csharp_space_around_binary_operators = before_and_after
|
||||||
|
csharp_space_around_declaration_statements = false
|
||||||
|
csharp_space_before_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_before_comma = false
|
||||||
|
csharp_space_before_dot = false
|
||||||
|
csharp_space_before_open_square_brackets = false
|
||||||
|
csharp_space_before_semicolon_in_for_statement = false
|
||||||
|
csharp_space_between_empty_square_brackets = false
|
||||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||||
|
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_parentheses = false
|
||||||
|
csharp_space_between_square_brackets = false
|
||||||
|
|
||||||
|
# Wrapping preferences
|
||||||
|
csharp_preserve_single_line_blocks = true
|
||||||
|
csharp_preserve_single_line_statements = true
|
||||||
|
|
||||||
|
#### Naming styles ####
|
||||||
|
|
||||||
|
# Naming rules
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||||
|
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
# Symbol specifications
|
||||||
|
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.types.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
|
||||||
|
# Naming styles
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case.required_prefix =
|
||||||
|
dotnet_naming_style.pascal_case.required_suffix =
|
||||||
|
dotnet_naming_style.pascal_case.word_separator =
|
||||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||||
|
dotnet_naming_style.begins_with_i.required_suffix =
|
||||||
|
dotnet_naming_style.begins_with_i.word_separator =
|
||||||
|
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||||
|
|
||||||
|
# Question
|
||||||
|
|
||||||
|
dotnet_diagnostic.ASP0025.severity = none # Use AddAuthorizationBuilder to register authorization services and construct policies [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1510.severity = none # Use 'ArgumentNullException.ThrowIfNull' instead of explicitly throwing a new exception instance [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1806.severity = none # 'MRBNumberIsValid' calls 'Append' but does not use the value the method returns. Linq methods are known to not have side effects. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1822.severity = none # Member 'GenerateRefreshToken' does not access instance data and can be marked as static [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1825.severity = none # Avoid unnecessary zero-length array allocations. Use Array.Empty<string>() instead. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1827.severity = none # Count() is used where Any() could be used instead to improve performance [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1829.severity = none # Use the \"Count\" property instead of Enumerable.Count() [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1861.severity = none # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA2208.severity = none # Method UpdateMRBAction passes 'MRB action cannot be null' as the paramName argument to a ArgumentNullException constructor. Replace this argument with one of the method's parameter names. Note that the provided parameter name should have the exact casing as declared on the method. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA2254.severity = none # The type or namespace name 'AspNetCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.CS0234.severity = none # The type or namespace name 'Extensions' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.CS0246.severity = none # The type or namespace name 'ILogger<>' could not be found (are you missing a using directive or an assembly reference?) [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.CS1998.severity = none # This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CS8019.severity = none # Unnecessary using directive
|
||||||
|
dotnet_diagnostic.CS8600.severity = none # Converting null literal or possible null value to non-nullable type. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CS8625.severity = none # Cannot convert null literal to non-nullable reference type. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CS8765.severity = none # Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes). [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.IDE0001.severity = none # Name can be simplified
|
||||||
|
dotnet_diagnostic.IDE0017.severity = none # Object initialization can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0022.severity = none # Use expression body for method [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.IDE0028.severity = none # Collection initialization can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0044.severity = none # Make field readonly [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0046.severity = none # "'if' statement can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0052.severity = none # Private member 'CustomerController._cache' can be removed as the value assigned to it is never read [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0074.severity = none # Use compound assignment [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0305.severity = none # Collection initialization can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = false
|
||||||
1
MesaFabApproval.API/.vscode/format-report.json
vendored
Normal file
1
MesaFabApproval.API/.vscode/format-report.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
30
MesaFabApproval.API/.vscode/launch.json
vendored
Normal file
30
MesaFabApproval.API/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (console)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/net8.0/MesaFabApproval.API.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "node Launch Current Opened File",
|
||||||
|
"program": "${file}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
6
MesaFabApproval.API/.vscode/mklink.md
vendored
Normal file
6
MesaFabApproval.API/.vscode/mklink.md
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# mklink
|
||||||
|
|
||||||
|
```bash 1731705389065 = 638673021890650000 = Fri Nov 15 2024 14:16:28 GMT-0700 (Mountain Standard Time)
|
||||||
|
mklink /J "L:\DevOps\Mesa_FI\MesaFabApproval\MesaFabApproval.API\.vscode\.UserSecrets" "C:\Users\phares\AppData\Roaming\Microsoft\UserSecrets\0b98e1f2-95ed-4edd-8149-58cce51ca059"
|
||||||
|
dotnet run --urls=https://localhost:7114/ -C Release
|
||||||
|
```
|
||||||
424
MesaFabApproval.API/.vscode/settings.json
vendored
Normal file
424
MesaFabApproval.API/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
{
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.wordWrap": "off"
|
||||||
|
},
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": false,
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"cSpell.words": [
|
||||||
|
"abutton",
|
||||||
|
"accessibilities",
|
||||||
|
"accodingly",
|
||||||
|
"acknowledgmentby",
|
||||||
|
"Acks",
|
||||||
|
"actionsheet",
|
||||||
|
"Additonal",
|
||||||
|
"Addtional",
|
||||||
|
"againm",
|
||||||
|
"agendaview",
|
||||||
|
"Antlr",
|
||||||
|
"Appover",
|
||||||
|
"Appprrovers",
|
||||||
|
"Approvalog",
|
||||||
|
"Aprovers",
|
||||||
|
"Aproverslist",
|
||||||
|
"asax",
|
||||||
|
"aspnetmvc",
|
||||||
|
"Assignedto",
|
||||||
|
"Atachments",
|
||||||
|
"Attachemnt",
|
||||||
|
"Attachemnts",
|
||||||
|
"Attchment",
|
||||||
|
"auditee",
|
||||||
|
"Auditee",
|
||||||
|
"Auditees",
|
||||||
|
"automaically",
|
||||||
|
"Autthorized",
|
||||||
|
"beacuase",
|
||||||
|
"beforeunload",
|
||||||
|
"Belguim",
|
||||||
|
"bfound",
|
||||||
|
"bgcolor",
|
||||||
|
"Bies",
|
||||||
|
"binded",
|
||||||
|
"blackbackground",
|
||||||
|
"blackhover",
|
||||||
|
"blackpressed",
|
||||||
|
"blueenergy",
|
||||||
|
"blueopal",
|
||||||
|
"buttongroup",
|
||||||
|
"BYMRB",
|
||||||
|
"bytesgot",
|
||||||
|
"CAID",
|
||||||
|
"casection",
|
||||||
|
"CAXXXX",
|
||||||
|
"CCPCR",
|
||||||
|
"CCPCRB",
|
||||||
|
"cellspacing",
|
||||||
|
"Cheeso's",
|
||||||
|
"chkbx",
|
||||||
|
"Clib",
|
||||||
|
"colorpicker",
|
||||||
|
"columnmenu",
|
||||||
|
"columnsreorder",
|
||||||
|
"columnsresize",
|
||||||
|
"comming",
|
||||||
|
"Containmen",
|
||||||
|
"Copmments",
|
||||||
|
"correctiv",
|
||||||
|
"Correctivet",
|
||||||
|
"Creat",
|
||||||
|
"currentd",
|
||||||
|
"Cyle",
|
||||||
|
"dadada",
|
||||||
|
"darkbluehover",
|
||||||
|
"darkbluepressed",
|
||||||
|
"darkred",
|
||||||
|
"datafields",
|
||||||
|
"datasource",
|
||||||
|
"dataviz",
|
||||||
|
"datepicker",
|
||||||
|
"datetimepicker",
|
||||||
|
"dayview",
|
||||||
|
"Deletet",
|
||||||
|
"Delgation",
|
||||||
|
"DENITED",
|
||||||
|
"Deparmtent",
|
||||||
|
"departmentids",
|
||||||
|
"Descirption",
|
||||||
|
"devprog",
|
||||||
|
"dfeffc",
|
||||||
|
"Disp",
|
||||||
|
"Dispo",
|
||||||
|
"Dispoitio",
|
||||||
|
"Dispos",
|
||||||
|
"Dispositon",
|
||||||
|
"Dispostion",
|
||||||
|
"Dispostions",
|
||||||
|
"dispotypevalidation",
|
||||||
|
"Docbase",
|
||||||
|
"Documentum",
|
||||||
|
"Documetum",
|
||||||
|
"dont",
|
||||||
|
"downlaoded",
|
||||||
|
"draganddrop",
|
||||||
|
"dragcancel",
|
||||||
|
"dropdownlist",
|
||||||
|
"Eamils",
|
||||||
|
"ECNPCRB",
|
||||||
|
"Ecns",
|
||||||
|
"edmx",
|
||||||
|
"EECN",
|
||||||
|
"emai",
|
||||||
|
"emailparams",
|
||||||
|
"Emergrncy",
|
||||||
|
"energyblue",
|
||||||
|
"Eran",
|
||||||
|
"Esql",
|
||||||
|
"ETECN",
|
||||||
|
"EXCELOPENXML",
|
||||||
|
"existinglocation",
|
||||||
|
"Expando",
|
||||||
|
"extrafield",
|
||||||
|
"fadc",
|
||||||
|
"fbec",
|
||||||
|
"fcfdfd",
|
||||||
|
"fdff",
|
||||||
|
"fece",
|
||||||
|
"feeebd",
|
||||||
|
"ffdc",
|
||||||
|
"ffdd",
|
||||||
|
"fieldset",
|
||||||
|
"FILIPE",
|
||||||
|
"filtermenu",
|
||||||
|
"Fldr",
|
||||||
|
"flintstone",
|
||||||
|
"FLOWLOCS",
|
||||||
|
"FMEA",
|
||||||
|
"ftplib",
|
||||||
|
"FTPSPN",
|
||||||
|
"GETDATE",
|
||||||
|
"gitea",
|
||||||
|
"globaldocudms",
|
||||||
|
"glyphicons",
|
||||||
|
"groupable",
|
||||||
|
"Guids",
|
||||||
|
"halflings",
|
||||||
|
"Hexsize",
|
||||||
|
"highcontrast",
|
||||||
|
"Hmac",
|
||||||
|
"holdsteps",
|
||||||
|
"hostspecific",
|
||||||
|
"icenium",
|
||||||
|
"IECN",
|
||||||
|
"imagebrowser",
|
||||||
|
"IMRB",
|
||||||
|
"Infineon",
|
||||||
|
"Insertd",
|
||||||
|
"inverseicons",
|
||||||
|
"IPCRB",
|
||||||
|
"ISADMIN",
|
||||||
|
"islast",
|
||||||
|
"ISNULL",
|
||||||
|
"ITAR",
|
||||||
|
"jquery",
|
||||||
|
"jqueryval",
|
||||||
|
"jqwidgets",
|
||||||
|
"jqxbuttongroup",
|
||||||
|
"jqxbuttons",
|
||||||
|
"jqxcalendar",
|
||||||
|
"jqxchart",
|
||||||
|
"jqxcheckbox",
|
||||||
|
"jqxcolorpicker",
|
||||||
|
"jqxcombobox",
|
||||||
|
"jqxcore",
|
||||||
|
"jqxdata",
|
||||||
|
"jqxdatatable",
|
||||||
|
"jqxdatetimeinput",
|
||||||
|
"jqxdocking",
|
||||||
|
"jqxdockpanel",
|
||||||
|
"jqxdragdrop",
|
||||||
|
"jqxdropdownbutton",
|
||||||
|
"jqxdropdownlist",
|
||||||
|
"jqxexpander",
|
||||||
|
"jqxgauge",
|
||||||
|
"jqxgrid",
|
||||||
|
"jqxinput",
|
||||||
|
"jqxknockout",
|
||||||
|
"jqxlistbox",
|
||||||
|
"jqxlistmenu",
|
||||||
|
"jqxmaskedinput",
|
||||||
|
"jqxmenu",
|
||||||
|
"jqxnavigationbar",
|
||||||
|
"jqxnumberinput",
|
||||||
|
"jqxpanel",
|
||||||
|
"jqxpasswordinput",
|
||||||
|
"jqxprogressbar",
|
||||||
|
"jqxradiobutton",
|
||||||
|
"jqxrangeselector",
|
||||||
|
"jqxrating",
|
||||||
|
"jqxresponse",
|
||||||
|
"jqxscrollbar",
|
||||||
|
"jqxscrollview",
|
||||||
|
"jqxslider",
|
||||||
|
"jqxsplitter",
|
||||||
|
"jqxswitchbutton",
|
||||||
|
"jqxtabs",
|
||||||
|
"jqxtooltip",
|
||||||
|
"jqxtouch",
|
||||||
|
"jqxtree",
|
||||||
|
"jqxtreegrid",
|
||||||
|
"jqxtreemap",
|
||||||
|
"jqxvalidator",
|
||||||
|
"jqxwindow",
|
||||||
|
"kendogridcustom",
|
||||||
|
"kendoui",
|
||||||
|
"labelelement",
|
||||||
|
"labelledby",
|
||||||
|
"Leanred",
|
||||||
|
"lightgray",
|
||||||
|
"linkbutton",
|
||||||
|
"Linq",
|
||||||
|
"Listdiv",
|
||||||
|
"listview",
|
||||||
|
"Lnks",
|
||||||
|
"localfilename",
|
||||||
|
"loclist",
|
||||||
|
"logis",
|
||||||
|
"logtext",
|
||||||
|
"loopmis",
|
||||||
|
"lotdispo",
|
||||||
|
"LOTDISPSITION",
|
||||||
|
"Lotfile",
|
||||||
|
"lotlist",
|
||||||
|
"lotstatusoption",
|
||||||
|
"LTRIM",
|
||||||
|
"MADUREIRA",
|
||||||
|
"mailrelay",
|
||||||
|
"MDTM",
|
||||||
|
"meego",
|
||||||
|
"meetingid",
|
||||||
|
"menubutton",
|
||||||
|
"mesafi",
|
||||||
|
"metroblack",
|
||||||
|
"metrodark",
|
||||||
|
"miliseconds",
|
||||||
|
"modalview",
|
||||||
|
"modernizr",
|
||||||
|
"Modernizr",
|
||||||
|
"monthview",
|
||||||
|
"MRBIs",
|
||||||
|
"Mrbs",
|
||||||
|
"msecs",
|
||||||
|
"multipleextended",
|
||||||
|
"Navigatable",
|
||||||
|
"nbsp",
|
||||||
|
"newbase",
|
||||||
|
"newchange",
|
||||||
|
"newdi",
|
||||||
|
"newfilename",
|
||||||
|
"newsource",
|
||||||
|
"Newtonsoft",
|
||||||
|
"notications",
|
||||||
|
"Notifcation",
|
||||||
|
"Notifyf",
|
||||||
|
"NTLM",
|
||||||
|
"Nullcc",
|
||||||
|
"numerictextbox",
|
||||||
|
"objdata",
|
||||||
|
"OCAP",
|
||||||
|
"occured",
|
||||||
|
"odata",
|
||||||
|
"oldfilename",
|
||||||
|
"OLHOLD",
|
||||||
|
"onclick",
|
||||||
|
"onmousemove",
|
||||||
|
"OPDESC",
|
||||||
|
"OPENQUERY",
|
||||||
|
"Oper",
|
||||||
|
"operationslist",
|
||||||
|
"Orginator",
|
||||||
|
"Originatorname",
|
||||||
|
"Ouellette",
|
||||||
|
"Owin",
|
||||||
|
"pageable",
|
||||||
|
"Pageable",
|
||||||
|
"panelbar",
|
||||||
|
"parentid",
|
||||||
|
"parminput",
|
||||||
|
"parms",
|
||||||
|
"Parms",
|
||||||
|
"particula",
|
||||||
|
"pasv",
|
||||||
|
"PASV",
|
||||||
|
"PATINDEX",
|
||||||
|
"PCRB",
|
||||||
|
"PCRBID",
|
||||||
|
"pcrvalues",
|
||||||
|
"pdbonly",
|
||||||
|
"Preventitive",
|
||||||
|
"preventivet",
|
||||||
|
"Prevetative",
|
||||||
|
"proces",
|
||||||
|
"Processedl",
|
||||||
|
"procs",
|
||||||
|
"productfamilies",
|
||||||
|
"progess",
|
||||||
|
"progressbar",
|
||||||
|
"qrcode",
|
||||||
|
"Quanityt",
|
||||||
|
"rangebar",
|
||||||
|
"Recep",
|
||||||
|
"Recepient",
|
||||||
|
"recieved",
|
||||||
|
"recordlock",
|
||||||
|
"remotefilename",
|
||||||
|
"reorderable",
|
||||||
|
"reportform",
|
||||||
|
"reportslist",
|
||||||
|
"reportslistdiv",
|
||||||
|
"Reqquired",
|
||||||
|
"Reqs",
|
||||||
|
"Requiest",
|
||||||
|
"Responsibles",
|
||||||
|
"RETR",
|
||||||
|
"Revisioing",
|
||||||
|
"Revisioned",
|
||||||
|
"Revison",
|
||||||
|
"rgba",
|
||||||
|
"rkotian",
|
||||||
|
"RNFR",
|
||||||
|
"RNTO",
|
||||||
|
"Roless",
|
||||||
|
"roundbg",
|
||||||
|
"RTRIM",
|
||||||
|
"SAMDB",
|
||||||
|
"scroller",
|
||||||
|
"scrollview",
|
||||||
|
"seleced",
|
||||||
|
"selectionlog",
|
||||||
|
"Selectpart",
|
||||||
|
"sess",
|
||||||
|
"Sfisharepoint",
|
||||||
|
"shinyblack",
|
||||||
|
"showpassword",
|
||||||
|
"SIGNON",
|
||||||
|
"simpleparser",
|
||||||
|
"slddrw",
|
||||||
|
"sldprt",
|
||||||
|
"sortasc",
|
||||||
|
"sortascbutton",
|
||||||
|
"sortdesc",
|
||||||
|
"sortdescbutton",
|
||||||
|
"sortremove",
|
||||||
|
"sparkline",
|
||||||
|
"splitview",
|
||||||
|
"SPNMRB",
|
||||||
|
"SPNPDB",
|
||||||
|
"SSRS",
|
||||||
|
"Sssign",
|
||||||
|
"Staus",
|
||||||
|
"stylesheet",
|
||||||
|
"Submited",
|
||||||
|
"subrole",
|
||||||
|
"subroles",
|
||||||
|
"Succefully",
|
||||||
|
"Succesfully",
|
||||||
|
"sucessfully",
|
||||||
|
"SURP",
|
||||||
|
"Swashbuckle",
|
||||||
|
"SWRN",
|
||||||
|
"tabindex",
|
||||||
|
"tabstrip",
|
||||||
|
"Tahoma",
|
||||||
|
"taskcompleted",
|
||||||
|
"Tasklist",
|
||||||
|
"Taveler",
|
||||||
|
"TECN",
|
||||||
|
"TECNs",
|
||||||
|
"TEMIRWAP",
|
||||||
|
"tempecd",
|
||||||
|
"tempimplement",
|
||||||
|
"templabel",
|
||||||
|
"tempvalue",
|
||||||
|
"TEMSA",
|
||||||
|
"timepicker",
|
||||||
|
"Tobe",
|
||||||
|
"Toplevel",
|
||||||
|
"Totrav",
|
||||||
|
"trainingby",
|
||||||
|
"Traininglist",
|
||||||
|
"traininglistdiv",
|
||||||
|
"transanction",
|
||||||
|
"Trav",
|
||||||
|
"Traveller",
|
||||||
|
"Traverler",
|
||||||
|
"TRAVLELER",
|
||||||
|
"Travler",
|
||||||
|
"TREEVIEW",
|
||||||
|
"trigerred",
|
||||||
|
"ttinclude",
|
||||||
|
"Uhandled",
|
||||||
|
"Updat",
|
||||||
|
"Uplaod",
|
||||||
|
"Upto",
|
||||||
|
"userevents",
|
||||||
|
"userids",
|
||||||
|
"userlist",
|
||||||
|
"Validatable",
|
||||||
|
"valueelement",
|
||||||
|
"Variabls",
|
||||||
|
"Verdana",
|
||||||
|
"vgrid",
|
||||||
|
"viewmodel",
|
||||||
|
"vsdoc",
|
||||||
|
"whethere",
|
||||||
|
"windowsphone",
|
||||||
|
"Winsock",
|
||||||
|
"worlflow"
|
||||||
|
]
|
||||||
|
}
|
||||||
135
MesaFabApproval.API/.vscode/tasks.json
vendored
Normal file
135
MesaFabApproval.API/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "User Secrets Init",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "User Secrets Set",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj",
|
||||||
|
"set",
|
||||||
|
"_UserSecretsId",
|
||||||
|
"0b98e1f2-95ed-4edd-8149-58cce51ca059"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "testDebug",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "testRelease",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary",
|
||||||
|
"-c",
|
||||||
|
"Release"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Publish AOT",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"-r",
|
||||||
|
"win-x64",
|
||||||
|
"-c",
|
||||||
|
"Release",
|
||||||
|
"-p:PublishAot=true",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.API.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ public interface ISmtpClientWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class SmtpClientWrapper : ISmtpClientWrapper {
|
public class SmtpClientWrapper : ISmtpClientWrapper {
|
||||||
private SmtpClient _client;
|
private readonly SmtpClient _client;
|
||||||
|
|
||||||
public SmtpClientWrapper(SmtpClient client) {
|
public SmtpClientWrapper(SmtpClient client) {
|
||||||
_client = client ??
|
_client = client ??
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
|
using System.Security.Principal;
|
||||||
|
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
using MesaFabApproval.Shared.Services;
|
using MesaFabApproval.Shared.Services;
|
||||||
@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace MesaFabApproval.API.Controllers;
|
namespace MesaFabApproval.API.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
[AllowAnonymous]
|
||||||
public class AuthenticationController : ControllerBase {
|
public class AuthenticationController : ControllerBase {
|
||||||
private readonly ILogger<AuthenticationController> _logger;
|
private readonly ILogger<AuthenticationController> _logger;
|
||||||
private readonly IMonInWorkerClient _monInClient;
|
private readonly IMonInWorkerClient _monInClient;
|
||||||
@ -26,7 +28,6 @@ public class AuthenticationController : ControllerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[AllowAnonymous]
|
|
||||||
[Route("auth/login")]
|
[Route("auth/login")]
|
||||||
public async Task<IActionResult> Login(AuthAttempt login) {
|
public async Task<IActionResult> Login(AuthAttempt login) {
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
@ -72,7 +73,51 @@ public class AuthenticationController : ControllerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[AllowAnonymous]
|
[Route("auth/login/localWindows")]
|
||||||
|
public async Task<IActionResult> LoginLocalWindows(WindowsIdentity identity) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isArgumentError = false;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to perform local Windows authentication");
|
||||||
|
|
||||||
|
if (identity is null) throw new ArgumentNullException("identity cannot be null");
|
||||||
|
|
||||||
|
LoginResult loginResult = await _authenticationService.AttemptLocalUserAuth(identity);
|
||||||
|
|
||||||
|
if (loginResult.IsAuthenticated)
|
||||||
|
return Ok(loginResult);
|
||||||
|
|
||||||
|
return Unauthorized();
|
||||||
|
} catch (ArgumentException ex) {
|
||||||
|
isArgumentError = true;
|
||||||
|
errorMessage = $"Invalid argument. {ex.Message}";
|
||||||
|
return BadRequest(errorMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot authenticate local Windows user, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "LoginLocalWindows";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isArgumentError) {
|
||||||
|
_logger.LogWarning(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
} else if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
[Route("auth/refresh")]
|
[Route("auth/refresh")]
|
||||||
public async Task<IActionResult> Refresh(AuthAttempt authAttempt) {
|
public async Task<IActionResult> Refresh(AuthAttempt authAttempt) {
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
@ -117,4 +162,17 @@ public class AuthenticationController : ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpOptions]
|
||||||
|
[Route("auth/refresh")]
|
||||||
|
public IActionResult RefreshOptions() {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Auth refresh options");
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Error in auth refresh options. Exception: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
56
MesaFabApproval.API/Controllers/CAController.cs
Normal file
56
MesaFabApproval.API/Controllers/CAController.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using MesaFabApproval.API.Services;
|
||||||
|
using MesaFabApproval.Shared.Models;
|
||||||
|
using MesaFabApproval.Shared.Services;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Controllers;
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class CAController : ControllerBase {
|
||||||
|
private readonly ILogger<ApprovalController> _logger;
|
||||||
|
private readonly ICAService _caService;
|
||||||
|
private readonly IMonInWorkerClient _monInClient;
|
||||||
|
|
||||||
|
public CAController(ILogger<ApprovalController> logger, ICAService caService,
|
||||||
|
IMonInWorkerClient monInClient) {
|
||||||
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
|
_caService = caService ?? throw new ArgumentNullException("ICAService not injected");
|
||||||
|
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("ca/isValidCANumber")]
|
||||||
|
public async Task<IActionResult> IsValidCANumber(int number) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to determine if {number} is a valid CA#");
|
||||||
|
|
||||||
|
if (number <= 0) return Ok(false);
|
||||||
|
|
||||||
|
bool isValid = await _caService.IsValidCANumber(number);
|
||||||
|
|
||||||
|
return Ok(isValid);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot determine if {number} is a valid CA#, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "IsValidCANumber";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
MesaFabApproval.API/Controllers/CustomerController.cs
Normal file
57
MesaFabApproval.API/Controllers/CustomerController.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using MesaFabApproval.API.Services;
|
||||||
|
using MesaFabApproval.Shared.Models;
|
||||||
|
using MesaFabApproval.Shared.Services;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class CustomerController : ControllerBase {
|
||||||
|
private readonly ILogger<CustomerController> _logger;
|
||||||
|
private readonly IMonInWorkerClient _monInClient;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly ICustomerService _customerService;
|
||||||
|
|
||||||
|
public CustomerController(ILogger<CustomerController> logger, IMonInWorkerClient monInClient, IMemoryCache cache, ICustomerService customerService) {
|
||||||
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
|
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||||
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
|
_customerService = customerService ?? throw new ArgumentNullException("ICustomerService");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("customer/all")]
|
||||||
|
public async Task<IActionResult> GetAllCustomerNames() {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to get all customer names");
|
||||||
|
|
||||||
|
IEnumerable<string> customerNames = await _customerService.GetCustomerNames();
|
||||||
|
|
||||||
|
return Ok(customerNames);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot get user by LoginID, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "GetAllCustomerNames";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
MesaFabApproval.API/Controllers/ECNController.cs
Normal file
56
MesaFabApproval.API/Controllers/ECNController.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using MesaFabApproval.API.Services;
|
||||||
|
using MesaFabApproval.Shared.Models;
|
||||||
|
using MesaFabApproval.Shared.Services;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Controllers;
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class ECNController : ControllerBase {
|
||||||
|
private readonly ILogger<ApprovalController> _logger;
|
||||||
|
private readonly IECNService _ecnService;
|
||||||
|
private readonly IMonInWorkerClient _monInClient;
|
||||||
|
|
||||||
|
public ECNController(ILogger<ApprovalController> logger, IECNService ecnService,
|
||||||
|
IMonInWorkerClient monInClient) {
|
||||||
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
|
_ecnService = ecnService ?? throw new ArgumentNullException("IECNService not injected");
|
||||||
|
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("ecn/isValidEcnNumber")]
|
||||||
|
public async Task<IActionResult> IsValidEcnNumber(int number) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to determine if {number} is a valid ECN#");
|
||||||
|
|
||||||
|
if (number <= 0) return Ok(false);
|
||||||
|
|
||||||
|
bool isValid = await _ecnService.IsValidECNNumber(number);
|
||||||
|
|
||||||
|
return Ok(isValid);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot determine if {number} is a valid ECN#, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "IsValidEcnNumber";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using MesaFabApproval.API.Services;
|
using MesaFabApproval.API.Services;
|
||||||
|
using MesaFabApproval.Models;
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
using MesaFabApproval.Shared.Services;
|
using MesaFabApproval.Shared.Services;
|
||||||
|
|
||||||
@ -15,10 +16,16 @@ public class MRBController : ControllerBase {
|
|||||||
private readonly IMRBService _mrbService;
|
private readonly IMRBService _mrbService;
|
||||||
private readonly IMonInWorkerClient _monInClient;
|
private readonly IMonInWorkerClient _monInClient;
|
||||||
|
|
||||||
public MRBController(ILogger<MRBController> logger, IMRBService mrbService, IMonInWorkerClient monInClient) {
|
private readonly string _mrbAttachmentPath;
|
||||||
|
|
||||||
|
public MRBController(ILogger<MRBController> logger,
|
||||||
|
IMRBService mrbService,
|
||||||
|
IMonInWorkerClient monInClient,
|
||||||
|
AppSettings appSettings) {
|
||||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
_mrbService = mrbService ?? throw new ArgumentNullException("IMRBService not injected");
|
_mrbService = mrbService ?? throw new ArgumentNullException("IMRBService not injected");
|
||||||
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||||
|
_mrbAttachmentPath = appSettings.MrbAttachmentPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -63,9 +70,51 @@ public class MRBController : ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("mrb/delete")]
|
||||||
|
public async Task<IActionResult> DeleteMRB(int mrbNumber) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isArgumentError = false;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to delete MRB# {mrbNumber}");
|
||||||
|
|
||||||
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||||
|
|
||||||
|
await _mrbService.DeleteMRB(mrbNumber);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
} catch (ArgumentException ex) {
|
||||||
|
isArgumentError = true;
|
||||||
|
errorMessage = ex.Message;
|
||||||
|
return BadRequest(errorMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot delete MRB {mrbNumber}, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "DeleteMRB";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isArgumentError) {
|
||||||
|
_logger.LogWarning(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
} else if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("mrb/all")]
|
[Route("mrb/all")]
|
||||||
public async Task<IActionResult> GetAllMRBs() {
|
public async Task<IActionResult> GetAllMRBs(bool bypassCache) {
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
bool isInternalError = false;
|
bool isInternalError = false;
|
||||||
string errorMessage = "";
|
string errorMessage = "";
|
||||||
@ -73,7 +122,7 @@ public class MRBController : ControllerBase {
|
|||||||
try {
|
try {
|
||||||
_logger.LogInformation("Attempting to get all MRBs");
|
_logger.LogInformation("Attempting to get all MRBs");
|
||||||
|
|
||||||
IEnumerable<MRB> allMrbs = await _mrbService.GetAllMRBs();
|
IEnumerable<MRB> allMrbs = await _mrbService.GetAllMRBs(bypassCache);
|
||||||
|
|
||||||
return Ok(allMrbs);
|
return Ok(allMrbs);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@ -95,9 +144,41 @@ public class MRBController : ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("mrb/numberIsValid")]
|
||||||
|
public async Task<IActionResult> NumberIsValid(int number) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to determine if {number} is a valid MRB#");
|
||||||
|
|
||||||
|
bool isValid = await _mrbService.MRBNumberIsValid(number);
|
||||||
|
|
||||||
|
return Ok(isValid);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Unable to determine if {number} is a valid MRB#, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "IsValidMRBNumber";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("mrb/getById")]
|
[Route("mrb/getById")]
|
||||||
public async Task<IActionResult> GetMRBById(int id) {
|
public async Task<IActionResult> GetMRBById(int id, bool bypassCache = false) {
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
bool isArgumentError = false;
|
bool isArgumentError = false;
|
||||||
bool isInternalError = false;
|
bool isInternalError = false;
|
||||||
@ -108,7 +189,7 @@ public class MRBController : ControllerBase {
|
|||||||
|
|
||||||
if (id <= 0) throw new ArgumentException("Invalid MRB number");
|
if (id <= 0) throw new ArgumentException("Invalid MRB number");
|
||||||
|
|
||||||
MRB mrb = await _mrbService.GetMRBById(id);
|
MRB mrb = await _mrbService.GetMRBById(id, bypassCache);
|
||||||
|
|
||||||
return Ok(mrb);
|
return Ok(mrb);
|
||||||
} catch (ArgumentException ex) {
|
} catch (ArgumentException ex) {
|
||||||
@ -148,7 +229,7 @@ public class MRBController : ControllerBase {
|
|||||||
try {
|
try {
|
||||||
_logger.LogInformation("Attempting to get an MRB by Title");
|
_logger.LogInformation("Attempting to get an MRB by Title");
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or emtpy");
|
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||||
|
|
||||||
MRB mrb = await _mrbService.GetMRBByTitle(title, bypassCache);
|
MRB mrb = await _mrbService.GetMRBByTitle(title, bypassCache);
|
||||||
|
|
||||||
@ -432,6 +513,49 @@ public class MRBController : ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("mrb/action/attachments")]
|
||||||
|
public async Task<IActionResult> GetActionAttachmentsForMRB(int mrbNumber, bool bypassCache) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isArgumentError = false;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to get action attachments for MRB {mrbNumber}");
|
||||||
|
|
||||||
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||||
|
|
||||||
|
List<MRBActionAttachment> attachments =
|
||||||
|
(await _mrbService.GetAllActionAttachmentsForMRB(mrbNumber, bypassCache)).ToList();
|
||||||
|
|
||||||
|
return Ok(attachments);
|
||||||
|
} catch (ArgumentException ex) {
|
||||||
|
isArgumentError = true;
|
||||||
|
errorMessage = ex.Message;
|
||||||
|
return BadRequest(errorMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot get action attachments for MRB# {mrbNumber}, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "GetMRBActionAttachments";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isArgumentError) {
|
||||||
|
_logger.LogWarning(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
} else if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("mrb/attach")]
|
[Route("mrb/attach")]
|
||||||
public async Task<IActionResult> SaveMRBAttachment([FromForm] IEnumerable<IFormFile> files, int mrbNumber) {
|
public async Task<IActionResult> SaveMRBAttachment([FromForm] IEnumerable<IFormFile> files, int mrbNumber) {
|
||||||
@ -476,6 +600,50 @@ public class MRBController : ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("mrb/action/attach")]
|
||||||
|
public async Task<IActionResult> SaveMRBActionAttachment([FromForm] IEnumerable<IFormFile> files, int actionId) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isArgumentError = false;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to save MRB action attachments");
|
||||||
|
|
||||||
|
if (files is null) throw new ArgumentNullException("Files cannot be null");
|
||||||
|
if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty");
|
||||||
|
if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID");
|
||||||
|
|
||||||
|
IEnumerable<UploadResult> uploadResults = (await _mrbService.UploadActionAttachments(files, actionId)).ToList();
|
||||||
|
|
||||||
|
return Ok(uploadResults);
|
||||||
|
} catch (ArgumentException ex) {
|
||||||
|
isArgumentError = true;
|
||||||
|
errorMessage = ex.Message;
|
||||||
|
return BadRequest(errorMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot save MRB action attachments, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "SaveMRBActionAttachments";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isArgumentError) {
|
||||||
|
_logger.LogWarning(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
} else if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("mrb/attachmentFile")]
|
[Route("mrb/attachmentFile")]
|
||||||
@ -531,6 +699,64 @@ public class MRBController : ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("mrb/actions/csvFile")]
|
||||||
|
public async Task<IActionResult> GetMRBActionsCsvFile(int mrbNumber) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isArgumentError = false;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to get MRB actions CSC file");
|
||||||
|
|
||||||
|
if (!(await _mrbService.MRBNumberIsValid(mrbNumber)))
|
||||||
|
throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||||
|
|
||||||
|
string path = $"{_mrbAttachmentPath}\\{mrbNumber}\\mrb{mrbNumber}Actions.csv";
|
||||||
|
|
||||||
|
await _mrbService.ConvertActionsToCsvFile(mrbNumber, path);
|
||||||
|
|
||||||
|
byte[] fs = System.IO.File.ReadAllBytes(path);
|
||||||
|
|
||||||
|
const string defaultContentType = "application/octet-stream";
|
||||||
|
|
||||||
|
FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider();
|
||||||
|
|
||||||
|
if (!contentTypeProvider.TryGetContentType(path, out string? contentType)) {
|
||||||
|
contentType = defaultContentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FileContentResult(fs, contentType) {
|
||||||
|
FileDownloadName = $"mrb{mrbNumber}Actions.csv"
|
||||||
|
};
|
||||||
|
} catch (ArgumentException ex) {
|
||||||
|
isArgumentError = true;
|
||||||
|
errorMessage = ex.Message;
|
||||||
|
return BadRequest(errorMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Cannot get MRB actions CSC file, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "GetMRBActionsCSVFile";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isArgumentError) {
|
||||||
|
_logger.LogWarning(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
} else if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpDelete]
|
[HttpDelete]
|
||||||
[Route("mrb/attach")]
|
[Route("mrb/attach")]
|
||||||
public async Task<IActionResult> DeleteMRBAttachment(MRBAttachment attachment) {
|
public async Task<IActionResult> DeleteMRBAttachment(MRBAttachment attachment) {
|
||||||
@ -702,4 +928,48 @@ public class MRBController : ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("mrb/notify/qa-pre-approver")]
|
||||||
|
public async Task<IActionResult> NotifyQAPreApprover(MRBNotification notification) {
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
bool isArgumentError = false;
|
||||||
|
bool isInternalError = false;
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to notify QA pre approver");
|
||||||
|
|
||||||
|
if (notification is null) throw new ArgumentNullException("MRBNotification cannot be null");
|
||||||
|
if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("Message cannot be null or empty");
|
||||||
|
|
||||||
|
await _mrbService.NotifyQAPreApprover(notification);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
} catch (ArgumentException ex) {
|
||||||
|
isArgumentError = true;
|
||||||
|
errorMessage = ex.Message;
|
||||||
|
return BadRequest(errorMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
isInternalError = true;
|
||||||
|
errorMessage = $"Unable to notify QA pre approver, because {ex.Message}";
|
||||||
|
return Problem(errorMessage);
|
||||||
|
} finally {
|
||||||
|
string metricName = "NotifyQAPreApprover";
|
||||||
|
DateTime end = DateTime.Now;
|
||||||
|
double millisecondsDiff = (end - start).TotalMilliseconds;
|
||||||
|
_monInClient.PostAverage(metricName + "Latency", millisecondsDiff);
|
||||||
|
|
||||||
|
if (isArgumentError) {
|
||||||
|
_logger.LogWarning(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
} else if (isInternalError) {
|
||||||
|
_logger.LogError(errorMessage);
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Critical);
|
||||||
|
} else {
|
||||||
|
_monInClient.PostStatus(metricName, StatusValue.Ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
1126
MesaFabApproval.API/Controllers/PCRBController.cs
Normal file
1126
MesaFabApproval.API/Controllers/PCRBController.cs
Normal file
File diff suppressed because it is too large
Load Diff
9
MesaFabApproval.API/GlobalSuppressions.cs
Normal file
9
MesaFabApproval.API/GlobalSuppressions.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// This file is used by Code Analysis to maintain SuppressMessage
|
||||||
|
// attributes that are applied to this project.
|
||||||
|
// Project-level suppressions either have no target or are given
|
||||||
|
// a specific target and scoped to a namespace, type, member, etc.
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>", Scope = "member", Target = "~M:MesaFabApprovalAPI.Services.AuthenticationService.AuthenticateUser(MesaFabApproval.Shared.Models.AuthAttempt)~System.Threading.Tasks.Task{MesaFabApproval.Shared.Models.LoginResult}")]
|
||||||
|
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>", Scope = "member", Target = "~M:MesaFabApprovalAPI.Services.AuthenticationService.AttemptLocalUserAuth(System.Security.Principal.WindowsIdentity)~System.Threading.Tasks.Task{MesaFabApproval.Shared.Models.LoginResult}")]
|
||||||
@ -1,32 +1,28 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UserSecretsId>0b98e1f2-95ed-4edd-8149-58cce51ca059</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dapper" Version="2.1.35" />
|
<PackageReference Include="Dapper" Version="2.1.35" />
|
||||||
<PackageReference Include="Dapper.Contrib" Version="2.0.78" />
|
<PackageReference Include="Dapper.Contrib" Version="2.0.78" />
|
||||||
<PackageReference Include="dotenv.net" Version="3.1.3" />
|
<PackageReference Include="dotenv.net" Version="3.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
|
||||||
<PackageReference Include="NLog" Version="5.3.2" />
|
<PackageReference Include="NLog" Version="5.2.8" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.11" />
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.8" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.0" />
|
||||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.0" />
|
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MesaFabApproval.Shared\MesaFabApproval.Shared.csproj" />
|
<ProjectReference Include="..\MesaFabApproval.Shared\MesaFabApproval.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System.DirectoryServices.AccountManagement">
|
<Reference Include="System.DirectoryServices.AccountManagement">
|
||||||
<HintPath>..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.DirectoryServices.AccountManagement.dll</HintPath>
|
<HintPath>..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.DirectoryServices.AccountManagement.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
93
MesaFabApproval.API/Models/AppSettings.cs
Normal file
93
MesaFabApproval.API/Models/AppSettings.cs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Models;
|
||||||
|
|
||||||
|
public record AppSettings(string Company,
|
||||||
|
string DbConnectionString,
|
||||||
|
string JwtAudience,
|
||||||
|
string JwtIssuer,
|
||||||
|
string JwtKey,
|
||||||
|
string MrbAttachmentPath,
|
||||||
|
string PcrbAttachmentPath,
|
||||||
|
bool ShouldSendEmail,
|
||||||
|
string SiteBaseUrl,
|
||||||
|
string WorkingDirectoryName) {
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
string result = JsonSerializer.Serialize(this, AppSettingsSourceGenerationContext.Default.AppSettings);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AppSettings Get(IConfigurationRoot configurationRoot) {
|
||||||
|
AppSettings? result;
|
||||||
|
try {
|
||||||
|
#pragma warning disable IL3050, IL2026
|
||||||
|
result = configurationRoot.Get<AppSettings>() ?? throw new Exception();
|
||||||
|
#pragma warning restore IL3050, IL2026
|
||||||
|
} catch (Exception) {
|
||||||
|
List<string> paths = [];
|
||||||
|
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers) {
|
||||||
|
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
|
||||||
|
continue;
|
||||||
|
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
|
||||||
|
continue;
|
||||||
|
paths.Add(physicalFileProvider.Root);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SetEnvironmentVariables(WebApplicationBuilder builder) {
|
||||||
|
builder.Configuration.AddUserSecrets<Program>();
|
||||||
|
AppSettings appSettings = Get(builder.Configuration);
|
||||||
|
Environment.SetEnvironmentVariable("FabApprovalDbConnectionString", appSettings.DbConnectionString);
|
||||||
|
Environment.SetEnvironmentVariable("FabApprovalJwtAudience", appSettings.JwtAudience);
|
||||||
|
Environment.SetEnvironmentVariable("FabApprovalJwtIssuer", appSettings.JwtIssuer);
|
||||||
|
Environment.SetEnvironmentVariable("FabApprovalJwtKey", appSettings.JwtKey);
|
||||||
|
Environment.SetEnvironmentVariable("FabApprovalMrbAttachmentPath", appSettings.MrbAttachmentPath);
|
||||||
|
Environment.SetEnvironmentVariable("FabApprovalPcrbAttachmentPath", appSettings.PcrbAttachmentPath);
|
||||||
|
Environment.SetEnvironmentVariable("FabApprovalShouldSendEmail", appSettings.ShouldSendEmail.ToString());
|
||||||
|
Environment.SetEnvironmentVariable("NewFabApprovalBaseUrl", appSettings.SiteBaseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static AppSettings LoadEnvironmentVariables() {
|
||||||
|
AppSettings result;
|
||||||
|
string dbConnectionString = Environment.GetEnvironmentVariable("FabApprovalDbConnectionString") ??
|
||||||
|
throw new ArgumentNullException("FabApprovalDbConnectionString environment variable not found");
|
||||||
|
string jwtAudience = Environment.GetEnvironmentVariable("FabApprovalJwtAudience") ??
|
||||||
|
throw new ArgumentNullException("FabApprovalJwtAudience environment variable not found");
|
||||||
|
string jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer") ??
|
||||||
|
throw new ArgumentNullException("FabApprovalJwtIssuer environment variable not found");
|
||||||
|
string jwtKey = Environment.GetEnvironmentVariable("FabApprovalJwtKey") ??
|
||||||
|
throw new ArgumentNullException("FabApprovalJwtKey environment variable not found");
|
||||||
|
string mrbAttachmentPath = Environment.GetEnvironmentVariable("FabApprovalMrbAttachmentPath") ??
|
||||||
|
throw new ArgumentNullException("FabApprovalMrbAttachmentPath environment variable not found");
|
||||||
|
string pcrbAttachmentPath = Environment.GetEnvironmentVariable("FabApprovalPcrbAttachmentPath") ??
|
||||||
|
throw new ArgumentNullException("FabApprovalPcrbAttachmentPath environment variable not found");
|
||||||
|
if (!bool.TryParse(Environment.GetEnvironmentVariable("FabApprovalShouldSendEmail"), out bool shouldSendEmail))
|
||||||
|
throw new ArgumentNullException("FabApprovalShouldSendEmail environment variable not found");
|
||||||
|
string siteBaseUrl = Environment.GetEnvironmentVariable("NewFabApprovalBaseUrl") ??
|
||||||
|
throw new ArgumentNullException("FabApprovalBaseUrl environment variable not found");
|
||||||
|
result = new("Infineon Technologies Americas Corp.",
|
||||||
|
DbConnectionString: dbConnectionString,
|
||||||
|
JwtAudience: jwtAudience,
|
||||||
|
JwtIssuer: jwtIssuer,
|
||||||
|
JwtKey: jwtKey,
|
||||||
|
MrbAttachmentPath: mrbAttachmentPath,
|
||||||
|
PcrbAttachmentPath: pcrbAttachmentPath,
|
||||||
|
ShouldSendEmail: shouldSendEmail,
|
||||||
|
SiteBaseUrl: siteBaseUrl,
|
||||||
|
"IFXApps");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||||
|
[JsonSerializable(typeof(AppSettings))]
|
||||||
|
internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext {
|
||||||
|
}
|
||||||
@ -1,16 +1,24 @@
|
|||||||
using MesaFabApproval.Shared.Services;
|
using System.Diagnostics;
|
||||||
using NLog.Web;
|
|
||||||
using MesaFabApprovalAPI.Services;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using dotenv.net;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using MesaFabApproval.API.Services;
|
|
||||||
using NLog.Extensions.Logging;
|
|
||||||
using MesaFabApproval.API.Clients;
|
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using dotenv.net;
|
||||||
|
|
||||||
|
using MesaFabApproval.API.Clients;
|
||||||
|
using MesaFabApproval.API.Services;
|
||||||
|
using MesaFabApproval.Models;
|
||||||
|
using MesaFabApproval.Shared.Services;
|
||||||
|
|
||||||
|
using MesaFabApprovalAPI.Services;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.HttpLogging;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
|
using NLog.Extensions.Logging;
|
||||||
|
using NLog.Web;
|
||||||
|
|
||||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@ -20,14 +28,26 @@ builder.Logging.ClearProviders();
|
|||||||
builder.Logging.SetMinimumLevel(LogLevel.Trace);
|
builder.Logging.SetMinimumLevel(LogLevel.Trace);
|
||||||
builder.Logging.AddNLog();
|
builder.Logging.AddNLog();
|
||||||
|
|
||||||
|
/*builder.Services.AddHttpLogging(o => {
|
||||||
|
o.LoggingFields = HttpLoggingFields.All;
|
||||||
|
o.RequestHeaders.Add("bearer");
|
||||||
|
o.MediaTypeOptions.AddText("application/javascript");
|
||||||
|
o.RequestBodyLogLimit = 4096;
|
||||||
|
o.ResponseBodyLogLimit = 4096;
|
||||||
|
o.CombineLogs = true;
|
||||||
|
});*/
|
||||||
|
|
||||||
builder.Services.AddMemoryCache();
|
builder.Services.AddMemoryCache();
|
||||||
|
|
||||||
string jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer") ??
|
if (Debugger.IsAttached) {
|
||||||
throw new ArgumentNullException("FabApprovalJwtIssuer environment variable not found");
|
string? jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer");
|
||||||
string jwtAudience = Environment.GetEnvironmentVariable("FabApprovalJwtAudience") ??
|
if (string.IsNullOrEmpty(jwtIssuer)) {
|
||||||
throw new ArgumentNullException("FabApprovalJwtAudience environment variable not found");
|
AppSettings.SetEnvironmentVariables(builder);
|
||||||
string jwtKey = Environment.GetEnvironmentVariable("FabApprovalJwtKey") ??
|
}
|
||||||
throw new ArgumentNullException("FabApprovalJwtKey environment variable not found");
|
}
|
||||||
|
|
||||||
|
AppSettings appSettings = AppSettings.LoadEnvironmentVariables();
|
||||||
|
builder.Services.AddSingleton(_ => appSettings);
|
||||||
|
|
||||||
builder.Services.AddAuthentication(options => {
|
builder.Services.AddAuthentication(options => {
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
@ -38,9 +58,9 @@ builder.Services.AddAuthentication(options => {
|
|||||||
options.SaveToken = true;
|
options.SaveToken = true;
|
||||||
options.TokenValidationParameters = new TokenValidationParameters {
|
options.TokenValidationParameters = new TokenValidationParameters {
|
||||||
ValidateIssuerSigningKey = true,
|
ValidateIssuerSigningKey = true,
|
||||||
ValidIssuer = jwtIssuer,
|
ValidIssuer = appSettings.JwtIssuer,
|
||||||
ValidateAudience = false,
|
ValidateAudience = false,
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)),
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.JwtKey)),
|
||||||
ClockSkew = TimeSpan.Zero
|
ClockSkew = TimeSpan.Zero
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -54,21 +74,34 @@ builder.Services.AddAuthorization(options => {
|
|||||||
|
|
||||||
builder.Services.AddHttpClient();
|
builder.Services.AddHttpClient();
|
||||||
|
|
||||||
|
builder.Services.AddCors(options => {
|
||||||
|
options.AddDefaultPolicy(options => {
|
||||||
|
options.AllowAnyOrigin();
|
||||||
|
options.AllowAnyMethod();
|
||||||
|
options.AllowAnyHeader();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddScoped<IDbConnectionService, DbConnectionService>();
|
builder.Services.AddScoped<IDbConnectionService, DbConnectionService>();
|
||||||
builder.Services.AddScoped<IDalService, DalService>();
|
builder.Services.AddScoped<IDalService, DalService>();
|
||||||
builder.Services.AddScoped<SmtpClient>((serviceProvider) => {
|
builder.Services.AddScoped<SmtpClient>((serviceProvider) => {
|
||||||
return new SmtpClient("mailrelay-external.infineon.com");
|
return new SmtpClient("mailrelay-external.infineon.com");
|
||||||
});
|
});
|
||||||
builder.Services.AddScoped<ISmtpClientWrapper, SmtpClientWrapper>();
|
builder.Services.AddScoped<ISmtpClientWrapper, SmtpClientWrapper>();
|
||||||
|
builder.Services.AddScoped<ICustomerService, CustomerService>();
|
||||||
|
builder.Services.AddScoped<ICAService, CAService>();
|
||||||
|
builder.Services.AddScoped<IECNService, ECNService>();
|
||||||
builder.Services.AddScoped<ISmtpService, SmtpService>();
|
builder.Services.AddScoped<ISmtpService, SmtpService>();
|
||||||
builder.Services.AddScoped<IUserService, UserService>();
|
builder.Services.AddScoped<IUserService, UserService>();
|
||||||
builder.Services.AddScoped<IMonInWorkerClient, MonInWorkerClient>();
|
builder.Services.AddScoped<IMonInWorkerClient, MonInWorkerClient>();
|
||||||
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
||||||
builder.Services.AddScoped<IMRBService, MRBService>();
|
builder.Services.AddScoped<IMRBService, MRBService>();
|
||||||
|
builder.Services.AddScoped<IPCRBService, PCRBService>();
|
||||||
builder.Services.AddScoped<IApprovalService, ApprovalService>();
|
builder.Services.AddScoped<IApprovalService, ApprovalService>();
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen(c => {
|
builder.Services.AddSwaggerGen(c => {
|
||||||
c.SwaggerDoc("v1", new OpenApiInfo {
|
c.SwaggerDoc("v1", new OpenApiInfo {
|
||||||
@ -95,28 +128,22 @@ builder.Services.AddSwaggerGen(c => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
builder.Services.AddCors(options => {
|
|
||||||
options.AddDefaultPolicy(
|
|
||||||
builder => {
|
|
||||||
builder.AllowAnyOrigin()
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowAnyMethod();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
WebApplication app = builder.Build();
|
WebApplication app = builder.Build();
|
||||||
|
|
||||||
|
if (Debugger.IsAttached)
|
||||||
|
app.Services.GetRequiredService<IApprovalService>();
|
||||||
|
|
||||||
app.UseCors();
|
app.UseCors();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment()) {
|
||||||
{
|
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
// app.UseHttpLogging();
|
||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
|
|
||||||
@ -125,3 +152,6 @@ app.UseAuthorization();
|
|||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
|
NLog.LogManager.Flush();
|
||||||
|
NLog.LogManager.Shutdown();
|
||||||
@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
-->
|
-->
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<DeleteExistingFiles>false</DeleteExistingFiles>
|
<DeleteExistingFiles>true</DeleteExistingFiles>
|
||||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||||
@ -18,5 +18,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<ProjectGuid>852e528d-015a-43b5-999d-f281e3359e5e</ProjectGuid>
|
<ProjectGuid>852e528d-015a-43b5-999d-f281e3359e5e</ProjectGuid>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -1,7 +1,7 @@
|
|||||||
using System.Net.Mail;
|
using System.Text;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ public class ApprovalService : IApprovalService {
|
|||||||
queryBuilder.Append("insert into Approval (IssueID, RoleName, SubRole, UserID, SubRoleID, ItemStatus, ");
|
queryBuilder.Append("insert into Approval (IssueID, RoleName, SubRole, UserID, SubRoleID, ItemStatus, ");
|
||||||
queryBuilder.Append("AssignedDate, DocumentTypeID, DisplayDeniedDocument, Step, TaskID) ");
|
queryBuilder.Append("AssignedDate, DocumentTypeID, DisplayDeniedDocument, Step, TaskID) ");
|
||||||
queryBuilder.Append($"values ({approval.IssueID}, '{approval.RoleName}', '{approval.SubRole}', {approval.UserID}, ");
|
queryBuilder.Append($"values ({approval.IssueID}, '{approval.RoleName}', '{approval.SubRole}', {approval.UserID}, ");
|
||||||
queryBuilder.Append($"{approval.SubRoleID}, 0, '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"{approval.SubRoleID}, 0, '{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"3, 0, {approval.Step}, {approval.TaskID});");
|
queryBuilder.Append($"3, 0, {approval.Step}, {approval.TaskID});");
|
||||||
|
|
||||||
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
@ -145,7 +145,7 @@ public class ApprovalService : IApprovalService {
|
|||||||
StringBuilder queryBuilder = new();
|
StringBuilder queryBuilder = new();
|
||||||
queryBuilder.Append("select src.SubRoleCategoryID, sr.SubRole as SubRoleName, src.SubRoleCategoryItem, sr.SubRoleID ");
|
queryBuilder.Append("select src.SubRoleCategoryID, sr.SubRole as SubRoleName, src.SubRoleCategoryItem, sr.SubRoleID ");
|
||||||
queryBuilder.Append("from SubRole sr join SubRoleCategory src on sr.SubRoleCategoryID=src.SubRoleCategoryID ");
|
queryBuilder.Append("from SubRole sr join SubRoleCategory src on sr.SubRoleCategoryID=src.SubRoleCategoryID ");
|
||||||
queryBuilder.Append($"where sr.RoleID={roleId} and sr.SubRole='{subRoleName}'");
|
queryBuilder.Append($"where sr.RoleID={roleId} and sr.SubRole='{subRoleName}' and sr.Inactive=0");
|
||||||
|
|
||||||
subRoles = (await _dalService.QueryAsync<SubRole>(queryBuilder.ToString())).ToList();
|
subRoles = (await _dalService.QueryAsync<SubRole>(queryBuilder.ToString())).ToList();
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ public class ApprovalService : IApprovalService {
|
|||||||
if (memberIds is null || memberIds.Count() <= 0)
|
if (memberIds is null || memberIds.Count() <= 0)
|
||||||
throw new Exception($"No members found in sub role {subRoleId}");
|
throw new Exception($"No members found in sub role {subRoleId}");
|
||||||
|
|
||||||
_cache.Set($"approvalMemberIds{subRoleId}", memberIds, DateTimeOffset.Now.AddHours(1));
|
_cache.Set($"approvalMemberIds{subRoleId}", memberIds, DateTimeOffset.Now.AddMinutes(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
members = new();
|
members = new();
|
||||||
@ -194,7 +194,7 @@ public class ApprovalService : IApprovalService {
|
|||||||
|
|
||||||
if (members.Count() <= 0) throw new Exception("No users found with IDs matching those found in SubRole");
|
if (members.Count() <= 0) throw new Exception("No users found with IDs matching those found in SubRole");
|
||||||
|
|
||||||
_cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddHours(1));
|
_cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddMinutes(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
return members;
|
return members;
|
||||||
@ -246,12 +246,10 @@ public class ApprovalService : IApprovalService {
|
|||||||
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
||||||
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
||||||
queryBuilder.Append($"ItemStatus={Convert.ToInt32(approval.ItemStatus)}, Step={approval.Step}, ");
|
queryBuilder.Append($"ItemStatus={Convert.ToInt32(approval.ItemStatus)}, Step={approval.Step}, ");
|
||||||
if (approval.NotifyDate > DateTime.MinValue)
|
|
||||||
queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
if (approval.CompletedDate < DateTime.MaxValue)
|
|
||||||
queryBuilder.Append($"CompletedDate='{approval.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"CompletedDate='{approval.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"Comments='{approval.Comments}', ");
|
queryBuilder.Append($"Comments='{approval.Comments.Replace("'", "''")}', ");
|
||||||
queryBuilder.Append($"TaskID={approval.TaskID} ");
|
queryBuilder.Append($"TaskID={approval.TaskID} ");
|
||||||
queryBuilder.Append($"where ApprovalID={approval.ApprovalID};");
|
queryBuilder.Append($"where ApprovalID={approval.ApprovalID};");
|
||||||
|
|
||||||
@ -274,7 +272,8 @@ public class ApprovalService : IApprovalService {
|
|||||||
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
||||||
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
||||||
queryBuilder.Append($"ItemStatus=1, Step={approval.Step}, ");
|
queryBuilder.Append($"ItemStatus=1, Step={approval.Step}, ");
|
||||||
if (approval.NotifyDate > DateTime.MinValue)
|
if (approval.NotifyDate < DateTimeUtilities.MIN_DT)
|
||||||
|
approval.NotifyDate = DateTimeUtilities.MIN_DT;
|
||||||
queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
@ -301,7 +300,8 @@ public class ApprovalService : IApprovalService {
|
|||||||
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
||||||
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
||||||
queryBuilder.Append($"ItemStatus=-1, Step={approval.Step}, ");
|
queryBuilder.Append($"ItemStatus=-1, Step={approval.Step}, ");
|
||||||
if (approval.NotifyDate > DateTime.MinValue)
|
if (approval.NotifyDate < DateTimeUtilities.MIN_DT)
|
||||||
|
approval.NotifyDate = DateTimeUtilities.MIN_DT;
|
||||||
queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
|
|||||||
@ -3,9 +3,11 @@ using System.IdentityModel.Tokens.Jwt;
|
|||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Principal;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
using MesaFabApproval.API.Services;
|
using MesaFabApproval.API.Services;
|
||||||
|
using MesaFabApproval.Models;
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
@ -15,6 +17,7 @@ namespace MesaFabApprovalAPI.Services;
|
|||||||
|
|
||||||
public interface IAuthenticationService {
|
public interface IAuthenticationService {
|
||||||
public Task<LoginResult> AuthenticateUser(AuthAttempt login);
|
public Task<LoginResult> AuthenticateUser(AuthAttempt login);
|
||||||
|
public Task<LoginResult> AttemptLocalUserAuth(WindowsIdentity identity);
|
||||||
public AuthTokens GenerateAuthTokens(AuthAttempt authAttempt, IEnumerable<string> roles);
|
public AuthTokens GenerateAuthTokens(AuthAttempt authAttempt, IEnumerable<string> roles);
|
||||||
public Task<LoginResult> RefreshAuthTokens(AuthAttempt authAttempt);
|
public Task<LoginResult> RefreshAuthTokens(AuthAttempt authAttempt);
|
||||||
}
|
}
|
||||||
@ -28,17 +31,13 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
private readonly string _jwtAudience;
|
private readonly string _jwtAudience;
|
||||||
private readonly string _jwtKey;
|
private readonly string _jwtKey;
|
||||||
|
|
||||||
public AuthenticationService(ILogger<AuthenticationService> logger, IMemoryCache cache, IUserService userService) {
|
public AuthenticationService(ILogger<AuthenticationService> logger, IMemoryCache cache, IUserService userService, AppSettings appSettings) {
|
||||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
||||||
|
_jwtKey = appSettings.JwtKey;
|
||||||
_jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer") ??
|
_jwtIssuer = appSettings.JwtIssuer;
|
||||||
throw new ArgumentNullException("FabApprovalJwtIssuer environment variable not found");
|
_jwtAudience = appSettings.JwtAudience;
|
||||||
_jwtAudience = Environment.GetEnvironmentVariable("FabApprovalJwtAudience") ??
|
|
||||||
throw new ArgumentNullException("FabApprovalJwtAudience environment variable not found");
|
|
||||||
_jwtKey = Environment.GetEnvironmentVariable("FabApprovalJwtKey") ??
|
|
||||||
throw new ArgumentNullException("FabApprovalJwtKey environment variable not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<LoginResult> AuthenticateUser(AuthAttempt login) {
|
public async Task<LoginResult> AuthenticateUser(AuthAttempt login) {
|
||||||
@ -68,8 +67,6 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
|
|
||||||
AuthTokens tokens = GenerateAuthTokens(login, roles);
|
AuthTokens tokens = GenerateAuthTokens(login, roles);
|
||||||
|
|
||||||
_cache.Set<string>(login.LoginID, tokens.RefreshToken);
|
|
||||||
|
|
||||||
return new LoginResult {
|
return new LoginResult {
|
||||||
IsAuthenticated = true,
|
IsAuthenticated = true,
|
||||||
AuthTokens = tokens,
|
AuthTokens = tokens,
|
||||||
@ -92,6 +89,36 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<LoginResult> AttemptLocalUserAuth(WindowsIdentity identity) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to authenticate local Windows system user");
|
||||||
|
|
||||||
|
if (identity is null) throw new ArgumentNullException("WindowsIdentity cannot be null");
|
||||||
|
|
||||||
|
User user = await _userService.GetUserByLoginId(identity.Name);
|
||||||
|
|
||||||
|
List<string> roles = new();
|
||||||
|
|
||||||
|
if (user.IsManager) roles.Add("manager");
|
||||||
|
if (user.IsAdmin) roles.Add("admin");
|
||||||
|
|
||||||
|
AuthAttempt authAttempt = new() {
|
||||||
|
LoginID = user.LoginID,
|
||||||
|
};
|
||||||
|
|
||||||
|
AuthTokens tokens = GenerateAuthTokens(authAttempt, roles);
|
||||||
|
|
||||||
|
return new LoginResult {
|
||||||
|
IsAuthenticated = true,
|
||||||
|
AuthTokens = tokens,
|
||||||
|
User = user
|
||||||
|
};
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to authenticate local Windows system user, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AuthTokens GenerateAuthTokens(AuthAttempt authAttempt, IEnumerable<string> roles) {
|
public AuthTokens GenerateAuthTokens(AuthAttempt authAttempt, IEnumerable<string> roles) {
|
||||||
try {
|
try {
|
||||||
_logger.LogInformation("Attempting to generate JWT");
|
_logger.LogInformation("Attempting to generate JWT");
|
||||||
@ -117,7 +144,7 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
Audience = _jwtAudience,
|
Audience = _jwtAudience,
|
||||||
Subject = identity,
|
Subject = identity,
|
||||||
NotBefore = DateTime.Now,
|
NotBefore = DateTime.Now,
|
||||||
Expires = DateTime.Now.AddMinutes(5),
|
Expires = DateTime.Now.AddHours(8),
|
||||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,6 +156,18 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
|
|
||||||
string refreshToken = GenerateRefreshToken();
|
string refreshToken = GenerateRefreshToken();
|
||||||
|
|
||||||
|
List<string>? refreshTokensForUser = _cache.Get<List<string>>(authAttempt.LoginID);
|
||||||
|
|
||||||
|
if (refreshTokensForUser is null)
|
||||||
|
refreshTokensForUser = new List<string>();
|
||||||
|
|
||||||
|
if (refreshTokensForUser.Count > 9)
|
||||||
|
refreshTokensForUser.RemoveRange(9, refreshTokensForUser.Count - 9);
|
||||||
|
|
||||||
|
refreshTokensForUser.Insert(0, refreshToken);
|
||||||
|
|
||||||
|
_cache.Set<List<string>>(authAttempt.LoginID, refreshTokensForUser, DateTimeOffset.Now.AddHours(4));
|
||||||
|
|
||||||
return new AuthTokens {
|
return new AuthTokens {
|
||||||
JwtToken = jwt,
|
JwtToken = jwt,
|
||||||
RefreshToken = refreshToken
|
RefreshToken = refreshToken
|
||||||
@ -164,8 +203,6 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
|
|
||||||
AuthTokens refreshedTokens = GenerateAuthTokens(authAttempt, roles);
|
AuthTokens refreshedTokens = GenerateAuthTokens(authAttempt, roles);
|
||||||
|
|
||||||
_cache.Set<string>(authAttempt.LoginID, refreshedTokens.RefreshToken, DateTimeOffset.Now.AddHours(1));
|
|
||||||
|
|
||||||
LoginResult loginResult = new LoginResult() {
|
LoginResult loginResult = new LoginResult() {
|
||||||
IsAuthenticated = true,
|
IsAuthenticated = true,
|
||||||
AuthTokens = refreshedTokens,
|
AuthTokens = refreshedTokens,
|
||||||
@ -198,13 +235,14 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
if (string.IsNullOrWhiteSpace(refreshToken))
|
if (string.IsNullOrWhiteSpace(refreshToken))
|
||||||
throw new ArgumentNullException("Refresh token cannot be null or empty");
|
throw new ArgumentNullException("Refresh token cannot be null or empty");
|
||||||
|
|
||||||
string? cachedRefreshToken = _cache.Get<string>(loginId);
|
List<string>? cachedRefreshTokensForUser = _cache.Get<List<string>>(loginId);
|
||||||
|
|
||||||
if (cachedRefreshToken is null) return false;
|
|
||||||
|
|
||||||
if (cachedRefreshToken.Equals(refreshToken)) return true;
|
|
||||||
|
|
||||||
|
if (cachedRefreshTokensForUser is null || !cachedRefreshTokensForUser.Contains(refreshToken)) {
|
||||||
|
_logger.LogInformation($"Could not find cached refresh tokens for user {loginId}");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
_logger.LogError($"An exception occurred when attempting to validate refresh token. Exception: {ex.Message}");
|
_logger.LogError($"An exception occurred when attempting to validate refresh token. Exception: {ex.Message}");
|
||||||
throw;
|
throw;
|
||||||
|
|||||||
46
MesaFabApproval.API/Services/CAService.cs
Normal file
46
MesaFabApproval.API/Services/CAService.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Services;
|
||||||
|
|
||||||
|
public interface ICAService {
|
||||||
|
Task<bool> IsValidCANumber(int number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CAService : ICAService {
|
||||||
|
private readonly ILogger<CAService> _logger;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly IDalService _dalService;
|
||||||
|
|
||||||
|
public CAService(ILogger<CAService> logger, IMemoryCache cache, IDalService dalService) {
|
||||||
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
|
_dalService = dalService ?? throw new ArgumentNullException("IDalService not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsValidCANumber(int number) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to determine if {number} is a valid CA#");
|
||||||
|
|
||||||
|
if (number <= 0) return false;
|
||||||
|
|
||||||
|
IEnumerable<int> caNumbers = _cache.Get<IEnumerable<int>>("caNumbers") ?? new HashSet<int>();
|
||||||
|
|
||||||
|
if (caNumbers.Contains(number)) return true;
|
||||||
|
|
||||||
|
string sql = $"select count(CANo) as count from _8DCorrectiveAction where CANo={number}";
|
||||||
|
|
||||||
|
int rowsReturned = (await _dalService.QueryAsync<int>(sql)).FirstOrDefault();
|
||||||
|
|
||||||
|
if (rowsReturned > 0) {
|
||||||
|
caNumbers.Append(number);
|
||||||
|
_cache.Set("caNumbers", caNumbers);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to determine if {number} is a valid CA#, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
MesaFabApproval.API/Services/CustomerService.cs
Normal file
38
MesaFabApproval.API/Services/CustomerService.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Services;
|
||||||
|
|
||||||
|
public interface ICustomerService {
|
||||||
|
Task<IEnumerable<string>> GetCustomerNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomerService : ICustomerService {
|
||||||
|
private readonly ILogger<CustomerService> _logger;
|
||||||
|
private readonly IDalService _dalService;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
|
||||||
|
public CustomerService(ILogger<CustomerService> logger, IDalService dalService, IMemoryCache cache) {
|
||||||
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
|
_dalService = dalService ?? throw new ArgumentNullException("IDalService not injected");
|
||||||
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<string>> GetCustomerNames() {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to get customer names");
|
||||||
|
|
||||||
|
IEnumerable<string>? customerNames = _cache.Get<IEnumerable<string>>("allCustomerNames");
|
||||||
|
|
||||||
|
if (customerNames is null) {
|
||||||
|
string sql = "select ProductFamily from ProductFamilies;";
|
||||||
|
|
||||||
|
customerNames = (await _dalService.QueryAsync<string>(sql)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return customerNames;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get customer names, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
|
|
||||||
|
using MesaFabApproval.Models;
|
||||||
|
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
namespace MesaFabApproval.API.Services;
|
namespace MesaFabApproval.API.Services;
|
||||||
@ -11,12 +13,10 @@ public interface IDbConnectionService {
|
|||||||
public class DbConnectionService : IDbConnectionService {
|
public class DbConnectionService : IDbConnectionService {
|
||||||
private readonly string _dbConnectionString;
|
private readonly string _dbConnectionString;
|
||||||
|
|
||||||
public DbConnectionService() {
|
public DbConnectionService(AppSettings appSettings) {
|
||||||
_dbConnectionString = Environment.GetEnvironmentVariable("FabApprovalDbConnectionString") ??
|
_dbConnectionString = appSettings.DbConnectionString;
|
||||||
throw new ArgumentNullException("FabApprovalDbConnectionString environment variable not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDbConnection GetConnection() {
|
public IDbConnection GetConnection() =>
|
||||||
return new SqlConnection(_dbConnectionString);
|
new SqlConnection(_dbConnectionString);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
46
MesaFabApproval.API/Services/ECNService.cs
Normal file
46
MesaFabApproval.API/Services/ECNService.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Services;
|
||||||
|
|
||||||
|
public interface IECNService {
|
||||||
|
Task<bool> IsValidECNNumber(int number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ECNService : IECNService {
|
||||||
|
private readonly ILogger<ECNService> _logger;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly IDalService _dalService;
|
||||||
|
|
||||||
|
public ECNService(ILogger<ECNService> logger, IMemoryCache cache, IDalService dalService) {
|
||||||
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
|
_dalService = dalService ?? throw new ArgumentNullException("IDalService not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsValidECNNumber(int number) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to determine if {number} is a valid ECN#");
|
||||||
|
|
||||||
|
if (number <= 0) return false;
|
||||||
|
|
||||||
|
IEnumerable<int> ecnNumbers = _cache.Get<IEnumerable<int>>("ecnNumbers") ?? new HashSet<int>();
|
||||||
|
|
||||||
|
if (ecnNumbers.Contains(number)) return true;
|
||||||
|
|
||||||
|
string sql = $"select count(ECNNumber) as count from ECN where ECNNumber={number}";
|
||||||
|
|
||||||
|
int rowsReturned = (await _dalService.QueryAsync<int>(sql)).FirstOrDefault();
|
||||||
|
|
||||||
|
if (rowsReturned > 0) {
|
||||||
|
ecnNumbers.Append(number);
|
||||||
|
_cache.Set("ecnNumbers", ecnNumbers);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to determine if {number} is a valid ECN#, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,21 @@
|
|||||||
using System.Net;
|
using System.Data;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
using MesaFabApproval.API.Utilities;
|
||||||
|
using MesaFabApproval.Models;
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
namespace MesaFabApproval.API.Services;
|
namespace MesaFabApproval.API.Services;
|
||||||
|
|
||||||
public interface IMRBService {
|
public interface IMRBService {
|
||||||
Task<IEnumerable<MRB>> GetAllMRBs();
|
Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache);
|
||||||
Task<MRB> GetMRBById(int id);
|
Task<bool> MRBNumberIsValid(int number);
|
||||||
|
Task<MRB> GetMRBById(int id, bool bypassCache = false);
|
||||||
Task<MRB> GetMRBByTitle(string title, bool bypassCache);
|
Task<MRB> GetMRBByTitle(string title, bool bypassCache);
|
||||||
Task CreateNewMRB(MRB mrb);
|
Task CreateNewMRB(MRB mrb);
|
||||||
Task UpdateMRB(MRB mrb);
|
Task UpdateMRB(MRB mrb);
|
||||||
@ -19,11 +24,16 @@ public interface IMRBService {
|
|||||||
Task UpdateMRBAction(MRBAction mrbAction);
|
Task UpdateMRBAction(MRBAction mrbAction);
|
||||||
Task DeleteMRBAction(int mrbActionID, int mrbNumber);
|
Task DeleteMRBAction(int mrbActionID, int mrbNumber);
|
||||||
Task<IEnumerable<UploadResult>> UploadAttachments(IEnumerable<IFormFile> files, int mrbNumber);
|
Task<IEnumerable<UploadResult>> UploadAttachments(IEnumerable<IFormFile> files, int mrbNumber);
|
||||||
|
Task<IEnumerable<UploadResult>> UploadActionAttachments(IEnumerable<IFormFile> files, int actionId);
|
||||||
Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
||||||
|
Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
||||||
Task DeleteAttachment(MRBAttachment attachment);
|
Task DeleteAttachment(MRBAttachment attachment);
|
||||||
Task NotifyNewApprovals(MRB mrb);
|
Task NotifyNewApprovals(MRB mrb);
|
||||||
Task NotifyApprovers(MRBNotification notification);
|
Task NotifyApprovers(MRBNotification notification);
|
||||||
Task NotifyOriginator(MRBNotification notification);
|
Task NotifyOriginator(MRBNotification notification);
|
||||||
|
Task NotifyQAPreApprover(MRBNotification notification);
|
||||||
|
Task DeleteMRB(int mrbNumber);
|
||||||
|
Task ConvertActionsToCsvFile(int mrbNumber, string path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MRBService : IMRBService {
|
public class MRBService : IMRBService {
|
||||||
@ -42,17 +52,16 @@ public class MRBService : IMRBService {
|
|||||||
IMemoryCache cache,
|
IMemoryCache cache,
|
||||||
IUserService userService,
|
IUserService userService,
|
||||||
IApprovalService approvalService,
|
IApprovalService approvalService,
|
||||||
ISmtpService smtpService) {
|
ISmtpService smtpService,
|
||||||
|
AppSettings appSettings) {
|
||||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
_dalService = dalService ?? throw new ArgumentNullException("IDalService not injected");
|
_dalService = dalService ?? throw new ArgumentNullException("IDalService not injected");
|
||||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
||||||
_approvalService = approvalService ?? throw new ArgumentNullException("IApprovalService not injected");
|
_approvalService = approvalService ?? throw new ArgumentNullException("IApprovalService not injected");
|
||||||
_smtpService = smtpService ?? throw new ArgumentNullException("ISmtpService not injected");
|
_smtpService = smtpService ?? throw new ArgumentNullException("ISmtpService not injected");
|
||||||
_siteBaseUrl = Environment.GetEnvironmentVariable("NewFabApprovalBaseUrl") ??
|
_siteBaseUrl = appSettings.SiteBaseUrl;
|
||||||
throw new ArgumentNullException("FabApprovalBaseUrl environment variable not found");
|
_mrbAttachmentPath = appSettings.MrbAttachmentPath;
|
||||||
_mrbAttachmentPath = Environment.GetEnvironmentVariable("FabApprovalMrbAttachmentPath") ??
|
|
||||||
throw new ArgumentNullException("FabApprovalMrbAttachmentPath environment variable not found");
|
|
||||||
}
|
}
|
||||||
public async Task CreateNewMRB(MRB mrb) {
|
public async Task CreateNewMRB(MRB mrb) {
|
||||||
try {
|
try {
|
||||||
@ -61,28 +70,30 @@ public class MRBService : IMRBService {
|
|||||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||||
|
|
||||||
StringBuilder queryBuilder = new();
|
StringBuilder queryBuilder = new();
|
||||||
queryBuilder.Append("insert into MRB (OriginatorID, Title, ");
|
queryBuilder.Append("insert into MRB (OriginatorID, Title, SubmittedDate, ");
|
||||||
if (mrb.SubmittedDate > DateTime.MinValue) queryBuilder.Append("SubmittedDate, ");
|
queryBuilder.Append("CloseDate, CancelDate, NumberOfLotsAffected, ApprovalDate, ");
|
||||||
if (mrb.CloseDate < DateTime.MaxValue) queryBuilder.Append("CloseDate, ");
|
|
||||||
if (mrb.CancelDate < DateTime.MaxValue) queryBuilder.Append("CancelDate, ");
|
|
||||||
queryBuilder.Append("NumberOfLotsAffected, ");
|
|
||||||
if (mrb.ApprovalDate < DateTime.MaxValue) queryBuilder.Append("ApprovalDate, ");
|
|
||||||
queryBuilder.Append("IssueDescription, CustomerImpacted, Department, Process, Val, RMANo, ");
|
queryBuilder.Append("IssueDescription, CustomerImpacted, Department, Process, Val, RMANo, ");
|
||||||
queryBuilder.Append("PCRBNo, SpecsImpacted, TrainingRequired, Status, StageNo) values (");
|
queryBuilder.Append("PCRBNo, SpecsImpacted, TrainingRequired, Status, StageNo, ");
|
||||||
|
queryBuilder.Append("CustomerImpactedName, ProcessECNNumber, Tool, Category) values (");
|
||||||
queryBuilder.Append($"{mrb.OriginatorID}, '{mrb.Title}', ");
|
queryBuilder.Append($"{mrb.OriginatorID}, '{mrb.Title}', ");
|
||||||
if (mrb.SubmittedDate > DateTime.MinValue)
|
if (mrb.SubmittedDate < DateTimeUtilities.MIN_DT)
|
||||||
|
mrb.SubmittedDate = DateTimeUtilities.MIN_DT;
|
||||||
queryBuilder.Append($"'{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"'{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
if (mrb.CloseDate < DateTime.MaxValue)
|
if (mrb.CloseDate > DateTimeUtilities.MAX_DT)
|
||||||
|
mrb.CloseDate = DateTimeUtilities.MAX_DT;
|
||||||
queryBuilder.Append($"'{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"'{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
if (mrb.CancelDate < DateTime.MaxValue)
|
if (mrb.CancelDate > DateTimeUtilities.MAX_DT)
|
||||||
|
mrb.CancelDate = DateTimeUtilities.MAX_DT;
|
||||||
queryBuilder.Append($"'{mrb.CancelDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"'{mrb.CancelDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"{mrb.NumberOfLotsAffected}, ");
|
queryBuilder.Append($"{mrb.NumberOfLotsAffected}, ");
|
||||||
if (mrb.ApprovalDate < DateTime.MaxValue)
|
if (mrb.ApprovalDate > DateTimeUtilities.MAX_DT)
|
||||||
|
mrb.ApprovalDate = DateTimeUtilities.MAX_DT;
|
||||||
queryBuilder.Append($"'{mrb.ApprovalDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"'{mrb.ApprovalDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"'{mrb.IssueDescription}', {Convert.ToUInt32(mrb.CustomerImpacted)}, ");
|
queryBuilder.Append($"'{mrb.IssueDescription}', {Convert.ToUInt32(mrb.CustomerImpacted)}, ");
|
||||||
queryBuilder.Append($"'{mrb.Department}', '{mrb.Process}', '{mrb.Val}', {mrb.RMANo}, {mrb.PCRBNo}, ");
|
queryBuilder.Append($"'{mrb.Department}', '{mrb.Process}', {mrb.Val}, {mrb.RMANo}, '{mrb.PCRBNo}', ");
|
||||||
queryBuilder.Append($"{Convert.ToInt32(mrb.SpecsImpacted)}, {Convert.ToInt32(mrb.TrainingRequired)}, ");
|
queryBuilder.Append($"{Convert.ToInt32(mrb.SpecsImpacted)}, {Convert.ToInt32(mrb.TrainingRequired)}, ");
|
||||||
queryBuilder.Append($"'{mrb.Status}', {mrb.StageNo});");
|
queryBuilder.Append($"'{mrb.Status}', {mrb.StageNo}, '{mrb.CustomerImpactedName}', ");
|
||||||
|
queryBuilder.Append($"{mrb.ProcessECNNumber}, '{mrb.Tool}', '{mrb.Category}');");
|
||||||
|
|
||||||
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
@ -105,11 +116,12 @@ public class MRBService : IMRBService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<MRB>> GetAllMRBs() {
|
public async Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache) {
|
||||||
try {
|
try {
|
||||||
_logger.LogInformation("Attempting to get all MRBs");
|
_logger.LogInformation("Attempting to get all MRBs");
|
||||||
|
|
||||||
IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
IEnumerable<MRB>? allMrbs = null;
|
||||||
|
if (!bypassCache) allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||||
|
|
||||||
if (allMrbs is null) {
|
if (allMrbs is null) {
|
||||||
StringBuilder queryBuilder = new();
|
StringBuilder queryBuilder = new();
|
||||||
@ -121,9 +133,6 @@ public class MRBService : IMRBService {
|
|||||||
_cache.Set("allMrbs", allMrbs, DateTimeOffset.Now.AddHours(1));
|
_cache.Set("allMrbs", allMrbs, DateTimeOffset.Now.AddHours(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allMrbs is null || allMrbs.Count() == 0)
|
|
||||||
throw new Exception("No MRBs found");
|
|
||||||
|
|
||||||
return allMrbs;
|
return allMrbs;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
_logger.LogError($"An exception occurred when attempting to get all MRBs. Exception: {ex.Message}");
|
_logger.LogError($"An exception occurred when attempting to get all MRBs. Exception: {ex.Message}");
|
||||||
@ -131,13 +140,43 @@ public class MRBService : IMRBService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<MRB> GetMRBById(int id) {
|
public async Task<bool> MRBNumberIsValid(int number) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to determine if {number} is a valid MRB#");
|
||||||
|
|
||||||
|
if (number <= 0) return false;
|
||||||
|
|
||||||
|
IEnumerable<int> mrbNumbers = _cache.Get<IEnumerable<int>>("mrbNumbers") ??
|
||||||
|
new HashSet<int>();
|
||||||
|
|
||||||
|
if (mrbNumbers.Contains(number)) return true;
|
||||||
|
|
||||||
|
string sql = $"select count(MRBNumber) as count from MRB where MRBNumber={number}";
|
||||||
|
|
||||||
|
int rowsReturned = (await _dalService.QueryAsync<int>(sql)).FirstOrDefault();
|
||||||
|
|
||||||
|
if (rowsReturned > 0) {
|
||||||
|
mrbNumbers.Append(number);
|
||||||
|
_cache.Set("mrbNumbers", mrbNumbers);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to determine if {number} is a valid MRB#, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MRB> GetMRBById(int id, bool bypassCache = false) {
|
||||||
try {
|
try {
|
||||||
_logger.LogInformation("Attempting to get an MRB by ID");
|
_logger.LogInformation("Attempting to get an MRB by ID");
|
||||||
|
|
||||||
if (id < 0) throw new ArgumentException("Invalid MRB number");
|
if (id < 0) throw new ArgumentException("Invalid MRB number");
|
||||||
|
|
||||||
MRB? mrb = _cache.Get<MRB>($"mrb{id}");
|
MRB? mrb = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
mrb = _cache.Get<MRB>($"mrb{id}");
|
||||||
|
|
||||||
if (mrb is null) {
|
if (mrb is null) {
|
||||||
StringBuilder queryBuilder = new();
|
StringBuilder queryBuilder = new();
|
||||||
@ -163,7 +202,7 @@ public class MRBService : IMRBService {
|
|||||||
try {
|
try {
|
||||||
_logger.LogInformation("Attempting to get an MRB by title");
|
_logger.LogInformation("Attempting to get an MRB by title");
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or emtpy");
|
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||||
|
|
||||||
MRB? mrb = null;
|
MRB? mrb = null;
|
||||||
|
|
||||||
@ -197,26 +236,33 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
StringBuilder queryBuilder = new();
|
StringBuilder queryBuilder = new();
|
||||||
queryBuilder.Append($"update MRB set OriginatorID = {mrb.OriginatorID}, ");
|
queryBuilder.Append($"update MRB set OriginatorID = {mrb.OriginatorID}, ");
|
||||||
queryBuilder.Append($"Title = '{mrb.Title}', ");
|
queryBuilder.Append($"Title = '{mrb.Title.Replace("'", "''")}', ");
|
||||||
if (mrb.SubmittedDate > DateTime.MinValue)
|
if (mrb.SubmittedDate < DateTimeUtilities.MIN_DT)
|
||||||
|
mrb.SubmittedDate = DateTimeUtilities.MIN_DT;
|
||||||
queryBuilder.Append($"SubmittedDate = '{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"SubmittedDate = '{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
if (mrb.CloseDate < DateTime.MaxValue)
|
if (mrb.CloseDate > DateTimeUtilities.MAX_DT)
|
||||||
|
mrb.CloseDate = DateTimeUtilities.MAX_DT;
|
||||||
queryBuilder.Append($"CloseDate = '{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"CloseDate = '{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
if (mrb.CancelDate < DateTime.MaxValue)
|
if (mrb.CancelDate > DateTimeUtilities.MAX_DT)
|
||||||
|
mrb.CancelDate = DateTimeUtilities.MAX_DT;
|
||||||
queryBuilder.Append($"CancelDate = '{mrb.CancelDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"CancelDate = '{mrb.CancelDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"NumberOfLotsAffected = {mrb.NumberOfLotsAffected}, ");
|
queryBuilder.Append($"NumberOfLotsAffected = {mrb.NumberOfLotsAffected}, ");
|
||||||
if (mrb.ApprovalDate < DateTime.MaxValue)
|
if (mrb.ApprovalDate > DateTimeUtilities.MAX_DT)
|
||||||
|
mrb.ApprovalDate = DateTimeUtilities.MAX_DT;
|
||||||
queryBuilder.Append($"ApprovalDate = '{mrb.ApprovalDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"ApprovalDate = '{mrb.ApprovalDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"IssueDescription = '{mrb.IssueDescription}', ");
|
queryBuilder.Append($"IssueDescription = '{mrb.IssueDescription.Replace("'", "''")}', ");
|
||||||
queryBuilder.Append($"CustomerImpacted = {Convert.ToInt32(mrb.CustomerImpacted)}, ");
|
queryBuilder.Append($"CustomerImpacted = {Convert.ToInt32(mrb.CustomerImpacted)}, ");
|
||||||
queryBuilder.Append($"Department = '{mrb.Department}', ");
|
queryBuilder.Append($"Department = '{mrb.Department.Replace("'", "''")}', ");
|
||||||
queryBuilder.Append($"Process = '{mrb.Process}', ");
|
queryBuilder.Append($"Process = '{mrb.Process.Replace("'", "''")}', ");
|
||||||
queryBuilder.Append($"Val = '{mrb.Val}', ");
|
queryBuilder.Append($"Val = {mrb.Val}, ");
|
||||||
queryBuilder.Append($"RMANo = {mrb.RMANo}, ");
|
queryBuilder.Append($"RMANo = {mrb.RMANo}, ");
|
||||||
queryBuilder.Append($"PCRBNo = {mrb.PCRBNo}, ");
|
queryBuilder.Append($"PCRBNo = '{mrb.PCRBNo}', ");
|
||||||
queryBuilder.Append($"SpecsImpacted = {Convert.ToInt32(mrb.SpecsImpacted)}, ");
|
queryBuilder.Append($"SpecsImpacted = {Convert.ToInt32(mrb.SpecsImpacted)}, ");
|
||||||
queryBuilder.Append($"TrainingRequired = {Convert.ToInt32(mrb.TrainingRequired)}, ");
|
queryBuilder.Append($"TrainingRequired = {Convert.ToInt32(mrb.TrainingRequired)}, ");
|
||||||
queryBuilder.Append($"Status = '{mrb.Status}', StageNo = {mrb.StageNo} ");
|
queryBuilder.Append($"Status = '{mrb.Status}', StageNo = {mrb.StageNo}, ");
|
||||||
|
queryBuilder.Append($"CustomerImpactedName = '{mrb.CustomerImpactedName.Replace("'", "''")}', ");
|
||||||
|
queryBuilder.Append($"ProcessECNNumber = '{mrb.ProcessECNNumber}', ");
|
||||||
|
queryBuilder.Append($"Tool = '{mrb.Tool.Replace("'", "''")}', Category = '{mrb.Category.Replace("'", "''")}' ");
|
||||||
queryBuilder.Append($"where MRBNumber = {mrb.MRBNumber};");
|
queryBuilder.Append($"where MRBNumber = {mrb.MRBNumber};");
|
||||||
|
|
||||||
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
@ -246,15 +292,16 @@ public class MRBService : IMRBService {
|
|||||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||||
|
|
||||||
StringBuilder queryBuilder = new();
|
StringBuilder queryBuilder = new();
|
||||||
queryBuilder.Append("insert into MRBAction (Action, Customer, Quantity, PartNumber, LotNumber, MRBNumber) ");
|
queryBuilder.Append("insert into MRBAction (Action, Customer, Quantity, PartNumber, LotNumber, MRBNumber, ");
|
||||||
|
queryBuilder.Append("ConvertFrom, ConvertTo, Justification) ");
|
||||||
queryBuilder.Append($"values ('{mrbAction.Action}', '{mrbAction.Customer}', {mrbAction.Quantity}, ");
|
queryBuilder.Append($"values ('{mrbAction.Action}', '{mrbAction.Customer}', {mrbAction.Quantity}, ");
|
||||||
queryBuilder.Append($"'{mrbAction.PartNumber}', '{mrbAction.LotNumber}', {mrbAction.MRBNumber});");
|
queryBuilder.Append($"'{mrbAction.PartNumber}', '{mrbAction.LotNumber}', {mrbAction.MRBNumber}, ");
|
||||||
|
queryBuilder.Append($"'{mrbAction.ConvertFrom}', '{mrbAction.ConvertTo}', '{mrbAction.Justification}');");
|
||||||
|
|
||||||
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
if (rowsAffected <= 0) throw new Exception("Unable to create MRB action in database");
|
if (rowsAffected <= 0) throw new Exception("Unable to create MRB action in database");
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
_logger.LogError($"An exception occurred when attempting to create new MRB action. Exception: {ex.Message}");
|
_logger.LogError($"An exception occurred when attempting to create new MRB action. Exception: {ex.Message}");
|
||||||
throw;
|
throw;
|
||||||
@ -305,15 +352,20 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
StringBuilder queryBuilder = new();
|
StringBuilder queryBuilder = new();
|
||||||
queryBuilder.Append($"update MRBAction set Action = '{mrbAction.Action}', ");
|
queryBuilder.Append($"update MRBAction set Action = '{mrbAction.Action}', ");
|
||||||
queryBuilder.Append($"Customer = '{mrbAction.Customer}', ");
|
queryBuilder.Append($"Customer = '{mrbAction.Customer.Replace("'", "''")}', ");
|
||||||
queryBuilder.Append($"Quantity = {mrbAction.Quantity}, ");
|
queryBuilder.Append($"Quantity = {mrbAction.Quantity}, ");
|
||||||
queryBuilder.Append($"PartNumber = '{mrbAction.PartNumber}', ");
|
queryBuilder.Append($"PartNumber = '{mrbAction.PartNumber.Replace("'", "''")}', ");
|
||||||
queryBuilder.Append($"LotNumber = '{mrbAction.LotNumber}', ");
|
queryBuilder.Append($"LotNumber = '{mrbAction.LotNumber.Replace("'", "''")}', ");
|
||||||
if (mrbAction.AssignedDate > DateTime.MinValue)
|
if (mrbAction.AssignedDate < DateTimeUtilities.MIN_DT)
|
||||||
|
mrbAction.AssignedDate = DateTimeUtilities.MIN_DT;
|
||||||
queryBuilder.Append($"AssignedDate= '{mrbAction.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"AssignedDate= '{mrbAction.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
if (mrbAction.CompletedDate < DateTime.MaxValue)
|
if (mrbAction.CompletedDate > DateTimeUtilities.MAX_DT)
|
||||||
|
mrbAction.CompletedDate = DateTimeUtilities.MAX_DT;
|
||||||
queryBuilder.Append($"CompletedDate= '{mrbAction.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
queryBuilder.Append($"CompletedDate= '{mrbAction.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
queryBuilder.Append($"CompletedByUserID={mrbAction.CompletedByUserID} ");
|
queryBuilder.Append($"CompletedByUserID={mrbAction.CompletedByUserID}, ");
|
||||||
|
queryBuilder.Append($"ConvertFrom='{mrbAction.ConvertFrom.Replace("'", "''")}', ");
|
||||||
|
queryBuilder.Append($"ConvertTo='{mrbAction.ConvertTo.Replace("'", "''")}', ");
|
||||||
|
queryBuilder.Append($"Justification='{mrbAction.Justification.Replace("'", "''")}' ");
|
||||||
queryBuilder.Append($"where ActionID={mrbAction.ActionID};");
|
queryBuilder.Append($"where ActionID={mrbAction.ActionID};");
|
||||||
|
|
||||||
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
@ -366,7 +418,6 @@ public class MRBService : IMRBService {
|
|||||||
if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty");
|
if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty");
|
||||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||||
|
|
||||||
List<Task> taskList = new ();
|
|
||||||
foreach (IFormFile file in files) {
|
foreach (IFormFile file in files) {
|
||||||
try {
|
try {
|
||||||
if (file is null) throw new ArgumentException("File cannot be null");
|
if (file is null) throw new ArgumentException("File cannot be null");
|
||||||
@ -375,8 +426,8 @@ public class MRBService : IMRBService {
|
|||||||
string encodedName = WebUtility.HtmlEncode(file.FileName);
|
string encodedName = WebUtility.HtmlEncode(file.FileName);
|
||||||
string path = $"{_mrbAttachmentPath}\\{mrbNumber}\\{encodedName}";
|
string path = $"{_mrbAttachmentPath}\\{mrbNumber}\\{encodedName}";
|
||||||
|
|
||||||
taskList.Add(SaveFileToFileSystem(file, path));
|
await FileUtilities.SaveFileToFileSystem(file, path);
|
||||||
taskList.Add(SaveAttachmentInDb(file, path, mrbNumber));
|
await SaveAttachmentInDb(file, path, mrbNumber);
|
||||||
|
|
||||||
UploadResult uploadResult = new() {
|
UploadResult uploadResult = new() {
|
||||||
UploadSuccessful = true,
|
UploadSuccessful = true,
|
||||||
@ -393,11 +444,55 @@ public class MRBService : IMRBService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return uploadResults;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"An exception occurred when attempting to upload attachment. Exception: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<UploadResult>> UploadActionAttachments(IEnumerable<IFormFile> files, int actionId) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to upload action attachments");
|
||||||
|
|
||||||
|
List<UploadResult> uploadResults = new();
|
||||||
|
|
||||||
|
if (files is null) throw new ArgumentNullException("Files cannot be null");
|
||||||
|
if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty");
|
||||||
|
if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID");
|
||||||
|
|
||||||
|
List<Task> taskList = new();
|
||||||
|
foreach (IFormFile file in files) {
|
||||||
|
try {
|
||||||
|
if (file is null) throw new ArgumentException("File cannot be null");
|
||||||
|
if (file.Length <= 0) throw new ArgumentException("File size cannot be zero");
|
||||||
|
|
||||||
|
string encodedName = WebUtility.HtmlEncode(file.FileName);
|
||||||
|
string path = $"{_mrbAttachmentPath}\\{actionId}\\{encodedName}";
|
||||||
|
|
||||||
|
taskList.Add(FileUtilities.SaveFileToFileSystem(file, path));
|
||||||
|
taskList.Add(SaveActionAttachmentInDb(file, path, actionId));
|
||||||
|
|
||||||
|
UploadResult uploadResult = new() {
|
||||||
|
UploadSuccessful = true,
|
||||||
|
FileName = file.Name
|
||||||
|
};
|
||||||
|
uploadResults.Add(uploadResult);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
UploadResult uploadResult = new() {
|
||||||
|
UploadSuccessful = false,
|
||||||
|
FileName = file.Name,
|
||||||
|
Error = ex.Message
|
||||||
|
};
|
||||||
|
uploadResults.Add(uploadResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Task.WaitAll(taskList.ToArray());
|
Task.WaitAll(taskList.ToArray());
|
||||||
|
|
||||||
return uploadResults;
|
return uploadResults;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
_logger.LogError($"An exception occurred when attempting to upload attachment. Exception: {ex.Message}");
|
_logger.LogError($"An exception occurred when attempting to upload action attachment. Exception: {ex.Message}");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,6 +525,41 @@ public class MRBService : IMRBService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to get all action attachments for MRB {mrbNumber}");
|
||||||
|
|
||||||
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||||
|
|
||||||
|
List<MRBActionAttachment>? attachments = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
attachments = _cache.Get<List<MRBActionAttachment>>($"mrbActionAttachments{mrbNumber}");
|
||||||
|
|
||||||
|
if (attachments is null) {
|
||||||
|
attachments = new List<MRBActionAttachment>();
|
||||||
|
|
||||||
|
foreach (MRBAction action in await GetMRBActionsForMRB(mrbNumber, false)) {
|
||||||
|
string sql = $"select * from MRBActionAttachment where ActionID = {action.ActionID};";
|
||||||
|
|
||||||
|
IEnumerable<MRBActionAttachment> newAttachments =
|
||||||
|
(await _dalService.QueryAsync<MRBActionAttachment>(sql)).ToList();
|
||||||
|
|
||||||
|
attachments.AddRange(newAttachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Set($"mrbActionAttachments{mrbNumber}", attachments, DateTimeOffset.Now.AddMinutes(15));
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachments;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
StringBuilder errMsgBuilder = new();
|
||||||
|
errMsgBuilder.Append($"An error occurred when attempting to get all attachments for MRB action {mrbNumber}. ");
|
||||||
|
errMsgBuilder.Append($"Exception: {ex.Message}");
|
||||||
|
_logger.LogError(errMsgBuilder.ToString());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteAttachment(MRBAttachment attachment) {
|
public async Task DeleteAttachment(MRBAttachment attachment) {
|
||||||
try {
|
try {
|
||||||
_logger.LogInformation("Attempting to delete an attachment");
|
_logger.LogInformation("Attempting to delete an attachment");
|
||||||
@ -459,7 +589,7 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(mrb.MRBNumber, true);
|
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(mrb.MRBNumber, true);
|
||||||
|
|
||||||
List<Approval> approvalsNeedingNotification = approvals.Where(a => a.NotifyDate <= DateTime.MinValue).ToList();
|
List<Approval> approvalsNeedingNotification = approvals.Where(a => a.NotifyDate <= DateTimeUtilities.MIN_DT).ToList();
|
||||||
|
|
||||||
HashSet<string> emailsAlreadySent = new();
|
HashSet<string> emailsAlreadySent = new();
|
||||||
foreach (Approval approval in approvalsNeedingNotification) {
|
foreach (Approval approval in approvalsNeedingNotification) {
|
||||||
@ -473,11 +603,12 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
List<MailAddress> ccAddresses = new();
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
string subject = $"[New Task] Mesa Fab Approval - MRB# {mrb.MRBNumber}";
|
string subject = $"[New Task] Mesa Fab Approval - MRB# {mrb.MRBNumber} - {mrb.Title}";
|
||||||
|
|
||||||
StringBuilder bodyBuilder = new();
|
StringBuilder bodyBuilder = new();
|
||||||
bodyBuilder.Append($"You have been assigned a new task in Mesa Fab Approval for issue {approval.IssueID}. The assigned role is {approval.SubRoleCategoryItem}. <br /> <br />");
|
bodyBuilder.Append($"MRB# {mrb.MRBNumber} [{mrb.Title}] is ready for your approval. ");
|
||||||
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?jwt=jwt&refreshToken=refreshToken&redirectPath=/mrb/{approval.IssueID} to view the task.");
|
bodyBuilder.Append($"The assigned role is {approval.SubRoleCategoryItem}. <br /> <br />");
|
||||||
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{approval.IssueID} to view the task.");
|
||||||
|
|
||||||
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
|
|
||||||
@ -501,10 +632,8 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(notification.MRB.MRBNumber, true);
|
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(notification.MRB.MRBNumber, true);
|
||||||
|
|
||||||
List<Approval> approvalsNeedingNotification = approvals.Where(a => a.NotifyDate <= DateTime.MinValue).ToList();
|
|
||||||
|
|
||||||
HashSet<string> emailsAlreadySent = new();
|
HashSet<string> emailsAlreadySent = new();
|
||||||
foreach (Approval approval in approvalsNeedingNotification) {
|
foreach (Approval approval in approvals) {
|
||||||
User user = await _userService.GetUserByUserId(approval.UserID);
|
User user = await _userService.GetUserByUserId(approval.UserID);
|
||||||
|
|
||||||
if (!emailsAlreadySent.Contains(user.Email)) {
|
if (!emailsAlreadySent.Contains(user.Email)) {
|
||||||
@ -515,11 +644,11 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
List<MailAddress> ccAddresses = new();
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber}";
|
string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber} - {notification.MRB.Title}";
|
||||||
|
|
||||||
StringBuilder bodyBuilder = new();
|
StringBuilder bodyBuilder = new();
|
||||||
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
||||||
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?jwt=jwt&refreshToken=refreshToken&redirectPath=/mrb/{approval.IssueID} to view the MRB.");
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{approval.IssueID} to view the MRB.");
|
||||||
|
|
||||||
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
|
|
||||||
@ -548,11 +677,11 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
List<MailAddress> ccAddresses = new();
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber}";
|
string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber} - {notification.MRB.Title}";
|
||||||
|
|
||||||
StringBuilder bodyBuilder = new();
|
StringBuilder bodyBuilder = new();
|
||||||
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
||||||
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?jwt=jwt&refreshToken=refreshToken&redirectPath=/mrb/{notification.MRB.MRBNumber} to view the MRB.");
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{notification.MRB.MRBNumber} to view the MRB.");
|
||||||
|
|
||||||
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@ -561,24 +690,202 @@ public class MRBService : IMRBService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveFileToFileSystem(IFormFile file, string path) {
|
public async Task NotifyQAPreApprover(MRBNotification notification) {
|
||||||
try {
|
try {
|
||||||
_logger.LogInformation($"Attempting to save file to file system");
|
_logger.LogInformation("Attempting to send notification to QA pre approver");
|
||||||
|
|
||||||
if (file is null) throw new ArgumentNullException("File cannot be null");
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
string roleName = "QA_PRE_APPROVAL";
|
||||||
|
|
||||||
|
int roleId = await _approvalService.GetRoleIdForRoleName(roleName);
|
||||||
|
|
||||||
|
if (roleId <= 0) throw new Exception($"could not find {roleName} role ID");
|
||||||
|
|
||||||
|
SubRole? subRole = (await _approvalService.GetSubRolesForSubRoleName(roleName, roleId)).FirstOrDefault();
|
||||||
|
|
||||||
|
if (subRole is null)
|
||||||
|
throw new Exception("Unable to find QA pre approver role");
|
||||||
|
|
||||||
|
IEnumerable<User> members = await _approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
||||||
|
|
||||||
|
List<MailAddress> toAddresses = new();
|
||||||
|
foreach (User member in members)
|
||||||
|
toAddresses.Add(new MailAddress(member.Email));
|
||||||
|
|
||||||
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
|
string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber} - {notification.MRB.Title}";
|
||||||
|
|
||||||
|
StringBuilder bodyBuilder = new();
|
||||||
|
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
||||||
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{notification.MRB.MRBNumber} to view the MRB.");
|
||||||
|
|
||||||
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to send notification to QA pre approver, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteMRB(int mrbNumber) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to delete MRB# {mrbNumber}");
|
||||||
|
|
||||||
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||||
|
|
||||||
|
string sql = $"delete from MRB where MRBNumber={mrbNumber}";
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(sql);
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception($"MRB {mrbNumber} not deleted from database");
|
||||||
|
|
||||||
|
IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||||
|
if (allMrbs is not null) {
|
||||||
|
List<MRB> mrbList = allMrbs.ToList();
|
||||||
|
mrbList.RemoveAll(m => m.MRBNumber == mrbNumber);
|
||||||
|
_cache.Set("allMrbs", mrbList, DateTimeOffset.Now.AddHours(1));
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to delete MRB {mrbNumber}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ConvertActionsToCsvFile(int mrbNumber, string path) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to convert MRB {mrbNumber} actions to a CSV file");
|
||||||
|
|
||||||
|
if (!(await MRBNumberIsValid(mrbNumber))) throw new ArgumentException($"{mrbNumber} is not a valid ");
|
||||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty");
|
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty");
|
||||||
|
|
||||||
if (File.Exists(path)) throw new Exception($"A file already exists with name {file.FileName}");
|
if (File.Exists(path)) File.Delete(path);
|
||||||
|
|
||||||
string? directoryPath = Path.GetDirectoryName(path);
|
string? directoryPath = Path.GetDirectoryName(path);
|
||||||
if (!string.IsNullOrWhiteSpace(directoryPath))
|
if (!string.IsNullOrWhiteSpace(directoryPath))
|
||||||
Directory.CreateDirectory(directoryPath);
|
Directory.CreateDirectory(directoryPath);
|
||||||
|
|
||||||
using (FileStream stream = File.Create(path)) {
|
IEnumerable<MRBAction> actions = await GetMRBActionsForMRB(mrbNumber, false);
|
||||||
await file.OpenReadStream().CopyToAsync(stream);
|
|
||||||
|
DataTable dt = await ConvertActionsToDataTable(actions);
|
||||||
|
|
||||||
|
using StreamWriter sw = new StreamWriter(path, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < dt.Columns.Count; i++) {
|
||||||
|
sw.Write(dt.Columns[i]);
|
||||||
|
if (i < dt.Columns.Count - 1) sw.Write(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw.Write(sw.NewLine);
|
||||||
|
|
||||||
|
foreach (DataRow dr in dt.Rows) {
|
||||||
|
for (int i = 0; i < dt.Columns.Count; i++) {
|
||||||
|
if (!Convert.IsDBNull(dr[i])) {
|
||||||
|
string? value = dr[i].ToString();
|
||||||
|
if (value is null) {
|
||||||
|
sw.Write("");
|
||||||
|
} else if (value.Contains(',')) {
|
||||||
|
value = String.Format("\"{0}\"", value);
|
||||||
|
sw.Write(value);
|
||||||
|
} else {
|
||||||
|
sw.Write(dr[i].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < dt.Columns.Count - 1) {
|
||||||
|
sw.Write(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Write(sw.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Close();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
_logger.LogError($"An exception occurred when attempting to save file to file system. Exception: {ex.Message}");
|
_logger.LogError($"Unable to convert MRB {mrbNumber} actions to a CSV file, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<DataTable> ConvertActionsToDataTable(IEnumerable<MRBAction> actions) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to convert MRB actions to a DataTable");
|
||||||
|
|
||||||
|
if (actions is null) throw new ArgumentNullException("MRB actions cannot be null");
|
||||||
|
|
||||||
|
DataTable dt = new();
|
||||||
|
|
||||||
|
if (actions.Count() > 0 && actions.First().Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
dt.Columns.Add("Action", typeof(string));
|
||||||
|
dt.Columns.Add("From Customer", typeof(string));
|
||||||
|
dt.Columns.Add("From Part Number", typeof(string));
|
||||||
|
dt.Columns.Add("Batch Number / Lot Number", typeof(string));
|
||||||
|
dt.Columns.Add("Qty", typeof(string));
|
||||||
|
dt.Columns.Add("To Customer", typeof(string));
|
||||||
|
dt.Columns.Add("To Part Number", typeof(string));
|
||||||
|
dt.Columns.Add("Assigned Date", typeof(string));
|
||||||
|
dt.Columns.Add("Completed Date", typeof(string));
|
||||||
|
dt.Columns.Add("Completed By", typeof(string));
|
||||||
|
|
||||||
|
foreach (MRBAction action in actions) {
|
||||||
|
if (action.CompletedByUser is null && action.CompletedByUserID > 0)
|
||||||
|
action.CompletedByUser = await _userService.GetUserByUserId(action.CompletedByUserID);
|
||||||
|
|
||||||
|
string convertFromCustomer = string.Empty;
|
||||||
|
string convertFromPart = string.Empty;
|
||||||
|
string convertToCustomer = string.Empty;
|
||||||
|
string convertToPart = string.Empty;
|
||||||
|
|
||||||
|
string[] convertFrom = action.ConvertFrom.Split(" ");
|
||||||
|
if (convertFrom.Length > 1) {
|
||||||
|
convertFromCustomer = convertFrom[0];
|
||||||
|
foreach (string partStr in convertFrom.Skip(1))
|
||||||
|
convertFromPart += partStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] convertTo = action.ConvertTo.Split(" ");
|
||||||
|
if (convertTo.Length > 1) {
|
||||||
|
convertToCustomer = convertTo[0];
|
||||||
|
foreach (string partStr in convertTo.Skip(1))
|
||||||
|
convertToPart += partStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.Rows.Add(action.Action, convertFromCustomer, convertFromPart, action.Quantity.ToString(),
|
||||||
|
convertToCustomer, convertToPart,
|
||||||
|
DateTimeUtilities.GetDateAsStringMinDefault(action.AssignedDate),
|
||||||
|
DateTimeUtilities.GetDateAsStringMaxDefault(action.CompletedDate),
|
||||||
|
action.CompletedByUser is null ? "" : action.CompletedByUser.GetFullName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dt.Columns.Add("Action", typeof(string));
|
||||||
|
dt.Columns.Add("Customer", typeof(string));
|
||||||
|
dt.Columns.Add("Qty", typeof(string));
|
||||||
|
dt.Columns.Add("Convert From", typeof(string));
|
||||||
|
dt.Columns.Add("Convert To", typeof(string));
|
||||||
|
dt.Columns.Add("Part Number", typeof(string));
|
||||||
|
dt.Columns.Add("Batch Number / Lot Number", typeof(string));
|
||||||
|
dt.Columns.Add("Justification", typeof(string));
|
||||||
|
dt.Columns.Add("Assigned Date", typeof(string));
|
||||||
|
dt.Columns.Add("Completed Date", typeof(string));
|
||||||
|
dt.Columns.Add("Completed By", typeof(string));
|
||||||
|
|
||||||
|
foreach (MRBAction action in actions) {
|
||||||
|
if (action.CompletedByUser is null && action.CompletedByUserID > 0)
|
||||||
|
action.CompletedByUser = await _userService.GetUserByUserId(action.CompletedByUserID);
|
||||||
|
|
||||||
|
dt.Rows.Add(action.Action, action.Customer, action.Quantity.ToString(), action.ConvertFrom, action.ConvertTo,
|
||||||
|
action.PartNumber, action.LotNumber, action.Justification,
|
||||||
|
DateTimeUtilities.GetDateAsStringMinDefault(action.AssignedDate),
|
||||||
|
DateTimeUtilities.GetDateAsStringMaxDefault(action.CompletedDate),
|
||||||
|
action.CompletedByUser is null ? "" : action.CompletedByUser.GetFullName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to convert MRB actions to a DataTable, because {ex.Message}");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -601,7 +908,30 @@ public class MRBService : IMRBService {
|
|||||||
if (rowsAffected <= 0)
|
if (rowsAffected <= 0)
|
||||||
throw new Exception("Unable to insert attachment in database");
|
throw new Exception("Unable to insert attachment in database");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
_logger.LogError($"An exception occurred when attempting to save file to file system. Exception: {ex.Message}");
|
_logger.LogError($"An exception occurred when attempting to save file to DB. Exception: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveActionAttachmentInDb(IFormFile file, string path, int actionId) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to save action attachment to database");
|
||||||
|
|
||||||
|
if (file is null) throw new ArgumentNullException("File cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty");
|
||||||
|
if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append("insert into MRBActionAttachment (ActionID, FileName, UploadDate, Path) ");
|
||||||
|
queryBuilder.Append($"values ({actionId}, '{file.FileName}', ");
|
||||||
|
queryBuilder.Append($"'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', '{path}');");
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsAffected <= 0)
|
||||||
|
throw new Exception("Unable to insert action attachment in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"An exception occurred when attempting to save file to DB. Exception: {ex.Message}");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
767
MesaFabApproval.API/Services/PCRBService.cs
Normal file
767
MesaFabApproval.API/Services/PCRBService.cs
Normal file
@ -0,0 +1,767 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Mail;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using MesaFabApproval.API.Utilities;
|
||||||
|
using MesaFabApproval.Models;
|
||||||
|
using MesaFabApproval.Shared.Models;
|
||||||
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Services;
|
||||||
|
|
||||||
|
public interface IPCRBService {
|
||||||
|
Task CreateNewPCRB(PCRB pcrb);
|
||||||
|
Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache);
|
||||||
|
Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task<PCRB> GetPCRBByTitle(string title, bool bypassCache);
|
||||||
|
Task UpdatePCRB(PCRB pcrb);
|
||||||
|
Task DeletePCRB(int planNumber);
|
||||||
|
Task<UploadResult> UploadAttachment(IFormFile file, PCRBAttachment attachment);
|
||||||
|
Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task UpdateAttachment(PCRBAttachment attachment);
|
||||||
|
Task DeleteAttachment(PCRBAttachment attachment);
|
||||||
|
Task CreateNewActionItem(PCRBActionItem actionItem);
|
||||||
|
Task UpdateActionItem(PCRBActionItem actionItem);
|
||||||
|
Task DeleteActionItem(int id);
|
||||||
|
Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task CreateNewAttendee(PCRBAttendee attendee);
|
||||||
|
Task UpdateAttendee(PCRBAttendee attendee);
|
||||||
|
Task DeleteAttendee(int id);
|
||||||
|
Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task CreatePCR3Document(PCR3Document document);
|
||||||
|
Task UpdatePCR3Document(PCR3Document document);
|
||||||
|
Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task NotifyNewApprovals(PCRB pcrb);
|
||||||
|
Task NotifyApprovers(PCRBNotification notification);
|
||||||
|
Task NotifyOriginator(PCRBNotification notification);
|
||||||
|
Task NotifyResponsiblePerson(PCRBActionItemNotification notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PCRBService : IPCRBService {
|
||||||
|
private readonly ILogger<PCRBService> _logger;
|
||||||
|
private readonly IDalService _dalService;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
private readonly IApprovalService _approvalService;
|
||||||
|
private readonly ISmtpService _smtpService;
|
||||||
|
|
||||||
|
private readonly string _pcrbAttachmentPath;
|
||||||
|
private readonly string _siteBaseUrl;
|
||||||
|
|
||||||
|
public PCRBService(ILogger<PCRBService> logger,
|
||||||
|
IDalService dalService,
|
||||||
|
IMemoryCache cache,
|
||||||
|
IUserService userService,
|
||||||
|
IApprovalService approvalService,
|
||||||
|
ISmtpService smtpService,
|
||||||
|
AppSettings appSettings) {
|
||||||
|
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||||
|
_dalService = dalService ?? throw new ArgumentNullException("IDalService not injected");
|
||||||
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
|
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
||||||
|
_approvalService = approvalService ??
|
||||||
|
throw new ArgumentNullException("IApprovalService not injected");
|
||||||
|
_smtpService = smtpService ?? throw new ArgumentNullException("ISmtpService not injected");
|
||||||
|
_siteBaseUrl = appSettings.SiteBaseUrl;
|
||||||
|
_pcrbAttachmentPath = appSettings.PcrbAttachmentPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateNewPCRB(PCRB pcrb) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to create new PCRB");
|
||||||
|
|
||||||
|
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append("insert into CCChangeControl (OwnerID, Title, ChangeLevel, ReasonForChange, ");
|
||||||
|
queryBuilder.Append("ChangeDescription, IsITAR, CurrentStep, InsertTimeStamp, LastUpdateDate) ");
|
||||||
|
queryBuilder.Append($"values ({pcrb.OwnerID}, '{pcrb.Title}', '{pcrb.ChangeLevel}', ");
|
||||||
|
queryBuilder.Append($"'{pcrb.ReasonForChange}', '{pcrb.ChangeDescription}', ");
|
||||||
|
queryBuilder.Append($"{Convert.ToInt32(pcrb.IsITAR)}, {pcrb.CurrentStep}, ");
|
||||||
|
queryBuilder.Append($"'{pcrb.InsertTimeStamp.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
|
queryBuilder.Append($"'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}')");
|
||||||
|
|
||||||
|
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsCreated <= 0) throw new Exception("unable to insert new PCRB in the database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to create new PCRB, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to get all PCRBs");
|
||||||
|
|
||||||
|
IEnumerable<PCRB>? allPCRBs = null;
|
||||||
|
if (!bypassCache) allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
|
||||||
|
if (allPCRBs is null) {
|
||||||
|
string sql = "select * from CCChangeControl";
|
||||||
|
|
||||||
|
allPCRBs = (await _dalService.QueryAsync<PCRB>(sql)).ToList();
|
||||||
|
|
||||||
|
foreach (PCRB pcrb in allPCRBs) {
|
||||||
|
if (string.IsNullOrWhiteSpace(pcrb.OwnerName) && pcrb.OwnerID > 0)
|
||||||
|
pcrb.OwnerName = (await _userService.GetUserByUserId(pcrb.OwnerID)).GetFullName();
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Set("allPCRBs", allPCRBs, DateTimeOffset.Now.AddHours(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allPCRBs is null || allPCRBs.Count() == 0)
|
||||||
|
throw new Exception("no PCRBs found");
|
||||||
|
|
||||||
|
return allPCRBs;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get all PCRBs, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to get a PCRB by plan#");
|
||||||
|
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB#");
|
||||||
|
|
||||||
|
PCRB? pcrb = null;
|
||||||
|
|
||||||
|
if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{planNumber}");
|
||||||
|
|
||||||
|
if (pcrb is null) {
|
||||||
|
string sql = $"select * from CCChangeControl where PlanNumber={planNumber}";
|
||||||
|
|
||||||
|
pcrb = (await _dalService.QueryAsync<PCRB>(sql)).FirstOrDefault();
|
||||||
|
|
||||||
|
if (pcrb is not null) {
|
||||||
|
if (string.IsNullOrWhiteSpace(pcrb.OwnerName) && pcrb.OwnerID > 0)
|
||||||
|
pcrb.OwnerName = (await _userService.GetUserByUserId(pcrb.OwnerID)).GetFullName();
|
||||||
|
|
||||||
|
_cache.Set($"pcrb{planNumber}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
_cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcrb is null) throw new Exception($"unable to find PCRB {planNumber}");
|
||||||
|
|
||||||
|
return pcrb;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get PCRB by Plan #, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PCRB> GetPCRBByTitle(string title, bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to get a PCRB by title");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||||
|
|
||||||
|
PCRB? pcrb = null;
|
||||||
|
|
||||||
|
if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{title}");
|
||||||
|
|
||||||
|
if (pcrb is null) {
|
||||||
|
string sql = $"select * from CCChangeControl where Title='{title}'";
|
||||||
|
|
||||||
|
pcrb = (await _dalService.QueryAsync<PCRB>(sql)).FirstOrDefault();
|
||||||
|
|
||||||
|
if (pcrb is not null) {
|
||||||
|
if (string.IsNullOrWhiteSpace(pcrb.OwnerName) && pcrb.OwnerID > 0)
|
||||||
|
pcrb.OwnerName = (await _userService.GetUserByUserId(pcrb.OwnerID)).GetFullName();
|
||||||
|
|
||||||
|
_cache.Set($"pcrb{title}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
_cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcrb is null) throw new Exception($"unable to find PCRB {title}");
|
||||||
|
|
||||||
|
return pcrb;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get PCRB by title, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdatePCRB(PCRB pcrb) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to update PCRB");
|
||||||
|
|
||||||
|
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append($"update CCChangeControl set OwnerID={pcrb.OwnerID}, ");
|
||||||
|
queryBuilder.Append($"Title='{pcrb.Title.Replace("'", "''")}', ChangeLevel='{pcrb.ChangeLevel}', ");
|
||||||
|
queryBuilder.Append($"CurrentStep={pcrb.CurrentStep}, ReasonForChange='{pcrb.ReasonForChange.Replace("'", "''")}', ");
|
||||||
|
queryBuilder.Append($"ChangeDescription='{pcrb.ChangeDescription.Replace("'", "''")}', ");
|
||||||
|
queryBuilder.Append($"IsITAR={Convert.ToInt32(pcrb.IsITAR)}, ");
|
||||||
|
queryBuilder.Append($"InsertTimeStamp='{pcrb.InsertTimeStamp.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
|
queryBuilder.Append($"ClosedDate='{pcrb.ClosedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
|
queryBuilder.Append($"LastUpdateDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}' ");
|
||||||
|
queryBuilder.Append($"where PlanNumber={pcrb.PlanNumber}");
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("unable to perform update in database");
|
||||||
|
|
||||||
|
_cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
_cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
|
||||||
|
IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
if (allPCRBs is not null) {
|
||||||
|
List<PCRB> pcrbList = allPCRBs.ToList();
|
||||||
|
pcrbList.RemoveAll(p => p.PlanNumber == pcrb.PlanNumber);
|
||||||
|
pcrbList.Add(pcrb);
|
||||||
|
_cache.Set("allPCRBs", pcrbList, DateTimeOffset.Now.AddHours(1));
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to update PCRB, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeletePCRB(int planNumber) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to delete PCRB {planNumber}");
|
||||||
|
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan #");
|
||||||
|
|
||||||
|
string sql = $"delete from CCChangeControl where PlanNumber={planNumber}";
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(sql);
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("delete operation failed in database");
|
||||||
|
|
||||||
|
IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
if (allPCRBs is not null) {
|
||||||
|
List<PCRB> pcrbList = allPCRBs.ToList();
|
||||||
|
pcrbList.RemoveAll(p => p.PlanNumber == planNumber);
|
||||||
|
_cache.Set("allPCRBs", pcrbList, DateTimeOffset.Now.AddHours(1));
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to delete PCRB {planNumber}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UploadResult> UploadAttachment(IFormFile file, PCRBAttachment attachment) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to upload attachment");
|
||||||
|
|
||||||
|
UploadResult? uploadResult = null;
|
||||||
|
|
||||||
|
if (file is null) throw new ArgumentNullException("File cannot be null");
|
||||||
|
if (file.Length <= 0) throw new ArgumentException("File size cannot be zero");
|
||||||
|
if (attachment is null) throw new ArgumentNullException("Attachment cannot be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
string encodedName = WebUtility.HtmlEncode(file.FileName);
|
||||||
|
string path = $"{_pcrbAttachmentPath}\\{attachment.PlanNumber}\\{attachment.Step}\\{encodedName}";
|
||||||
|
|
||||||
|
attachment.Path = path;
|
||||||
|
|
||||||
|
await FileUtilities.SaveFileToFileSystem(file, path);
|
||||||
|
await SaveAttachmentInDb(file, attachment);
|
||||||
|
|
||||||
|
uploadResult = new() {
|
||||||
|
UploadSuccessful = true,
|
||||||
|
FileName = file.FileName
|
||||||
|
};
|
||||||
|
} catch (Exception ex) {
|
||||||
|
uploadResult = new() {
|
||||||
|
UploadSuccessful = false,
|
||||||
|
FileName = file.FileName,
|
||||||
|
Error = ex.Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return uploadResult;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to upload attachment, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to get all attachments for PCRB Plan# {planNumber}");
|
||||||
|
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCRBAttachment>? attachments = null;
|
||||||
|
|
||||||
|
if (!bypassCache)
|
||||||
|
attachments = _cache.Get<IEnumerable<PCRBAttachment>>($"pcrbAttachments{planNumber}");
|
||||||
|
|
||||||
|
if (attachments is null) {
|
||||||
|
string sql = $"select * from CCAttachment where PlanNumber={planNumber}";
|
||||||
|
|
||||||
|
attachments = await _dalService.QueryAsync<PCRBAttachment>(sql);
|
||||||
|
|
||||||
|
_cache.Set($"pcrbAttachments{planNumber}", attachments, DateTimeOffset.Now.AddMinutes(15));
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachments;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get all attachments for PCRB Plan# {planNumber}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAttachment(PCRBAttachment attachment) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to update an attachment");
|
||||||
|
|
||||||
|
if (attachment is null)
|
||||||
|
throw new ArgumentNullException("attachment cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append($"update CCAttachment ");
|
||||||
|
queryBuilder.Append($"set Title='{attachment.Title.Replace("'", "''")}' where ID={attachment.ID}");
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("update failed in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to update attachment, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAttachment(PCRBAttachment attachment) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to update an attachment");
|
||||||
|
|
||||||
|
if (attachment is null)
|
||||||
|
throw new ArgumentNullException("attachment cannot be null");
|
||||||
|
|
||||||
|
if (!File.Exists(attachment.Path)) throw new FileNotFoundException("No file found at provided path");
|
||||||
|
|
||||||
|
File.Delete(attachment.Path);
|
||||||
|
|
||||||
|
string sql = $"delete from CCAttachment where ID={attachment.ID}";
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(sql);
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("update failed in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to update attachment, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateNewActionItem(PCRBActionItem actionItem) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to create new action item");
|
||||||
|
|
||||||
|
if (actionItem is null) throw new ArgumentNullException("action item cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append("insert into CCPCRBActionItem (Name, Gating, ClosedStatus, ClosedDate, ");
|
||||||
|
queryBuilder.Append("ClosedByID, UploadedByID, UploadedDateTime, ResponsiblePersonID, PlanNumber, ");
|
||||||
|
queryBuilder.Append($"Step) values ('{actionItem.Name}', {Convert.ToInt32(actionItem.Gating)}, ");
|
||||||
|
queryBuilder.Append($"{Convert.ToInt32(actionItem.ClosedStatus)}, ");
|
||||||
|
DateTime closedDateCopy = actionItem.ClosedDate ?? DateTimeUtilities.MAX_DT;
|
||||||
|
queryBuilder.Append($"'{closedDateCopy.ToString("yyyy-MM-dd HH:mm:ss")}', {actionItem.ClosedByID}, ");
|
||||||
|
queryBuilder.Append($"{actionItem.UploadedByID}, '{actionItem.UploadedDateTime.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
|
queryBuilder.Append($"{actionItem.ResponsiblePersonID}, {actionItem.PlanNumber}, ");
|
||||||
|
queryBuilder.Append($"{actionItem.Step});");
|
||||||
|
|
||||||
|
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsCreated <= 0) throw new Exception("unable to insert new action item in the database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to create new action item, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateActionItem(PCRBActionItem actionItem) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to update an action item");
|
||||||
|
|
||||||
|
if (actionItem is null)
|
||||||
|
throw new ArgumentNullException("action item cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append($"update CCPCRBActionItem set Name='{actionItem.Name.Replace("'", "''")}', Gating={Convert.ToInt32(actionItem.Gating)}, ");
|
||||||
|
queryBuilder.Append($"ClosedStatus={Convert.ToInt32(actionItem.ClosedStatus)}, ");
|
||||||
|
DateTime closedDateCopy = actionItem.ClosedDate ?? DateTimeUtilities.MAX_DT;
|
||||||
|
queryBuilder.Append($"ClosedDate='{closedDateCopy.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
|
queryBuilder.Append($"ClosedByID={actionItem.ClosedByID}, ResponsiblePersonID={actionItem.ResponsiblePersonID}, ");
|
||||||
|
queryBuilder.Append($"Step={actionItem.Step} where ID={actionItem.ID}");
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("update failed in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to update attachment, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteActionItem(int id) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to delete action item {id}");
|
||||||
|
|
||||||
|
if (id <= 0) throw new ArgumentException($"{id} is not a valid PCRB action item ID");
|
||||||
|
|
||||||
|
string sql = $"delete from CCPCRBActionItem where ID={id}";
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(sql);
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("delete operation failed in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to delete action item {id}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to get all action items for PCRB plan# {planNumber}");
|
||||||
|
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCRBActionItem>? actionItems = null;
|
||||||
|
|
||||||
|
if (!bypassCache)
|
||||||
|
actionItems = _cache.Get<IEnumerable<PCRBActionItem>>($"pcrbActionItems{planNumber}");
|
||||||
|
|
||||||
|
if (actionItems is null) {
|
||||||
|
string sql = $"select * from CCPCRBActionItem where PlanNumber={planNumber}";
|
||||||
|
|
||||||
|
actionItems = await _dalService.QueryAsync<PCRBActionItem>(sql);
|
||||||
|
|
||||||
|
_cache.Set($"pcrbActionItems{planNumber}", actionItems, DateTimeOffset.Now.AddMinutes(15));
|
||||||
|
}
|
||||||
|
|
||||||
|
return actionItems;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get all action items for PCRB plan# {planNumber}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateNewAttendee(PCRBAttendee attendee) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to create new attendee");
|
||||||
|
|
||||||
|
if (attendee is null) throw new ArgumentNullException("attendee item cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append("insert into CCPCRBAttendee (PlanNumber, JobTitle, Location, Attended, AttendeeID, Step) ");
|
||||||
|
queryBuilder.Append($"values ({attendee.PlanNumber}, '{attendee.JobTitle}', '{attendee.Location}', ");
|
||||||
|
queryBuilder.Append($"{Convert.ToInt32(attendee.Attended)}, {attendee.AttendeeID}, ");
|
||||||
|
queryBuilder.Append($"{attendee.Step});");
|
||||||
|
|
||||||
|
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsCreated <= 0) throw new Exception("unable to insert new attendee in the database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to create new attendee, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAttendee(PCRBAttendee attendee) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to update an attendee");
|
||||||
|
|
||||||
|
if (attendee is null)
|
||||||
|
throw new ArgumentNullException("attendee cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append($"update CCPCRBAttendee set JobTitle='{attendee.JobTitle}', ");
|
||||||
|
queryBuilder.Append($"Location='{attendee.Location}', Attended={Convert.ToInt32(attendee.Attended)}, ");
|
||||||
|
queryBuilder.Append($"AttendeeID={attendee.AttendeeID}, ");
|
||||||
|
queryBuilder.Append($"Step={attendee.Step} where ID={attendee.ID}");
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("update failed in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to update attendee, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAttendee(int id) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to delete attendee {id}");
|
||||||
|
|
||||||
|
if (id <= 0) throw new ArgumentException($"{id} is not a valid attendee ID");
|
||||||
|
|
||||||
|
string sql = $"delete from CCPCRBAttendee where ID={id}";
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(sql);
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("delete operation failed in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to delete attendee {id}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to get all attendees for PCRB plan# {planNumber}");
|
||||||
|
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCRBAttendee>? attendees = null;
|
||||||
|
|
||||||
|
if (!bypassCache)
|
||||||
|
attendees = _cache.Get<IEnumerable<PCRBAttendee>>($"pcrbAttendees{planNumber}");
|
||||||
|
|
||||||
|
if (attendees is null) {
|
||||||
|
string sql = $"select * from CCPCRBAttendee where PlanNumber={planNumber}";
|
||||||
|
|
||||||
|
attendees = await _dalService.QueryAsync<PCRBAttendee>(sql);
|
||||||
|
|
||||||
|
_cache.Set($"pcrbAttendees{planNumber}", attendees, DateTimeOffset.Now.AddMinutes(15));
|
||||||
|
}
|
||||||
|
|
||||||
|
return attendees;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get all attendees for PCRB plan# {planNumber}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreatePCR3Document(PCR3Document document) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to create new PCR3 document");
|
||||||
|
|
||||||
|
if (document is null) throw new ArgumentNullException("document item cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append("insert into CCPCR3Document (PlanNumber, DocType) ");
|
||||||
|
queryBuilder.Append($"values ({document.PlanNumber}, '{document.DocType}')");
|
||||||
|
|
||||||
|
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsCreated <= 0) throw new Exception("unable to insert new PCR3 document in the database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to create new PCR3 document, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdatePCR3Document(PCR3Document document) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to update a PCR3 document");
|
||||||
|
|
||||||
|
if (document is null) throw new ArgumentNullException("document cannot be null");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append($"update CCPCR3Document set DocNumbers='{document.DocNumbers}', ");
|
||||||
|
queryBuilder.Append($"Comment='{document.Comment.Replace("'", "''")}', ECNNumber={document.ECNNumber}, ");
|
||||||
|
queryBuilder.Append($"CompletedDate='{document.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||||
|
queryBuilder.Append($"CompletedByID={document.CompletedByID} ");
|
||||||
|
queryBuilder.Append($"where ID={document.ID}");
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsAffected <= 0) throw new Exception("update failed in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to update PCR3 document, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to get all PCR3 documents for PCRB plan# {planNumber}");
|
||||||
|
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCR3Document>? documents = null;
|
||||||
|
|
||||||
|
if (!bypassCache)
|
||||||
|
documents = _cache.Get<IEnumerable<PCR3Document>>($"pcr3Documents{planNumber}");
|
||||||
|
|
||||||
|
if (documents is null) {
|
||||||
|
string sql = $"select * from CCPCR3Document where PlanNumber={planNumber}";
|
||||||
|
|
||||||
|
documents = await _dalService.QueryAsync<PCR3Document>(sql);
|
||||||
|
|
||||||
|
_cache.Set($"pcr3Documents{planNumber}", documents, DateTimeOffset.Now.AddMinutes(15));
|
||||||
|
}
|
||||||
|
|
||||||
|
return documents;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to get all PCR3 documents for PCRB plan# {planNumber}, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyNewApprovals(PCRB pcrb) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to notify approvers");
|
||||||
|
|
||||||
|
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
|
||||||
|
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, true);
|
||||||
|
|
||||||
|
List<Approval> approvalsNeedingNotification = approvals.Where(a => a.Step == pcrb.CurrentStep &&
|
||||||
|
a.NotifyDate <= DateTimeUtilities.MIN_DT &&
|
||||||
|
a.AssignedDate > DateTimeUtilities.MIN_DT).ToList();
|
||||||
|
|
||||||
|
HashSet<string> emailsAlreadySent = new();
|
||||||
|
foreach (Approval approval in approvalsNeedingNotification) {
|
||||||
|
User user = await _userService.GetUserByUserId(approval.UserID);
|
||||||
|
|
||||||
|
if (!emailsAlreadySent.Contains(user.Email.ToLower())) {
|
||||||
|
emailsAlreadySent.Add(user.Email);
|
||||||
|
|
||||||
|
List<MailAddress> toAddresses = new();
|
||||||
|
toAddresses.Add(new MailAddress(user.Email.ToLower()));
|
||||||
|
|
||||||
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
|
string subject = $"[New Task] Mesa Fab Approval - PCRB# {pcrb.PlanNumber} - {pcrb.Title}";
|
||||||
|
|
||||||
|
StringBuilder bodyBuilder = new();
|
||||||
|
bodyBuilder.Append($"PCRB# {pcrb.PlanNumber} [{pcrb.Title}] PCR{approval.Step} is ready for your approval. ");
|
||||||
|
bodyBuilder.Append($"The assigned role is {approval.SubRoleCategoryItem}. <br /> <br />");
|
||||||
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{approval.IssueID} to view the PCRB.");
|
||||||
|
|
||||||
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
|
|
||||||
|
approval.NotifyDate = DateTime.Now;
|
||||||
|
await _approvalService.UpdateApproval(approval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to notify approvers, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyApprovers(PCRBNotification notification) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to send notification to approvers");
|
||||||
|
|
||||||
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(notification.PCRB.PlanNumber, true);
|
||||||
|
|
||||||
|
HashSet<string> emailsAlreadySent = new();
|
||||||
|
foreach (Approval approval in approvals) {
|
||||||
|
User user = await _userService.GetUserByUserId(approval.UserID);
|
||||||
|
|
||||||
|
if (!emailsAlreadySent.Contains(user.Email)) {
|
||||||
|
emailsAlreadySent.Add(user.Email);
|
||||||
|
|
||||||
|
List<MailAddress> toAddresses = new();
|
||||||
|
toAddresses.Add(new MailAddress(user.Email));
|
||||||
|
|
||||||
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
|
string subject = $"[Update] Mesa Fab Approval - PCRB# {notification.PCRB.PlanNumber} - {notification.PCRB.Title}";
|
||||||
|
|
||||||
|
StringBuilder bodyBuilder = new();
|
||||||
|
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
||||||
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{approval.IssueID} to view the PCRB.");
|
||||||
|
|
||||||
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
|
|
||||||
|
approval.NotifyDate = DateTime.Now;
|
||||||
|
await _approvalService.UpdateApproval(approval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to send notification to originator, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyOriginator(PCRBNotification notification) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to send notification to originator");
|
||||||
|
|
||||||
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
User user = await _userService.GetUserByUserId(notification.PCRB.OwnerID);
|
||||||
|
|
||||||
|
List<MailAddress> toAddresses = new();
|
||||||
|
toAddresses.Add(new MailAddress(user.Email));
|
||||||
|
|
||||||
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
|
string subject = $"[Update] Mesa Fab Approval - PCRB# {notification.PCRB.PlanNumber} - {notification.PCRB.Title}";
|
||||||
|
|
||||||
|
StringBuilder bodyBuilder = new();
|
||||||
|
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
||||||
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{notification.PCRB.PlanNumber} to view the PCRB.");
|
||||||
|
|
||||||
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to send notification to originator, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyResponsiblePerson(PCRBActionItemNotification notification) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation("Attempting to notify responsible person");
|
||||||
|
|
||||||
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message))
|
||||||
|
throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
if (notification.ActionItem.ResponsiblePerson is null)
|
||||||
|
notification.ActionItem.ResponsiblePerson = await _userService.GetUserByUserId(notification.ActionItem.ResponsiblePersonID);
|
||||||
|
|
||||||
|
List<MailAddress> toAddresses = new();
|
||||||
|
toAddresses.Add(new MailAddress(notification.ActionItem.ResponsiblePerson.Email));
|
||||||
|
|
||||||
|
List<MailAddress> ccAddresses = new();
|
||||||
|
|
||||||
|
string subject = $"[New Task] Mesa Fab Approval - PCRB# {notification.PCRB.PlanNumber} - {notification.PCRB.Title}";
|
||||||
|
|
||||||
|
StringBuilder bodyBuilder = new();
|
||||||
|
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
||||||
|
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{notification.PCRB.PlanNumber} to view the PCRB.");
|
||||||
|
|
||||||
|
await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to notify responsible person, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAttachmentInDb(IFormFile file, PCRBAttachment attachment) {
|
||||||
|
try {
|
||||||
|
_logger.LogInformation($"Attempting to save attachment to database");
|
||||||
|
|
||||||
|
if (file is null) throw new ArgumentNullException("File cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(attachment.Path)) throw new ArgumentException("Path cannot be null or empty");
|
||||||
|
if (attachment.PlanNumber <= 0) throw new ArgumentException($"{attachment.PlanNumber} is not a valid PCRB Plan#");
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new();
|
||||||
|
queryBuilder.Append("insert into CCAttachment (PlanNumber, FileName, UploadDateTime, Path, UploadedByID, Title, ");
|
||||||
|
queryBuilder.Append($"Step) values ({attachment.PlanNumber}, '{file.FileName}', ");
|
||||||
|
queryBuilder.Append($"'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', '{attachment.Path}', {attachment.UploadedByID}, ");
|
||||||
|
queryBuilder.Append($"'{attachment.Title}', {attachment.Step});");
|
||||||
|
|
||||||
|
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||||
|
|
||||||
|
if (rowsAffected <= 0)
|
||||||
|
throw new Exception("Unable to insert attachment in database");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.LogError($"Unable to save file to DB, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,10 @@
|
|||||||
using MesaFabApproval.API.Clients;
|
using System.Net.Mail;
|
||||||
|
|
||||||
|
using MesaFabApproval.API.Clients;
|
||||||
|
using MesaFabApproval.Models;
|
||||||
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
using System.Net.Mail;
|
|
||||||
|
|
||||||
namespace MesaFabApproval.API.Services;
|
namespace MesaFabApproval.API.Services;
|
||||||
|
|
||||||
public interface ISmtpService {
|
public interface ISmtpService {
|
||||||
@ -15,13 +16,12 @@ public class SmtpService : ISmtpService {
|
|||||||
private readonly ISmtpClientWrapper _smtpClient;
|
private readonly ISmtpClientWrapper _smtpClient;
|
||||||
private readonly bool _shouldSendEmail;
|
private readonly bool _shouldSendEmail;
|
||||||
|
|
||||||
public SmtpService(ILogger<SmtpService> logger, ISmtpClientWrapper smtpClient) {
|
public SmtpService(ILogger<SmtpService> logger, ISmtpClientWrapper smtpClient, AppSettings appSettings) {
|
||||||
_logger = logger ??
|
_logger = logger ??
|
||||||
throw new ArgumentNullException("ILogger not injected");
|
throw new ArgumentNullException("ILogger not injected");
|
||||||
_smtpClient = smtpClient ??
|
_smtpClient = smtpClient ??
|
||||||
throw new ArgumentNullException("SmtpClient not injected");
|
throw new ArgumentNullException("SmtpClient not injected");
|
||||||
if (!Boolean.TryParse(Environment.GetEnvironmentVariable("FabApprovalShouldSendEmail"), out _shouldSendEmail))
|
_shouldSendEmail = appSettings.ShouldSendEmail;
|
||||||
throw new ArgumentNullException("FabApprovalShouldSendEmail environment variable not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SendEmail(IEnumerable<MailAddress> recipients,
|
public async Task<bool> SendEmail(IEnumerable<MailAddress> recipients,
|
||||||
|
|||||||
31
MesaFabApproval.API/Utilities/FileUtilities.cs
Normal file
31
MesaFabApproval.API/Utilities/FileUtilities.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.API.Utilities;
|
||||||
|
|
||||||
|
public class FileUtilities {
|
||||||
|
private static readonly Logger _logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public static async Task SaveFileToFileSystem(IFormFile file, string path) {
|
||||||
|
try {
|
||||||
|
_logger.Info($"Attempting to save file to file system");
|
||||||
|
|
||||||
|
if (file is null) throw new ArgumentNullException("File cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty");
|
||||||
|
|
||||||
|
if (File.Exists(path)) throw new Exception($"A file already exists with name {file.FileName}");
|
||||||
|
|
||||||
|
string? directoryPath = Path.GetDirectoryName(path);
|
||||||
|
if (!string.IsNullOrWhiteSpace(directoryPath))
|
||||||
|
Directory.CreateDirectory(directoryPath);
|
||||||
|
|
||||||
|
using (Stream stream = File.Create(path)) {
|
||||||
|
await file.CopyToAsync(stream);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_logger.Error($"Unable to save file to file system, because {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +1,3 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
autoReload="true">
|
|
||||||
|
|
||||||
<extensions>
|
|
||||||
<add assembly="NLog.Web.AspNetCore"/>
|
|
||||||
</extensions>
|
|
||||||
|
|
||||||
<targets>
|
|
||||||
<target name="asyncFile" xsi:type="AsyncWrapper">
|
|
||||||
<target
|
|
||||||
name="appLog"
|
|
||||||
xsi:type="File"
|
|
||||||
fileName="d:\logs\MesaProveInApi\log.txt"
|
|
||||||
archiveFilename="d:\logs\MesaProveInApi\archive\log-${shortdate}.txt"
|
|
||||||
maxArchiveFiles="15"
|
|
||||||
archiveEvery="Day"
|
|
||||||
/>
|
|
||||||
<target
|
|
||||||
name="consoleLog"
|
|
||||||
xsi:type="Console"
|
|
||||||
/>
|
|
||||||
</target>
|
|
||||||
</targets>
|
|
||||||
|
|
||||||
<rules>
|
|
||||||
<logger name="Microsoft.*" finalMinLevel="Warn" />
|
|
||||||
<logger name="System.Net.Http.HttpClient.*" finalMinLevel="Warn" />
|
|
||||||
<logger name="*" minlevel="Debug" writeTo="consoleLog, appLog"/>
|
|
||||||
</rules>
|
|
||||||
</nlog>
|
|
||||||
@ -8,7 +8,7 @@
|
|||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<targets>
|
<targets>
|
||||||
<target name="asyncFile" xsi:type="AsyncWrapper">
|
<target name="asyncLog" xsi:type="AsyncWrapper">
|
||||||
<target
|
<target
|
||||||
name="appLog"
|
name="appLog"
|
||||||
xsi:type="File"
|
xsi:type="File"
|
||||||
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
<rules>
|
<rules>
|
||||||
<logger name="Microsoft.*" finalMinLevel="Warn" />
|
<logger name="Microsoft.*" finalMinLevel="Warn" />
|
||||||
|
<logger name="Microsoft.AspNetCore.HttpLogging.*" finalMinLevel="Info" />
|
||||||
<logger name="System.Net.Http.HttpClient.*" finalMinLevel="Warn" />
|
<logger name="System.Net.Http.HttpClient.*" finalMinLevel="Warn" />
|
||||||
<logger name="*" minlevel="Info" writeTo="consoleLog, appLog" />
|
<logger name="*" minlevel="Info" writeTo="consoleLog, appLog" />
|
||||||
</rules>
|
</rules>
|
||||||
|
|||||||
1
MesaFabApproval.Client/.vscode/format-report.json
vendored
Normal file
1
MesaFabApproval.Client/.vscode/format-report.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
30
MesaFabApproval.Client/.vscode/launch.json
vendored
Normal file
30
MesaFabApproval.Client/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (console)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/net8.0/MesaFabApproval.API.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "node Launch Current Opened File",
|
||||||
|
"program": "${file}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
6
MesaFabApproval.Client/.vscode/mklink.md
vendored
Normal file
6
MesaFabApproval.Client/.vscode/mklink.md
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# mklink
|
||||||
|
|
||||||
|
```bash 1731705389065 = 638673021890650000 = Fri Nov 15 2024 14:16:28 GMT-0700 (Mountain Standard Time)
|
||||||
|
mklink /J "L:\DevOps\Mesa_FI\MesaFabApproval\MesaFabApproval.API\.vscode\.UserSecrets" "C:\Users\phares\AppData\Roaming\Microsoft\UserSecrets\0b98e1f2-95ed-4edd-8149-58cce51ca059"
|
||||||
|
dotnet run --urls=https://localhost:7114/ -C Release
|
||||||
|
```
|
||||||
424
MesaFabApproval.Client/.vscode/settings.json
vendored
Normal file
424
MesaFabApproval.Client/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
{
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.wordWrap": "off"
|
||||||
|
},
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": false,
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"cSpell.words": [
|
||||||
|
"abutton",
|
||||||
|
"accessibilities",
|
||||||
|
"accodingly",
|
||||||
|
"acknowledgmentby",
|
||||||
|
"Acks",
|
||||||
|
"actionsheet",
|
||||||
|
"Additonal",
|
||||||
|
"Addtional",
|
||||||
|
"againm",
|
||||||
|
"agendaview",
|
||||||
|
"Antlr",
|
||||||
|
"Appover",
|
||||||
|
"Appprrovers",
|
||||||
|
"Approvalog",
|
||||||
|
"Aprovers",
|
||||||
|
"Aproverslist",
|
||||||
|
"asax",
|
||||||
|
"aspnetmvc",
|
||||||
|
"Assignedto",
|
||||||
|
"Atachments",
|
||||||
|
"Attachemnt",
|
||||||
|
"Attachemnts",
|
||||||
|
"Attchment",
|
||||||
|
"auditee",
|
||||||
|
"Auditee",
|
||||||
|
"Auditees",
|
||||||
|
"automaically",
|
||||||
|
"Autthorized",
|
||||||
|
"beacuase",
|
||||||
|
"beforeunload",
|
||||||
|
"Belguim",
|
||||||
|
"bfound",
|
||||||
|
"bgcolor",
|
||||||
|
"Bies",
|
||||||
|
"binded",
|
||||||
|
"blackbackground",
|
||||||
|
"blackhover",
|
||||||
|
"blackpressed",
|
||||||
|
"blueenergy",
|
||||||
|
"blueopal",
|
||||||
|
"buttongroup",
|
||||||
|
"BYMRB",
|
||||||
|
"bytesgot",
|
||||||
|
"CAID",
|
||||||
|
"casection",
|
||||||
|
"CAXXXX",
|
||||||
|
"CCPCR",
|
||||||
|
"CCPCRB",
|
||||||
|
"cellspacing",
|
||||||
|
"Cheeso's",
|
||||||
|
"chkbx",
|
||||||
|
"Clib",
|
||||||
|
"colorpicker",
|
||||||
|
"columnmenu",
|
||||||
|
"columnsreorder",
|
||||||
|
"columnsresize",
|
||||||
|
"comming",
|
||||||
|
"Containmen",
|
||||||
|
"Copmments",
|
||||||
|
"correctiv",
|
||||||
|
"Correctivet",
|
||||||
|
"Creat",
|
||||||
|
"currentd",
|
||||||
|
"Cyle",
|
||||||
|
"dadada",
|
||||||
|
"darkbluehover",
|
||||||
|
"darkbluepressed",
|
||||||
|
"darkred",
|
||||||
|
"datafields",
|
||||||
|
"datasource",
|
||||||
|
"dataviz",
|
||||||
|
"datepicker",
|
||||||
|
"datetimepicker",
|
||||||
|
"dayview",
|
||||||
|
"Deletet",
|
||||||
|
"Delgation",
|
||||||
|
"DENITED",
|
||||||
|
"Deparmtent",
|
||||||
|
"departmentids",
|
||||||
|
"Descirption",
|
||||||
|
"devprog",
|
||||||
|
"dfeffc",
|
||||||
|
"Disp",
|
||||||
|
"Dispo",
|
||||||
|
"Dispoitio",
|
||||||
|
"Dispos",
|
||||||
|
"Dispositon",
|
||||||
|
"Dispostion",
|
||||||
|
"Dispostions",
|
||||||
|
"dispotypevalidation",
|
||||||
|
"Docbase",
|
||||||
|
"Documentum",
|
||||||
|
"Documetum",
|
||||||
|
"dont",
|
||||||
|
"downlaoded",
|
||||||
|
"draganddrop",
|
||||||
|
"dragcancel",
|
||||||
|
"dropdownlist",
|
||||||
|
"Eamils",
|
||||||
|
"ECNPCRB",
|
||||||
|
"Ecns",
|
||||||
|
"edmx",
|
||||||
|
"EECN",
|
||||||
|
"emai",
|
||||||
|
"emailparams",
|
||||||
|
"Emergrncy",
|
||||||
|
"energyblue",
|
||||||
|
"Eran",
|
||||||
|
"Esql",
|
||||||
|
"ETECN",
|
||||||
|
"EXCELOPENXML",
|
||||||
|
"existinglocation",
|
||||||
|
"Expando",
|
||||||
|
"extrafield",
|
||||||
|
"fadc",
|
||||||
|
"fbec",
|
||||||
|
"fcfdfd",
|
||||||
|
"fdff",
|
||||||
|
"fece",
|
||||||
|
"feeebd",
|
||||||
|
"ffdc",
|
||||||
|
"ffdd",
|
||||||
|
"fieldset",
|
||||||
|
"FILIPE",
|
||||||
|
"filtermenu",
|
||||||
|
"Fldr",
|
||||||
|
"flintstone",
|
||||||
|
"FLOWLOCS",
|
||||||
|
"FMEA",
|
||||||
|
"ftplib",
|
||||||
|
"FTPSPN",
|
||||||
|
"GETDATE",
|
||||||
|
"gitea",
|
||||||
|
"globaldocudms",
|
||||||
|
"glyphicons",
|
||||||
|
"groupable",
|
||||||
|
"Guids",
|
||||||
|
"halflings",
|
||||||
|
"Hexsize",
|
||||||
|
"highcontrast",
|
||||||
|
"Hmac",
|
||||||
|
"holdsteps",
|
||||||
|
"hostspecific",
|
||||||
|
"icenium",
|
||||||
|
"IECN",
|
||||||
|
"imagebrowser",
|
||||||
|
"IMRB",
|
||||||
|
"Infineon",
|
||||||
|
"Insertd",
|
||||||
|
"inverseicons",
|
||||||
|
"IPCRB",
|
||||||
|
"ISADMIN",
|
||||||
|
"islast",
|
||||||
|
"ISNULL",
|
||||||
|
"ITAR",
|
||||||
|
"jquery",
|
||||||
|
"jqueryval",
|
||||||
|
"jqwidgets",
|
||||||
|
"jqxbuttongroup",
|
||||||
|
"jqxbuttons",
|
||||||
|
"jqxcalendar",
|
||||||
|
"jqxchart",
|
||||||
|
"jqxcheckbox",
|
||||||
|
"jqxcolorpicker",
|
||||||
|
"jqxcombobox",
|
||||||
|
"jqxcore",
|
||||||
|
"jqxdata",
|
||||||
|
"jqxdatatable",
|
||||||
|
"jqxdatetimeinput",
|
||||||
|
"jqxdocking",
|
||||||
|
"jqxdockpanel",
|
||||||
|
"jqxdragdrop",
|
||||||
|
"jqxdropdownbutton",
|
||||||
|
"jqxdropdownlist",
|
||||||
|
"jqxexpander",
|
||||||
|
"jqxgauge",
|
||||||
|
"jqxgrid",
|
||||||
|
"jqxinput",
|
||||||
|
"jqxknockout",
|
||||||
|
"jqxlistbox",
|
||||||
|
"jqxlistmenu",
|
||||||
|
"jqxmaskedinput",
|
||||||
|
"jqxmenu",
|
||||||
|
"jqxnavigationbar",
|
||||||
|
"jqxnumberinput",
|
||||||
|
"jqxpanel",
|
||||||
|
"jqxpasswordinput",
|
||||||
|
"jqxprogressbar",
|
||||||
|
"jqxradiobutton",
|
||||||
|
"jqxrangeselector",
|
||||||
|
"jqxrating",
|
||||||
|
"jqxresponse",
|
||||||
|
"jqxscrollbar",
|
||||||
|
"jqxscrollview",
|
||||||
|
"jqxslider",
|
||||||
|
"jqxsplitter",
|
||||||
|
"jqxswitchbutton",
|
||||||
|
"jqxtabs",
|
||||||
|
"jqxtooltip",
|
||||||
|
"jqxtouch",
|
||||||
|
"jqxtree",
|
||||||
|
"jqxtreegrid",
|
||||||
|
"jqxtreemap",
|
||||||
|
"jqxvalidator",
|
||||||
|
"jqxwindow",
|
||||||
|
"kendogridcustom",
|
||||||
|
"kendoui",
|
||||||
|
"labelelement",
|
||||||
|
"labelledby",
|
||||||
|
"Leanred",
|
||||||
|
"lightgray",
|
||||||
|
"linkbutton",
|
||||||
|
"Linq",
|
||||||
|
"Listdiv",
|
||||||
|
"listview",
|
||||||
|
"Lnks",
|
||||||
|
"localfilename",
|
||||||
|
"loclist",
|
||||||
|
"logis",
|
||||||
|
"logtext",
|
||||||
|
"loopmis",
|
||||||
|
"lotdispo",
|
||||||
|
"LOTDISPSITION",
|
||||||
|
"Lotfile",
|
||||||
|
"lotlist",
|
||||||
|
"lotstatusoption",
|
||||||
|
"LTRIM",
|
||||||
|
"MADUREIRA",
|
||||||
|
"mailrelay",
|
||||||
|
"MDTM",
|
||||||
|
"meego",
|
||||||
|
"meetingid",
|
||||||
|
"menubutton",
|
||||||
|
"mesafi",
|
||||||
|
"metroblack",
|
||||||
|
"metrodark",
|
||||||
|
"miliseconds",
|
||||||
|
"modalview",
|
||||||
|
"modernizr",
|
||||||
|
"Modernizr",
|
||||||
|
"monthview",
|
||||||
|
"MRBIs",
|
||||||
|
"Mrbs",
|
||||||
|
"msecs",
|
||||||
|
"multipleextended",
|
||||||
|
"Navigatable",
|
||||||
|
"nbsp",
|
||||||
|
"newbase",
|
||||||
|
"newchange",
|
||||||
|
"newdi",
|
||||||
|
"newfilename",
|
||||||
|
"newsource",
|
||||||
|
"Newtonsoft",
|
||||||
|
"notications",
|
||||||
|
"Notifcation",
|
||||||
|
"Notifyf",
|
||||||
|
"NTLM",
|
||||||
|
"Nullcc",
|
||||||
|
"numerictextbox",
|
||||||
|
"objdata",
|
||||||
|
"OCAP",
|
||||||
|
"occured",
|
||||||
|
"odata",
|
||||||
|
"oldfilename",
|
||||||
|
"OLHOLD",
|
||||||
|
"onclick",
|
||||||
|
"onmousemove",
|
||||||
|
"OPDESC",
|
||||||
|
"OPENQUERY",
|
||||||
|
"Oper",
|
||||||
|
"operationslist",
|
||||||
|
"Orginator",
|
||||||
|
"Originatorname",
|
||||||
|
"Ouellette",
|
||||||
|
"Owin",
|
||||||
|
"pageable",
|
||||||
|
"Pageable",
|
||||||
|
"panelbar",
|
||||||
|
"parentid",
|
||||||
|
"parminput",
|
||||||
|
"parms",
|
||||||
|
"Parms",
|
||||||
|
"particula",
|
||||||
|
"pasv",
|
||||||
|
"PASV",
|
||||||
|
"PATINDEX",
|
||||||
|
"PCRB",
|
||||||
|
"PCRBID",
|
||||||
|
"pcrvalues",
|
||||||
|
"pdbonly",
|
||||||
|
"Preventitive",
|
||||||
|
"preventivet",
|
||||||
|
"Prevetative",
|
||||||
|
"proces",
|
||||||
|
"Processedl",
|
||||||
|
"procs",
|
||||||
|
"productfamilies",
|
||||||
|
"progess",
|
||||||
|
"progressbar",
|
||||||
|
"qrcode",
|
||||||
|
"Quanityt",
|
||||||
|
"rangebar",
|
||||||
|
"Recep",
|
||||||
|
"Recepient",
|
||||||
|
"recieved",
|
||||||
|
"recordlock",
|
||||||
|
"remotefilename",
|
||||||
|
"reorderable",
|
||||||
|
"reportform",
|
||||||
|
"reportslist",
|
||||||
|
"reportslistdiv",
|
||||||
|
"Reqquired",
|
||||||
|
"Reqs",
|
||||||
|
"Requiest",
|
||||||
|
"Responsibles",
|
||||||
|
"RETR",
|
||||||
|
"Revisioing",
|
||||||
|
"Revisioned",
|
||||||
|
"Revison",
|
||||||
|
"rgba",
|
||||||
|
"rkotian",
|
||||||
|
"RNFR",
|
||||||
|
"RNTO",
|
||||||
|
"Roless",
|
||||||
|
"roundbg",
|
||||||
|
"RTRIM",
|
||||||
|
"SAMDB",
|
||||||
|
"scroller",
|
||||||
|
"scrollview",
|
||||||
|
"seleced",
|
||||||
|
"selectionlog",
|
||||||
|
"Selectpart",
|
||||||
|
"sess",
|
||||||
|
"Sfisharepoint",
|
||||||
|
"shinyblack",
|
||||||
|
"showpassword",
|
||||||
|
"SIGNON",
|
||||||
|
"simpleparser",
|
||||||
|
"slddrw",
|
||||||
|
"sldprt",
|
||||||
|
"sortasc",
|
||||||
|
"sortascbutton",
|
||||||
|
"sortdesc",
|
||||||
|
"sortdescbutton",
|
||||||
|
"sortremove",
|
||||||
|
"sparkline",
|
||||||
|
"splitview",
|
||||||
|
"SPNMRB",
|
||||||
|
"SPNPDB",
|
||||||
|
"SSRS",
|
||||||
|
"Sssign",
|
||||||
|
"Staus",
|
||||||
|
"stylesheet",
|
||||||
|
"Submited",
|
||||||
|
"subrole",
|
||||||
|
"subroles",
|
||||||
|
"Succefully",
|
||||||
|
"Succesfully",
|
||||||
|
"sucessfully",
|
||||||
|
"SURP",
|
||||||
|
"Swashbuckle",
|
||||||
|
"SWRN",
|
||||||
|
"tabindex",
|
||||||
|
"tabstrip",
|
||||||
|
"Tahoma",
|
||||||
|
"taskcompleted",
|
||||||
|
"Tasklist",
|
||||||
|
"Taveler",
|
||||||
|
"TECN",
|
||||||
|
"TECNs",
|
||||||
|
"TEMIRWAP",
|
||||||
|
"tempecd",
|
||||||
|
"tempimplement",
|
||||||
|
"templabel",
|
||||||
|
"tempvalue",
|
||||||
|
"TEMSA",
|
||||||
|
"timepicker",
|
||||||
|
"Tobe",
|
||||||
|
"Toplevel",
|
||||||
|
"Totrav",
|
||||||
|
"trainingby",
|
||||||
|
"Traininglist",
|
||||||
|
"traininglistdiv",
|
||||||
|
"transanction",
|
||||||
|
"Trav",
|
||||||
|
"Traveller",
|
||||||
|
"Traverler",
|
||||||
|
"TRAVLELER",
|
||||||
|
"Travler",
|
||||||
|
"TREEVIEW",
|
||||||
|
"trigerred",
|
||||||
|
"ttinclude",
|
||||||
|
"Uhandled",
|
||||||
|
"Updat",
|
||||||
|
"Uplaod",
|
||||||
|
"Upto",
|
||||||
|
"userevents",
|
||||||
|
"userids",
|
||||||
|
"userlist",
|
||||||
|
"Validatable",
|
||||||
|
"valueelement",
|
||||||
|
"Variabls",
|
||||||
|
"Verdana",
|
||||||
|
"vgrid",
|
||||||
|
"viewmodel",
|
||||||
|
"vsdoc",
|
||||||
|
"whethere",
|
||||||
|
"windowsphone",
|
||||||
|
"Winsock",
|
||||||
|
"worlflow"
|
||||||
|
]
|
||||||
|
}
|
||||||
121
MesaFabApproval.Client/.vscode/tasks.json
vendored
Normal file
121
MesaFabApproval.Client/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "User Secrets Init",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"user-secrets",
|
||||||
|
"-p",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client.csproj",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "testDebug",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "testRelease",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary",
|
||||||
|
"-c",
|
||||||
|
"Release"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Publish AOT",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"-r",
|
||||||
|
"win-x64",
|
||||||
|
"-c",
|
||||||
|
"Release",
|
||||||
|
"-p:PublishAot=true",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Client.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
8
MesaFabApproval.Client/GlobalSuppressions.cs
Normal file
8
MesaFabApproval.Client/GlobalSuppressions.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// This file is used by Code Analysis to maintain SuppressMessage
|
||||||
|
// attributes that are applied to this project.
|
||||||
|
// Project-level suppressions either have no target or are given
|
||||||
|
// a specific target and scoped to a namespace, type, member, etc.
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>", Scope = "member", Target = "~M:MesaFabApproval.Client.Services.AuthenticationService.AttemptLocalUserAuth~System.Threading.Tasks.Task{System.Security.Claims.ClaimsPrincipal}")]
|
||||||
@ -1,13 +1,20 @@
|
|||||||
@inherits LayoutComponentBase
|
@using System.Text.Json
|
||||||
|
@using System.Text
|
||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
@inject IAuthenticationService authenticationService
|
||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
@inject IMemoryCache cache
|
@inject IMemoryCache cache
|
||||||
|
@inject IJSRuntime jsRuntime
|
||||||
|
@inject IHttpClientFactory httpClientFactory
|
||||||
|
@inject ISnackbar snackbar
|
||||||
@inject NavigationManager navManager
|
@inject NavigationManager navManager
|
||||||
|
|
||||||
<MudThemeProvider />
|
<MudThemeProvider />
|
||||||
<MudDialogProvider />
|
<MudDialogProvider />
|
||||||
<MudSnackbarProvider />
|
<MudSnackbarProvider />
|
||||||
|
<MudPopoverProvider />
|
||||||
|
|
||||||
<div style="height: 100vh;">
|
<div style="height: 100vh;">
|
||||||
<MudLayout>
|
<MudLayout>
|
||||||
@ -33,18 +40,21 @@
|
|||||||
StartIcon="@Icons.Material.Filled.Home">
|
StartIcon="@Icons.Material.Filled.Home">
|
||||||
Return to Main Site
|
Return to Main Site
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
<MudDivider Class="my-1" />
|
<MudDivider Class="my-1" />
|
||||||
@if (authStateProvider.CurrentUser is not null) {
|
@if (authStateProvider.CurrentUser is not null) {
|
||||||
<MudNavGroup Title="Create New">
|
<MudNavGroup Title="Create New">
|
||||||
<MudNavLink OnClick="@(() => GoTo("mrb/new"))">Create New MRB</MudNavLink>
|
<MudNavLink OnClick="@(() => GoTo("mrb/new"))">Create New MRB</MudNavLink>
|
||||||
|
<MudNavLink OnClick="@(() => GoTo("pcrb/new"))">Create New PCRB</MudNavLink>
|
||||||
</MudNavGroup>
|
</MudNavGroup>
|
||||||
<MudNavLink OnClick="@(() => GoTo(""))" Icon="@Icons.Material.Filled.Dashboard">Dashboard</MudNavLink>
|
<MudNavLink OnClick="@(() => GoTo(""))" Icon="@Icons.Material.Filled.Dashboard">Dashboard</MudNavLink>
|
||||||
<MudNavLink OnClick="@(() => GoTo("mrb/all"))" Icon="@Icons.Material.Filled.Ballot">MRB</MudNavLink>
|
<MudNavLink OnClick="@(() => GoTo("mrb/all"))" Icon="@Icons.Material.Filled.Ballot">MRB List</MudNavLink>
|
||||||
|
<MudNavLink OnClick="@(() => GoTo("pcrb/all"))" Icon="@Icons.Material.Filled.Ballot">PCRB List</MudNavLink>
|
||||||
}
|
}
|
||||||
</MudNavMenu>
|
</MudNavMenu>
|
||||||
</MudDrawer>
|
</MudDrawer>
|
||||||
<div style="display: flex; flex-flow: column; height: 100%;">
|
<div style="display: flex; flex-flow: column; height: 100%;">
|
||||||
<MudMainContent Style="@($"background:{Colors.Grey.Lighten2}; flex-grow: 1;")">
|
<MudMainContent Style="@($"background:#E0E0E0; flex-grow: 1;")">
|
||||||
@Body
|
@Body
|
||||||
</MudMainContent>
|
</MudMainContent>
|
||||||
</div>
|
</div>
|
||||||
@ -67,4 +77,48 @@
|
|||||||
cache.Set("redirectUrl", page);
|
cache.Set("redirectUrl", page);
|
||||||
navManager.NavigateTo(page);
|
navManager.NavigateTo(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task GoToExternal(string url, string content) {
|
||||||
|
IJSObjectReference windowModule = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "./js/OpenInNewWindow.js");
|
||||||
|
await windowModule.InvokeAsync<object>("OpenInNewWindow", url, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GoToOldSite() {
|
||||||
|
try {
|
||||||
|
User? currentUser = authStateProvider.CurrentUser;
|
||||||
|
|
||||||
|
AuthTokens? authTokens = await authenticationService.GetAuthTokens();
|
||||||
|
|
||||||
|
if (currentUser is null || authTokens is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navManager.NavigateTo("login");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthAttempt authAttempt = new() {
|
||||||
|
LoginID = currentUser.LoginID,
|
||||||
|
AuthTokens = authTokens
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpClient httpClient = httpClientFactory.CreateClient("OldSite");
|
||||||
|
|
||||||
|
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "Account/ExternalAuthSetup");
|
||||||
|
|
||||||
|
request.Content = new StringContent(JsonSerializer.Serialize(authAttempt),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request);
|
||||||
|
|
||||||
|
if (httpResponseMessage.IsSuccessStatusCode) {
|
||||||
|
snackbar.Add("Old site auth setup successful", Severity.Success);
|
||||||
|
} else {
|
||||||
|
snackbar.Add($"Old site auth setup failed, because {httpResponseMessage.ReasonPhrase}", Severity.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
await GoToExternal($"{Configuration["OldFabApprovalUrl"]}", "");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
snackbar.Add($"Unable to go to old site, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -7,16 +7,23 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
|
<Watch Include="**\*.razor" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.6" />
|
</ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.6" PrivateAssets="all" />
|
<ItemGroup>
|
||||||
|
<Watch Remove="Pages\Components\PCRBApproverForm.razor" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.8" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.6" />
|
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
|
||||||
<PackageReference Include="MudBlazor" Version="6.20.0" />
|
<PackageReference Include="MudBlazor" Version="7.6.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.6.1" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("redirectPath", out var redirectPath)) {
|
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("redirectPath", out var redirectPath)) {
|
||||||
_redirectPath = System.Net.WebUtility.UrlDecode(redirectPath);
|
_redirectPath = redirectPath.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(_jwt) && !string.IsNullOrWhiteSpace(_refreshToken)) {
|
if (!string.IsNullOrWhiteSpace(_jwt) && !string.IsNullOrWhiteSpace(_refreshToken)) {
|
||||||
@ -35,11 +35,12 @@
|
|||||||
|
|
||||||
string loginId = userService.GetLoginIdFromClaimsPrincipal(principal);
|
string loginId = userService.GetLoginIdFromClaimsPrincipal(principal);
|
||||||
|
|
||||||
|
await authService.ClearCurrentUser();
|
||||||
|
await authService.ClearTokens();
|
||||||
|
|
||||||
await authService.SetLoginId(loginId);
|
await authService.SetLoginId(loginId);
|
||||||
await authService.SetTokens(_jwt, _refreshToken);
|
await authService.SetTokens(_jwt, _refreshToken);
|
||||||
|
await authService.SetCurrentUser(null);
|
||||||
User? user = await userService.GetUserByLoginId(loginId);
|
|
||||||
await authService.SetCurrentUser(user);
|
|
||||||
|
|
||||||
await authStateProvider.StateHasChanged(principal);
|
await authStateProvider.StateHasChanged(principal);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<MudDialog>
|
<MudDialog>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<MudPaper Class="p-2">
|
<MudPaper Class="m-2 p-2">
|
||||||
<MudForm @bind-Errors="@errors">
|
<MudForm @bind-Errors="@errors">
|
||||||
<MudTextField T="string"
|
<MudTextField T="string"
|
||||||
Label="Comments"
|
Label="Comments"
|
||||||
@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
private bool processing = false;
|
private bool processing = false;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync() {
|
protected override void OnParametersSet() {
|
||||||
comments = string.Empty;
|
comments = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +64,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Cancel() {
|
private void Cancel() {
|
||||||
MudDialog.Cancel();
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,115 @@
|
|||||||
|
@inject ISnackbar snackbar
|
||||||
|
@inject IMRBService mrbService
|
||||||
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
<MudPaper Class="m-2 p-2">
|
||||||
|
<MudForm @bind-Errors="@errors">
|
||||||
|
<MudTextField T="string"
|
||||||
|
Label="Comments"
|
||||||
|
Required="true"
|
||||||
|
RequiredError="You must provide a comment"
|
||||||
|
@bind-Value="@comments"
|
||||||
|
@bind-Text="@comments"
|
||||||
|
Immediate="true"
|
||||||
|
AutoGrow
|
||||||
|
AutoFocus/>
|
||||||
|
<MudFileUpload T="IReadOnlyList<IBrowserFile>" OnFilesChanged="AddAttachments">
|
||||||
|
<ActivatorContent>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
style="margin: auto;"
|
||||||
|
StartIcon="@Icons.Material.Filled.AttachFile">
|
||||||
|
@if (attachmentUploadInProcess) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
} else {
|
||||||
|
<MudText>Upload Supporting Document</MudText>
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
</ActivatorContent>
|
||||||
|
</MudFileUpload>
|
||||||
|
</MudForm>
|
||||||
|
</MudPaper>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=SubmitComments>
|
||||||
|
@if (processing) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
} else {
|
||||||
|
<MudText>Ok</MudText>
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Class="grey text-black m1-auto"
|
||||||
|
OnClick=Cancel>
|
||||||
|
Cancel
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string comments { get; set; } = "";
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int actionId { get; set; } = 0;
|
||||||
|
|
||||||
|
private string[] errors = { };
|
||||||
|
|
||||||
|
private bool processing = false;
|
||||||
|
private bool attachmentUploadInProcess = false;
|
||||||
|
|
||||||
|
protected override void OnParametersSet() {
|
||||||
|
comments = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SubmitComments() {
|
||||||
|
processing = true;
|
||||||
|
try {
|
||||||
|
if (string.IsNullOrWhiteSpace(comments) || comments.Length < 5)
|
||||||
|
throw new Exception("Comments must be at least five characters long");
|
||||||
|
|
||||||
|
MudDialog.Close(DialogResult.Ok(comments));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
snackbar.Add(ex.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
processing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddAttachments(InputFileChangeEventArgs args) {
|
||||||
|
attachmentUploadInProcess = true;
|
||||||
|
try {
|
||||||
|
if (actionId <= 0)
|
||||||
|
throw new Exception($"{actionId} is not a valid MRB action ID");
|
||||||
|
|
||||||
|
IReadOnlyList<IBrowserFile> attachments = args.GetMultipleFiles();
|
||||||
|
|
||||||
|
if (authStateProvider.CurrentUser is not null) {
|
||||||
|
await mrbService.UploadActionAttachments(attachments, actionId);
|
||||||
|
|
||||||
|
await mrbService.GetAllActionAttachmentsForMRB(actionId, true);
|
||||||
|
|
||||||
|
attachmentUploadInProcess = false;
|
||||||
|
|
||||||
|
snackbar.Add("Attachments successfully uploaded", Severity.Success);
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
attachmentUploadInProcess = false;
|
||||||
|
snackbar.Add($"Unable to upload attachments, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,48 +1,110 @@
|
|||||||
@inject IMRBService mrbService
|
@inject IMRBService mrbService
|
||||||
@inject ISnackbar snackbar
|
@inject ISnackbar snackbar
|
||||||
|
@inject ICustomerService customerService
|
||||||
|
|
||||||
<MudDialog>
|
<MudDialog>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<MudPaper Class="p-2">
|
<MudPaper Class="m-2 p-2">
|
||||||
<MudForm @bind-Errors="@errors">
|
<MudForm @bind-Errors="@errors">
|
||||||
<MudSelect T="string"
|
<MudSelect T="string"
|
||||||
Label="Action"
|
Label="Action"
|
||||||
|
Disabled="@(!string.IsNullOrWhiteSpace(mrbAction.Action))"
|
||||||
Required="true"
|
Required="true"
|
||||||
RequiredError="You must select an action!"
|
RequiredError="You must select an action!"
|
||||||
@bind-Value="@mrbAction.Action"
|
@bind-Value="@mrbAction.Action"
|
||||||
Text="@mrbAction.Action">
|
Text="@mrbAction.Action">
|
||||||
<MudSelectItem Value="@("Block")" />
|
<MudSelectItem Value="@("Block")" />
|
||||||
<MudSelectItem Value="@("Convert")" />
|
<MudSelectItem Value="@("Convert")" />
|
||||||
<MudSelectItem Value="@("Other")" />
|
|
||||||
<MudSelectItem Value="@("Recall")" />
|
<MudSelectItem Value="@("Recall")" />
|
||||||
<MudSelectItem Value="@("Scrap")" />
|
<MudSelectItem Value="@("Scrap")" />
|
||||||
<MudSelectItem Value="@("Unblock")" />
|
<MudSelectItem Value="@("Unblock")" />
|
||||||
<MudSelectItem Value="@("Waiver")" />
|
<MudSelectItem Value="@("Waiver")" />
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
<MudTextField T="string"
|
@if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
Label="Customer / Vendor"
|
<MudSelect T="string"
|
||||||
Required="true"
|
Label="Convert From Customer"
|
||||||
RequiredError="Customer / Vendor required!"
|
Required
|
||||||
@bind-Value="@mrbAction.Customer"
|
Variant="Variant.Outlined"
|
||||||
Text="@mrbAction.Customer" />
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=convertFromCustomer
|
||||||
|
Text="@convertFromCustomer">
|
||||||
|
@foreach (string customer in customerNames) {
|
||||||
|
<MudSelectItem Value="@(customer)" />
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
<MudTextField @bind-Value="@convertFromPart"
|
||||||
|
Label="Convert From Part Number"
|
||||||
|
Required
|
||||||
|
RequiredError="Part number required!"
|
||||||
|
Text="@convertFromPart" />
|
||||||
|
<MudSelect T="string"
|
||||||
|
Label="Convert To Customer"
|
||||||
|
Required
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=convertToCustomer
|
||||||
|
Text="@convertToCustomer">
|
||||||
|
@foreach (string customer in customerNames) {
|
||||||
|
<MudSelectItem Value="@(customer)" />
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
<MudTextField @bind-Value="@convertToPart"
|
||||||
|
Label="Convert To Part Number"
|
||||||
|
Required
|
||||||
|
RequiredError="Part number required!"
|
||||||
|
Text="@convertToPart" />
|
||||||
|
} else {
|
||||||
|
<MudSelect T="string"
|
||||||
|
Label="Affected Customer"
|
||||||
|
Required
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=mrbAction.Customer
|
||||||
|
Text="@mrbAction.Customer">
|
||||||
|
@foreach (string customer in customerNames) {
|
||||||
|
<MudSelectItem Value="@(customer)" />
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
<MudAutocomplete T="string"
|
||||||
|
Label="Part Number"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=mrbAction.PartNumber
|
||||||
|
Text="@mrbAction.PartNumber"
|
||||||
|
SearchFunc="@PartNumberSearch"
|
||||||
|
ResetValueOnEmptyText
|
||||||
|
CoerceText />
|
||||||
|
}
|
||||||
<MudTextField T="int"
|
<MudTextField T="int"
|
||||||
|
InputType="@InputType.Number"
|
||||||
Label="Qty"
|
Label="Qty"
|
||||||
Required="true"
|
Required="true"
|
||||||
RequiredError="You must supply a quantity!"
|
RequiredError="You must supply a quantity!"
|
||||||
@bind-Value=mrbAction.Quantity
|
@bind-Value=mrbAction.Quantity
|
||||||
Text="@mrbAction.Quantity.ToString()" />
|
Text="@mrbAction.Quantity.ToString()" />
|
||||||
<MudTextField T="string"
|
<MudAutocomplete T="string"
|
||||||
Label="Part Number"
|
|
||||||
Required="true"
|
|
||||||
RequiredError="Part number required!"
|
|
||||||
@bind-Value="@mrbAction.PartNumber"
|
|
||||||
Text="@mrbAction.PartNumber" />
|
|
||||||
<MudTextField T="string"
|
|
||||||
Label="Batch Number / Lot Number"
|
Label="Batch Number / Lot Number"
|
||||||
Required="true"
|
Variant="Variant.Outlined"
|
||||||
RequiredError="Batch number / Lot number required!"
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
@bind-Value="@mrbAction.LotNumber"
|
@bind-Value=mrbAction.LotNumber
|
||||||
Text="@mrbAction.LotNumber" />
|
Text="@mrbAction.LotNumber"
|
||||||
|
SearchFunc="@LotNumberSearch"
|
||||||
|
ResetValueOnEmptyText
|
||||||
|
CoerceText />
|
||||||
|
@if (mrbAction.Action.Equals("Scrap")) {
|
||||||
|
<MudSelect T="string"
|
||||||
|
Label="Justification"
|
||||||
|
Required
|
||||||
|
RequiredError="Justification required!"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=mrbAction.Justification
|
||||||
|
Text="@mrbAction.Justification">
|
||||||
|
<MudSelectItem Value="@("Obsolete")" />
|
||||||
|
<MudSelectItem Value="@("Aged Material")" />
|
||||||
|
<MudSelectItem Value="@("Out of Specification")" />
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
</MudForm>
|
</MudForm>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
@ -86,6 +148,17 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public MRBAction mrbAction { get; set; }
|
public MRBAction mrbAction { get; set; }
|
||||||
|
|
||||||
|
private IEnumerable<MRBAction>? actions = null;
|
||||||
|
|
||||||
|
private MRBAction lastAction = null;
|
||||||
|
|
||||||
|
private IEnumerable<string> customerNames = new List<string>();
|
||||||
|
|
||||||
|
private string convertFromCustomer = string.Empty;
|
||||||
|
private string convertFromPart = string.Empty;
|
||||||
|
private string convertToCustomer = string.Empty;
|
||||||
|
private string convertToPart = string.Empty;
|
||||||
|
|
||||||
private bool isVisible { get; set; }
|
private bool isVisible { get; set; }
|
||||||
private string[] errors = { };
|
private string[] errors = { };
|
||||||
private bool processingSave = false;
|
private bool processingSave = false;
|
||||||
@ -95,16 +168,46 @@
|
|||||||
isVisible = true;
|
isVisible = true;
|
||||||
|
|
||||||
if (mrbAction is null) {
|
if (mrbAction is null) {
|
||||||
mrbAction = new() {
|
snackbar.Add("MRB action cannot be null", Severity.Warning);
|
||||||
Action = "",
|
MudDialog.Cancel();
|
||||||
Customer = "",
|
} else {
|
||||||
Quantity = 0,
|
actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, false)).OrderByDescending(a => a.ActionID);
|
||||||
PartNumber = "",
|
|
||||||
LotNumber = "",
|
if (actions is not null && actions.Count() > 0) {
|
||||||
MRBNumber = 0
|
if (string.IsNullOrWhiteSpace(mrbAction.Action))
|
||||||
};
|
mrbAction.Action = actions.First().Action;
|
||||||
|
if (string.IsNullOrWhiteSpace(mrbAction.Customer))
|
||||||
|
mrbAction.Customer = actions.First().Customer;
|
||||||
|
if (string.IsNullOrWhiteSpace(mrbAction.LotNumber))
|
||||||
|
mrbAction.LotNumber = actions.First().LotNumber;
|
||||||
|
if (string.IsNullOrWhiteSpace(mrbAction.PartNumber))
|
||||||
|
mrbAction.PartNumber = actions.First().PartNumber;
|
||||||
|
if (string.IsNullOrWhiteSpace(mrbAction.Justification))
|
||||||
|
mrbAction.Justification = actions.First().Justification;
|
||||||
|
if (mrbAction.Quantity == 0)
|
||||||
|
mrbAction.Quantity = actions.First().Quantity;
|
||||||
|
|
||||||
|
if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
string[] convertFrom = actions.First().ConvertFrom.Split(" ");
|
||||||
|
if (convertFrom.Length > 1) {
|
||||||
|
convertFromCustomer = convertFrom[0];
|
||||||
|
foreach (string partStr in convertFrom.Skip(1))
|
||||||
|
convertFromPart += partStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string[] convertTo = actions.First().ConvertTo.Split(" ");
|
||||||
|
if (convertTo.Length > 1) {
|
||||||
|
convertToCustomer = convertTo[0];
|
||||||
|
foreach (string partStr in convertTo.Skip(1))
|
||||||
|
convertToPart += partStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customerNames is null || customerNames.Count() <= 0)
|
||||||
|
customerNames = await customerService.GetAllCustomerNames();
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,9 +215,22 @@
|
|||||||
bool actionIsValid = mrbAction.Action.Equals("Block") || mrbAction.Action.Equals("Convert") ||
|
bool actionIsValid = mrbAction.Action.Equals("Block") || mrbAction.Action.Equals("Convert") ||
|
||||||
mrbAction.Action.Equals("Other") || mrbAction.Action.Equals("Recall") || mrbAction.Action.Equals("Scrap") ||
|
mrbAction.Action.Equals("Other") || mrbAction.Action.Equals("Recall") || mrbAction.Action.Equals("Scrap") ||
|
||||||
mrbAction.Action.Equals("Unblock") || mrbAction.Action.Equals("Waiver");
|
mrbAction.Action.Equals("Unblock") || mrbAction.Action.Equals("Waiver");
|
||||||
return actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Customer) &&
|
actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Customer) &&
|
||||||
!string.IsNullOrWhiteSpace(mrbAction.PartNumber) &&
|
!string.IsNullOrWhiteSpace(mrbAction.PartNumber) &&
|
||||||
!string.IsNullOrWhiteSpace(mrbAction.LotNumber);
|
!string.IsNullOrWhiteSpace(mrbAction.LotNumber);
|
||||||
|
actionIsValid = actionIsValid && mrbAction.Quantity > 0;
|
||||||
|
|
||||||
|
if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(convertFromCustomer) &&
|
||||||
|
!string.IsNullOrWhiteSpace(convertFromPart) &&
|
||||||
|
!string.IsNullOrWhiteSpace(convertToCustomer) &&
|
||||||
|
!string.IsNullOrWhiteSpace(convertToPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mrbAction.Action.Equals("Scrap", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Justification);
|
||||||
|
|
||||||
|
return actionIsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SaveMRBAction() {
|
private async void SaveMRBAction() {
|
||||||
@ -122,6 +238,11 @@
|
|||||||
try {
|
try {
|
||||||
if (!FormIsValid()) throw new Exception("You must complete the form before saving!");
|
if (!FormIsValid()) throw new Exception("You must complete the form before saving!");
|
||||||
|
|
||||||
|
if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
mrbAction.ConvertFrom = $"{convertFromCustomer} {convertFromPart}";
|
||||||
|
mrbAction.ConvertTo = $"{convertToCustomer} {convertToPart}";
|
||||||
|
}
|
||||||
|
|
||||||
if (mrbAction.MRBNumber > 0) {
|
if (mrbAction.MRBNumber > 0) {
|
||||||
if (mrbAction.ActionID <= 0) {
|
if (mrbAction.ActionID <= 0) {
|
||||||
await mrbService.CreateMRBAction(mrbAction);
|
await mrbService.CreateMRBAction(mrbAction);
|
||||||
@ -130,10 +251,14 @@
|
|||||||
await mrbService.UpdateMRBAction(mrbAction);
|
await mrbService.UpdateMRBAction(mrbAction);
|
||||||
snackbar.Add("MRB action updated", Severity.Success);
|
snackbar.Add("MRB action updated", Severity.Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, true)).OrderByDescending(a => a.ActionID);
|
||||||
} else {
|
} else {
|
||||||
snackbar.Add("MRB action saved", Severity.Success);
|
snackbar.Add("MRB action saved", Severity.Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
|
||||||
MudDialog.Close(DialogResult.Ok(mrbAction));
|
MudDialog.Close(DialogResult.Ok(mrbAction));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
snackbar.Add(ex.Message, Severity.Error);
|
snackbar.Add(ex.Message, Severity.Error);
|
||||||
@ -153,6 +278,8 @@
|
|||||||
await mrbService.DeleteMRBAction(mrbAction);
|
await mrbService.DeleteMRBAction(mrbAction);
|
||||||
snackbar.Add("MRB action successfully deleted", Severity.Success);
|
snackbar.Add("MRB action successfully deleted", Severity.Success);
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
|
||||||
MudDialog.Close(DialogResult.Ok<MRBAction>(null));
|
MudDialog.Close(DialogResult.Ok<MRBAction>(null));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
snackbar.Add(ex.Message, Severity.Error);
|
snackbar.Add(ex.Message, Severity.Error);
|
||||||
@ -163,4 +290,38 @@
|
|||||||
private void Cancel() {
|
private void Cancel() {
|
||||||
MudDialog.Cancel();
|
MudDialog.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<string>> PartNumberSearch(string value, CancellationToken token) {
|
||||||
|
if (actions is null) return new List<string> { value };
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(value)) return new string[0];
|
||||||
|
|
||||||
|
HashSet<string> partNumbers = new();
|
||||||
|
|
||||||
|
partNumbers.Add(value);
|
||||||
|
|
||||||
|
foreach (MRBAction action in actions) {
|
||||||
|
if (action.PartNumber.Contains(value, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
partNumbers.Add(action.PartNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partNumbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<string>> LotNumberSearch(string value, CancellationToken token) {
|
||||||
|
if (actions is null) return new List<string> { value };
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(value)) return new string[0];
|
||||||
|
|
||||||
|
HashSet<string> lotNumbers = new();
|
||||||
|
|
||||||
|
lotNumbers.Add(value);
|
||||||
|
|
||||||
|
foreach (MRBAction action in actions) {
|
||||||
|
if (action.LotNumber.Contains(value, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
lotNumbers.Add(action.LotNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lotNumbers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,111 @@
|
|||||||
|
@inject IApprovalService approvalService
|
||||||
|
@inject ISnackbar snackbar
|
||||||
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
@if (availableApprovers is not null) {
|
||||||
|
<MudPaper Class="m-2 p-2">
|
||||||
|
<MudSelect T="User"
|
||||||
|
Label="Select a User"
|
||||||
|
Required
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=selectedUser
|
||||||
|
Text="@(selectedUser is null ? "" : selectedUser.GetFullName())">
|
||||||
|
@foreach (User user in availableApprovers) {
|
||||||
|
<MudSelectItem Value="@user">
|
||||||
|
@user.GetFullName()
|
||||||
|
</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Submit>
|
||||||
|
<MudText>Submit</MudText>
|
||||||
|
</MudButton>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Secondary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Cancel>
|
||||||
|
<MudText>Cancel</MudText>
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
<MudOverlay Visible=processing DarkBackground="true" AutoClose="false">
|
||||||
|
<MudProgressCircular Color="Color.Info" Size="Size.Medium" Indeterminate="true" />
|
||||||
|
</MudOverlay>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public User selectedUser { get; set; }
|
||||||
|
|
||||||
|
private bool processing = false;
|
||||||
|
|
||||||
|
private HashSet<User> availableApprovers = new();
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync() {
|
||||||
|
try {
|
||||||
|
processing = true;
|
||||||
|
|
||||||
|
string roleName = "QA_PRE_APPROVAL";
|
||||||
|
string subRoleName = "QA_PRE_APPROVAL";
|
||||||
|
|
||||||
|
IEnumerable<User> qaApprovers = await GetApprovalGroupMembersForRoleAndSubRole(roleName, subRoleName);
|
||||||
|
|
||||||
|
foreach (User approver in qaApprovers)
|
||||||
|
availableApprovers.Add(approver);
|
||||||
|
|
||||||
|
roleName = "MRB Approver";
|
||||||
|
subRoleName = "MRBApprover";
|
||||||
|
|
||||||
|
IEnumerable<User> mrbApprovers = await GetApprovalGroupMembersForRoleAndSubRole(roleName, subRoleName);
|
||||||
|
|
||||||
|
foreach (User approver in mrbApprovers)
|
||||||
|
availableApprovers.Add(approver);
|
||||||
|
|
||||||
|
selectedUser = availableApprovers.First();
|
||||||
|
|
||||||
|
processing = false;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
processing = false;
|
||||||
|
snackbar.Add($"Unable to get all approvers, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Submit() {
|
||||||
|
MudDialog.Close(DialogResult.Ok(selectedUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<User>> GetApprovalGroupMembersForRoleAndSubRole(string roleName, string subRoleName) {
|
||||||
|
HashSet<User> members = new();
|
||||||
|
|
||||||
|
int roleId = await approvalService.GetRoleIdForRoleName(roleName);
|
||||||
|
|
||||||
|
if (roleId <= 0) throw new Exception($"could not find {roleName} role ID");
|
||||||
|
|
||||||
|
IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName(subRoleName, roleId);
|
||||||
|
|
||||||
|
foreach (SubRole subRole in subRoles) {
|
||||||
|
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
||||||
|
|
||||||
|
foreach (User member in subRoleMembers) {
|
||||||
|
members.Add(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
}
|
||||||
151
MesaFabApproval.Client/Pages/Components/PCR3DocumentForm.razor
Normal file
151
MesaFabApproval.Client/Pages/Components/PCR3DocumentForm.razor
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
@inject NavigationManager navigationManager
|
||||||
|
@inject IPCRBService pcrbService
|
||||||
|
@inject IUserService userService
|
||||||
|
@inject IECNService ecnService
|
||||||
|
@inject ISnackbar snackbar
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
<MudPaper Class="m-2 p-2">
|
||||||
|
<MudForm @bind-Errors="@errors">
|
||||||
|
<MudTextField T="string"
|
||||||
|
Label="Document Type"
|
||||||
|
@bind-Value="@document.DocType"
|
||||||
|
@bind-Text="@document.DocType"
|
||||||
|
Disabled
|
||||||
|
AutoGrow />
|
||||||
|
<MudTextField Label="Document Numbers - Rev. & Title"
|
||||||
|
@bind-Value="@document.DocNumbers"
|
||||||
|
@bind-Text="@document.DocNumbers"
|
||||||
|
Immediate
|
||||||
|
AutoGrow
|
||||||
|
AutoFocus />
|
||||||
|
@if (DocNumberIsNA()) {
|
||||||
|
<MudTextField Label="Comments"
|
||||||
|
@bind-Value="@document.Comment"
|
||||||
|
@bind-Text="@document.Comment"
|
||||||
|
Required
|
||||||
|
RequiredError="You must provide a comment"
|
||||||
|
Immediate
|
||||||
|
AutoGrow />
|
||||||
|
} else {
|
||||||
|
<MudTextField @bind-Value="@document.ECNNumber"
|
||||||
|
Required
|
||||||
|
RequiredError="You must provide a valid ECN#"
|
||||||
|
Clearable
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
InputType="@InputType.Number"
|
||||||
|
Validation="@(new Func<int, Task<string>>(ECNNoIsValid))"
|
||||||
|
Label="ECN#"
|
||||||
|
Immediate
|
||||||
|
AutoGrow />
|
||||||
|
}
|
||||||
|
<MudCheckBox Label="Complete"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
@bind-Value=complete
|
||||||
|
LabelPosition="LabelPosition.Start" />
|
||||||
|
</MudForm>
|
||||||
|
</MudPaper>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
@if ((DocNumberIsNA() && !string.IsNullOrWhiteSpace(document.Comment)) ||
|
||||||
|
(!DocNumberIsNA() && ecnNoIsValid)) {
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Save>
|
||||||
|
@if (saveInProcess) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
} else {
|
||||||
|
<MudText>Save</MudText>
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
}
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Class="grey text-black m1-auto"
|
||||||
|
OnClick=Cancel>
|
||||||
|
Cancel
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter]
|
||||||
|
MudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public required PCR3Document document { get; set; }
|
||||||
|
|
||||||
|
private string[] errors = { };
|
||||||
|
|
||||||
|
private bool complete = false;
|
||||||
|
|
||||||
|
private bool saveInProcess = false;
|
||||||
|
|
||||||
|
private bool ecnNoIsValid = true;
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() {
|
||||||
|
complete = document.CompletedByID > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Save() {
|
||||||
|
saveInProcess = true;
|
||||||
|
try {
|
||||||
|
if (authStateProvider.CurrentUser is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navigationManager.NavigateTo("login");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!complete) {
|
||||||
|
document.CompletedByID = 0;
|
||||||
|
document.CompletedBy = null;
|
||||||
|
document.CompletedDate = DateTimeUtilities.MAX_DT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (complete && document.CompletedByID <= 0) {
|
||||||
|
document.CompletedByID = authStateProvider.CurrentUser.UserID;
|
||||||
|
document.CompletedBy = authStateProvider.CurrentUser;
|
||||||
|
document.CompletedDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DocNumberIsNA() && !ecnNoIsValid)
|
||||||
|
throw new Exception($"{document.ECNNumber} is not a valid ECN#");
|
||||||
|
if (DocNumberIsNA() && string.IsNullOrWhiteSpace(document.Comment))
|
||||||
|
throw new Exception("you must provide a comment");
|
||||||
|
|
||||||
|
await pcrbService.UpdatePCR3Document(document);
|
||||||
|
|
||||||
|
await pcrbService.GetPCR3DocumentsForPlanNumber(document.PlanNumber, true);
|
||||||
|
|
||||||
|
saveInProcess = false;
|
||||||
|
|
||||||
|
MudDialog.Close(DialogResult.Ok(document));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
saveInProcess = false;
|
||||||
|
snackbar.Add($"Unable to save document, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DocNumberIsNA() {
|
||||||
|
if (document.DocNumbers.ToLower().Equals("na") ||
|
||||||
|
document.DocNumbers.ToLower().Equals("n/a")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> ECNNoIsValid(int ecnNumber) {
|
||||||
|
string? result = await ecnService.ECNNumberIsValidStr(ecnNumber);
|
||||||
|
if (result is null) ecnNoIsValid = true;
|
||||||
|
else ecnNoIsValid = false;
|
||||||
|
StateHasChanged();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
201
MesaFabApproval.Client/Pages/Components/PCRBActionItemForm.razor
Normal file
201
MesaFabApproval.Client/Pages/Components/PCRBActionItemForm.razor
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
@inject NavigationManager navigationManager
|
||||||
|
@inject IPCRBService pcrbService
|
||||||
|
@inject IUserService userService
|
||||||
|
@inject ISnackbar snackbar
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
<MudPaper Class="m-2 p-2">
|
||||||
|
<MudForm @bind-Errors="@errors">
|
||||||
|
<MudTextField T="string"
|
||||||
|
Label="Action"
|
||||||
|
Required
|
||||||
|
RequiredError="Enter action item"
|
||||||
|
@bind-Value="@name"
|
||||||
|
@bind-Text="@name"
|
||||||
|
Immediate
|
||||||
|
Clearable
|
||||||
|
AutoGrow
|
||||||
|
AutoFocus />
|
||||||
|
<MudCheckBox Label="Gating"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
@bind-Value=gating
|
||||||
|
LabelPosition="LabelPosition.Start" />
|
||||||
|
<MudCheckBox Label="Closed"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
@bind-Value="@closedStatus"
|
||||||
|
LabelPosition="LabelPosition.Start" />
|
||||||
|
@if (closedStatus) {
|
||||||
|
<MudDatePicker Label="Closed Date"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
@bind-Date="@closedDate"
|
||||||
|
Clearable
|
||||||
|
MinDate="@DateTimeUtilities.MIN_DT"
|
||||||
|
MaxDate="@DateTimeUtilities.MAX_DT"
|
||||||
|
Placeholder="Select a closed date" />
|
||||||
|
}
|
||||||
|
<MudSelect T="User"
|
||||||
|
Label="Responsible Person"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
Required
|
||||||
|
RequiredError="You must select a responsible person"
|
||||||
|
Clearable
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
ToStringFunc="@UserToNameConverter"
|
||||||
|
@bind-Value=@responsiblePerson>
|
||||||
|
@foreach (User user in allActiveUsers.OrderBy(u => u.FirstName)) {
|
||||||
|
<MudSelectItem T="User" Value="@(user)" />
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
</MudForm>
|
||||||
|
</MudPaper>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Save>
|
||||||
|
@if (saveActionItemInProcess) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
} else {
|
||||||
|
<MudText>Submit</MudText>
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Class="grey text-black m1-auto"
|
||||||
|
OnClick=Cancel>
|
||||||
|
Cancel
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter]
|
||||||
|
MudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int planNumber { get; set; } = 0;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int step { get; set; } = 0;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public PCRBActionItem? actionItem { get; set; } = null;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public IEnumerable<User> allActiveUsers { get; set; }
|
||||||
|
|
||||||
|
private string[] errors = { };
|
||||||
|
|
||||||
|
private string name = "";
|
||||||
|
private bool gating = false;
|
||||||
|
private DateTime? closedDate = DateTimeUtilities.MAX_DT;
|
||||||
|
private bool closedStatus = false;
|
||||||
|
private User? responsiblePerson = null;
|
||||||
|
|
||||||
|
private bool saveActionItemInProcess = false;
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() {
|
||||||
|
if (authStateProvider.CurrentUser is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navigationManager.NavigateTo("login");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (planNumber <= 0) {
|
||||||
|
snackbar.Add($"{planNumber} is not a valid PCRB plan#", Severity.Error);
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allActiveUsers is null || allActiveUsers.Count() <= 0)
|
||||||
|
allActiveUsers = await userService.GetAllActiveUsers();
|
||||||
|
|
||||||
|
if (actionItem is not null) {
|
||||||
|
name = actionItem.Name;
|
||||||
|
gating = actionItem.Gating;
|
||||||
|
closedStatus = actionItem.ClosedStatus;
|
||||||
|
closedDate = actionItem.ClosedDate;
|
||||||
|
if (closedDate.Equals(DateTimeUtilities.MAX_DT)) {
|
||||||
|
closedDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
if (actionItem.ResponsiblePersonID > 0) {
|
||||||
|
if (actionItem.ResponsiblePerson is not null) responsiblePerson = actionItem.ResponsiblePerson;
|
||||||
|
else responsiblePerson = await userService.GetUserByUserId(actionItem.ResponsiblePersonID);
|
||||||
|
actionItem.ResponsiblePerson = responsiblePerson;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
name = "";
|
||||||
|
gating = false;
|
||||||
|
closedStatus = false;
|
||||||
|
closedDate = DateTime.Now;
|
||||||
|
responsiblePerson = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Save() {
|
||||||
|
saveActionItemInProcess = true;
|
||||||
|
try {
|
||||||
|
if (authStateProvider.CurrentUser is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navigationManager.NavigateTo("login");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(name)) throw new Exception("name missing");
|
||||||
|
|
||||||
|
if (actionItem is null) {
|
||||||
|
actionItem = new() {
|
||||||
|
Name = name,
|
||||||
|
UploadedBy = authStateProvider.CurrentUser,
|
||||||
|
UploadedByID = authStateProvider.CurrentUser.UserID,
|
||||||
|
PlanNumber = planNumber,
|
||||||
|
Step = step,
|
||||||
|
Gating = gating,
|
||||||
|
ClosedStatus = closedStatus,
|
||||||
|
ResponsiblePerson = responsiblePerson,
|
||||||
|
ResponsiblePersonID = responsiblePerson.UserID,
|
||||||
|
ClosedDate = closedDate,
|
||||||
|
ClosedBy = closedDate is null || closedDate >= DateTimeUtilities.MAX_DT ? null : authStateProvider.CurrentUser,
|
||||||
|
ClosedByID = closedStatus ? authStateProvider.CurrentUser.UserID : 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (actionItem.ClosedStatus == false) {
|
||||||
|
actionItem.ClosedDate = DateTimeUtilities.MAX_DT;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pcrbService.CreateNewActionItem(actionItem);
|
||||||
|
} else {
|
||||||
|
actionItem.Name = name;
|
||||||
|
actionItem.Gating = gating;
|
||||||
|
actionItem.ClosedStatus = closedStatus;
|
||||||
|
actionItem.ClosedDate = closedDate;
|
||||||
|
if (closedStatus) {
|
||||||
|
actionItem.ClosedBy = authStateProvider.CurrentUser;
|
||||||
|
actionItem.ClosedByID = authStateProvider.CurrentUser.UserID;
|
||||||
|
} else {
|
||||||
|
actionItem.ClosedDate = DateTimeUtilities.MAX_DT;
|
||||||
|
}
|
||||||
|
actionItem.ResponsiblePerson = responsiblePerson;
|
||||||
|
if (responsiblePerson is not null)
|
||||||
|
actionItem.ResponsiblePersonID = responsiblePerson.UserID;
|
||||||
|
|
||||||
|
await pcrbService.UpdateActionItem(actionItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveActionItemInProcess = false;
|
||||||
|
|
||||||
|
MudDialog.Close(DialogResult.Ok(actionItem));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
saveActionItemInProcess = false;
|
||||||
|
snackbar.Add($"Unable to save action item, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Func<User, string> UserToNameConverter = u => u is null ? string.Empty : u.GetFullName();
|
||||||
|
|
||||||
|
private Func<PCRBAttachment, string> AttachmentToFileNameConverter = a => a is null ? "" : a.FileName;
|
||||||
|
}
|
||||||
250
MesaFabApproval.Client/Pages/Components/PCRBApproverForm.razor
Normal file
250
MesaFabApproval.Client/Pages/Components/PCRBApproverForm.razor
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
@inject NavigationManager navigationManager
|
||||||
|
@inject IPCRBService pcrbService
|
||||||
|
@inject IUserService userService
|
||||||
|
@inject IApprovalService approvalService
|
||||||
|
@inject ISnackbar snackbar
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
<MudPaper Class="m-2 p-2">
|
||||||
|
<MudForm @bind-Errors="@errors">
|
||||||
|
<MudSelect T="string"
|
||||||
|
Label="Job Title"
|
||||||
|
Required
|
||||||
|
RequiredError="You must provide a job title"
|
||||||
|
ValueChanged="@SelectedJobTitleChanged"
|
||||||
|
@bind-Text="@selectedJobTitle"
|
||||||
|
Immediate
|
||||||
|
Disabled="@(approval is not null && !string.IsNullOrWhiteSpace(selectedJobTitle))"
|
||||||
|
Clearable
|
||||||
|
AutoFocus >
|
||||||
|
@foreach (string jt in availableJobTitles) {
|
||||||
|
<MudSelectItem Value="@jt">@jt</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
<MudSelect T="User"
|
||||||
|
Label="Select a User"
|
||||||
|
Required
|
||||||
|
Clearable
|
||||||
|
Disabled="@(string.IsNullOrWhiteSpace(selectedJobTitle))"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=selectedUser
|
||||||
|
ToStringFunc="@UserToNameConverter">
|
||||||
|
@foreach (User user in availableUsers) {
|
||||||
|
<MudSelectItem Value="@user">@user.GetFullName()</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
</MudForm>
|
||||||
|
</MudPaper>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Save>
|
||||||
|
@if (saveAttendeeInProcess) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
} else {
|
||||||
|
<MudText>Submit</MudText>
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Class="grey text-black m1-auto"
|
||||||
|
OnClick=Cancel>
|
||||||
|
Cancel
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter]
|
||||||
|
MudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int planNumber { get; set; } = 0;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int step { get; set; } = 0;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Approval? approval { get; set; } = null;
|
||||||
|
|
||||||
|
private HashSet<string> availableJobTitles = new();
|
||||||
|
|
||||||
|
private Dictionary<string, SubRole> jobTitleToSubRoleMap = new();
|
||||||
|
|
||||||
|
private Dictionary<string, IEnumerable<User>> jobTitleToAvailableUsersMap = new();
|
||||||
|
|
||||||
|
private HashSet<User> availableUsers = new();
|
||||||
|
|
||||||
|
private string[] errors = { };
|
||||||
|
|
||||||
|
private string selectedJobTitle = "";
|
||||||
|
private User? selectedUser = null;
|
||||||
|
|
||||||
|
private bool saveAttendeeInProcess = false;
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() {
|
||||||
|
if (authStateProvider.CurrentUser is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navigationManager.NavigateTo("login");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (planNumber <= 0) {
|
||||||
|
snackbar.Add($"{planNumber} is not a valid PCRB plan#", Severity.Error);
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
await GetAttendees();
|
||||||
|
|
||||||
|
if (approval is not null) {
|
||||||
|
selectedJobTitle = approval.RoleName;
|
||||||
|
if (approval.UserID > 0) {
|
||||||
|
if (approval.User is not null) {
|
||||||
|
selectedUser = approval.User;
|
||||||
|
} else {
|
||||||
|
selectedUser = await userService.GetUserByUserId(approval.UserID);
|
||||||
|
approval.User = selectedUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedJobTitleChanged(selectedJobTitle);
|
||||||
|
} else {
|
||||||
|
selectedJobTitle = "";
|
||||||
|
selectedUser = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Save() {
|
||||||
|
saveAttendeeInProcess = true;
|
||||||
|
try {
|
||||||
|
if (authStateProvider.CurrentUser is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navigationManager.NavigateTo("login");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(selectedJobTitle)) throw new Exception("job title missing");
|
||||||
|
if (selectedUser is null) throw new Exception("attendee not selected");
|
||||||
|
|
||||||
|
PCRB pcrb = await pcrbService.GetPCRBByPlanNumber(planNumber, false);
|
||||||
|
|
||||||
|
if (approval is null) {
|
||||||
|
jobTitleToSubRoleMap.TryGetValue($"{selectedJobTitle}{selectedUser.UserID}", out SubRole? subRole);
|
||||||
|
|
||||||
|
if (subRole is null) throw new Exception($"no approval role found for job title {selectedJobTitle}");
|
||||||
|
|
||||||
|
approval = new() {
|
||||||
|
RoleName = subRole.SubRoleCategoryItem,
|
||||||
|
SubRole = subRole.SubRoleName,
|
||||||
|
SubRoleID = subRole.SubRoleID,
|
||||||
|
IssueID = planNumber,
|
||||||
|
Step = step,
|
||||||
|
User = selectedUser,
|
||||||
|
UserID = selectedUser.UserID,
|
||||||
|
AssignedDate = DateTimeUtilities.MIN_DT
|
||||||
|
};
|
||||||
|
|
||||||
|
await approvalService.CreateApproval(approval);
|
||||||
|
} else {
|
||||||
|
int originalUserId = approval.UserID;
|
||||||
|
|
||||||
|
approval.UserID = selectedUser.UserID;
|
||||||
|
approval.User = selectedUser;
|
||||||
|
|
||||||
|
if (originalUserId != approval.UserID) {
|
||||||
|
if (approval.AssignedDate > DateTimeUtilities.MIN_DT)
|
||||||
|
approval.AssignedDate = DateTime.Now;
|
||||||
|
approval.NotifyDate = DateTimeUtilities.MIN_DT;
|
||||||
|
}
|
||||||
|
|
||||||
|
await approvalService.UpdateApproval(approval);
|
||||||
|
|
||||||
|
if (originalUserId != approval.UserID)
|
||||||
|
await pcrbService.NotifyNewApprovals(pcrb);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveAttendeeInProcess = false;
|
||||||
|
|
||||||
|
MudDialog.Close(DialogResult.Ok(approval));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
saveAttendeeInProcess = false;
|
||||||
|
snackbar.Add($"Unable to save attendee, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Func<User, string> UserToNameConverter = u => u is null ? string.Empty : u.GetFullName();
|
||||||
|
|
||||||
|
private async Task GetAttendees() {
|
||||||
|
int roleId = await approvalService.GetRoleIdForRoleName("Module Manager");
|
||||||
|
|
||||||
|
if (roleId <= 0) throw new Exception($"could not find Director role ID");
|
||||||
|
|
||||||
|
availableJobTitles.Clear();
|
||||||
|
jobTitleToAvailableUsersMap.Clear();
|
||||||
|
jobTitleToSubRoleMap.Clear();
|
||||||
|
|
||||||
|
IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName("MMSubRole", roleId);
|
||||||
|
|
||||||
|
HashSet<string> defaultSubRoleCategoryItems = new() { "Si Production", "Si Engineering", "Quality" };
|
||||||
|
HashSet<string> unusedSubRoleCategoryItems = new() { "GaN Engineering", "GaN Operations", "Integration" };
|
||||||
|
foreach (SubRole subRole in subRoles) {
|
||||||
|
if (approval is null) {
|
||||||
|
if (!defaultSubRoleCategoryItems.Contains(subRole.SubRoleCategoryItem) &&
|
||||||
|
!unusedSubRoleCategoryItems.Contains(subRole.SubRoleCategoryItem)) {
|
||||||
|
availableJobTitles.Add(subRole.SubRoleCategoryItem);
|
||||||
|
|
||||||
|
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
||||||
|
|
||||||
|
jobTitleToAvailableUsersMap.Add(subRole.SubRoleCategoryItem, subRoleMembers);
|
||||||
|
|
||||||
|
foreach (User member in subRoleMembers) {
|
||||||
|
jobTitleToSubRoleMap.Add($"{subRole.SubRoleCategoryItem}{member.UserID}", subRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!unusedSubRoleCategoryItems.Contains(subRole.SubRoleCategoryItem)) {
|
||||||
|
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
||||||
|
|
||||||
|
jobTitleToAvailableUsersMap.Add(subRole.SubRoleCategoryItem, subRoleMembers);
|
||||||
|
|
||||||
|
foreach (User member in subRoleMembers)
|
||||||
|
availableUsers.Add(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectedJobTitleChanged(string jobTitle) {
|
||||||
|
selectedJobTitle = jobTitle;
|
||||||
|
|
||||||
|
selectedUser = null;
|
||||||
|
|
||||||
|
availableUsers.Clear();
|
||||||
|
|
||||||
|
if (approval is null) {
|
||||||
|
if (jobTitleToAvailableUsersMap.TryGetValue(jobTitle, out IEnumerable<User>? jobTitleMembers)) {
|
||||||
|
if (jobTitleMembers is not null) {
|
||||||
|
foreach (User member in jobTitleMembers)
|
||||||
|
availableUsers.Add(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach (IEnumerable<User> memberList in jobTitleToAvailableUsersMap.Values) {
|
||||||
|
if (memberList is not null) {
|
||||||
|
foreach(User member in memberList) {
|
||||||
|
availableUsers.Add(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
140
MesaFabApproval.Client/Pages/Components/PCRBAttachmentForm.razor
Normal file
140
MesaFabApproval.Client/Pages/Components/PCRBAttachmentForm.razor
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
@inject NavigationManager navigationManager
|
||||||
|
@inject IPCRBService pcrbService
|
||||||
|
@inject ISnackbar snackbar
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
<MudPaper Class="m-2 p-2">
|
||||||
|
<MudForm @bind-Errors="@errors">
|
||||||
|
<MudTextField T="string"
|
||||||
|
Label="File Name"
|
||||||
|
Disabled
|
||||||
|
Immediate
|
||||||
|
@bind-Value="@fileName"
|
||||||
|
@bind-Text="@fileName"
|
||||||
|
AutoGrow />
|
||||||
|
<MudFileUpload T="IBrowserFile"
|
||||||
|
FilesChanged="AddFile"
|
||||||
|
Required
|
||||||
|
Disabled="@(!string.IsNullOrWhiteSpace(fileName))"
|
||||||
|
RequiredError="You must select a file">
|
||||||
|
<ActivatorContent>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
style="margin: auto;"
|
||||||
|
StartIcon="@Icons.Material.Filled.AttachFile">
|
||||||
|
@if (addFileInProcess) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
} else {
|
||||||
|
<MudText>Add File</MudText>
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
</ActivatorContent>
|
||||||
|
</MudFileUpload>
|
||||||
|
</MudForm>
|
||||||
|
</MudPaper>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Submit>
|
||||||
|
@if (processing) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
<MudText>Submit</MudText>
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Class="grey text-black m1-auto"
|
||||||
|
OnClick=Cancel>
|
||||||
|
Cancel
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int planNumber { get; set; } = 0;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int step { get; set; } = 0;
|
||||||
|
|
||||||
|
private string[] errors = { };
|
||||||
|
|
||||||
|
private string fileName = "";
|
||||||
|
|
||||||
|
private IBrowserFile? file = null;
|
||||||
|
|
||||||
|
private bool addFileInProcess = false;
|
||||||
|
private bool processing = false;
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() {
|
||||||
|
if (planNumber <= 0) {
|
||||||
|
snackbar.Add($"{planNumber} is not a valid PCRB plan#", Severity.Error);
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step <= 0) {
|
||||||
|
snackbar.Add($"{step} is not a valid PCRB stage#", Severity.Error);
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authStateProvider.CurrentUser is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navigationManager.NavigateTo("login");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddFile(IBrowserFile newFile) {
|
||||||
|
addFileInProcess = true;
|
||||||
|
file = newFile;
|
||||||
|
fileName = newFile.Name;
|
||||||
|
addFileInProcess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Submit() {
|
||||||
|
processing = true;
|
||||||
|
try {
|
||||||
|
if (authStateProvider.CurrentUser is null) {
|
||||||
|
await authStateProvider.Logout();
|
||||||
|
navigationManager.NavigateTo("login");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(fileName))
|
||||||
|
throw new Exception("file name missing");
|
||||||
|
|
||||||
|
if (file is null)
|
||||||
|
throw new Exception("file is missing");
|
||||||
|
|
||||||
|
PCRBAttachment attachment = new() {
|
||||||
|
Step = step,
|
||||||
|
UploadDateTime = DateTime.Now,
|
||||||
|
UploadedByID = authStateProvider.CurrentUser.UserID,
|
||||||
|
PlanNumber = planNumber,
|
||||||
|
File = file,
|
||||||
|
FileName = fileName
|
||||||
|
};
|
||||||
|
|
||||||
|
await pcrbService.UploadAttachment(attachment);
|
||||||
|
|
||||||
|
processing = false;
|
||||||
|
|
||||||
|
MudDialog.Close(DialogResult.Ok(attachment));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
snackbar.Add($"Unable to save document, because {ex.Message}", Severity.Error);
|
||||||
|
processing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
}
|
||||||
74
MesaFabApproval.Client/Pages/Components/UserSelector.razor
Normal file
74
MesaFabApproval.Client/Pages/Components/UserSelector.razor
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
@inject IUserService userService
|
||||||
|
@inject ISnackbar snackbar
|
||||||
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
@if (allUsers is not null) {
|
||||||
|
<MudPaper Class="p-2">
|
||||||
|
<MudSelect T="User"
|
||||||
|
Label="Select a User"
|
||||||
|
Required
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
|
@bind-Value=selectedUser
|
||||||
|
Text="@(selectedUser is null ? "" : selectedUser.GetFullName())">
|
||||||
|
@foreach (User user in allUsers) {
|
||||||
|
<MudSelectItem Value="@user">
|
||||||
|
@user.GetFullName()
|
||||||
|
</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Submit>
|
||||||
|
<MudText>Submit</MudText>
|
||||||
|
</MudButton>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Secondary"
|
||||||
|
Class="m1-auto"
|
||||||
|
OnClick=Cancel>
|
||||||
|
<MudText>Cancel</MudText>
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
<MudOverlay Visible=processing DarkBackground="true" AutoClose="false">
|
||||||
|
<MudProgressCircular Color="Color.Info" Size="Size.Medium" Indeterminate="true" />
|
||||||
|
</MudOverlay>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public User selectedUser { get; set; }
|
||||||
|
|
||||||
|
private bool processing = false;
|
||||||
|
|
||||||
|
private IEnumerable<User> allUsers = new List<User>();
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync() {
|
||||||
|
try {
|
||||||
|
processing = true;
|
||||||
|
selectedUser = authStateProvider.CurrentUser;
|
||||||
|
allUsers = await userService.GetAllActiveUsers();
|
||||||
|
processing = false;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
processing = false;
|
||||||
|
snackbar.Add($"Unable to get all users, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Submit() {
|
||||||
|
MudDialog.Close(DialogResult.Ok(selectedUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
MudDialog.Close(DialogResult.Cancel());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,18 +1,27 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@page "/Dashboard"
|
@page "/Dashboard"
|
||||||
|
@inject IConfiguration Configuration
|
||||||
@inject MesaFabApprovalAuthStateProvider stateProvider
|
@inject MesaFabApprovalAuthStateProvider stateProvider
|
||||||
@inject IApprovalService approvalService
|
@inject IApprovalService approvalService
|
||||||
@inject IMemoryCache cache
|
@inject IMemoryCache cache
|
||||||
@inject NavigationManager navigationManager
|
@inject NavigationManager navigationManager
|
||||||
@inject ISnackbar snackbar
|
@inject ISnackbar snackbar
|
||||||
|
@inject IMRBService mrbService
|
||||||
|
@inject IPCRBService pcrbService
|
||||||
|
@inject IECNService ecnService
|
||||||
|
@inject ICAService caService
|
||||||
|
@inject IJSRuntime jsRuntime
|
||||||
|
|
||||||
<PageTitle>Dashboard</PageTitle>
|
<PageTitle>Dashboard</PageTitle>
|
||||||
|
|
||||||
<MudPaper Class="p-2 m-2" MinWidth="100%">
|
<MudPaper Class="p-2 m-2">
|
||||||
<MudText Typo="Typo.h3" Align="Align.Center">Dashboard</MudText>
|
<MudText Typo="Typo.h3" Align="Align.Center">Dashboard</MudText>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
|
||||||
@if (stateProvider.CurrentUser is not null && approvalList is not null) {
|
<MudPaper Class="p-2 m-2">
|
||||||
|
<MudTabs Class="p-2" Rounded Centered Color="Color.Info" MinimumTabWidth="50%">
|
||||||
|
<MudTabPanel Text="My Active Approvals" Style="min-width:50%; text-align: center;">
|
||||||
|
@if (stateProvider.CurrentUser is not null && approvalList is not null && !myApprovalsProcessing) {
|
||||||
<MudPaper Outlined="true"
|
<MudPaper Outlined="true"
|
||||||
Class="p-2 m-2 d-flex flex-column justify-center">
|
Class="p-2 m-2 d-flex flex-column justify-center">
|
||||||
<MudText Typo="Typo.h4" Align="Align.Center">My Active Approvals</MudText>
|
<MudText Typo="Typo.h4" Align="Align.Center">My Active Approvals</MudText>
|
||||||
@ -23,12 +32,12 @@
|
|||||||
SortLabel="Sort by">
|
SortLabel="Sort by">
|
||||||
<HeaderContent>
|
<HeaderContent>
|
||||||
<MudTh>
|
<MudTh>
|
||||||
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<Approval,object>(x=>x.IssueID)">
|
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.IssueID)">
|
||||||
Issue ID
|
Issue ID
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
<MudTh>
|
<MudTh>
|
||||||
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<Approval,object>(x=>x.SubRoleCategoryItem)">
|
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.SubRoleCategoryItem)">
|
||||||
Role
|
Role
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
@ -38,14 +47,16 @@
|
|||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
<MudTh>
|
<MudTh>
|
||||||
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<Approval,object>(x=>x.Step)">
|
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.Step)">
|
||||||
Step
|
Step
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
</HeaderContent>
|
</HeaderContent>
|
||||||
<RowTemplate>
|
<RowTemplate>
|
||||||
<MudTd DataLabel="Issue ID">
|
<MudTd DataLabel="Issue ID">
|
||||||
<MudLink OnClick="@(() => GoTo($"/mrb/{context.IssueID}"))">@context.IssueID</MudLink>
|
@if (context.IssueID > 0) {
|
||||||
|
<MudLink OnClick="@(() => FollowLink(context.IssueID))">@context.IssueID</MudLink>
|
||||||
|
}
|
||||||
</MudTd>
|
</MudTd>
|
||||||
<MudTd DataLabel="Role">@context.SubRoleCategoryItem</MudTd>
|
<MudTd DataLabel="Role">@context.SubRoleCategoryItem</MudTd>
|
||||||
<MudTd DataLabel="Assigned Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.AssignedDate)</MudTd>
|
<MudTd DataLabel="Assigned Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.AssignedDate)</MudTd>
|
||||||
@ -56,22 +67,297 @@
|
|||||||
</PagerContent>
|
</PagerContent>
|
||||||
</MudTable>
|
</MudTable>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
} else {
|
||||||
|
<MudOverlay Visible DarkBackground="true" AutoClose="false">
|
||||||
|
<MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText>
|
||||||
|
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
|
||||||
|
</MudOverlay>
|
||||||
}
|
}
|
||||||
|
</MudTabPanel>
|
||||||
|
<MudTabPanel Text="My MRBs" Style="min-width:50%; text-align: center;">
|
||||||
|
@if (stateProvider.CurrentUser is not null && myMRBs is not null && !myMrbsProcessing) {
|
||||||
|
<MudPaper Outlined="true"
|
||||||
|
Class="p-2 m-2 d-flex flex-column justify-center">
|
||||||
|
<MudText Typo="Typo.h4" Align="Align.Center">My MRBs</MudText>
|
||||||
|
<MudDivider DividerType="DividerType.Middle" Class="my-2" />
|
||||||
|
<MudTable Items="@myMRBs"
|
||||||
|
Class="m-2"
|
||||||
|
Striped
|
||||||
|
SortLabel="Sort by"
|
||||||
|
Filter="new Func<MRB, bool>(FilterFuncForMRBTable)">
|
||||||
|
<ToolBarContent>
|
||||||
|
<MudSpacer />
|
||||||
|
<MudTextField @bind-Value="mrbSearchString"
|
||||||
|
Placeholder="Search"
|
||||||
|
Immediate
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||||
|
IconSize="Size.Medium"
|
||||||
|
Class="mt-0" />
|
||||||
|
</ToolBarContent>
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<MRB,object>(x=>x.MRBNumber)">
|
||||||
|
MRB#
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.Title)">
|
||||||
|
Title
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.SubmittedDate)">
|
||||||
|
Submitted Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.ApprovalDate)">
|
||||||
|
Approval Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CancelDate)">
|
||||||
|
Cancel Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CloseDate)">
|
||||||
|
Completed Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd DataLabel="MRB#">
|
||||||
|
<MudLink OnClick="@(() => GoTo($"mrb/{context.MRBNumber}"))">@context.MRBNumber</MudLink>
|
||||||
|
</MudTd>
|
||||||
|
<MudTd DataLabel="Title">@context.Title</MudTd>
|
||||||
|
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.SubmittedDate)</MudTd>
|
||||||
|
<MudTd DataLabel="Approval Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ApprovalDate)</MudTd>
|
||||||
|
<MudTd DataLabel="Cancel Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CancelDate)</MudTd>
|
||||||
|
<MudTd DataLabel="Completed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CloseDate)</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
<PagerContent>
|
||||||
|
<MudTablePager />
|
||||||
|
</PagerContent>
|
||||||
|
</MudTable>
|
||||||
|
</MudPaper>
|
||||||
|
} else {
|
||||||
|
<MudOverlay Visible DarkBackground="true" AutoClose="false">
|
||||||
|
<MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText>
|
||||||
|
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
|
||||||
|
</MudOverlay>
|
||||||
|
}
|
||||||
|
</MudTabPanel>
|
||||||
|
<MudTabPanel Text="My PCRBs" Style="min-width:50%; text-align: center;">
|
||||||
|
@if (stateProvider.CurrentUser is not null && myPCRBs is not null && !myPcrbsProcessing) {
|
||||||
|
<MudPaper Outlined="true"
|
||||||
|
Class="p-2 m-2 d-flex flex-column justify-center">
|
||||||
|
<MudText Typo="Typo.h4" Align="Align.Center">My PCRBs</MudText>
|
||||||
|
<MudDivider DividerType="DividerType.Middle" Class="my-2" />
|
||||||
|
<MudTable Items="@myPCRBs"
|
||||||
|
Class="m-2"
|
||||||
|
Striped
|
||||||
|
SortLabel="Sort by"
|
||||||
|
Filter="new Func<PCRB, bool>(FilterFuncForPCRBTable)">
|
||||||
|
<ToolBarContent>
|
||||||
|
<MudSpacer />
|
||||||
|
<MudTextField @bind-Value="pcrbSearchString"
|
||||||
|
Placeholder="Search"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
Immediate
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||||
|
IconSize="Size.Medium"
|
||||||
|
Class="mt-0" />
|
||||||
|
</ToolBarContent>
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<PCRB,object>(x=>x.PlanNumber)">
|
||||||
|
PCRB#
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.Title)">
|
||||||
|
Title
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.CurrentStep)">
|
||||||
|
Current Step
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.InsertTimeStamp)">
|
||||||
|
Submitted Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.LastUpdateDate)">
|
||||||
|
Last Updated
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.ClosedDate)">
|
||||||
|
Completed Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd DataLabel="PCRB#">
|
||||||
|
<MudLink OnClick="@(() => GoTo($"pcrb/{context.PlanNumber}"))">@context.PlanNumber</MudLink>
|
||||||
|
</MudTd>
|
||||||
|
<MudTd DataLabel="Title">@context.Title</MudTd>
|
||||||
|
<MudTd DataLabel="Current Step">@(GetCurrentPCRBStep(context.CurrentStep))</MudTd>
|
||||||
|
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.InsertTimeStamp)</MudTd>
|
||||||
|
<MudTd DataLabel="Last Updated">@DateTimeUtilities.GetDateAsStringMinDefault(context.LastUpdateDate)</MudTd>
|
||||||
|
<MudTd DataLabel="Completed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ClosedDate)</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
<PagerContent>
|
||||||
|
<MudTablePager />
|
||||||
|
</PagerContent>
|
||||||
|
</MudTable>
|
||||||
|
</MudPaper>
|
||||||
|
} else {
|
||||||
|
<MudOverlay Visible DarkBackground="true" AutoClose="false">
|
||||||
|
<MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText>
|
||||||
|
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
|
||||||
|
</MudOverlay>
|
||||||
|
}
|
||||||
|
</MudTabPanel>
|
||||||
|
</MudTabs>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private IEnumerable<Approval> approvalList = new List<Approval>();
|
private IEnumerable<Approval> approvalList = new List<Approval>();
|
||||||
|
private IEnumerable<MRB> myMRBs = new List<MRB>();
|
||||||
|
private IEnumerable<PCRB> myPCRBs = new List<PCRB>();
|
||||||
|
|
||||||
|
private IEnumerable<int> ecnNumbers = new HashSet<int>();
|
||||||
|
private IEnumerable<int> caNumbers = new HashSet<int>();
|
||||||
|
private IEnumerable<int> mrbNumbers = new HashSet<int>();
|
||||||
|
private IEnumerable<int> pcrbNumbers = new HashSet<int>();
|
||||||
|
|
||||||
|
private bool myApprovalsProcessing = false;
|
||||||
|
private bool myMrbsProcessing = false;
|
||||||
|
private bool myPcrbsProcessing = false;
|
||||||
|
|
||||||
|
private string mrbSearchString = "";
|
||||||
|
private string pcrbSearchString = "";
|
||||||
|
|
||||||
protected async override Task OnParametersSetAsync() {
|
protected async override Task OnParametersSetAsync() {
|
||||||
try {
|
try {
|
||||||
if (stateProvider.CurrentUser is not null)
|
if (stateProvider.CurrentUser is not null) {
|
||||||
approvalList = (await approvalService.GetApprovalsForUserId(stateProvider.CurrentUser.UserID, true)).ToList();
|
myApprovalsProcessing = true;
|
||||||
} catch (Exception ex) {
|
approvalList = (await approvalService.GetApprovalsForUserId(stateProvider.CurrentUser.UserID, true))
|
||||||
snackbar.Add($"Unable to fetch your outstanding approvals, because {ex.Message}", Severity.Error);
|
.Where(a => a.CompletedDate > DateTime.Now && a.ItemStatus == 0)
|
||||||
|
.ToList()
|
||||||
|
.OrderByDescending(x => x.AssignedDate);
|
||||||
|
myApprovalsProcessing = false;
|
||||||
|
|
||||||
|
myMrbsProcessing = true;
|
||||||
|
myMRBs = (await mrbService.GetAllMRBs(false)).Where(m => m.OriginatorID == stateProvider.CurrentUser.UserID)
|
||||||
|
.ToList()
|
||||||
|
.OrderByDescending(x => x.SubmittedDate);
|
||||||
|
myMrbsProcessing = false;
|
||||||
|
|
||||||
|
myPcrbsProcessing = true;
|
||||||
|
myPCRBs = (await pcrbService.GetAllPCRBs(false)).Where(p => p.OwnerID == stateProvider.CurrentUser.UserID)
|
||||||
|
.ToList()
|
||||||
|
.OrderByDescending(p => p.InsertTimeStamp);
|
||||||
|
myPcrbsProcessing = false;
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
myApprovalsProcessing = false;
|
||||||
|
myMrbsProcessing = false;
|
||||||
|
myPcrbsProcessing = false;
|
||||||
|
snackbar.Add($"Unable to load the dashboard, because {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task FollowLink(int issueId) {
|
||||||
|
HashSet<Task> tasks = new();
|
||||||
|
|
||||||
|
bool isEcn = false;
|
||||||
|
bool isCa = false;
|
||||||
|
bool isMrb = false;
|
||||||
|
bool isPcrb = false;
|
||||||
|
if (ecnNumbers.Contains(issueId))
|
||||||
|
isEcn = true;
|
||||||
|
if (caNumbers.Contains(issueId))
|
||||||
|
isCa = true;
|
||||||
|
if (mrbNumbers.Contains(issueId))
|
||||||
|
isMrb = true;
|
||||||
|
if (pcrbNumbers.Contains(issueId))
|
||||||
|
isPcrb = true;
|
||||||
|
|
||||||
|
if (!isEcn && !isCa && !isMrb) {
|
||||||
|
Task<bool> isEcnTask = ecnService.ECNNumberIsValid(issueId);
|
||||||
|
tasks.Add(isEcnTask);
|
||||||
|
|
||||||
|
Task<bool> isCaTask = caService.CANumberIsValid(issueId);
|
||||||
|
tasks.Add(isCaTask);
|
||||||
|
|
||||||
|
Task<bool> isMrbTask = mrbService.NumberIsValid(issueId);
|
||||||
|
tasks.Add(isMrbTask);
|
||||||
|
|
||||||
|
Task<bool> isPcrbTask = pcrbService.IdIsValid(issueId);
|
||||||
|
tasks.Add(isPcrbTask);
|
||||||
|
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
|
||||||
|
if (isEcnTask.Result) {
|
||||||
|
isEcn = true;
|
||||||
|
} else if (isCaTask.Result) {
|
||||||
|
isCa = true;
|
||||||
|
} else if (isMrbTask.Result) {
|
||||||
|
isMrb = true;
|
||||||
|
} else if (isPcrbTask.Result) {
|
||||||
|
isPcrb = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEcn) await GoToExternal($"{Configuration["OldFabApprovalUrl"]}/ECN/Edit?IssueID={issueId}", "");
|
||||||
|
if (isCa) await GoToExternal($"{Configuration["OldFabApprovalUrl"]}/CorrectiveAction/Edit?IssueID={issueId}", "");
|
||||||
|
if (isMrb) GoTo($"mrb/{issueId}");
|
||||||
|
if (isPcrb) GoTo($"pcrb/{issueId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GoTo(string page) {
|
private void GoTo(string page) {
|
||||||
cache.Set("redirectUrl", page);
|
cache.Set("redirectUrl", page);
|
||||||
navigationManager.NavigateTo(page);
|
navigationManager.NavigateTo("/" + page);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GoToExternal(string url, string content) {
|
||||||
|
IJSObjectReference windowModule = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "./js/OpenInNewWindow.js");
|
||||||
|
await windowModule.InvokeAsync<object>("OpenInNewWindow", url, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FilterFuncForMRBTable(MRB mrb) => MRBFilterFunc(mrb, mrbSearchString);
|
||||||
|
|
||||||
|
private bool MRBFilterFunc(MRB mrb, string searchString) {
|
||||||
|
if (string.IsNullOrWhiteSpace(searchString))
|
||||||
|
return true;
|
||||||
|
if (mrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
|
||||||
|
return true;
|
||||||
|
if (mrb.MRBNumber.ToString().Contains(searchString.Trim()))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FilterFuncForPCRBTable(PCRB pcrb) => PCRBFilterFunc(pcrb, pcrbSearchString);
|
||||||
|
|
||||||
|
private bool PCRBFilterFunc(PCRB pcrb, string searchString) {
|
||||||
|
if (string.IsNullOrWhiteSpace(searchString))
|
||||||
|
return true;
|
||||||
|
if (pcrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
|
||||||
|
return true;
|
||||||
|
if (pcrb.PlanNumber.ToString().Contains(searchString.Trim()))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCurrentPCRBStep(int step) {
|
||||||
|
if (step < 0 || step > (PCRB.Stages.Length - 1)) return string.Empty;
|
||||||
|
else return PCRB.Stages[step];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,19 @@
|
|||||||
<MudText>Log In</MudText>
|
<MudText>Log In</MudText>
|
||||||
}
|
}
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
<MudDivider />
|
||||||
|
@* <MudButton
|
||||||
|
Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Class="m-1"
|
||||||
|
OnClick="LoginLocal" >
|
||||||
|
@if (processingLocal) {
|
||||||
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<MudText>Processing</MudText>
|
||||||
|
} else {
|
||||||
|
<MudText>Log In (SSO)</MudText>
|
||||||
|
}
|
||||||
|
</MudButton> *@
|
||||||
</MudForm>
|
</MudForm>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
|
||||||
@ -55,6 +68,7 @@
|
|||||||
public string? redirectUrlSub { get; set; }
|
public string? redirectUrlSub { get; set; }
|
||||||
private bool success;
|
private bool success;
|
||||||
private bool processing = false;
|
private bool processing = false;
|
||||||
|
private bool processingLocal = false;
|
||||||
private string[] errors = { };
|
private string[] errors = { };
|
||||||
private string? username;
|
private string? username;
|
||||||
private string? password;
|
private string? password;
|
||||||
@ -81,4 +95,19 @@
|
|||||||
SubmitLogin();
|
SubmitLogin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoginLocal() {
|
||||||
|
processingLocal = true;
|
||||||
|
|
||||||
|
await authStateProvider.LoginLocal();
|
||||||
|
if (!string.IsNullOrWhiteSpace(redirectUrl) && !string.IsNullOrWhiteSpace(redirectUrlSub)) {
|
||||||
|
navManager.NavigateTo($"{redirectUrl}/{redirectUrlSub}");
|
||||||
|
} else if (!string.IsNullOrWhiteSpace(redirectUrl)) {
|
||||||
|
navManager.NavigateTo(redirectUrl);
|
||||||
|
} else {
|
||||||
|
navManager.NavigateTo("dashboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
processingLocal = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,11 @@
|
|||||||
Submitted Date
|
Submitted Date
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.ApprovalDate)">
|
||||||
|
Approval Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
<MudTh>
|
<MudTh>
|
||||||
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CloseDate)">
|
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CloseDate)">
|
||||||
Closed Date
|
Closed Date
|
||||||
@ -56,11 +61,12 @@
|
|||||||
</HeaderContent>
|
</HeaderContent>
|
||||||
<RowTemplate>
|
<RowTemplate>
|
||||||
<MudTd DataLabel="MRB#">
|
<MudTd DataLabel="MRB#">
|
||||||
<MudLink OnClick="@(() => GoTo($"/mrb/{context.MRBNumber}"))">@context.MRBNumber</MudLink>
|
<MudLink OnClick="@(() => GoTo($"mrb/{context.MRBNumber}"))">@context.MRBNumber</MudLink>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
<MudTd DataLabel="Title">@context.Title</MudTd>
|
<MudTd DataLabel="Title">@context.Title</MudTd>
|
||||||
<MudTd DataLabel="Originator">@context.OriginatorName</MudTd>
|
<MudTd DataLabel="Originator">@context.OriginatorName</MudTd>
|
||||||
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.SubmittedDate)</MudTd>
|
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.SubmittedDate)</MudTd>
|
||||||
|
<MudTd DataLabel="Approval Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ApprovalDate)</MudTd>
|
||||||
<MudTd DataLabel="Closed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CloseDate)</MudTd>
|
<MudTd DataLabel="Closed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CloseDate)</MudTd>
|
||||||
</RowTemplate>
|
</RowTemplate>
|
||||||
<PagerContent>
|
<PagerContent>
|
||||||
@ -84,7 +90,7 @@
|
|||||||
if (mrbService is null) {
|
if (mrbService is null) {
|
||||||
throw new Exception("MRB service not injected!");
|
throw new Exception("MRB service not injected!");
|
||||||
} else {
|
} else {
|
||||||
allMrbs = await mrbService.GetAllMRBs();
|
allMrbs = await mrbService.GetAllMRBs(false);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
snackbar.Add(ex.Message, Severity.Error);
|
snackbar.Add(ex.Message, Severity.Error);
|
||||||
@ -97,11 +103,11 @@
|
|||||||
private bool FilterFunc(MRB mrb, string searchString) {
|
private bool FilterFunc(MRB mrb, string searchString) {
|
||||||
if (string.IsNullOrWhiteSpace(searchString))
|
if (string.IsNullOrWhiteSpace(searchString))
|
||||||
return true;
|
return true;
|
||||||
if (mrb.Title.ToLower().Contains(searchString.ToLower()))
|
if (mrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
|
||||||
return true;
|
return true;
|
||||||
if (mrb.OriginatorName.ToLower().Contains(searchString.ToLower()))
|
if (mrb.OriginatorName.ToLower().Contains(searchString.Trim().ToLower()))
|
||||||
return true;
|
return true;
|
||||||
if (mrb.MRBNumber.ToString().Contains(searchString))
|
if (mrb.MRBNumber.ToString().Contains(searchString.Trim()))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
126
MesaFabApproval.Client/Pages/PCRBAll.razor
Normal file
126
MesaFabApproval.Client/Pages/PCRBAll.razor
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
@page "/pcrb/all"
|
||||||
|
@using System.Globalization
|
||||||
|
@inject IPCRBService pcrbService
|
||||||
|
@inject ISnackbar snackbar
|
||||||
|
@inject IMemoryCache cache
|
||||||
|
@inject NavigationManager navigationManager
|
||||||
|
|
||||||
|
<PageTitle>PCRB</PageTitle>
|
||||||
|
|
||||||
|
<MudPaper Class="p-2 m-2">
|
||||||
|
<MudText Typo="Typo.h3" Align="Align.Center">PCRB List</MudText>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
@if (allPCRBs is not null && allPCRBs.Count() > 0) {
|
||||||
|
<MudTable Items="@allPCRBs"
|
||||||
|
Class="m-2"
|
||||||
|
Striped="true"
|
||||||
|
Filter="new Func<PCRB,bool>(FilterFuncForTable)"
|
||||||
|
SortLabel="Sort By"
|
||||||
|
Hover="true">
|
||||||
|
<ToolBarContent>
|
||||||
|
<MudSpacer />
|
||||||
|
<MudTextField @bind-Value="searchString"
|
||||||
|
Placeholder="Search"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||||
|
IconSize="Size.Medium"
|
||||||
|
Class="mt-0" />
|
||||||
|
</ToolBarContent>
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<PCRB,object>(x=>x.PlanNumber)">
|
||||||
|
Change#
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.Title)">
|
||||||
|
Title
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.OwnerName)">
|
||||||
|
Owner
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>Stage</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.InsertTimeStamp)">
|
||||||
|
Submitted Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.LastUpdateDate)">
|
||||||
|
Last Updated
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
<MudTh>
|
||||||
|
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.ClosedDate)">
|
||||||
|
Closed Date
|
||||||
|
</MudTableSortLabel>
|
||||||
|
</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd DataLabel="Plan#">
|
||||||
|
<MudLink OnClick="@(() => GoTo($"pcrb/{context.PlanNumber.ToString()}"))">@context.PlanNumber</MudLink>
|
||||||
|
</MudTd>
|
||||||
|
<MudTd DataLabel="Title">@context.Title</MudTd>
|
||||||
|
<MudTd DataLabel="Owner">@context.OwnerName</MudTd>
|
||||||
|
<MudTd DataLabel="Stage">@(GetStageName(context.CurrentStep))</MudTd>
|
||||||
|
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.InsertTimeStamp)</MudTd>
|
||||||
|
<MudTd DataLabel="Last Updated">@DateTimeUtilities.GetDateAsStringMinDefault(context.LastUpdateDate)</MudTd>
|
||||||
|
<MudTd DataLabel="Closed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ClosedDate)</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
<PagerContent>
|
||||||
|
<MudTablePager />
|
||||||
|
</PagerContent>
|
||||||
|
</MudTable>
|
||||||
|
}
|
||||||
|
|
||||||
|
<MudOverlay @bind-Visible=inProcess DarkBackground="true" AutoClose="false">
|
||||||
|
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
|
||||||
|
</MudOverlay>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private bool inProcess = false;
|
||||||
|
private string searchString = "";
|
||||||
|
private IEnumerable<PCRB> allPCRBs = new List<PCRB>();
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() {
|
||||||
|
inProcess = true;
|
||||||
|
try {
|
||||||
|
if (pcrbService is null) {
|
||||||
|
throw new Exception("PCRB service not injected!");
|
||||||
|
} else {
|
||||||
|
allPCRBs = await pcrbService.GetAllPCRBs(false);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
snackbar.Add(ex.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
inProcess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FilterFuncForTable(PCRB pcrb) => FilterFunc(pcrb, searchString);
|
||||||
|
|
||||||
|
private bool FilterFunc(PCRB pcrb, string searchString) {
|
||||||
|
if (string.IsNullOrWhiteSpace(searchString))
|
||||||
|
return true;
|
||||||
|
if (pcrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
|
||||||
|
return true;
|
||||||
|
if (pcrb.OwnerName.ToLower().Contains(searchString.Trim().ToLower()))
|
||||||
|
return true;
|
||||||
|
if (pcrb.PlanNumber.ToString().Contains(searchString.Trim()))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GoTo(string page) {
|
||||||
|
cache.Set("redirectUrl", page);
|
||||||
|
navigationManager.NavigateTo(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetStageName(int step) {
|
||||||
|
if (step >= PCRB.Stages.Length || step < 0) return "";
|
||||||
|
return PCRB.Stages[step];
|
||||||
|
}
|
||||||
|
}
|
||||||
1771
MesaFabApproval.Client/Pages/PCRBSingle.razor
Normal file
1771
MesaFabApproval.Client/Pages/PCRBSingle.razor
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,17 +9,23 @@ using MesaFabApproval.Client.Services;
|
|||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
using Blazored.SessionStorage;
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args);
|
WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||||
|
|
||||||
string _apiBaseUrl = builder.Configuration["FabApprovalApiBaseUrl"] ??
|
string _apiBaseUrl = builder.Configuration["FabApprovalApiBaseUrl"] ??
|
||||||
throw new NullReferenceException("FabApprovalApiBaseUrl not found in config");
|
throw new NullReferenceException("FabApprovalApiBaseUrl not found in config");
|
||||||
|
|
||||||
builder.Services.AddBlazoredSessionStorage();
|
string _oldSiteUrl = builder.Configuration["OldFabApprovalUrl"] ??
|
||||||
|
throw new NullReferenceException("OldFabApprovalUrl not found in config");
|
||||||
|
|
||||||
builder.Services.AddTransient<ApiHttpClientHandler>();
|
builder.Services.AddTransient<ApiHttpClientHandler>();
|
||||||
|
|
||||||
|
builder.Services
|
||||||
|
.AddHttpClient("API_Handler", client => {
|
||||||
|
client.BaseAddress = new Uri(_apiBaseUrl);
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services
|
builder.Services
|
||||||
.AddHttpClient("API", client => {
|
.AddHttpClient("API", client => {
|
||||||
client.BaseAddress = new Uri(_apiBaseUrl);
|
client.BaseAddress = new Uri(_apiBaseUrl);
|
||||||
@ -27,6 +33,12 @@ builder.Services
|
|||||||
})
|
})
|
||||||
.AddHttpMessageHandler<ApiHttpClientHandler>();
|
.AddHttpMessageHandler<ApiHttpClientHandler>();
|
||||||
|
|
||||||
|
builder.Services
|
||||||
|
.AddHttpClient("OldSite", client => {
|
||||||
|
client.BaseAddress = new Uri(_oldSiteUrl);
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddMemoryCache();
|
builder.Services.AddMemoryCache();
|
||||||
|
|
||||||
builder.Services.AddMudServices(config => {
|
builder.Services.AddMudServices(config => {
|
||||||
@ -35,13 +47,18 @@ builder.Services.AddMudServices(config => {
|
|||||||
config.SnackbarConfiguration.MaxDisplayedSnackbars = 5;
|
config.SnackbarConfiguration.MaxDisplayedSnackbars = 5;
|
||||||
config.SnackbarConfiguration.SnackbarVariant = Variant.Filled;
|
config.SnackbarConfiguration.SnackbarVariant = Variant.Filled;
|
||||||
config.SnackbarConfiguration.ShowCloseIcon = true;
|
config.SnackbarConfiguration.ShowCloseIcon = true;
|
||||||
config.SnackbarConfiguration.VisibleStateDuration = 5000;
|
config.SnackbarConfiguration.VisibleStateDuration = 7000;
|
||||||
config.SnackbarConfiguration.HideTransitionDuration = 500;
|
config.SnackbarConfiguration.HideTransitionDuration = 500;
|
||||||
config.SnackbarConfiguration.ShowTransitionDuration = 500;
|
config.SnackbarConfiguration.ShowTransitionDuration = 500;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.Services.AddScoped<ILocalStorageService, LocalStorageService>();
|
||||||
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
||||||
|
builder.Services.AddScoped<ICustomerService, CustomerService>();
|
||||||
builder.Services.AddScoped<IUserService, UserService>();
|
builder.Services.AddScoped<IUserService, UserService>();
|
||||||
|
builder.Services.AddScoped<IECNService, ECNService>();
|
||||||
|
builder.Services.AddScoped<ICAService, CAService>();
|
||||||
|
builder.Services.AddScoped<IPCRBService, PCRBService>();
|
||||||
builder.Services.AddScoped<IMRBService, MRBService>();
|
builder.Services.AddScoped<IMRBService, MRBService>();
|
||||||
builder.Services.AddScoped<IApprovalService, ApprovalService>();
|
builder.Services.AddScoped<IApprovalService, ApprovalService>();
|
||||||
builder.Services.AddScoped<MesaFabApprovalAuthStateProvider>();
|
builder.Services.AddScoped<MesaFabApprovalAuthStateProvider>();
|
||||||
|
|||||||
@ -193,9 +193,6 @@ public class ApprovalService : IApprovalService {
|
|||||||
if (!responseMessage.IsSuccessStatusCode) {
|
if (!responseMessage.IsSuccessStatusCode) {
|
||||||
throw new Exception($"Denial failed, because {responseMessage.ReasonPhrase}");
|
throw new Exception($"Denial failed, because {responseMessage.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
|
|
||||||
await GetApprovalsForIssueId(approval.IssueID, true);
|
|
||||||
await GetApprovalsForUserId(approval.UserID, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> GetRoleIdForRoleName(string roleName) {
|
public async Task<int> GetRoleIdForRoleName(string roleName) {
|
||||||
@ -292,7 +289,7 @@ public class ApprovalService : IApprovalService {
|
|||||||
if (members is null || members.Count() <= 0)
|
if (members is null || members.Count() <= 0)
|
||||||
throw new Exception($"unable to find group members for sub role {subRoleId}");
|
throw new Exception($"unable to find group members for sub role {subRoleId}");
|
||||||
|
|
||||||
_cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddMinutes(15));
|
_cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddMinutes(2));
|
||||||
} else {
|
} else {
|
||||||
throw new Exception($"Unable to get group members, because {responseMessage.ReasonPhrase}");
|
throw new Exception($"Unable to get group members, because {responseMessage.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Security.Principal;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
using Blazored.SessionStorage;
|
|
||||||
|
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
@ -13,6 +12,7 @@ namespace MesaFabApproval.Client.Services;
|
|||||||
|
|
||||||
public interface IAuthenticationService {
|
public interface IAuthenticationService {
|
||||||
Task<ClaimsPrincipal> SendAuthenticationRequest(string loginId, string password);
|
Task<ClaimsPrincipal> SendAuthenticationRequest(string loginId, string password);
|
||||||
|
Task<ClaimsPrincipal> AttemptLocalUserAuth();
|
||||||
Task<ClaimsPrincipal> FetchAuthState();
|
Task<ClaimsPrincipal> FetchAuthState();
|
||||||
Task ClearTokens();
|
Task ClearTokens();
|
||||||
Task ClearCurrentUser();
|
Task ClearCurrentUser();
|
||||||
@ -26,15 +26,15 @@ public interface IAuthenticationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class AuthenticationService : IAuthenticationService {
|
public class AuthenticationService : IAuthenticationService {
|
||||||
private readonly ISessionStorageService _sessionStorageService;
|
private readonly ILocalStorageService _localStorageService;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
public AuthenticationService(ISessionStorageService sessionStorageService,
|
public AuthenticationService(ILocalStorageService localStorageService,
|
||||||
IMemoryCache cache,
|
IMemoryCache cache,
|
||||||
IHttpClientFactory httpClientFactory) {
|
IHttpClientFactory httpClientFactory) {
|
||||||
_sessionStorageService = sessionStorageService ??
|
_localStorageService = localStorageService ??
|
||||||
throw new ArgumentNullException("ISessionStorageService not injected");
|
throw new ArgumentNullException("ILocalStorageService not injected");
|
||||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected");
|
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||||
}
|
}
|
||||||
@ -84,10 +84,55 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ClaimsPrincipal> AttemptLocalUserAuth() {
|
||||||
|
WindowsIdentity? user = WindowsIdentity.GetCurrent();
|
||||||
|
|
||||||
|
if (user is null)
|
||||||
|
throw new Exception("no authenticated user found");
|
||||||
|
|
||||||
|
if (!user.IsAuthenticated)
|
||||||
|
throw new Exception("you are not authenticated");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/login/localWindows");
|
||||||
|
|
||||||
|
request.Content = new StringContent(JsonSerializer.Serialize(user),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request);
|
||||||
|
|
||||||
|
if (httpResponseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginResult loginResult = JsonSerializer.Deserialize<LoginResult>(responseContent, jsonSerializerOptions) ??
|
||||||
|
throw new Exception("Unable to parse login result from API response");
|
||||||
|
|
||||||
|
if (!loginResult.IsAuthenticated) throw new Exception($"User with Login ID {user.Name} not authorized");
|
||||||
|
|
||||||
|
await SetLoginId(loginResult.User.LoginID);
|
||||||
|
|
||||||
|
await SetTokens(loginResult.AuthTokens.JwtToken, loginResult.AuthTokens.RefreshToken);
|
||||||
|
|
||||||
|
await SetCurrentUser(loginResult.User);
|
||||||
|
|
||||||
|
ClaimsPrincipal principal = GetClaimsPrincipalFromJwt(loginResult.AuthTokens.JwtToken);
|
||||||
|
|
||||||
|
return principal;
|
||||||
|
} else {
|
||||||
|
throw new Exception($"Login API request failed for {user.Name}, because {httpResponseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ClaimsPrincipal> FetchAuthState() {
|
public async Task<ClaimsPrincipal> FetchAuthState() {
|
||||||
string? jwt = _cache.Get<string>("MesaFabApprovalJwt");
|
string? jwt = _cache.Get<string>("MesaFabApprovalJwt");
|
||||||
|
|
||||||
if (jwt is null) jwt = await _sessionStorageService.GetItemAsync<string>("MesaFabApprovalJwt");
|
if (jwt is null) jwt = await _localStorageService.GetItem("MesaFabApprovalJwt");
|
||||||
|
|
||||||
if (jwt is null) throw new Exception("Unable to find JWT");
|
if (jwt is null) throw new Exception("Unable to find JWT");
|
||||||
|
|
||||||
@ -98,9 +143,9 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
|
|
||||||
public async Task ClearTokens() {
|
public async Task ClearTokens() {
|
||||||
_cache.Remove("MesaFabApprovalJwt");
|
_cache.Remove("MesaFabApprovalJwt");
|
||||||
await _sessionStorageService.RemoveItemAsync("MesaFabApprovalJwt");
|
await _localStorageService.RemoveItem("MesaFabApprovalJwt");
|
||||||
_cache.Remove("MesaFabApprovalRefreshToken");
|
_cache.Remove("MesaFabApprovalRefreshToken");
|
||||||
await _sessionStorageService.RemoveItemAsync("MesaFabApprovalRefreshToken");
|
await _localStorageService.RemoveItem("MesaFabApprovalRefreshToken");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetTokens(string jwt, string refreshToken) {
|
public async Task SetTokens(string jwt, string refreshToken) {
|
||||||
@ -108,37 +153,37 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException("Refresh token cannot be null or empty");
|
if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException("Refresh token cannot be null or empty");
|
||||||
|
|
||||||
_cache.Set<string>("MesaFabApprovalJwt", jwt);
|
_cache.Set<string>("MesaFabApprovalJwt", jwt);
|
||||||
await _sessionStorageService.SetItemAsync<string>("MesaFabApprovalJwt", jwt);
|
await _localStorageService.AddItem("MesaFabApprovalJwt", jwt);
|
||||||
_cache.Set<string>("MesaFabApprovalRefreshToken", refreshToken);
|
_cache.Set<string>("MesaFabApprovalRefreshToken", refreshToken);
|
||||||
await _sessionStorageService.SetItemAsync<string>("MesaFabApprovalRefreshToken", refreshToken);
|
await _localStorageService.AddItem("MesaFabApprovalRefreshToken", refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetLoginId(string loginId) {
|
public async Task SetLoginId(string loginId) {
|
||||||
if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentNullException("LoginId cannot be null or empty");
|
if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentNullException("LoginId cannot be null or empty");
|
||||||
|
|
||||||
_cache.Set<string>("MesaFabApprovalUserId", loginId);
|
_cache.Set<string>("MesaFabApprovalUserId", loginId);
|
||||||
await _sessionStorageService.SetItemAsync<string>("MesaFabApprovalUserId", loginId);
|
await _localStorageService.AddItem("MesaFabApprovalUserId", loginId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetCurrentUser(User user) {
|
public async Task SetCurrentUser(User? user) {
|
||||||
if (user is null) throw new ArgumentNullException("User cannot be null");
|
|
||||||
|
|
||||||
_cache.Set<User>("MesaFabApprovalCurrentUser", user);
|
_cache.Set<User>("MesaFabApprovalCurrentUser", user);
|
||||||
await _sessionStorageService.SetItemAsync<User>("MesaFabApprovalCurrentUser", user);
|
await _localStorageService.AddItem<User>("MesaFabApprovalCurrentUser", user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ClearCurrentUser() {
|
public async Task ClearCurrentUser() {
|
||||||
_cache.Remove("MesaFabApprovalCurrentUser");
|
_cache.Remove("MesaFabApprovalCurrentUser");
|
||||||
await _sessionStorageService.RemoveItemAsync("MesaFabApprovalCurrentUser");
|
await _localStorageService.RemoveItem("MesaFabApprovalCurrentUser");
|
||||||
_cache.Remove("MesaFabApprovalUserId");
|
_cache.Remove("MesaFabApprovalUserId");
|
||||||
await _sessionStorageService.RemoveItemAsync("MesaFabApprovalUserId");
|
await _localStorageService.RemoveItem("MesaFabApprovalUserId");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> GetCurrentUser() {
|
public async Task<User> GetCurrentUser() {
|
||||||
User? currentUser = null;
|
User? currentUser = null;
|
||||||
|
|
||||||
currentUser = _cache.Get<User>("MesaFabApprovalCurrentUser") ??
|
currentUser = _cache.Get<User>("MesaFabApprovalCurrentUser");
|
||||||
await _sessionStorageService.GetItemAsync<User>("MesaFabApprovalCurrentUser");
|
|
||||||
|
if (currentUser is null)
|
||||||
|
currentUser = await _localStorageService.GetItem<User>("MesaFabApprovalCurrentUser");
|
||||||
|
|
||||||
return currentUser;
|
return currentUser;
|
||||||
}
|
}
|
||||||
@ -147,10 +192,10 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
AuthTokens? authTokens = null;
|
AuthTokens? authTokens = null;
|
||||||
|
|
||||||
string? jwt = _cache.Get<string>("MesaFabApprovalJwt");
|
string? jwt = _cache.Get<string>("MesaFabApprovalJwt");
|
||||||
if (jwt is null) jwt = await _sessionStorageService.GetItemAsync<string>("MesaFabApprovalJwt");
|
if (jwt is null) jwt = await _localStorageService.GetItem("MesaFabApprovalJwt");
|
||||||
|
|
||||||
string? refreshToken = _cache.Get<string>("MesaFabApprovalRefreshToken");
|
string? refreshToken = _cache.Get<string>("MesaFabApprovalRefreshToken");
|
||||||
if (refreshToken is null) refreshToken = await _sessionStorageService.GetItemAsync<string>("MesaFabApprovalRefreshToken");
|
if (refreshToken is null) refreshToken = await _localStorageService.GetItem("MesaFabApprovalRefreshToken");
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(jwt) && !string.IsNullOrWhiteSpace(refreshToken)) {
|
if (!string.IsNullOrWhiteSpace(jwt) && !string.IsNullOrWhiteSpace(refreshToken)) {
|
||||||
authTokens = new() {
|
authTokens = new() {
|
||||||
@ -164,7 +209,7 @@ public class AuthenticationService : IAuthenticationService {
|
|||||||
|
|
||||||
public async Task<string> GetLoginId() {
|
public async Task<string> GetLoginId() {
|
||||||
string? loginId = _cache.Get<string>("MesaFabApprovalUserId");
|
string? loginId = _cache.Get<string>("MesaFabApprovalUserId");
|
||||||
if (loginId is null) loginId = await _sessionStorageService.GetItemAsync<string>("MesaFabApprovalUserId");
|
if (loginId is null) loginId = await _localStorageService.GetItem("MesaFabApprovalUserId");
|
||||||
|
|
||||||
return loginId;
|
return loginId;
|
||||||
}
|
}
|
||||||
|
|||||||
44
MesaFabApproval.Client/Services/CAService.cs
Normal file
44
MesaFabApproval.Client/Services/CAService.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Client.Services;
|
||||||
|
|
||||||
|
public interface ICAService {
|
||||||
|
Task<bool> CANumberIsValid(int number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CAService : ICAService {
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
|
public CAService(IHttpClientFactory httpClientFactory) {
|
||||||
|
_httpClientFactory = httpClientFactory ??
|
||||||
|
throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CANumberIsValid(int number) {
|
||||||
|
if (number <= 0) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"ca/isValidCANumber?number={number}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isValid = JsonSerializer.Deserialize<bool>(responseContent, jsonSerializerOptions);
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new Exception($"Unable to determine if {number} is a valid CA#, because {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
MesaFabApproval.Client/Services/CustomerService.cs
Normal file
51
MesaFabApproval.Client/Services/CustomerService.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Client.Services;
|
||||||
|
|
||||||
|
public interface ICustomerService {
|
||||||
|
Task<IEnumerable<string>> GetAllCustomerNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomerService : ICustomerService {
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
|
public CustomerService(IMemoryCache cache, IHttpClientFactory httpClientFactory) {
|
||||||
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
|
_httpClientFactory = httpClientFactory ??
|
||||||
|
throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<string>> GetAllCustomerNames() {
|
||||||
|
IEnumerable<string>? allCustomerNames = null;
|
||||||
|
|
||||||
|
allCustomerNames = _cache.Get<IEnumerable<string>>("allCustomerNames");
|
||||||
|
|
||||||
|
if (allCustomerNames is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"customer/all");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
allCustomerNames = JsonSerializer.Deserialize<IEnumerable<string>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
throw new Exception("Unable to parse names from API response");
|
||||||
|
|
||||||
|
_cache.Set($"allCustomerNames", allCustomerNames, DateTimeOffset.Now.AddHours(1));
|
||||||
|
} else {
|
||||||
|
throw new Exception($"Unable to get all customer names, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allCustomerNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
MesaFabApproval.Client/Services/ECNService.cs
Normal file
52
MesaFabApproval.Client/Services/ECNService.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Client.Services;
|
||||||
|
|
||||||
|
public interface IECNService {
|
||||||
|
Task<string> ECNNumberIsValidStr(int ecnNumber);
|
||||||
|
Task<bool> ECNNumberIsValid(int number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ECNService : IECNService {
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
|
public ECNService(IHttpClientFactory httpClientFactory) {
|
||||||
|
_httpClientFactory = httpClientFactory ??
|
||||||
|
throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> ECNNumberIsValidStr(int ecnNumber) {
|
||||||
|
if (ecnNumber <= 0 || !await ECNNumberIsValid(ecnNumber))
|
||||||
|
return $"{ecnNumber} is not a valid ECN#";
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ECNNumberIsValid(int number) {
|
||||||
|
if (number <= 0) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"ecn/isValidEcnNumber?number={number}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isValid = JsonSerializer.Deserialize<bool>(responseContent, jsonSerializerOptions);
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new Exception($"Unable to determine if {number} is a valid ECN#, because {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
MesaFabApproval.Client/Services/LocalStorageService.cs
Normal file
49
MesaFabApproval.Client/Services/LocalStorageService.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
using Microsoft.JSInterop;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Client.Services;
|
||||||
|
|
||||||
|
public interface ILocalStorageService {
|
||||||
|
Task AddItem(string key, string value);
|
||||||
|
Task AddItem<T>(string key, T value);
|
||||||
|
Task RemoveItem(string key);
|
||||||
|
Task<string> GetItem(string key);
|
||||||
|
Task<T?> GetItem<T>(string key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LocalStorageService : ILocalStorageService {
|
||||||
|
private readonly IJSRuntime _jsRuntime;
|
||||||
|
|
||||||
|
public LocalStorageService(IJSRuntime jsRuntime) {
|
||||||
|
_jsRuntime = jsRuntime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddItem(string key, string value) {
|
||||||
|
await _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddItem<T>(string key, T value) {
|
||||||
|
string item = JsonSerializer.Serialize(value);
|
||||||
|
await _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveItem(string key) {
|
||||||
|
await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetItem(string key) {
|
||||||
|
return await _jsRuntime.InvokeAsync<string>("localStorage.getItem", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<T?> GetItem<T>(string key) {
|
||||||
|
string item = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", key);
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
return JsonSerializer.Deserialize<T>(item, jsonSerializerOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ using System.Text;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components.Forms;
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
using Microsoft.AspNetCore.StaticFiles;
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
@ -13,10 +14,12 @@ using MudBlazor;
|
|||||||
namespace MesaFabApproval.Client.Services;
|
namespace MesaFabApproval.Client.Services;
|
||||||
|
|
||||||
public interface IMRBService {
|
public interface IMRBService {
|
||||||
Task<IEnumerable<MRB>> GetAllMRBs();
|
Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache);
|
||||||
Task<MRB> GetMRBById(int id);
|
Task<MRB> GetMRBById(int id, bool bypassCache = false);
|
||||||
Task<MRB> GetMRBByTitle(string title, bool bypassCache);
|
Task<MRB> GetMRBByTitle(string title, bool bypassCache);
|
||||||
Task CreateNewMRB(MRB mrb);
|
Task CreateNewMRB(MRB mrb);
|
||||||
|
Task RecallMRB(MRB mrb, User recallUser);
|
||||||
|
Task DeleteMRB(int mrbNumber);
|
||||||
Task UpdateMRB(MRB mrb);
|
Task UpdateMRB(MRB mrb);
|
||||||
Task SubmitForApproval(MRB mrb);
|
Task SubmitForApproval(MRB mrb);
|
||||||
Task GenerateActionTasks(MRB mrb, MRBAction action);
|
Task GenerateActionTasks(MRB mrb, MRBAction action);
|
||||||
@ -25,11 +28,15 @@ public interface IMRBService {
|
|||||||
Task UpdateMRBAction(MRBAction mrbAction);
|
Task UpdateMRBAction(MRBAction mrbAction);
|
||||||
Task DeleteMRBAction(MRBAction mrbAction);
|
Task DeleteMRBAction(MRBAction mrbAction);
|
||||||
Task UploadAttachments(IEnumerable<IBrowserFile> files, int mrbNumber);
|
Task UploadAttachments(IEnumerable<IBrowserFile> files, int mrbNumber);
|
||||||
|
Task UploadActionAttachments(IEnumerable<IBrowserFile> files, int actionId);
|
||||||
Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
||||||
|
Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
||||||
Task DeleteAttachment(MRBAttachment attachment);
|
Task DeleteAttachment(MRBAttachment attachment);
|
||||||
Task NotifyNewApprovals(MRB mrb);
|
Task NotifyNewApprovals(MRB mrb);
|
||||||
Task NotifyApprovers(MRBNotification notification);
|
Task NotifyApprovers(MRBNotification notification);
|
||||||
Task NotifyOriginator(MRBNotification notification);
|
Task NotifyOriginator(MRBNotification notification);
|
||||||
|
Task NotifyQAPreApprover(MRBNotification notification);
|
||||||
|
Task<bool> NumberIsValid(int number);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MRBService : IMRBService {
|
public class MRBService : IMRBService {
|
||||||
@ -81,14 +88,63 @@ public class MRBService : IMRBService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<MRB>> GetAllMRBs() {
|
public async Task RecallMRB(MRB mrb, User recallUser) {
|
||||||
|
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||||
|
if (mrb.StageNo < 1) throw new ArgumentException("MRB already in Draft stage");
|
||||||
|
if (mrb.StageNo >= 4) throw new Exception("you cannot recall a completed MRB");
|
||||||
|
|
||||||
|
mrb.StageNo = 0;
|
||||||
|
mrb.SubmittedDate = DateTimeUtilities.MIN_DT;
|
||||||
|
mrb.ApprovalDate = DateTimeUtilities.MAX_DT;
|
||||||
|
mrb.CloseDate = DateTimeUtilities.MAX_DT;
|
||||||
|
await UpdateMRB(mrb);
|
||||||
|
|
||||||
|
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(mrb.MRBNumber, false);
|
||||||
|
|
||||||
|
foreach (Approval approval in approvals) {
|
||||||
|
if (approval.CompletedDate >= DateTimeUtilities.MAX_DT) {
|
||||||
|
string comment = $"Recalled by {recallUser.GetFullName()}.";
|
||||||
|
approval.Comments = comment;
|
||||||
|
|
||||||
|
approval.CompletedDate = DateTime.Now;
|
||||||
|
approval.ItemStatus = -1;
|
||||||
|
|
||||||
|
await _approvalService.UpdateApproval(approval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string message = $"MRB# {mrb.MRBNumber} [{mrb.Title}] has been recalled by {recallUser.GetFullName()}.";
|
||||||
|
MRBNotification notification = new() { Message = message, MRB = mrb };
|
||||||
|
|
||||||
|
await NotifyApprovers(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteMRB(int mrbNumber) {
|
||||||
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"mrb/delete?mrbNumber={mrbNumber}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode) {
|
||||||
|
throw new Exception($"Unable to delete MRB# {mrbNumber}, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<MRB> allMRBs = await GetAllMRBs(true);
|
||||||
|
_cache.Set("allMrbs", allMRBs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache) {
|
||||||
try {
|
try {
|
||||||
IEnumerable<MRB>? allMRBs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
IEnumerable<MRB>? allMRBs = null;
|
||||||
|
if (!bypassCache) allMRBs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||||
|
|
||||||
if (allMRBs is null) {
|
if (allMRBs is null) {
|
||||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, "mrb/all");
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/all?bypassCache={bypassCache}");
|
||||||
|
|
||||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
@ -113,17 +169,48 @@ public class MRBService : IMRBService {
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task<MRB> GetMRBById(int id) {
|
|
||||||
|
public async Task<bool> NumberIsValid(int number) {
|
||||||
|
try {
|
||||||
|
if (number <= 0) return false;
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/numberIsValid?number={number}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isValid = JsonSerializer.Deserialize<bool>(responseContent, jsonSerializerOptions);
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new Exception($"Unable to determine if {number} is a valid MRB#, because {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MRB> GetMRBById(int id, bool bypassCache=false) {
|
||||||
if (id <= 0) throw new ArgumentException($"Invalid MRB number: {id}");
|
if (id <= 0) throw new ArgumentException($"Invalid MRB number: {id}");
|
||||||
|
|
||||||
MRB? mrb = _cache.Get<MRB>($"mrb{id}");
|
MRB? mrb = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
mrb = _cache.Get<MRB>($"mrb{id}");
|
||||||
|
|
||||||
if (mrb is null) mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.MRBNumber == id);
|
if (mrb is null && !bypassCache) mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.MRBNumber == id);
|
||||||
|
|
||||||
if (mrb is null) {
|
if (mrb is null) {
|
||||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/getById?id={id}");
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/getById?id={id}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
@ -147,12 +234,13 @@ public class MRBService : IMRBService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<MRB> GetMRBByTitle(string title, bool bypassCache) {
|
public async Task<MRB> GetMRBByTitle(string title, bool bypassCache) {
|
||||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or emtpy");
|
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||||
|
|
||||||
MRB? mrb = null;
|
MRB? mrb = null;
|
||||||
if (!bypassCache) mrb = _cache.Get<MRB>($"mrb{title}");
|
if (!bypassCache) mrb = _cache.Get<MRB>($"mrb{title}");
|
||||||
|
|
||||||
if (mrb is null) mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.Title.Equals(title));
|
if (mrb is null && !bypassCache)
|
||||||
|
mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.Title.Equals(title));
|
||||||
|
|
||||||
if (mrb is null) {
|
if (mrb is null) {
|
||||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
@ -324,7 +412,8 @@ public class MRBService : IMRBService {
|
|||||||
|
|
||||||
foreach (IBrowserFile file in files) {
|
foreach (IBrowserFile file in files) {
|
||||||
try {
|
try {
|
||||||
StreamContent fileContent = new StreamContent(file.OpenReadStream());
|
long maxFileSize = 1024L * 1024L * 1024L * 2L;
|
||||||
|
StreamContent fileContent = new StreamContent(file.OpenReadStream(maxFileSize));
|
||||||
|
|
||||||
FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider();
|
FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider();
|
||||||
|
|
||||||
@ -349,9 +438,85 @@ public class MRBService : IMRBService {
|
|||||||
if (!responseMessage.IsSuccessStatusCode)
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
throw new Exception($"Unable to save attachments, because {responseMessage.ReasonPhrase}");
|
throw new Exception($"Unable to save attachments, because {responseMessage.ReasonPhrase}");
|
||||||
|
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
IEnumerable<UploadResult> results = JsonSerializer.Deserialize<IEnumerable<UploadResult>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
new List<UploadResult>();
|
||||||
|
|
||||||
|
foreach (UploadResult result in results) {
|
||||||
|
if (result.UploadSuccessful) {
|
||||||
|
_snackbar.Add($"{result.FileName} successfully uploaded", Severity.Success);
|
||||||
|
} else {
|
||||||
|
_snackbar.Add($"{result.FileName} not uploaded, because {result.Error}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await GetAllAttachmentsForMRB(mrbNumber, true);
|
await GetAllAttachmentsForMRB(mrbNumber, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UploadActionAttachments(IEnumerable<IBrowserFile> files, int actionId) {
|
||||||
|
if (files is null) throw new ArgumentNullException("Files cannot be null");
|
||||||
|
if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty");
|
||||||
|
if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/action/attach?actionId={actionId}");
|
||||||
|
|
||||||
|
using MultipartFormDataContent content = new MultipartFormDataContent();
|
||||||
|
|
||||||
|
foreach (IBrowserFile file in files) {
|
||||||
|
try {
|
||||||
|
long maxFileSize = 1024L * 1024L * 1024L * 2L;
|
||||||
|
StreamContent fileContent = new StreamContent(file.OpenReadStream(maxFileSize));
|
||||||
|
|
||||||
|
FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider();
|
||||||
|
|
||||||
|
const string defaultContentType = "application/octet-stream";
|
||||||
|
|
||||||
|
if (!contentTypeProvider.TryGetContentType(file.Name, out string? contentType)) {
|
||||||
|
contentType = defaultContentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
|
||||||
|
|
||||||
|
content.Add(content: fileContent, name: "\"files\"", fileName: file.Name);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_snackbar.Add($"File {file.Name} not saved, because {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestMessage.Content = content;
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception($"Unable to save action attachments, because {responseMessage.ReasonPhrase}");
|
||||||
|
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
IEnumerable<UploadResult> results = JsonSerializer.Deserialize<IEnumerable<UploadResult>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
new List<UploadResult>();
|
||||||
|
|
||||||
|
foreach (UploadResult result in results) {
|
||||||
|
if (result.UploadSuccessful) {
|
||||||
|
_snackbar.Add($"{result.FileName} successfully uploaded", Severity.Success);
|
||||||
|
} else {
|
||||||
|
_snackbar.Add($"{result.FileName} not uploaded, because {result.Error}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await GetAllAttachmentsForMRB(actionId, true);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache) {
|
public async Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache) {
|
||||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||||
|
|
||||||
@ -386,6 +551,40 @@ public class MRBService : IMRBService {
|
|||||||
return mrbAttachments;
|
return mrbAttachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache) {
|
||||||
|
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||||
|
|
||||||
|
IEnumerable<MRBActionAttachment>? actionAttachments = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
actionAttachments = _cache.Get<IEnumerable<MRBActionAttachment>>($"mrbActionAttachments{mrbNumber}");
|
||||||
|
|
||||||
|
if (actionAttachments is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/action/attachments?mrbNumber={mrbNumber}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
actionAttachments = JsonSerializer.Deserialize<IEnumerable<MRBActionAttachment>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
new List<MRBActionAttachment>();
|
||||||
|
|
||||||
|
if (actionAttachments.Count() > 0)
|
||||||
|
_cache.Set($"mrbActionAttachments{mrbNumber}", actionAttachments, DateTimeOffset.Now.AddMinutes(5));
|
||||||
|
} else {
|
||||||
|
throw new Exception($"Unable to get MRB {mrbNumber} action attachments, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return actionAttachments;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteAttachment(MRBAttachment attachment) {
|
public async Task DeleteAttachment(MRBAttachment attachment) {
|
||||||
if (attachment is null) throw new ArgumentNullException("MRB attachment cannot be null");
|
if (attachment is null) throw new ArgumentNullException("MRB attachment cannot be null");
|
||||||
|
|
||||||
@ -534,4 +733,23 @@ public class MRBService : IMRBService {
|
|||||||
if (!responseMessage.IsSuccessStatusCode)
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
throw new Exception($"Unable to notify MRB originator, because {responseMessage.ReasonPhrase}");
|
throw new Exception($"Unable to notify MRB originator, because {responseMessage.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task NotifyQAPreApprover(MRBNotification notification) {
|
||||||
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/notify/qa-pre-approver");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception($"Unable to notify QA pre approver, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,16 @@ public class MesaFabApprovalAuthStateProvider : AuthenticationStateProvider, IDi
|
|||||||
CurrentUser = await _authService.GetCurrentUser();
|
CurrentUser = await _authService.GetCurrentUser();
|
||||||
|
|
||||||
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)));
|
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)));
|
||||||
|
|
||||||
|
if (CurrentUser is null) {
|
||||||
|
string loginId = _userService.GetLoginIdFromClaimsPrincipal(principal);
|
||||||
|
|
||||||
|
User? user = await _userService.GetUserByLoginId(loginId);
|
||||||
|
|
||||||
|
await _authService.SetCurrentUser(user);
|
||||||
|
|
||||||
|
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LoginAsync(string loginId, string password) {
|
public async Task LoginAsync(string loginId, string password) {
|
||||||
@ -64,6 +74,19 @@ public class MesaFabApprovalAuthStateProvider : AuthenticationStateProvider, IDi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task LoginLocal() {
|
||||||
|
try {
|
||||||
|
ClaimsPrincipal principal = await _authService.AttemptLocalUserAuth();
|
||||||
|
|
||||||
|
CurrentUser = await _authService.GetCurrentUser();
|
||||||
|
|
||||||
|
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_snackbar.Add(ex.Message, Severity.Error);
|
||||||
|
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Logout() {
|
public async Task Logout() {
|
||||||
CurrentUser = null;
|
CurrentUser = null;
|
||||||
await _authService.ClearTokens();
|
await _authService.ClearTokens();
|
||||||
@ -82,7 +105,7 @@ public class MesaFabApprovalAuthStateProvider : AuthenticationStateProvider, IDi
|
|||||||
CurrentUser = await _authService.GetCurrentUser();
|
CurrentUser = await _authService.GetCurrentUser();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Console.WriteLine($"Unable to get authentication state, because {ex.Message}");
|
// _snackbar.Add($"Unable to fetch authentication state, because {ex.Message}", Severity.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
767
MesaFabApproval.Client/Services/PCRBService.cs
Normal file
767
MesaFabApproval.Client/Services/PCRBService.cs
Normal file
@ -0,0 +1,767 @@
|
|||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
using MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
using MudBlazor;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Client.Services;
|
||||||
|
|
||||||
|
public interface IPCRBService {
|
||||||
|
Task<string> IdIsValid(string id);
|
||||||
|
Task<bool> IdIsValid(int id);
|
||||||
|
Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache);
|
||||||
|
Task CreateNewPCRB(PCRB pcrb);
|
||||||
|
Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task<PCRB> GetPCRBByTitle(string title, bool bypassCache);
|
||||||
|
Task UpdatePCRB(PCRB pcrb);
|
||||||
|
Task DeletePCRB(int planNumber);
|
||||||
|
Task UploadAttachment(PCRBAttachment attachment);
|
||||||
|
Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task UpdateAttachment(PCRBAttachment attachment);
|
||||||
|
Task DeleteAttachment(PCRBAttachment attachment);
|
||||||
|
Task CreateNewActionItem(PCRBActionItem actionItem);
|
||||||
|
Task UpdateActionItem(PCRBActionItem actionItem);
|
||||||
|
Task DeleteActionItem(int id);
|
||||||
|
Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task CreateNewAttendee(PCRBAttendee attendee);
|
||||||
|
Task UpdateAttendee(PCRBAttendee attendee);
|
||||||
|
Task DeleteAttendee(int id);
|
||||||
|
Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task CreatePCR3Document(PCR3Document document);
|
||||||
|
Task UpdatePCR3Document(PCR3Document document);
|
||||||
|
Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache);
|
||||||
|
Task NotifyNewApprovals(PCRB pcrb);
|
||||||
|
Task NotifyApprovers(PCRBNotification notification);
|
||||||
|
Task NotifyOriginator(PCRBNotification notification);
|
||||||
|
Task NotifyResponsiblePerson(PCRBActionItemNotification notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PCRBService : IPCRBService {
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
private readonly ISnackbar _snackbar;
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
|
||||||
|
public PCRBService(IMemoryCache cache,
|
||||||
|
IHttpClientFactory httpClientFactory,
|
||||||
|
ISnackbar snackbar,
|
||||||
|
IUserService userService) {
|
||||||
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
|
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||||
|
_snackbar = snackbar ?? throw new ArgumentNullException("ISnackbar not injected");
|
||||||
|
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> IdIsValid(string id) {
|
||||||
|
bool isMatch = true;
|
||||||
|
if (string.IsNullOrWhiteSpace(id)) isMatch = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/getByPlanNumber?planNumber={id}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
PCRB? pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions);
|
||||||
|
|
||||||
|
if (pcrb is null) isMatch = false;
|
||||||
|
} else {
|
||||||
|
isMatch = false;
|
||||||
|
}
|
||||||
|
} catch (Exception) {
|
||||||
|
isMatch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMatch) return $"{id} is not a valid PCRB#";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IdIsValid(int id) {
|
||||||
|
bool isMatch = true;
|
||||||
|
if (id <= 0) isMatch = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/getByPlanNumber?planNumber={id}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
PCRB? pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions);
|
||||||
|
|
||||||
|
if (pcrb is null) isMatch = false;
|
||||||
|
} else {
|
||||||
|
isMatch = false;
|
||||||
|
}
|
||||||
|
} catch (Exception) {
|
||||||
|
isMatch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache) {
|
||||||
|
try {
|
||||||
|
IEnumerable<PCRB>? allPCRBs = null;
|
||||||
|
if (!bypassCache) allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
|
||||||
|
if (allPCRBs is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/all?bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
allPCRBs = JsonSerializer.Deserialize<IEnumerable<PCRB>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
throw new Exception("Unable to parse PCRBs from API response");
|
||||||
|
|
||||||
|
_cache.Set($"allPCRBs", allPCRBs, DateTimeOffset.Now.AddMinutes(15));
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allPCRBs;
|
||||||
|
} catch (Exception) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateNewPCRB(PCRB pcrb) {
|
||||||
|
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(pcrb),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
PCRB newPCRB = await GetPCRBByTitle(pcrb.Title, true);
|
||||||
|
|
||||||
|
_cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
_cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
|
||||||
|
IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
if (allPCRBs is not null) {
|
||||||
|
List<PCRB> pcrbList = allPCRBs.ToList();
|
||||||
|
pcrbList.Add(newPCRB);
|
||||||
|
_cache.Set("allPCRBs", pcrbList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan #");
|
||||||
|
|
||||||
|
PCRB? pcrb = null;
|
||||||
|
if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{planNumber}");
|
||||||
|
|
||||||
|
if (pcrb is null && !bypassCache)
|
||||||
|
pcrb = _cache.Get<IEnumerable<PCRB>>("allPCRBs")?.FirstOrDefault(m => m.PlanNumber == planNumber);
|
||||||
|
|
||||||
|
if (pcrb is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage =
|
||||||
|
new(HttpMethod.Get, $"pcrb/getByPlanNumber?planNumber={planNumber}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions) ??
|
||||||
|
throw new Exception("unable to parse PCRB from API response");
|
||||||
|
|
||||||
|
_cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
_cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
|
||||||
|
if (bypassCache) {
|
||||||
|
IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
if (allPCRBs is not null) {
|
||||||
|
List<PCRB> pcrbList = allPCRBs.ToList();
|
||||||
|
pcrbList.RemoveAll(p => p.PlanNumber == planNumber);
|
||||||
|
pcrbList.Add(pcrb);
|
||||||
|
_cache.Set("allPCRBs", pcrbList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pcrb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PCRB> GetPCRBByTitle(string title, bool bypassCache) {
|
||||||
|
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentNullException("title cannot be null");
|
||||||
|
|
||||||
|
PCRB? pcrb = null;
|
||||||
|
if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{title}");
|
||||||
|
|
||||||
|
if (pcrb is null && !bypassCache)
|
||||||
|
pcrb = _cache.Get<IEnumerable<PCRB>>("allPCRBs")?.FirstOrDefault(m => m.Title.Equals(title));
|
||||||
|
|
||||||
|
if (pcrb is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage =
|
||||||
|
new(HttpMethod.Get, $"pcrb/getByTitle?title={title}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions) ??
|
||||||
|
throw new Exception("unable to parse PCRB from API response");
|
||||||
|
|
||||||
|
_cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
_cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
|
||||||
|
if (bypassCache) {
|
||||||
|
IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
if (allPCRBs is not null) {
|
||||||
|
List<PCRB> pcrbList = allPCRBs.ToList();
|
||||||
|
pcrbList.RemoveAll(p => p.PlanNumber == pcrb.PlanNumber);
|
||||||
|
pcrbList.Add(pcrb);
|
||||||
|
_cache.Set("allPCRBs", pcrbList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pcrb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdatePCRB(PCRB pcrb) {
|
||||||
|
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(pcrb),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
_cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
_cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1));
|
||||||
|
|
||||||
|
IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs");
|
||||||
|
if (allPCRBs is not null) {
|
||||||
|
List<PCRB> pcrbList = allPCRBs.ToList();
|
||||||
|
pcrbList.RemoveAll(m => m.PlanNumber == pcrb.PlanNumber);
|
||||||
|
pcrbList.Add(pcrb);
|
||||||
|
_cache.Set("allPCRBs", pcrbList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeletePCRB(int planNumber) {
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan #");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb?planNumber={planNumber}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode) throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
IEnumerable<PCRB> allPCRBs = await GetAllPCRBs(true);
|
||||||
|
_cache.Set("allPCRBs", allPCRBs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UploadAttachment(PCRBAttachment attachment) {
|
||||||
|
if (attachment is null) throw new ArgumentNullException("attachment cannot be null");
|
||||||
|
if (attachment.File is null) throw new ArgumentNullException("file cannot be null");
|
||||||
|
if (attachment.File.Size <= 0) throw new ArgumentException("file size must be greater than zero");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/attachment");
|
||||||
|
|
||||||
|
using MultipartFormDataContent content = new MultipartFormDataContent();
|
||||||
|
|
||||||
|
try {
|
||||||
|
long maxFileSize = 1024L * 1024L * 1024L * 2L;
|
||||||
|
StreamContent fileContent = new StreamContent(attachment.File.OpenReadStream(maxFileSize));
|
||||||
|
|
||||||
|
FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider();
|
||||||
|
|
||||||
|
const string defaultContentType = "application/octet-stream";
|
||||||
|
|
||||||
|
if (!contentTypeProvider.TryGetContentType(attachment.File.Name, out string? contentType)) {
|
||||||
|
contentType = defaultContentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
|
||||||
|
|
||||||
|
content.Add(content: fileContent, name: "\"file\"", fileName: attachment.File.Name);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_snackbar.Add(ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
content.Add(new StringContent(attachment.PlanNumber.ToString()), "PlanNumber");
|
||||||
|
content.Add(new StringContent(attachment.FileName), "FileName");
|
||||||
|
content.Add(new StringContent(attachment.UploadedByID.ToString()), "UploadedByID");
|
||||||
|
content.Add(new StringContent(attachment.Title), "Title");
|
||||||
|
content.Add(new StringContent(attachment.UploadDateTime.ToString("yyyy-MM-dd HH:mm:ss")), "UploadDateTime");
|
||||||
|
content.Add(new StringContent(attachment.Step.ToString()), "Step");
|
||||||
|
|
||||||
|
requestMessage.Content = content;
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
await GetAttachmentsByPlanNumber(attachment.PlanNumber, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCRBAttachment>? attachments = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
attachments = _cache.Get<IEnumerable<PCRBAttachment>>($"pcrbAttachments{planNumber}");
|
||||||
|
|
||||||
|
if (attachments is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/attachments?planNumber={planNumber}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
attachments = JsonSerializer.Deserialize<IEnumerable<PCRBAttachment>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
new List<PCRBAttachment>();
|
||||||
|
|
||||||
|
if (attachments.Count() > 0) {
|
||||||
|
foreach (PCRBAttachment attachment in attachments) {
|
||||||
|
attachment.UploadedBy = await _userService.GetUserByUserId(attachment.UploadedByID);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Set($"pcrbAttachments{planNumber}", attachments, DateTimeOffset.Now.AddMinutes(5));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAttachment(PCRBAttachment attachment) {
|
||||||
|
if (attachment is null) throw new ArgumentNullException("attachment cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/attachment");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(attachment),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAttachment(PCRBAttachment attachment) {
|
||||||
|
if (attachment is null) throw new ArgumentNullException("attachment cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb/attachment");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(attachment),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateNewActionItem(PCRBActionItem actionItem) {
|
||||||
|
if (actionItem is null) throw new ArgumentNullException("action item cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/actionItem");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(actionItem),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
await GetActionItemsForPlanNumber(actionItem.PlanNumber, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateActionItem(PCRBActionItem actionItem) {
|
||||||
|
if (actionItem is null) throw new ArgumentNullException("action item cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/actionItem");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(actionItem),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteActionItem(int id) {
|
||||||
|
if (id <= 0) throw new ArgumentException($"{id} is not a valid PCRB action item ID");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb/actionItem?id={id}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode) throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCRBActionItem>? actionItems = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
actionItems = _cache.Get<IEnumerable<PCRBActionItem>>($"pcrbActionItems{planNumber}");
|
||||||
|
|
||||||
|
if (actionItems is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/actionItems?planNumber={planNumber}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
actionItems = JsonSerializer.Deserialize<IEnumerable<PCRBActionItem>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
new List<PCRBActionItem>();
|
||||||
|
|
||||||
|
if (actionItems.Count() > 0) {
|
||||||
|
foreach (PCRBActionItem actionItem in actionItems) {
|
||||||
|
actionItem.UploadedBy = await _userService.GetUserByUserId(actionItem.UploadedByID);
|
||||||
|
if (actionItem.ResponsiblePersonID > 0)
|
||||||
|
actionItem.ResponsiblePerson = await _userService.GetUserByUserId(actionItem.ResponsiblePersonID);
|
||||||
|
if (actionItem.ClosedByID > 0)
|
||||||
|
actionItem.ClosedBy = await _userService.GetUserByUserId(actionItem.ClosedByID);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Set($"pcrbActionItems{planNumber}", actionItems, DateTimeOffset.Now.AddMinutes(5));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return actionItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateNewAttendee(PCRBAttendee attendee) {
|
||||||
|
if (attendee is null) throw new ArgumentNullException("attendee cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/attendee");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(attendee),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
await GetAttendeesByPlanNumber(attendee.PlanNumber, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAttendee(PCRBAttendee attendee) {
|
||||||
|
if (attendee is null) throw new ArgumentNullException("attendee cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/attendee");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(attendee),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAttendee(int id) {
|
||||||
|
if (id <= 0) throw new ArgumentException($"{id} is not a valid PCRB attendee ID");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb/attendee?id={id}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode) throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCRBAttendee>? attendees = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
attendees = _cache.Get<IEnumerable<PCRBAttendee>>($"pcrbAttendees{planNumber}");
|
||||||
|
|
||||||
|
if (attendees is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/attendees?planNumber={planNumber}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
attendees = JsonSerializer.Deserialize<IEnumerable<PCRBAttendee>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
new List<PCRBAttendee>();
|
||||||
|
|
||||||
|
if (attendees.Count() > 0) {
|
||||||
|
foreach (PCRBAttendee attendee in attendees)
|
||||||
|
attendee.Attendee = await _userService.GetUserByUserId(attendee.AttendeeID);
|
||||||
|
|
||||||
|
_cache.Set($"pcrbAttendees{planNumber}", attendees, DateTimeOffset.Now.AddMinutes(5));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attendees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreatePCR3Document(PCR3Document document) {
|
||||||
|
if (document is null) throw new ArgumentNullException("document cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/pcr3Document");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(document),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
|
||||||
|
await GetPCR3DocumentsForPlanNumber(document.PlanNumber, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdatePCR3Document(PCR3Document document) {
|
||||||
|
if (document is null) throw new ArgumentNullException("document cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/pcr3Document");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(document),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache) {
|
||||||
|
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#");
|
||||||
|
|
||||||
|
IEnumerable<PCR3Document>? documents = null;
|
||||||
|
if (!bypassCache)
|
||||||
|
documents = _cache.Get<IEnumerable<PCR3Document>>($"pcr3Documents{planNumber}");
|
||||||
|
|
||||||
|
if (documents is null) {
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/pcr3Documents?planNumber={planNumber}&bypassCache={bypassCache}");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (responseMessage.IsSuccessStatusCode) {
|
||||||
|
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
documents = JsonSerializer.Deserialize<IEnumerable<PCR3Document>>(responseContent, jsonSerializerOptions) ??
|
||||||
|
new List<PCR3Document>();
|
||||||
|
|
||||||
|
if (documents.Count() > 0) {
|
||||||
|
foreach (PCR3Document document in documents) {
|
||||||
|
if (document.CompletedByID > 0)
|
||||||
|
document.CompletedBy = await _userService.GetUserByUserId(document.CompletedByID);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Set($"pcr3Documents{planNumber}", documents, DateTimeOffset.Now.AddMinutes(5));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception(responseMessage.ReasonPhrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return documents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyNewApprovals(PCRB pcrb) {
|
||||||
|
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/new-approvals");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(pcrb),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception($"Unable to notify new PCRB approvers, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyApprovers(PCRBNotification notification) {
|
||||||
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/approvers");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception($"Unable to notify PCRB approvers, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyOriginator(PCRBNotification notification) {
|
||||||
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/originator");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception($"Unable to notify PCRB originator, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyResponsiblePerson(PCRBActionItemNotification notification) {
|
||||||
|
if (notification is null) throw new ArgumentNullException("notification cannot be null");
|
||||||
|
if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty");
|
||||||
|
|
||||||
|
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/responsiblePerson");
|
||||||
|
|
||||||
|
requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||||
|
|
||||||
|
if (!responseMessage.IsSuccessStatusCode)
|
||||||
|
throw new Exception($"Unable to notify PCRB responsible person, because {responseMessage.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ using System.Text.Json;
|
|||||||
|
|
||||||
using MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components.WebAssembly.Http;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
namespace MesaFabApproval.Client.Services;
|
namespace MesaFabApproval.Client.Services;
|
||||||
@ -141,7 +142,7 @@ public class UserService : IUserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (activeUsers is null)
|
if (activeUsers is null)
|
||||||
activeUsers = new List<User>();
|
throw new Exception("unable to fetch all active users");
|
||||||
|
|
||||||
return activeUsers;
|
return activeUsers;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
namespace MesaFabApproval.Client.Util;
|
|
||||||
|
|
||||||
public class DateTimeUtilities {
|
|
||||||
public static string GetDateAsStringMinDefault(DateTime dt) {
|
|
||||||
return dt > DateTime.MinValue ? dt.ToString("yyyy-MM-dd HH:mm") : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetDateAsStringMaxDefault(DateTime dt) {
|
|
||||||
return dt < DateTime.MaxValue ? dt.ToString("yyyy-MM-dd HH:mm") : "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -8,12 +8,16 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using MesaFabApproval.Client.Services;
|
using MesaFabApproval.Client.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using MudBlazor;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace MesaFabApproval.Client.Utilities;
|
namespace MesaFabApproval.Client.Utilities;
|
||||||
|
|
||||||
public class ApiHttpClientHandler : DelegatingHandler {
|
public class ApiHttpClientHandler : DelegatingHandler {
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly IAuthenticationService _authService;
|
private readonly IAuthenticationService _authService;
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
private readonly ISnackbar _snackbar;
|
||||||
private readonly MesaFabApprovalAuthStateProvider _authStateProvider;
|
private readonly MesaFabApprovalAuthStateProvider _authStateProvider;
|
||||||
private readonly NavigationManager _navigationManager;
|
private readonly NavigationManager _navigationManager;
|
||||||
|
|
||||||
@ -22,11 +26,16 @@ public class ApiHttpClientHandler : DelegatingHandler {
|
|||||||
public ApiHttpClientHandler(IMemoryCache cache,
|
public ApiHttpClientHandler(IMemoryCache cache,
|
||||||
IConfiguration config,
|
IConfiguration config,
|
||||||
IAuthenticationService authService,
|
IAuthenticationService authService,
|
||||||
|
IHttpClientFactory httpClientFactory,
|
||||||
|
ISnackbar snackbar,
|
||||||
MesaFabApprovalAuthStateProvider authStateProvider,
|
MesaFabApprovalAuthStateProvider authStateProvider,
|
||||||
NavigationManager navigationManager) {
|
NavigationManager navigationManager) {
|
||||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||||
_apiBaseUrl = config["FabApprovalApiBaseUrl"] ??
|
_apiBaseUrl = config["FabApprovalApiBaseUrl"] ??
|
||||||
throw new NullReferenceException("FabApprovalApiBaseUrl not found in config");
|
throw new NullReferenceException("FabApprovalApiBaseUrl not found in config");
|
||||||
|
_httpClientFactory = httpClientFactory ??
|
||||||
|
throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||||
|
_snackbar = snackbar ?? throw new ArgumentNullException("ISnackbar not injected");
|
||||||
_authService = authService ??
|
_authService = authService ??
|
||||||
throw new ArgumentNullException("IAuthenticationService not injected");
|
throw new ArgumentNullException("IAuthenticationService not injected");
|
||||||
_authStateProvider = authStateProvider ??
|
_authStateProvider = authStateProvider ??
|
||||||
@ -39,14 +48,27 @@ public class ApiHttpClientHandler : DelegatingHandler {
|
|||||||
CancellationToken cancellationToken) {
|
CancellationToken cancellationToken) {
|
||||||
AuthTokens? authTokens = await _authService.GetAuthTokens();
|
AuthTokens? authTokens = await _authService.GetAuthTokens();
|
||||||
|
|
||||||
if (authTokens is not null) requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken);
|
HttpRequestMessage initialRequestMessage = new() {
|
||||||
|
Content = requestMessage.Content,
|
||||||
|
Method = requestMessage.Method,
|
||||||
|
RequestUri = requestMessage.RequestUri
|
||||||
|
};
|
||||||
|
|
||||||
HttpResponseMessage responseMessage = await base.SendAsync(requestMessage, cancellationToken);
|
if (authTokens is not null) {
|
||||||
|
initialRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken);
|
||||||
|
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpClient initialClient = _httpClientFactory.CreateClient("API_Handler");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = await initialClient.SendAsync(initialRequestMessage, cancellationToken);
|
||||||
|
|
||||||
|
HttpClient refreshClient = _httpClientFactory.CreateClient("API_Handler");
|
||||||
|
|
||||||
if (responseMessage.StatusCode.Equals(HttpStatusCode.Unauthorized)) {
|
if (responseMessage.StatusCode.Equals(HttpStatusCode.Unauthorized)) {
|
||||||
string? loginId = await _authService.GetLoginId();
|
string? loginId = await _authService.GetLoginId();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(loginId) && authTokens is not null) {
|
if (!string.IsNullOrWhiteSpace(loginId)) {
|
||||||
AuthAttempt authAttempt = new() {
|
AuthAttempt authAttempt = new() {
|
||||||
LoginID = loginId,
|
LoginID = loginId,
|
||||||
AuthTokens = authTokens
|
AuthTokens = authTokens
|
||||||
@ -54,29 +76,25 @@ public class ApiHttpClientHandler : DelegatingHandler {
|
|||||||
|
|
||||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/refresh");
|
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/refresh");
|
||||||
|
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken);
|
|
||||||
|
|
||||||
request.Content = new StringContent(JsonSerializer.Serialize(authAttempt),
|
request.Content = new StringContent(JsonSerializer.Serialize(authAttempt),
|
||||||
Encoding.UTF8,
|
Encoding.UTF8,
|
||||||
"application/json");
|
"application/json");
|
||||||
|
|
||||||
HttpClient httpClient = new HttpClient() {
|
if (authTokens is not null) {
|
||||||
BaseAddress = new Uri(_apiBaseUrl)
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken);
|
||||||
};
|
}
|
||||||
|
|
||||||
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
|
HttpResponseMessage httpResponseMessage = await refreshClient.SendAsync(request, cancellationToken);
|
||||||
|
|
||||||
HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request, cancellationToken);
|
|
||||||
|
|
||||||
if (httpResponseMessage.IsSuccessStatusCode) {
|
|
||||||
string responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
|
string responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
if (httpResponseMessage.IsSuccessStatusCode) {
|
||||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||||
PropertyNameCaseInsensitive = true
|
PropertyNameCaseInsensitive = true
|
||||||
};
|
};
|
||||||
|
|
||||||
LoginResult loginResult = JsonSerializer.Deserialize<LoginResult>(responseContent, jsonSerializerOptions) ??
|
LoginResult loginResult = JsonSerializer.Deserialize<LoginResult>(responseContent, jsonSerializerOptions) ??
|
||||||
throw new Exception("Unable to parse login result from API response");
|
throw new Exception("unable to parse login result from API response");
|
||||||
|
|
||||||
if (!loginResult.IsAuthenticated) throw new Exception($"User with Login ID {loginId} not authorized");
|
if (!loginResult.IsAuthenticated) throw new Exception($"User with Login ID {loginId} not authorized");
|
||||||
|
|
||||||
@ -91,6 +109,7 @@ public class ApiHttpClientHandler : DelegatingHandler {
|
|||||||
await _authStateProvider.Logout();
|
await _authStateProvider.Logout();
|
||||||
|
|
||||||
string? redirectUrl = _cache.Get<string>("redirectUrl");
|
string? redirectUrl = _cache.Get<string>("redirectUrl");
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(redirectUrl)) {
|
if (!string.IsNullOrWhiteSpace(redirectUrl)) {
|
||||||
_navigationManager.NavigateTo($"login/{redirectUrl}");
|
_navigationManager.NavigateTo($"login/{redirectUrl}");
|
||||||
} else {
|
} else {
|
||||||
@ -102,6 +121,9 @@ public class ApiHttpClientHandler : DelegatingHandler {
|
|||||||
return await base.SendAsync(requestMessage, cancellationToken);
|
return await base.SendAsync(requestMessage, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialClient.Dispose();
|
||||||
|
refreshClient.Dispose();
|
||||||
|
|
||||||
return responseMessage;
|
return responseMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
@using MesaFabApproval.Client.Layout
|
@using MesaFabApproval.Client.Layout
|
||||||
@using MesaFabApproval.Client.Pages.Components
|
@using MesaFabApproval.Client.Pages.Components
|
||||||
@using MesaFabApproval.Client.Services
|
@using MesaFabApproval.Client.Services
|
||||||
@using MesaFabApproval.Client.Util
|
@using MesaFabApproval.Shared.Utilities
|
||||||
@using MesaFabApproval.Shared.Models
|
@using MesaFabApproval.Shared.Models
|
||||||
@using MudBlazor
|
@using MudBlazor
|
||||||
@using Microsoft.AspNetCore.Authorization
|
@using Microsoft.AspNetCore.Authorization
|
||||||
|
|||||||
5
MesaFabApproval.Client/wwwroot/js/OpenInNewWindow.js
Normal file
5
MesaFabApproval.Client/wwwroot/js/OpenInNewWindow.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export function OpenInNewWindow(url, message) {
|
||||||
|
var newwindow = window.open('', '_blank');
|
||||||
|
newwindow.document.write(message);
|
||||||
|
newwindow.location.href = url;
|
||||||
|
}
|
||||||
262
MesaFabApproval.Shared/.editorconfig
Normal file
262
MesaFabApproval.Shared/.editorconfig
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# C# files
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
#### Core EditorConfig Options ####
|
||||||
|
|
||||||
|
# Indentation and spacing
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
end_of_line = crlf
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
#### .NET Coding Conventions ####
|
||||||
|
|
||||||
|
# Organize usings
|
||||||
|
dotnet_separate_import_directive_groups = true
|
||||||
|
dotnet_sort_system_directives_first = true
|
||||||
|
file_header_template = unset
|
||||||
|
|
||||||
|
# this. and Me. preferences
|
||||||
|
dotnet_style_qualification_for_event = true
|
||||||
|
dotnet_style_qualification_for_field = true
|
||||||
|
dotnet_style_qualification_for_method = true
|
||||||
|
dotnet_style_qualification_for_property = true
|
||||||
|
|
||||||
|
# Language keywords vs BCL types preferences
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||||
|
dotnet_style_predefined_type_for_member_access = true
|
||||||
|
|
||||||
|
# Parentheses preferences
|
||||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:error
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:error
|
||||||
|
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:error
|
||||||
|
|
||||||
|
# Modifier preferences
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||||
|
|
||||||
|
# Expression-level preferences
|
||||||
|
dotnet_style_coalesce_expression = false
|
||||||
|
dotnet_style_collection_initializer = true
|
||||||
|
dotnet_style_explicit_tuple_names = true:error
|
||||||
|
dotnet_style_namespace_match_folder = true
|
||||||
|
dotnet_style_null_propagation = true
|
||||||
|
dotnet_style_object_initializer = true
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
dotnet_style_prefer_auto_properties = true
|
||||||
|
dotnet_style_prefer_compound_assignment = true
|
||||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
|
||||||
|
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = false
|
||||||
|
dotnet_style_prefer_inferred_tuple_names = false
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||||
|
dotnet_style_prefer_simplified_interpolation = true
|
||||||
|
|
||||||
|
# Field preferences
|
||||||
|
dotnet_style_readonly_field = true:warning
|
||||||
|
|
||||||
|
# Parameter preferences
|
||||||
|
dotnet_code_quality_unused_parameters = all:error
|
||||||
|
|
||||||
|
# Suppression preferences
|
||||||
|
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
dotnet_style_allow_multiple_blank_lines_experimental = false:error
|
||||||
|
dotnet_style_allow_statement_immediately_after_block_experimental = false:warning
|
||||||
|
|
||||||
|
#### C# Coding Conventions ####
|
||||||
|
|
||||||
|
# var preferences
|
||||||
|
csharp_style_var_elsewhere = false:error
|
||||||
|
csharp_style_var_for_built_in_types = false:error
|
||||||
|
csharp_style_var_when_type_is_apparent = false:error
|
||||||
|
|
||||||
|
# Expression-bodied members
|
||||||
|
csharp_style_expression_bodied_accessors = false
|
||||||
|
csharp_style_expression_bodied_constructors = false
|
||||||
|
csharp_style_expression_bodied_indexers = false
|
||||||
|
csharp_style_expression_bodied_lambdas = true
|
||||||
|
csharp_style_expression_bodied_local_functions = false
|
||||||
|
csharp_style_expression_bodied_methods = when_on_single_line:suggestion
|
||||||
|
csharp_style_expression_bodied_operators = false
|
||||||
|
csharp_style_expression_bodied_properties = false
|
||||||
|
|
||||||
|
# Pattern matching preferences
|
||||||
|
csharp_style_pattern_matching_over_as_with_null_check = false
|
||||||
|
csharp_style_pattern_matching_over_is_with_cast_check = false
|
||||||
|
csharp_style_prefer_extended_property_pattern = true
|
||||||
|
csharp_style_prefer_not_pattern = true
|
||||||
|
csharp_style_prefer_pattern_matching = true
|
||||||
|
csharp_style_prefer_switch_expression = false
|
||||||
|
|
||||||
|
# Null-checking preferences
|
||||||
|
csharp_style_conditional_delegate_call = false
|
||||||
|
|
||||||
|
# Modifier preferences
|
||||||
|
csharp_prefer_static_local_function = false
|
||||||
|
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
|
||||||
|
csharp_style_prefer_readonly_struct = true:warning
|
||||||
|
csharp_style_prefer_readonly_struct_member = true
|
||||||
|
|
||||||
|
# Code-block preferences
|
||||||
|
csharp_prefer_braces = when_multiline:error
|
||||||
|
csharp_prefer_simple_using_statement = false
|
||||||
|
csharp_style_namespace_declarations = file_scoped:error
|
||||||
|
csharp_style_prefer_method_group_conversion = true:suggestion
|
||||||
|
csharp_style_prefer_top_level_statements = true:error
|
||||||
|
|
||||||
|
# Expression-level preferences
|
||||||
|
csharp_prefer_simple_default_expression = true
|
||||||
|
csharp_style_deconstructed_variable_declaration = false
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = false
|
||||||
|
csharp_style_inlined_variable_declaration = true
|
||||||
|
csharp_style_prefer_index_operator = false:error
|
||||||
|
csharp_style_prefer_local_over_anonymous_function = true:error
|
||||||
|
csharp_style_prefer_null_check_over_type_check = true
|
||||||
|
csharp_style_prefer_range_operator = false:error
|
||||||
|
csharp_style_prefer_tuple_swap = true
|
||||||
|
csharp_style_prefer_utf8_string_literals = true
|
||||||
|
csharp_style_throw_expression = false
|
||||||
|
csharp_style_unused_value_assignment_preference = unused_local_variable
|
||||||
|
csharp_style_unused_value_expression_statement_preference = unused_local_variable
|
||||||
|
|
||||||
|
# 'using' directive preferences
|
||||||
|
csharp_using_directive_placement = outside_namespace:error
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
||||||
|
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
|
||||||
|
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
|
||||||
|
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:error
|
||||||
|
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
||||||
|
|
||||||
|
#### C# Formatting Rules ####
|
||||||
|
|
||||||
|
# New line preferences
|
||||||
|
csharp_new_line_before_catch = false
|
||||||
|
csharp_new_line_before_else = false
|
||||||
|
csharp_new_line_before_finally = false
|
||||||
|
csharp_new_line_before_members_in_anonymous_types = true
|
||||||
|
csharp_new_line_before_members_in_object_initializers = true
|
||||||
|
csharp_new_line_before_open_brace = none
|
||||||
|
csharp_new_line_between_query_expression_clauses = true
|
||||||
|
|
||||||
|
# Indentation preferences
|
||||||
|
csharp_indent_block_contents = true
|
||||||
|
csharp_indent_braces = false
|
||||||
|
csharp_indent_case_contents = true
|
||||||
|
csharp_indent_case_contents_when_block = true
|
||||||
|
csharp_indent_labels = one_less_than_current
|
||||||
|
csharp_indent_switch_labels = true
|
||||||
|
|
||||||
|
# Space preferences
|
||||||
|
csharp_space_after_cast = false
|
||||||
|
csharp_space_after_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_after_comma = true
|
||||||
|
csharp_space_after_dot = false
|
||||||
|
csharp_space_after_keywords_in_control_flow_statements = true
|
||||||
|
csharp_space_after_semicolon_in_for_statement = true
|
||||||
|
csharp_space_around_binary_operators = before_and_after
|
||||||
|
csharp_space_around_declaration_statements = false
|
||||||
|
csharp_space_before_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_before_comma = false
|
||||||
|
csharp_space_before_dot = false
|
||||||
|
csharp_space_before_open_square_brackets = false
|
||||||
|
csharp_space_before_semicolon_in_for_statement = false
|
||||||
|
csharp_space_between_empty_square_brackets = false
|
||||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||||
|
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_parentheses = false
|
||||||
|
csharp_space_between_square_brackets = false
|
||||||
|
|
||||||
|
# Wrapping preferences
|
||||||
|
csharp_preserve_single_line_blocks = true
|
||||||
|
csharp_preserve_single_line_statements = true
|
||||||
|
|
||||||
|
#### Naming styles ####
|
||||||
|
|
||||||
|
# Naming rules
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||||
|
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
# Symbol specifications
|
||||||
|
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.types.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
|
||||||
|
# Naming styles
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case.required_prefix =
|
||||||
|
dotnet_naming_style.pascal_case.required_suffix =
|
||||||
|
dotnet_naming_style.pascal_case.word_separator =
|
||||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||||
|
dotnet_naming_style.begins_with_i.required_suffix =
|
||||||
|
dotnet_naming_style.begins_with_i.word_separator =
|
||||||
|
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||||
|
|
||||||
|
# Question
|
||||||
|
|
||||||
|
dotnet_diagnostic.ASP0025.severity = none # Use AddAuthorizationBuilder to register authorization services and construct policies [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1510.severity = none # Use 'ArgumentNullException.ThrowIfNull' instead of explicitly throwing a new exception instance [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1806.severity = none # 'MRBNumberIsValid' calls 'Append' but does not use the value the method returns. Linq methods are known to not have side effects. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1822.severity = none # Member 'GenerateRefreshToken' does not access instance data and can be marked as static [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1825.severity = none # Avoid unnecessary zero-length array allocations. Use Array.Empty<string>() instead. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1827.severity = none # Count() is used where Any() could be used instead to improve performance [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1829.severity = none # Use the \"Count\" property instead of Enumerable.Count() [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA1861.severity = none # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA2208.severity = none # Method UpdateMRBAction passes 'MRB action cannot be null' as the paramName argument to a ArgumentNullException constructor. Replace this argument with one of the method's parameter names. Note that the provided parameter name should have the exact casing as declared on the method. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CA2211.severity = none # Non-constant fields should not be visible
|
||||||
|
dotnet_diagnostic.CA2254.severity = none # The type or namespace name 'AspNetCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.CS0234.severity = none # The type or namespace name 'Extensions' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.CS0246.severity = none # The type or namespace name 'ILogger<>' could not be found (are you missing a using directive or an assembly reference?) [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.CS1998.severity = none # This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CS8019.severity = none # Unnecessary using directive
|
||||||
|
dotnet_diagnostic.CS8600.severity = none # Converting null literal or possible null value to non-nullable type. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CS8625.severity = none # Cannot convert null literal to non-nullable reference type. [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.CS8765.severity = none # Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes). [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.IDE0001.severity = none # Name can be simplified
|
||||||
|
dotnet_diagnostic.IDE0017.severity = none # Object initialization can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0022.severity = none # Use expression body for method [MesaFabApproval.Shared]",
|
||||||
|
dotnet_diagnostic.IDE0028.severity = none # Collection initialization can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0044.severity = none # Make field readonly [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0046.severity = none # "'if' statement can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0052.severity = none # Private member 'CustomerController._cache' can be removed as the value assigned to it is never read [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0074.severity = none # Use compound assignment [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE0305.severity = none # Collection initialization can be simplified [MesaFabApproval.API]",
|
||||||
|
dotnet_diagnostic.IDE1006.severity = none # Naming rule violation: These words must begin with upper case characters
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = false
|
||||||
1
MesaFabApproval.Shared/.vscode/format-report.json
vendored
Normal file
1
MesaFabApproval.Shared/.vscode/format-report.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
6
MesaFabApproval.Shared/.vscode/mklink.md
vendored
Normal file
6
MesaFabApproval.Shared/.vscode/mklink.md
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# mklink
|
||||||
|
|
||||||
|
```bash 1731705389065 = 638673021890650000 = Fri Nov 15 2024 14:16:28 GMT-0700 (Mountain Standard Time)
|
||||||
|
mklink /J "L:\DevOps\Mesa_FI\MesaFabApproval\MesaFabApproval.API\.vscode\.UserSecrets" "C:\Users\phares\AppData\Roaming\Microsoft\UserSecrets\0b98e1f2-95ed-4edd-8149-58cce51ca059"
|
||||||
|
dotnet run --urls=https://localhost:7114/ -C Release
|
||||||
|
```
|
||||||
429
MesaFabApproval.Shared/.vscode/settings.json
vendored
Normal file
429
MesaFabApproval.Shared/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,429 @@
|
|||||||
|
{
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.wordWrap": "off"
|
||||||
|
},
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": false,
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/node_modules": true
|
||||||
|
},
|
||||||
|
"cSpell.words": [
|
||||||
|
"abutton",
|
||||||
|
"accessibilities",
|
||||||
|
"accodingly",
|
||||||
|
"acknowledgmentby",
|
||||||
|
"Acks",
|
||||||
|
"actionsheet",
|
||||||
|
"Additonal",
|
||||||
|
"Addtional",
|
||||||
|
"againm",
|
||||||
|
"agendaview",
|
||||||
|
"AHPS",
|
||||||
|
"Akrion",
|
||||||
|
"Antlr",
|
||||||
|
"Appover",
|
||||||
|
"Appprrovers",
|
||||||
|
"Approvalog",
|
||||||
|
"Aprovers",
|
||||||
|
"Aproverslist",
|
||||||
|
"asax",
|
||||||
|
"aspnetmvc",
|
||||||
|
"Assignedto",
|
||||||
|
"Atachments",
|
||||||
|
"Attachemnt",
|
||||||
|
"Attachemnts",
|
||||||
|
"Attchment",
|
||||||
|
"auditee",
|
||||||
|
"Auditee",
|
||||||
|
"Auditees",
|
||||||
|
"automaically",
|
||||||
|
"Autthorized",
|
||||||
|
"beacuase",
|
||||||
|
"beforeunload",
|
||||||
|
"Belguim",
|
||||||
|
"bfound",
|
||||||
|
"bgcolor",
|
||||||
|
"Bies",
|
||||||
|
"binded",
|
||||||
|
"Biorad",
|
||||||
|
"blackbackground",
|
||||||
|
"blackhover",
|
||||||
|
"blackpressed",
|
||||||
|
"blueenergy",
|
||||||
|
"blueopal",
|
||||||
|
"buttongroup",
|
||||||
|
"BYMRB",
|
||||||
|
"bytesgot",
|
||||||
|
"CAID",
|
||||||
|
"casection",
|
||||||
|
"CAXXXX",
|
||||||
|
"CCPCR",
|
||||||
|
"CCPCRB",
|
||||||
|
"cellspacing",
|
||||||
|
"Cheeso's",
|
||||||
|
"chkbx",
|
||||||
|
"Clib",
|
||||||
|
"colorpicker",
|
||||||
|
"columnmenu",
|
||||||
|
"columnsreorder",
|
||||||
|
"columnsresize",
|
||||||
|
"comming",
|
||||||
|
"Containmen",
|
||||||
|
"Copmments",
|
||||||
|
"correctiv",
|
||||||
|
"Correctivet",
|
||||||
|
"Creat",
|
||||||
|
"currentd",
|
||||||
|
"Cyle",
|
||||||
|
"dadada",
|
||||||
|
"darkbluehover",
|
||||||
|
"darkbluepressed",
|
||||||
|
"darkred",
|
||||||
|
"datafields",
|
||||||
|
"datasource",
|
||||||
|
"dataviz",
|
||||||
|
"datepicker",
|
||||||
|
"datetimepicker",
|
||||||
|
"dayview",
|
||||||
|
"Deletet",
|
||||||
|
"Delgation",
|
||||||
|
"DENITED",
|
||||||
|
"Deparmtent",
|
||||||
|
"departmentids",
|
||||||
|
"Descirption",
|
||||||
|
"devprog",
|
||||||
|
"dfeffc",
|
||||||
|
"Disp",
|
||||||
|
"Dispo",
|
||||||
|
"Dispoitio",
|
||||||
|
"Dispos",
|
||||||
|
"Dispositon",
|
||||||
|
"Dispostion",
|
||||||
|
"Dispostions",
|
||||||
|
"dispotypevalidation",
|
||||||
|
"Docbase",
|
||||||
|
"Documentum",
|
||||||
|
"Documetum",
|
||||||
|
"dont",
|
||||||
|
"downlaoded",
|
||||||
|
"draganddrop",
|
||||||
|
"dragcancel",
|
||||||
|
"dropdownlist",
|
||||||
|
"Eamils",
|
||||||
|
"ECNPCRB",
|
||||||
|
"Ecns",
|
||||||
|
"edmx",
|
||||||
|
"EECN",
|
||||||
|
"emai",
|
||||||
|
"emailparams",
|
||||||
|
"Emergrncy",
|
||||||
|
"energyblue",
|
||||||
|
"Eran",
|
||||||
|
"Esql",
|
||||||
|
"ETECN",
|
||||||
|
"EXCELOPENXML",
|
||||||
|
"existinglocation",
|
||||||
|
"Expando",
|
||||||
|
"extrafield",
|
||||||
|
"fadc",
|
||||||
|
"fbec",
|
||||||
|
"fcfdfd",
|
||||||
|
"fdff",
|
||||||
|
"fece",
|
||||||
|
"feeebd",
|
||||||
|
"ffdc",
|
||||||
|
"ffdd",
|
||||||
|
"fieldset",
|
||||||
|
"FILIPE",
|
||||||
|
"filtermenu",
|
||||||
|
"Fldr",
|
||||||
|
"flintstone",
|
||||||
|
"FLOWLOCS",
|
||||||
|
"FMEA",
|
||||||
|
"ftplib",
|
||||||
|
"FTPSPN",
|
||||||
|
"GETDATE",
|
||||||
|
"gitea",
|
||||||
|
"globaldocudms",
|
||||||
|
"glyphicons",
|
||||||
|
"groupable",
|
||||||
|
"Guids",
|
||||||
|
"halflings",
|
||||||
|
"Hexsize",
|
||||||
|
"highcontrast",
|
||||||
|
"Hmac",
|
||||||
|
"holdsteps",
|
||||||
|
"hostspecific",
|
||||||
|
"icenium",
|
||||||
|
"IECN",
|
||||||
|
"imagebrowser",
|
||||||
|
"IMRB",
|
||||||
|
"Infineon",
|
||||||
|
"Insertd",
|
||||||
|
"inverseicons",
|
||||||
|
"IPCRB",
|
||||||
|
"ISADMIN",
|
||||||
|
"islast",
|
||||||
|
"ISNULL",
|
||||||
|
"ITAR",
|
||||||
|
"jquery",
|
||||||
|
"jqueryval",
|
||||||
|
"jqwidgets",
|
||||||
|
"jqxbuttongroup",
|
||||||
|
"jqxbuttons",
|
||||||
|
"jqxcalendar",
|
||||||
|
"jqxchart",
|
||||||
|
"jqxcheckbox",
|
||||||
|
"jqxcolorpicker",
|
||||||
|
"jqxcombobox",
|
||||||
|
"jqxcore",
|
||||||
|
"jqxdata",
|
||||||
|
"jqxdatatable",
|
||||||
|
"jqxdatetimeinput",
|
||||||
|
"jqxdocking",
|
||||||
|
"jqxdockpanel",
|
||||||
|
"jqxdragdrop",
|
||||||
|
"jqxdropdownbutton",
|
||||||
|
"jqxdropdownlist",
|
||||||
|
"jqxexpander",
|
||||||
|
"jqxgauge",
|
||||||
|
"jqxgrid",
|
||||||
|
"jqxinput",
|
||||||
|
"jqxknockout",
|
||||||
|
"jqxlistbox",
|
||||||
|
"jqxlistmenu",
|
||||||
|
"jqxmaskedinput",
|
||||||
|
"jqxmenu",
|
||||||
|
"jqxnavigationbar",
|
||||||
|
"jqxnumberinput",
|
||||||
|
"jqxpanel",
|
||||||
|
"jqxpasswordinput",
|
||||||
|
"jqxprogressbar",
|
||||||
|
"jqxradiobutton",
|
||||||
|
"jqxrangeselector",
|
||||||
|
"jqxrating",
|
||||||
|
"jqxresponse",
|
||||||
|
"jqxscrollbar",
|
||||||
|
"jqxscrollview",
|
||||||
|
"jqxslider",
|
||||||
|
"jqxsplitter",
|
||||||
|
"jqxswitchbutton",
|
||||||
|
"jqxtabs",
|
||||||
|
"jqxtooltip",
|
||||||
|
"jqxtouch",
|
||||||
|
"jqxtree",
|
||||||
|
"jqxtreegrid",
|
||||||
|
"jqxtreemap",
|
||||||
|
"jqxvalidator",
|
||||||
|
"jqxwindow",
|
||||||
|
"kendogridcustom",
|
||||||
|
"kendoui",
|
||||||
|
"labelelement",
|
||||||
|
"labelledby",
|
||||||
|
"Leanred",
|
||||||
|
"lightgray",
|
||||||
|
"linkbutton",
|
||||||
|
"Linq",
|
||||||
|
"Listdiv",
|
||||||
|
"listview",
|
||||||
|
"Lnks",
|
||||||
|
"localfilename",
|
||||||
|
"loclist",
|
||||||
|
"logis",
|
||||||
|
"logtext",
|
||||||
|
"loopmis",
|
||||||
|
"lotdispo",
|
||||||
|
"LOTDISPSITION",
|
||||||
|
"Lotfile",
|
||||||
|
"lotlist",
|
||||||
|
"lotstatusoption",
|
||||||
|
"LTRIM",
|
||||||
|
"MADUREIRA",
|
||||||
|
"mailrelay",
|
||||||
|
"MDTM",
|
||||||
|
"meego",
|
||||||
|
"meetingid",
|
||||||
|
"menubutton",
|
||||||
|
"mesafi",
|
||||||
|
"metroblack",
|
||||||
|
"metrodark",
|
||||||
|
"miliseconds",
|
||||||
|
"modalview",
|
||||||
|
"modernizr",
|
||||||
|
"Modernizr",
|
||||||
|
"monthview",
|
||||||
|
"MRBIs",
|
||||||
|
"Mrbs",
|
||||||
|
"msecs",
|
||||||
|
"multipleextended",
|
||||||
|
"Navigatable",
|
||||||
|
"nbsp",
|
||||||
|
"newbase",
|
||||||
|
"newchange",
|
||||||
|
"newdi",
|
||||||
|
"newfilename",
|
||||||
|
"newsource",
|
||||||
|
"Newtonsoft",
|
||||||
|
"Nontransferrable",
|
||||||
|
"notications",
|
||||||
|
"Notifcation",
|
||||||
|
"Notifyf",
|
||||||
|
"NTLM",
|
||||||
|
"Nullcc",
|
||||||
|
"numerictextbox",
|
||||||
|
"objdata",
|
||||||
|
"OCAP",
|
||||||
|
"occured",
|
||||||
|
"odata",
|
||||||
|
"oldfilename",
|
||||||
|
"OLHOLD",
|
||||||
|
"onclick",
|
||||||
|
"onmousemove",
|
||||||
|
"OPDESC",
|
||||||
|
"OPENQUERY",
|
||||||
|
"Oper",
|
||||||
|
"operationslist",
|
||||||
|
"Orginator",
|
||||||
|
"Originatorname",
|
||||||
|
"Ouellette",
|
||||||
|
"Owin",
|
||||||
|
"pageable",
|
||||||
|
"Pageable",
|
||||||
|
"panelbar",
|
||||||
|
"parentid",
|
||||||
|
"parminput",
|
||||||
|
"parms",
|
||||||
|
"Parms",
|
||||||
|
"particula",
|
||||||
|
"pasv",
|
||||||
|
"PASV",
|
||||||
|
"PATINDEX",
|
||||||
|
"PCRB",
|
||||||
|
"PCRBID",
|
||||||
|
"pcrvalues",
|
||||||
|
"pdbonly",
|
||||||
|
"Preventitive",
|
||||||
|
"preventivet",
|
||||||
|
"Prevetative",
|
||||||
|
"proces",
|
||||||
|
"Processedl",
|
||||||
|
"procs",
|
||||||
|
"productfamilies",
|
||||||
|
"progess",
|
||||||
|
"progressbar",
|
||||||
|
"qrcode",
|
||||||
|
"Quanityt",
|
||||||
|
"rangebar",
|
||||||
|
"Recep",
|
||||||
|
"Recepient",
|
||||||
|
"recieved",
|
||||||
|
"recordlock",
|
||||||
|
"remotefilename",
|
||||||
|
"reorderable",
|
||||||
|
"reportform",
|
||||||
|
"reportslist",
|
||||||
|
"reportslistdiv",
|
||||||
|
"Reqquired",
|
||||||
|
"Reqs",
|
||||||
|
"Requiest",
|
||||||
|
"Responsibles",
|
||||||
|
"RETR",
|
||||||
|
"Revisioing",
|
||||||
|
"Revisioned",
|
||||||
|
"Revison",
|
||||||
|
"rgba",
|
||||||
|
"rkotian",
|
||||||
|
"RNFR",
|
||||||
|
"RNTO",
|
||||||
|
"Roless",
|
||||||
|
"roundbg",
|
||||||
|
"RTRIM",
|
||||||
|
"SAMDB",
|
||||||
|
"scroller",
|
||||||
|
"scrollview",
|
||||||
|
"seleced",
|
||||||
|
"selectionlog",
|
||||||
|
"Selectpart",
|
||||||
|
"sess",
|
||||||
|
"Sfisharepoint",
|
||||||
|
"shinyblack",
|
||||||
|
"showpassword",
|
||||||
|
"SIGNON",
|
||||||
|
"simpleparser",
|
||||||
|
"slddrw",
|
||||||
|
"sldprt",
|
||||||
|
"sortasc",
|
||||||
|
"sortascbutton",
|
||||||
|
"sortdesc",
|
||||||
|
"sortdescbutton",
|
||||||
|
"sortremove",
|
||||||
|
"sparkline",
|
||||||
|
"splitview",
|
||||||
|
"SPNMRB",
|
||||||
|
"SPNPDB",
|
||||||
|
"SSRS",
|
||||||
|
"Sssign",
|
||||||
|
"Staus",
|
||||||
|
"stylesheet",
|
||||||
|
"Submited",
|
||||||
|
"subrole",
|
||||||
|
"subroles",
|
||||||
|
"Succefully",
|
||||||
|
"Succesfully",
|
||||||
|
"sucessfully",
|
||||||
|
"SURP",
|
||||||
|
"Swashbuckle",
|
||||||
|
"SWRN",
|
||||||
|
"tabindex",
|
||||||
|
"tabstrip",
|
||||||
|
"Tahoma",
|
||||||
|
"taskcompleted",
|
||||||
|
"Tasklist",
|
||||||
|
"Taveler",
|
||||||
|
"TECN",
|
||||||
|
"TECNs",
|
||||||
|
"TEMIRWAP",
|
||||||
|
"tempecd",
|
||||||
|
"tempimplement",
|
||||||
|
"templabel",
|
||||||
|
"tempvalue",
|
||||||
|
"TEMSA",
|
||||||
|
"Tencor",
|
||||||
|
"timepicker",
|
||||||
|
"Tobe",
|
||||||
|
"Toplevel",
|
||||||
|
"Totrav",
|
||||||
|
"trainingby",
|
||||||
|
"Traininglist",
|
||||||
|
"traininglistdiv",
|
||||||
|
"transanction",
|
||||||
|
"Trav",
|
||||||
|
"Traveller",
|
||||||
|
"Traverler",
|
||||||
|
"TRAVLELER",
|
||||||
|
"Travler",
|
||||||
|
"TREEVIEW",
|
||||||
|
"trigerred",
|
||||||
|
"ttinclude",
|
||||||
|
"Uhandled",
|
||||||
|
"Updat",
|
||||||
|
"Uplaod",
|
||||||
|
"Upto",
|
||||||
|
"userevents",
|
||||||
|
"userids",
|
||||||
|
"userlist",
|
||||||
|
"Validatable",
|
||||||
|
"valueelement",
|
||||||
|
"Variabls",
|
||||||
|
"Verdana",
|
||||||
|
"vgrid",
|
||||||
|
"viewmodel",
|
||||||
|
"vsdoc",
|
||||||
|
"whethere",
|
||||||
|
"windowsphone",
|
||||||
|
"Winsock",
|
||||||
|
"worlflow"
|
||||||
|
]
|
||||||
|
}
|
||||||
42
MesaFabApproval.Shared/.vscode/tasks.json
vendored
Normal file
42
MesaFabApproval.Shared/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/MesaFabApproval.Shared.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.6" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
namespace MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
public class Approval {
|
public class Approval {
|
||||||
public int ApprovalID { get; set; }
|
public int ApprovalID { get; set; }
|
||||||
@ -10,9 +12,9 @@ public class Approval {
|
|||||||
public required int SubRoleID { get; set; }
|
public required int SubRoleID { get; set; }
|
||||||
public int ItemStatus { get; set; } = 0;
|
public int ItemStatus { get; set; } = 0;
|
||||||
public string StatusMessage = "Assigned";
|
public string StatusMessage = "Assigned";
|
||||||
public DateTime NotifyDate { get; set; } = DateTime.MinValue;
|
public DateTime NotifyDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||||
public required DateTime AssignedDate { get; set; }
|
public required DateTime AssignedDate { get; set; }
|
||||||
public DateTime CompletedDate { get; set; } = DateTime.MaxValue;
|
public DateTime CompletedDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
public string Comments { get; set; } = "";
|
public string Comments { get; set; } = "";
|
||||||
public int Step { get; set; } = 1;
|
public int Step { get; set; } = 1;
|
||||||
public string SubRoleCategoryItem { get; set; } = "";
|
public string SubRoleCategoryItem { get; set; } = "";
|
||||||
|
|||||||
@ -1,39 +1,43 @@
|
|||||||
using System.Collections.Immutable;
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
namespace MesaFabApproval.Shared.Models;
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
public class MRB {
|
public class MRB {
|
||||||
public static string[] Stages { get; } = {
|
public static string[] Stages { get; } = [
|
||||||
"Draft",
|
"Draft",
|
||||||
"QA Pre Approval",
|
"QA Pre Approval",
|
||||||
"Pending Approval",
|
"Pending Approval",
|
||||||
"Approved",
|
"Approved",
|
||||||
"Complete"
|
"Complete"
|
||||||
};
|
];
|
||||||
|
|
||||||
public int MRBNumber { get; set; }
|
public int MRBNumber { get; set; }
|
||||||
public int OriginatorID { get; set; }
|
public int OriginatorID { get; set; }
|
||||||
public string OriginatorName { get; set; } = "";
|
public string OriginatorName { get; set; } = "";
|
||||||
public string Title { get; set; } = "";
|
public string Title { get; set; } = "";
|
||||||
public DateTime SubmittedDate { get; set; } = DateTime.MinValue;
|
public DateTime SubmittedDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||||
public DateTime CloseDate { get; set; } = DateTime.MaxValue;
|
public DateTime CloseDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
public DateTime CancelDate { get; set; } = DateTime.MaxValue;
|
public DateTime CancelDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
public DateTime ApprovalDate { get; set; } = DateTime.MaxValue;
|
public DateTime ApprovalDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
public string IssueDescription { get; set; } = "";
|
public string IssueDescription { get; set; } = "";
|
||||||
public int NumberOfLotsAffected { get; set; }
|
public int NumberOfLotsAffected { get; set; }
|
||||||
public string Val { get; set; } = "";
|
public double Val { get; set; }
|
||||||
public bool CustomerImpacted { get; set; } = false;
|
public bool CustomerImpacted { get; set; } = false;
|
||||||
|
public string CustomerImpactedName { get; set; } = "";
|
||||||
public string Department { get; set; } = "";
|
public string Department { get; set; } = "";
|
||||||
public string Process { get; set; } = "";
|
public string Process { get; set; } = "";
|
||||||
public int RMANo { get; set; }
|
public int RMANo { get; set; }
|
||||||
public int PCRBNo { get; set; }
|
public string PCRBNo { get; set; } = "";
|
||||||
public bool SpecsImpacted { get; set; } = false;
|
public bool SpecsImpacted { get; set; } = false;
|
||||||
|
public int ProcessECNNumber { get; set; }
|
||||||
public bool TrainingRequired { get; set; } = false;
|
public bool TrainingRequired { get; set; } = false;
|
||||||
public IEnumerable<MRBAttachment>? Attachments { get; set; }
|
public IEnumerable<MRBAttachment>? Attachments { get; set; }
|
||||||
public IEnumerable<MRBAction>? Actions { get; set; }
|
public IEnumerable<MRBAction>? Actions { get; set; }
|
||||||
public IEnumerable<int>? ApproverUserIds { get; set; }
|
public IEnumerable<int>? ApproverUserIds { get; set; }
|
||||||
public required int StageNo { get; set; }
|
public required int StageNo { get; set; }
|
||||||
public required string Status { get; set; }
|
public required string Status { get; set; }
|
||||||
|
public string Tool { get; set; } = "";
|
||||||
|
public string Category { get; set; } = string.Empty;
|
||||||
|
|
||||||
public sealed class StageApprovalData {
|
public sealed class StageApprovalData {
|
||||||
public required string RoleName { get; set; }
|
public required string RoleName { get; set; }
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
namespace MesaFabApproval.Shared.Models;
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
public class MRBAction {
|
public class MRBAction {
|
||||||
public int ActionID { get; set; }
|
public int ActionID { get; set; }
|
||||||
@ -8,8 +10,11 @@ public class MRBAction {
|
|||||||
public required string PartNumber { get; set; }
|
public required string PartNumber { get; set; }
|
||||||
public required string LotNumber { get; set; }
|
public required string LotNumber { get; set; }
|
||||||
public required int MRBNumber { get; set; }
|
public required int MRBNumber { get; set; }
|
||||||
public DateTime AssignedDate { get; set; } = DateTime.MinValue;
|
public DateTime AssignedDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||||
public DateTime CompletedDate { get; set; } = DateTime.MaxValue;
|
public DateTime CompletedDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
public int CompletedByUserID { get; set; } = 0;
|
public int CompletedByUserID { get; set; } = 0;
|
||||||
public User? CompletedByUser { get; set; }
|
public User? CompletedByUser { get; set; }
|
||||||
|
public string ConvertFrom { get; set; } = "";
|
||||||
|
public string ConvertTo { get; set; } = "";
|
||||||
|
public string Justification { get; set; } = "";
|
||||||
}
|
}
|
||||||
9
MesaFabApproval.Shared/Models/MRBActionAttachment.cs
Normal file
9
MesaFabApproval.Shared/Models/MRBActionAttachment.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
|
public class MRBActionAttachment {
|
||||||
|
public required int AttachmentID { get; set; }
|
||||||
|
public required int ActionID { get; set; }
|
||||||
|
public required string FileName { get; set; }
|
||||||
|
public required DateTime UploadDate { get; set; }
|
||||||
|
public required string Path { get; set; }
|
||||||
|
}
|
||||||
20
MesaFabApproval.Shared/Models/PCR3Document.cs
Normal file
20
MesaFabApproval.Shared/Models/PCR3Document.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
|
public class PCR3Document {
|
||||||
|
public int ID { get; set; }
|
||||||
|
public required int PlanNumber { get; set; }
|
||||||
|
public required string DocType { get; set; }
|
||||||
|
public string DocNumbers { get; set; } = "N/A";
|
||||||
|
public DateTime CompletedDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
|
public int CompletedByID { get; set; } = 0;
|
||||||
|
public User? CompletedBy { get; set; }
|
||||||
|
public string Comment { get; set; } = string.Empty;
|
||||||
|
public int ECNNumber { get; set; } = 0;
|
||||||
|
|
||||||
|
public string GetEcnNumberString() {
|
||||||
|
if (this.ECNNumber > 0) return this.ECNNumber.ToString();
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
MesaFabApproval.Shared/Models/PCRB.cs
Normal file
26
MesaFabApproval.Shared/Models/PCRB.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
|
public class PCRB {
|
||||||
|
public static string[] Stages { get; } = [
|
||||||
|
"Draft",
|
||||||
|
"PCR1",
|
||||||
|
"PCR2",
|
||||||
|
"PCR3",
|
||||||
|
"Complete"
|
||||||
|
];
|
||||||
|
|
||||||
|
public int PlanNumber { get; set; }
|
||||||
|
public int OwnerID { get; set; }
|
||||||
|
public string OwnerName { get; set; } = "";
|
||||||
|
public string Title { get; set; } = "";
|
||||||
|
public string ChangeLevel { get; set; } = "Mesa - Class 3";
|
||||||
|
public bool IsITAR { get; set; } = false;
|
||||||
|
public int CurrentStep { get; set; } = 0;
|
||||||
|
public string ReasonForChange { get; set; } = "";
|
||||||
|
public string ChangeDescription { get; set; } = "";
|
||||||
|
public DateTime InsertTimeStamp { get; set; } = DateTimeUtilities.MIN_DT;
|
||||||
|
public DateTime LastUpdateDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||||
|
public DateTime ClosedDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
|
}
|
||||||
21
MesaFabApproval.Shared/Models/PCRBActionItem.cs
Normal file
21
MesaFabApproval.Shared/Models/PCRBActionItem.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using MesaFabApproval.Shared.Utilities;
|
||||||
|
|
||||||
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
|
public class PCRBActionItem {
|
||||||
|
public int ID { get; set; }
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public bool Gating { get; set; } = false;
|
||||||
|
public bool ClosedStatus { get; set; } = false;
|
||||||
|
public DateTime? ClosedDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||||
|
public int ClosedByID { get; set; } = 0;
|
||||||
|
public User? ClosedBy { get; set; }
|
||||||
|
public required int UploadedByID { get; set; }
|
||||||
|
public User? UploadedBy { get; set; }
|
||||||
|
public DateTime UploadedDateTime { get; set; } = DateTime.Now;
|
||||||
|
public int ResponsiblePersonID { get; set; } = 0;
|
||||||
|
public User? ResponsiblePerson { get; set; }
|
||||||
|
public required int PlanNumber { get; set; }
|
||||||
|
public required int Step { get; set; }
|
||||||
|
public DateTime NotifyDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
namespace MesaFabApproval.Shared.Models;
|
||||||
|
|
||||||
|
public class PCRBActionItemNotification {
|
||||||
|
public required PCRB PCRB { get; set; }
|
||||||
|
public required PCRBActionItem ActionItem { get; set; }
|
||||||
|
public required string Message { get; set; }
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user