Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
483e130
TD-5474: Create a new messaging service project
ArunimaGeorge Apr 24, 2025
f2144fe
Merge pull request #1096 from TechnologyEnhancedLearning/Develop/Feat…
ArunimaGeorge Apr 25, 2025
b2cdaf8
TD-5477: Change in folder structure
ArunimaGeorge Apr 28, 2025
b6e49b3
TD-5477: Create an email queue processing system.
ArunimaGeorge May 27, 2025
85e49e4
TD-5477: Added history details in SPs.
ArunimaGeorge Jun 9, 2025
ae4f434
Merge pull request #1142 from TechnologyEnhancedLearning/Develop/Feat…
ArunimaGeorge Jun 9, 2025
ffb5438
Merging changes from RC to Messaging Service
ArunimaGeorge Jun 17, 2025
c9bec6e
Merge pull request #1187 from TechnologyEnhancedLearning/Develop/Feat…
ArunimaGeorge Jun 17, 2025
acacd84
Merge branch 'MessagingService-OpenAPI-Integration' into TD-5490
swapnamol-abraham Jul 3, 2025
c230650
Merge pull request #1236 from TechnologyEnhancedLearning/TD-5490
swapnamol-abraham Jul 3, 2025
8044b46
TD-5736: Replace existing Web UI service SMTP notifications with Gov …
swapnamol-abraham Jul 8, 2025
218d0da
Merge pull request #1243 from TechnologyEnhancedLearning/Develop/Fixe…
swapnamol-abraham Jul 9, 2025
19b01d8
TD-5790: Save Successful email transactions for One-off emails
ArunimaGeorge Jul 11, 2025
ea5bc0c
TD-5736: Implemented the Invite user and catalogue permission request…
swapnamol-abraham Jul 11, 2025
4ff2d67
TD-5736: Template data updaated
swapnamol-abraham Jul 11, 2025
7656887
Merge pull request #1257 from TechnologyEnhancedLearning/Develop/Feat…
ArunimaGeorge Jul 11, 2025
17f32dd
Merge pull request #1259 from TechnologyEnhancedLearning/Develop/Fixe…
swapnamol-abraham Jul 11, 2025
764fe32
TD-5814: Replaced the SMTP notification with GovNotify in Full user u…
ArunimaGeorge Jul 14, 2025
21ccde4
Merge pull request #1264 from TechnologyEnhancedLearning/Develop/Feat…
ArunimaGeorge Jul 14, 2025
9426f30
Added Not Exists condition in sql data queries.
ArunimaGeorge Jul 15, 2025
ca5ef29
latest from RC
ArunimaGeorge Feb 24, 2026
c439704
Merge latest from RC to Messaging service
ArunimaGeorge Feb 24, 2026
2b1ab38
Merge pull request #1710 from TechnologyEnhancedLearning/Merge-RC-Mes…
AnjuJose011 Mar 3, 2026
4bee6a8
TD-6874: Implement GovNotify History in LH Admin UI
ArunimaGeorge Mar 20, 2026
79dd9a1
Merge pull request #1748 from TechnologyEnhancedLearning/Develop/Feat…
ArunimaGeorge Mar 30, 2026
df0cbf4
TD-7055: Changed the response format from Open API send email method.
ArunimaGeorge Mar 30, 2026
8a7e470
Merge pull request #1755 from TechnologyEnhancedLearning/Develop/Feat…
ArunimaGeorge Apr 8, 2026
0d0e6a4
Merge latest RC changes to Messaging Service.
ArunimaGeorge Apr 8, 2026
ca7e26d
Model update
ArunimaGeorge Apr 8, 2026
e8e05c7
Merge pull request #1770 from TechnologyEnhancedLearning/Merge-RC-to-…
ArunimaGeorge Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,5 @@ obj
/LearningHub.Nhs.WebUI.BlazorClient/wwwroot/appsettings.Development.json
/LearningHub.Nhs.WebUI.BlazorClient/Properties/launchSettings.json
/.github/dependabot.yml
/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.dbmdl
/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.jfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using LearningHub.Nhs.AdminUI.Configuration;
using LearningHub.Nhs.AdminUI.Extensions;
using LearningHub.Nhs.AdminUI.Interfaces;
using LearningHub.Nhs.Models.Paging;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Threading.Tasks;
using LearningHub.Nhs.Models.GovNotifyMessaging;

namespace LearningHub.Nhs.AdminUI.Controllers
{
/// <summary>
/// Defines the <see cref="GovNotifyDashboardController" />.
/// </summary>
public class GovNotifyDashboardController : BaseController
{
/// <summary>
/// Defines the websettings.
/// </summary>
private readonly IOptions<WebSettings> websettings;

/// <summary>
/// Defines the govNotifyDashboardService.
/// </summary>
private IGovNotifyDashboardService govNotifyDashboardService;

/// <summary>
/// Initializes a new instance of the <see cref="GovNotifyDashboardController"/> class.
/// </summary>
/// <param name="hostingEnvironment">The hostingEnvironment<see cref="IWebHostEnvironment"/>.</param>
/// <param name="govNotifyDashboardService">The govNotifyDashboardService<see cref="IGovNotifyDashboardService"/>.</param>
/// <param name="websettings">The websettings<see cref="IOptions{WebSettings}"/>.</param>
public GovNotifyDashboardController(IWebHostEnvironment hostingEnvironment,
IGovNotifyDashboardService govNotifyDashboardService,
IOptions<WebSettings> websettings)
: base(hostingEnvironment)
{
this.websettings = websettings;
this.govNotifyDashboardService = govNotifyDashboardService;
}

/// <summary>
/// Initial call to get paginated result.
/// </summary>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
public async Task<IActionResult> Index()
{
return await this.GetMessageRequests(
new PagingRequestModel
{
Page = 1,
PageSize = this.websettings.Value.DefaultPageSize,
SortColumn = "CreatedAt",
SortDirection = "D",
});
}

/// <summary>
/// Get paginated result based on the filters.
/// </summary>
/// <param name="pagingRequestModel"></param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
[HttpPost]
public async Task<IActionResult> Index(string pagingRequestModel)
{
var requestModel = JsonConvert.DeserializeObject<PagingRequestModel>(pagingRequestModel);
return await this.GetMessageRequests(requestModel);
}

/// <summary>
/// Get message request details by id.
/// </summary>
/// <param name="id"></param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
[HttpGet]
public async Task<IActionResult> Details(int id)
{
var notification = await this.govNotifyDashboardService.GetMessageRequestById(id);
return this.View(notification);
}

private async Task<IActionResult> GetMessageRequests(PagingRequestModel requestModel)
{
requestModel.Sanitize();
requestModel.PageSize = this.websettings.Value.DefaultPageSize;

var model = new TablePagingViewModel<MessageRequestViewModel>
{
Results = await this.govNotifyDashboardService.GetPagedAsync(requestModel),
SortColumn = requestModel.SortColumn,
SortDirection = requestModel.SortDirection,
Filter = requestModel.Filter,
};

model.Paging = new PagingViewModel
{
CurrentPage = requestModel.Page,
HasItems = model.Results.Items.Any(),
PageSize = this.websettings.Value.DefaultPageSize,
TotalItems = model.Results.TotalItemCount,
};

model.ListPageHeader = new ListPageHeaderViewModel
{
TotalItemCount = model.Results.TotalItemCount,
DisplayedCount = model.Results.Items.Count(),
DefaultPageSize = this.websettings.Value.DefaultPageSize,
FilterCount = model.Filter != null ? model.Filter.Count() : 0,
CreateRequired = false,
};

return this.View(model);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace LearningHub.Nhs.AdminUI.Interfaces
{
using LearningHub.Nhs.Models.Common;
using LearningHub.Nhs.Models.GovNotifyMessaging;
using LearningHub.Nhs.Models.Paging;
using System.Threading.Tasks;

/// <summary>
/// Defines the <see cref="IGovNotifyDashboardService" />.
/// </summary>
public interface IGovNotifyDashboardService
{
/// <summary>
/// The GetPagedAsync.
/// </summary>
/// <param name="pagingRequestModel">The pagingRequestModel<see cref="PagingRequestModel"/>.</param>
/// <returns>The <see cref="PagedResultSet{MessageRequestViewModel}"/>.</returns>
Task<PagedResultSet<MessageRequestViewModel>> GetPagedAsync(PagingRequestModel pagingRequestModel);

/// <summary>
/// Get Message Request By Id.
/// </summary>
/// <param name="id">id.</param>
/// <returns>The <see cref="Task"/>.</returns>
Task<MessageRequestViewModel> GetMessageRequestById(int id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<PackageReference Include="HtmlSanitizer" Version="6.0.453" />
<PackageReference Include="IdentityModel" Version="4.6.0" />
<PackageReference Include="LearningHub.Nhs.Caching" Version="2.0.2" />
<PackageReference Include="LearningHub.Nhs.Models" Version="4.0.16" />
<PackageReference Include="LearningHub.Nhs.Models" Version="4.0.17" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.19.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.36" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.36" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur
services.AddScoped<IProviderService, ProviderService>();
services.AddScoped<IMoodleApiService, MoodleApiService>();
services.AddScoped<IMoodleBridgeApiService, MoodleBridgeApiService>();
services.AddScoped<IGovNotifyDashboardService, GovNotifyDashboardService>();

// Configure Azure Search
services.Configure<AzureSearchConfig>(configuration.GetSection("AzureSearch"));
Expand Down
130 changes: 130 additions & 0 deletions AdminUI/LearningHub.Nhs.AdminUI/Services/GovNotifyDashboardService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using LearningHub.Nhs.AdminUI.Interfaces;
using LearningHub.Nhs.Models.Common;
using LearningHub.Nhs.Models.Paging;
using Newtonsoft.Json;
using System.Threading.Tasks;
using System;
using LearningHub.Nhs.Models.GovNotifyMessaging;
using Newtonsoft.Json.Converters;
using System.Collections.Generic;

namespace LearningHub.Nhs.AdminUI.Services
{
/// <summary>
/// Defines the <see cref="GovNotifyDashboardService" />.
/// </summary>
public class GovNotifyDashboardService: BaseService, IGovNotifyDashboardService
{
/// <summary>
/// Initializes a new instance of the <see cref="GovNotifyDashboardService"/> class.
/// </summary>
/// <param name="learningHubHttpClient"></param>
/// <param name="openApiHttpClient"></param>
public GovNotifyDashboardService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient)
:base(learningHubHttpClient, openApiHttpClient)
{
}

/// <summary>
/// The GetPagedAsync.
/// </summary>
/// <param name="pagingRequestModel">The pagingRequestModel<see cref="PagingRequestModel"/>.</param>
/// <returns>The <see cref="PagedResultSet{MessageRequestViewModel}"/>.</returns>
public async Task<PagedResultSet<MessageRequestViewModel>> GetPagedAsync(PagingRequestModel pagingRequestModel)
{
try
{
PagedResultSet<MessageRequestViewModel> viewmodel = null;
var sortDirection = " ";

if (string.IsNullOrEmpty(pagingRequestModel.SortColumn))
{
pagingRequestModel.SortColumn = " ";
}

if (string.IsNullOrEmpty(pagingRequestModel.SortDirection))
{
pagingRequestModel.SortDirection = " ";
}
else
{
sortDirection = pagingRequestModel.SortDirection == "A" ? "ASC" :
pagingRequestModel.SortDirection == "D" ? "DESC" : "ASC";
}

var settings = new JsonSerializerSettings
{
Converters = new List<JsonConverter>
{
new StringEnumConverter()
}
};

var filter = JsonConvert.SerializeObject(pagingRequestModel.Filter, settings);
var client = await this.OpenApiHttpClient.GetClientAsync();

var request = $"GovNotifyMessage/GetMessageRequests"
+ $"/{pagingRequestModel.Page}"
+ $"/{pagingRequestModel.PageSize}"
+ $"/{pagingRequestModel.SortColumn}"
+ $"/{sortDirection}"
+$"/{Uri.EscapeDataString(filter)}";

var response = await client.GetAsync(request).ConfigureAwait(false);

if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
viewmodel = JsonConvert.DeserializeObject<PagedResultSet<MessageRequestViewModel>>(result);
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized
||
response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
throw new Exception("AccessDenied");
}

return viewmodel;
}
catch (Exception ex)
{
return null;
}
}

/// <summary>
/// Get message request details by id.
/// </summary>
/// <param name="id">id.</param>
/// <returns>The <see cref="Task"/>.</returns>
public async Task<MessageRequestViewModel> GetMessageRequestById(int id)
{
try
{
MessageRequestViewModel viewmodel = null;
var client = await this.OpenApiHttpClient.GetClientAsync();

var request = $"GovNotifyMessage/GetMessageRequestById/{id}";
var response = await client.GetAsync(request).ConfigureAwait(false);

if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
viewmodel = JsonConvert.DeserializeObject<MessageRequestViewModel>(result);
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized
||
response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
throw new Exception("AccessDenied");
}

return viewmodel;
}
catch (Exception ex)
{
return null;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
@model LearningHub.Nhs.Models.GovNotifyMessaging.MessageRequestViewModel
@using LearningHub.Nhs.AdminUI.Services

@{
ViewData["Title"] = "Details";
}
@section SideMenu {
@{
await Html.RenderPartialAsync("_NavSection");
}
}

<div class="panel-body admin-body">
<div class="d-flex flex-row justify-content-between col-12">
<a href="@Url.Action("Index", "GovNotifyDashboard")" class="pl-3"><i class="fa-solid fa-chevron-left">&nbsp;</i> Go back</a>
</div>
<div class="admin-section">
<div class="col-12">
<div class="id-container">ID @Model.Id</div>
<dl>
<dt>
Recipient
</dt>
<dd>
@Html.DisplayFor(model => model.Recipient)
</dd>
<dt>
Request type
</dt>
<dd>
@Html.DisplayFor(model => model.RequestType)
</dd>
<dt>
Request status
</dt>
<dd>
@Html.DisplayFor(model => model.RequestStatus)
</dd>
<dt>
Retry count
</dt>
<dd>
@Html.DisplayFor(model => model.RetryCount)
</dd>
<dt>
Created date
</dt>
<dd>
@Html.DisplayFor(model => model.CreatedAt)
</dd>
<dt>
Deliver after date
</dt>
<dd>
@Html.DisplayFor(model => model.DeliverAfter)
</dd>
<dt>
Sent Date
</dt>
<dd>
@Html.DisplayFor(model => model.SentAt)
</dd>
<dt>
Last attempt date
</dt>
<dd>
@Html.DisplayFor(model => model.LastAttemptAt)
</dd>
<dt>
Error message
</dt>
<dd>
@Html.Raw(OutputSanitizer.SanitizeOutputHtml(Model.ErrorMessage))
</dd>
</dl>
</div>
</div>

</div>

Loading
Loading