From de041e256c25f8968b74101b445776fee6f24349 Mon Sep 17 00:00:00 2001 From: Herrera Date: Mon, 29 Jun 2026 16:08:55 -0700 Subject: [PATCH 1/3] PSP-11710 : PIMS Notifications Panel not Displaying Reminders (BVT Observations) - HOTFIX --- .../api/Repositories/Ches/ChesRepository.cs | 22 ++++++++++++++++--- .../api/Services/NotificationUserService.cs | 12 +++++----- .../INotificationUserOutputRepository.cs | 3 ++- .../NotificationUserOutputRepository.cs | 21 +++++++++--------- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/source/backend/api/Repositories/Ches/ChesRepository.cs b/source/backend/api/Repositories/Ches/ChesRepository.cs index d350979e69..441618da1a 100644 --- a/source/backend/api/Repositories/Ches/ChesRepository.cs +++ b/source/backend/api/Repositories/Ches/ChesRepository.cs @@ -2,7 +2,6 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mime; -using System.Security.Authentication; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -12,6 +11,7 @@ using Pims.Api.Models.CodeTypes; using Pims.Api.Models.Config; using Pims.Api.Models.Requests.Http; +using Pims.Core.Api.Exceptions; using Polly.Registry; namespace Pims.Api.Repositories.Ches @@ -98,33 +98,49 @@ public async Task> SendEmailAsync(EmailRequest r _logger.LogError("CHES email send failed: {Status} {Reason} {Body}", response.StatusCode, response.ReasonPhrase, errorBody); result.Message = $"CHES email send failed: {response.StatusCode} {response.ReasonPhrase}. Response body: {errorBody}"; } + + return result; } catch (HttpRequestException ex) { result.Status = ExternalResponseStatus.Error; result.Message = $"HTTP error sending CHES email: {ex.Message}"; _logger.LogError(ex, "HTTP error sending CHES email."); + + return result; } catch (TaskCanceledException ex) { result.Status = ExternalResponseStatus.Error; result.Message = $"Timeout sending CHES email: {ex.Message}"; _logger.LogError(ex, "Timeout sending CHES email."); + + return result; } catch (JsonException ex) { result.Status = ExternalResponseStatus.Error; result.Message = $"Serialization error: {ex.Message}"; _logger.LogError(ex, "Serialization error sending CHES email."); + + return result; } catch (AuthenticationException ex) { - result.Status = ExternalResponseStatus.Error; + result.Status = ExternalResponseStatus.NotExecuted; result.Message = $"Authentication error: {ex.Message}"; _logger.LogError(ex, "Authentication error sending CHES email."); + + return result; } + catch (Exception ex) + { + result.Status = ExternalResponseStatus.Error; + result.Message = $"Unexpected error sending CHES email: {ex.Message}"; + _logger.LogError(ex, "Unexpected error sending CHES email."); - return result; + return result; + } } public async Task TryGetHealthAsync() diff --git a/source/backend/api/Services/NotificationUserService.cs b/source/backend/api/Services/NotificationUserService.cs index ac58982115..ca55e4ebd3 100644 --- a/source/backend/api/Services/NotificationUserService.cs +++ b/source/backend/api/Services/NotificationUserService.cs @@ -57,8 +57,6 @@ public async Task PushNotificationUser(long notificationUserId) } userNotification.NotificationRetryCnt = userNotification.NotificationRetryCnt.HasValue ? ++userNotification.NotificationRetryCnt : 1; - var updatedNotification = _notificationUserOutputRepository.Update(userNotification); - _notificationUserOutputRepository.CommitTransaction(); if (userNotification.NotificationOutputTypeCode == NotificationOutputTypes.EMAIL.ToString()) { @@ -77,24 +75,24 @@ public async Task PushNotificationUser(long notificationUserId) { case ExternalResponseStatus.Success: { - updatedNotification.NotificationSentDt = DateTime.UtcNow; + userNotification.NotificationSentDt = DateTime.UtcNow; } break; case ExternalResponseStatus.Error: case ExternalResponseStatus.NotExecuted: { - updatedNotification.NotificationErrorDt = DateOnly.FromDateTime(DateTime.UtcNow); - updatedNotification.NotificationErrorReason = chesResponse.Message; + userNotification.NotificationErrorDt = DateOnly.FromDateTime(DateTime.UtcNow); + userNotification.NotificationErrorReason = chesResponse.Message; } break; } } else { - updatedNotification.NotificationSentDt = DateTime.UtcNow; + userNotification.NotificationSentDt = DateTime.UtcNow; } - _notificationUserOutputRepository.Update(updatedNotification); + _ = await _notificationUserOutputRepository.Update(userNotification); _notificationUserOutputRepository.CommitTransaction(); return; diff --git a/source/backend/dal/Repositories/Interfaces/INotificationUserOutputRepository.cs b/source/backend/dal/Repositories/Interfaces/INotificationUserOutputRepository.cs index 024838cead..a601db0d14 100644 --- a/source/backend/dal/Repositories/Interfaces/INotificationUserOutputRepository.cs +++ b/source/backend/dal/Repositories/Interfaces/INotificationUserOutputRepository.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using Pims.Api.Models.Models.Concepts.Notification; using Pims.Dal.Entities; @@ -10,6 +11,6 @@ public interface INotificationUserOutputRepository : IRepository public PimsNotificationUserOutput GetById(long notificationUserOutputId); - public PimsNotificationUserOutput Update(PimsNotificationUserOutput userNotification); + public Task Update(PimsNotificationUserOutput userNotification); } } diff --git a/source/backend/dal/Repositories/NotificationUserOutputRepository.cs b/source/backend/dal/Repositories/NotificationUserOutputRepository.cs index f67de4c77d..d9c92d43da 100644 --- a/source/backend/dal/Repositories/NotificationUserOutputRepository.cs +++ b/source/backend/dal/Repositories/NotificationUserOutputRepository.cs @@ -1,8 +1,9 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; +using System.Threading.Tasks; using LinqKit; +using Medallion.Threading; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Pims.Api.Models.Models.Concepts.Notification; @@ -14,12 +15,16 @@ namespace Pims.Dal.Repositories { public class NotificationUserOutputRepository : BaseRepository, INotificationUserOutputRepository { + private readonly IDistributedLockProvider _synchronizationProvider; + public NotificationUserOutputRepository( PimsContext dbContext, ClaimsPrincipal user, - ILogger logger) + IDistributedLockProvider synchronizationProvider, + ILogger logger) : base(dbContext, user, logger) { + _synchronizationProvider = synchronizationProvider; } public PimsNotificationUserOutput GetById(long notificationUserOutputId) @@ -75,25 +80,21 @@ public PimsNotificationUserOutput GetById(long notificationUserOutputId) .FirstOrDefault(x => x.NotificationUserOutputId == notificationUserOutputId) ?? throw new KeyNotFoundException(); } - public PimsNotificationUserOutput Update(PimsNotificationUserOutput userNotification) + public async Task Update(PimsNotificationUserOutput userNotification) { - try + var @lock = _synchronizationProvider.CreateLock("NotificationUserOutputLock"); + await using (await @lock.AcquireAsync()) { - using var scope = Logger.QueryScope(); userNotification.ThrowIfNull(nameof(userNotification)); var existingUserNotification = Context.PimsNotificationUserOutputs .FirstOrDefault(x => x.NotificationUserOutputId == userNotification.NotificationUserOutputId); Context.Entry(existingUserNotification).CurrentValues.SetValues(userNotification); + Context.Update(existingUserNotification); return existingUserNotification; } - catch(Exception ex) - { - Logger.LogError(ex.Message); - return null; - } } public IEnumerable GetAllByFilter(NotificationUserSearchFilterModel filter) From 2921f26877bf7f913d1f65404a9c415185c18ca9 Mon Sep 17 00:00:00 2001 From: Herrera Date: Mon, 29 Jun 2026 16:18:11 -0700 Subject: [PATCH 2/3] - UPDATE --- .../dal/Repositories/NotificationUserOutputRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/backend/dal/Repositories/NotificationUserOutputRepository.cs b/source/backend/dal/Repositories/NotificationUserOutputRepository.cs index d9c92d43da..f59e132c2b 100644 --- a/source/backend/dal/Repositories/NotificationUserOutputRepository.cs +++ b/source/backend/dal/Repositories/NotificationUserOutputRepository.cs @@ -123,7 +123,7 @@ public IEnumerable GetAllByFilter(NotificationUserSe if(filter.NotificationTriggerDate is not null) { - predicateBuilder.And(x => x.NotificationUser.Notification.NotificationTriggerDate == filter.NotificationTriggerDate); + predicateBuilder.And(x => x.NotificationUser.Notification.NotificationTriggerDate <= filter.NotificationTriggerDate); } var query = Context.PimsNotificationUserOutputs From 6fd9a5cb55d6f8a3eba7e29f5681a086f4cc935a Mon Sep 17 00:00:00 2001 From: Herrera Date: Mon, 29 Jun 2026 16:31:26 -0700 Subject: [PATCH 3/3] - bump --- source/backend/api/Pims.Api.csproj | 4 ++-- source/frontend/package-lock.json | 4 ++-- source/frontend/package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/backend/api/Pims.Api.csproj b/source/backend/api/Pims.Api.csproj index d62898afe0..af0c886284 100644 --- a/source/backend/api/Pims.Api.csproj +++ b/source/backend/api/Pims.Api.csproj @@ -2,8 +2,8 @@ 0ef6255f-9ea0-49ec-8c65-c172304b4926 - 6.3.0-123.13 - 6.3.0.123 + 6.3.1-123.13 + 6.3.1.123 true {16BC0468-78F6-4C91-87DA-7403C919E646} net8.0 diff --git a/source/frontend/package-lock.json b/source/frontend/package-lock.json index ed8eb2b2e1..0d50b52fcb 100644 --- a/source/frontend/package-lock.json +++ b/source/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "6.3.0-123.0", + "version": "6.3.1-123.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "frontend", - "version": "6.3.0-123.0", + "version": "6.3.1-123.0", "dependencies": { "@bcgov/bc-sans": "1.0.1", "@bcgov/design-tokens": "3.0.0-rc1", diff --git a/source/frontend/package.json b/source/frontend/package.json index e69d38eb2f..f6084020d9 100644 --- a/source/frontend/package.json +++ b/source/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "6.3.0-123.13", + "version": "6.3.1-123.13", "private": true, "dependencies": { "@bcgov/bc-sans": "1.0.1",