MRB webassembly
This commit is contained in:
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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user