MRB webassembly
This commit is contained in:
parent
ba8d92ea01
commit
9b7e3ef897
281
.editorconfig
281
.editorconfig
@ -1,74 +1,229 @@
|
||||
# EditorConfig is awesome:http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||
root = true
|
||||
|
||||
[*]
|
||||
# Don't use tabs for indentation.
|
||||
# (Please don't specify an indent_size here; that has too many unintended consequences.)
|
||||
indent_style = space
|
||||
|
||||
charset = utf-8
|
||||
|
||||
# Where supported, trim trailing whitespace on all lines.
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Where supported (e.g. in VS Code but not VS), add a final newline to files.
|
||||
insert_final_newline = true
|
||||
|
||||
# Code files
|
||||
[*.{cs,csx,vb,vbx}]
|
||||
indent_size = 4
|
||||
dotnet_sort_system_directives_first = true:warning
|
||||
|
||||
# Xml project files
|
||||
[*.{*proj,vcxproj.filters,projitems}]
|
||||
indent_size = 2
|
||||
|
||||
# Xml config files
|
||||
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct,tasks,xml,yml}]
|
||||
indent_size = 2
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
# PowerShell
|
||||
[*.{ps1,psm1}]
|
||||
indent_size = 4
|
||||
|
||||
# Shell
|
||||
[*.sh]
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
|
||||
# Dotnet code style settings:
|
||||
# C# files
|
||||
[*.cs]
|
||||
# Sort using and Import directives with System.* appearing first
|
||||
|
||||
#### 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
|
||||
|
||||
# Don't use this. qualifier
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
# 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
|
||||
|
||||
# use int x = .. over Int32
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
|
||||
# use int.MaxValue over Int32.MaxValue
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
# 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
|
||||
|
||||
# Require var all the time.
|
||||
csharp_style_var_for_built_in_types = false:suggestion
|
||||
csharp_style_var_when_type_is_apparent = false:suggestion
|
||||
csharp_style_var_elsewhere = false:suggestion
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||
|
||||
# Disallow throw expressions.
|
||||
csharp_style_throw_expression = false:suggestion
|
||||
# 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
|
||||
|
||||
# Newline settings
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = 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
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -337,3 +337,6 @@ ASALocalRun/
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.vscode
|
||||
|
||||
.env
|
||||
|
@ -1,20 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2020
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34616.47
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fab2ApprovalSystem", "Fab2ApprovalSystem\Fab2ApprovalSystem.csproj", "{AAE52608-4DD1-4732-92BD-CC8915DEC71E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MesaFabApproval.API", "MesaFabApproval.API\MesaFabApproval.API.csproj", "{852E528D-015A-43B5-999D-F281E3359E5E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MesaFabApproval.Shared", "MesaFabApproval.Shared\MesaFabApproval.Shared.csproj", "{2C16014D-B04E-46AF-AB4C-D2691D44A339}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MesaFabApproval.Client", "MesaFabApproval.Client\MesaFabApproval.Client.csproj", "{34D52F44-A81F-4247-8180-16E204824A07}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{2C16014D-B04E-46AF-AB4C-D2691D44A339} = {2C16014D-B04E-46AF-AB4C-D2691D44A339}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 2
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = http://tfs.intra.infineon.com:8080/tfs/manufacturingit
|
||||
SccLocalPath0 = .
|
||||
SccProjectUniqueName1 = Fab2ApprovalSystem\\Fab2ApprovalSystem.csproj
|
||||
SccProjectName1 = Fab2ApprovalSystem
|
||||
SccLocalPath1 = Fab2ApprovalSystem
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
@ -24,8 +24,23 @@ Global
|
||||
{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{852E528D-015A-43B5-999D-F281E3359E5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{852E528D-015A-43B5-999D-F281E3359E5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{852E528D-015A-43B5-999D-F281E3359E5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{852E528D-015A-43B5-999D-F281E3359E5E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{34D52F44-A81F-4247-8180-16E204824A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{34D52F44-A81F-4247-8180-16E204824A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{34D52F44-A81F-4247-8180-16E204824A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{34D52F44-A81F-4247-8180-16E204824A07}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {A966A184-1FCD-4B6A-978C-5907CC12406B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -17,7 +17,7 @@ namespace Fab2ApprovalSystem
|
||||
LoginPath = new PathString("/Account/Login")
|
||||
});
|
||||
// Use a cookie to temporarily store information about a user logging in with a third party login provider
|
||||
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
|
||||
// app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
|
||||
|
||||
// Uncomment the following lines to enable logging in with third party login providers
|
||||
//app.UseMicrosoftAccountAuthentication(
|
||||
|
@ -12,19 +12,24 @@ using Fab2ApprovalSystem.Models;
|
||||
using System.Web.Security;
|
||||
using Fab2ApprovalSystem.Misc;
|
||||
using Fab2ApprovalSystem.DMO;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace Fab2ApprovalSystem.Controllers
|
||||
{
|
||||
namespace Fab2ApprovalSystem.Controllers {
|
||||
[Authorize]
|
||||
public class AccountController : Controller
|
||||
{
|
||||
public class AccountController : Controller {
|
||||
private string _apiBaseUrl;
|
||||
|
||||
public AccountController()
|
||||
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
|
||||
{
|
||||
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))) {
|
||||
_apiBaseUrl = Environment.GetEnvironmentVariable("FabApprovalApiBaseUrl") ??
|
||||
throw new ArgumentNullException("FabApprovalApiBaseUrl environment variable not found");
|
||||
}
|
||||
|
||||
public AccountController(UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
public AccountController(UserManager<ApplicationUser> userManager) {
|
||||
UserManager = userManager;
|
||||
}
|
||||
|
||||
@ -34,9 +39,8 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
// GET: /Account/Login
|
||||
[AllowAnonymous]
|
||||
// try to make the browser refresh the login page every time, to prevent issues with changing usernames and the anti-forgery token validation
|
||||
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
|
||||
public ActionResult Login(string returnUrl)
|
||||
{
|
||||
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
|
||||
public ActionResult Login(string returnUrl) {
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
return View();
|
||||
}
|
||||
@ -44,18 +48,32 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult Login(LoginModel model, string returnUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
|
||||
//{
|
||||
// return RedirectToLocal(returnUrl);
|
||||
//}
|
||||
|
||||
UserAccountDMO userDMO = new UserAccountDMO();
|
||||
public async Task<ActionResult> Login(LoginModel model, string returnUrl) {
|
||||
try {
|
||||
bool isLoginValid;
|
||||
MembershipProvider domainProvider;
|
||||
|
||||
HttpClient httpClient = HttpClientFactory.Create();
|
||||
httpClient.BaseAddress = new Uri(_apiBaseUrl);
|
||||
|
||||
AuthAttempt authAttempt = new AuthAttempt() {
|
||||
LoginID = model.LoginID,
|
||||
Password = model.Password
|
||||
};
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/login");
|
||||
|
||||
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;
|
||||
@ -64,28 +82,26 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
#if (!DEBUG)
|
||||
|
||||
bool isIFX = false;
|
||||
//domainProvider = Membership.Providers["NA_ADMembershipProvider"];
|
||||
//isLoginValid = domainProvider.ValidateUser(model.LoginID, model.Password);
|
||||
//domainProvider = Membership.Providers["NA_ADMembershipProvider"];
|
||||
//isLoginValid = domainProvider.ValidateUser(model.LoginID, model.Password);
|
||||
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY")
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||
isLoginValid = true;
|
||||
else
|
||||
{
|
||||
isLoginValid = Functions.NA_ADAuthenticate(model.LoginID, model.Password);
|
||||
if (!isLoginValid)
|
||||
{
|
||||
isLoginValid = Functions.IFX_ADAuthenticate(model.LoginID, model.Password);
|
||||
isIFX = true;
|
||||
}
|
||||
} else {
|
||||
isLoginValid = loginResult.IsAuthenticated;
|
||||
if (isLoginValid) isIFX = true;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (isLoginValid)
|
||||
{
|
||||
if (isLoginValid) {
|
||||
UserAccountDMO userDMO = new UserAccountDMO();
|
||||
LoginModel user = userDMO.GetUser(model.LoginID);
|
||||
if (user != null)
|
||||
{
|
||||
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;
|
||||
@ -94,22 +110,16 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
Session[GlobalVars.CAN_CREATE_PARTS_REQUEST] = user.IsAdmin || PartsRequestController.CanCreatePartsRequest(user.UserID);
|
||||
|
||||
FormsAuthentication.SetAuthCookie(user.LoginID, true);
|
||||
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ModelState.AddModelError("", "The user name does not exist in the DB. Please contact the System Admin");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ModelState.AddModelError("", "The user name or password provided is incorrect.");
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Functions.WriteEvent(@User.Identity.Name + " " + ex.InnerException , System.Diagnostics.EventLogEntryType.Error);
|
||||
} 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);
|
||||
}
|
||||
@ -119,287 +129,87 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
|
||||
}
|
||||
|
||||
////
|
||||
//// POST: /Account/Login
|
||||
//[HttpPost]
|
||||
//[AllowAnonymous]
|
||||
//[ValidateAntiForgeryToken]
|
||||
//public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
|
||||
//{
|
||||
// if (ModelState.IsValid)
|
||||
// {
|
||||
// var user = await UserManager.FindAsync(model.UserName, model.Password);
|
||||
// if (user != null)
|
||||
// {
|
||||
// await SignInAsync(user, model.RememberMe);
|
||||
// return RedirectToLocal(returnUrl);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ModelState.AddModelError("", "Invalid username or password.");
|
||||
// }
|
||||
// }
|
||||
|
||||
// // If we got this far, something failed, redisplay form
|
||||
// return View(model);
|
||||
//}
|
||||
|
||||
//
|
||||
// GET: /Account/Register
|
||||
[AllowAnonymous]
|
||||
public ActionResult Register()
|
||||
{
|
||||
public ActionResult Register() {
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/Register
|
||||
//[HttpPost]
|
||||
//[AllowAnonymous]
|
||||
//[ValidateAntiForgeryToken]
|
||||
//public async Task<ActionResult> Register(RegisterViewModel model)
|
||||
//{
|
||||
// if (ModelState.IsValid)
|
||||
// {
|
||||
// var user = new ApplicationUser() { UserName = model.UserName };
|
||||
// var result = await UserManager.CreateAsync(user, model.Password);
|
||||
// if (result.Succeeded)
|
||||
// {
|
||||
// await SignInAsync(user, isPersistent: false);
|
||||
// return RedirectToAction("Index", "Home");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// AddErrors(result);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // If we got this far, something failed, redisplay form
|
||||
// return View(model);
|
||||
//}
|
||||
|
||||
//
|
||||
// POST: /Account/Disassociate
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
|
||||
{
|
||||
public async Task<ActionResult> Disassociate(string loginProvider, string providerKey) {
|
||||
ManageMessageId? message = null;
|
||||
IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
|
||||
if (result.Succeeded)
|
||||
{
|
||||
if (result.Succeeded) {
|
||||
message = ManageMessageId.RemoveLoginSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
message = ManageMessageId.Error;
|
||||
}
|
||||
return RedirectToAction("Manage", new { Message = message });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/Manage
|
||||
#pragma warning disable IDE0060 // Remove unused parameter
|
||||
public ActionResult Manage(ManageMessageId? message)
|
||||
#pragma warning restore IDE0060 // Remove unused parameter
|
||||
{
|
||||
//ViewBag.StatusMessage =
|
||||
// message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||
// : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
|
||||
// : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
|
||||
// : message == ManageMessageId.Error ? "An error has occurred."
|
||||
// : "";
|
||||
//ViewBag.HasLocalPassword = HasPassword();
|
||||
//ViewBag.ReturnUrl = Url.Action("Manage");
|
||||
public ActionResult Manage(ManageMessageId? message) {
|
||||
return View();
|
||||
}
|
||||
#pragma warning restore IDE0060 // Remove unused parameter
|
||||
|
||||
////
|
||||
//// POST: /Account/Manage
|
||||
//[HttpPost]
|
||||
//[ValidateAntiForgeryToken]
|
||||
//public async Task<ActionResult> Manage(ManageUserViewModel model)
|
||||
//{
|
||||
// bool hasPassword = HasPassword();
|
||||
// ViewBag.HasLocalPassword = hasPassword;
|
||||
// ViewBag.ReturnUrl = Url.Action("Manage");
|
||||
// if (hasPassword)
|
||||
// {
|
||||
// if (ModelState.IsValid)
|
||||
// {
|
||||
// IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
|
||||
// if (result.Succeeded)
|
||||
// {
|
||||
// return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// AddErrors(result);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // User does not have a password so remove any validation errors caused by a missing OldPassword field
|
||||
// ModelState state = ModelState["OldPassword"];
|
||||
// if (state != null)
|
||||
// {
|
||||
// state.Errors.Clear();
|
||||
// }
|
||||
|
||||
// if (ModelState.IsValid)
|
||||
// {
|
||||
// IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
|
||||
// if (result.Succeeded)
|
||||
// {
|
||||
// return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// AddErrors(result);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // If we got this far, something failed, redisplay form
|
||||
// return View(model);
|
||||
//}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLogin
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult ExternalLogin(string provider, string returnUrl)
|
||||
{
|
||||
public ActionResult ExternalLogin(string provider, string returnUrl) {
|
||||
// Request a redirect to the external login provider
|
||||
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
|
||||
}
|
||||
|
||||
////
|
||||
//// GET: /Account/ExternalLoginCallback
|
||||
//[AllowAnonymous]
|
||||
//public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
|
||||
//{
|
||||
// var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
|
||||
// if (loginInfo == null)
|
||||
// {
|
||||
// return RedirectToAction("Login");
|
||||
// }
|
||||
|
||||
// // Sign in the user with this external login provider if the user already has a login
|
||||
// var user = await UserManager.FindAsync(loginInfo.Login);
|
||||
// if (user != null)
|
||||
// {
|
||||
// await SignInAsync(user, isPersistent: false);
|
||||
// return RedirectToLocal(returnUrl);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // If the user does not have an account, then prompt the user to create an account
|
||||
// ViewBag.ReturnUrl = returnUrl;
|
||||
// ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
|
||||
// return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
|
||||
// }
|
||||
//}
|
||||
|
||||
//
|
||||
// POST: /Account/LinkLogin
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult LinkLogin(string provider)
|
||||
{
|
||||
public ActionResult LinkLogin(string provider) {
|
||||
// Request a redirect to the external login provider to link a login for the current user
|
||||
return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId());
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/LinkLoginCallback
|
||||
public async Task<ActionResult> LinkLoginCallback()
|
||||
{
|
||||
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
|
||||
if (loginInfo == null)
|
||||
{
|
||||
public async Task<ActionResult> LinkLoginCallback() {
|
||||
ExternalLoginInfo loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
|
||||
if (loginInfo == null) {
|
||||
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
|
||||
}
|
||||
var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
|
||||
if (result.Succeeded) {
|
||||
return RedirectToAction("Manage");
|
||||
}
|
||||
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLoginConfirmation
|
||||
//[HttpPost]
|
||||
//[AllowAnonymous]
|
||||
//[ValidateAntiForgeryToken]
|
||||
//public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
|
||||
//{
|
||||
// if (User.Identity.IsAuthenticated)
|
||||
// {
|
||||
// return RedirectToAction("Manage");
|
||||
// }
|
||||
|
||||
// if (ModelState.IsValid)
|
||||
// {
|
||||
// // Get the information about the user from the external login provider
|
||||
// var info = await AuthenticationManager.GetExternalLoginInfoAsync();
|
||||
// if (info == null)
|
||||
// {
|
||||
// return View("ExternalLoginFailure");
|
||||
// }
|
||||
// var user = new ApplicationUser() { UserName = model.UserName };
|
||||
// var result = await UserManager.CreateAsync(user);
|
||||
// if (result.Succeeded)
|
||||
// {
|
||||
// result = await UserManager.AddLoginAsync(user.Id, info.Login);
|
||||
// if (result.Succeeded)
|
||||
// {
|
||||
// await SignInAsync(user, isPersistent: false);
|
||||
// return RedirectToLocal(returnUrl);
|
||||
// }
|
||||
// }
|
||||
// AddErrors(result);
|
||||
// }
|
||||
|
||||
// ViewBag.ReturnUrl = returnUrl;
|
||||
// return View(model);
|
||||
//}
|
||||
|
||||
//
|
||||
// POST: /Account/LogOff
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult LogOff()
|
||||
{
|
||||
//AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
|
||||
//AuthenticationManager.SignOut();
|
||||
public ActionResult LogOff() {
|
||||
FormsAuthentication.SignOut();
|
||||
return RedirectToAction("Login", "Account");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ExternalLoginFailure
|
||||
[AllowAnonymous]
|
||||
public ActionResult ExternalLoginFailure()
|
||||
{
|
||||
public ActionResult ExternalLoginFailure() {
|
||||
return View();
|
||||
}
|
||||
|
||||
[ChildActionOnly]
|
||||
public ActionResult RemoveAccountList()
|
||||
{
|
||||
var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId());
|
||||
public ActionResult RemoveAccountList() {
|
||||
IList<UserLoginInfo> linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId());
|
||||
ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
|
||||
return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && UserManager != null)
|
||||
{
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && UserManager != null) {
|
||||
UserManager.Dispose();
|
||||
UserManager = null;
|
||||
}
|
||||
@ -410,71 +220,52 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
// Used for XSRF protection when adding external logins
|
||||
private const string XsrfKey = "XsrfId";
|
||||
|
||||
private IAuthenticationManager AuthenticationManager
|
||||
{
|
||||
get
|
||||
{
|
||||
private IAuthenticationManager AuthenticationManager {
|
||||
get {
|
||||
return HttpContext.GetOwinContext().Authentication;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
|
||||
{
|
||||
private async Task SignInAsync(ApplicationUser user, bool isPersistent) {
|
||||
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
|
||||
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
|
||||
ClaimsIdentity identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
|
||||
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
|
||||
}
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
private void AddErrors(IdentityResult result) {
|
||||
foreach (string error in result.Errors) {
|
||||
ModelState.AddModelError("", error);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasPassword()
|
||||
{
|
||||
var user = UserManager.FindById(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
private bool HasPassword() {
|
||||
ApplicationUser user = UserManager.FindById(User.Identity.GetUserId());
|
||||
if (user != null) {
|
||||
return user.PasswordHash != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum ManageMessageId
|
||||
{
|
||||
public enum ManageMessageId {
|
||||
ChangePasswordSuccess,
|
||||
SetPasswordSuccess,
|
||||
RemoveLoginSuccess,
|
||||
Error
|
||||
}
|
||||
|
||||
private ActionResult RedirectToLocal(string returnUrl)
|
||||
{
|
||||
if (Url.IsLocalUrl(returnUrl))
|
||||
{
|
||||
private ActionResult RedirectToLocal(string returnUrl) {
|
||||
if (Url.IsLocalUrl(returnUrl)) {
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//return RedirectToAction("HierarchicalDataTest", "Home");
|
||||
|
||||
} else {
|
||||
return RedirectToAction("MyTasks", "Home");
|
||||
//return RedirectToAction("Index", "Home", new { tabName = "MyTasks"});
|
||||
}
|
||||
}
|
||||
|
||||
private class ChallengeResult : HttpUnauthorizedResult
|
||||
{
|
||||
public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null)
|
||||
{
|
||||
private class ChallengeResult : HttpUnauthorizedResult {
|
||||
public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null) {
|
||||
}
|
||||
|
||||
public ChallengeResult(string provider, string redirectUri, string userId)
|
||||
{
|
||||
public ChallengeResult(string provider, string redirectUri, string userId) {
|
||||
LoginProvider = provider;
|
||||
RedirectUri = redirectUri;
|
||||
UserId = userId;
|
||||
@ -484,11 +275,9 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
public string RedirectUri { get; set; }
|
||||
public string UserId { get; set; }
|
||||
|
||||
public override void ExecuteResult(ControllerContext context)
|
||||
{
|
||||
var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
|
||||
if (UserId != null)
|
||||
{
|
||||
public override void ExecuteResult(ControllerContext context) {
|
||||
AuthenticationProperties properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
|
||||
if (UserId != null) {
|
||||
properties.Dictionary[XsrfKey] = UserId;
|
||||
}
|
||||
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
|
||||
|
@ -2,23 +2,18 @@ using Fab2ApprovalSystem.DMO;
|
||||
using Fab2ApprovalSystem.Models;
|
||||
using Fab2ApprovalSystem.ViewModels;
|
||||
using Fab2ApprovalSystem.Utilities;
|
||||
using Kendo.Mvc.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Kendo.Mvc.Extensions;
|
||||
using Fab2ApprovalSystem.Misc;
|
||||
using System.Configuration;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Fab2ApprovalSystem.Controllers
|
||||
{
|
||||
namespace Fab2ApprovalSystem.Controllers {
|
||||
[Authorize]
|
||||
[SessionExpireFilter]
|
||||
public class TrainingController : Controller
|
||||
{
|
||||
public class TrainingController : Controller {
|
||||
UserAccountDMO userDMO = new UserAccountDMO();
|
||||
AdminDMO adminDMO = new AdminDMO();
|
||||
TrainingDMO trainingDMO = new TrainingDMO();
|
||||
@ -26,19 +21,17 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
public EmailUtilities emailer = new EmailUtilities();
|
||||
|
||||
// GET: Training
|
||||
public ActionResult Index()
|
||||
{
|
||||
public ActionResult Index() {
|
||||
return View();
|
||||
}
|
||||
|
||||
//public int Create(int ecnId, List<int> groupIds)
|
||||
public int Create(int ecnId)
|
||||
{
|
||||
public int Create(int ecnId) {
|
||||
ECN_DMO ecnDMO = new ECN_DMO();
|
||||
|
||||
//Delete old training if exists
|
||||
int oldTrainingId = trainingDMO.GetTrainingId(ecnId);
|
||||
if (oldTrainingId != null && oldTrainingId != 0)
|
||||
{
|
||||
if (oldTrainingId != null && oldTrainingId != 0) {
|
||||
trainingDMO.DeleteTraining(oldTrainingId);
|
||||
}
|
||||
|
||||
@ -47,23 +40,20 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
TrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(ecnId);
|
||||
string ECNTitle = ecnDMO.GetECN(ecnId).Title;
|
||||
List<int> Trainees = new List<int>();
|
||||
foreach (var group in TrainingGroups)
|
||||
{
|
||||
foreach (int group in TrainingGroups) {
|
||||
Trainees.AddRange(trainingDMO.GetTrainees(group));
|
||||
}
|
||||
Trainees = (from a in Trainees select a).Distinct().ToList();
|
||||
|
||||
foreach (var trainee in Trainees)
|
||||
{
|
||||
foreach (int trainee in Trainees) {
|
||||
int assignmentId = trainingDMO.CreateAssignment(trainingId, trainee);
|
||||
NotifyTrainee(trainee, assignmentId, ecnId, ECNTitle);
|
||||
}
|
||||
|
||||
return trainingId;
|
||||
}
|
||||
public ActionResult AddUserToTrainingAdHoc(int trainingId, int traineeId, int ecnId)
|
||||
{
|
||||
if ((bool)Session[GlobalVars.IS_ADMIN])
|
||||
{
|
||||
public ActionResult AddUserToTrainingAdHoc(int trainingId, int traineeId, int ecnId) {
|
||||
if ((bool)Session[GlobalVars.IS_ADMIN]) {
|
||||
//Get ECN
|
||||
ECN ecn = ecnDMO.GetECN(ecnId);
|
||||
|
||||
@ -72,172 +62,120 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
|
||||
//Get Training
|
||||
Training training = trainingDMO.GetTraining(trainingId);
|
||||
if (ecn != null)
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
if (training != null)
|
||||
{
|
||||
if (!trainingDMO.IsUserAssigned(traineeId, trainingId))
|
||||
{
|
||||
if (training.DeletedDate == null && !ecn.Deleted)
|
||||
{
|
||||
if (ecn != null) {
|
||||
if (user != null) {
|
||||
if (training != null) {
|
||||
if (!trainingDMO.IsUserAssigned(traineeId, trainingId)) {
|
||||
if (training.DeletedDate == null && !ecn.Deleted) {
|
||||
//Both the ECN and training still exist
|
||||
if (training.CompletedDate != null)
|
||||
{
|
||||
if (training.CompletedDate != null) {
|
||||
//Training is completed and now we need to re-open it.
|
||||
trainingDMO.reOpenTraining(trainingId);
|
||||
int assignmentId = trainingDMO.CreateAssignment(trainingId, traineeId);
|
||||
NotifyTrainee(traineeId, assignmentId, ecnId, ecn.Title);
|
||||
return Content("Success");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
//training is still open, just add a user and notify
|
||||
int assignmentId = trainingDMO.CreateAssignment(trainingId, traineeId);
|
||||
NotifyTrainee(traineeId, assignmentId, ecnId, ecn.Title);
|
||||
return Content("Success");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
//Ecn or training task have been deleted.
|
||||
return Content("Training or ECN has been deleted.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("User already has an open or completed assignment for this training.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Invalid training id.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("invalid userId");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("ECN invalid");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Not Authorized");
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult AddGroupToTrainingAdHoc(int trainingId, int groupId, int ecnId)
|
||||
{
|
||||
if ((bool)Session[GlobalVars.IS_ADMIN])
|
||||
{
|
||||
public ActionResult AddGroupToTrainingAdHoc(int trainingId, int groupId, int ecnId) {
|
||||
if ((bool)Session[GlobalVars.IS_ADMIN]) {
|
||||
ECN ecn = ecnDMO.GetECN(ecnId);
|
||||
Training training = trainingDMO.GetTraining(trainingId);
|
||||
TrainingGroup group = trainingDMO.GetTrainingGroupByID(groupId);
|
||||
List<int> groupMemberIds = trainingDMO.GetTrainees(groupId);
|
||||
int usersAdded = 0;
|
||||
|
||||
if (ecn != null)
|
||||
{
|
||||
if (training != null)
|
||||
{
|
||||
if (training.DeletedDate == null && !ecn.Deleted)
|
||||
{
|
||||
if (training.CompletedDate != null)
|
||||
{
|
||||
if (ecn != null) {
|
||||
if (training != null) {
|
||||
if (training.DeletedDate == null && !ecn.Deleted) {
|
||||
if (training.CompletedDate != null) {
|
||||
//Training is completed and now we need to re-open it.
|
||||
foreach (int id in groupMemberIds)
|
||||
{
|
||||
foreach (int id in groupMemberIds) {
|
||||
//Check to make sure user doesn't have an active assignment for this training
|
||||
if (!trainingDMO.IsUserAssigned(id, trainingId))
|
||||
{
|
||||
if (!trainingDMO.IsUserAssigned(id, trainingId)) {
|
||||
usersAdded++;
|
||||
int assignmentId = trainingDMO.CreateAssignment(trainingId, id);
|
||||
NotifyTrainee(id, assignmentId, ecnId, ecn.Title);
|
||||
}
|
||||
}
|
||||
if (usersAdded > 0)
|
||||
{
|
||||
if (usersAdded > 0) {
|
||||
trainingDMO.reOpenTraining(trainingId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
//training is still open, just add a users and notify
|
||||
foreach (int id in groupMemberIds)
|
||||
{
|
||||
foreach (int id in groupMemberIds) {
|
||||
//Check to make sure user doesn't have an active assignment for this training
|
||||
if (!trainingDMO.IsUserAssigned(id, trainingId))
|
||||
{
|
||||
if (!trainingDMO.IsUserAssigned(id, trainingId)) {
|
||||
usersAdded++;
|
||||
int assignmentId = trainingDMO.CreateAssignment(trainingId, id);
|
||||
NotifyTrainee(id, assignmentId, ecnId, ecn.Title);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (usersAdded > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (usersAdded > 0) {
|
||||
try {
|
||||
trainingDMO.AddTrainingGroupToECN(ecnId, groupId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
return Content(e.ToString());
|
||||
}
|
||||
}
|
||||
return Content("Success. " + usersAdded + " users added.");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Training or ECN has been deleted.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Invalid training id.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("ECN invalid");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Not Authorized");
|
||||
}
|
||||
}
|
||||
public ActionResult DeleteTrainingByECN(int ECNNumber)
|
||||
{
|
||||
|
||||
public ActionResult DeleteTrainingByECN(int ECNNumber) {
|
||||
int trainingId = trainingDMO.GetTrainingId(ECNNumber);
|
||||
if (trainingId != null && trainingId != 0)
|
||||
{
|
||||
if (trainingId != null && trainingId != 0) {
|
||||
trainingDMO.DeleteTraining(trainingId);
|
||||
}
|
||||
return RedirectToAction("ViewTrainings");
|
||||
}
|
||||
|
||||
public ActionResult DeleteTrainingByID(int trainingId)
|
||||
{
|
||||
if (trainingId != null && trainingId != 0)
|
||||
{
|
||||
public ActionResult DeleteTrainingByID(int trainingId) {
|
||||
if (trainingId != null && trainingId != 0) {
|
||||
trainingDMO.DeleteTraining(trainingId);
|
||||
}
|
||||
return RedirectToAction("ViewTrainings");
|
||||
}
|
||||
public void NotifyTrainee(int userId, int assignmentId, int ecnId, string title)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
public void NotifyTrainee(int userId, int assignmentId, int ecnId, string title) {
|
||||
try {
|
||||
string emailSentList = "";
|
||||
//ECN ecn = ecnDMO.GetECN(ecnNumber);
|
||||
//List<string> emailIst = ldDMO.GetApproverEmailList(@issueID, currentStep).Distinct().ToList();
|
||||
string recipient = userDMO.GetUserEmailByID(userId.ToString());
|
||||
|
||||
string emailTemplate = "ECNTrainingAssigned.txt";
|
||||
@ -248,7 +186,6 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
subject = "ECN# " + ecnId + " - Training Assignment Notice - " + title;
|
||||
|
||||
EmailNotification en = new EmailNotification(subject, ConfigurationManager.AppSettings["EmailTemplatesPath"]);
|
||||
//string emailparams = "";
|
||||
userEmail = recipient;
|
||||
string[] emailparams = new string[4];
|
||||
emailparams[0] = assignmentId.ToString();
|
||||
@ -260,60 +197,46 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
//#endif
|
||||
|
||||
en.SendNotificationEmail(emailTemplate, GlobalVars.SENDER_EMAIL, senderName, userEmail, null, subject, emailparams);
|
||||
//en.SendNotificationEmail(emailTemplate, SenderEmail, senderName, userEmail, null, subject, emailparams);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
string detailedException = "";
|
||||
try
|
||||
{
|
||||
try {
|
||||
detailedException = e.InnerException.ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
detailedException = e.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult ViewTrainingPartial(int trainingID, int userID)
|
||||
{
|
||||
public ActionResult ViewTrainingPartial(int trainingID, int userID) {
|
||||
List<TrainingAssignment> TrainingData = trainingDMO.GetTrainingAssignmentsByUser(trainingID, userID);
|
||||
if (trainingID > 0)
|
||||
{
|
||||
if (trainingID > 0) {
|
||||
ViewBag.ECNNumber = trainingDMO.GetTraining(trainingID).ECN;
|
||||
}
|
||||
return PartialView(TrainingData);
|
||||
}
|
||||
public ActionResult ViewTrainingDocsPartial(int trainingAssignmentId)
|
||||
{
|
||||
|
||||
public ActionResult ViewTrainingDocsPartial(int trainingAssignmentId) {
|
||||
ViewBag.trainingAssignmentId = trainingAssignmentId;
|
||||
//IEnumerable<TrainingDocAck> attachments = ecnDMO.GetECNAttachments(ecnNumber);
|
||||
IEnumerable<TrainingDocAck> attachments = trainingDMO.GetAssignedDocs(trainingAssignmentId);
|
||||
return PartialView(attachments);
|
||||
}
|
||||
public ActionResult AcknowledgeDocument(int trainingAssignmentID, int trainingDocAckID)
|
||||
{
|
||||
|
||||
public ActionResult AcknowledgeDocument(int trainingAssignmentID, int trainingDocAckID) {
|
||||
//Check to see if acknowledgement is valid(Security Feature to protect data integrity)
|
||||
if (trainingDMO.CheckValidDocAck(trainingDocAckID))
|
||||
{
|
||||
if (trainingDMO.CheckValidDocAck(trainingDocAckID)) {
|
||||
trainingDMO.AcknowledgeDocument(trainingDocAckID);
|
||||
bool isFinishedTrainingAssignment = trainingDMO.CheckTrainingAssignmentStatus(trainingAssignmentID);
|
||||
|
||||
if (isFinishedTrainingAssignment)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isFinishedTrainingAssignment) {
|
||||
try {
|
||||
trainingDMO.UpdateAssignmentStatus(trainingAssignmentID);
|
||||
bool isFinishedTraining = trainingDMO.CheckTrainingStatus(trainingAssignmentID);
|
||||
if (isFinishedTraining)
|
||||
{
|
||||
if (isFinishedTraining) {
|
||||
int TrainingID = trainingDMO.GetTrainingIdByAssignment(trainingAssignmentID);
|
||||
trainingDMO.UpdateTrainingStatus(TrainingID);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
string exception = e.ToString();
|
||||
return Content(exception);
|
||||
}
|
||||
@ -322,53 +245,38 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
|
||||
return Content("Marked Succesfully.");
|
||||
}
|
||||
public ActionResult AcknowledgeReviewNoDocuments(int trainingAssignmentID)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
public ActionResult AcknowledgeReviewNoDocuments(int trainingAssignmentID) {
|
||||
try {
|
||||
trainingDMO.UpdateAssignmentStatus(trainingAssignmentID);
|
||||
bool isFinishedTraining = trainingDMO.CheckTrainingStatus(trainingAssignmentID);
|
||||
if (isFinishedTraining)
|
||||
{
|
||||
if (isFinishedTraining) {
|
||||
int TrainingID = trainingDMO.GetTrainingIdByAssignment(trainingAssignmentID);
|
||||
trainingDMO.UpdateTrainingStatus(TrainingID);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
string exception = e.ToString();
|
||||
return Content(exception, "application/json");
|
||||
}
|
||||
|
||||
return Json(new { test = "Succesfully saved" });
|
||||
}
|
||||
//public ActionResult ViewTrainings()
|
||||
//{
|
||||
// IEnumerable<Training> trainings = trainingDMO.GetTrainings();
|
||||
|
||||
// return View(trainings);
|
||||
//}
|
||||
public ActionResult TrainingReports()
|
||||
{
|
||||
|
||||
public ActionResult TrainingReports() {
|
||||
return View();
|
||||
}
|
||||
public ActionResult TrainingReportsView(int? filterType, string filterValue)
|
||||
{
|
||||
|
||||
public ActionResult TrainingReportsView(int? filterType, string filterValue) {
|
||||
ViewBag.TrainingGroups = adminDMO.GetTrainingGroups();
|
||||
IEnumerable<Training> trainingList = trainingDMO.GetAllTrainings();
|
||||
//Group Filter
|
||||
if (filterType == 1 && filterValue != "")
|
||||
{
|
||||
if (filterType == 1 && filterValue != "") {
|
||||
ViewBag.GroupFilter = filterValue;
|
||||
List<Training> filteredTraining = new List<Training>();
|
||||
foreach (var item in trainingList)
|
||||
{
|
||||
foreach (Training item in trainingList) {
|
||||
List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(item.ECN);
|
||||
foreach (int id in assignedTrainingGroups)
|
||||
{
|
||||
if (filterValue == id.ToString())
|
||||
{
|
||||
foreach (int id in assignedTrainingGroups) {
|
||||
if (filterValue == id.ToString()) {
|
||||
filteredTraining.Add(item);
|
||||
}
|
||||
}
|
||||
@ -377,11 +285,9 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
return PartialView(trainingList);
|
||||
}
|
||||
//Status Filter
|
||||
if (filterType == 2 && filterValue != "")
|
||||
{
|
||||
if (filterType == 2 && filterValue != "") {
|
||||
List<Training> filteredTraining = new List<Training>();
|
||||
switch (filterValue)
|
||||
{
|
||||
switch (filterValue) {
|
||||
case "1":
|
||||
//Completed
|
||||
filteredTraining = (from a in trainingList where a.Status == true && a.Deleted != true select a).ToList();
|
||||
@ -399,13 +305,12 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
return PartialView(trainingList);
|
||||
}
|
||||
//Default return all.
|
||||
else
|
||||
{
|
||||
else {
|
||||
return PartialView(trainingList);
|
||||
}
|
||||
}
|
||||
public ActionResult ViewTrainingAssignmentsReportView(int trainingID, string statusFilter, string groupFilter)
|
||||
{
|
||||
|
||||
public ActionResult ViewTrainingAssignmentsReportView(int trainingID, string statusFilter, string groupFilter) {
|
||||
bool? trainingStatus = trainingDMO.GetTraining(trainingID).Status;
|
||||
int ECNNumber = trainingDMO.GetTraining(trainingID).ECN;
|
||||
string ECNTitle = ecnDMO.GetECN(ECNNumber).Title;
|
||||
@ -420,38 +325,29 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
//float assignmentCount = trainingAssignments.Count();
|
||||
float assignmentCount = (from a in trainingAssignments where a.Deleted != true select a).Count();
|
||||
float totalCompleted = 0;
|
||||
foreach (var assignment in trainingAssignments)
|
||||
{
|
||||
if (assignment.status == true && assignment.Deleted != true)
|
||||
{
|
||||
foreach (TrainingAssignment assignment in trainingAssignments) {
|
||||
if (assignment.status == true && assignment.Deleted != true) {
|
||||
totalCompleted++;
|
||||
}
|
||||
}
|
||||
#pragma warning disable IDE0047 // Remove unnecessary parentheses
|
||||
percentComplete = (totalCompleted / assignmentCount) * 100;
|
||||
#pragma warning restore IDE0047 // Remove unnecessary parentheses
|
||||
percentComplete = totalCompleted / assignmentCount * 100;
|
||||
ViewBag.PercentComplete = percentComplete.ToString("0.00") + "%";
|
||||
|
||||
if (groupFilter != "" && groupFilter != null)
|
||||
{
|
||||
if (groupFilter != "" && groupFilter != null) {
|
||||
ViewBag.GroupFilter = groupFilter;
|
||||
List<TrainingAssignment> groupFilteredTraining = new List<TrainingAssignment>();
|
||||
List<int> groupMemberIds = trainingDMO.GetTrainees(Convert.ToInt32(groupFilter));
|
||||
foreach (var assignment in trainingAssignments)
|
||||
{
|
||||
if (trainingDMO.isUserTrainingMember(Convert.ToInt32(groupFilter), assignment.UserID))
|
||||
{
|
||||
foreach (TrainingAssignment assignment in trainingAssignments) {
|
||||
if (trainingDMO.isUserTrainingMember(Convert.ToInt32(groupFilter), assignment.UserID)) {
|
||||
groupFilteredTraining.Add(assignment);
|
||||
}
|
||||
}
|
||||
trainingAssignments = groupFilteredTraining;
|
||||
|
||||
}
|
||||
if (statusFilter != "" && statusFilter != null)
|
||||
{
|
||||
if (statusFilter != "" && statusFilter != null) {
|
||||
List<TrainingAssignment> filteredTraining = new List<TrainingAssignment>();
|
||||
switch (statusFilter)
|
||||
{
|
||||
switch (statusFilter) {
|
||||
|
||||
case "1":
|
||||
//Completed
|
||||
@ -475,8 +371,8 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
|
||||
return PartialView(trainingAssignments);
|
||||
}
|
||||
public ActionResult ViewTrainingAssignments(int trainingID)
|
||||
{
|
||||
|
||||
public ActionResult ViewTrainingAssignments(int trainingID) {
|
||||
bool? trainingStatus = trainingDMO.GetTraining(trainingID).Status;
|
||||
int ECNNumber = trainingDMO.GetTraining(trainingID).ECN;
|
||||
string ECNTitle = ecnDMO.GetECN(ECNNumber).Title;
|
||||
@ -490,24 +386,21 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
|
||||
return View(trainingAssignments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to return all the training assignments for a specified user
|
||||
/// </summary>
|
||||
/// <param name="userID"></param>
|
||||
/// <returns></returns>
|
||||
public ActionResult ViewMyTrainingAssignments()
|
||||
{
|
||||
public ActionResult ViewMyTrainingAssignments() {
|
||||
int userID = (int)Session[GlobalVars.SESSION_USERID];
|
||||
List<TrainingAssignment> assignments = trainingDMO.GetTrainingAssignmentsByUserID(userID);
|
||||
List<ECNTrainingAssignments> ViewData = new List<ECNTrainingAssignments>();
|
||||
foreach (var assignment in assignments)
|
||||
{
|
||||
foreach (TrainingAssignment assignment in assignments) {
|
||||
Training training = trainingDMO.GetTraining(assignment.TrainingID);
|
||||
if (training != null && !assignment.status)
|
||||
{
|
||||
if (training != null && !assignment.status) {
|
||||
int ecnID = training.ECN;
|
||||
ViewData.Add(new ECNTrainingAssignments
|
||||
{
|
||||
ViewData.Add(new ECNTrainingAssignments {
|
||||
TrainingAssignmentID = assignment.ID,
|
||||
ECN_ID = ecnID,
|
||||
TrainingID = assignment.TrainingID,
|
||||
@ -520,57 +413,48 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
|
||||
return View(ViewData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to return all assigned documents for a specified training assignment
|
||||
/// </summary>
|
||||
/// <param name="assignmentID"></param>
|
||||
/// <returns></returns>
|
||||
public ActionResult ViewMyTrainingAssignment(int assignmentID, int ECNNumber)
|
||||
{
|
||||
public ActionResult ViewMyTrainingAssignment(int assignmentID, int ECNNumber) {
|
||||
ViewBag.ECNNumber = ECNNumber;
|
||||
ViewBag.AssignmentID = assignmentID;
|
||||
ViewBag.IsCompleted = trainingDMO.GetAssignment(assignmentID).status;
|
||||
return View(trainingDMO.GetAssignedDocs(assignmentID));
|
||||
}
|
||||
public ActionResult ViewTrainings(int? filterType, string filterValue)
|
||||
{
|
||||
|
||||
public ActionResult ViewTrainings(int? filterType, string filterValue) {
|
||||
IEnumerable<Training> AllTrainings = trainingDMO.GetTrainings();
|
||||
ViewBag.TrainingGroups = adminDMO.GetTrainingGroups();
|
||||
ViewBag.AllGroups = trainingDMO.GetTrainingGroups();
|
||||
//Group Filter
|
||||
if (filterType == 1 && filterValue != "")
|
||||
{
|
||||
if (filterType == 1 && filterValue != "") {
|
||||
ViewBag.GroupFilter = filterValue;
|
||||
List<Training> filteredTraining = new List<Training>();
|
||||
foreach (var item in AllTrainings)
|
||||
{
|
||||
foreach (Training item in AllTrainings) {
|
||||
List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(item.ECN);
|
||||
foreach (int id in assignedTrainingGroups)
|
||||
{
|
||||
if (filterValue == id.ToString())
|
||||
{
|
||||
foreach (int id in assignedTrainingGroups) {
|
||||
if (filterValue == id.ToString()) {
|
||||
filteredTraining.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
AllTrainings = filteredTraining;
|
||||
return View(AllTrainings);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ViewBag.AllGroups = trainingDMO.GetTrainingGroups();
|
||||
return View(AllTrainings);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public ActionResult ViewAllTrainings()
|
||||
{
|
||||
|
||||
public ActionResult ViewAllTrainings() {
|
||||
return View();
|
||||
}
|
||||
public ActionResult DeleteAssignment(int assignmentId)
|
||||
{
|
||||
|
||||
public ActionResult DeleteAssignment(int assignmentId) {
|
||||
trainingDMO.DeleteTrainingAssignment(assignmentId);
|
||||
trainingDMO.DeleteTrainingDocAck(assignmentId);
|
||||
|
||||
@ -578,116 +462,81 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
//TO-DO Put this in its own method.
|
||||
bool isFinishedTrainingAssignment = trainingDMO.CheckTrainingAssignmentStatus(assignmentId);
|
||||
|
||||
if (isFinishedTrainingAssignment)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isFinishedTrainingAssignment) {
|
||||
try {
|
||||
trainingDMO.UpdateAssignmentStatus(assignmentId);
|
||||
bool isFinishedTraining = trainingDMO.CheckTrainingStatus(assignmentId);
|
||||
if (isFinishedTraining)
|
||||
{
|
||||
if (isFinishedTraining) {
|
||||
int TrainingID = trainingDMO.GetTrainingIdByAssignment(assignmentId);
|
||||
trainingDMO.UpdateTrainingStatus(TrainingID);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
string exception = e.ToString();
|
||||
return Content(exception, "application/json");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return Json(new { test = "Succesfully saved" });
|
||||
}
|
||||
public ActionResult ManuallyExecuteECNTraining(int ecnId, int[] trainingGroupsIn)
|
||||
{
|
||||
if ((bool)Session[GlobalVars.IS_ADMIN])
|
||||
{
|
||||
|
||||
public ActionResult ManuallyExecuteECNTraining(int ecnId, int[] trainingGroupsIn) {
|
||||
if ((bool)Session[GlobalVars.IS_ADMIN]) {
|
||||
List<int> newTrainingGroupIds = new List<int>(trainingGroupsIn);
|
||||
//Get ECN
|
||||
ECN ecn = ecnDMO.GetECN(ecnId);
|
||||
if (ecn != null)
|
||||
{
|
||||
if (ecn.CloseDate != null)
|
||||
{
|
||||
if (newTrainingGroupIds.Count > 0)
|
||||
{
|
||||
if (ecn != null) {
|
||||
if (ecn.CloseDate != null) {
|
||||
if (newTrainingGroupIds.Count > 0) {
|
||||
//Check each assigned group id and see if it's already saved to the ECN
|
||||
List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(ecnId);
|
||||
IEnumerable<int> onlyNewTrainingIds = newTrainingGroupIds.Except(assignedTrainingGroups);
|
||||
try
|
||||
{
|
||||
foreach (int trainingId in onlyNewTrainingIds)
|
||||
{
|
||||
try {
|
||||
foreach (int trainingId in onlyNewTrainingIds) {
|
||||
trainingDMO.AddTrainingGroupToECN(ecnId, trainingId);
|
||||
}
|
||||
|
||||
trainingDMO.SetTrainingFlag(ecnId);
|
||||
Create(ecnId);
|
||||
return Content("Success");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
return Content("Failed: " + e.Message.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("There were no training groups to assign to. Please select at least one training groups.");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Selected ECN hasn't been approved yet.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Invalid ECN");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("Not Autthorized");
|
||||
}
|
||||
}
|
||||
public ActionResult CheckECN(int ecnId)
|
||||
{
|
||||
|
||||
public ActionResult CheckECN(int ecnId) {
|
||||
ECN ecn = ecnDMO.GetECN(ecnId);
|
||||
if (ecn != null)
|
||||
{
|
||||
if (ecn.CloseDate != null)
|
||||
{
|
||||
if (ecn != null) {
|
||||
if (ecn.CloseDate != null) {
|
||||
List<int> trainingGroupIds = trainingDMO.GetECNAssignedTrainingGroups(ecnId);
|
||||
List<TrainingGroup> assignedGroups = new List<TrainingGroup>();
|
||||
foreach (int trainingGroupId in trainingGroupIds)
|
||||
{
|
||||
foreach (int trainingGroupId in trainingGroupIds) {
|
||||
TrainingGroup trainingGroup = trainingDMO.GetTrainingGroupByID(trainingGroupId);
|
||||
assignedGroups.Add(trainingGroup);
|
||||
}
|
||||
return Json(trainingGroupIds.ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("ECN not yet approved.");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return Content("That ECN wasn't found.");
|
||||
}
|
||||
|
||||
}
|
||||
public bool RunTrainingReport()
|
||||
{
|
||||
|
||||
public bool RunTrainingReport() {
|
||||
bool isSuccess = false;
|
||||
try
|
||||
{
|
||||
try {
|
||||
string emailBody = "<h1>Mesa Approval Open Training Assignments Daily Report</h1> <br />";
|
||||
emailBody += "<p>The following contains open training assignments in the Mesa Approval system. ";
|
||||
emailBody += "Please ensure the following users complete their training assignments. ";
|
||||
@ -696,8 +545,7 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
//Get all users set up to receive the training report email.
|
||||
List<TrainingReportUser> trainingReportUsers = adminDMO.GetTrainingReportUsers();
|
||||
List<string> emailList = new List<string>();
|
||||
foreach (var user in trainingReportUsers)
|
||||
{
|
||||
foreach (TrainingReportUser user in trainingReportUsers) {
|
||||
string userEmail = userDMO.GetUserByID(user.UserId).Email;
|
||||
emailList.Add(userEmail);
|
||||
}
|
||||
@ -705,8 +553,7 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
//Get a list of open trainings
|
||||
List<Training> openTrainings = trainingDMO.GetAllOpenTrainings();
|
||||
|
||||
foreach (Training training in openTrainings)
|
||||
{
|
||||
foreach (Training training in openTrainings) {
|
||||
string trainingSection = "";
|
||||
int trainingSectionUserCount = 0;
|
||||
string ecnTitle = ecnDMO.GetECN(training.ECN).Title;
|
||||
@ -715,23 +562,18 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
trainingSection += "<table>";
|
||||
trainingSection += "<tr><th>Name</th><th>Date Assigned</th></tr>";
|
||||
List<TrainingAssignment> openAssignments = trainingDMO.GetOpenAssignmentsByTrainingID(training.TrainingID);
|
||||
foreach (TrainingAssignment assignment in openAssignments)
|
||||
{
|
||||
foreach (TrainingAssignment assignment in openAssignments) {
|
||||
|
||||
if (!userDMO.GetUserByID(assignment.UserID).OOO)
|
||||
{
|
||||
if (!userDMO.GetUserByID(assignment.UserID).OOO) {
|
||||
trainingSectionUserCount++;
|
||||
|
||||
DateTime? assignmentDate = assignment.DateAssigned;
|
||||
|
||||
string DateAssigned = assignmentDate.HasValue ? assignmentDate.Value.ToString("MM/dd/yyyy") : "<not available>";
|
||||
|
||||
if (assignmentDate.HasValue && (DateTime.Now.Date - assignmentDate.Value.Date).TotalDays > 15)
|
||||
{
|
||||
if (assignmentDate.HasValue && (DateTime.Now.Date - assignmentDate.Value.Date).TotalDays > 15) {
|
||||
trainingSection += "<tr><td>" + assignment.FullName + "</td><td style=\"color:red;\">" + DateAssigned + "</td>";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
trainingSection += "<tr><td>" + assignment.FullName + "</td><td>" + DateAssigned + "</td>";
|
||||
}
|
||||
|
||||
@ -745,13 +587,10 @@ namespace Fab2ApprovalSystem.Controllers
|
||||
List<string> ccRecipients = emailList;
|
||||
emailer.SendNotification("MesaFabApproval@infineon.com", ccRecipients, "Mesa Approval Daily Open Training Report", emailBody, "Daily Open Training Report");
|
||||
isSuccess = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
isSuccess = false;
|
||||
}
|
||||
return isSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Fab2ApprovalSystem.Models;
|
||||
using Dapper;
|
||||
using System.Transactions;
|
||||
@ -13,8 +11,7 @@ using Fab2ApprovalSystem.ViewModels;
|
||||
using System.Reflection;
|
||||
using Fab2ApprovalSystem.Misc;
|
||||
|
||||
namespace Fab2ApprovalSystem.DMO
|
||||
{
|
||||
namespace Fab2ApprovalSystem.DMO {
|
||||
public class LotDispositionDMO
|
||||
{
|
||||
private IDbConnection db = new SqlConnection(GlobalVars.DB_CONNECTION_STRING);
|
||||
|
@ -153,6 +153,8 @@
|
||||
<Compile Include="Models\ApprovalLog.cs" />
|
||||
<Compile Include="Models\ApprovalLogHistory.cs" />
|
||||
<Compile Include="Models\ApproveListModel.cs" />
|
||||
<Compile Include="Models\AuthAttempt.cs" />
|
||||
<Compile Include="Models\AuthTokens.cs" />
|
||||
<Compile Include="Models\ChangeControlModel.cs" />
|
||||
<Compile Include="Models\Common.cs" />
|
||||
<Compile Include="Models\C_8DAuditedStandard.cs">
|
||||
@ -182,6 +184,7 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>FabApproval.edmx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Models\LoginResult.cs" />
|
||||
<Compile Include="Models\LotTravellerModel.cs" />
|
||||
<Compile Include="Models\PartsRequestModels.cs" />
|
||||
<Compile Include="Models\TECNNotificationsUser.cs">
|
||||
|
@ -6,10 +6,8 @@ using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using System.Web;
|
||||
|
||||
namespace Fab2ApprovalSystem.Misc
|
||||
{
|
||||
public class EmailNotification
|
||||
{
|
||||
namespace Fab2ApprovalSystem.Misc {
|
||||
public class EmailNotification {
|
||||
#region Variabls
|
||||
protected string _subject = null;
|
||||
protected string _TemplatesPath = null;
|
||||
@ -18,10 +16,8 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <summary>
|
||||
/// Email subject
|
||||
/// </summary>
|
||||
public string EmailSubject
|
||||
{
|
||||
public string EmailSubject {
|
||||
set { _subject = value; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -29,11 +25,9 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// </summary>
|
||||
/// <param name="FileName">File Name</param>
|
||||
/// <returns>String: Containing the Entire content of the file</returns>
|
||||
protected string ReadEmailFile(string FileName)
|
||||
{
|
||||
protected string ReadEmailFile(string FileName) {
|
||||
string retVal = null;
|
||||
try
|
||||
{
|
||||
try {
|
||||
//setting the file name path
|
||||
string path = _TemplatesPath + FileName;
|
||||
FileInfo TheFile = new FileInfo(System.Web.HttpContext.Current.Server.MapPath(path));
|
||||
@ -46,17 +40,12 @@ namespace Fab2ApprovalSystem.Misc
|
||||
StreamReader sr = new StreamReader(System.Web.HttpContext.Current.Server.MapPath(@path), System.Text.Encoding.GetEncoding(1256));
|
||||
retVal = sr.ReadToEnd(); // getting the entire text from the file.
|
||||
sr.Close();
|
||||
}
|
||||
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Error Reading File." + ex.Message);
|
||||
|
||||
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// this function will send email. it will read the mail setting from the web.config
|
||||
/// </summary>
|
||||
@ -66,8 +55,8 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="cc">CC ids</param>
|
||||
/// <param name="email_title">Email Subject</param>
|
||||
/// <param name="email_body">Email Body</param>
|
||||
protected void SendEmail(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body)
|
||||
{
|
||||
#pragma warning disable IDE0060 // Remove unused parameter
|
||||
protected void SendEmail(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body) {
|
||||
// creating email message
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.IsBodyHtml = true;// email body will allow html elements
|
||||
@ -87,27 +76,18 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.Subject = email_title;
|
||||
msg.Body = email_body;
|
||||
|
||||
|
||||
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient("mailrelay-internal.infineon.com");
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient("mailrelay-internal.infineon.com");
|
||||
|
||||
// sending the message.
|
||||
try
|
||||
{
|
||||
try {
|
||||
SmtpMail.Send(msg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine("Exception caught in CreateTestMessage2(): {0}",
|
||||
ex.ToString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#pragma warning restore IDE0060 // Remove unused parameter
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@ -119,8 +99,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="email_title"></param>
|
||||
/// <param name="email_body"></param>
|
||||
/// <param name="attachmentPath"></param>
|
||||
protected void SendEmailWithAttachment(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, string attachmentPath)
|
||||
{
|
||||
protected void SendEmailWithAttachment(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, string attachmentPath) {
|
||||
// creating email message
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.IsBodyHtml = true;// email body will allow html elements
|
||||
@ -140,22 +119,14 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.Body = email_body;
|
||||
msg.Attachments.Add(new Attachment(attachmentPath));
|
||||
|
||||
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient();
|
||||
#if(!DEBUG)
|
||||
// sending the message.
|
||||
SmtpMail.Send(msg);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -165,8 +136,8 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="cc"></param>
|
||||
/// <param name="email_title"></param>
|
||||
/// <param name="email_body"></param>
|
||||
protected void SendEmail(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body)
|
||||
{
|
||||
#pragma warning disable IDE0060 // Remove unused parameter
|
||||
protected void SendEmail(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body) {
|
||||
// creating email message
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.IsBodyHtml = true;// email body will allow html elements
|
||||
@ -175,8 +146,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
//msg.From = new MailAddress(SenderEmail, SenderName);
|
||||
msg.From = new MailAddress("MesaFabApproval@infineon.com", "Mesa Fab Approval");
|
||||
// adding the Recepient Email ID
|
||||
foreach (string recepient in RecepientList)
|
||||
{
|
||||
foreach (string recepient in RecepientList) {
|
||||
msg.To.Add(recepient);
|
||||
}
|
||||
|
||||
@ -188,26 +158,18 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.Subject = email_title;
|
||||
msg.Body = email_body;
|
||||
|
||||
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient();
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient();
|
||||
|
||||
// sending the message.
|
||||
try
|
||||
{
|
||||
try {
|
||||
SmtpMail.Send(msg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine("Exception caught in CreateTestMessage2(): {0}",
|
||||
ex.ToString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
#pragma warning restore IDE0060 // Remove unused parameter
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@ -219,8 +181,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="email_title"></param>
|
||||
/// <param name="email_body"></param>
|
||||
/// <param name="attachmentPath"></param>
|
||||
protected void SendEmailWithAttachment(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, string attachmentPath)
|
||||
{
|
||||
protected void SendEmailWithAttachment(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, string attachmentPath) {
|
||||
// creating email message
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.IsBodyHtml = true;// email body will allow html elements
|
||||
@ -229,8 +190,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.From = new MailAddress(SenderEmail, SenderName);
|
||||
|
||||
// adding the Recepient Email ID
|
||||
foreach (string recepient in RecepientList)
|
||||
{
|
||||
foreach (string recepient in RecepientList) {
|
||||
if (recepient != null)
|
||||
msg.To.Add(recepient);
|
||||
}
|
||||
@ -244,19 +204,13 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.Body = email_body;
|
||||
msg.Attachments.Add(new Attachment(attachmentPath));
|
||||
|
||||
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient();
|
||||
|
||||
// sending the message.
|
||||
SmtpMail.Send(msg);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -267,8 +221,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="email_title"></param>
|
||||
/// <param name="email_body"></param>
|
||||
/// <param name="attachments"></param>
|
||||
protected void SendEmailWithAttachments(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, List<string> attachments)
|
||||
{
|
||||
protected void SendEmailWithAttachments(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, List<string> attachments) {
|
||||
// creating email message
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.IsBodyHtml = true;// email body will allow html elements
|
||||
@ -286,35 +239,29 @@ namespace Fab2ApprovalSystem.Misc
|
||||
//setting email subject and body
|
||||
msg.Subject = email_title;
|
||||
msg.Body = email_body;
|
||||
foreach (string attachment in attachments)
|
||||
{
|
||||
foreach (string attachment in attachments) {
|
||||
msg.Attachments.Add(new Attachment(attachment));
|
||||
}
|
||||
|
||||
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient();
|
||||
#if(!DEBUG)
|
||||
// sending the message.
|
||||
SmtpMail.Send(msg);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="SenderEmail"></param>
|
||||
/// <param name="SenderName"></param>
|
||||
/// <param name="RecepientList"></param>
|
||||
/// <param name="cc"></param>
|
||||
/// <param name="email_title"></param>
|
||||
/// <param name="email_body"></param>
|
||||
/// <param name="attachments"></param>
|
||||
protected void SendEmailWithAttachments(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, List<string> attachments)
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="SenderEmail"></param>
|
||||
/// <param name="SenderName"></param>
|
||||
/// <param name="RecepientList"></param>
|
||||
/// <param name="cc"></param>
|
||||
/// <param name="email_title"></param>
|
||||
/// <param name="email_body"></param>
|
||||
/// <param name="attachments"></param>
|
||||
protected void SendEmailWithAttachments(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, List<string> attachments) {
|
||||
// creating email message
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.IsBodyHtml = true;// email body will allow html elements
|
||||
@ -323,8 +270,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.From = new MailAddress(SenderEmail, SenderName);
|
||||
|
||||
// adding the Recepient Email ID
|
||||
foreach (string recepient in RecepientList)
|
||||
{
|
||||
foreach (string recepient in RecepientList) {
|
||||
if (recepient != null)
|
||||
msg.To.Add(recepient);
|
||||
}
|
||||
@ -337,44 +283,32 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.Subject = email_title;
|
||||
msg.Body = email_body;
|
||||
|
||||
foreach (string attachment in attachments)
|
||||
{
|
||||
foreach (string attachment in attachments) {
|
||||
msg.Attachments.Add(new Attachment(attachment));
|
||||
}
|
||||
|
||||
|
||||
//create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section
|
||||
SmtpClient SmtpMail = new SmtpClient();
|
||||
|
||||
// sending the message.
|
||||
SmtpMail.Send(msg);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public EmailNotification()
|
||||
{
|
||||
public EmailNotification() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Constructor Function
|
||||
/// </summary>
|
||||
/// <param name="EmailHeaderSubject">Email Header Subject</param>
|
||||
/// <param name="TemplatesPath">Emails Files Templates</param>
|
||||
public EmailNotification(string EmailHeaderSubject, string TemplatesPath)
|
||||
{
|
||||
public EmailNotification(string EmailHeaderSubject, string TemplatesPath) {
|
||||
_subject = EmailHeaderSubject;
|
||||
_TemplatesPath = TemplatesPath;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This function will send the email notification by reading the email template and substitute the arguments
|
||||
/// </summary>
|
||||
@ -386,43 +320,33 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="Subject">EMail Subject</param>
|
||||
/// <param name="Args">Arguments</param>
|
||||
/// <returns>String: Return the body of the email to be send</returns>
|
||||
public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, params string[] Args)
|
||||
{
|
||||
public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, params string[] Args) {
|
||||
string retVal = null;
|
||||
|
||||
//reading the file
|
||||
string FileContents = ReadEmailFile(EmailTemplateFile);
|
||||
|
||||
|
||||
string emailBody = FileContents;
|
||||
|
||||
//setting formatting the string
|
||||
retVal = string.Format(emailBody, Args);
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
//check if we are in debug mode or not. to send email
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY")
|
||||
{
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||
SendEmail(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? Subject + " for: " + RecepientEmail : _subject), retVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#if(!DEBUG)
|
||||
SendEmail(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This function will send the email notification by reading the email template and substitute the arguments along with the attachments
|
||||
/// </summary>
|
||||
@ -435,8 +359,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="attachmentPath"></param>
|
||||
/// <param name="Args"></param>
|
||||
/// <returns></returns>
|
||||
public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, string attachmentPath, params string[] Args)
|
||||
{
|
||||
public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, string attachmentPath, params string[] Args) {
|
||||
string retVal = null;
|
||||
|
||||
//reading the file
|
||||
@ -447,32 +370,22 @@ namespace Fab2ApprovalSystem.Misc
|
||||
//setting formatting the string
|
||||
retVal = string.Format(emailBody, Args);
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
//check if we are in debug mode or not. to send email
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY")
|
||||
{
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||
SendEmailWithAttachment(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject + RecepientEmail : _subject), retVal, attachmentPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#if(!DEBUG)
|
||||
SendEmailWithAttachment(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachmentPath);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -485,8 +398,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="attachmentPath"></param>
|
||||
/// <param name="Args"></param>
|
||||
/// <returns></returns>
|
||||
public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, string attachmentPath, params string[] Args)
|
||||
{
|
||||
public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, string attachmentPath, params string[] Args) {
|
||||
string retVal = null;
|
||||
|
||||
//reading the file
|
||||
@ -497,41 +409,28 @@ namespace Fab2ApprovalSystem.Misc
|
||||
//setting formatting the string
|
||||
retVal = string.Format(emailBody, Args);
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
//check if we are in debug mode or not. to send email
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY")
|
||||
{
|
||||
foreach(string email in RecepientEmail)
|
||||
{
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||
foreach (string email in RecepientEmail) {
|
||||
Subject += email + ";";
|
||||
}
|
||||
|
||||
RecepientEmail.Clear();
|
||||
SendEmailWithAttachment(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject : _subject), retVal, attachmentPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#if (!DEBUG)
|
||||
SendEmailWithAttachment(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachmentPath);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/////////============================================================
|
||||
|
||||
public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args)
|
||||
{
|
||||
public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args) {
|
||||
string retVal = null;
|
||||
|
||||
//reading the file
|
||||
@ -542,32 +441,22 @@ namespace Fab2ApprovalSystem.Misc
|
||||
//setting formatting the string
|
||||
retVal = string.Format(emailBody, Args);
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
//check if we are in debug mode or not. to send email
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY")
|
||||
{
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||
SendEmailWithAttachments(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject + RecepientEmail : _subject), retVal, attachments);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#if(!DEBUG)
|
||||
SendEmailWithAttachments(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachments);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -580,8 +469,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="attachmentPath"></param>
|
||||
/// <param name="Args"></param>
|
||||
/// <returns></returns>
|
||||
public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args)
|
||||
{
|
||||
public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args) {
|
||||
string retVal = null;
|
||||
|
||||
//reading the file
|
||||
@ -592,39 +480,27 @@ namespace Fab2ApprovalSystem.Misc
|
||||
//setting formatting the string
|
||||
retVal = string.Format(emailBody, Args);
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
//check if we are in debug mode or not. to send email
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY")
|
||||
{
|
||||
foreach(string email in RecepientEmail)
|
||||
{
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||
foreach (string email in RecepientEmail) {
|
||||
Subject += email + ";";
|
||||
}
|
||||
|
||||
RecepientEmail.Clear();
|
||||
SendEmailWithAttachments(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject : _subject), retVal, attachments);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#if (!DEBUG)
|
||||
SendEmailWithAttachments(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachments);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -636,8 +512,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="Subject"></param>
|
||||
/// <param name="Args"></param>
|
||||
/// <returns></returns>
|
||||
public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, params string[] Args)
|
||||
{
|
||||
public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, params string[] Args) {
|
||||
string retVal = null;
|
||||
|
||||
//reading the file
|
||||
@ -648,33 +523,24 @@ namespace Fab2ApprovalSystem.Misc
|
||||
//setting formatting the string
|
||||
retVal = string.Format(emailBody, Args);
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
//check if we are in debug mode or not. to send email
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY")
|
||||
{
|
||||
foreach (string email in RecepientEmail)
|
||||
{
|
||||
if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") {
|
||||
foreach (string email in RecepientEmail) {
|
||||
Subject += email + ";";
|
||||
}
|
||||
RecepientEmail.Clear();
|
||||
SendEmail(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#if (!DEBUG)
|
||||
SendEmail(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -683,10 +549,8 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="subject"></param>
|
||||
/// <param name="body"></param>
|
||||
/// <param name="importance"></param>
|
||||
public void SendNotificationEmailToAdmin(string subject, string body, MailPriority importance)
|
||||
{
|
||||
try
|
||||
{
|
||||
public void SendNotificationEmailToAdmin(string subject, string body, MailPriority importance) {
|
||||
try {
|
||||
System.Configuration.ConfigurationManager.RefreshSection("appSettings");
|
||||
|
||||
SmtpClient client = new SmtpClient(ConfigurationManager.AppSettings["SMTP Server"]);
|
||||
@ -704,30 +568,23 @@ namespace Fab2ApprovalSystem.Misc
|
||||
msg.Subject = subject;
|
||||
msg.Body = temp;
|
||||
msg.Priority = importance;
|
||||
//#if(!DEBUG)
|
||||
//#if(!DEBUG)
|
||||
client.Send(msg);
|
||||
//#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//#endif
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetTestRecipientsList()
|
||||
{
|
||||
var r = new List<string>();
|
||||
try
|
||||
{
|
||||
public List<string> GetTestRecipientsList() {
|
||||
List<string> r = new List<string>();
|
||||
try {
|
||||
string emails = ConfigurationManager.AppSettings["Test Email Recipients"];
|
||||
foreach (string s in emails.Split(';', ','))
|
||||
{
|
||||
foreach (string s in emails.Split(';', ',')) {
|
||||
if (!String.IsNullOrWhiteSpace(s))
|
||||
r.Add(s);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
r.Add("dhuang2@infineon.com");
|
||||
}
|
||||
return r;
|
||||
|
@ -10,57 +10,44 @@ using System.Net.Mail;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
|
||||
namespace Fab2ApprovalSystem.Misc
|
||||
{
|
||||
public static class Functions
|
||||
{
|
||||
namespace Fab2ApprovalSystem.Misc {
|
||||
public static class Functions {
|
||||
/// <summary>
|
||||
/// Writes to the Application Event Log and sends an email notification if appropriate
|
||||
/// </summary>
|
||||
/// <param name="logtext"></param>
|
||||
/// <param name="eventType"></param>
|
||||
public static void WriteEvent(string logtext, System.Diagnostics.EventLogEntryType eventType)
|
||||
{
|
||||
public static void WriteEvent(string logtext, System.Diagnostics.EventLogEntryType eventType) {
|
||||
//#if(!DEBUG)
|
||||
EmailNotification en = new EmailNotification();
|
||||
EventLog ev = new EventLog("Application");
|
||||
ev.Source = "Fab Approval System";
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
//Write to the Event Log
|
||||
ev.WriteEntry(logtext, eventType);
|
||||
|
||||
////Send an email notification if appropriate
|
||||
////Don't attempt to send an email if the error is pertaining to an email problem
|
||||
if (!logtext.Contains("SendEmailNotification()"))
|
||||
{
|
||||
if (!logtext.Contains("SendEmailNotification()")) {
|
||||
//Only send email notifications for Error and Warning level events
|
||||
if (eventType == System.Diagnostics.EventLogEntryType.Error)
|
||||
en.SendNotificationEmailToAdmin(ev.Source + " - Error Notification", logtext, MailPriority.High);
|
||||
//else if (eventType == System.Diagnostics.EventLogEntryType.Warning)
|
||||
// SendEmailNotification(ErrorRecipient(), ev.Source + " Warning Event Logged", logtext, NORMAL_PRI);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
//throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
} finally {
|
||||
ev = null;
|
||||
}
|
||||
//#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the FTP Server Name
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string FTPServer()
|
||||
{
|
||||
public static string FTPServer() {
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
return ConfigurationManager.AppSettings["FTP Server"];
|
||||
}
|
||||
@ -69,8 +56,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// Returns the FTP User Name
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string FTPUser()
|
||||
{
|
||||
public static string FTPUser() {
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
return ConfigurationManager.AppSettings["FTP User"];
|
||||
}
|
||||
@ -79,8 +65,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// Returns the FTP Password
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string FTPPassword()
|
||||
{
|
||||
public static string FTPPassword() {
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
return ConfigurationManager.AppSettings["FTP Password"];
|
||||
}
|
||||
@ -89,41 +74,32 @@ namespace Fab2ApprovalSystem.Misc
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetAttachmentFolder()
|
||||
{
|
||||
public static string GetAttachmentFolder() {
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
return ConfigurationManager.AppSettings["AttachmentFolder"];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="oldECNNumber"></param>
|
||||
/// <param name="newECNNumber"></param>
|
||||
public static void CopyAttachments(int oldECNNumber, int newECNNumber)
|
||||
{
|
||||
public static void CopyAttachments(int oldECNNumber, int newECNNumber) {
|
||||
// The Name of the Upload component is "files"
|
||||
string oldFolderPath = Functions.GetAttachmentFolder() + "ECN\\" + oldECNNumber.ToString();
|
||||
string newFolderPath = Functions.GetAttachmentFolder() + "ECN\\" + newECNNumber.ToString() ;
|
||||
string newFolderPath = Functions.GetAttachmentFolder() + "ECN\\" + newECNNumber.ToString();
|
||||
|
||||
DirectoryInfo newdi = new DirectoryInfo(newFolderPath);
|
||||
|
||||
|
||||
if (!newdi.Exists)
|
||||
newdi.Create();
|
||||
|
||||
|
||||
FileInfo[] existingFiles = new DirectoryInfo(oldFolderPath ).GetFiles();
|
||||
foreach (FileInfo file in existingFiles)
|
||||
{
|
||||
if (!file.Name.Contains("ECNApprovalLog_" + oldECNNumber.ToString()) && !file.Name.Contains("ECNForm_" + oldECNNumber.ToString()))
|
||||
FileInfo[] existingFiles = new DirectoryInfo(oldFolderPath).GetFiles();
|
||||
foreach (FileInfo file in existingFiles) {
|
||||
if (!file.Name.Contains("ECNApprovalLog_" + oldECNNumber.ToString()) && !file.Name.Contains("ECNForm_" + oldECNNumber.ToString()))
|
||||
//var fileName = Path.GetFileName(file.FullName);
|
||||
file.CopyTo(Path.Combine(newFolderPath, file.Name));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -132,13 +108,11 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="userID"></param>
|
||||
/// <param name="pwd"></param>
|
||||
/// <returns></returns>
|
||||
public static bool NA_ADAuthenticate(string userID, string pwd)
|
||||
{
|
||||
public static bool NA_ADAuthenticate(string userID, string pwd) {
|
||||
|
||||
string naContainer = ConfigurationManager.AppSettings["NAContainer"];
|
||||
string naDomain = ConfigurationManager.AppSettings["NADomain"];
|
||||
try
|
||||
{
|
||||
try {
|
||||
PrincipalContext contextUser = new PrincipalContext(ContextType.Domain,
|
||||
naDomain,
|
||||
naContainer,
|
||||
@ -149,12 +123,9 @@ namespace Fab2ApprovalSystem.Misc
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -163,13 +134,11 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// <param name="userID"></param>
|
||||
/// <param name="pwd"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IFX_ADAuthenticate(string userID, string pwd)
|
||||
{
|
||||
public static bool IFX_ADAuthenticate(string userID, string pwd) {
|
||||
|
||||
string container = ConfigurationManager.AppSettings["IFXContainer"];
|
||||
string domain = ConfigurationManager.AppSettings["IFXDomain"];
|
||||
try
|
||||
{
|
||||
try {
|
||||
PrincipalContext contextUser = new PrincipalContext(ContextType.Domain,
|
||||
domain,
|
||||
container,
|
||||
@ -180,18 +149,12 @@ namespace Fab2ApprovalSystem.Misc
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string FTPSPNBatch()
|
||||
{
|
||||
public static string FTPSPNBatch() {
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
return ConfigurationManager.AppSettings["FTPSPNBatchFileName"];
|
||||
}
|
||||
@ -200,8 +163,7 @@ namespace Fab2ApprovalSystem.Misc
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string FTPSPNBatch_Test()
|
||||
{
|
||||
public static string FTPSPNBatch_Test() {
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
return ConfigurationManager.AppSettings["FTPSPNBatchFileName_Test"];
|
||||
}
|
||||
@ -211,50 +173,44 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// </summary>
|
||||
/// <param name="casection"></param>
|
||||
/// <returns></returns>
|
||||
public static string CASectionMapper(GlobalVars.CASection casection)
|
||||
{
|
||||
switch (casection)
|
||||
{
|
||||
public static string CASectionMapper(GlobalVars.CASection casection) {
|
||||
switch (casection) {
|
||||
case GlobalVars.CASection.Main:
|
||||
return "Main";
|
||||
|
||||
case GlobalVars.CASection.D1:
|
||||
return "D1";
|
||||
|
||||
|
||||
case GlobalVars.CASection.D2:
|
||||
return "D2";
|
||||
|
||||
|
||||
case GlobalVars.CASection.D3:
|
||||
return "D3";
|
||||
|
||||
|
||||
case GlobalVars.CASection.D4:
|
||||
return "D4";
|
||||
|
||||
|
||||
case GlobalVars.CASection.D5:
|
||||
return "D5";
|
||||
|
||||
|
||||
case GlobalVars.CASection.D6:
|
||||
return "D6";
|
||||
|
||||
|
||||
case GlobalVars.CASection.D7:
|
||||
return "D7";
|
||||
|
||||
|
||||
case GlobalVars.CASection.D8:
|
||||
return "D8";
|
||||
case GlobalVars.CASection.CF: // CA Findings
|
||||
return "CF";
|
||||
|
||||
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string DocumentTypeMapper(GlobalVars.DocumentType docType)
|
||||
{
|
||||
switch (docType)
|
||||
{
|
||||
case GlobalVars.DocumentType.Audit:
|
||||
public static string DocumentTypeMapper(GlobalVars.DocumentType docType) {
|
||||
switch (docType) {
|
||||
case GlobalVars.DocumentType.Audit:
|
||||
return "Audit";
|
||||
case GlobalVars.DocumentType.ChangeControl:
|
||||
return "ChangeControl";
|
||||
@ -280,17 +236,15 @@ namespace Fab2ApprovalSystem.Misc
|
||||
/// </summary>
|
||||
/// <param name="caNo"></param>
|
||||
/// <returns></returns>
|
||||
public static string ReturnCANoStringFormat(int caNo)
|
||||
{
|
||||
public static string ReturnCANoStringFormat(int caNo) {
|
||||
string caNoString = "";
|
||||
if(caNo == 0)
|
||||
if (caNo == 0)
|
||||
return "";
|
||||
caNoString = "C" + caNo.ToString().PadLeft(5, '0');
|
||||
return caNoString;
|
||||
}
|
||||
|
||||
public static string ReturnAuditNoStringFormat(int auditNo)
|
||||
{
|
||||
public static string ReturnAuditNoStringFormat(int auditNo) {
|
||||
string auditNoString = "";
|
||||
if (auditNo == 0)
|
||||
return "";
|
||||
@ -298,12 +252,10 @@ namespace Fab2ApprovalSystem.Misc
|
||||
return auditNoString;
|
||||
}
|
||||
|
||||
public static string ReturnPartsRequestNoStringFormat(int PRNumber)
|
||||
{
|
||||
public static string ReturnPartsRequestNoStringFormat(int PRNumber) {
|
||||
if (PRNumber == 0)
|
||||
return "";
|
||||
return String.Format("PR{0:000000}", PRNumber);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
7
Fab2ApprovalSystem/Models/AuthAttempt.cs
Normal file
7
Fab2ApprovalSystem/Models/AuthAttempt.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Fab2ApprovalSystem.Models {
|
||||
public class AuthAttempt {
|
||||
public string LoginID { get; set; }
|
||||
public string Password { get; set; } = "";
|
||||
public AuthTokens AuthTokens { get; set; }
|
||||
}
|
||||
}
|
6
Fab2ApprovalSystem/Models/AuthTokens.cs
Normal file
6
Fab2ApprovalSystem/Models/AuthTokens.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Fab2ApprovalSystem.Models {
|
||||
public class AuthTokens {
|
||||
public string JwtToken { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
}
|
||||
}
|
6
Fab2ApprovalSystem/Models/LoginResult.cs
Normal file
6
Fab2ApprovalSystem/Models/LoginResult.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Fab2ApprovalSystem.Models {
|
||||
public class LoginResult {
|
||||
public bool IsAuthenticated { get; set; }
|
||||
public AuthTokens AuthTokens { get; set; }
|
||||
}
|
||||
}
|
@ -83,14 +83,29 @@
|
||||
@*<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", "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>
|
||||
} else {
|
||||
string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ??
|
||||
"https://localhost:7255";
|
||||
string mrbUrl = wasmClientUrl + "/redirect?redirectPath=/mrb/new";
|
||||
<li><a href="@mrbUrl">Create MRB</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", "Audit")>Create Audit</a></li>
|
||||
<li><a href=@Url.Action("Create", "CorrectiveAction")>Create Corrective Action</a></li>
|
||||
@*@if (Convert.ToBoolean(Session[GlobalVars.CAN_CREATE_PARTS_REQUEST]))
|
||||
{
|
||||
<li><a href=@Url.Action("Create", "PartsRequest")>Create New/Repair Spare Parts Request</a></li>
|
||||
}*@
|
||||
{
|
||||
<li><a href=@Url.Action("Create", "PartsRequest")>Create New/Repair Spare Parts Request</a></li>
|
||||
}*@
|
||||
@*<li><a href="#">Another Doc</a></li>*@
|
||||
</ul>
|
||||
</li>
|
||||
@ -125,6 +140,14 @@
|
||||
menu.Add().Text("My Training").Action("ViewMyTrainingAssignments", "Training");
|
||||
menu.Add().Text("Training Reports").Action("TrainingReports", "Training");
|
||||
menu.Add().Text("All Documents").Action("AllDocuments", "Home");
|
||||
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/all";
|
||||
menu.Add().Text("MRB").Url(mrbUrl);
|
||||
//menu.Add().Text("Special Work Requests").Action("SpecialWorkRequestList", "Home");
|
||||
//menu.Add().Text("PCRB").Action("ChangeControlList", "Home");
|
||||
//menu.Add().Text("MRB").Action("MRBList", "Home");
|
||||
|
@ -11,18 +11,6 @@
|
||||
<link rel="stylesheet" href="/Content/kendo/kendo.blueopal.min.css" />
|
||||
<link rel="stylesheet" href="~/Content/kendogridcustom.css" />
|
||||
|
||||
@*<link rel="stylesheet" href="~/Scripts/jqwidgets/styles/jqx.base.css" type="text/css" />
|
||||
<link rel="stylesheet" href="~/Scripts/jqwidgets/styles/jqx.energyblue.css" type="text/css" />
|
||||
<link rel="stylesheet" href="~/Scripts/jqwidgets/styles/jqx.arctic.css" type="text/css" />
|
||||
|
||||
|
||||
<script type="text/javascript" src="~/Scripts/jqwidgets/jqxcore.js"></script>
|
||||
<script type="text/javascript" src="~/Scripts/jqwidgets/jqxdata.js"></script>
|
||||
<script type="text/javascript" src="~/Scripts/jqwidgets/jqxbuttons.js"></script>
|
||||
<script type="text/javascript" src="~/Scripts/jqwidgets/jqxscrollbar.js"></script>
|
||||
<script type="text/javascript" src="~/Scripts/jqwidgets/jqxlistbox.js"></script>
|
||||
<script type="text/javascript" src="~/Scripts/jqwidgets/jqxpanel.js"></script>
|
||||
<script type="text/javascript" src="~/Scripts/jqwidgets/jqxtree.js"></script>*@
|
||||
<style>
|
||||
.k-grid .k-grid-header .k-header .k-link {
|
||||
height: auto;
|
||||
|
13
MesaFabApproval.API/.config/dotnet-tools.json
Normal file
13
MesaFabApproval.API/.config/dotnet-tools.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "8.0.6",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
20
MesaFabApproval.API/Clients/SmtpClientWrapper.cs
Normal file
20
MesaFabApproval.API/Clients/SmtpClientWrapper.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace MesaFabApproval.API.Clients;
|
||||
|
||||
public interface ISmtpClientWrapper {
|
||||
void Send(MailMessage message);
|
||||
}
|
||||
|
||||
public class SmtpClientWrapper : ISmtpClientWrapper {
|
||||
private SmtpClient _client;
|
||||
|
||||
public SmtpClientWrapper(SmtpClient client) {
|
||||
_client = client ??
|
||||
throw new ArgumentNullException("SmtpClient not injected");
|
||||
}
|
||||
|
||||
public void Send(MailMessage message) {
|
||||
_client.Send(message);
|
||||
}
|
||||
}
|
401
MesaFabApproval.API/Controllers/ApprovalController.cs
Normal file
401
MesaFabApproval.API/Controllers/ApprovalController.cs
Normal file
@ -0,0 +1,401 @@
|
||||
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 ApprovalController : ControllerBase {
|
||||
private readonly ILogger<ApprovalController> _logger;
|
||||
private readonly IApprovalService _approvalService;
|
||||
private readonly IMonInWorkerClient _monInClient;
|
||||
|
||||
public ApprovalController(ILogger<ApprovalController> logger, IApprovalService approvalService,
|
||||
IMonInWorkerClient monInClient) {
|
||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||
_approvalService = approvalService ?? throw new ArgumentNullException("IApprovalService not injected");
|
||||
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("approval")]
|
||||
public async Task<IActionResult> CreateApproval(Approval approval) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate a new approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException("Approval cannot be null");
|
||||
|
||||
await _approvalService.CreateApproval(approval);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot create new approval, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "CreateApproval";
|
||||
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]
|
||||
[Route("approval/issue")]
|
||||
public async Task<IActionResult> GetApprovalsForIssueId(int issueId, bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get approvals for issue {issueId}");
|
||||
|
||||
if (issueId <= 0) throw new ArgumentException($"{issueId} is not a valid issue ID");
|
||||
|
||||
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(issueId, bypassCache);
|
||||
|
||||
return Ok(approvals);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get approvals, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetApprovalsForIssueId";
|
||||
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]
|
||||
[Route("approval/user")]
|
||||
public async Task<IActionResult> GetApprovalsForUserId(int userId, bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get approvals for user ID {userId}");
|
||||
|
||||
if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID");
|
||||
|
||||
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForUserId(userId, bypassCache);
|
||||
|
||||
return Ok(approvals);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get approvals, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetApprovalsForUserId";
|
||||
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]
|
||||
[Route("approval/members")]
|
||||
public async Task<IActionResult> GetApprovalGroupMembers(int subRoleId) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get approval group members for group {subRoleId}");
|
||||
|
||||
if (subRoleId <= 0) throw new ArgumentException($"{subRoleId} is not a valid sub role ID");
|
||||
|
||||
IEnumerable<User> members = await _approvalService.GetApprovalGroupMembers(subRoleId);
|
||||
|
||||
return Ok(members);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get approval group members, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetApprovalsGroupMembers";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("approval")]
|
||||
public async Task<IActionResult> UpdateApproval(Approval approval) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to update approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException($"approval cannot be null");
|
||||
|
||||
await _approvalService.UpdateApproval(approval);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot update approval, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "UpdateApproval";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("approval/approve")]
|
||||
public async Task<IActionResult> Approve(Approval approval) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"attempting to submit approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException($"approval cannot be null");
|
||||
|
||||
await _approvalService.Approve(approval);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot approve, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "Approve";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("approval/deny")]
|
||||
public async Task<IActionResult> Deny(Approval approval) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"attempting to deny approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException($"approval cannot be null");
|
||||
|
||||
await _approvalService.Deny(approval);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Approval denial failed, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "Deny";
|
||||
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]
|
||||
[Route("approval/roleId")]
|
||||
public async Task<IActionResult> GetRoleIdForRoleName(string roleName) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get role ID by role name");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("role name cannot be null or empty");
|
||||
|
||||
int roleId = await _approvalService.GetRoleIdForRoleName(roleName);
|
||||
|
||||
return Ok(roleId);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get role ID, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetRoleIdForRoleName";
|
||||
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]
|
||||
[Route("approval/subRoles")]
|
||||
public async Task<IActionResult> GetSubRolesForSubRoleName(string subRoleName, int roleId) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get sub roles by sub role name");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(subRoleName)) throw new ArgumentException("sub role name cannot be null or empty");
|
||||
if (roleId <= 0) throw new ArgumentException($"{roleId} is not a valid role ID");
|
||||
|
||||
IEnumerable<SubRole> subRoles = await _approvalService.GetSubRolesForSubRoleName(subRoleName, roleId);
|
||||
|
||||
return Ok(subRoles);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get role ID, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetSubRoleIdForSubRoleName";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
178
MesaFabApproval.API/Controllers/AuthenticationController.cs
Normal file
178
MesaFabApproval.API/Controllers/AuthenticationController.cs
Normal file
@ -0,0 +1,178 @@
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Principal;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
using MesaFabApproval.Shared.Services;
|
||||
|
||||
using MesaFabApprovalAPI.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace MesaFabApproval.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[AllowAnonymous]
|
||||
public class AuthenticationController : ControllerBase {
|
||||
private readonly ILogger<AuthenticationController> _logger;
|
||||
private readonly IMonInWorkerClient _monInClient;
|
||||
private readonly IAuthenticationService _authenticationService;
|
||||
|
||||
public AuthenticationController(ILogger<AuthenticationController> logger,
|
||||
IMonInWorkerClient monInClient,
|
||||
IAuthenticationService authenticationService) {
|
||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||
_authenticationService = authenticationService ??
|
||||
throw new ArgumentNullException("IAuthenticationService not injected");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("auth/login")]
|
||||
public async Task<IActionResult> Login(AuthAttempt login) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to perform authentication");
|
||||
|
||||
if (login is null) throw new ArgumentNullException("Login cannot be null");
|
||||
|
||||
LoginResult loginResult = await _authenticationService.AuthenticateUser(login);
|
||||
|
||||
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 user, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "Login";
|
||||
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/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")]
|
||||
public async Task<IActionResult> Refresh(AuthAttempt authAttempt) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to refresh auth tokens");
|
||||
|
||||
if (authAttempt is null) throw new ArgumentNullException("AuthAttempt cannot be null");
|
||||
if (authAttempt.AuthTokens is null) throw new ArgumentNullException("AuthTokens cannot be null");
|
||||
|
||||
LoginResult loginResult = await _authenticationService.RefreshAuthTokens(authAttempt);
|
||||
|
||||
return Ok(loginResult);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = $"Invalid argument. {ex.Message}";
|
||||
return BadRequest(errorMessage);
|
||||
} catch (AuthenticationException ex) {
|
||||
_logger.LogInformation($"Unable to refresh tokens, because {ex.Message}");
|
||||
return Unauthorized();
|
||||
} catch (Exception ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = $"Cannot authenticate user, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "RefreshTokens";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
910
MesaFabApproval.API/Controllers/MRBController.cs
Normal file
910
MesaFabApproval.API/Controllers/MRBController.cs
Normal file
@ -0,0 +1,910 @@
|
||||
using MesaFabApproval.API.Services;
|
||||
using MesaFabApproval.Shared.Models;
|
||||
using MesaFabApproval.Shared.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
|
||||
namespace MesaFabApproval.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class MRBController : ControllerBase {
|
||||
private readonly ILogger<MRBController> _logger;
|
||||
private readonly IMRBService _mrbService;
|
||||
private readonly IMonInWorkerClient _monInClient;
|
||||
|
||||
public MRBController(ILogger<MRBController> logger, IMRBService mrbService, IMonInWorkerClient monInClient) {
|
||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||
_mrbService = mrbService ?? throw new ArgumentNullException("IMRBService not injected");
|
||||
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("mrb/new")]
|
||||
public async Task<IActionResult> CreateNewMRB(MRB mrb) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate a new MRB");
|
||||
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
await _mrbService.CreateNewMRB(mrb);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot create new MRB, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "CreateNewMRB";
|
||||
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]
|
||||
[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]
|
||||
[Route("mrb/all")]
|
||||
public async Task<IActionResult> GetAllMRBs(bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get all MRBs");
|
||||
|
||||
IEnumerable<MRB> allMrbs = await _mrbService.GetAllMRBs(bypassCache);
|
||||
|
||||
return Ok(allMrbs);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get all MRBs, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetAllMRBs";
|
||||
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]
|
||||
[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]
|
||||
[Route("mrb/getById")]
|
||||
public async Task<IActionResult> GetMRBById(int id, bool bypassCache = false) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get an MRB by Id");
|
||||
|
||||
if (id <= 0) throw new ArgumentException("Invalid MRB number");
|
||||
|
||||
MRB mrb = await _mrbService.GetMRBById(id, bypassCache);
|
||||
|
||||
return Ok(mrb);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get MRB by Id, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetMRBbyId";
|
||||
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]
|
||||
[Route("mrb/getByTitle")]
|
||||
public async Task<IActionResult> GetMRBByTitle(string title, bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get an MRB by Title");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||
|
||||
MRB mrb = await _mrbService.GetMRBByTitle(title, bypassCache);
|
||||
|
||||
return Ok(mrb);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get MRB by title, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetMRBbyTitle";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("mrb")]
|
||||
public async Task<IActionResult> UpdateMRB(MRB mrb) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to update an MRB");
|
||||
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
await _mrbService.UpdateMRB(mrb);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot update MRB, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "UpdateMRB";
|
||||
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("mrbAction")]
|
||||
public async Task<IActionResult> CreateMRBAction(MRBAction mrbAction) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate a new MRB");
|
||||
|
||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||
|
||||
await _mrbService.CreateMRBAction(mrbAction);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot create new MRB action, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "CreateNewMRBAction";
|
||||
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]
|
||||
[Route("mrbAction")]
|
||||
public async Task<IActionResult> GetMRBActionsForMRB(int mrbNumber, bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get all MRBs");
|
||||
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
IEnumerable<MRBAction> mrbActions = await _mrbService.GetMRBActionsForMRB(mrbNumber, bypassCache);
|
||||
|
||||
return Ok(mrbActions);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get all MRBs, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetMRBActionsForMRB";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("mrbAction")]
|
||||
public async Task<IActionResult> UpdateMRBAction(MRBAction mrbAction) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to update an MRB action");
|
||||
|
||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||
|
||||
await _mrbService.UpdateMRBAction(mrbAction);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot update MRB action, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "UpdateMRBAction";
|
||||
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]
|
||||
[Route("mrbAction")]
|
||||
public async Task<IActionResult> DeleteMRBAction(int mrbActionID, int mrbNumber) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to delete MRB action {mrbActionID}");
|
||||
|
||||
if (mrbActionID <= 0) throw new ArgumentException($"{mrbActionID} is not a valid MRB ActionID");
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRBNumber");
|
||||
|
||||
await _mrbService.DeleteMRBAction(mrbActionID, mrbNumber);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot delete MRB action, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "DeleteMRBAction";
|
||||
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]
|
||||
[Route("mrb/attachments")]
|
||||
public async Task<IActionResult> GetAttachmentsForMRB(int mrbNumber, bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get MRB attachments for MRB {mrbNumber}");
|
||||
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
List<MRBAttachment> attachments = (await _mrbService.GetAllAttachmentsForMRB(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 attachments for MRB {mrbNumber}, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetMRBAttachments";
|
||||
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]
|
||||
[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]
|
||||
[Route("mrb/attach")]
|
||||
public async Task<IActionResult> SaveMRBAttachment([FromForm] IEnumerable<IFormFile> files, int mrbNumber) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to save MRB attachments");
|
||||
|
||||
if (files is null) throw new ArgumentNullException("Files cannot be null");
|
||||
if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty");
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
IEnumerable<UploadResult> uploadResults = (await _mrbService.UploadAttachments(files, mrbNumber)).ToList();
|
||||
|
||||
return Ok(uploadResults);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot save MRB attachments, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "SaveMRBAttachments";
|
||||
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("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]
|
||||
[HttpGet]
|
||||
[Route("mrb/attachmentFile")]
|
||||
public async Task<IActionResult> GetMRBAttachmentFile(string path, string fileName) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get MRB attachment file");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty");
|
||||
if (!System.IO.File.Exists(path)) throw new ArgumentException("No file exists at provided path");
|
||||
if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentException("Filename cannot be null or empty");
|
||||
|
||||
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 = fileName
|
||||
};
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get MRB attachment file, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetMRBAttachmentFile";
|
||||
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]
|
||||
[Route("mrb/attach")]
|
||||
public async Task<IActionResult> DeleteMRBAttachment(MRBAttachment attachment) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to delete MRB attachment");
|
||||
|
||||
if (attachment is null) throw new ArgumentNullException("Attachment cannot be null");
|
||||
|
||||
await _mrbService.DeleteAttachment(attachment);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get MRB attachment file, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "DeleteMRBAttachment";
|
||||
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("mrb/notify/new-approvals")]
|
||||
public async Task<IActionResult> NotifyNewApprovals(MRB mrb) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to notify new approvers");
|
||||
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
await _mrbService.NotifyNewApprovals(mrb);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Unable to notify new approvers, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "NotifyNewMRBApprovers";
|
||||
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("mrb/notify/approvers")]
|
||||
public async Task<IActionResult> NotifyApprovers(MRBNotification notification) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to notify approvers");
|
||||
|
||||
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");
|
||||
|
||||
await _mrbService.NotifyApprovers(notification);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Unable to notify approvers, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "NotifyMRBApprovers";
|
||||
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("mrb/notify/originator")]
|
||||
public async Task<IActionResult> NotifyOriginator(MRBNotification notification) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to notify originator");
|
||||
|
||||
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.NotifyOriginator(notification);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Unable to notify originator, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "NotifyMRBOriginator";
|
||||
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("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
264
MesaFabApproval.API/Controllers/PCRBController.cs
Normal file
264
MesaFabApproval.API/Controllers/PCRBController.cs
Normal file
@ -0,0 +1,264 @@
|
||||
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 PCRBController : ControllerBase {
|
||||
private readonly ILogger<MRBController> _logger;
|
||||
private readonly IPCRBService _pcrbService;
|
||||
private readonly IMonInWorkerClient _monInClient;
|
||||
|
||||
public PCRBController(ILogger<MRBController> logger, IPCRBService pcrbService, IMonInWorkerClient monInClient) {
|
||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||
_pcrbService = pcrbService ?? throw new ArgumentNullException("IPCRBService not injected");
|
||||
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("pcrb")]
|
||||
public async Task<IActionResult> CreateNewPCRB(PCRB pcrb) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate a new PCRB");
|
||||
|
||||
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||
|
||||
await _pcrbService.CreateNewPCRB(pcrb);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot create new PCRB, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "CreateNewPCRB";
|
||||
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]
|
||||
[Route("pcrb/all")]
|
||||
public async Task<IActionResult> GetAllPCRBs(bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get all PCRBs");
|
||||
|
||||
IEnumerable<PCRB> allPCRBs = await _pcrbService.GetAllPCRBs(bypassCache);
|
||||
|
||||
return Ok(allPCRBs);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get all PCRBs, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetAllPCRBs";
|
||||
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]
|
||||
[Route("pcrb/getByTitle")]
|
||||
public async Task<IActionResult> GetPCRBByTitle(string title, bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get an PCRB by Title");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||
|
||||
PCRB pcrb = await _pcrbService.GetPCRBByTitle(title, bypassCache);
|
||||
|
||||
return Ok(pcrb);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get PCRB by title, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetPCRBbyTitle";
|
||||
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]
|
||||
[Route("pcrb/getByPlanNumber")]
|
||||
public async Task<IActionResult> GetPCRBByPlanNumber(int planNumber, bool bypassCache) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get an PCRB by Title");
|
||||
|
||||
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan #");
|
||||
|
||||
PCRB pcrb = await _pcrbService.GetPCRBByPlanNumber(planNumber, bypassCache);
|
||||
|
||||
return Ok(pcrb);
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get PCRB by plan number, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetPCRBbyPlanNumber";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("pcrb")]
|
||||
public async Task<IActionResult> UpdatePCRB(PCRB pcrb) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to update a PCRB");
|
||||
|
||||
if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null");
|
||||
|
||||
await _pcrbService.UpdatePCRB(pcrb);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot update PCRB, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "UpdatePCRB";
|
||||
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]
|
||||
[Route("pcrb")]
|
||||
public async Task<IActionResult> DeletePCRB(int planNumber) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to delete PCRB# {planNumber}");
|
||||
|
||||
if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan #");
|
||||
|
||||
await _pcrbService.DeletePCRB(planNumber);
|
||||
|
||||
return Ok();
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = ex.Message;
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot delete PCRB# {planNumber}, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "DeletePCRB";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
223
MesaFabApproval.API/Controllers/UserController.cs
Normal file
223
MesaFabApproval.API/Controllers/UserController.cs
Normal file
@ -0,0 +1,223 @@
|
||||
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]
|
||||
public class UserController : ControllerBase {
|
||||
private readonly ILogger<UserController> _logger;
|
||||
private readonly IMonInWorkerClient _monInClient;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public UserController(ILogger<UserController> logger,
|
||||
IMonInWorkerClient monInClient,
|
||||
IMemoryCache cache,
|
||||
IUserService userService) {
|
||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||
_monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected");
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("/user/loginId")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> GetUserByLoginId(string loginId) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get user by LoginID");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(loginId))
|
||||
throw new ArgumentException("LoginID cannot be null or empty");
|
||||
|
||||
User? user = _cache.Get<User>($"user{loginId}");
|
||||
|
||||
if (user is null) {
|
||||
user = await _userService.GetUserByLoginId(loginId);
|
||||
|
||||
_cache.Set($"user{loginId}", user, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
if (user is not null) return Ok(user);
|
||||
|
||||
throw new Exception($"User with LoginID {loginId} not found");
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = $"Invalid argument. {ex.Message}";
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get user by LoginID, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetUserByLoginId";
|
||||
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]
|
||||
[Route("/user/userId")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> GetUserByUserId(int userId) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get user by LoginID");
|
||||
|
||||
if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID");
|
||||
|
||||
User? user = _cache.Get<User>($"user{userId}");
|
||||
|
||||
if (user is null) {
|
||||
user = await _userService.GetUserByUserId(userId);
|
||||
|
||||
_cache.Set($"user{userId}", user, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
if (user is not null) return Ok(user);
|
||||
|
||||
throw new Exception($"User with UserID {userId} not found");
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = $"Invalid argument. {ex.Message}";
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get user by User ID, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetUserByUserId";
|
||||
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]
|
||||
[Route("/users/active")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> GetAllActiveUsers() {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get all active users");
|
||||
|
||||
IEnumerable<User>? activeUsers = _cache.Get<IEnumerable<User>>($"activeUsers");
|
||||
|
||||
if (activeUsers is null) {
|
||||
activeUsers = await _userService.GetAllActiveUsers();
|
||||
|
||||
_cache.Set($"activeUsers", activeUsers, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
if (activeUsers is not null) return Ok(activeUsers);
|
||||
|
||||
throw new Exception($"No active users found");
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get all active users, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetAllActiveUsers";
|
||||
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]
|
||||
[Route("/approver")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> GetApproverUserIdsForSubRoleCategoryItem(string subRoleCategoryItem) {
|
||||
DateTime start = DateTime.Now;
|
||||
bool isArgumentError = false;
|
||||
bool isInternalError = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get approver user IDs");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(subRoleCategoryItem))
|
||||
throw new ArgumentException("SubRoleCategoryItem cannot be null or empty");
|
||||
|
||||
IEnumerable<int>? approverUserIds = _cache.Get<IEnumerable<int>>($"approvers{subRoleCategoryItem}");
|
||||
|
||||
if (approverUserIds is null) {
|
||||
approverUserIds = await _userService.GetApproverUserIdsBySubRoleCategoryItem(subRoleCategoryItem);
|
||||
|
||||
_cache.Set($"approvers{subRoleCategoryItem}", approverUserIds, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
if (approverUserIds is not null) return Ok(approverUserIds);
|
||||
|
||||
throw new Exception($"Approvers for SubRoleCategoryItem {subRoleCategoryItem} not found");
|
||||
} catch (ArgumentException ex) {
|
||||
isArgumentError = true;
|
||||
errorMessage = $"Invalid argument. {ex.Message}";
|
||||
return BadRequest(errorMessage);
|
||||
} catch (Exception ex) {
|
||||
isInternalError = true;
|
||||
errorMessage = $"Cannot get approver user IDs, because {ex.Message}";
|
||||
return Problem(errorMessage);
|
||||
} finally {
|
||||
string metricName = "GetApproverUserIds";
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
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}")]
|
32
MesaFabApproval.API/MesaFabApproval.API.csproj
Normal file
32
MesaFabApproval.API/MesaFabApproval.API.csproj
Normal file
@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.35" />
|
||||
<PackageReference Include="Dapper.Contrib" Version="2.0.78" />
|
||||
<PackageReference Include="dotenv.net" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||
<PackageReference Include="NLog" Version="5.3.3" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.12" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.0" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MesaFabApproval.Shared\MesaFabApproval.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.DirectoryServices.AccountManagement">
|
||||
<HintPath>..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.DirectoryServices.AccountManagement.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
145
MesaFabApproval.API/Program.cs
Normal file
145
MesaFabApproval.API/Program.cs
Normal file
@ -0,0 +1,145 @@
|
||||
using MesaFabApproval.Shared.Services;
|
||||
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 Microsoft.AspNetCore.HttpLogging;
|
||||
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
DotEnv.Load();
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.SetMinimumLevel(LogLevel.Trace);
|
||||
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();
|
||||
|
||||
string jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer") ??
|
||||
throw new ArgumentNullException("FabApprovalJwtIssuer environment variable not found");
|
||||
string jwtAudience = Environment.GetEnvironmentVariable("FabApprovalJwtAudience") ??
|
||||
throw new ArgumentNullException("FabApprovalJwtAudience environment variable not found");
|
||||
string jwtKey = Environment.GetEnvironmentVariable("FabApprovalJwtKey") ??
|
||||
throw new ArgumentNullException("FabApprovalJwtKey environment variable not found");
|
||||
|
||||
builder.Services.AddAuthentication(options => {
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(options => {
|
||||
options.RequireHttpsMetadata = false;
|
||||
options.SaveToken = true;
|
||||
options.TokenValidationParameters = new TokenValidationParameters {
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = jwtIssuer,
|
||||
ValidateAudience = false,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)),
|
||||
ClockSkew = TimeSpan.Zero
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options => {
|
||||
options.DefaultPolicy = new AuthorizationPolicyBuilder()
|
||||
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
});
|
||||
|
||||
builder.Services.AddHttpClient();
|
||||
|
||||
builder.Services.AddCors(options => {
|
||||
options.AddDefaultPolicy(options => {
|
||||
options.AllowAnyOrigin();
|
||||
options.AllowAnyMethod();
|
||||
options.AllowAnyHeader();
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<IDbConnectionService, DbConnectionService>();
|
||||
builder.Services.AddScoped<IDalService, DalService>();
|
||||
builder.Services.AddScoped<SmtpClient>((serviceProvider) => {
|
||||
return new SmtpClient("mailrelay-external.infineon.com");
|
||||
});
|
||||
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<IUserService, UserService>();
|
||||
builder.Services.AddScoped<IMonInWorkerClient, MonInWorkerClient>();
|
||||
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
||||
builder.Services.AddScoped<IMRBService, MRBService>();
|
||||
builder.Services.AddScoped<IPCRBService, PCRBService>();
|
||||
builder.Services.AddScoped<IApprovalService, ApprovalService>();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
#if DEBUG
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(c => {
|
||||
c.SwaggerDoc("v1", new OpenApiInfo {
|
||||
Title = "Mesa Fab Approval API",
|
||||
Version = "v1"
|
||||
});
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Please insert JWT with Bearer into field",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey
|
||||
});
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
new string[] { }
|
||||
}
|
||||
});
|
||||
});
|
||||
#endif
|
||||
|
||||
WebApplication app = builder.Build();
|
||||
|
||||
app.UseCors();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
// app.UseHttpLogging();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
||||
NLog.LogManager.Flush();
|
||||
NLog.LogManager.Shutdown();
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<DeleteExistingFiles>true</DeleteExistingFiles>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<PublishProvider>FileSystem</PublishProvider>
|
||||
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<ProjectGuid>852e528d-015a-43b5-999d-f281e3359e5e</ProjectGuid>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishReadyToRun>true</PublishReadyToRun>
|
||||
</PropertyGroup>
|
||||
</Project>
|
320
MesaFabApproval.API/Services/ApprovalService.cs
Normal file
320
MesaFabApproval.API/Services/ApprovalService.cs
Normal file
@ -0,0 +1,320 @@
|
||||
using System.Text;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
using MesaFabApproval.Shared.Utilities;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace MesaFabApproval.API.Services;
|
||||
|
||||
public interface IApprovalService {
|
||||
Task<int> GetRoleIdForRoleName(string roleName);
|
||||
Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId);
|
||||
Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId);
|
||||
Task CreateApproval(Approval approval);
|
||||
Task UpdateApproval(Approval approval);
|
||||
Task Approve(Approval approval);
|
||||
Task Deny(Approval approval);
|
||||
Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache);
|
||||
Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache);
|
||||
}
|
||||
|
||||
public class ApprovalService : IApprovalService {
|
||||
private readonly ILogger<ApprovalService> _logger;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IDalService _dalService;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public ApprovalService(ILogger<ApprovalService> logger, IMemoryCache cache, IDalService dalService, IUserService userService) {
|
||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_dalService = dalService ?? throw new ArgumentNullException("IDalService not injected");
|
||||
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
||||
}
|
||||
|
||||
public async Task CreateApproval(Approval approval) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate new Approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException("Approval cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("insert into Approval (IssueID, RoleName, SubRole, UserID, SubRoleID, ItemStatus, ");
|
||||
queryBuilder.Append("AssignedDate, DocumentTypeID, DisplayDeniedDocument, Step, TaskID) ");
|
||||
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($"3, 0, {approval.Step}, {approval.TaskID});");
|
||||
|
||||
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsCreated <= 0) throw new Exception("Unable to insert approval in database");
|
||||
|
||||
await GetApprovalsForIssueId(approval.IssueID, true);
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to create new Approval. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get all approvals for issue {issueId}");
|
||||
|
||||
if (issueId <= 0) throw new ArgumentException($"{issueId} is not a valid issue ID");
|
||||
|
||||
IEnumerable<Approval>? approvals = new List<Approval>();
|
||||
|
||||
if (!bypassCache)
|
||||
approvals = _cache.Get<IEnumerable<Approval>>($"approvals{issueId}");
|
||||
|
||||
if (approvals is null || approvals.Count() == 0) {
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("select a.*, src.SubRoleCategoryItem from Approval a ");
|
||||
queryBuilder.Append("join SubRole sr on a.SubRoleID=sr.SubRoleID ");
|
||||
queryBuilder.Append("join SubRoleCategory src on sr.SubRoleCategoryID=src.SubRoleCategoryID ");
|
||||
queryBuilder.Append($"where a.IssueID={issueId}");
|
||||
|
||||
approvals = (await _dalService.QueryAsync<Approval>(queryBuilder.ToString())).ToList();
|
||||
|
||||
foreach (Approval approval in approvals) {
|
||||
int successfulUpdates = 0;
|
||||
|
||||
User? user = await _userService.GetUserByUserId(approval.UserID);
|
||||
if (user is not null) {
|
||||
approval.User = user;
|
||||
successfulUpdates++;
|
||||
}
|
||||
|
||||
if (approval.ItemStatus < 0)
|
||||
approval.StatusMessage = "Denied";
|
||||
if (approval.ItemStatus == 0)
|
||||
approval.StatusMessage = "Assigned";
|
||||
if (approval.ItemStatus > 0)
|
||||
approval.StatusMessage = "Approved";
|
||||
}
|
||||
|
||||
_cache.Set($"approvals{issueId}", approvals, DateTimeOffset.Now.AddMinutes(5));
|
||||
}
|
||||
|
||||
return approvals;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Unable to fetch approvals for issue {issueId}, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GetRoleIdForRoleName(string roleName) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get role ID by name");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
throw new ArgumentException("Role name cannot be null or empty");
|
||||
|
||||
int roleId = _cache.Get<int>($"role{roleName}");
|
||||
|
||||
if (roleId <= 0) {
|
||||
string sql = $"select RoleID from Role where RoleName = '{roleName}'";
|
||||
|
||||
roleId = (await _dalService.QueryAsync<int>(sql)).ToList().FirstOrDefault();
|
||||
|
||||
if (roleId > 0)
|
||||
_cache.Set($"role{roleName}", roleId, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
if (roleId <= 0)
|
||||
throw new Exception($"Unable to find role with name {roleName}");
|
||||
|
||||
return roleId;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Unable to find role ID, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get sub role ID by name for role ID {roleId}");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(subRoleName))
|
||||
throw new ArgumentException("sub role name cannot be null or empty");
|
||||
if (roleId <= 0) throw new ArgumentException($"{roleId} is not a valid role ID");
|
||||
|
||||
IEnumerable<SubRole>? subRoles = _cache.Get<IEnumerable<SubRole>>($"subRoles{subRoleName}");
|
||||
|
||||
if (subRoles is null || subRoles.Count() <= 0) {
|
||||
StringBuilder queryBuilder = new();
|
||||
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($"where sr.RoleID={roleId} and sr.SubRole='{subRoleName}'");
|
||||
|
||||
subRoles = (await _dalService.QueryAsync<SubRole>(queryBuilder.ToString())).ToList();
|
||||
|
||||
if (subRoles is not null && subRoles.Count() > 0)
|
||||
_cache.Set($"subRole{subRoleName}", subRoles, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
if (subRoles is null || subRoles.Count() <= 0)
|
||||
throw new Exception($"Unable to find sub role with name {subRoleName} for role {roleId}");
|
||||
|
||||
return subRoles;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Unable to find sub roles, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get members of sub role {subRoleId}");
|
||||
|
||||
if (subRoleId <= 0) throw new ArgumentException($"{subRoleId} is not a valid sub role ID");
|
||||
|
||||
List<User>? members = _cache.Get<List<User>>($"approvalMembers{subRoleId}");
|
||||
|
||||
if (members is null || members.Count() <= 0) {
|
||||
IEnumerable<int>? memberIds = _cache.Get<IEnumerable<int>>($"approvalMemberIds{subRoleId}");
|
||||
|
||||
if (memberIds is null) {
|
||||
string sql = $"select UserID from UserSubRole where SubRoleID = {subRoleId};";
|
||||
|
||||
memberIds = await _dalService.QueryAsync<int>(sql);
|
||||
|
||||
if (memberIds is null || memberIds.Count() <= 0)
|
||||
throw new Exception($"No members found in sub role {subRoleId}");
|
||||
|
||||
_cache.Set($"approvalMemberIds{subRoleId}", memberIds, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
members = new();
|
||||
foreach (int id in memberIds) {
|
||||
User member = await _userService.GetUserByUserId(id);
|
||||
|
||||
members.Add(member);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
return members;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Unable to get sub role {subRoleId} members, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get approvals for user ID {userId}");
|
||||
|
||||
if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID");
|
||||
|
||||
IEnumerable<Approval>? approvals = null;
|
||||
|
||||
if (!bypassCache) approvals = _cache.Get<IEnumerable<Approval>>($"approvalMembers{userId}");
|
||||
|
||||
if (approvals is null) {
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append($"select a.*, src.SubRoleCategoryItem from Approval a ");
|
||||
queryBuilder.Append("join SubRole sr on a.SubRoleID=sr.SubRoleID ");
|
||||
queryBuilder.Append("join SubRoleCategory src on sr.SubRoleCategoryID=src.SubRoleCategoryID ");
|
||||
queryBuilder.Append($"where UserID={userId} and ");
|
||||
queryBuilder.Append($"((CompletedDate >= '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}') or ");
|
||||
queryBuilder.Append($"(CompletedDate is null));");
|
||||
string sql = queryBuilder.ToString();
|
||||
|
||||
approvals = (await _dalService.QueryAsync<Approval>(sql)).ToList();
|
||||
|
||||
_cache.Set($"approvalMembers{userId}", approvals, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
return approvals;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Unable to get approvals for user ID {userId}, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateApproval(Approval approval) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to update an approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException("Approval cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
||||
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
||||
queryBuilder.Append($"ItemStatus={Convert.ToInt32(approval.ItemStatus)}, Step={approval.Step}, ");
|
||||
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($"CompletedDate='{approval.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
queryBuilder.Append($"Comments='{approval.Comments}', ");
|
||||
queryBuilder.Append($"TaskID={approval.TaskID} ");
|
||||
queryBuilder.Append($"where ApprovalID={approval.ApprovalID};");
|
||||
|
||||
int rowsUpdated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsUpdated <= 0) throw new Exception("Unable to update approval in database");
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Approval update failed, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Approve(Approval approval) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to submit approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException("Approval cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
||||
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
||||
queryBuilder.Append($"ItemStatus=1, Step={approval.Step}, ");
|
||||
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($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
queryBuilder.Append($"Comments='{approval.Comments}', ");
|
||||
queryBuilder.Append($"TaskID={approval.TaskID} ");
|
||||
queryBuilder.Append($"where ApprovalID={approval.ApprovalID};");
|
||||
|
||||
int rowsUpdated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsUpdated <= 0) throw new Exception("Unable to submit approval in database");
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Approval failed, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Deny(Approval approval) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to deny approval");
|
||||
|
||||
if (approval is null) throw new ArgumentNullException("Approval cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', ");
|
||||
queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, ");
|
||||
queryBuilder.Append($"ItemStatus=-1, Step={approval.Step}, ");
|
||||
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($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
queryBuilder.Append($"Comments='{approval.Comments}', ");
|
||||
queryBuilder.Append($"TaskID={approval.TaskID} ");
|
||||
queryBuilder.Append($"where ApprovalID={approval.ApprovalID};");
|
||||
|
||||
int rowsUpdated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsUpdated <= 0) throw new Exception("Unable to deny approval in database");
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Approval denial failed, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
254
MesaFabApproval.API/Services/AuthenticationService.cs
Normal file
254
MesaFabApproval.API/Services/AuthenticationService.cs
Normal file
@ -0,0 +1,254 @@
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
|
||||
using MesaFabApproval.API.Services;
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace MesaFabApprovalAPI.Services;
|
||||
|
||||
public interface IAuthenticationService {
|
||||
public Task<LoginResult> AuthenticateUser(AuthAttempt login);
|
||||
public Task<LoginResult> AttemptLocalUserAuth(WindowsIdentity identity);
|
||||
public AuthTokens GenerateAuthTokens(AuthAttempt authAttempt, IEnumerable<string> roles);
|
||||
public Task<LoginResult> RefreshAuthTokens(AuthAttempt authAttempt);
|
||||
}
|
||||
|
||||
public class AuthenticationService : IAuthenticationService {
|
||||
private readonly ILogger<AuthenticationService> _logger;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
private readonly string _jwtIssuer;
|
||||
private readonly string _jwtAudience;
|
||||
private readonly string _jwtKey;
|
||||
|
||||
public AuthenticationService(ILogger<AuthenticationService> logger, IMemoryCache cache, IUserService userService) {
|
||||
_logger = logger ?? throw new ArgumentNullException("ILogger not injected");
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_userService = userService ?? throw new ArgumentNullException("IUserService not injected");
|
||||
|
||||
_jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer") ??
|
||||
throw new ArgumentNullException("FabApprovalJwtIssuer environment variable not found");
|
||||
_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) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to authenticate user");
|
||||
|
||||
if (login is null) throw new ArgumentNullException("Login cannot be null");
|
||||
|
||||
string domain = "infineon.com";
|
||||
|
||||
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain)) {
|
||||
bool isValid = pc.ValidateCredentials(login.LoginID, login.Password);
|
||||
|
||||
if (isValid) {
|
||||
User? user = _cache.Get<User>($"user{login.LoginID}");
|
||||
|
||||
if (user is null) {
|
||||
user = await _userService.GetUserByLoginId(login.LoginID);
|
||||
|
||||
_cache.Set<User>($"user{login.LoginID}", user, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
List<string> roles = new();
|
||||
|
||||
if (user.IsManager) roles.Add("manager");
|
||||
if (user.IsAdmin) roles.Add("admin");
|
||||
|
||||
AuthTokens tokens = GenerateAuthTokens(login, roles);
|
||||
|
||||
return new LoginResult {
|
||||
IsAuthenticated = true,
|
||||
AuthTokens = tokens,
|
||||
User = user
|
||||
};
|
||||
} else {
|
||||
return new LoginResult() {
|
||||
IsAuthenticated= false,
|
||||
AuthTokens = new() {
|
||||
JwtToken = "",
|
||||
RefreshToken = ""
|
||||
},
|
||||
User = null
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to authenticate user. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate JWT");
|
||||
|
||||
if (authAttempt is null) throw new ArgumentNullException("AuthAttempt cannot be null");
|
||||
if (string.IsNullOrWhiteSpace(authAttempt.LoginID)) throw new ArgumentException("UserName cannot be null or empty");
|
||||
if (roles is null) throw new ArgumentNullException("roles cannot be null");
|
||||
|
||||
byte[] key = Encoding.ASCII.GetBytes(_jwtKey);
|
||||
|
||||
List<Claim> claims = new() {
|
||||
new Claim(nameof(authAttempt.LoginID), authAttempt.LoginID)
|
||||
};
|
||||
|
||||
foreach (string role in roles) {
|
||||
claims.Add(new Claim(ClaimTypes.Role, role));
|
||||
}
|
||||
|
||||
ClaimsIdentity identity = new ClaimsIdentity(claims);
|
||||
|
||||
SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor {
|
||||
Issuer = _jwtIssuer,
|
||||
Audience = _jwtAudience,
|
||||
Subject = identity,
|
||||
NotBefore = DateTime.Now,
|
||||
Expires = DateTime.Now.AddHours(2),
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
|
||||
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
||||
JwtSecurityToken token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
|
||||
|
||||
string jwt = tokenHandler.WriteToken(token);
|
||||
|
||||
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 {
|
||||
JwtToken = jwt,
|
||||
RefreshToken = refreshToken
|
||||
};
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to generate JWT. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<LoginResult> RefreshAuthTokens(AuthAttempt authAttempt) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to refresh auth tokens");
|
||||
|
||||
if (authAttempt is null) throw new ArgumentNullException("AuthAttempt cannot be null");
|
||||
if (authAttempt.AuthTokens is null) throw new ArgumentNullException("AuthTokens cannot be null");
|
||||
|
||||
bool refreshTokenIsValid = IsRefreshTokenValid(authAttempt.LoginID, authAttempt.AuthTokens.RefreshToken);
|
||||
|
||||
if (refreshTokenIsValid) {
|
||||
User? user = _cache.Get<User>($"user{authAttempt.LoginID}");
|
||||
|
||||
if (user is null) {
|
||||
user = await _userService.GetUserByLoginId(authAttempt.LoginID);
|
||||
|
||||
_cache.Set<User>($"user{authAttempt.LoginID}", user, DateTimeOffset.Now.AddDays(1));
|
||||
}
|
||||
|
||||
List<string> roles = new();
|
||||
|
||||
if (user.IsManager) roles.Add("manager");
|
||||
if (user.IsAdmin) roles.Add("admin");
|
||||
|
||||
AuthTokens refreshedTokens = GenerateAuthTokens(authAttempt, roles);
|
||||
|
||||
LoginResult loginResult = new LoginResult() {
|
||||
IsAuthenticated = true,
|
||||
AuthTokens = refreshedTokens,
|
||||
User = user
|
||||
};
|
||||
|
||||
return loginResult;
|
||||
} else {
|
||||
throw new AuthenticationException("Invalid refresh token");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to refresh auth tokens. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateRefreshToken() {
|
||||
byte[] randomNumber = new byte[32];
|
||||
using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) {
|
||||
rng.GetBytes(randomNumber);
|
||||
return Convert.ToBase64String(randomNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsRefreshTokenValid(string loginId, string refreshToken) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to determine if refresh token is valid");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentNullException("LoginID cannot be null or empty");
|
||||
if (string.IsNullOrWhiteSpace(refreshToken))
|
||||
throw new ArgumentNullException("Refresh token cannot be null or empty");
|
||||
|
||||
List<string>? cachedRefreshTokensForUser = _cache.Get<List<string>>(loginId);
|
||||
|
||||
if (cachedRefreshTokensForUser is null || !cachedRefreshTokensForUser.Contains(refreshToken)) {
|
||||
_logger.LogInformation($"Could not find cached refresh tokens for user {loginId}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to validate refresh token. Exception: {ex.Message}");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
89
MesaFabApproval.API/Services/DalService.cs
Normal file
89
MesaFabApproval.API/Services/DalService.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using System.Data;
|
||||
|
||||
using Dapper;
|
||||
|
||||
namespace MesaFabApproval.API.Services;
|
||||
|
||||
public interface IDalService {
|
||||
Task<IEnumerable<T>> QueryAsync<T>(string sql);
|
||||
Task<int> ExecuteAsync(string sql);
|
||||
}
|
||||
|
||||
public class DalService : IDalService {
|
||||
private static readonly int RETRIES = 3;
|
||||
private static readonly int BACKOFF_SECONDS_INTERVAL = 30;
|
||||
|
||||
private readonly ILogger<DalService> _logger;
|
||||
private readonly IDbConnectionService _dbConnectionService;
|
||||
|
||||
public DalService(IDbConnectionService dbConnectionService, ILogger<DalService> logger) {
|
||||
_dbConnectionService = dbConnectionService ??
|
||||
throw new ArgumentNullException("IDbConnectionService not injected");
|
||||
_logger = logger ??
|
||||
throw new ArgumentNullException("ILogger not injected");
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<T>> QueryAsync<T>(string sql) {
|
||||
if (sql is null) throw new ArgumentNullException("sql cannot be null");
|
||||
|
||||
int remainingRetries = RETRIES;
|
||||
bool queryWasSuccessful = false;
|
||||
Exception exception = null;
|
||||
IEnumerable<T> result = new List<T>();
|
||||
while (!queryWasSuccessful && remainingRetries > 0) {
|
||||
int backoffSeconds = (RETRIES - remainingRetries--) * BACKOFF_SECONDS_INTERVAL;
|
||||
Task.Delay(backoffSeconds * 1000).Wait();
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to perform query with {sql}. Remaining retries: {remainingRetries}");
|
||||
|
||||
using (IDbConnection conn = _dbConnectionService.GetConnection()) {
|
||||
result = await conn.QueryAsync<T>(sql);
|
||||
}
|
||||
|
||||
queryWasSuccessful = true;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred while attempting to perform a query. Exception: {ex.Message}");
|
||||
exception = ex;
|
||||
}
|
||||
}
|
||||
|
||||
if (!queryWasSuccessful && exception is not null) {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> ExecuteAsync(string sql) {
|
||||
if (sql is null) throw new ArgumentNullException("sql cannot be null");
|
||||
|
||||
int remainingRetries = RETRIES;
|
||||
bool queryWasSuccessful = false;
|
||||
Exception exception = null;
|
||||
int rowsAffected = 0;
|
||||
while (!queryWasSuccessful && remainingRetries > 0) {
|
||||
int backoffSeconds = (RETRIES - remainingRetries--) * BACKOFF_SECONDS_INTERVAL;
|
||||
Task.Delay(backoffSeconds * 1000).Wait();
|
||||
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to execute {sql}. Remaining retries: {remainingRetries}");
|
||||
|
||||
using (IDbConnection conn = _dbConnectionService.GetConnection()) {
|
||||
rowsAffected = await conn.ExecuteAsync(sql);
|
||||
}
|
||||
|
||||
queryWasSuccessful = true;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred while attempting to execute a query. Exception: {ex.Message}");
|
||||
exception = ex;
|
||||
}
|
||||
}
|
||||
|
||||
if (!queryWasSuccessful && exception is not null) {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
return rowsAffected;
|
||||
}
|
||||
}
|
22
MesaFabApproval.API/Services/DbConnectionService.cs
Normal file
22
MesaFabApproval.API/Services/DbConnectionService.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System.Data;
|
||||
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace MesaFabApproval.API.Services;
|
||||
|
||||
public interface IDbConnectionService {
|
||||
IDbConnection GetConnection();
|
||||
}
|
||||
|
||||
public class DbConnectionService : IDbConnectionService {
|
||||
private readonly string _dbConnectionString;
|
||||
|
||||
public DbConnectionService() {
|
||||
_dbConnectionString = Environment.GetEnvironmentVariable("FabApprovalDbConnectionString") ??
|
||||
throw new ArgumentNullException("FabApprovalDbConnectionString environment variable not found");
|
||||
}
|
||||
|
||||
public IDbConnection GetConnection() {
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
}
|
825
MesaFabApproval.API/Services/MRBService.cs
Normal file
825
MesaFabApproval.API/Services/MRBService.cs
Normal file
@ -0,0 +1,825 @@
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Text;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
using MesaFabApproval.Shared.Utilities;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace MesaFabApproval.API.Services;
|
||||
|
||||
public interface IMRBService {
|
||||
Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache);
|
||||
Task<bool> MRBNumberIsValid(int number);
|
||||
Task<MRB> GetMRBById(int id, bool bypassCache = false);
|
||||
Task<MRB> GetMRBByTitle(string title, bool bypassCache);
|
||||
Task CreateNewMRB(MRB mrb);
|
||||
Task UpdateMRB(MRB mrb);
|
||||
Task CreateMRBAction(MRBAction mrbAction);
|
||||
Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache);
|
||||
Task UpdateMRBAction(MRBAction mrbAction);
|
||||
Task DeleteMRBAction(int mrbActionID, 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<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
||||
Task DeleteAttachment(MRBAttachment attachment);
|
||||
Task NotifyNewApprovals(MRB mrb);
|
||||
Task NotifyApprovers(MRBNotification notification);
|
||||
Task NotifyOriginator(MRBNotification notification);
|
||||
Task NotifyQAPreApprover(MRBNotification notification);
|
||||
Task DeleteMRB(int mrbNumber);
|
||||
}
|
||||
|
||||
public class MRBService : IMRBService {
|
||||
private readonly ILogger<MRBService> _logger;
|
||||
private readonly IDalService _dalService;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IApprovalService _approvalService;
|
||||
private readonly ISmtpService _smtpService;
|
||||
|
||||
private readonly string _siteBaseUrl;
|
||||
private readonly string _mrbAttachmentPath;
|
||||
|
||||
public MRBService(ILogger<MRBService> logger,
|
||||
IDalService dalService,
|
||||
IMemoryCache cache,
|
||||
IUserService userService,
|
||||
IApprovalService approvalService,
|
||||
ISmtpService smtpService) {
|
||||
_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 = Environment.GetEnvironmentVariable("NewFabApprovalBaseUrl") ??
|
||||
throw new ArgumentNullException("FabApprovalBaseUrl environment variable not found");
|
||||
_mrbAttachmentPath = Environment.GetEnvironmentVariable("FabApprovalMrbAttachmentPath") ??
|
||||
throw new ArgumentNullException("FabApprovalMrbAttachmentPath environment variable not found");
|
||||
}
|
||||
public async Task CreateNewMRB(MRB mrb) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate new MRB");
|
||||
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("insert into MRB (OriginatorID, Title, SubmittedDate, ");
|
||||
queryBuilder.Append("CloseDate, CancelDate, NumberOfLotsAffected, ApprovalDate, ");
|
||||
queryBuilder.Append("IssueDescription, CustomerImpacted, Department, Process, Val, RMANo, ");
|
||||
queryBuilder.Append("PCRBNo, SpecsImpacted, TrainingRequired, Status, StageNo, ");
|
||||
queryBuilder.Append("CustomerImpactedName, ProcessECNNumber, Tool, Category) values (");
|
||||
queryBuilder.Append($"{mrb.OriginatorID}, '{mrb.Title}', ");
|
||||
if (mrb.SubmittedDate < DateTimeUtilities.MIN_DT)
|
||||
mrb.SubmittedDate = DateTimeUtilities.MIN_DT;
|
||||
queryBuilder.Append($"'{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
if (mrb.CloseDate > DateTimeUtilities.MAX_DT)
|
||||
mrb.CloseDate = DateTimeUtilities.MAX_DT;
|
||||
queryBuilder.Append($"'{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
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.NumberOfLotsAffected}, ");
|
||||
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.IssueDescription}', {Convert.ToUInt32(mrb.CustomerImpacted)}, ");
|
||||
queryBuilder.Append($"'{mrb.Department}', '{mrb.Process}', {mrb.Val}, {mrb.RMANo}, '{mrb.PCRBNo}', ");
|
||||
queryBuilder.Append($"{Convert.ToInt32(mrb.SpecsImpacted)}, {Convert.ToInt32(mrb.TrainingRequired)}, ");
|
||||
queryBuilder.Append($"'{mrb.Status}', {mrb.StageNo}, '{mrb.CustomerImpactedName}', ");
|
||||
queryBuilder.Append($"{mrb.ProcessECNNumber}, '{mrb.Tool}', '{mrb.Category}');");
|
||||
|
||||
int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsCreated <= 0) throw new Exception("Unable to create new MRB");
|
||||
|
||||
mrb = await GetMRBByTitle(mrb.Title, true);
|
||||
|
||||
_cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
_cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
|
||||
IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||
if (allMrbs is not null) {
|
||||
List<MRB> mrbList = allMrbs.ToList();
|
||||
mrbList.Add(mrb);
|
||||
_cache.Set("allMrbs", mrbList, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to create new MRB. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get all MRBs");
|
||||
|
||||
IEnumerable<MRB>? allMrbs = null;
|
||||
if (!bypassCache) allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||
|
||||
if (allMrbs is null) {
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("select (u.FirstName + ' ' + u.LastName) as OriginatorName, m.* ");
|
||||
queryBuilder.Append("from MRB m join Users u on m.OriginatorID = u.UserID;");
|
||||
|
||||
allMrbs = (await _dalService.QueryAsync<MRB>(queryBuilder.ToString())).ToList();
|
||||
|
||||
_cache.Set("allMrbs", allMrbs, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
if (allMrbs is null || allMrbs.Count() == 0)
|
||||
throw new Exception("No MRBs found");
|
||||
|
||||
return allMrbs;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to get all MRBs. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
_logger.LogInformation("Attempting to get an MRB by ID");
|
||||
|
||||
if (id < 0) throw new ArgumentException("Invalid MRB number");
|
||||
|
||||
MRB? mrb = null;
|
||||
if (!bypassCache)
|
||||
mrb = _cache.Get<MRB>($"mrb{id}");
|
||||
|
||||
if (mrb is null) {
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("select (u.FirstName + ' ' + u.LastName) as OriginatorName, m.* ");
|
||||
queryBuilder.Append("from MRB m join Users u on m.OriginatorID = u.UserID ");
|
||||
queryBuilder.Append($"where m.MRBNumber = {id}");
|
||||
|
||||
mrb = (await _dalService.QueryAsync<MRB>(queryBuilder.ToString())).FirstOrDefault();
|
||||
|
||||
_cache.Set($"mrb{id}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
if (mrb is null) throw new Exception($"Unable to get MRB {id}");
|
||||
|
||||
return mrb;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to get an MRB. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MRB> GetMRBByTitle(string title, bool bypassCache) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get an MRB by title");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||
|
||||
MRB? mrb = null;
|
||||
|
||||
if (!bypassCache) mrb = _cache.Get<MRB>($"mrb{title}");
|
||||
|
||||
if (mrb is null) {
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("select (u.FirstName + ' ' + u.LastName) as OriginatorName, m.* ");
|
||||
queryBuilder.Append("from MRB m join Users u on m.OriginatorID = u.UserID ");
|
||||
queryBuilder.Append($"where m.Title = '{title}'");
|
||||
|
||||
mrb = (await _dalService.QueryAsync<MRB>(queryBuilder.ToString())).FirstOrDefault();
|
||||
|
||||
_cache.Set($"mrb{title}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
if (mrb is null) throw new Exception($"Unable to get MRB {title}");
|
||||
|
||||
return mrb;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to get an MRB. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateMRB(MRB mrb) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to update an MRB");
|
||||
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append($"update MRB set OriginatorID = {mrb.OriginatorID}, ");
|
||||
queryBuilder.Append($"Title = '{mrb.Title}', ");
|
||||
if (mrb.SubmittedDate < DateTimeUtilities.MIN_DT)
|
||||
mrb.SubmittedDate = DateTimeUtilities.MIN_DT;
|
||||
queryBuilder.Append($"SubmittedDate = '{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
if (mrb.CloseDate > DateTimeUtilities.MAX_DT)
|
||||
mrb.CloseDate = DateTimeUtilities.MAX_DT;
|
||||
queryBuilder.Append($"CloseDate = '{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
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($"NumberOfLotsAffected = {mrb.NumberOfLotsAffected}, ");
|
||||
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($"IssueDescription = '{mrb.IssueDescription}', ");
|
||||
queryBuilder.Append($"CustomerImpacted = {Convert.ToInt32(mrb.CustomerImpacted)}, ");
|
||||
queryBuilder.Append($"Department = '{mrb.Department}', ");
|
||||
queryBuilder.Append($"Process = '{mrb.Process}', ");
|
||||
queryBuilder.Append($"Val = {mrb.Val}, ");
|
||||
queryBuilder.Append($"RMANo = {mrb.RMANo}, ");
|
||||
queryBuilder.Append($"PCRBNo = '{mrb.PCRBNo}', ");
|
||||
queryBuilder.Append($"SpecsImpacted = {Convert.ToInt32(mrb.SpecsImpacted)}, ");
|
||||
queryBuilder.Append($"TrainingRequired = {Convert.ToInt32(mrb.TrainingRequired)}, ");
|
||||
queryBuilder.Append($"Status = '{mrb.Status}', StageNo = {mrb.StageNo}, ");
|
||||
queryBuilder.Append($"CustomerImpactedName = '{mrb.CustomerImpactedName}', ");
|
||||
queryBuilder.Append($"ProcessECNNumber = '{mrb.ProcessECNNumber}', ");
|
||||
queryBuilder.Append($"Tool = '{mrb.Tool}', Category = '{mrb.Category}' ");
|
||||
queryBuilder.Append($"where MRBNumber = {mrb.MRBNumber};");
|
||||
|
||||
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsAffected <= 0) throw new Exception($"Unable to update MRB {mrb.MRBNumber}");
|
||||
|
||||
_cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
_cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
|
||||
IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||
if (allMrbs is not null) {
|
||||
List<MRB> mrbList = allMrbs.ToList();
|
||||
mrbList.RemoveAll(m => m.MRBNumber ==mrb.MRBNumber);
|
||||
mrbList.Add(mrb);
|
||||
_cache.Set("allMrbs", mrbList, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to update an MRB. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateMRBAction(MRBAction mrbAction) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to generate new MRB action");
|
||||
|
||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
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($"'{mrbAction.PartNumber}', '{mrbAction.LotNumber}', {mrbAction.MRBNumber}, ");
|
||||
queryBuilder.Append($"'{mrbAction.ConvertFrom}', '{mrbAction.ConvertTo}', '{mrbAction.Justification}');");
|
||||
|
||||
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsAffected <= 0) throw new Exception("Unable to create MRB action in database");
|
||||
|
||||
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to create new MRB action. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get MRB actions for MRB {mrbNumber}");
|
||||
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
IEnumerable<MRBAction>? mrbActions = null;
|
||||
|
||||
if (!bypassCache)
|
||||
_cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbNumber}");
|
||||
|
||||
if (mrbActions is null) {
|
||||
string sql = $"select * from MRBAction where MRBNumber = {mrbNumber}";
|
||||
|
||||
mrbActions = (await _dalService.QueryAsync<MRBAction>(sql)).ToList();
|
||||
|
||||
if (mrbActions is not null) {
|
||||
foreach (MRBAction action in mrbActions) {
|
||||
if (action.CompletedDate < DateTime.MaxValue && action.CompletedByUserID > 0) {
|
||||
action.CompletedByUser = await _userService.GetUserByUserId(action.CompletedByUserID);
|
||||
}
|
||||
}
|
||||
|
||||
_cache.Set($"mrbActions{mrbNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(30));
|
||||
}
|
||||
}
|
||||
|
||||
if (mrbActions is null) throw new Exception($"Unable to find MRB actions for MRB {mrbNumber}");
|
||||
|
||||
return mrbActions;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Unable to get MRB actions for MRB {mrbNumber}, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateMRBAction(MRBAction mrbAction) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to update MRB action");
|
||||
|
||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append($"update MRBAction set Action = '{mrbAction.Action}', ");
|
||||
queryBuilder.Append($"Customer = '{mrbAction.Customer}', ");
|
||||
queryBuilder.Append($"Quantity = {mrbAction.Quantity}, ");
|
||||
queryBuilder.Append($"PartNumber = '{mrbAction.PartNumber}', ");
|
||||
queryBuilder.Append($"LotNumber = '{mrbAction.LotNumber}', ");
|
||||
if (mrbAction.AssignedDate < DateTimeUtilities.MIN_DT)
|
||||
mrbAction.AssignedDate = DateTimeUtilities.MIN_DT;
|
||||
queryBuilder.Append($"AssignedDate= '{mrbAction.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', ");
|
||||
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($"CompletedByUserID={mrbAction.CompletedByUserID}, ");
|
||||
queryBuilder.Append($"ConvertFrom='{mrbAction.ConvertFrom}', ");
|
||||
queryBuilder.Append($"ConvertTo='{mrbAction.ConvertTo}', ");
|
||||
queryBuilder.Append($"Justification='{mrbAction.Justification}' ");
|
||||
queryBuilder.Append($"where ActionID={mrbAction.ActionID};");
|
||||
|
||||
int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString());
|
||||
|
||||
if (rowsAffected <= 0) throw new Exception($"There were no MRB actions found with MRB# {mrbAction.MRBNumber}");
|
||||
|
||||
List<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbAction.MRBNumber}")?.ToList();
|
||||
if (mrbActions is not null) {
|
||||
mrbActions.RemoveAll(m => m.ActionID == mrbAction.ActionID);
|
||||
mrbActions.Add(mrbAction);
|
||||
_cache.Set($"mrbActions{mrbAction.MRBNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(30));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Unable to update MRB action, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteMRBAction(int mrbActionID, int mrbNumber) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to delete MRB action {mrbActionID}");
|
||||
|
||||
if (mrbActionID <= 0) throw new ArgumentException($"{mrbActionID} is not a valid MRBActionID");
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRBNumber");
|
||||
|
||||
string sql = $"delete from MRBAction where ActionID = {mrbActionID};";
|
||||
|
||||
int rowsAffected = await _dalService.ExecuteAsync(sql);
|
||||
|
||||
if (rowsAffected <= 0) throw new Exception($"No MRB action was found to delete for ActionID {mrbActionID}");
|
||||
|
||||
List<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbNumber}")?.ToList();
|
||||
if (mrbActions is not null) {
|
||||
mrbActions.RemoveAll(m => m.ActionID == mrbActionID);
|
||||
_cache.Set($"mrbActions{mrbNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(30));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to delete MRB action {mrbActionID}. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<UploadResult>> UploadAttachments(IEnumerable<IFormFile> files, int mrbNumber) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to upload 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 (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
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}\\{mrbNumber}\\{encodedName}";
|
||||
|
||||
await SaveFileToFileSystem(file, path);
|
||||
await SaveAttachmentInDb(file, path, mrbNumber);
|
||||
|
||||
UploadResult uploadResult = new() {
|
||||
UploadSuccessful = true,
|
||||
FileName = file.FileName
|
||||
};
|
||||
uploadResults.Add(uploadResult);
|
||||
} catch (Exception ex) {
|
||||
UploadResult uploadResult = new() {
|
||||
UploadSuccessful = false,
|
||||
FileName = file.FileName,
|
||||
Error = ex.Message
|
||||
};
|
||||
uploadResults.Add(uploadResult);
|
||||
}
|
||||
}
|
||||
|
||||
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(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());
|
||||
|
||||
return uploadResults;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to upload action attachment. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to get all attachments for MRB {mrbNumber}");
|
||||
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
IEnumerable<MRBAttachment>? attachments = null;
|
||||
if (!bypassCache)
|
||||
_cache.Get<IEnumerable<MRBAttachment>>($"mrbAttachments{mrbNumber}");
|
||||
|
||||
if (attachments is null) {
|
||||
string sql = $"select * from MRBAttachment where MRBNumber = {mrbNumber};";
|
||||
|
||||
attachments = (await _dalService.QueryAsync<MRBAttachment>(sql)).ToList();
|
||||
|
||||
_cache.Set($"mrbAttachments{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 {mrbNumber}. ");
|
||||
errMsgBuilder.Append($"Exception: {ex.Message}");
|
||||
_logger.LogError(errMsgBuilder.ToString());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to delete 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 MRBAttachment where AttachmentID = {attachment.AttachmentID};";
|
||||
|
||||
int rowsDeleted = await _dalService.ExecuteAsync(sql);
|
||||
|
||||
if (rowsDeleted <= 0)
|
||||
throw new Exception($"No attachments found in the database with attachment ID {attachment.AttachmentID}");
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to delete an attachment. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task NotifyNewApprovals(MRB mrb) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to notify approvers");
|
||||
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(mrb.MRBNumber, true);
|
||||
|
||||
List<Approval> approvalsNeedingNotification = approvals.Where(a => a.NotifyDate <= 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)) {
|
||||
emailsAlreadySent.Add(user.Email);
|
||||
|
||||
List<MailAddress> toAddresses = new();
|
||||
toAddresses.Add(new MailAddress(user.Email));
|
||||
|
||||
List<MailAddress> ccAddresses = new();
|
||||
|
||||
string subject = $"[New Task] Mesa Fab Approval - MRB# {mrb.MRBNumber} - {mrb.Title}";
|
||||
|
||||
StringBuilder bodyBuilder = new();
|
||||
bodyBuilder.Append($"MRB# {mrb.MRBNumber} [{mrb.Title}] is ready for your approval. ");
|
||||
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());
|
||||
|
||||
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(MRBNotification notification) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to send notification to approvers");
|
||||
|
||||
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");
|
||||
|
||||
IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(notification.MRB.MRBNumber, 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 - MRB# {notification.MRB.MRBNumber} - {notification.MRB.Title}";
|
||||
|
||||
StringBuilder bodyBuilder = new();
|
||||
bodyBuilder.Append($"{notification.Message} <br /> <br />");
|
||||
bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{approval.IssueID} to view the MRB.");
|
||||
|
||||
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(MRBNotification notification) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to send notification to originator");
|
||||
|
||||
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");
|
||||
|
||||
User user = await _userService.GetUserByUserId(notification.MRB.OriginatorID);
|
||||
|
||||
List<MailAddress> toAddresses = new();
|
||||
toAddresses.Add(new MailAddress(user.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 originator, because {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task NotifyQAPreApprover(MRBNotification notification) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to send notification to QA pre approver");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveFileToFileSystem(IFormFile file, string path) {
|
||||
try {
|
||||
_logger.LogInformation($"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.LogError($"An exception occurred when attempting to save file to file system. Exception: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveAttachmentInDb(IFormFile file, string path, int mrbNumber) {
|
||||
try {
|
||||
_logger.LogInformation($"Attempting to save 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 (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("insert into MRBAttachment (MRBNumber, FileName, UploadDate, Path) ");
|
||||
queryBuilder.Append($"values ({mrbNumber}, '{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 attachment in database");
|
||||
} catch (Exception ex) {
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
214
MesaFabApproval.API/Services/PCRBService.cs
Normal file
214
MesaFabApproval.API/Services/PCRBService.cs
Normal file
@ -0,0 +1,214 @@
|
||||
using System.Text;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace MesaFabApproval.API.Services;
|
||||
|
||||
public interface IPCRBService {
|
||||
public Task CreateNewPCRB(PCRB pcrb);
|
||||
public Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache);
|
||||
public Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache);
|
||||
public Task<PCRB> GetPCRBByTitle(string title, bool bypassCache);
|
||||
public Task UpdatePCRB(PCRB pcrb);
|
||||
public Task DeletePCRB(int planNumber);
|
||||
}
|
||||
|
||||
public class PCRBService : IPCRBService {
|
||||
private readonly ILogger<PCRBService> _logger;
|
||||
private readonly IDalService _dalService;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
|
||||
public PCRBService(ILogger<PCRBService> logger,
|
||||
IDalService dalService,
|
||||
IMemoryCache cache,
|
||||
IUserService userService) {
|
||||
_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");
|
||||
}
|
||||
|
||||
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}', ChangeLevel='{pcrb.ChangeLevel}', ");
|
||||
queryBuilder.Append($"CurrentStep={pcrb.CurrentStep}, ReasonForChange='{pcrb.ReasonForChange}', ");
|
||||
queryBuilder.Append($"ChangeDescription='{pcrb.ChangeDescription}', ");
|
||||
queryBuilder.Append($"IsITAR={Convert.ToInt32(pcrb.IsITAR)}, ");
|
||||
queryBuilder.Append($"InsertTimeStamp='{pcrb.InsertTimeStamp.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;
|
||||
}
|
||||
}
|
||||
}
|
79
MesaFabApproval.API/Services/SmtpService.cs
Normal file
79
MesaFabApproval.API/Services/SmtpService.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using MesaFabApproval.API.Clients;
|
||||
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace MesaFabApproval.API.Services;
|
||||
|
||||
public interface ISmtpService {
|
||||
Task<bool> SendEmail(IEnumerable<MailAddress> recipients, IEnumerable<MailAddress> ccRecipients, string subject, string body);
|
||||
}
|
||||
|
||||
public class SmtpService : ISmtpService {
|
||||
private readonly ILogger<SmtpService> _logger;
|
||||
private readonly ISmtpClientWrapper _smtpClient;
|
||||
private readonly bool _shouldSendEmail;
|
||||
|
||||
public SmtpService(ILogger<SmtpService> logger, ISmtpClientWrapper smtpClient) {
|
||||
_logger = logger ??
|
||||
throw new ArgumentNullException("ILogger not injected");
|
||||
_smtpClient = smtpClient ??
|
||||
throw new ArgumentNullException("SmtpClient not injected");
|
||||
if (!Boolean.TryParse(Environment.GetEnvironmentVariable("FabApprovalShouldSendEmail"), out _shouldSendEmail))
|
||||
throw new ArgumentNullException("FabApprovalShouldSendEmail environment variable not found");
|
||||
}
|
||||
|
||||
public async Task<bool> SendEmail(IEnumerable<MailAddress> recipients,
|
||||
IEnumerable<MailAddress> ccRecipients,
|
||||
string subject,
|
||||
string body) {
|
||||
if (recipients.IsNullOrEmpty()) throw new ArgumentNullException("recipients cannot be null or empty!");
|
||||
if (ccRecipients is null) throw new ArgumentNullException("ccRecipients cannot be null!");
|
||||
if (subject.IsNullOrEmpty()) throw new ArgumentNullException("subject cannot be null or empty!");
|
||||
if (body.IsNullOrEmpty()) throw new ArgumentNullException("body cannot be null or empty!");
|
||||
|
||||
return await Task.Run(() => {
|
||||
int maxRetries = 3;
|
||||
int backoffSeconds = 30;
|
||||
|
||||
bool messageWasSent = false;
|
||||
|
||||
try {
|
||||
if (_shouldSendEmail) {
|
||||
int remainingRetries = maxRetries;
|
||||
while (!messageWasSent && remainingRetries > 0) {
|
||||
try {
|
||||
Task.Delay((maxRetries - remainingRetries--) * backoffSeconds * 1000);
|
||||
|
||||
_logger.LogInformation($"Attempting to send notification. Remaining retries: {remainingRetries}");
|
||||
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.IsBodyHtml = true;
|
||||
msg.From = new MailAddress("MesaFabApproval@infineon.com", "Mesa Fab Approval");
|
||||
msg.Sender = new MailAddress("MesaFabApproval@infineon.com", "Mesa Fab Approval");
|
||||
foreach (MailAddress recipient in recipients) msg.To.Add(recipient);
|
||||
msg.Bcc.Add("chase.tucker@infineon.com");
|
||||
foreach (MailAddress ccRecipient in ccRecipients) msg.CC.Add(ccRecipient);
|
||||
msg.Subject = subject;
|
||||
msg.Body = body;
|
||||
|
||||
_smtpClient.Send(msg);
|
||||
|
||||
messageWasSent = true;
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"Message not sent successfully. Exception: {ex.Message}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_logger.LogInformation("Not sending email per local configuration");
|
||||
messageWasSent = true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError($"An exception occurred when attempting to send notification. Exception: {ex.Message}");
|
||||
}
|
||||
|
||||
return messageWasSent;
|
||||
});
|
||||
}
|
||||
}
|
147
MesaFabApproval.API/Services/UserService.cs
Normal file
147
MesaFabApproval.API/Services/UserService.cs
Normal file
@ -0,0 +1,147 @@
|
||||
using System.Text;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace MesaFabApproval.API.Services;
|
||||
|
||||
public interface IUserService {
|
||||
Task<IEnumerable<User>> GetAllActiveUsers();
|
||||
Task<User> GetUserByLoginId(string loginId);
|
||||
Task<User> GetUserByUserId(int userId);
|
||||
Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item);
|
||||
}
|
||||
|
||||
public class UserService : IUserService {
|
||||
private readonly ILogger<UserService> _logger;
|
||||
private readonly IDalService _dalService;
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
public UserService(ILogger<UserService> 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<User>> GetAllActiveUsers() {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get all active users");
|
||||
|
||||
IEnumerable<User>? allActiveUsers = _cache.Get<IEnumerable<User>>("allActiveUsers");
|
||||
|
||||
if (allActiveUsers is null) {
|
||||
string sql = "select * from Users where IsActive = 1";
|
||||
|
||||
allActiveUsers = (await _dalService.QueryAsync<User>(sql)).ToList();
|
||||
|
||||
_cache.Set("allActiveUsers", allActiveUsers, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
if (allActiveUsers is null || allActiveUsers.Count() == 0) {
|
||||
throw new Exception("No users found");
|
||||
}
|
||||
|
||||
return allActiveUsers;
|
||||
} catch (Exception ex) {
|
||||
string errMsg = $"An exception occurred when attempting to get all users. Exception: {ex.Message}";
|
||||
_logger.LogError(errMsg);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<User> GetUserByLoginId(string loginId) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get user by LoginId");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(loginId))
|
||||
throw new ArgumentException("LoginId cannot be null or empty");
|
||||
|
||||
User? user = _cache.Get<User>($"userByLoginId{loginId}");
|
||||
|
||||
if (user is null)
|
||||
user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.LoginID == loginId);
|
||||
|
||||
if (user is null) {
|
||||
string sql = $"select * from Users where LoginID = '{loginId}';";
|
||||
|
||||
user = (await _dalService.QueryAsync<User>(sql)).FirstOrDefault();
|
||||
|
||||
_cache.Set($"userByLoginId{loginId}", user, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
if (user is null) throw new Exception($"No user found with LoginID {loginId}");
|
||||
|
||||
return user;
|
||||
} catch (Exception ex) {
|
||||
string errMsg = $"An exception occurred when attempting to get user for LoginID {loginId}. Exception: {ex.Message}";
|
||||
_logger.LogError(errMsg);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<User> GetUserByUserId(int userId) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get user by user ID");
|
||||
|
||||
if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID");
|
||||
|
||||
User? user = _cache.Get<User>($"userByUserId{userId}");
|
||||
|
||||
if (user is null)
|
||||
user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.UserID == userId);
|
||||
|
||||
if (user is null) {
|
||||
string sql = $"select * from Users where UserID = '{userId}';";
|
||||
|
||||
user = (await _dalService.QueryAsync<User>(sql)).FirstOrDefault();
|
||||
|
||||
_cache.Set($"userByUserId{userId}", user, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
if (user is null) throw new Exception($"No user found with UserID {userId}");
|
||||
|
||||
return user;
|
||||
} catch (Exception ex) {
|
||||
string errMsg = $"An exception occurred when attempting to get user for UserID {userId}. Exception: {ex.Message}";
|
||||
_logger.LogError(errMsg);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item) {
|
||||
try {
|
||||
_logger.LogInformation("Attempting to get approver user IDs");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(item)) throw new ArgumentException("SubRoleCategoryItem cannot be null or empty");
|
||||
|
||||
IEnumerable<int>? userIds = _cache.Get<IEnumerable<int>>($"approverUserIdsBySubRollCategory{item}");
|
||||
|
||||
if (userIds is null) {
|
||||
StringBuilder queryBuilder = new();
|
||||
queryBuilder.Append("select us.UserID ");
|
||||
queryBuilder.Append("from SubRole as sr ");
|
||||
queryBuilder.Append("join UserSubRole as us on sr.SubRoleID=us.SubRoleID ");
|
||||
queryBuilder.Append("join SubRoleCategory as sc on sr.SubRoleCategoryID=sc.SubRoleCategoryID ");
|
||||
queryBuilder.Append($"where sc.SubRoleCategoryItem='{item}'");
|
||||
|
||||
userIds = (await _dalService.QueryAsync<int>(queryBuilder.ToString())).ToList();
|
||||
|
||||
_cache.Set($"approverUserIdsBySubRollCategory{item}", userIds, DateTimeOffset.Now.AddHours(1));
|
||||
}
|
||||
|
||||
if (userIds is null || userIds.Count() == 0) {
|
||||
throw new Exception($"No users found for SubRoleCategoryItem {item}");
|
||||
}
|
||||
|
||||
return userIds;
|
||||
} catch (Exception ex) {
|
||||
string errMsg = $"An exception occurred when attempting to get approver user IDs. Exception: {ex.Message}";
|
||||
_logger.LogError(errMsg);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
3
MesaFabApproval.API/appsettings.json
Normal file
3
MesaFabApproval.API/appsettings.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"AllowedHosts": "*"
|
||||
}
|
33
MesaFabApproval.API/nLog.config
Normal file
33
MesaFabApproval.API/nLog.config
Normal file
@ -0,0 +1,33 @@
|
||||
<?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="asyncLog" xsi:type="AsyncWrapper">
|
||||
<target
|
||||
name="appLog"
|
||||
xsi:type="File"
|
||||
fileName="d:\logs\MesaFabApproval.API\log.txt"
|
||||
archiveFilename="d:\logs\MesaFabApproval.API\archive\log-${shortdate}.txt"
|
||||
maxArchiveFiles="30"
|
||||
archiveEvery="Day"
|
||||
/>
|
||||
<target
|
||||
name="consoleLog"
|
||||
xsi:type="Console"
|
||||
/>
|
||||
</target>
|
||||
</targets>
|
||||
|
||||
<rules>
|
||||
<logger name="Microsoft.*" finalMinLevel="Warn" />
|
||||
<logger name="Microsoft.AspNetCore.HttpLogging.*" finalMinLevel="Info" />
|
||||
<logger name="System.Net.Http.HttpClient.*" finalMinLevel="Warn" />
|
||||
<logger name="*" minlevel="Info" writeTo="asyncLog" />
|
||||
</rules>
|
||||
</nlog>
|
26
MesaFabApproval.Client/App.razor
Normal file
26
MesaFabApproval.Client/App.razor
Normal file
@ -0,0 +1,26 @@
|
||||
<CascadingAuthenticationState>
|
||||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" >
|
||||
<NotAuthorized>
|
||||
@if (context.User.Identity?.IsAuthenticated != true) {
|
||||
<RedirectToLogin />
|
||||
} else {
|
||||
<p role="alert">You are not authorized to access this resource.</p>
|
||||
}
|
||||
</NotAuthorized>
|
||||
<Authorizing>
|
||||
<MudProgressCircular Color="Color.Tertiary" Indeterminate="true" />
|
||||
<div>Authorizing...</div>
|
||||
</Authorizing>
|
||||
</AuthorizeRouteView>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</CascadingAuthenticationState>
|
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}")]
|
71
MesaFabApproval.Client/Layout/MainLayout.razor
Normal file
71
MesaFabApproval.Client/Layout/MainLayout.razor
Normal file
@ -0,0 +1,71 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||
@inject IConfiguration Configuration
|
||||
@inject IMemoryCache cache
|
||||
@inject NavigationManager navManager
|
||||
|
||||
<MudThemeProvider />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
<MudPopoverProvider />
|
||||
|
||||
<div style="height: 100vh;">
|
||||
<MudLayout>
|
||||
<MudAppBar Elevation="1" Color="Color.Info">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||
<MudText Typo="Typo.h5" Class="ml-3">Mesa Fab Approval</MudText>
|
||||
@if (authStateProvider.CurrentUser is not null) {
|
||||
<MudSpacer />
|
||||
<MudText Typo="Typo.h6" Class="mr-3">@authStateProvider.CurrentUser.FirstName @authStateProvider.CurrentUser.LastName</MudText>
|
||||
<MudIconButton Variant="Variant.Filled"
|
||||
Color="Color.Tertiary"
|
||||
OnClick=Logout
|
||||
Edge="Edge.End"
|
||||
Icon="@Icons.Material.Filled.Logout" />
|
||||
}
|
||||
</MudAppBar>
|
||||
<MudDrawer @bind-Open="_drawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2">
|
||||
<MudNavMenu Color="Color.Info" Bordered="true" Class="d-flex flex-column justify-center p-1 gap-1">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Tertiary"
|
||||
Href="@Configuration["OldFabApprovalUrl"]"
|
||||
Target="_blank"
|
||||
StartIcon="@Icons.Material.Filled.Home">
|
||||
Return to Main Site
|
||||
</MudButton>
|
||||
<MudDivider Class="my-1" />
|
||||
@if (authStateProvider.CurrentUser is not null) {
|
||||
<MudNavGroup Title="Create New">
|
||||
<MudNavLink OnClick="@(() => GoTo("mrb/new"))">Create New MRB</MudNavLink>
|
||||
</MudNavGroup>
|
||||
<MudNavLink OnClick="@(() => GoTo(""))" Icon="@Icons.Material.Filled.Dashboard">Dashboard</MudNavLink>
|
||||
<MudNavLink OnClick="@(() => GoTo("mrb/all"))" Icon="@Icons.Material.Filled.Ballot">MRB List</MudNavLink>
|
||||
}
|
||||
</MudNavMenu>
|
||||
</MudDrawer>
|
||||
<div style="display: flex; flex-flow: column; height: 100%;">
|
||||
<MudMainContent Style="@($"background:#E0E0E0; flex-grow: 1;")">
|
||||
@Body
|
||||
</MudMainContent>
|
||||
</div>
|
||||
</MudLayout>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
bool _drawerOpen = true;
|
||||
|
||||
void DrawerToggle() {
|
||||
_drawerOpen = !_drawerOpen;
|
||||
}
|
||||
|
||||
void Logout() {
|
||||
authStateProvider.Logout();
|
||||
}
|
||||
|
||||
private void GoTo(string page) {
|
||||
DrawerToggle();
|
||||
cache.Set("redirectUrl", page);
|
||||
navManager.NavigateTo(page);
|
||||
}
|
||||
}
|
77
MesaFabApproval.Client/Layout/MainLayout.razor.css
Normal file
77
MesaFabApproval.Client/Layout/MainLayout.razor.css
Normal file
@ -0,0 +1,77 @@
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
white-space: nowrap;
|
||||
margin-left: 1.5rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.top-row ::deep a:first-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@media (max-width: 640.98px) {
|
||||
.top-row {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.page {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.top-row.auth ::deep a:first-child {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.top-row, article {
|
||||
padding-left: 2rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
}
|
||||
}
|
29
MesaFabApproval.Client/MesaFabApproval.Client.csproj
Normal file
29
MesaFabApproval.Client/MesaFabApproval.Client.csproj
Normal file
@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Watch Include="**\*.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.StaticFiles" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||
<PackageReference Include="MudBlazor" Version="7.6.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MesaFabApproval.Shared\MesaFabApproval.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
64
MesaFabApproval.Client/Pages/AuthenticatedRedirect.razor
Normal file
64
MesaFabApproval.Client/Pages/AuthenticatedRedirect.razor
Normal file
@ -0,0 +1,64 @@
|
||||
@page "/redirect"
|
||||
@attribute [AllowAnonymous]
|
||||
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||
@inject IAuthenticationService authService
|
||||
@inject IUserService userService
|
||||
@inject ISnackbar snackbar
|
||||
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
@code {
|
||||
private string? _jwt;
|
||||
private string? _refreshToken;
|
||||
private string? _redirectPath;
|
||||
|
||||
protected override async Task OnParametersSetAsync() {
|
||||
try {
|
||||
Uri uri = navigationManager.ToAbsoluteUri(navigationManager.Uri);
|
||||
|
||||
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("jwt", out var jwt)) {
|
||||
_jwt = System.Net.WebUtility.UrlDecode(jwt);
|
||||
}
|
||||
|
||||
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("refreshToken", out var refreshToken)) {
|
||||
_refreshToken = System.Net.WebUtility.UrlDecode(refreshToken);
|
||||
}
|
||||
|
||||
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("redirectPath", out var redirectPath)) {
|
||||
_redirectPath = System.Net.WebUtility.UrlDecode(redirectPath);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_jwt) && !string.IsNullOrWhiteSpace(_refreshToken)) {
|
||||
await authService.SetTokens(_jwt, _refreshToken);
|
||||
|
||||
ClaimsPrincipal principal = authService.GetClaimsPrincipalFromJwt(_jwt);
|
||||
|
||||
string loginId = userService.GetLoginIdFromClaimsPrincipal(principal);
|
||||
|
||||
await authService.SetLoginId(loginId);
|
||||
await authService.SetTokens(_jwt, _refreshToken);
|
||||
|
||||
User? user = await userService.GetUserByLoginId(loginId);
|
||||
await authService.SetCurrentUser(user);
|
||||
|
||||
await authStateProvider.StateHasChanged(principal);
|
||||
}
|
||||
|
||||
if (authStateProvider.CurrentUser is not null && !string.IsNullOrWhiteSpace(_redirectPath)) {
|
||||
navigationManager.NavigateTo(_redirectPath);
|
||||
} else {
|
||||
await authStateProvider.Logout();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_redirectPath)) {
|
||||
navigationManager.NavigateTo($"login/{_redirectPath}");
|
||||
} else {
|
||||
navigationManager.NavigateTo("login");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
snackbar.Add($"Redirect failed, because {ex.Message}", Severity.Error);
|
||||
navigationManager.NavigateTo("login");
|
||||
}
|
||||
}
|
||||
}
|
69
MesaFabApproval.Client/Pages/Components/Comments.razor
Normal file
69
MesaFabApproval.Client/Pages/Components/Comments.razor
Normal file
@ -0,0 +1,69 @@
|
||||
@inject ISnackbar snackbar
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudPaper Class="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/>
|
||||
</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; } = "";
|
||||
|
||||
private string[] errors = { };
|
||||
|
||||
private bool processing = 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());
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
@inject ISnackbar snackbar
|
||||
@inject IMRBService mrbService
|
||||
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudPaper Class="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);
|
||||
}
|
||||
}
|
||||
}
|
261
MesaFabApproval.Client/Pages/Components/MRBActionForm.razor
Normal file
261
MesaFabApproval.Client/Pages/Components/MRBActionForm.razor
Normal file
@ -0,0 +1,261 @@
|
||||
@inject IMRBService mrbService
|
||||
@inject ISnackbar snackbar
|
||||
@inject ICustomerService customerService
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudPaper Class="p-2">
|
||||
<MudForm @bind-Errors="@errors">
|
||||
<MudSelect T="string"
|
||||
Label="Action"
|
||||
Required="true"
|
||||
RequiredError="You must select an action!"
|
||||
@bind-Value="@mrbAction.Action"
|
||||
Text="@mrbAction.Action">
|
||||
<MudSelectItem Value="@("Block")" />
|
||||
<MudSelectItem Value="@("Convert")" />
|
||||
<MudSelectItem Value="@("Recall")" />
|
||||
<MudSelectItem Value="@("Scrap")" />
|
||||
<MudSelectItem Value="@("Unblock")" />
|
||||
<MudSelectItem Value="@("Waiver")" />
|
||||
</MudSelect>
|
||||
@if (mrbAction.Action.Equals("Convert")) {
|
||||
<MudTextField @bind-Value="@mrbAction.ConvertFrom"
|
||||
Label="Convert From"
|
||||
Required
|
||||
RequiredError="Conversion value required!"
|
||||
Text="@mrbAction.ConvertFrom" />
|
||||
<MudTextField @bind-Value="@mrbAction.ConvertTo"
|
||||
Label="Convert To"
|
||||
Required
|
||||
RequiredError="Conversion value required!"
|
||||
Text="@mrbAction.ConvertTo" />
|
||||
}
|
||||
<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>
|
||||
<MudTextField T="int"
|
||||
InputType="@InputType.Number"
|
||||
Label="Qty"
|
||||
Required="true"
|
||||
RequiredError="You must supply a quantity!"
|
||||
@bind-Value=mrbAction.Quantity
|
||||
Text="@mrbAction.Quantity.ToString()" />
|
||||
<MudAutocomplete T="string"
|
||||
Label="Part Number"
|
||||
Variant="Variant.Outlined"
|
||||
AnchorOrigin="Origin.BottomCenter"
|
||||
@bind-Value=mrbAction.PartNumber
|
||||
Text="@mrbAction.PartNumber"
|
||||
SearchFunc="@PartNumberSearch"
|
||||
ResetValueOnEmptyText
|
||||
CoerceText />
|
||||
<MudAutocomplete T="string"
|
||||
Label="Batch Number / Lot Number"
|
||||
Variant="Variant.Outlined"
|
||||
AnchorOrigin="Origin.BottomCenter"
|
||||
@bind-Value=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>
|
||||
</MudPaper>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Tertiary"
|
||||
Class="m1-auto"
|
||||
OnClick=SaveMRBAction>
|
||||
@if (processingSave) {
|
||||
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||
<MudText>Processing</MudText>
|
||||
} else {
|
||||
<MudText>Save</MudText>
|
||||
}
|
||||
</MudButton>
|
||||
@if (mrbAction is not null && mrbAction.ActionID > 0) {
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Secondary"
|
||||
Disabled="@(mrbAction is null || (mrbAction is not null && mrbAction.ActionID <= 0))"
|
||||
Class="m1-auto"
|
||||
OnClick=DeleteMRBAction>
|
||||
@if (processingDelete) {
|
||||
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||
<MudText>Processing</MudText>
|
||||
} else {
|
||||
<MudText>Delete</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 MRBAction mrbAction { get; set; }
|
||||
|
||||
private IEnumerable<MRBAction>? actions = null;
|
||||
|
||||
private MRBAction lastAction = null;
|
||||
|
||||
private IEnumerable<string> customerNames = new List<string>();
|
||||
|
||||
private bool isVisible { get; set; }
|
||||
private string[] errors = { };
|
||||
private bool processingSave = false;
|
||||
private bool processingDelete = false;
|
||||
|
||||
protected override async Task OnParametersSetAsync() {
|
||||
isVisible = true;
|
||||
|
||||
if (mrbAction is null) {
|
||||
snackbar.Add("MRB action cannot be null", Severity.Warning);
|
||||
MudDialog.Cancel();
|
||||
} else {
|
||||
actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, false)).OrderByDescending(a => a.ActionID);
|
||||
|
||||
if (actions is not null && actions.Count() > 0) {
|
||||
if (string.IsNullOrWhiteSpace(mrbAction.LotNumber))
|
||||
mrbAction.LotNumber = actions.First().LotNumber;
|
||||
if (string.IsNullOrWhiteSpace(mrbAction.PartNumber))
|
||||
mrbAction.PartNumber = actions.First().PartNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if (customerNames is null || customerNames.Count() <= 0)
|
||||
customerNames = await customerService.GetAllCustomerNames();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private bool FormIsValid() {
|
||||
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("Unblock") || mrbAction.Action.Equals("Waiver");
|
||||
actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Customer) &&
|
||||
!string.IsNullOrWhiteSpace(mrbAction.PartNumber) &&
|
||||
!string.IsNullOrWhiteSpace(mrbAction.LotNumber);
|
||||
|
||||
if (mrbAction.Action.Equals("Scrap"))
|
||||
return actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Justification);
|
||||
|
||||
return actionIsValid;
|
||||
}
|
||||
|
||||
private async void SaveMRBAction() {
|
||||
processingSave = true;
|
||||
try {
|
||||
if (!FormIsValid()) throw new Exception("You must complete the form before saving!");
|
||||
|
||||
if (mrbAction.MRBNumber > 0) {
|
||||
if (mrbAction.ActionID <= 0) {
|
||||
await mrbService.CreateMRBAction(mrbAction);
|
||||
snackbar.Add("MRB action created", Severity.Success);
|
||||
} else {
|
||||
await mrbService.UpdateMRBAction(mrbAction);
|
||||
snackbar.Add("MRB action updated", Severity.Success);
|
||||
}
|
||||
|
||||
actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, true)).OrderByDescending(a => a.ActionID);
|
||||
} else {
|
||||
snackbar.Add("MRB action saved", Severity.Success);
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
MudDialog.Close(DialogResult.Ok(mrbAction));
|
||||
} catch (Exception ex) {
|
||||
snackbar.Add(ex.Message, Severity.Error);
|
||||
}
|
||||
processingSave = false;
|
||||
}
|
||||
|
||||
private async void DeleteMRBAction() {
|
||||
processingDelete = true;
|
||||
try {
|
||||
if (mrbAction is null) throw new Exception("MRB action cannot be null!");
|
||||
if (mrbAction.ActionID <= 0)
|
||||
throw new Exception("You cannot delete an action before creating it!");
|
||||
if (mrbAction.MRBNumber <= 0)
|
||||
throw new Exception("Invalid MRB number!");
|
||||
|
||||
await mrbService.DeleteMRBAction(mrbAction);
|
||||
snackbar.Add("MRB action successfully deleted", Severity.Success);
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
MudDialog.Close(DialogResult.Ok<MRBAction>(null));
|
||||
} catch (Exception ex) {
|
||||
snackbar.Add(ex.Message, Severity.Error);
|
||||
}
|
||||
processingDelete = false;
|
||||
}
|
||||
|
||||
private void 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="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;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
@attribute [AllowAnonymous]
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@code {
|
||||
protected override void OnInitialized() {
|
||||
Navigation.NavigateTo("login");
|
||||
}
|
||||
}
|
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());
|
||||
}
|
||||
}
|
248
MesaFabApproval.Client/Pages/Dashboard.razor
Normal file
248
MesaFabApproval.Client/Pages/Dashboard.razor
Normal file
@ -0,0 +1,248 @@
|
||||
@page "/"
|
||||
@page "/Dashboard"
|
||||
@inject IConfiguration Configuration
|
||||
@inject MesaFabApprovalAuthStateProvider stateProvider
|
||||
@inject IApprovalService approvalService
|
||||
@inject IMemoryCache cache
|
||||
@inject NavigationManager navigationManager
|
||||
@inject ISnackbar snackbar
|
||||
@inject IMRBService mrbService
|
||||
@inject IECNService ecnService
|
||||
@inject ICAService caService
|
||||
@inject IJSRuntime jsRuntime
|
||||
|
||||
<PageTitle>Dashboard</PageTitle>
|
||||
|
||||
<MudPaper Class="p-2 m-2">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center">Dashboard</MudText>
|
||||
</MudPaper>
|
||||
|
||||
<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"
|
||||
Class="p-2 m-2 d-flex flex-column justify-center">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center">My Active Approvals</MudText>
|
||||
<MudDivider DividerType="DividerType.Middle" Class="my-2" />
|
||||
<MudTable Items="@approvalList"
|
||||
Class="m-2"
|
||||
Striped
|
||||
SortLabel="Sort by">
|
||||
<HeaderContent>
|
||||
<MudTh>
|
||||
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.IssueID)">
|
||||
Issue ID
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.SubRoleCategoryItem)">
|
||||
Role
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<Approval,object>(x=>x.AssignedDate)">
|
||||
Assigned Date
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.Step)">
|
||||
Step
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="Issue ID">
|
||||
@if (context.IssueID > 0) {
|
||||
<MudLink OnClick="@(() => FollowLink(context.IssueID))">@context.IssueID</MudLink>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Role">@context.SubRoleCategoryItem</MudTd>
|
||||
<MudTd DataLabel="Assigned Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.AssignedDate)</MudTd>
|
||||
<MudTd DataLabel="Step">@context.Step</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 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"
|
||||
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>
|
||||
</MudTabs>
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
private IEnumerable<Approval> approvalList = new List<Approval>();
|
||||
private IEnumerable<MRB> myMRBs = new List<MRB>();
|
||||
|
||||
private IEnumerable<int> ecnNumbers = new HashSet<int>();
|
||||
private IEnumerable<int> caNumbers = new HashSet<int>();
|
||||
private IEnumerable<int> mrbNumbers = new HashSet<int>();
|
||||
|
||||
private bool myApprovalsProcessing = false;
|
||||
private bool myMrbsProcessing = false;
|
||||
|
||||
private string mrbSearchString = "";
|
||||
|
||||
protected async override Task OnParametersSetAsync() {
|
||||
try {
|
||||
if (stateProvider.CurrentUser is not null) {
|
||||
myApprovalsProcessing = true;
|
||||
approvalList = (await approvalService.GetApprovalsForUserId(stateProvider.CurrentUser.UserID, true))
|
||||
.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;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
myMrbsProcessing = 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;
|
||||
if (ecnNumbers.Contains(issueId))
|
||||
isEcn = true;
|
||||
if (caNumbers.Contains(issueId))
|
||||
isCa = true;
|
||||
if (mrbNumbers.Contains(issueId))
|
||||
isMrb = 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);
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
if (isEcnTask.Result) {
|
||||
isEcn = true;
|
||||
} else if (isCaTask.Result) {
|
||||
isCa = true;
|
||||
} else if (isMrbTask.Result) {
|
||||
isMrb = 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}");
|
||||
}
|
||||
|
||||
private void GoTo(string page) {
|
||||
cache.Set("redirectUrl", 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;
|
||||
}
|
||||
}
|
113
MesaFabApproval.Client/Pages/Login.razor
Normal file
113
MesaFabApproval.Client/Pages/Login.razor
Normal file
@ -0,0 +1,113 @@
|
||||
@page "/login"
|
||||
@page "/login/{redirectUrl}"
|
||||
@page "/login/{redirectUrl}/{redirectUrlSub}"
|
||||
@attribute [AllowAnonymous]
|
||||
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||
@inject NavigationManager navManager
|
||||
@inject ISnackbar snackbar
|
||||
|
||||
<MudPaper Class="p-2 m-2">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center">Login</MudText>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Class="p-2 m-2">
|
||||
<MudForm @bind-IsValid="@success" @bind-Errors="@errors">
|
||||
<MudTextField T="string"
|
||||
Label="Windows Username"
|
||||
Required="true"
|
||||
RequiredError="Username is required!"
|
||||
Variant="Variant.Outlined"
|
||||
@bind-Value=username
|
||||
Class="m-1"
|
||||
Immediate="true"
|
||||
AutoFocus
|
||||
OnKeyDown=SubmitIfEnter />
|
||||
<MudTextField T="string"
|
||||
Label="Windows Password"
|
||||
Required="true"
|
||||
RequiredError="Password is required!"
|
||||
Variant="Variant.Outlined"
|
||||
@bind-Value=password
|
||||
InputType="InputType.Password"
|
||||
Class="m-1"
|
||||
Immediate="true"
|
||||
OnKeyDown=SubmitIfEnter />
|
||||
<MudButton
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Tertiary"
|
||||
Disabled="@(!success)"
|
||||
Class="m-1"
|
||||
OnClick=SubmitLogin >
|
||||
@if (processing) {
|
||||
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||
<MudText>Processing</MudText>
|
||||
} else {
|
||||
<MudText>Log In</MudText>
|
||||
}
|
||||
</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>
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string? redirectUrl { get; set; }
|
||||
[Parameter]
|
||||
public string? redirectUrlSub { get; set; }
|
||||
private bool success;
|
||||
private bool processing = false;
|
||||
private bool processingLocal = false;
|
||||
private string[] errors = { };
|
||||
private string? username;
|
||||
private string? password;
|
||||
|
||||
private async Task SubmitLogin() {
|
||||
processing = true;
|
||||
if (string.IsNullOrWhiteSpace(username)) snackbar.Add("Username is required!", Severity.Error);
|
||||
else if (string.IsNullOrWhiteSpace(password)) snackbar.Add("Password is required!", Severity.Error);
|
||||
else {
|
||||
await authStateProvider.LoginAsync(username, password);
|
||||
if (!string.IsNullOrWhiteSpace(redirectUrl) && !string.IsNullOrWhiteSpace(redirectUrlSub)) {
|
||||
navManager.NavigateTo($"{redirectUrl}/{redirectUrlSub}");
|
||||
} else if (!string.IsNullOrWhiteSpace(redirectUrl)) {
|
||||
navManager.NavigateTo(redirectUrl);
|
||||
} else {
|
||||
navManager.NavigateTo("dashboard");
|
||||
}
|
||||
}
|
||||
processing = false;
|
||||
}
|
||||
|
||||
private async Task SubmitIfEnter(KeyboardEventArgs e) {
|
||||
if (e.Key == "Enter" && success) {
|
||||
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;
|
||||
}
|
||||
}
|
119
MesaFabApproval.Client/Pages/MRBAll.razor
Normal file
119
MesaFabApproval.Client/Pages/MRBAll.razor
Normal file
@ -0,0 +1,119 @@
|
||||
@page "/mrb/all"
|
||||
@using System.Globalization
|
||||
@inject IMRBService mrbService
|
||||
@inject ISnackbar snackbar
|
||||
@inject IMemoryCache cache
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
<PageTitle>MRB</PageTitle>
|
||||
|
||||
<MudPaper Class="p-2 m-2">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center">MRB List</MudText>
|
||||
</MudPaper>
|
||||
|
||||
@if (allMrbs is not null && allMrbs.Count() > 0) {
|
||||
<MudTable Items="@allMrbs"
|
||||
Class="m-2"
|
||||
Striped="true"
|
||||
Filter="new Func<MRB,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<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.OriginatorName)">
|
||||
Originator
|
||||
</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.CloseDate)">
|
||||
Closed 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="Originator">@context.OriginatorName</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>
|
||||
</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<MRB> allMrbs = new List<MRB>();
|
||||
|
||||
protected override async Task OnParametersSetAsync() {
|
||||
inProcess = true;
|
||||
try {
|
||||
if (mrbService is null) {
|
||||
throw new Exception("MRB service not injected!");
|
||||
} else {
|
||||
allMrbs = await mrbService.GetAllMRBs(false);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
snackbar.Add(ex.Message, Severity.Error);
|
||||
}
|
||||
inProcess = false;
|
||||
}
|
||||
|
||||
private bool FilterFuncForTable(MRB mrb) => FilterFunc(mrb, searchString);
|
||||
|
||||
private bool FilterFunc(MRB mrb, string searchString) {
|
||||
if (string.IsNullOrWhiteSpace(searchString))
|
||||
return true;
|
||||
if (mrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
|
||||
return true;
|
||||
if (mrb.OriginatorName.ToLower().Contains(searchString.Trim().ToLower()))
|
||||
return true;
|
||||
if (mrb.MRBNumber.ToString().Contains(searchString.Trim()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void GoTo(string page) {
|
||||
cache.Set("redirectUrl", page);
|
||||
navigationManager.NavigateTo(page);
|
||||
}
|
||||
}
|
1702
MesaFabApproval.Client/Pages/MRBSingle.razor
Normal file
1702
MesaFabApproval.Client/Pages/MRBSingle.razor
Normal file
File diff suppressed because it is too large
Load Diff
119
MesaFabApproval.Client/Pages/PCRBAll.razor
Normal file
119
MesaFabApproval.Client/Pages/PCRBAll.razor
Normal file
@ -0,0 +1,119 @@
|
||||
@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)">
|
||||
Plan#
|
||||
</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>
|
||||
<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="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);
|
||||
}
|
||||
}
|
263
MesaFabApproval.Client/Pages/PCRBSingle.razor
Normal file
263
MesaFabApproval.Client/Pages/PCRBSingle.razor
Normal file
@ -0,0 +1,263 @@
|
||||
@page "/pcrb/{planNumber}"
|
||||
@page "/pcrb/new"
|
||||
@using System.Text
|
||||
|
||||
@inject ISnackbar snackbar
|
||||
@inject IPCRBService pcrbService
|
||||
@inject IUserService userService
|
||||
@inject IMemoryCache cache
|
||||
@inject NavigationManager navigationManager
|
||||
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
||||
|
||||
<PageTitle>PCRB @planNumber</PageTitle>
|
||||
|
||||
<MudPaper Class="p-2 m-2 d-flex flex-row justify-content-between">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.ChevronLeft"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Dark"
|
||||
OnClick="@ReturnToAllPcrbs"
|
||||
Size="Size.Large" />
|
||||
<MudText Typo="Typo.h3" Align="Align.Center">PCRB @planNumber</MudText>
|
||||
<MudPaper Height="100%" Width="0.1%" Square="true" />
|
||||
</MudPaper>
|
||||
|
||||
@if (pcrb is not null) {
|
||||
<MudTimeline Class="mt-2 pt-2" TimelineOrientation="TimelineOrientation.Horizontal"
|
||||
TimelinePosition="TimelinePosition.Bottom">
|
||||
@for (int i = 0; i < PCRB.Stages.Length; i++) {
|
||||
Color color;
|
||||
if (pcrb.CurrentStep > i || pcrb.CurrentStep == (PCRB.Stages.Length - 1)) {
|
||||
color = Color.Success;
|
||||
} else if (pcrb.CurrentStep == i) {
|
||||
color = Color.Info;
|
||||
} else {
|
||||
color = Color.Dark;
|
||||
}
|
||||
|
||||
string stageName = PCRB.Stages[i];
|
||||
|
||||
<MudTimelineItem Color="@color" Variant="Variant.Filled">
|
||||
<MudText Align="Align.Center" Color="@color">@stageName</MudText>
|
||||
</MudTimelineItem>
|
||||
}
|
||||
</MudTimeline>
|
||||
|
||||
bool pcrbIsSubmitted = pcrb.InsertTimeStamp > DateTimeUtilities.MIN_DT;
|
||||
bool userIsOriginator = pcrb.OwnerID == authStateProvider.CurrentUser?.UserID;
|
||||
bool userIsAdmin = authStateProvider.CurrentUser is null ? false : authStateProvider.CurrentUser.IsAdmin;
|
||||
|
||||
<MudPaper Outlined="true"
|
||||
Class="p-2 m-2 d-flex flex-wrap gap-3 justify-content-center align-content-center"
|
||||
Elevation="10">
|
||||
@if (!pcrbIsSubmitted && !string.IsNullOrWhiteSpace(pcrb.Title)) {
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Tertiary"
|
||||
OnClick=SavePCRB>
|
||||
@if (saveInProcess) {
|
||||
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
||||
<MudText>Processing</MudText>
|
||||
} else {
|
||||
<MudText>Save</MudText>
|
||||
}
|
||||
</MudButton>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
@if (!pcrbIsSubmitted && GetIncompleteFields().Count() > 0) {
|
||||
IEnumerable<string> incompleteFields = GetIncompleteFields();
|
||||
StringBuilder errorBuilder = new();
|
||||
errorBuilder.Append($"Incomplete fields: {incompleteFields.First()}");
|
||||
for (int i = 1; i < incompleteFields.Count(); i++) {
|
||||
errorBuilder.Append($", {incompleteFields.ElementAt(i)}");
|
||||
}
|
||||
|
||||
<MudPaper Outlined Class="p-2 m-2">
|
||||
<MudText Align="Align.Center" Color="Color.Secondary" Typo="Typo.h6">
|
||||
@errorBuilder.ToString()
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
<MudPaper Outlined="true"
|
||||
Class="p-2 m-2 d-flex flex-wrap gap-3 justify-content-center align-content-start"
|
||||
Elevation="10">
|
||||
<MudTextField @bind-Value=pcrb.PlanNumber
|
||||
Text="@pcrb.PlanNumber.ToString()"
|
||||
T="int"
|
||||
Disabled="true"
|
||||
Label="Plan#"
|
||||
Required
|
||||
Variant="Variant.Outlined" />
|
||||
<MudTextField @bind-Value=pcrb.Title
|
||||
Text="@pcrb.Title"
|
||||
Disabled="@(pcrbIsSubmitted)"
|
||||
T="string"
|
||||
AutoGrow
|
||||
AutoFocus
|
||||
Immediate
|
||||
Clearable
|
||||
Required
|
||||
Variant="Variant.Outlined"
|
||||
Label="Title" />
|
||||
<MudSelect T="User"
|
||||
Label="Originator"
|
||||
Variant="Variant.Outlined"
|
||||
Required
|
||||
Clearable
|
||||
AnchorOrigin="Origin.BottomCenter"
|
||||
ToStringFunc="@UserToNameConverter"
|
||||
Disabled=@(pcrbIsSubmitted)
|
||||
@bind-Value=@selectedOwner>
|
||||
@foreach (User user in allActiveUsers.OrderBy(u => u.LastName)) {
|
||||
<MudSelectItem T="User" Value="@(user)" />
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect T="string"
|
||||
Variant="Variant.Outlined"
|
||||
Required
|
||||
Clearable
|
||||
AnchorOrigin="Origin.BottomCenter"
|
||||
Disabled="@pcrbIsSubmitted"
|
||||
@bind-Value="@pcrb.ChangeLevel"
|
||||
Text="@pcrb.ChangeLevel"
|
||||
Label="Change Level">
|
||||
<MudSelectItem Value="@("Global")" />
|
||||
<MudSelectItem Value="@("Other Site + Mesa")" />
|
||||
<MudSelectItem Value="@("Mesa")" />
|
||||
</MudSelect>
|
||||
<MudCheckBox Disabled="@pcrbIsSubmitted"
|
||||
Color="Color.Tertiary"
|
||||
@bind-Value=pcrb.IsITAR
|
||||
Label="Export Controlled"
|
||||
LabelPosition="LabelPosition.Start" />
|
||||
<MudTextField Disabled="true"
|
||||
T="string"
|
||||
Value="@DateTimeUtilities.GetDateAsStringMinDefault(pcrb.InsertTimeStamp)"
|
||||
Label="Submit Date"
|
||||
Variant="Variant.Outlined" />
|
||||
<MudTextField Disabled="true"
|
||||
T="string"
|
||||
Value="@DateTimeUtilities.GetDateAsStringMinDefault(pcrb.LastUpdateDate)"
|
||||
Label="Last Update"
|
||||
Variant="Variant.Outlined" />
|
||||
<MudTextField @bind-Value=pcrb.ChangeDescription
|
||||
Text="@pcrb.ChangeDescription"
|
||||
Disabled="@(pcrbIsSubmitted)"
|
||||
T="string"
|
||||
AutoGrow
|
||||
Immediate
|
||||
Clearable
|
||||
Required
|
||||
Variant="Variant.Outlined"
|
||||
Label="Description" />
|
||||
<MudTextField @bind-Value=pcrb.ReasonForChange
|
||||
Text="@pcrb.ReasonForChange"
|
||||
Disabled="@(pcrbIsSubmitted)"
|
||||
T="string"
|
||||
AutoGrow
|
||||
Immediate
|
||||
Clearable
|
||||
Required
|
||||
Variant="Variant.Outlined"
|
||||
Label="Reason For Change" />
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string planNumber { get; set; } = "";
|
||||
|
||||
private int planNumberInt = 0;
|
||||
private PCRB pcrb = null;
|
||||
|
||||
private IEnumerable<User> allActiveUsers = new List<User>();
|
||||
private User selectedOwner = null;
|
||||
|
||||
private bool processing = false;
|
||||
private bool saveInProcess = false;
|
||||
|
||||
protected override async Task OnParametersSetAsync() {
|
||||
processing = true;
|
||||
try {
|
||||
allActiveUsers = await userService.GetAllActiveUsers();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(planNumber) && Int32.TryParse(planNumber, out planNumberInt)) {
|
||||
pcrb = await pcrbService.GetPCRBByPlanNumber(planNumberInt, false);
|
||||
if (pcrb.OwnerID > 0) selectedOwner = await userService.GetUserByUserId(pcrb.OwnerID);
|
||||
} else {
|
||||
int ownerID = 0;
|
||||
string ownerName = string.Empty;
|
||||
if (authStateProvider.CurrentUser is not null) {
|
||||
selectedOwner = authStateProvider.CurrentUser;
|
||||
ownerID = authStateProvider.CurrentUser.UserID;
|
||||
ownerName = authStateProvider.CurrentUser.GetFullName();
|
||||
}
|
||||
|
||||
pcrb = new() {
|
||||
OwnerID = ownerID,
|
||||
OwnerName = ownerName,
|
||||
CurrentStep = 0
|
||||
};
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
snackbar.Add(ex.Message, Severity.Error);
|
||||
}
|
||||
processing = false;
|
||||
}
|
||||
|
||||
private Func<User, string> UserToNameConverter = u => u is null ? string.Empty : u.GetFullName();
|
||||
|
||||
private void ReturnToAllPcrbs() {
|
||||
cache.Set("redirectUrl", $"pcrb/all");
|
||||
navigationManager.NavigateTo("pcrb/all");
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetIncompleteFields() {
|
||||
List<string> incompleteFields = new();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(pcrb.Title))
|
||||
incompleteFields.Add("Title");
|
||||
if (selectedOwner is null || pcrb.OwnerID <= 0 || string.IsNullOrWhiteSpace(pcrb.OwnerName))
|
||||
incompleteFields.Add("Originator");
|
||||
if (string.IsNullOrWhiteSpace(pcrb.ChangeLevel))
|
||||
incompleteFields.Add("Change Level");
|
||||
if (string.IsNullOrWhiteSpace(pcrb.ChangeDescription))
|
||||
incompleteFields.Add("Description");
|
||||
if (string.IsNullOrWhiteSpace(pcrb.ReasonForChange))
|
||||
incompleteFields.Add("Reason For Change");
|
||||
|
||||
return incompleteFields;
|
||||
}
|
||||
|
||||
private async void SavePCRB() {
|
||||
saveInProcess = true;
|
||||
try {
|
||||
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
||||
|
||||
int initialPlanNumber = pcrb.PlanNumber;
|
||||
|
||||
pcrb.OwnerID = selectedOwner.UserID;
|
||||
pcrb.OwnerName = selectedOwner.GetFullName();
|
||||
|
||||
if (initialPlanNumber <= 0) {
|
||||
await pcrbService.CreateNewPCRB(pcrb);
|
||||
} else {
|
||||
await pcrbService.UpdatePCRB(pcrb);
|
||||
}
|
||||
|
||||
pcrb = await pcrbService.GetPCRBByTitle(pcrb.Title, true);
|
||||
|
||||
cache.Set("redirectUrl", $"pcrb/{pcrb.PlanNumber}");
|
||||
|
||||
saveInProcess = false;
|
||||
StateHasChanged();
|
||||
snackbar.Add($"PCRB {pcrb.PlanNumber} successfully saved", Severity.Success);
|
||||
|
||||
if (initialPlanNumber <= 0)
|
||||
navigationManager.NavigateTo($"pcrb/{pcrb.PlanNumber}");
|
||||
} catch (Exception ex) {
|
||||
saveInProcess = false;
|
||||
snackbar.Add($"Unable to save PCRB, because {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
}
|
64
MesaFabApproval.Client/Program.cs
Normal file
64
MesaFabApproval.Client/Program.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using MesaFabApproval.Client;
|
||||
using MesaFabApproval.Client.Utilities;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
|
||||
using MudBlazor.Services;
|
||||
using MesaFabApproval.Client.Services;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using System.Net.Http.Headers;
|
||||
using MudBlazor;
|
||||
|
||||
WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
|
||||
string _apiBaseUrl = builder.Configuration["FabApprovalApiBaseUrl"] ??
|
||||
throw new NullReferenceException("FabApprovalApiBaseUrl not found in config");
|
||||
|
||||
builder.Services.AddTransient<ApiHttpClientHandler>();
|
||||
|
||||
builder.Services
|
||||
.AddHttpClient("API_Handler", client => {
|
||||
client.BaseAddress = new Uri(_apiBaseUrl);
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
|
||||
});
|
||||
|
||||
builder.Services
|
||||
.AddHttpClient("API", client => {
|
||||
client.BaseAddress = new Uri(_apiBaseUrl);
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
|
||||
})
|
||||
.AddHttpMessageHandler<ApiHttpClientHandler>();
|
||||
|
||||
builder.Services.AddMemoryCache();
|
||||
|
||||
builder.Services.AddMudServices(config => {
|
||||
config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomCenter;
|
||||
config.SnackbarConfiguration.PreventDuplicates = true;
|
||||
config.SnackbarConfiguration.MaxDisplayedSnackbars = 5;
|
||||
config.SnackbarConfiguration.SnackbarVariant = Variant.Filled;
|
||||
config.SnackbarConfiguration.ShowCloseIcon = true;
|
||||
config.SnackbarConfiguration.VisibleStateDuration = 7000;
|
||||
config.SnackbarConfiguration.HideTransitionDuration = 500;
|
||||
config.SnackbarConfiguration.ShowTransitionDuration = 500;
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<ILocalStorageService, LocalStorageService>();
|
||||
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
||||
builder.Services.AddScoped<ICustomerService, CustomerService>();
|
||||
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<IApprovalService, ApprovalService>();
|
||||
builder.Services.AddScoped<MesaFabApprovalAuthStateProvider>();
|
||||
builder.Services.AddScoped<AuthenticationStateProvider>(sp =>
|
||||
sp.GetRequiredService<MesaFabApprovalAuthStateProvider>());
|
||||
|
||||
builder.Services.AddAuthorizationCore();
|
||||
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
|
||||
await builder.Build().RunAsync();
|
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<DeleteExistingFiles>true</DeleteExistingFiles>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<PublishProvider>FileSystem</PublishProvider>
|
||||
<PublishUrl>bin\Release\net8.0\browser-wasm\publish\</PublishUrl>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
|
||||
<ProjectGuid>34d52f44-a81f-4247-8180-16e204824a07</ProjectGuid>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
300
MesaFabApproval.Client/Services/ApprovalService.cs
Normal file
300
MesaFabApproval.Client/Services/ApprovalService.cs
Normal file
@ -0,0 +1,300 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace MesaFabApproval.Client.Services;
|
||||
|
||||
public interface IApprovalService {
|
||||
Task<int> GetRoleIdForRoleName(string roleName);
|
||||
Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId);
|
||||
Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId);
|
||||
Task CreateApproval(Approval approval);
|
||||
Task UpdateApproval(Approval approval);
|
||||
Task Approve(Approval approval);
|
||||
Task Deny(Approval approval);
|
||||
Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache);
|
||||
Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache);
|
||||
}
|
||||
|
||||
public class ApprovalService : IApprovalService {
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public ApprovalService(IMemoryCache cache, IHttpClientFactory httpClientFactory) {
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_httpClientFactory = httpClientFactory ??
|
||||
throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||
}
|
||||
|
||||
public async Task CreateApproval(Approval approval) {
|
||||
if (approval is null) throw new ArgumentNullException("approval cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Post, "approval");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
throw new Exception($"Unable to create approval, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
await GetApprovalsForIssueId(approval.IssueID, true);
|
||||
await GetApprovalsForUserId(approval.UserID, true);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache) {
|
||||
if (issueId <= 0) throw new ArgumentException($"{issueId} is not a valid issue ID");
|
||||
|
||||
IEnumerable<Approval>? approvals = null;
|
||||
|
||||
if (!bypassCache)
|
||||
approvals = _cache.Get<IEnumerable<Approval>>($"approvals{issueId}");
|
||||
|
||||
if (approvals is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/issue?issueId={issueId}&bypassCache={bypassCache}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
approvals = JsonSerializer.Deserialize<IEnumerable<Approval>>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse approvals from API response");
|
||||
|
||||
_cache.Set($"approvals{issueId}", approvals, DateTimeOffset.Now.AddMinutes(15));
|
||||
} else {
|
||||
throw new Exception($"Unable to get approvals, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Approval approval in approvals) {
|
||||
if (approval.ItemStatus < 0)
|
||||
approval.StatusMessage = "Denied";
|
||||
if (approval.ItemStatus == 0)
|
||||
approval.StatusMessage = "Assigned";
|
||||
if (approval.ItemStatus > 0)
|
||||
approval.StatusMessage = "Approved";
|
||||
}
|
||||
|
||||
return approvals;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache) {
|
||||
if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID");
|
||||
|
||||
IEnumerable<Approval>? approvals = null;
|
||||
|
||||
if (!bypassCache) approvals = _cache.Get<IEnumerable<Approval>>($"approvals{userId}");
|
||||
|
||||
if (approvals is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/user?userId={userId}&bypassCache={bypassCache}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
approvals = JsonSerializer.Deserialize<IEnumerable<Approval>>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse approvals from API response");
|
||||
|
||||
_cache.Set($"approvals{userId}", approvals, DateTimeOffset.Now.AddMinutes(15));
|
||||
} else {
|
||||
throw new Exception($"Unable to get approvals, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Approval approval in approvals) {
|
||||
if (approval.ItemStatus < 0)
|
||||
approval.StatusMessage = "Denied";
|
||||
if (approval.ItemStatus == 0)
|
||||
approval.StatusMessage = "Assigned";
|
||||
if (approval.ItemStatus > 0)
|
||||
approval.StatusMessage = "Approved";
|
||||
}
|
||||
|
||||
return approvals;
|
||||
}
|
||||
|
||||
public async Task UpdateApproval(Approval approval) {
|
||||
if (approval is null) throw new ArgumentNullException("approval cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
throw new Exception($"Unable to update approval, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
await GetApprovalsForIssueId(approval.IssueID, true);
|
||||
await GetApprovalsForUserId(approval.UserID, true);
|
||||
}
|
||||
|
||||
public async Task Approve(Approval approval) {
|
||||
if (approval is null) throw new ArgumentNullException("approval cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval/approve");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
throw new Exception($"Approval failed, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
await GetApprovalsForIssueId(approval.IssueID, true);
|
||||
await GetApprovalsForUserId(approval.UserID, true);
|
||||
}
|
||||
|
||||
public async Task Deny(Approval approval) {
|
||||
if (approval is null) throw new ArgumentNullException("approval cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval/deny");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
throw new Exception($"Denial failed, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GetRoleIdForRoleName(string roleName) {
|
||||
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("role name cannot be null or empty");
|
||||
|
||||
int roleId = _cache.Get<int>($"roleId{roleName}");
|
||||
|
||||
if (roleId <= 0) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/roleId?roleName={roleName}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
roleId = JsonSerializer.Deserialize<int>(responseContent, jsonSerializerOptions);
|
||||
|
||||
if (roleId <= 0)
|
||||
throw new Exception($"unable to find role ID for {roleName}");
|
||||
|
||||
_cache.Set($"roleId{roleName}", roleId, DateTimeOffset.Now.AddMinutes(15));
|
||||
} else {
|
||||
throw new Exception($"Unable to get role ID, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId) {
|
||||
if (string.IsNullOrWhiteSpace(subRoleName)) throw new ArgumentException("role name cannot be null or empty");
|
||||
if (roleId <= 0) throw new ArgumentException($"{roleId} is not a valid role ID");
|
||||
|
||||
IEnumerable<SubRole>? subRoles = _cache.Get<IEnumerable<SubRole>>($"subRoles{subRoleName}");
|
||||
|
||||
if (subRoles is null || subRoles.Count() <= 0) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/subRoles?subRoleName={subRoleName}&roleId={roleId}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
subRoles = JsonSerializer.Deserialize<IEnumerable<SubRole>>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse sub roles from API response");
|
||||
|
||||
if (subRoles is not null && subRoles.Count() > 0) {
|
||||
_cache.Set($"subRoles{subRoleName}", subRoles, DateTimeOffset.Now.AddMinutes(15));
|
||||
} else {
|
||||
throw new Exception($"unable to find sub roles for {subRoleName}");
|
||||
}
|
||||
} else {
|
||||
throw new Exception($"Unable to get sub roles, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
return subRoles;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId) {
|
||||
if (subRoleId <= 0) throw new ArgumentException($"{subRoleId} is not a valid sub role ID");
|
||||
|
||||
IEnumerable<User>? members = _cache.Get<IEnumerable<User>>($"approvalMembers{subRoleId}");
|
||||
|
||||
if (members is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/members?subRoleId={subRoleId}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
members = JsonSerializer.Deserialize<IEnumerable<User>>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse users from API response");
|
||||
|
||||
if (members is null || members.Count() <= 0)
|
||||
throw new Exception($"unable to find group members for sub role {subRoleId}");
|
||||
|
||||
_cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddMinutes(15));
|
||||
} else {
|
||||
throw new Exception($"Unable to get group members, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
}
|
232
MesaFabApproval.Client/Services/AuthenticationService.cs
Normal file
232
MesaFabApproval.Client/Services/AuthenticationService.cs
Normal file
@ -0,0 +1,232 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace MesaFabApproval.Client.Services;
|
||||
|
||||
public interface IAuthenticationService {
|
||||
Task<ClaimsPrincipal> SendAuthenticationRequest(string loginId, string password);
|
||||
Task<ClaimsPrincipal> AttemptLocalUserAuth();
|
||||
Task<ClaimsPrincipal> FetchAuthState();
|
||||
Task ClearTokens();
|
||||
Task ClearCurrentUser();
|
||||
Task SetTokens(string jwt, string refreshToken);
|
||||
Task SetLoginId(string loginId);
|
||||
Task SetCurrentUser(User user);
|
||||
Task<User> GetCurrentUser();
|
||||
Task<AuthTokens> GetAuthTokens();
|
||||
Task<string> GetLoginId();
|
||||
ClaimsPrincipal GetClaimsPrincipalFromJwt(string jwt);
|
||||
}
|
||||
|
||||
public class AuthenticationService : IAuthenticationService {
|
||||
private readonly ILocalStorageService _localStorageService;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public AuthenticationService(ILocalStorageService localStorageService,
|
||||
IMemoryCache cache,
|
||||
IHttpClientFactory httpClientFactory) {
|
||||
_localStorageService = localStorageService ??
|
||||
throw new ArgumentNullException("ILocalStorageService not injected");
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||
}
|
||||
|
||||
public async Task<ClaimsPrincipal> SendAuthenticationRequest(string loginId, string password) {
|
||||
if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentException("loginId cannot be null or empty");
|
||||
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("password cannot be null or empty");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
AuthAttempt authAttempt = new() {
|
||||
LoginID = loginId,
|
||||
Password = password
|
||||
};
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/login");
|
||||
|
||||
request.Content = new StringContent(JsonSerializer.Serialize(authAttempt),
|
||||
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 {loginId} not authorized");
|
||||
|
||||
await SetLoginId(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 {loginId}, because {httpResponseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
string? jwt = _cache.Get<string>("MesaFabApprovalJwt");
|
||||
|
||||
if (jwt is null) jwt = await _localStorageService.GetItem("MesaFabApprovalJwt");
|
||||
|
||||
if (jwt is null) throw new Exception("Unable to find JWT");
|
||||
|
||||
ClaimsPrincipal principal = GetClaimsPrincipalFromJwt(jwt);
|
||||
|
||||
return principal;
|
||||
}
|
||||
|
||||
public async Task ClearTokens() {
|
||||
_cache.Remove("MesaFabApprovalJwt");
|
||||
await _localStorageService.RemoveItem("MesaFabApprovalJwt");
|
||||
_cache.Remove("MesaFabApprovalRefreshToken");
|
||||
await _localStorageService.RemoveItem("MesaFabApprovalRefreshToken");
|
||||
}
|
||||
|
||||
public async Task SetTokens(string jwt, string refreshToken) {
|
||||
if (string.IsNullOrWhiteSpace(jwt)) throw new ArgumentNullException("JWT cannot be null or empty");
|
||||
if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException("Refresh token cannot be null or empty");
|
||||
|
||||
_cache.Set<string>("MesaFabApprovalJwt", jwt);
|
||||
await _localStorageService.AddItem("MesaFabApprovalJwt", jwt);
|
||||
_cache.Set<string>("MesaFabApprovalRefreshToken", refreshToken);
|
||||
await _localStorageService.AddItem("MesaFabApprovalRefreshToken", refreshToken);
|
||||
}
|
||||
|
||||
public async Task SetLoginId(string loginId) {
|
||||
if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentNullException("LoginId cannot be null or empty");
|
||||
|
||||
_cache.Set<string>("MesaFabApprovalUserId", loginId);
|
||||
await _localStorageService.AddItem("MesaFabApprovalUserId", loginId);
|
||||
}
|
||||
|
||||
public async Task SetCurrentUser(User user) {
|
||||
if (user is null) throw new ArgumentNullException("User cannot be null");
|
||||
|
||||
_cache.Set<User>("MesaFabApprovalCurrentUser", user);
|
||||
await _localStorageService.AddItem<User>("MesaFabApprovalCurrentUser", user);
|
||||
}
|
||||
|
||||
public async Task ClearCurrentUser() {
|
||||
_cache.Remove("MesaFabApprovalCurrentUser");
|
||||
await _localStorageService.RemoveItem("MesaFabApprovalCurrentUser");
|
||||
_cache.Remove("MesaFabApprovalUserId");
|
||||
await _localStorageService.RemoveItem("MesaFabApprovalUserId");
|
||||
}
|
||||
|
||||
public async Task<User> GetCurrentUser() {
|
||||
User? currentUser = null;
|
||||
|
||||
currentUser = _cache.Get<User>("MesaFabApprovalCurrentUser") ??
|
||||
await _localStorageService.GetItem<User>("MesaFabApprovalCurrentUser");
|
||||
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
public async Task<AuthTokens> GetAuthTokens() {
|
||||
AuthTokens? authTokens = null;
|
||||
|
||||
string? jwt = _cache.Get<string>("MesaFabApprovalJwt");
|
||||
if (jwt is null) jwt = await _localStorageService.GetItem("MesaFabApprovalJwt");
|
||||
|
||||
string? refreshToken = _cache.Get<string>("MesaFabApprovalRefreshToken");
|
||||
if (refreshToken is null) refreshToken = await _localStorageService.GetItem("MesaFabApprovalRefreshToken");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(jwt) && !string.IsNullOrWhiteSpace(refreshToken)) {
|
||||
authTokens = new() {
|
||||
JwtToken = jwt,
|
||||
RefreshToken = refreshToken
|
||||
};
|
||||
}
|
||||
|
||||
return authTokens;
|
||||
}
|
||||
|
||||
public async Task<string> GetLoginId() {
|
||||
string? loginId = _cache.Get<string>("MesaFabApprovalUserId");
|
||||
if (loginId is null) loginId = await _localStorageService.GetItem("MesaFabApprovalUserId");
|
||||
|
||||
return loginId;
|
||||
}
|
||||
|
||||
public ClaimsPrincipal GetClaimsPrincipalFromJwt(string jwt) {
|
||||
if (string.IsNullOrWhiteSpace(jwt)) throw new ArgumentException("JWT cannot be null or empty");
|
||||
|
||||
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
||||
if (!tokenHandler.CanReadToken(jwt)) {
|
||||
throw new Exception("Unable to parse JWT from API");
|
||||
}
|
||||
|
||||
JwtSecurityToken jwtSecurityToken = tokenHandler.ReadJwtToken(jwt);
|
||||
|
||||
ClaimsIdentity identity = new ClaimsIdentity(jwtSecurityToken.Claims, "MesaFabApprovalWasm");
|
||||
|
||||
return new(identity);
|
||||
}
|
||||
}
|
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);
|
||||
}
|
||||
}
|
755
MesaFabApproval.Client/Services/MRBService.cs
Normal file
755
MesaFabApproval.Client/Services/MRBService.cs
Normal file
@ -0,0 +1,755 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
using MesaFabApproval.Shared.Utilities;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
using MudBlazor;
|
||||
|
||||
namespace MesaFabApproval.Client.Services;
|
||||
|
||||
public interface IMRBService {
|
||||
Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache);
|
||||
Task<MRB> GetMRBById(int id, bool bypassCache = false);
|
||||
Task<MRB> GetMRBByTitle(string title, bool bypassCache);
|
||||
Task CreateNewMRB(MRB mrb);
|
||||
Task RecallMRB(MRB mrb, User recallUser);
|
||||
Task DeleteMRB(int mrbNumber);
|
||||
Task UpdateMRB(MRB mrb);
|
||||
Task SubmitForApproval(MRB mrb);
|
||||
Task GenerateActionTasks(MRB mrb, MRBAction action);
|
||||
Task CreateMRBAction(MRBAction mrbAction);
|
||||
Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache);
|
||||
Task UpdateMRBAction(MRBAction mrbAction);
|
||||
Task DeleteMRBAction(MRBAction mrbAction);
|
||||
Task UploadAttachments(IEnumerable<IBrowserFile> files, int mrbNumber);
|
||||
Task UploadActionAttachments(IEnumerable<IBrowserFile> files, int actionId);
|
||||
Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
||||
Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache);
|
||||
Task DeleteAttachment(MRBAttachment attachment);
|
||||
Task NotifyNewApprovals(MRB mrb);
|
||||
Task NotifyApprovers(MRBNotification notification);
|
||||
Task NotifyOriginator(MRBNotification notification);
|
||||
Task NotifyQAPreApprover(MRBNotification notification);
|
||||
Task<bool> NumberIsValid(int number);
|
||||
}
|
||||
|
||||
public class MRBService : IMRBService {
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly ISnackbar _snackbar;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IApprovalService _approvalService;
|
||||
|
||||
public MRBService(IMemoryCache cache,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ISnackbar snackbar,
|
||||
IUserService userService,
|
||||
IApprovalService approvalService) {
|
||||
_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");
|
||||
_approvalService = approvalService ?? throw new ArgumentNullException("IApprovalService not injected");
|
||||
}
|
||||
|
||||
public async Task CreateNewMRB(MRB mrb) {
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Post, "mrb/new");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrb),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
throw new Exception($"Unable to generate new MRB, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
mrb = await GetMRBByTitle(mrb.Title, true);
|
||||
|
||||
_cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
_cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
|
||||
IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||
if (allMrbs is not null) {
|
||||
List<MRB> mrbList = allMrbs.ToList();
|
||||
mrbList.Add(mrb);
|
||||
_cache.Set("allMrbs", mrbList);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
IEnumerable<MRB>? allMRBs = null;
|
||||
if (!bypassCache) allMRBs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||
|
||||
if (allMRBs is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/all?bypassCache={bypassCache}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
allMRBs = JsonSerializer.Deserialize<IEnumerable<MRB>>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse MRBs from API response");
|
||||
|
||||
_cache.Set($"allMrbs", allMRBs, DateTimeOffset.Now.AddMinutes(15));
|
||||
} else {
|
||||
throw new Exception($"Unable to get all MRBs, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
return allMRBs;
|
||||
} catch (Exception) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
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}");
|
||||
|
||||
MRB? mrb = null;
|
||||
if (!bypassCache)
|
||||
mrb = _cache.Get<MRB>($"mrb{id}");
|
||||
|
||||
if (mrb is null && !bypassCache) mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.MRBNumber == id);
|
||||
|
||||
if (mrb is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/getById?id={id}&bypassCache={bypassCache}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
mrb = JsonSerializer.Deserialize<MRB>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse MRB from API response");
|
||||
|
||||
_cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
} else {
|
||||
throw new Exception($"Unable to get MRB by Id, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
return mrb;
|
||||
}
|
||||
|
||||
public async Task<MRB> GetMRBByTitle(string title, bool bypassCache) {
|
||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty");
|
||||
|
||||
MRB? mrb = null;
|
||||
if (!bypassCache) mrb = _cache.Get<MRB>($"mrb{title}");
|
||||
|
||||
if (mrb is null && !bypassCache)
|
||||
mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.Title.Equals(title));
|
||||
|
||||
if (mrb is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/getByTitle?title={title}&bypassCache={bypassCache}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
mrb = JsonSerializer.Deserialize<MRB>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse MRB from API response");
|
||||
|
||||
_cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
} else {
|
||||
throw new Exception($"Unable to get MRB by title, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
return mrb;
|
||||
}
|
||||
|
||||
public async Task UpdateMRB(MRB mrb) {
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Put, $"mrb");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrb),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
throw new Exception($"Unable to update MRB, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
_cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
_cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1));
|
||||
|
||||
IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs");
|
||||
if (allMrbs is not null) {
|
||||
List<MRB> mrbList = allMrbs.ToList();
|
||||
mrbList.RemoveAll(m => m.MRBNumber == mrb.MRBNumber);
|
||||
mrbList.Add(mrb);
|
||||
_cache.Set("allMrbs", mrbList);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateMRBAction(MRBAction mrbAction) {
|
||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Post, "mrbAction");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrbAction),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode)
|
||||
throw new Exception($"Unable to create new MRB action, because {responseMessage.ReasonPhrase}");
|
||||
|
||||
await GetMRBActionsForMRB(mrbAction.MRBNumber, true);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache) {
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||
|
||||
IEnumerable<MRBAction>? mrbActions = null;
|
||||
if (!bypassCache)
|
||||
mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbNumber}");
|
||||
|
||||
if (mrbActions is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrbAction?mrbNumber={mrbNumber}&bypassCache={bypassCache}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
mrbActions = JsonSerializer.Deserialize<IEnumerable<MRBAction>>(responseContent, jsonSerializerOptions) ??
|
||||
new List<MRBAction>();
|
||||
|
||||
if (mrbActions.Count() > 0)
|
||||
_cache.Set($"mrbActions{mrbNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(5));
|
||||
} else {
|
||||
throw new Exception($"Unable to get MRB {mrbNumber} actions, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
return mrbActions;
|
||||
}
|
||||
|
||||
public async Task UpdateMRBAction(MRBAction mrbAction) {
|
||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Put, $"mrbAction");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrbAction),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
throw new Exception($"Unable to update MRB action, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
IEnumerable<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbAction.MRBNumber}");
|
||||
if (mrbActions is not null) {
|
||||
List<MRBAction> mrbActionList = mrbActions.ToList();
|
||||
mrbActionList.RemoveAll(a => a.ActionID == mrbAction.ActionID);
|
||||
mrbActionList.Add(mrbAction);
|
||||
_cache.Set($"mrbActions{mrbAction.MRBNumber}", mrbActionList, DateTimeOffset.Now.AddMinutes(5));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteMRBAction(MRBAction mrbAction) {
|
||||
if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null");
|
||||
if (mrbAction.ActionID <= 0) throw new ArgumentException($"{mrbAction.ActionID} is not a valid MRBActionID");
|
||||
if (mrbAction.MRBNumber <= 0) throw new ArgumentException($"{mrbAction.MRBNumber} is not a valid MRBNumber");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
string route = $"mrbAction?mrbActionID={mrbAction.ActionID}&mrbNumber={mrbAction.MRBNumber}";
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Delete, route);
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode)
|
||||
throw new Exception($"Unable to delete MRB action {mrbAction.ActionID}");
|
||||
|
||||
IEnumerable<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbAction.MRBNumber}");
|
||||
if (mrbActions is not null) {
|
||||
List<MRBAction> mrbActionList = mrbActions.ToList();
|
||||
mrbActionList.RemoveAll(a => a.ActionID == mrbAction.ActionID);
|
||||
_cache.Set($"mrbActions{mrbAction.MRBNumber}", mrbActionList, DateTimeOffset.Now.AddMinutes(5));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UploadAttachments(IEnumerable<IBrowserFile> files, int mrbNumber) {
|
||||
if (files is null) throw new ArgumentNullException("Files cannot be null");
|
||||
if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty");
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/attach?mrbNumber={mrbNumber}");
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#");
|
||||
|
||||
IEnumerable<MRBAttachment>? mrbAttachments = null;
|
||||
if (!bypassCache)
|
||||
mrbAttachments = _cache.Get<IEnumerable<MRBAttachment>>($"mrbAttachments{mrbNumber}");
|
||||
|
||||
if (mrbAttachments is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/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
|
||||
};
|
||||
|
||||
mrbAttachments = JsonSerializer.Deserialize<IEnumerable<MRBAttachment>>(responseContent, jsonSerializerOptions) ??
|
||||
new List<MRBAttachment>();
|
||||
|
||||
if (mrbAttachments.Count() > 0)
|
||||
_cache.Set($"mrbAttachments{mrbNumber}", mrbAttachments, DateTimeOffset.Now.AddMinutes(5));
|
||||
} else {
|
||||
throw new Exception($"Unable to get MRB {mrbNumber} attachments, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (attachment is null) throw new ArgumentNullException("MRB attachment cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Delete, "mrb/attach");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(attachment),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode)
|
||||
throw new Exception($"Unable to delete MRB attachment");
|
||||
|
||||
IEnumerable<MRBAttachment>? mrbAttachments = _cache.Get<IEnumerable<MRBAttachment>>($"mrbAttachments{attachment.MRBNumber}");
|
||||
if (mrbAttachments is not null) {
|
||||
List<MRBAttachment> mrbAttachmentList = mrbAttachments.ToList();
|
||||
mrbAttachmentList.RemoveAll(a => a.AttachmentID == attachment.AttachmentID);
|
||||
_cache.Set($"mrbAttachments{attachment.MRBNumber}", mrbAttachmentList, DateTimeOffset.Now.AddMinutes(5));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SubmitForApproval(MRB mrb) {
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
string roleName = "QA_PRE_APPROVAL";
|
||||
string subRoleName = "QA_PRE_APPROVAL";
|
||||
|
||||
if (mrb.StageNo > 1) {
|
||||
roleName = "MRB Approver";
|
||||
subRoleName = "MRBApprover";
|
||||
}
|
||||
|
||||
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> members = await _approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
||||
|
||||
foreach (User member in members) {
|
||||
Approval approval = new() {
|
||||
IssueID = mrb.MRBNumber,
|
||||
RoleName = roleName,
|
||||
SubRole = subRole.SubRoleName,
|
||||
UserID = member.UserID,
|
||||
SubRoleID = subRole.SubRoleID,
|
||||
AssignedDate = DateTime.Now,
|
||||
Step = mrb.StageNo
|
||||
};
|
||||
|
||||
await _approvalService.CreateApproval(approval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task GenerateActionTasks(MRB mrb, MRBAction action) {
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
if (action is null) throw new ArgumentNullException("MRBAction cannot be null");
|
||||
|
||||
string roleName = "MRB Actions";
|
||||
string subRoleName = "MRBActions";
|
||||
|
||||
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> members = await _approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
||||
|
||||
foreach (User member in members) {
|
||||
Approval approval = new() {
|
||||
IssueID = action.MRBNumber,
|
||||
RoleName = roleName,
|
||||
SubRole = subRole.SubRoleName,
|
||||
UserID = member.UserID,
|
||||
SubRoleID = subRole.SubRoleID,
|
||||
AssignedDate = DateTime.Now,
|
||||
Step = mrb.StageNo,
|
||||
SubRoleCategoryItem = subRole.SubRoleCategoryItem,
|
||||
TaskID = action.ActionID
|
||||
};
|
||||
|
||||
await _approvalService.CreateApproval(approval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task NotifyNewApprovals(MRB mrb) {
|
||||
if (mrb is null) throw new ArgumentNullException("MRB cannot be null");
|
||||
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/notify/new-approvals");
|
||||
|
||||
requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrb),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode)
|
||||
throw new Exception($"Unable to notify new MRB approvers, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
public async Task NotifyApprovers(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/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 MRB approvers, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
|
||||
public async Task NotifyOriginator(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/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 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}");
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
using System.Security.Claims;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
|
||||
using MudBlazor;
|
||||
|
||||
namespace MesaFabApproval.Client.Services;
|
||||
|
||||
public class MesaFabApprovalAuthStateProvider : AuthenticationStateProvider, IDisposable {
|
||||
private readonly IAuthenticationService _authService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ISnackbar _snackbar;
|
||||
|
||||
public User? CurrentUser { get; private set; }
|
||||
|
||||
public MesaFabApprovalAuthStateProvider(IAuthenticationService authService,
|
||||
ISnackbar snackbar,
|
||||
IUserService userService) {
|
||||
_authService = authService ??
|
||||
throw new ArgumentNullException("IAuthenticationService not injected");
|
||||
_snackbar = snackbar ??
|
||||
throw new ArgumentNullException("ISnackbar not injected");
|
||||
_userService = userService ??
|
||||
throw new ArgumentNullException("IUserService not injected");
|
||||
AuthenticationStateChanged += OnAuthenticationStateChangedAsync;
|
||||
}
|
||||
|
||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync() {
|
||||
ClaimsPrincipal principal = new();
|
||||
try {
|
||||
principal = await _authService.FetchAuthState();
|
||||
|
||||
CurrentUser = await _authService.GetCurrentUser();
|
||||
|
||||
return new(principal);
|
||||
} catch (Exception ex) {
|
||||
return new(new ClaimsPrincipal());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StateHasChanged(ClaimsPrincipal principal) {
|
||||
if (principal is null) throw new ArgumentNullException("ClaimsPrincipal cannot be null");
|
||||
|
||||
CurrentUser = await _authService.GetCurrentUser();
|
||||
|
||||
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)));
|
||||
}
|
||||
|
||||
public async Task LoginAsync(string loginId, string password) {
|
||||
try {
|
||||
if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentException("LoginId cannot be null or empty");
|
||||
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Password cannot be null or empty");
|
||||
|
||||
ClaimsPrincipal principal = await _authService.SendAuthenticationRequest(loginId, password);
|
||||
|
||||
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 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() {
|
||||
CurrentUser = null;
|
||||
await _authService.ClearTokens();
|
||||
await _authService.ClearCurrentUser();
|
||||
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new())));
|
||||
}
|
||||
|
||||
public void Dispose() => AuthenticationStateChanged -= OnAuthenticationStateChangedAsync;
|
||||
|
||||
private async void OnAuthenticationStateChangedAsync(Task<AuthenticationState> task) {
|
||||
try {
|
||||
AuthenticationState authenticationState = await task;
|
||||
if (authenticationState is not null) {
|
||||
ClaimsPrincipal principal = await _authService.FetchAuthState();
|
||||
|
||||
CurrentUser = await _authService.GetCurrentUser();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// _snackbar.Add($"Unable to fetch authentication state, because {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
}
|
263
MesaFabApproval.Client/Services/PCRBService.cs
Normal file
263
MesaFabApproval.Client/Services/PCRBService.cs
Normal file
@ -0,0 +1,263 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
using MudBlazor;
|
||||
|
||||
namespace MesaFabApproval.Client.Services;
|
||||
|
||||
public interface IPCRBService {
|
||||
Task<string> IdIsValid(string 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);
|
||||
}
|
||||
|
||||
public class PCRBService : IPCRBService {
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly ISnackbar _snackbar;
|
||||
|
||||
public PCRBService(IMemoryCache cache, IHttpClientFactory httpClientFactory, ISnackbar snackbar) {
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||
_snackbar = snackbar ?? throw new ArgumentNullException("ISnackbar 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<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("MRB 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/delete?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);
|
||||
}
|
||||
}
|
208
MesaFabApproval.Client/Services/UserService.cs
Normal file
208
MesaFabApproval.Client/Services/UserService.cs
Normal file
@ -0,0 +1,208 @@
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Http;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace MesaFabApproval.Client.Services;
|
||||
|
||||
public interface IUserService {
|
||||
ClaimsPrincipal GetClaimsPrincipalFromUser(User user);
|
||||
string GetLoginIdFromClaimsPrincipal(ClaimsPrincipal claimsPrincipal);
|
||||
Task<User> GetUserFromClaimsPrincipal(ClaimsPrincipal claimsPrincipal);
|
||||
Task<User> GetUserByUserId(int userId);
|
||||
Task<User> GetUserByLoginId(string loginId);
|
||||
Task<IEnumerable<User>> GetAllActiveUsers();
|
||||
Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item);
|
||||
}
|
||||
|
||||
public class UserService : IUserService {
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public UserService(IMemoryCache cache, IHttpClientFactory httpClientFactory) {
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected");
|
||||
}
|
||||
|
||||
public ClaimsPrincipal GetClaimsPrincipalFromUser(User user) {
|
||||
if (user is null) throw new ArgumentNullException("user cannot be null");
|
||||
|
||||
List<Claim> claims = new() {
|
||||
new Claim(nameof(user.LoginID), user.LoginID)
|
||||
};
|
||||
|
||||
if (user.IsManager) claims.Add(new Claim(ClaimTypes.Role, "manager"));
|
||||
if (user.IsAdmin) claims.Add(new Claim(ClaimTypes.Role, "admin"));
|
||||
|
||||
ClaimsIdentity identity = new ClaimsIdentity(claims, "MesaFabApprovalWasm");
|
||||
|
||||
return new ClaimsPrincipal(identity);
|
||||
}
|
||||
|
||||
public async Task<User> GetUserByUserId(int userId) {
|
||||
if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID");
|
||||
|
||||
User? user = _cache.Get<User>($"user{userId}");
|
||||
|
||||
if (user is null)
|
||||
user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.UserID == userId);
|
||||
|
||||
if (user is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"user/userId?userId={userId}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
user = JsonSerializer.Deserialize<User>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse user from API response");
|
||||
|
||||
_cache.Set($"user{userId}", user, DateTimeOffset.Now.AddDays(1));
|
||||
} else {
|
||||
throw new Exception($"GetUserByUserId failed for user {userId}, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
if (user is null) throw new Exception($"User for userId {userId} not found");
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<User> GetUserByLoginId(string loginId) {
|
||||
if (string.IsNullOrWhiteSpace(loginId))
|
||||
throw new ArgumentNullException("loginId cannot be null or empty");
|
||||
|
||||
User? user = _cache.Get<User>($"user{loginId}");
|
||||
|
||||
if (user is null)
|
||||
user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.LoginID == loginId);
|
||||
|
||||
if (user is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"user/loginId?loginId={loginId}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
user = JsonSerializer.Deserialize<User>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse user from API response");
|
||||
|
||||
_cache.Set($"user{loginId}", user, DateTimeOffset.Now.AddDays(1));
|
||||
} else {
|
||||
throw new Exception($"GetUserByLoginId failed for {loginId}, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
if (user is null) throw new Exception($"User for loginId {loginId} not found");
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<User>> GetAllActiveUsers() {
|
||||
IEnumerable<User>? activeUsers = _cache.Get<IEnumerable<User>>("allActiveUsers");
|
||||
|
||||
if (activeUsers is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"users/active");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
activeUsers = JsonSerializer.Deserialize<IEnumerable<User>>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse user from API response");
|
||||
|
||||
_cache.Set("allActiveUsers", activeUsers, DateTimeOffset.Now.AddHours(1));
|
||||
} else {
|
||||
throw new Exception($"Cannot get all active users, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
if (activeUsers is null)
|
||||
throw new Exception("unable to fetch all active users");
|
||||
|
||||
return activeUsers;
|
||||
}
|
||||
|
||||
public string GetLoginIdFromClaimsPrincipal(ClaimsPrincipal principal) {
|
||||
if (principal is null) throw new ArgumentNullException("Principal cannot be null");
|
||||
|
||||
Claim loginIdClaim = principal.FindFirst("LoginID") ??
|
||||
throw new Exception("LoginID claim not found in principal");
|
||||
|
||||
string loginId = loginIdClaim.Value;
|
||||
|
||||
return loginId;
|
||||
}
|
||||
|
||||
public async Task<User> GetUserFromClaimsPrincipal(ClaimsPrincipal claimsPrincipal) {
|
||||
if (claimsPrincipal is null) throw new ArgumentNullException("ClaimsPrincipal cannot be null");
|
||||
|
||||
Claim loginIdClaim = claimsPrincipal.FindFirst("LoginID") ??
|
||||
throw new Exception("LoginID claim not found in principal");
|
||||
|
||||
string loginId = loginIdClaim.Value ??
|
||||
throw new Exception("LoginID claim value is null");
|
||||
|
||||
User user = await GetUserByLoginId(loginId) ??
|
||||
throw new Exception($"User for loginId {loginId} not found");
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item) {
|
||||
if (string.IsNullOrWhiteSpace(item)) throw new ArgumentException("SubRoleCategoryItem cannot be null or empty");
|
||||
|
||||
IEnumerable<int>? approverUserIds = _cache.Get<IEnumerable<int>>($"approvers{item}");
|
||||
|
||||
if (approverUserIds is null) {
|
||||
HttpClient httpClient = _httpClientFactory.CreateClient("API");
|
||||
|
||||
HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approver?subRoleCategoryItem={item}");
|
||||
|
||||
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) {
|
||||
string responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions jsonSerializerOptions = new() {
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
approverUserIds = JsonSerializer.Deserialize<IEnumerable<int>>(responseContent, jsonSerializerOptions) ??
|
||||
throw new Exception("Unable to parse user from API response");
|
||||
|
||||
_cache.Set($"approvers{item}", approverUserIds, DateTimeOffset.Now.AddDays(1));
|
||||
} else {
|
||||
throw new Exception($"Unable to get approvers for SubRoleCategoryItem {item}, because {responseMessage.ReasonPhrase}");
|
||||
}
|
||||
}
|
||||
|
||||
if (approverUserIds is null) throw new Exception($"Approvers for SubRoleCategoryItem {item} not found");
|
||||
|
||||
return approverUserIds;
|
||||
}
|
||||
}
|
129
MesaFabApproval.Client/Utilities/ApiHttpClientHandler.cs
Normal file
129
MesaFabApproval.Client/Utilities/ApiHttpClientHandler.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Text;
|
||||
|
||||
using MesaFabApproval.Shared.Models;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.Net.Http.Headers;
|
||||
using MesaFabApproval.Client.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace MesaFabApproval.Client.Utilities;
|
||||
|
||||
public class ApiHttpClientHandler : DelegatingHandler {
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IAuthenticationService _authService;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly ISnackbar _snackbar;
|
||||
private readonly MesaFabApprovalAuthStateProvider _authStateProvider;
|
||||
private readonly NavigationManager _navigationManager;
|
||||
|
||||
private readonly string _apiBaseUrl;
|
||||
|
||||
public ApiHttpClientHandler(IMemoryCache cache,
|
||||
IConfiguration config,
|
||||
IAuthenticationService authService,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ISnackbar snackbar,
|
||||
MesaFabApprovalAuthStateProvider authStateProvider,
|
||||
NavigationManager navigationManager) {
|
||||
_cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected");
|
||||
_apiBaseUrl = config["FabApprovalApiBaseUrl"] ??
|
||||
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 ??
|
||||
throw new ArgumentNullException("IAuthenticationService not injected");
|
||||
_authStateProvider = authStateProvider ??
|
||||
throw new ArgumentNullException("MesaFabApprovalAuthStateProvider not injected");
|
||||
_navigationManager = navigationManager ??
|
||||
throw new ArgumentNullException("NavigationManager not injected");
|
||||
}
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage requestMessage,
|
||||
CancellationToken cancellationToken) {
|
||||
AuthTokens? authTokens = await _authService.GetAuthTokens();
|
||||
|
||||
HttpRequestMessage initialRequestMessage = new() {
|
||||
Content = requestMessage.Content,
|
||||
Method = requestMessage.Method,
|
||||
RequestUri = requestMessage.RequestUri
|
||||
};
|
||||
|
||||
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)) {
|
||||
string? loginId = await _authService.GetLoginId();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(loginId)) {
|
||||
AuthAttempt authAttempt = new() {
|
||||
LoginID = loginId,
|
||||
AuthTokens = authTokens
|
||||
};
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/refresh");
|
||||
|
||||
request.Content = new StringContent(JsonSerializer.Serialize(authAttempt),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
if (authTokens is not null) {
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken);
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponseMessage = await refreshClient.SendAsync(request, cancellationToken);
|
||||
|
||||
string responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
|
||||
if (httpResponseMessage.IsSuccessStatusCode) {
|
||||
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 {loginId} not authorized");
|
||||
|
||||
if (loginResult.AuthTokens is not null) {
|
||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", loginResult.AuthTokens.JwtToken);
|
||||
await _authService.SetTokens(loginResult.AuthTokens.JwtToken, loginResult.AuthTokens.RefreshToken);
|
||||
}
|
||||
|
||||
if (loginResult.User is not null)
|
||||
await _authService.SetCurrentUser(loginResult.User);
|
||||
} else {
|
||||
await _authStateProvider.Logout();
|
||||
|
||||
string? redirectUrl = _cache.Get<string>("redirectUrl");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(redirectUrl)) {
|
||||
_navigationManager.NavigateTo($"login/{redirectUrl}");
|
||||
} else {
|
||||
_navigationManager.NavigateTo("login");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return await base.SendAsync(requestMessage, cancellationToken);
|
||||
}
|
||||
|
||||
initialClient.Dispose();
|
||||
refreshClient.Dispose();
|
||||
|
||||
return responseMessage;
|
||||
}
|
||||
}
|
22
MesaFabApproval.Client/_Imports.razor
Normal file
22
MesaFabApproval.Client/_Imports.razor
Normal file
@ -0,0 +1,22 @@
|
||||
@using System.IdentityModel.Tokens.Jwt
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Http
|
||||
@using Microsoft.JSInterop
|
||||
@using MesaFabApproval.Client
|
||||
@using MesaFabApproval.Client.Layout
|
||||
@using MesaFabApproval.Client.Pages.Components
|
||||
@using MesaFabApproval.Client.Services
|
||||
@using MesaFabApproval.Shared.Utilities
|
||||
@using MesaFabApproval.Shared.Models
|
||||
@using MudBlazor
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using System.Security.Claims
|
||||
@using Microsoft.Extensions.Caching.Memory
|
||||
@using Microsoft.AspNetCore.WebUtilities
|
||||
@attribute [Authorize]
|
BIN
MesaFabApproval.Client/wwwroot/android-chrome-192x192.png
Normal file
BIN
MesaFabApproval.Client/wwwroot/android-chrome-192x192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
BIN
MesaFabApproval.Client/wwwroot/android-chrome-512x512.png
Normal file
BIN
MesaFabApproval.Client/wwwroot/android-chrome-512x512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
BIN
MesaFabApproval.Client/wwwroot/apple-touch-icon.png
Normal file
BIN
MesaFabApproval.Client/wwwroot/apple-touch-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
4
MesaFabApproval.Client/wwwroot/appsettings.json
Normal file
4
MesaFabApproval.Client/wwwroot/appsettings.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"OldFabApprovalUrl": "https://mesaapproval-test.mes.infineon.com",
|
||||
"FabApprovalApiBaseUrl": "https://mesaapproval-test.mes.infineon.com:7114"
|
||||
}
|
103
MesaFabApproval.Client/wwwroot/css/app.css
Normal file
103
MesaFabApproval.Client/wwwroot/css/app.css
Normal file
@ -0,0 +1,103 @@
|
||||
html, body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
h1:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #0071c1;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
outline: 1px solid red;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
.blazor-error-boundary {
|
||||
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
||||
padding: 1rem 1rem 1rem 3.7rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred."
|
||||
}
|
||||
|
||||
.loading-progress {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 8rem;
|
||||
height: 8rem;
|
||||
margin: 20vh auto 1rem auto;
|
||||
}
|
||||
|
||||
.loading-progress circle {
|
||||
fill: none;
|
||||
stroke: #e0e0e0;
|
||||
stroke-width: 0.6rem;
|
||||
transform-origin: 50% 50%;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.loading-progress circle:last-child {
|
||||
stroke: #1b6ec2;
|
||||
stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
|
||||
transition: stroke-dasharray 0.05s ease-in-out;
|
||||
}
|
||||
|
||||
.loading-progress-text {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
|
||||
}
|
||||
|
||||
.loading-progress-text:after {
|
||||
content: var(--blazor-load-percentage-text, "Loading");
|
||||
}
|
||||
|
||||
code {
|
||||
color: #c02d76;
|
||||
}
|
7
MesaFabApproval.Client/wwwroot/css/bootstrap/bootstrap.min.css
vendored
Normal file
7
MesaFabApproval.Client/wwwroot/css/bootstrap/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
MesaFabApproval.Client/wwwroot/favicon-16x16.png
Normal file
BIN
MesaFabApproval.Client/wwwroot/favicon-16x16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 446 B |
BIN
MesaFabApproval.Client/wwwroot/favicon-32x32.png
Normal file
BIN
MesaFabApproval.Client/wwwroot/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 865 B |
BIN
MesaFabApproval.Client/wwwroot/favicon.ico
Normal file
BIN
MesaFabApproval.Client/wwwroot/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
49
MesaFabApproval.Client/wwwroot/index.html
Normal file
49
MesaFabApproval.Client/wwwroot/index.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Mesa Fab Approval</title>
|
||||
<base href="/" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="css/app.css" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link href="MesaFabApproval.Client.styles.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<svg class="loading-progress">
|
||||
<circle r="40%" cx="50%" cy="50%" />
|
||||
<circle r="40%" cx="50%" cy="50%" />
|
||||
</svg>
|
||||
<div class="loading-progress-text"></div>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
|
||||
<script>
|
||||
if (window.location.hostname.includes("localhost")) {
|
||||
Blazor.start({
|
||||
webAssembly: {
|
||||
environment: "Development"
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Blazor.start();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
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;
|
||||
}
|
1
MesaFabApproval.Client/wwwroot/site.webmanifest
Normal file
1
MesaFabApproval.Client/wwwroot/site.webmanifest
Normal file
@ -0,0 +1 @@
|
||||
{"name":"Mesa Fab Approval","short_name":"MesaFabApproval","icons":[{"src":"android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
16
MesaFabApproval.Shared/MesaFabApproval.Shared.csproj
Normal file
16
MesaFabApproval.Shared/MesaFabApproval.Shared.csproj
Normal file
@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
22
MesaFabApproval.Shared/Models/Approval.cs
Normal file
22
MesaFabApproval.Shared/Models/Approval.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using MesaFabApproval.Shared.Utilities;
|
||||
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class Approval {
|
||||
public int ApprovalID { get; set; }
|
||||
public required int IssueID { get; set; }
|
||||
public required string RoleName { get; set; }
|
||||
public required string SubRole { get; set; }
|
||||
public required int UserID { get; set; }
|
||||
public User? User { get; set; }
|
||||
public required int SubRoleID { get; set; }
|
||||
public int ItemStatus { get; set; } = 0;
|
||||
public string StatusMessage = "Assigned";
|
||||
public DateTime NotifyDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||
public required DateTime AssignedDate { get; set; }
|
||||
public DateTime CompletedDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||
public string Comments { get; set; } = "";
|
||||
public int Step { get; set; } = 1;
|
||||
public string SubRoleCategoryItem { get; set; } = "";
|
||||
public int TaskID { get; set; }
|
||||
}
|
7
MesaFabApproval.Shared/Models/AuthAttempt.cs
Normal file
7
MesaFabApproval.Shared/Models/AuthAttempt.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class AuthAttempt {
|
||||
public required string LoginID { get; set; }
|
||||
public string Password { get; set; } = "";
|
||||
public AuthTokens? AuthTokens { get; set; }
|
||||
}
|
6
MesaFabApproval.Shared/Models/AuthTokens.cs
Normal file
6
MesaFabApproval.Shared/Models/AuthTokens.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class AuthTokens {
|
||||
public required string JwtToken { get; set; }
|
||||
public required string RefreshToken { get; set; }
|
||||
}
|
7
MesaFabApproval.Shared/Models/LoginResult.cs
Normal file
7
MesaFabApproval.Shared/Models/LoginResult.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class LoginResult {
|
||||
public required bool IsAuthenticated { get; set; }
|
||||
public required User User { get; set; }
|
||||
public required AuthTokens AuthTokens { get; set; }
|
||||
}
|
46
MesaFabApproval.Shared/Models/MRB.cs
Normal file
46
MesaFabApproval.Shared/Models/MRB.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using MesaFabApproval.Shared.Utilities;
|
||||
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class MRB {
|
||||
public static string[] Stages { get; } = {
|
||||
"Draft",
|
||||
"QA Pre Approval",
|
||||
"Pending Approval",
|
||||
"Approved",
|
||||
"Complete"
|
||||
};
|
||||
|
||||
public int MRBNumber { get; set; }
|
||||
public int OriginatorID { get; set; }
|
||||
public string OriginatorName { get; set; } = "";
|
||||
public string Title { get; set; } = "";
|
||||
public DateTime SubmittedDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||
public DateTime CloseDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||
public DateTime CancelDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||
public DateTime ApprovalDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||
public string IssueDescription { get; set; } = "";
|
||||
public int NumberOfLotsAffected { get; set; }
|
||||
public int Val { get; set; }
|
||||
public bool CustomerImpacted { get; set; } = false;
|
||||
public string CustomerImpactedName { get; set; } = "";
|
||||
public string Department { get; set; } = "";
|
||||
public string Process { get; set; } = "";
|
||||
public int RMANo { get; set; }
|
||||
public string PCRBNo { get; set; } = "";
|
||||
public bool SpecsImpacted { get; set; } = false;
|
||||
public int ProcessECNNumber { get; set; }
|
||||
public bool TrainingRequired { get; set; } = false;
|
||||
public IEnumerable<MRBAttachment>? Attachments { get; set; }
|
||||
public IEnumerable<MRBAction>? Actions { get; set; }
|
||||
public IEnumerable<int>? ApproverUserIds { get; set; }
|
||||
public required int StageNo { 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 required string RoleName { get; set; }
|
||||
public required string SubRoleName { get; set; }
|
||||
}
|
||||
}
|
20
MesaFabApproval.Shared/Models/MRBAction.cs
Normal file
20
MesaFabApproval.Shared/Models/MRBAction.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using MesaFabApproval.Shared.Utilities;
|
||||
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class MRBAction {
|
||||
public int ActionID { get; set; }
|
||||
public required string Action { get; set; }
|
||||
public required string Customer { get; set; }
|
||||
public required int Quantity { get; set; }
|
||||
public required string PartNumber { get; set; }
|
||||
public required string LotNumber { get; set; }
|
||||
public required int MRBNumber { get; set; }
|
||||
public DateTime AssignedDate { get; set; } = DateTimeUtilities.MIN_DT;
|
||||
public DateTime CompletedDate { get; set; } = DateTimeUtilities.MAX_DT;
|
||||
public int CompletedByUserID { get; set; } = 0;
|
||||
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; }
|
||||
}
|
13
MesaFabApproval.Shared/Models/MRBAttachment.cs
Normal file
13
MesaFabApproval.Shared/Models/MRBAttachment.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class MRBAttachment {
|
||||
public int AttachmentID { get; set; }
|
||||
public required int MRBNumber { get; set; }
|
||||
public required string FileName { get; set; }
|
||||
public required int UserID { get; set; }
|
||||
public required DateTime UploadDate { get; set; }
|
||||
public string? Path { get; set; }
|
||||
public IBrowserFile? File { get; set; }
|
||||
}
|
6
MesaFabApproval.Shared/Models/MRBNotification.cs
Normal file
6
MesaFabApproval.Shared/Models/MRBNotification.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class MRBNotification {
|
||||
public required string Message { get; set; }
|
||||
public required MRB MRB { get; set; }
|
||||
}
|
8
MesaFabApproval.Shared/Models/MonInMetricRequest.cs
Normal file
8
MesaFabApproval.Shared/Models/MonInMetricRequest.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class MonInMetricRequest {
|
||||
public required string resource { get; set; }
|
||||
public required DateTime dateTime { get; set; }
|
||||
public required string metricName { get; set; }
|
||||
public required double metricValue { get; set; }
|
||||
}
|
27
MesaFabApproval.Shared/Models/PCRB.cs
Normal file
27
MesaFabApproval.Shared/Models/PCRB.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using MesaFabApproval.Shared.Utilities;
|
||||
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class PCRB {
|
||||
public static string[] Stages { get; } = {
|
||||
"Draft",
|
||||
"QA Pre Approval",
|
||||
"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";
|
||||
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;
|
||||
}
|
56
MesaFabApproval.Shared/Models/Process.cs
Normal file
56
MesaFabApproval.Shared/Models/Process.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace MesaFabApproval.Shared.Models;
|
||||
|
||||
public class Process {
|
||||
public required string Name { get; set; } = "";
|
||||
|
||||
private static readonly Process Receiving = new Process { Name="Receiving" };
|
||||
private static readonly Process Kitting = new Process { Name = "Kitting" };
|
||||
private static readonly Process Cleans = new Process { Name = "Cleans" };
|
||||
private static readonly Process Reactor = new Process { Name = "Reactor" };
|
||||
private static readonly Process Metrology = new Process { Name = "Metrology" };
|
||||
private static readonly Process FQA = new Process { Name = "FQA" };
|
||||
private static readonly Process Packaging = new Process { Name = "Packaging" };
|
||||
private static readonly Process Shipping = new Process { Name = "Shipping" };
|
||||
private static readonly Process BuildingInfrastructure = new Process { Name = "Building Infrastructure" };
|
||||
private static readonly Process Conversion = new Process { Name = "Conversion" };
|
||||
private static readonly Process RMA = new Process { Name = "RMA" };
|
||||
private static readonly Process CustomerCompliant = new Process { Name = "Customer Compliant" };
|
||||
|
||||
public static IEnumerable<Process> ProductionProcesses = new HashSet<Process> {
|
||||
Cleans,
|
||||
Reactor,
|
||||
Metrology,
|
||||
FQA,
|
||||
Packaging
|
||||
};
|
||||
|
||||
public static IEnumerable<Process> EngineeringProcesses = new HashSet<Process> {
|
||||
Conversion,
|
||||
Cleans,
|
||||
Reactor,
|
||||
Metrology,
|
||||
FQA,
|
||||
Packaging
|
||||
};
|
||||
|
||||
public static IEnumerable<Process> MaterialsProcesses = new HashSet<Process> {
|
||||
Receiving,
|
||||
Kitting,
|
||||
Shipping
|
||||
};
|
||||
|
||||
public static IEnumerable<Process> FacilitiesProcesses = new HashSet<Process> {
|
||||
BuildingInfrastructure
|
||||
};
|
||||
|
||||
public static IEnumerable<Process> MaintenanceProcesses = new HashSet<Process> {
|
||||
Cleans,
|
||||
Reactor,
|
||||
Packaging
|
||||
};
|
||||
|
||||
public static IEnumerable<Process> QualityProcesses = new HashSet<Process> {
|
||||
RMA,
|
||||
CustomerCompliant
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user