From 156dee075134c940b39624e91994cacd04d24667 Mon Sep 17 00:00:00 2001 From: Chase Tucker Date: Tue, 9 Apr 2024 10:44:57 -0700 Subject: [PATCH] Switched to standard MonIn library --- .../FabApprovalWorkerService.csproj | 4 +- .../Models/MonInMetricRequest.cs | 9 - .../Models/RawMonInStatusRequest.cs | 9 - .../Models/StatusValue.cs | 10 - .../Models/TrainingAssignment.cs | 12 -- FabApprovalWorkerService/Program.cs | 21 +- .../Services/ECNService.cs | 42 ++-- .../Services/MonInClient.cs | 58 ++++++ .../Services/MonInWorkerClient.cs | 181 ------------------ .../Services/TrainingService.cs | 26 ++- .../Services/UserService.cs | 70 +++---- .../Services/WindowsService.cs | 16 +- .../SetupScripts/CreateECNTable.sql | 20 +- .../SetupScripts/CreateTrainingTables.sql | 39 ++++ .../SetupScripts/SetupDb.bat | 1 + .../Workers/ExpiredOOOStatusWorker.cs | 16 +- .../Workers/ExpiredTECNWorker.cs | 109 +++++++++++ .../Workers/ExpiringTECNWorker.cs | 26 ++- .../Workers/PendingOOOStatusWorker.cs | 44 +++-- .../ECNServiceTests.cs | 14 +- .../TrainingServiceTests.cs | 143 ++++++++++++++ .../UserServiceTests.cs | 14 -- 22 files changed, 539 insertions(+), 345 deletions(-) delete mode 100644 FabApprovalWorkerService/Models/MonInMetricRequest.cs delete mode 100644 FabApprovalWorkerService/Models/RawMonInStatusRequest.cs delete mode 100644 FabApprovalWorkerService/Models/StatusValue.cs delete mode 100644 FabApprovalWorkerService/Models/TrainingAssignment.cs create mode 100644 FabApprovalWorkerService/Services/MonInClient.cs delete mode 100644 FabApprovalWorkerService/Services/MonInWorkerClient.cs create mode 100644 FabApprovalWorkerService/SetupScripts/CreateTrainingTables.sql create mode 100644 FabApprovalWorkerService/Workers/ExpiredTECNWorker.cs diff --git a/FabApprovalWorkerService/FabApprovalWorkerService.csproj b/FabApprovalWorkerService/FabApprovalWorkerService.csproj index 07e9db7..ced7649 100644 --- a/FabApprovalWorkerService/FabApprovalWorkerService.csproj +++ b/FabApprovalWorkerService/FabApprovalWorkerService.csproj @@ -29,9 +29,9 @@ - - + + diff --git a/FabApprovalWorkerService/Models/MonInMetricRequest.cs b/FabApprovalWorkerService/Models/MonInMetricRequest.cs deleted file mode 100644 index 7ab5429..0000000 --- a/FabApprovalWorkerService/Models/MonInMetricRequest.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace FabApprovalWorkerService.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; } -} diff --git a/FabApprovalWorkerService/Models/RawMonInStatusRequest.cs b/FabApprovalWorkerService/Models/RawMonInStatusRequest.cs deleted file mode 100644 index ed1ddae..0000000 --- a/FabApprovalWorkerService/Models/RawMonInStatusRequest.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace FabApprovalWorkerService.Models; - -public class RawMonInStatusRequest -{ - public required string resource { get; set; } - public required DateTime dateTime { get; set; } - public required string statusName { get; set; } - public required string statusValue { get; set; } -} diff --git a/FabApprovalWorkerService/Models/StatusValue.cs b/FabApprovalWorkerService/Models/StatusValue.cs deleted file mode 100644 index 7154bda..0000000 --- a/FabApprovalWorkerService/Models/StatusValue.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace FabApprovalWorkerService.Models; - -public enum StatusValue { - Up, - Ok, - Warning, - Critical, - Down, - Unknown -} diff --git a/FabApprovalWorkerService/Models/TrainingAssignment.cs b/FabApprovalWorkerService/Models/TrainingAssignment.cs deleted file mode 100644 index 32a1ee9..0000000 --- a/FabApprovalWorkerService/Models/TrainingAssignment.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Dapper.Contrib.Extensions; - -namespace FabApprovalWorkerService.Models; -[Table("TrainingAssignment")] -public class TrainingAssignment { - [Key] - public int ID { get; set; } - public int TrainingID { get; set; } - public bool Status { get; set; } = false; - public bool Deleted { get; set; } = false; - public DateTime DeletedDate { get; set; } -} diff --git a/FabApprovalWorkerService/Program.cs b/FabApprovalWorkerService/Program.cs index e94eb71..c9e7829 100644 --- a/FabApprovalWorkerService/Program.cs +++ b/FabApprovalWorkerService/Program.cs @@ -17,7 +17,7 @@ builder.Logging.AddNLog(); builder.Services.AddHttpClient(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped((serviceProvider) => { return new SmtpClient("mailrelay-external.infineon.com"); @@ -27,6 +27,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddQuartz(q => { JobKey pendingOOOStatusJob = new JobKey("Pending OOO status job"); @@ -46,7 +47,7 @@ builder.Services.AddQuartz(q => { q.AddTrigger(opts => opts .ForJob(expiredOOOStatusJob) .WithIdentity("Expired OOO status trigger") - .WithCronSchedule(CronScheduleBuilder.DailyAtHourAndMinute(0, 0)) + .WithCronSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 52)) ); JobKey expiringTECNJob = new JobKey("Expiring TECN job"); @@ -56,11 +57,17 @@ builder.Services.AddQuartz(q => { q.AddTrigger(opts => opts .ForJob(expiringTECNJob) .WithIdentity("Expiring TECN trigger") - .WithSimpleSchedule(x => x - .WithIntervalInMinutes(10) - .RepeatForever() - ) - .StartNow() + .WithCronSchedule(CronScheduleBuilder.DailyAtHourAndMinute(6, 0)) + ); + + JobKey expiredTECNJob = new JobKey("Expired TECN job"); + q.AddJob(opts => opts + .WithIdentity(expiredTECNJob) + ); + q.AddTrigger(opts => opts + .ForJob(expiredTECNJob) + .WithIdentity("Expired TECN trigger") + .WithCronSchedule(CronScheduleBuilder.DailyAtHourAndMinute(6, 0)) ); }); diff --git a/FabApprovalWorkerService/Services/ECNService.cs b/FabApprovalWorkerService/Services/ECNService.cs index e4f9586..27bb8ca 100644 --- a/FabApprovalWorkerService/Services/ECNService.cs +++ b/FabApprovalWorkerService/Services/ECNService.cs @@ -23,21 +23,30 @@ public class ECNService : IECNService { try { _logger.LogInformation("Attempting to get all TECNs expired in the last day"); - string today = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - string yesterday = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd HH:mm:ss"); + DateTime today = DateTime.Now.Date; + DateTime tomorrow = DateTime.Now.Date.AddDays(1); StringBuilder queryBuilder = new StringBuilder(); queryBuilder.Append("select ECNNumber, IsTECN, ExpirationDate, ExtensionDate, OriginatorID, Title "); queryBuilder.Append($"from ECN where IsTECN = 1 and "); - queryBuilder.Append($"ExpirationDate between '{yesterday}' "); - queryBuilder.Append($"and '{today}'"); + queryBuilder.Append("Cancelled = 0 and Deleted = 0 "); + queryBuilder.Append("and (CloseDate IS NULL or CloseDate = '');"); - IEnumerable expiredTecns = (await _dalService.QueryAsync(queryBuilder.ToString())); + IEnumerable activeTecns = await _dalService.QueryAsync(queryBuilder.ToString()); + + _logger.LogInformation($"There are {activeTecns.Count()} active TECNs"); + + IEnumerable expiredTecns = activeTecns.Where(e => ((e.ExpirationDate < tomorrow) && (e.ExpirationDate >= today)) || + ((e.ExtensionDate < tomorrow) && (e.ExtensionDate >= today))); + + _logger.LogInformation($"There are {expiredTecns.Count()} TECNs with an expiration date or extension date today"); IEnumerable expiredTecnsNotExtended = expiredTecns - .Where(e => e.ExtensionDate < DateTime.Now) + .Where(e => !(e.ExtensionDate >= tomorrow)) .ToList(); + _logger.LogInformation($"There are {expiredTecnsNotExtended.Count()} TECNs expiring today"); + return expiredTecnsNotExtended; } catch (Exception ex) { StringBuilder errMsgBuilder = new(); @@ -52,21 +61,30 @@ public class ECNService : IECNService { try { _logger.LogInformation("Attempting to get all TECNs expiring in the next five days"); - string today = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - string fiveDaysFromToday = DateTime.Now.AddDays(5).ToString("yyyy-MM-dd HH:mm:ss"); + DateTime tomorrow = DateTime.Now.AddDays(1).Date; + DateTime fiveDaysFromToday = DateTime.Now.AddDays(5).Date; StringBuilder queryBuilder = new StringBuilder(); queryBuilder.Append("select * from ECN "); queryBuilder.Append($"where IsTECN = 1 and "); - queryBuilder.Append($"ExpirationDate between '{today}' "); - queryBuilder.Append($"and '{fiveDaysFromToday}';"); + queryBuilder.Append("Cancelled = 0 and Deleted = 0 "); + queryBuilder.Append("and (CloseDate IS NULL or CloseDate = '');"); - IEnumerable expiringTecns = (await _dalService.QueryAsync(queryBuilder.ToString())); + IEnumerable activeTecns = (await _dalService.QueryAsync(queryBuilder.ToString())); + + _logger.LogInformation($"There are {activeTecns.Count()} active TECNs"); + + IEnumerable expiringTecns = activeTecns.Where(e => ((e.ExpirationDate >= tomorrow) && (e.ExpirationDate <= fiveDaysFromToday)) || + ((e.ExtensionDate >= tomorrow) && (e.ExtensionDate <= fiveDaysFromToday))); + + _logger.LogInformation($"There are {expiringTecns.Count()} TECNs with an expiration date or extension date in the next 5 days"); IEnumerable expiringTecnsNotExtended = expiringTecns - .Where(e => e.ExtensionDate <= DateTime.Now.AddDays(5)) + .Where(e => !(e.ExtensionDate > fiveDaysFromToday)) .ToList(); + _logger.LogInformation($"There are {expiringTecnsNotExtended.Count()} TECNs expiring in the next five days"); + return expiringTecnsNotExtended; } catch (Exception ex) { StringBuilder errMsgBuilder = new(); diff --git a/FabApprovalWorkerService/Services/MonInClient.cs b/FabApprovalWorkerService/Services/MonInClient.cs new file mode 100644 index 0000000..17dc33a --- /dev/null +++ b/FabApprovalWorkerService/Services/MonInClient.cs @@ -0,0 +1,58 @@ +using Infineon.Monitoring.MonA; + +namespace FabApprovalWorkerService.Services; + +public interface IMonInClient { + void PostMetric(string metricName, double metricValue); + void PostStatus(string statusName, State state); +} + +public class MonInClient : IMonInClient { + private readonly ILogger _logger; + + private readonly string _site; + private readonly string _resource; + + public MonInClient(ILogger logger) { + _logger = logger ?? + throw new ArgumentNullException("ILogger not injected"); + _site = Environment.GetEnvironmentVariable("MonInSite") ?? + throw new ArgumentNullException("MonInSite environment variable not found"); + _resource = Environment.GetEnvironmentVariable("FabApprovalWorkerServiceMonInResource") ?? + throw new ArgumentNullException("FabApprovalWorkerServiceMonInResource environment variable not found"); + } + + public void PostMetric(string metricName, double metricValue) { + try { + _logger.LogInformation("Attempting to send MonIn metric request for resource {0} with name {1} and value {2}", + _resource, + metricName, + metricValue); + + MonIn.GetInstance().SendPerformanceMessage(_site, _resource, metricName, metricValue); + } catch (Exception ex) { + _logger.LogError("An exception occurred when attempting to send MonIn metric request for resource {0} with name {1} and value {2}. Exception: {3}", + _resource, + metricName, + metricValue, + ex.Message); + } + } + + public void PostStatus(string statusName, State state) { + try { + _logger.LogInformation("Attempting to send MonIn status request for resource {0} with name {1} and value {2}", + _resource, + statusName, + state.ToString()); + + MonIn.GetInstance().SendStatus(_site, _resource, statusName, state); + } catch (Exception ex) { + _logger.LogError("An exception occurred when attempting to send MonIn status request for resource {0} with name {1} and value {2}. Exception: {3}", + _resource, + statusName, + state.ToString(), + ex.Message); + } + } +} diff --git a/FabApprovalWorkerService/Services/MonInWorkerClient.cs b/FabApprovalWorkerService/Services/MonInWorkerClient.cs deleted file mode 100644 index 71b13e3..0000000 --- a/FabApprovalWorkerService/Services/MonInWorkerClient.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System.Text; -using System.Text.Json; - -using FabApprovalWorkerService.Models; - -using static System.Net.Mime.MediaTypeNames; - -namespace FabApprovalWorkerService.Services; - -public interface IMonInWorkerClient { - void PostAverage(string metricName, double metricValue); - void PostCount(string metricName, double metricValue); - void PostStatus(string statusName, StatusValue statusValue); -} - -public class MonInWorkerClient : IMonInWorkerClient { - - private readonly IHttpClientFactory _httpClientFactory; - private readonly IConfiguration _config; - private readonly ILogger _logger; - - private readonly string _baseUrl; - private readonly int _retryLimit = -1; - private readonly int _backoffInSeconds = -1; - - private readonly string _resource; - - public MonInWorkerClient(IHttpClientFactory httpClientFactory, - IConfiguration config, - ILogger logger) { - _httpClientFactory = httpClientFactory; - if (_httpClientFactory is null) throw new ArgumentNullException("IHttpClientFactory not injected"); - - _config = config ?? - throw new ArgumentNullException("IConfiguration not injected"); - - _logger = logger ?? - throw new ArgumentNullException("ILogger not injected"); - - _baseUrl = Environment.GetEnvironmentVariable("MonInWorkerUrl") ?? - throw new ArgumentNullException("MonInWorkerUrl environment variable not found"); - - if (!Int32.TryParse(Environment.GetEnvironmentVariable("MonInRetries"), out _retryLimit)) - throw new ArgumentNullException("Valid MonInRetries environment variable not found"); - - if (!Int32.TryParse(Environment.GetEnvironmentVariable("MonInBackoffSeconds"), out _backoffInSeconds)) - throw new ArgumentNullException("Valid MonInBackoffSeconds environment varialbe not found"); - - _resource = Environment.GetEnvironmentVariable("FabApprovalWorkerServiceMonInResource") ?? - throw new ArgumentNullException("FabApprovalWorkerServiceMonInResource environment variable not found"); - } - - public async void PostStatus(string statusName, StatusValue statusValue) { - string url = _baseUrl + "status"; - - _logger.LogInformation("Attempting to send MonIn status request for resource {0} with name {1} and value {2} to url {3}", - _resource, - statusName, - statusValue.ToString(), - url); - - try { - bool success = false; - int retries = _retryLimit; - while (!success && retries > 0) { - Task.Delay(TimeSpan.FromSeconds((_retryLimit - retries) * _backoffInSeconds)).Wait(); - - HttpClient httpClient = _httpClientFactory.CreateClient(); - - RawMonInStatusRequest statusRequest = new RawMonInStatusRequest() { - resource = _resource, - dateTime = DateTime.Now, - statusName = statusName, - statusValue = statusValue.ToString() - }; - - StringContent statusRequestJson = new StringContent(JsonSerializer.Serialize(statusRequest), - Encoding.UTF8, - Application.Json); - using HttpResponseMessage httpResponseMessage = - await httpClient.PostAsync(url, statusRequestJson); - - success = httpResponseMessage.IsSuccessStatusCode; - retries--; - } - } catch (Exception ex) { - _logger.LogError("An exception occurred when attempting to send MonIn status request for resource {0} with name {1} and value {2} to url {3}. Exception: {4}", - _resource, - statusName, - statusValue.ToString(), - url, - ex.Message); - } - } - - public async void PostCount(string metricName, double metricValue) { - string url = _baseUrl + "count"; - - _logger.LogInformation("Attempting to send MonIn count request for resource {0} with name {1} and value {2} to url {3}", - _resource, - metricName, - metricValue, - url); - - try { - bool success = false; - int retries = _retryLimit; - while (!success && retries > 0) { - Task.Delay(TimeSpan.FromSeconds((_retryLimit - retries) * _backoffInSeconds)).Wait(); - - HttpClient httpClient = _httpClientFactory.CreateClient(); - - MonInMetricRequest metricRequest = new MonInMetricRequest() { - resource = _resource, - dateTime = DateTime.Now, - metricName = metricName, - metricValue = metricValue - }; - - StringContent metricRequestJson = new StringContent(JsonSerializer.Serialize(metricRequest), - Encoding.UTF8, - Application.Json); - using HttpResponseMessage httpResponseMessage = - await httpClient.PostAsync(url, metricRequestJson); - - success = httpResponseMessage.IsSuccessStatusCode; - retries--; - } - } catch (Exception ex) { - _logger.LogError("An exception occurred when attempting to send MonIn count request for resource {0} with name {1} and value {2} to url {3}. Exception: {4}", - _resource, - metricName, - metricValue, - url, - ex.Message); - } - } - - public async void PostAverage(string metricName, double metricValue) { - string url = _baseUrl + "average"; - - _logger.LogInformation("Attempting to send MonIn average request for resource {0} with name {1} and value {2} to url {3}", - _resource, - metricName, - metricValue, - url); - - try { - bool success = false; - int retries = _retryLimit; - while (!success && retries > 0) { - Task.Delay(TimeSpan.FromSeconds((_retryLimit - retries) * _backoffInSeconds)).Wait(); - - HttpClient httpClient = _httpClientFactory.CreateClient(); - - MonInMetricRequest metricRequest = new MonInMetricRequest() { - resource = _resource, - dateTime = DateTime.Now, - metricName = metricName, - metricValue = metricValue - }; - - StringContent metricRequestJson = new StringContent(JsonSerializer.Serialize(metricRequest), - Encoding.UTF8, - Application.Json); - using HttpResponseMessage httpResponseMessage = - await httpClient.PostAsync(url, metricRequestJson); - - success = httpResponseMessage.IsSuccessStatusCode; - retries--; - } - } catch (Exception ex) { - _logger.LogError("An exception occurred when attempting to send MonIn average request for resource {0} with name {1} and value {2} to url {3}. Exception: {4}", - _resource, - metricName, - metricValue, - url, - ex.Message); - } - } -} diff --git a/FabApprovalWorkerService/Services/TrainingService.cs b/FabApprovalWorkerService/Services/TrainingService.cs index 1ebab9b..f64598f 100644 --- a/FabApprovalWorkerService/Services/TrainingService.cs +++ b/FabApprovalWorkerService/Services/TrainingService.cs @@ -6,6 +6,7 @@ namespace FabApprovalWorkerService.Services; public interface ITrainingService { Task> GetTrainingIdsForECN(int ecnNumber); + Task MarkTrainingAsComplete(int trainingId); Task DeleteTrainingAssignment(int trainingId); Task> GetTrainingAssignmentIdsForTraining(int trainingId); Task DeleteDocAssignment(int trainingAssignmentId); @@ -30,7 +31,7 @@ public class TrainingService : ITrainingService { StringBuilder queryBuilder = new(); queryBuilder.Append($"update TrainingDocAcks set Deleted = 1, "); - queryBuilder.Append($"DeletedDate = {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} "); + queryBuilder.Append($"DeletedDate = '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}' "); queryBuilder.Append($"where TrainingAssignmentID = {trainingAssignmentId} and Reviewed = 0;"); await _dalService.ExecuteAsync(queryBuilder.ToString()); @@ -51,7 +52,7 @@ public class TrainingService : ITrainingService { StringBuilder queryBuilder = new(); queryBuilder.Append($"update TrainingAssignments set Deleted = 1, "); - queryBuilder.Append($"DeletedDate = {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} "); + queryBuilder.Append($"DeletedDate = '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}' "); queryBuilder.Append($"where TrainingID = {trainingId} and status = 0;"); await _dalService.ExecuteAsync(queryBuilder.ToString()); @@ -64,6 +65,27 @@ public class TrainingService : ITrainingService { } } + public async Task MarkTrainingAsComplete(int trainingId) { + if (trainingId <= 0) throw new ArgumentException($"Invalid training id: {trainingId}"); + + try { + _logger.LogInformation($"Attempting to mark training {trainingId} as complete"); + + StringBuilder queryBuilder = new(); + queryBuilder.Append($"update Training set Status = 1, "); + queryBuilder.Append($"CompletedDate = '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}' "); + queryBuilder.Append($"where TrainingID = {trainingId};"); + + await _dalService.ExecuteAsync(queryBuilder.ToString()); + } catch (Exception ex) { + StringBuilder errMsgBuilder = new(); + errMsgBuilder.Append($"An exception occurred when attempting to mark training {trainingId} "); + errMsgBuilder.Append($"as complete. Exception: {ex.Message}"); + _logger.LogError(errMsgBuilder.ToString()); + throw; + } + } + public async Task> GetTrainingAssignmentIdsForTraining(int trainingId) { if (trainingId <= 0) throw new ArgumentException($"Invalid trainingID: {trainingId}"); diff --git a/FabApprovalWorkerService/Services/UserService.cs b/FabApprovalWorkerService/Services/UserService.cs index b5a53f7..139f8a6 100644 --- a/FabApprovalWorkerService/Services/UserService.cs +++ b/FabApprovalWorkerService/Services/UserService.cs @@ -44,7 +44,7 @@ public class UserService : IUserService { StringBuilder queryBuilder = new(); queryBuilder.Append("select * from Users where OOO = 1 and IsActive = 1 and "); - queryBuilder.Append($"OOOExpirationDate <= '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}';"); + queryBuilder.Append($"OOOExpirationDate <= '{DateTime.Now.Date.ToString("yyyy-MM-dd HH:mm:ss")}';"); return (await _dalService.QueryAsync(queryBuilder.ToString())).ToList(); } catch (Exception ex) { @@ -60,7 +60,7 @@ public class UserService : IUserService { StringBuilder queryBuilder = new(); queryBuilder.Append("select * from OOOTemp where Processed = 0 and "); - queryBuilder.Append($"OOOStartDate <= '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}';"); + queryBuilder.Append($"OOOStartDate <= '{DateTime.Now.Date.ToString("yyyy-MM-dd HH:mm:ss")}';"); return (await _dalService.QueryAsync(queryBuilder.ToString())).ToList(); } catch (Exception ex) { @@ -92,7 +92,7 @@ public class UserService : IUserService { public async Task IsDelegatorAlreadyDelegatedTo(int userId) { try { - _logger.LogInformation($"Attempting to determine if user {userId} is already OOO."); + _logger.LogInformation($"Attempting to determine if user {userId} is already a delegate."); if (userId <= 0) { _logger.LogInformation($"DelegatedTo is {userId}, which is not an active user Id"); @@ -127,7 +127,7 @@ public class UserService : IUserService { foreach (UserSubRole role in userSubRoles) { queryBuilder.Clear(); queryBuilder.Append("insert into OOODelegatedRoles (UserID, DelegatedSubRoleID, InsertTimeStamp, Active) "); - queryBuilder.Append($"values ({userId}, {role.SubRoleID}, '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', 1);"); + queryBuilder.Append($"values ({userId}, {role.SubRoleID}, '{DateTime.Now.Date.ToString("yyyy-MM-dd HH:mm:ss")}', 1);"); await _dalService.ExecuteAsync(queryBuilder.ToString()); } @@ -196,23 +196,26 @@ public class UserService : IUserService { if (userId <= 0) throw new ArgumentException($"User Id {userId} is not a valid user Id"); - if (delegatedUserId <= 0) - throw new ArgumentException($"Delegated user Id {delegatedUserId} is not a valid user Id"); + if (delegatedUserId > 0) { + _logger.LogInformation($"User {userId} delegated sub roles to {delegatedUserId}"); - StringBuilder queryBuilder = new StringBuilder(); - queryBuilder.Append("select SubRoleID from OOODelegatedRoles O inner join UserSubRole U "); - queryBuilder.Append("on O.DelegatedSubRoleID = U.UserSubRoleID "); - queryBuilder.Append($"where O.UserID = {userId} and Active = 1"); + StringBuilder queryBuilder = new StringBuilder(); + queryBuilder.Append("select SubRoleID from OOODelegatedRoles O inner join UserSubRole U "); + queryBuilder.Append("on O.DelegatedSubRoleID = U.UserSubRoleID "); + queryBuilder.Append($"where O.UserID = {userId} and Active = 1"); - List userSubRoleIds = (await _dalService.QueryAsync(queryBuilder.ToString())).ToList(); + List userSubRoleIds = (await _dalService.QueryAsync(queryBuilder.ToString())).ToList(); - foreach (int id in userSubRoleIds) { - queryBuilder.Clear(); - queryBuilder.Append($"update UserSubRole set UserID = {userId}, Delegated = 0 "); - queryBuilder.Append($"where UserID = {delegatedUserId} and Delegated = 1 "); - queryBuilder.Append($"and SubRoleID in ({string.Join(',', userSubRoleIds)})"); + foreach (int id in userSubRoleIds) { + queryBuilder.Clear(); + queryBuilder.Append($"update UserSubRole set UserID = {userId}, Delegated = 0 "); + queryBuilder.Append($"where UserID = {delegatedUserId} and Delegated = 1 "); + queryBuilder.Append($"and SubRoleID in ({string.Join(',', userSubRoleIds)})"); - await _dalService.ExecuteAsync(queryBuilder.ToString()); + await _dalService.ExecuteAsync(queryBuilder.ToString()); + } + } else { + _logger.LogInformation($"User {userId} had no delegated sub roles"); } return true; @@ -256,25 +259,28 @@ public class UserService : IUserService { if (userId <= 0) throw new ArgumentException($"User Id {userId} is not a valid user Id"); - if (delegatedUserId <= 0) - throw new ArgumentException($"Delegated user Id {delegatedUserId} is not a valid user Id"); + if (delegatedUserId > 0) { + _logger.LogInformation($"User {userId} delegated approvals to {delegatedUserId}"); - StringBuilder queryBuilder = new StringBuilder(); + StringBuilder queryBuilder = new StringBuilder(); - queryBuilder.Append("select SubRoleID from OOODelegatedRoles O inner join UserSubRole U "); - queryBuilder.Append("on O.DelegatedSubRoleID = U.UserSubRoleID "); - queryBuilder.Append($"where O.UserID = {userId} and Active = 1"); + queryBuilder.Append("select SubRoleID from OOODelegatedRoles O inner join UserSubRole U "); + queryBuilder.Append("on O.DelegatedSubRoleID = U.UserSubRoleID "); + queryBuilder.Append($"where O.UserID = {userId} and Active = 1"); - List userSubRoleIds = (await _dalService.QueryAsync(queryBuilder.ToString())).ToList(); + List userSubRoleIds = (await _dalService.QueryAsync(queryBuilder.ToString())).ToList(); - foreach (int id in userSubRoleIds) { - queryBuilder.Clear(); - queryBuilder.Append($"update Approval set UserID = {userId}, Delegated = 0 "); - queryBuilder.Append($"where UserID = {delegatedUserId} and Delegated = 1 and "); - queryBuilder.Append($"(ItemStatus = {PENDING_ITEM_STATUS} or ItemStatus = {DENITED_ITEM_STATUS}) "); - queryBuilder.Append($"and SubRoleID in ({string.Join(',', userSubRoleIds)})"); + foreach (int id in userSubRoleIds) { + queryBuilder.Clear(); + queryBuilder.Append($"update Approval set UserID = {userId}, Delegated = 0 "); + queryBuilder.Append($"where UserID = {delegatedUserId} and Delegated = 1 and "); + queryBuilder.Append($"(ItemStatus = {PENDING_ITEM_STATUS} or ItemStatus = {DENITED_ITEM_STATUS}) "); + queryBuilder.Append($"and SubRoleID in ({string.Join(',', userSubRoleIds)})"); - await _dalService.ExecuteAsync(queryBuilder.ToString()); + await _dalService.ExecuteAsync(queryBuilder.ToString()); + } + } else { + _logger.LogInformation($"User {userId} had not delegated approvals"); } return true; @@ -332,7 +338,7 @@ public class UserService : IUserService { _logger.LogInformation($"Attempting to set OOOTemp {oooTemp.ID} Processed to {oooTemp.Processed}"); - string sql = $"update OOOTemp set Processed = {oooTemp.Processed} where ID = {oooTemp.ID}"; + string sql = $"update OOOTemp set Processed = {Convert.ToInt32(oooTemp.Processed)} where ID = {oooTemp.ID}"; return (await _dalService.ExecuteAsync(sql)) > 0; } catch (Exception ex) { diff --git a/FabApprovalWorkerService/Services/WindowsService.cs b/FabApprovalWorkerService/Services/WindowsService.cs index 0f8b4b3..5e08d65 100644 --- a/FabApprovalWorkerService/Services/WindowsService.cs +++ b/FabApprovalWorkerService/Services/WindowsService.cs @@ -1,18 +1,20 @@ using FabApprovalWorkerService.Models; +using Infineon.Monitoring.MonA; + namespace FabApprovalWorkerService.Services; public class WindowsService : BackgroundService { private readonly ILogger _logger; - private readonly IMonInWorkerClient _monInClient; + private readonly IMonInClient _monInClient; public WindowsService(ILogger logger, IServiceProvider serviceProvider) { _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); using (IServiceScope scope = serviceProvider.CreateScope()) { - _monInClient = scope.ServiceProvider.GetService() ?? - throw new ArgumentNullException("IMonInWorkerClient not injected"); + _monInClient = scope.ServiceProvider.GetService() ?? + throw new ArgumentNullException("IMonInClient not injected"); } } @@ -21,18 +23,18 @@ public class WindowsService : BackgroundService { try { while (!stoppingToken.IsCancellationRequested) { - await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); + _monInClient.PostStatus("WindowsService", State.Ok); - _monInClient.PostStatus("WindowsService", StatusValue.Ok); + await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); } } catch (OperationCanceledException) { _logger.LogError("The Windows service has been stopped"); - _monInClient.PostStatus("WindowsService", StatusValue.Critical); + _monInClient.PostStatus("WindowsService", State.Critical); } catch (Exception ex) { _logger.LogError($"An exception occurred when running Windows Service. Exception: {ex.Message}"); - _monInClient.PostStatus("WindowsService", StatusValue.Critical); + _monInClient.PostStatus("WindowsService", State.Critical); Environment.Exit(1); } diff --git a/FabApprovalWorkerService/SetupScripts/CreateECNTable.sql b/FabApprovalWorkerService/SetupScripts/CreateECNTable.sql index a627c62..0455da8 100644 --- a/FabApprovalWorkerService/SetupScripts/CreateECNTable.sql +++ b/FabApprovalWorkerService/SetupScripts/CreateECNTable.sql @@ -3,14 +3,22 @@ drop table if exists ECN; create table ECN ( ECNNumber integer primary key not null, IsTECN integer default 0, - ExpirationDate text, - ExtensionDate text, + ExpirationDate text default '', + ExtensionDate text default '', OriginatorID integer not null, - Title text not null + Title text not null, + Deleted integer default 0, + Cancelled integer default 0, + CloseDate text default '' ); insert into ECN (ECNNumber, IsTECN, ExpirationDate, ExtensionDate, OriginatorID, Title) -values (1, 0, '2024-04-06 00:00:00', null, 1, 'title1'), -(2, 1, '2024-04-04 00:00:00', null, 6, 'title2'), +values (1, 1, '2024-04-05 00:00:00', null, 1, 'title1'), +(2, 1, '2024-04-04 12:00:00', null, 6, 'title2'), (3, 1, '2024-06-01 00:00:00', null, 4, 'title3'), -(4, 1, '2024-04-03 00:00:00', '2024-06-01 00:00:00', 3, 'title4') \ No newline at end of file +(4, 1, '2024-02-05 00:00:00', '2024-04-05 09:00:00', 3, 'title4'), +(5, 1, '2024-06-01 00:00:00', null, 4, 'title3'), +(6, 1, '2024-04-07 00:00:00', null, 9, 'title6'), +(7, 1, '2024-04-07 00:00:00', '2024-06-01 00:00:00', 13, 'title9'), +(8, 1, '2024-02-05 00:00:00', '2024-04-07 09:00:00', 3, 'title4'), +(9, 1, '2024-02-05 00:00:00', '2024-04-06 09:00:00', 3, 'title4') \ No newline at end of file diff --git a/FabApprovalWorkerService/SetupScripts/CreateTrainingTables.sql b/FabApprovalWorkerService/SetupScripts/CreateTrainingTables.sql new file mode 100644 index 0000000..eecc93b --- /dev/null +++ b/FabApprovalWorkerService/SetupScripts/CreateTrainingTables.sql @@ -0,0 +1,39 @@ +drop table if exists Training; + +create table Training ( + TrainingID integer primary key, + ECN integer not null, + Status integer default 0, + CompletedDate text +); + +insert into Training (ECN) +values (1), (2), (3), (4), (5), (6), (7), (8), (9); + +drop table if exists TrainingAssignments; + +create table TrainingAssignments ( + ID integer primary key, + TrainingID integer not null, + Deleted integer default 0, + status integer default 0, + DeletedDate text +); + +insert into TrainingAssignments (TrainingID) +values (1), (1), (2), (2), (3), (3), (4), (4), (5), (5), (6), (6), +(7), (7), (8), (8), (9), (9); + +drop table if exists TrainingDocAcks; + +create table TrainingDocAcks ( + ID integer primary key, + TrainingAssignmentID integer not null, + Reviewed integer default 0, + Deleted integer default 0, + DeletedDate text +); + +insert into TrainingDocAcks (TrainingAssignmentID) +values (1), (1), (2), (2), (3), (3), (4), (4), (5), (5), (6), (6), +(7), (7), (8), (8), (9), (9); \ No newline at end of file diff --git a/FabApprovalWorkerService/SetupScripts/SetupDb.bat b/FabApprovalWorkerService/SetupScripts/SetupDb.bat index 78b016c..7fb83c9 100644 --- a/FabApprovalWorkerService/SetupScripts/SetupDb.bat +++ b/FabApprovalWorkerService/SetupScripts/SetupDb.bat @@ -6,4 +6,5 @@ sqlite3 D:\FabApprovalWorkerService\LocalDb.db < .\CreateOOODelegatedRolesTable. sqlite3 D:\FabApprovalWorkerService\LocalDb.db < .\CreateApprovalTable.sql sqlite3 D:\FabApprovalWorkerService\LocalDb.db < .\CreateECNTable.sql sqlite3 D:\FabApprovalWorkerService\LocalDb.db < .\CreateTECNNotificationUsersTable.sql +sqlite3 D:\FabApprovalWorkerService\LocalDb.db < .\CreateTrainingTables.sql pause \ No newline at end of file diff --git a/FabApprovalWorkerService/Workers/ExpiredOOOStatusWorker.cs b/FabApprovalWorkerService/Workers/ExpiredOOOStatusWorker.cs index a0c2270..f304288 100644 --- a/FabApprovalWorkerService/Workers/ExpiredOOOStatusWorker.cs +++ b/FabApprovalWorkerService/Workers/ExpiredOOOStatusWorker.cs @@ -1,6 +1,8 @@ using FabApprovalWorkerService.Models; using FabApprovalWorkerService.Services; +using Infineon.Monitoring.MonA; + using Quartz; using System.Text; @@ -9,11 +11,11 @@ namespace FabApprovalWorkerService.Workers; public sealed class ExpiredOOOStatusWorker : IJob { private readonly ILogger _logger; - private readonly IMonInWorkerClient _monInClient; + private readonly IMonInClient _monInClient; private readonly IUserService _userService; public ExpiredOOOStatusWorker(ILogger logger, - IMonInWorkerClient monInClient, + IMonInClient monInClient, IUserService userService) { _logger = logger; if (_logger is null) @@ -21,7 +23,7 @@ public sealed class ExpiredOOOStatusWorker : IJob { _monInClient = monInClient; if (_monInClient is null) { - throw new ArgumentNullException("IMonInWorkerClient not injected"); + throw new ArgumentNullException("IMonInClient not injected"); } _userService = userService; @@ -39,6 +41,8 @@ public sealed class ExpiredOOOStatusWorker : IJob { _logger.LogInformation("Attempting to remove OOO status for users with OOO expired earlier than now"); List expiredOOOUsers = await _userService.GetAllExpiredOOOUsersAsync(); + + _logger.LogInformation($"There are {expiredOOOUsers.Count()} OOO users expiring"); foreach (User user in expiredOOOUsers) { bool approvalsRemoved = await _userService.RemoveDelegatedApprovalsForUser(user.UserID, user.DelegatedTo); @@ -67,12 +71,12 @@ public sealed class ExpiredOOOStatusWorker : IJob { } finally { DateTime end = DateTime.Now; double latencyInMS = (end - start).TotalMilliseconds; - _monInClient.PostAverage(metricName + "Latency", latencyInMS); + _monInClient.PostMetric(metricName + "Latency", latencyInMS); if (isInternalError) { - _monInClient.PostStatus(metricName, StatusValue.Critical); + _monInClient.PostStatus(metricName, State.Critical); } else { - _monInClient.PostStatus(metricName, StatusValue.Ok); + _monInClient.PostStatus(metricName, State.Ok); } } } diff --git a/FabApprovalWorkerService/Workers/ExpiredTECNWorker.cs b/FabApprovalWorkerService/Workers/ExpiredTECNWorker.cs new file mode 100644 index 0000000..96679fe --- /dev/null +++ b/FabApprovalWorkerService/Workers/ExpiredTECNWorker.cs @@ -0,0 +1,109 @@ +using FabApprovalWorkerService.Models; +using FabApprovalWorkerService.Services; + +using Infineon.Monitoring.MonA; + +using Quartz; + +using System.Net.Mail; + +using System.Text; + +namespace FabApprovalWorkerService.Workers; +public class ExpiredTECNWorker : IJob { + private readonly ILogger _logger; + private readonly IECNService _ecnService; + private readonly ITrainingService _trainingService; + private readonly IUserService _userService; + private readonly ISmtpService _smtpService; + private readonly IMonInClient _monInClient; + private readonly string _baseUrl; + + public ExpiredTECNWorker(ILogger logger, + IECNService ecnService, + ITrainingService trainingService, + IUserService userService, + ISmtpService smtpService, + IMonInClient monInClient) { + _logger = logger ?? + throw new ArgumentNullException("ILogger not injected"); + _ecnService = ecnService ?? + throw new ArgumentNullException("IECNService not injected"); + _trainingService = trainingService ?? + throw new ArgumentNullException("ITrainingService not injected"); + _userService = userService ?? + throw new ArgumentNullException("IUserService not injected"); + _smtpService = smtpService ?? + throw new ArgumentNullException("ISmtpService not injected"); + _monInClient = monInClient ?? + throw new ArgumentNullException("IMonInClient not injected"); + _baseUrl = Environment.GetEnvironmentVariable("FabApprovalBaseUrl") ?? + throw new ArgumentNullException("FabApprovalBaseUrl environment variable not found"); + } + + public async Task Execute(IJobExecutionContext context) { + DateTime start = DateTime.Now; + bool isInternalError = false; + StringBuilder errorMessage = new(); + string metricName = "ExpiredTECNWorker"; + + try { + _logger.LogInformation("Attempting to process expired TECNs"); + + List expiredEcns = (await _ecnService.GetExpiredTECNs()).ToList(); + + List tecnNotificationUserEmails = new(); + + if (expiredEcns.Any()) { + List emails = (await _ecnService.GetTECNNotificationUserEmails()).ToList(); + foreach (string email in emails) tecnNotificationUserEmails.Add(new MailAddress(email)); + } + + foreach (ECN ecn in expiredEcns) { + List trainingIds = (await _trainingService.GetTrainingIdsForECN(ecn.ECNNumber)).ToList(); + + foreach (int trainingId in trainingIds) { + await _trainingService.DeleteTrainingAssignment(trainingId); + + List trainingAssignmentIds = + (await _trainingService.GetTrainingAssignmentIdsForTraining(trainingId)).ToList(); + + foreach (int assignmentId in trainingAssignmentIds) { + await _trainingService.DeleteDocAssignment(assignmentId); + } + + await _trainingService.MarkTrainingAsComplete(trainingId); + } + + string recipientEmail = await _userService.GetUserEmail(ecn.OriginatorID); + List recipientEamils = new List() { + new MailAddress(recipientEmail) + }; + + string subject = "Notice of Expired TECN"; + + StringBuilder bodyBuilder = new(); + bodyBuilder.Append($"Good day, TECN# {ecn.ECNNumber} expired on {ecn.ExpirationDate.ToString("MMMM dd, yyyy")}. "); + bodyBuilder.Append($"
Review TECN here. "); + + await _smtpService.SendEmail(recipientEamils, tecnNotificationUserEmails, subject, bodyBuilder.ToString()); + } + } catch (Exception ex) { + StringBuilder errMsgBuilder = new(); + errMsgBuilder.Append("An exception occurred when attempting to process expired TECNs. "); + errMsgBuilder.Append($"Exception: {ex.Message}"); + _logger.LogError(errMsgBuilder.ToString()); + isInternalError = true; + } finally { + DateTime end = DateTime.Now; + double latencyInMS = (end - start).TotalMilliseconds; + _monInClient.PostMetric(metricName + "Latency", latencyInMS); + + if (isInternalError) { + _monInClient.PostStatus(metricName, State.Critical); + } else { + _monInClient.PostStatus(metricName, State.Ok); + } + } + } +} diff --git a/FabApprovalWorkerService/Workers/ExpiringTECNWorker.cs b/FabApprovalWorkerService/Workers/ExpiringTECNWorker.cs index 3b8e975..cb99afb 100644 --- a/FabApprovalWorkerService/Workers/ExpiringTECNWorker.cs +++ b/FabApprovalWorkerService/Workers/ExpiringTECNWorker.cs @@ -1,6 +1,8 @@ using FabApprovalWorkerService.Models; using FabApprovalWorkerService.Services; +using Infineon.Monitoring.MonA; + using Quartz; using System.Net.Mail; @@ -10,26 +12,29 @@ namespace FabApprovalWorkerService.Workers; public class ExpiringTECNWorker : IJob { private readonly ILogger _logger; - private readonly IMonInWorkerClient _monInClient; + private readonly IMonInClient _monInClient; private readonly IUserService _userService; private readonly IECNService _ecnService; private readonly ISmtpService _smtpService; + private readonly string _baseUrl; public ExpiringTECNWorker(ILogger logger, - IMonInWorkerClient monInClient, + IMonInClient monInClient, IUserService userService, IECNService ecnService, ISmtpService smtpService) { _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); _monInClient = monInClient ?? - throw new ArgumentNullException("IMonInWorkerClient not injected"); + throw new ArgumentNullException("IMonInClient not injected"); _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); _ecnService = ecnService ?? throw new ArgumentNullException("IECNService not injected"); _smtpService = smtpService ?? throw new ArgumentNullException("ISmtpService not injected"); + _baseUrl = Environment.GetEnvironmentVariable("FabApprovalBaseUrl") ?? + throw new ArgumentNullException("FabApprovalBaseUrl environment variable not found"); } public async Task Execute(IJobExecutionContext context) { @@ -45,12 +50,15 @@ public class ExpiringTECNWorker : IJob { _logger.LogInformation($"There are {expiringTECNs.Count()} TECNs expiring in the next 5 days"); + IEnumerable tecnNotificationUserEmails = new List(); + if (expiringTECNs.Any()) + tecnNotificationUserEmails = await _ecnService.GetTECNNotificationUserEmails(); + foreach (ECN eCN in expiringTECNs) { string recipientEmail = await _userService.GetUserEmail(eCN.OriginatorID); MailAddress recipientAddress = new MailAddress(recipientEmail); List recipientList = new () { recipientAddress }; - IEnumerable tecnNotificationUserEmails = await _ecnService.GetTECNNotificationUserEmails(); List ccRecipientList = new(); foreach (string email in tecnNotificationUserEmails) { ccRecipientList.Add(new MailAddress(email)); @@ -59,10 +67,10 @@ public class ExpiringTECNWorker : IJob { StringBuilder bodyBuilder = new(); bodyBuilder.Append($"Good day, TECN# {eCN.ECNNumber} will be expire on "); bodyBuilder.Append($"{eCN.ExpirationDate.ToString("MMMM dd, yyyy")}. "); - bodyBuilder.Append($"
Review TECN "); + bodyBuilder.Append($"
Review TECN
"); bodyBuilder.Append("here "); - string subject = $"Notice of expiring TECN - {eCN.Title}"; + string subject = $"Notice of Expiring TECN - {eCN.Title}"; await _smtpService.SendEmail(recipientList, ccRecipientList, subject, bodyBuilder.ToString()); } @@ -75,12 +83,12 @@ public class ExpiringTECNWorker : IJob { } finally { DateTime end = DateTime.Now; double latencyInMS = (end - start).TotalMilliseconds; - _monInClient.PostAverage(metricName + "Latency", latencyInMS); + _monInClient.PostMetric(metricName + "Latency", latencyInMS); if (isInternalError) { - _monInClient.PostStatus(metricName, StatusValue.Critical); + _monInClient.PostStatus(metricName, State.Critical); } else { - _monInClient.PostStatus(metricName, StatusValue.Ok); + _monInClient.PostStatus(metricName, State.Ok); } } } diff --git a/FabApprovalWorkerService/Workers/PendingOOOStatusWorker.cs b/FabApprovalWorkerService/Workers/PendingOOOStatusWorker.cs index fb61ad1..dc9e11d 100644 --- a/FabApprovalWorkerService/Workers/PendingOOOStatusWorker.cs +++ b/FabApprovalWorkerService/Workers/PendingOOOStatusWorker.cs @@ -1,6 +1,8 @@ using FabApprovalWorkerService.Models; using FabApprovalWorkerService.Services; +using Infineon.Monitoring.MonA; + using Quartz; using System.Text; @@ -9,11 +11,11 @@ namespace FabApprovalWorkerService.Workers; public sealed class PendingOOOStatusWorker : IJob { private readonly ILogger _logger; - private readonly IMonInWorkerClient _monInClient; + private readonly IMonInClient _monInClient; private readonly IUserService _userService; public PendingOOOStatusWorker(ILogger logger, - IMonInWorkerClient monInClient, + IMonInClient monInClient, IUserService userService) { _logger = logger; if (_logger is null) @@ -21,7 +23,7 @@ public sealed class PendingOOOStatusWorker : IJob { _monInClient = monInClient; if (_monInClient is null) { - throw new ArgumentNullException("IMonInWorkerClient not injected"); + throw new ArgumentNullException("IMonInClient not injected"); } _userService = userService; @@ -39,25 +41,27 @@ public sealed class PendingOOOStatusWorker : IJob { _logger.LogInformation("Attempting to set OOO status for users pending earlier than now"); List pendingOOOUsers = await _userService.GetAllPendingOOOUsersAsync(); + + _logger.LogInformation($"There are {pendingOOOUsers.Count()} pending OOO users"); foreach (OOOTemp oooTemp in pendingOOOUsers) { - Task userAlreadyOOO = _userService.IsUserAlreadyOOO(oooTemp.OOOUserID); - Task delegateAlreadyADelegate = _userService.IsDelegatorAlreadyDelegatedTo(oooTemp.DelegatedTo); + bool userAlreadyOOO = await _userService.IsUserAlreadyOOO(oooTemp.OOOUserID); + bool delegateAlreadyADelegate = await _userService.IsDelegatorAlreadyDelegatedTo(oooTemp.DelegatedTo); - if (!userAlreadyOOO.Result && !delegateAlreadyADelegate.Result) { - List enableOOOTasks = new(); - enableOOOTasks.Add(_userService.InsertDelegatedRoles(oooTemp.OOOUserID)); - enableOOOTasks.Add(_userService.DelegateUserSubRoles(oooTemp.OOOUserID, oooTemp.DelegatedTo)); - enableOOOTasks.Add(_userService.DelegateApprovalsForUser(oooTemp.OOOUserID, oooTemp.DelegatedTo)); - Task enableOOOTasksResult = Task.WhenAll(enableOOOTasks); + if (!userAlreadyOOO && !delegateAlreadyADelegate) { + await _userService.InsertDelegatedRoles(oooTemp.OOOUserID); + await _userService.DelegateUserSubRoles(oooTemp.OOOUserID, oooTemp.DelegatedTo); + await _userService.DelegateApprovalsForUser(oooTemp.OOOUserID, oooTemp.DelegatedTo); - if (enableOOOTasksResult.IsCompletedSuccessfully) { - bool userIsNowOOO = await _userService.FlagUserAsOOO(oooTemp); - if (userIsNowOOO) { - oooTemp.Processed = true; - await _userService.SetOOOTempProcessed(oooTemp); - } + bool userIsNowOOO = await _userService.FlagUserAsOOO(oooTemp); + if (userIsNowOOO) { + oooTemp.Processed = true; + await _userService.SetOOOTempProcessed(oooTemp); } + } else if (userAlreadyOOO) { + _logger.LogInformation($"User {oooTemp.OOOUserID} is already OOO"); + } else if (delegateAlreadyADelegate) { + _logger.LogInformation($"Delegate {oooTemp.DelegatedTo} is already a delegate"); } } @@ -71,12 +75,12 @@ public sealed class PendingOOOStatusWorker : IJob { } finally { DateTime end = DateTime.Now; double latencyInMS = (end - start).TotalMilliseconds; - _monInClient.PostAverage(metricName + "Latency", latencyInMS); + _monInClient.PostMetric(metricName + "Latency", latencyInMS); if (isInternalError) { - _monInClient.PostStatus(metricName, StatusValue.Critical); + _monInClient.PostStatus(metricName, State.Critical); } else { - _monInClient.PostStatus(metricName, StatusValue.Ok); + _monInClient.PostStatus(metricName, State.Ok); } } } diff --git a/FabApprovalWorkerServiceTests/ECNServiceTests.cs b/FabApprovalWorkerServiceTests/ECNServiceTests.cs index cd54a0d..394ea80 100644 --- a/FabApprovalWorkerServiceTests/ECNServiceTests.cs +++ b/FabApprovalWorkerServiceTests/ECNServiceTests.cs @@ -115,21 +115,21 @@ internal class ECNServiceTests { OriginatorID = 1, Title = "title1", IsTECN = true, - ExpirationDate = DateTime.Now.AddHours(-2) + ExpirationDate = DateTime.Now.Date.AddHours(2) }, new ECN() { ECNNumber = 2, OriginatorID = 1, Title = "title2", IsTECN = true, - ExpirationDate = DateTime.Now.AddHours(-20) + ExpirationDate = DateTime.Now.Date.AddHours(20) }, new ECN() { ECNNumber = 3, OriginatorID = 1, Title = "title3", IsTECN = true, - ExpirationDate = DateTime.Now.AddHours(-12) + ExpirationDate = DateTime.Now.Date.AddHours(12) }, }; @@ -186,22 +186,22 @@ internal class ECNServiceTests { OriginatorID = 1, Title = "title1", IsTECN = true, - ExpirationDate = DateTime.Now.AddHours(-2) + ExpirationDate = DateTime.Now.Date.AddHours(2) }, new ECN() { ECNNumber = 2, OriginatorID = 1, Title = "title2", IsTECN = true, - ExpirationDate = DateTime.Now.AddHours(-20) + ExpirationDate = DateTime.Now.Date.AddHours(20) }, new ECN() { ECNNumber = 3, OriginatorID = 1, Title = "title3", IsTECN = true, - ExpirationDate = DateTime.Now.AddHours(-12), - ExtensionDate = DateTime.Now.AddDays(10) + ExpirationDate = DateTime.Now.Date.AddHours(12), + ExtensionDate = DateTime.Now.Date.AddDays(10) }, }; diff --git a/FabApprovalWorkerServiceTests/TrainingServiceTests.cs b/FabApprovalWorkerServiceTests/TrainingServiceTests.cs index 8f75830..fa81327 100644 --- a/FabApprovalWorkerServiceTests/TrainingServiceTests.cs +++ b/FabApprovalWorkerServiceTests/TrainingServiceTests.cs @@ -26,4 +26,147 @@ public class TrainingServiceTests { public void TrainingServiceWithNullDalServiceShouldThrowException() { Assert.Throws(() => new TrainingService(_mockLogger.Object, null)); } + + [Test] + public void DeleteDocAssignmentWithInvalidIdShouldThrowException() { + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => await _trainingService.DeleteDocAssignment(-1)); + } + + [Test] + public void DeleteDocAssignmentWithDbErrorShouldThrowException() { + _mockDalService.Setup(d => d.ExecuteAsync(It.IsAny())).Throws(new Exception()); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => await _trainingService.DeleteDocAssignment(1)); + } + + [Test] + public async Task DeleteDocAssignmentShouldExecuteSqlQuery() { + _mockDalService.Setup(d => d.ExecuteAsync(It.IsAny())).Returns(Task.FromResult(3)); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + await _trainingService.DeleteDocAssignment(3); + + _mockDalService.Verify(d => d.ExecuteAsync(It.IsAny())); + } + + [Test] + public void DeleteTrainingAssignmentWithInvalidIdShouldThrowException() { + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => await _trainingService.DeleteTrainingAssignment(-1)); + } + + [Test] + public void DeleteTrainingAssignmentWithDbErrorShouldThrowException() { + _mockDalService.Setup(d => d.ExecuteAsync(It.IsAny())).Throws(new Exception()); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => await _trainingService.DeleteTrainingAssignment(1)); + } + + [Test] + public async Task DeleteTrainingAssignmentShouldExecuteSqlQuery() { + _mockDalService.Setup(d => d.ExecuteAsync(It.IsAny())).Returns(Task.FromResult(3)); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + await _trainingService.DeleteTrainingAssignment(3); + + _mockDalService.Verify(d => d.ExecuteAsync(It.IsAny())); + } + + [Test] + public void GetTrainingAssignmentIdsForTrainingWithInvalidIdShouldThrowException() { + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => { + IEnumerable ids = await _trainingService.GetTrainingAssignmentIdsForTraining(-1); + }); + } + + [Test] + public void GetTrainingAssignmentIdsForTrainingWithDbErrorShouldThrowException() { + _mockDalService.Setup(d => d.QueryAsync(It.IsAny())).Throws(new Exception()); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => await _trainingService.GetTrainingAssignmentIdsForTraining(1)); + } + + [Test] + public async Task GetTrainingAssignmentIdsForTrainingShouldReturnExpectedIds() { + IEnumerable expectedIds = new List() { 4, 7, 2 }; + + _mockDalService.Setup(d => d.QueryAsync(It.IsAny())).Returns(Task.FromResult(expectedIds)); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + IEnumerable actualIds = await _trainingService.GetTrainingAssignmentIdsForTraining(1); + + Assert.That(actualIds.Count(), Is.EqualTo(expectedIds.Count())); + } + + [Test] + public void GetTrainingIdsForEcnWithInvalidIdShouldThrowException() { + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => { + IEnumerable ids = await _trainingService.GetTrainingIdsForECN(-1); + }); + } + + [Test] + public void GetTrainingIdsForEcnWithDbErrorShouldThrowException() { + _mockDalService.Setup(d => d.QueryAsync(It.IsAny())).Throws(new Exception()); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => await _trainingService.GetTrainingIdsForECN(1)); + } + + [Test] + public async Task GetTrainingIdsForEcnsShouldReturnExpectedIds() { + IEnumerable expectedIds = new List() { 4, 7, 2 }; + + _mockDalService.Setup(d => d.QueryAsync(It.IsAny())).Returns(Task.FromResult(expectedIds)); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + IEnumerable actualIds = await _trainingService.GetTrainingIdsForECN(1); + + Assert.That(actualIds.Count(), Is.EqualTo(expectedIds.Count())); + } + + [Test] + public void MarkTrainingAsCompleteWithInvalidIdShouldThrowException() { + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task() => await _trainingService.MarkTrainingAsComplete(-1)); + } + + [Test] + public void MarkTrainingCompleteWithDbErrorShouldThrowException() { + _mockDalService.Setup(d => d.ExecuteAsync(It.IsAny())).Throws(new Exception()); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + Assert.ThrowsAsync(async Task () => await _trainingService.MarkTrainingAsComplete(1)); + } + + [Test] + public async Task MarkTrainingCompleteShouldExecuteSql() { + _mockDalService.Setup(d => d.ExecuteAsync(It.IsAny())).Returns(Task.FromResult(1)); + + _trainingService = new TrainingService(_mockLogger.Object, _mockDalService.Object); + + await _trainingService.MarkTrainingAsComplete(1); + + _mockDalService.Verify(d => d.ExecuteAsync(It.IsAny())); + } } diff --git a/FabApprovalWorkerServiceTests/UserServiceTests.cs b/FabApprovalWorkerServiceTests/UserServiceTests.cs index 2f08813..c2a5b8c 100644 --- a/FabApprovalWorkerServiceTests/UserServiceTests.cs +++ b/FabApprovalWorkerServiceTests/UserServiceTests.cs @@ -272,13 +272,6 @@ internal class UserServiceTests { Assert.ThrowsAsync(async Task () => await _userService.RemoveDelegatedUserSubRoles(0, 2)); } - [Test] - public async Task RemoveDelegateUserSubRolesWithInvalidDelegateIdShouldThrowException() { - _userService = new UserService(MOCK_LOGGER, _mockDalService.Object); - - Assert.ThrowsAsync(async Task () => await _userService.RemoveDelegatedUserSubRoles(2, 0)); - } - [Test] public async Task RemoveDelegatedUserSubRolesWithValidParamsShouldReturnTrue() { IEnumerable roleIds = new List() {1, 2}; @@ -323,13 +316,6 @@ internal class UserServiceTests { Assert.ThrowsAsync(async Task () => await _userService.RemoveDelegatedApprovalsForUser(0, 2)); } - [Test] - public async Task RemoveDelegatedApprovalsForUserWithInvalidDelegateIdShouldThrowException() { - _userService = new UserService(MOCK_LOGGER, _mockDalService.Object); - - Assert.ThrowsAsync(async Task () => await _userService.RemoveDelegatedApprovalsForUser(2, 0)); - } - [Test] public async Task RemoveDelegatedApprovalsForUserWithValidUserIdShouldReturnTrue() { IEnumerable roleIds = new List() { 1, 2 };