diff --git a/.gitignore b/.gitignore
index fcd06e014..5bc784140 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,5 @@ obj
/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj.user
/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj.user
/ReportAPI/LearningHub.Nhs.ReportApi/web.config
+/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.dbmdl
+/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.jfm
\ No newline at end of file
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj
index eba6b6ffa..2038ce016 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj
+++ b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj
@@ -89,7 +89,7 @@
-
+
diff --git a/LearningHub.Nhs.MessagingService/Model/SendEmailRequest.cs b/LearningHub.Nhs.MessagingService/Model/SendEmailRequest.cs
deleted file mode 100644
index da0044425..000000000
--- a/LearningHub.Nhs.MessagingService/Model/SendEmailRequest.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace LearningHub.Nhs.MessagingService.Model
-{
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
-
- ///
- /// Defines the .
- ///
- public class SendEmailRequest
- {
- ///
- /// Gets or Sets the Email.
- ///
- [Required]
- public string Email { get; set; }
-
- ///
- /// Gets or Sets the TemplateId.
- ///
- [Required]
- public string TemplateId { get; set; }
-
- ///
- /// Gets or Sets the Personalisation.
- ///
- public Dictionary Personalisation { get; set; }
- }
-}
diff --git a/LearningHub.Nhs.MessagingService/Model/SendSmsRequest.cs b/LearningHub.Nhs.MessagingService/Model/SendSmsRequest.cs
deleted file mode 100644
index cb2481cfe..000000000
--- a/LearningHub.Nhs.MessagingService/Model/SendSmsRequest.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace LearningHub.Nhs.MessagingService.Model
-{
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
-
- ///
- /// Defines the .
- ///
- public class SendSmsRequest
- {
- ///
- /// Gets or Sets the PhoneNumber.
- ///
- [Required]
- public string PhoneNumber { get; set; }
-
- ///
- /// Gets or Sets the TemplateId.
- ///
- [Required]
- public string TemplateId { get; set; }
-
- ///
- /// Gets or Sets the Personalisation.
- ///
- public Dictionary Personalisation { get; set; }
- }
-}
diff --git a/LearningHub.Nhs.MessagingService/Services/GovNotifyService.cs b/LearningHub.Nhs.MessagingService/Services/GovNotifyService.cs
deleted file mode 100644
index b81c8e7b2..000000000
--- a/LearningHub.Nhs.MessagingService/Services/GovNotifyService.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-namespace LearningHub.Nhs.MessagingService.Services
-{
- using System;
- using System.Collections.Generic;
- using System.Text.Json;
- using System.Threading.Tasks;
- using LearningHub.Nhs.MessagingService.Interfaces;
- using LearningHub.Nhs.MessagingService.Model;
- using Microsoft.Extensions.Options;
- using Notify.Client;
-
- ///
- /// GovNotify Service class.
- ///
- public class GovNotifyService : IGovNotifyService
- {
- private readonly NotificationClient client;
-
- ///
- /// Initializes a new instance of the class.
- /// GovNotifyService.
- ///
- /// The Messaging Service Model.
- public GovNotifyService(IOptions options)
- {
- this.client = new NotificationClient(options.Value.GovNotifyApiKey);
- }
-
- ///
- /// Sends an email via the UK Gov.Notify service.
- ///
- /// The recipient's email address.
- /// The ID of the Gov.Notify template to be used for the email.
- ///
- /// A dictionary containing key-value pairs for personalising the email template.
- /// Keys should match the placeholders in the Gov.Notify template.
- ///
- ///
- /// A unique message ID representing the queued email.
- ///
- public async Task SendEmailAsync(string email, string templateId, Dictionary personalisation)
- {
- var normalisedPersonlisation = new Dictionary();
- foreach (var item in personalisation)
- {
- if (item.Value is JsonElement element)
- {
- normalisedPersonlisation[item.Key] = element.ToString();
- }
- else
- {
- normalisedPersonlisation[item.Key] = item.Value;
- }
- }
-
- var response = await this.client.SendEmailAsync(email, templateId, normalisedPersonlisation);
- return response.id;
- }
-
- ///
- /// Sends an SMS via the UK Gov.Notify service.
- ///
- /// The recipient's phone number.
- /// The ID of the Gov.Notify template to be used for the SMS.
- ///
- /// A dictionary containing key-value pairs for personalising the SMS template.
- /// Keys should match the placeholders in the Gov.Notify template.
- ///
- ///
- /// A unique message ID representing the queued SMS.
- ///
- public async Task SendSmsAsync(string phoneNumber, string templateId, Dictionary personalisation)
- {
- var normalisedPersonlisation = new Dictionary();
- foreach (var item in personalisation)
- {
- if (item.Value is JsonElement element)
- {
- normalisedPersonlisation[item.Key] = element.ToString();
- }
- else
- {
- normalisedPersonlisation[item.Key] = item.Value;
- }
- }
-
- var response = await this.client.SendSmsAsync(phoneNumber, templateId, normalisedPersonlisation);
- return response.id;
- }
- }
-}
diff --git a/LearningHub.Nhs.WebUI.sln b/LearningHub.Nhs.WebUI.sln
index e4ca88071..43f5211d5 100644
--- a/LearningHub.Nhs.WebUI.sln
+++ b/LearningHub.Nhs.WebUI.sln
@@ -83,7 +83,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.WebUI.Autom
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MessagingService", "MessagingService", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.MessagingService", "LearningHub.Nhs.MessagingService\LearningHub.Nhs.MessagingService.csproj", "{713B0099-60E3-4D28-980F-448FC68BC7EE}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MessageQueueing", "MessageQueueing", "{FC592E2B-861F-4C9A-BD1A-95CB97D36285}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.MessageQueueing", "MessageQueueing\LearningHub.Nhs.MessageQueueing\LearningHub.Nhs.MessageQueueing.csproj", "{534A145F-1FE4-B601-48FF-979744373E4B}"
+EndProject
+Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "LearningHub.Nhs.MessageQueueing.Database", "MessageQueueing\LearningHub.Nhs.MessageQueueing.Database\LearningHub.Nhs.MessageQueueing.Database.sqlproj", "{AFC1A740-BBA1-44BC-8A52-A65D2E506E69}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.MessagingService", "MessagingService\LearningHub.Nhs.MessagingService\LearningHub.Nhs.MessagingService.csproj", "{CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -349,14 +355,34 @@ Global
{A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|Any CPU.Build.0 = Release|Any CPU
{A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|x64.ActiveCfg = Release|Any CPU
{A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|x64.Build.0 = Release|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|x64.ActiveCfg = Debug|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|x64.Build.0 = Debug|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|Any CPU.Build.0 = Release|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|x64.ActiveCfg = Release|Any CPU
- {713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|x64.Build.0 = Release|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Debug|x64.Build.0 = Debug|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Release|x64.ActiveCfg = Release|Any CPU
+ {534A145F-1FE4-B601-48FF-979744373E4B}.Release|x64.Build.0 = Release|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Debug|x64.Build.0 = Debug|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Debug|x64.Deploy.0 = Debug|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Release|x64.ActiveCfg = Release|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Release|x64.Build.0 = Release|Any CPU
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69}.Release|x64.Deploy.0 = Release|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Debug|x64.Build.0 = Debug|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Release|x64.ActiveCfg = Release|Any CPU
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -392,7 +418,9 @@ Global
{E585A74A-F358-4446-B10E-0FF07B4FF601} = {A4209011-1740-4902-B889-2F2FAF98383F}
{AAC8306E-1DEB-460D-84C7-40166D189B88} = {A4209011-1740-4902-B889-2F2FAF98383F}
{6167F037-166C-4C5A-81BE-55618E77D4E8} = {A4209011-1740-4902-B889-2F2FAF98383F}
- {713B0099-60E3-4D28-980F-448FC68BC7EE} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {534A145F-1FE4-B601-48FF-979744373E4B} = {FC592E2B-861F-4C9A-BD1A-95CB97D36285}
+ {AFC1A740-BBA1-44BC-8A52-A65D2E506E69} = {FC592E2B-861F-4C9A-BD1A-95CB97D36285}
+ {CCB52C7C-47B6-1AE7-7578-7A26B3FFEB71} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1ECA38C8-7C69-4DE6-8293-852C603F4217}
diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
index 1b4ac83d1..fa0dca0f8 100644
--- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
+++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
@@ -113,7 +113,7 @@
-
+
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.sqlproj b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.sqlproj
new file mode 100644
index 000000000..79c159525
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.sqlproj
@@ -0,0 +1,81 @@
+
+
+
+ Debug
+ AnyCPU
+ LearningHub.Nhs.MessageQueueing.Database
+ 2.0
+ 4.1
+ {afc1a740-bba1-44bc-8a52-a65d2e506e69}
+ Microsoft.Data.Tools.Schema.Sql.Sql160DatabaseSchemaProvider
+ Database
+
+
+ LearningHub.Nhs.MessageQueueing.Database
+ LearningHub.Nhs.MessageQueueing.Database
+ 1033, CI
+ BySchemaAndSchemaType
+ True
+ v4.7.2
+ CS
+ Properties
+ False
+ True
+ True
+
+
+ bin\Release\
+ $(MSBuildProjectName).sql
+ False
+ pdbonly
+ true
+ false
+ true
+ prompt
+ 4
+
+
+ bin\Debug\
+ $(MSBuildProjectName).sql
+ false
+ true
+ full
+ false
+ true
+ true
+ prompt
+ 4
+
+
+ 11.0
+
+ True
+ 11.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.sqlproj.user b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.sqlproj.user
new file mode 100644
index 000000000..0b07de1b2
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/LearningHub.Nhs.MessageQueueing.Database.sqlproj.user
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Scripts/Post-Deploy/Scripts/RequestStatusData.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Scripts/Post-Deploy/Scripts/RequestStatusData.sql
new file mode 100644
index 000000000..d09b31f81
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Scripts/Post-Deploy/Scripts/RequestStatusData.sql
@@ -0,0 +1,6 @@
+INSERT [dbo].[RequestStatus] ([Id], [RequestStatus]) VALUES (1, N'Pending')
+GO
+INSERT [dbo].[RequestStatus] ([Id], [RequestStatus]) VALUES (2, N'Sent')
+GO
+INSERT [dbo].[RequestStatus] ([Id], [RequestStatus]) VALUES (3, N'Failed')
+GO
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Scripts/Post-Deploy/Scripts/RequestTypeData.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Scripts/Post-Deploy/Scripts/RequestTypeData.sql
new file mode 100644
index 000000000..a933ca65a
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Scripts/Post-Deploy/Scripts/RequestTypeData.sql
@@ -0,0 +1,6 @@
+INSERT [dbo].[RequestType] ([Id], [RequestType]) VALUES (1, N'Email')
+GO
+INSERT [dbo].[RequestType] ([Id], [RequestType]) VALUES (2, N'SMS')
+GO
+INSERT [dbo].[RequestType] ([Id], [RequestType]) VALUES (3, N'SingleEmail')
+GO
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/CreateQueueRequests.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/CreateQueueRequests.sql
new file mode 100644
index 000000000..a7d8bb494
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/CreateQueueRequests.sql
@@ -0,0 +1,20 @@
+-------------------------------------------------------------------------------
+-- Author Arunima George
+-- Created 27-05-2025
+-- Purpose Create email requests.
+--
+-- Modification History
+--
+-- 27-05-2025 Arunima George Initial Revision
+-------------------------------------------------------------------------------
+
+Create PROCEDURE [dbo].[CreateQueueRequests]
+ @QueueRequests dbo.QueueRequestTableType READONLY
+AS
+BEGIN
+
+ INSERT INTO QueueRequests (RequestTypeId, Recipient, TemplateId, Personalisation, Status, RetryCount, CreatedAt, DeliverAfter)
+ SELECT 1, Recipient, TemplateId, Personalisation, 1, 0, SYSDATETIMEOFFSET(), DeliverAfter
+ FROM @QueueRequests;
+END
+GO
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/GetQueueRequests.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/GetQueueRequests.sql
new file mode 100644
index 000000000..7f2ac520c
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/GetQueueRequests.sql
@@ -0,0 +1,20 @@
+-------------------------------------------------------------------------------
+-- Author Arunima George
+-- Created 27-05-2025
+-- Purpose Fetch pending/failed email requests from QueueRequests table.
+--
+-- Modification History
+--
+-- 27-05-2025 Arunima George Initial Revision
+-------------------------------------------------------------------------------
+
+CREATE PROCEDURE [dbo].[GetQueueRequests]
+AS
+BEGIN
+
+ select Id,Recipient,TemplateId,Personalisation,Status,RetryCount
+ from dbo.QueueRequests
+where RequestTypeId = 1 and Status in (1,3) and RetryCount < 3 and (DeliverAfter is null or DeliverAfter <= SYSDATETIMEOFFSET())
+
+END
+GO
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/MessageDeliveryFailed.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/MessageDeliveryFailed.sql
new file mode 100644
index 000000000..4d00ebac4
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/MessageDeliveryFailed.sql
@@ -0,0 +1,24 @@
+-------------------------------------------------------------------------------
+-- Author Arunima George
+-- Created 27-05-2025
+-- Purpose Update message request status as failed.
+--
+-- Modification History
+--
+-- 27-05-2025 Arunima George Initial Revision
+-------------------------------------------------------------------------------
+
+CREATE PROCEDURE [dbo].[MessageDeliveryFailed]
+ @Id int,
+ @ErrorMessage nvarchar(max)
+AS
+BEGIN
+ UPDATE [dbo].[QueueRequests]
+ SET
+ Status = 3,
+ RetryCount = RetryCount + 1,
+ ErrorMessage = @ErrorMessage,
+ LastAttemptAt = SYSDATETIMEOFFSET()
+ where Id = @Id;
+END
+GO
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/MessageDeliverySuccess.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/MessageDeliverySuccess.sql
new file mode 100644
index 000000000..b971d912f
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/MessageDeliverySuccess.sql
@@ -0,0 +1,26 @@
+-------------------------------------------------------------------------------
+-- Author Arunima George
+-- Created 27-05-2025
+-- Purpose Update message request status as success.
+--
+-- Modification History
+--
+-- 27-05-2025 Arunima George Initial Revision
+-------------------------------------------------------------------------------
+
+CREATE PROCEDURE [dbo].[MessageDeliverySuccess]
+ @Id int,
+ @NotificationId nvarchar(100)
+
+AS
+BEGIN
+ UPDATE [dbo].[QueueRequests]
+ SET
+ Status = 2,
+ NotificationId = @NotificationId,
+ RetryCount = RetryCount + 1,
+ SentAt = SYSDATETIMEOFFSET(),
+ LastAttemptAt = SYSDATETIMEOFFSET()
+ where Id = @Id;
+END
+GO
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/SaveFailedSingleEmail.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/SaveFailedSingleEmail.sql
new file mode 100644
index 000000000..32a4c6395
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Stored Procedures/SaveFailedSingleEmail.sql
@@ -0,0 +1,21 @@
+-------------------------------------------------------------------------------
+-- Author Arunima George
+-- Created 27-05-2025
+-- Purpose Save one-off(like otp emails) failed email request.
+--
+-- Modification History
+--
+-- 27-05-2025 Arunima George Initial Revision
+-------------------------------------------------------------------------------
+
+CREATE PROCEDURE [dbo].[SaveFailedSingleEmail]
+ @Recipient nvarchar(255),
+ @TemplateId nvarchar(50),
+ @Personalisation nvarchar(max),
+ @ErrorMessage nvarchar(max)
+AS
+BEGIN
+ insert into [dbo].[QueueRequests] (RequestTypeId, Recipient, TemplateId, Personalisation, Status, CreatedAt, LastAttemptAt,ErrorMessage )
+ values (3, @Recipient, @TemplateId, @Personalisation, 3, SYSDATETIMEOFFSET(), SYSDATETIMEOFFSET(), @ErrorMessage);
+END
+GO
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/QueueRequests.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/QueueRequests.sql
new file mode 100644
index 000000000..fad33bf9d
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/QueueRequests.sql
@@ -0,0 +1,34 @@
+CREATE TABLE [dbo].[QueueRequests](
+ [Id] [int] IDENTITY(1,1) NOT NULL,
+ [RequestTypeId] [int] NOT NULL,
+ [Recipient] [nvarchar](255) NOT NULL,
+ [TemplateId] [nvarchar](50) NOT NULL,
+ [Personalisation] [nvarchar](max) NULL,
+ [Status] [int] NOT NULL,
+ [NotificationId] [nvarchar](100) NULL,
+ [RetryCount] [int] NULL,
+ [CreatedAt] [datetimeoffset](7) NOT NULL,
+ [DeliverAfter] [datetimeoffset](7) NULL,
+ [SentAt] [datetimeoffset](7) NULL,
+ [LastAttemptAt] [datetimeoffset](7) NULL,
+ [ErrorMessage] [nvarchar](max) NULL,
+ CONSTRAINT [PK_QueueRequests] PRIMARY KEY CLUSTERED
+(
+ [Id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[QueueRequests] WITH CHECK ADD CONSTRAINT [FK_QueueRequests_RequestStatus] FOREIGN KEY([Status])
+REFERENCES [dbo].[RequestStatus] ([Id])
+GO
+
+ALTER TABLE [dbo].[QueueRequests] CHECK CONSTRAINT [FK_QueueRequests_RequestStatus]
+GO
+
+ALTER TABLE [dbo].[QueueRequests] WITH CHECK ADD CONSTRAINT [FK_QueueRequests_RequestType] FOREIGN KEY([RequestTypeId])
+REFERENCES [dbo].[RequestType] ([Id])
+GO
+
+ALTER TABLE [dbo].[QueueRequests] CHECK CONSTRAINT [FK_QueueRequests_RequestType]
+GO
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/RequestStatus.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/RequestStatus.sql
new file mode 100644
index 000000000..ce9918dc3
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/RequestStatus.sql
@@ -0,0 +1,9 @@
+CREATE TABLE [dbo].[RequestStatus](
+ [Id] [int] NOT NULL,
+ [RequestStatus] [nvarchar](20) NOT NULL,
+ CONSTRAINT [PK_RequestStatus] PRIMARY KEY CLUSTERED
+(
+ [Id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
+) ON [PRIMARY]
+GO
\ No newline at end of file
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/RequestType.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/RequestType.sql
new file mode 100644
index 000000000..a9be6c049
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/Tables/RequestType.sql
@@ -0,0 +1,9 @@
+CREATE TABLE [dbo].[RequestType](
+ [Id] [int] NOT NULL,
+ [RequestType] [nvarchar](20) NOT NULL,
+ CONSTRAINT [PK_RequestType] PRIMARY KEY CLUSTERED
+(
+ [Id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
+) ON [PRIMARY]
+GO
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/User-Defined Table Types/QueueRequestTableType.sql b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/User-Defined Table Types/QueueRequestTableType.sql
new file mode 100644
index 000000000..479676b6b
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing.Database/User-Defined Table Types/QueueRequestTableType.sql
@@ -0,0 +1,7 @@
+CREATE TYPE [dbo].[QueueRequestTableType] AS TABLE(
+ [Recipient] [nvarchar](255) NOT NULL,
+ [TemplateId] [nvarchar](50) NOT NULL,
+ [Personalisation] [nvarchar](max) NULL,
+ [DeliverAfter] [datetimeoffset](7) NULL
+)
+GO
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing/EntityFramework/MessageQueueDbContext.cs b/MessageQueueing/LearningHub.Nhs.MessageQueueing/EntityFramework/MessageQueueDbContext.cs
new file mode 100644
index 000000000..5b392c8d6
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing/EntityFramework/MessageQueueDbContext.cs
@@ -0,0 +1,41 @@
+namespace LearningHub.Nhs.MessageQueueing.EntityFramework
+{
+ using LearningHub.Nhs.Models.GovNotifyMessaging;
+ using Microsoft.EntityFrameworkCore;
+
+ ///
+ /// The Message Queue Db Context.
+ ///
+ public class MessageQueueDbContext : DbContext
+ {
+ ///
+ /// The options.
+ ///
+ private readonly MessageQueueDbContextOptions options;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The options.
+ public MessageQueueDbContext(MessageQueueDbContextOptions options)
+ : base(options.Options)
+ {
+ this.options = options;
+ }
+
+ ///
+ /// Gets the Options.
+ ///
+ public MessageQueueDbContextOptions Options
+ {
+ get { return this.options; }
+ }
+
+ ////public virtual DbSet QueueRequests { get; set; }
+
+ ///
+ /// Gets or sets the PendingMessageRequests.
+ ///
+ public virtual DbSet PendingMessageRequests { get; set; }
+ }
+}
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing/EntityFramework/MessageQueueDbContextOptions.cs b/MessageQueueing/LearningHub.Nhs.MessageQueueing/EntityFramework/MessageQueueDbContextOptions.cs
new file mode 100644
index 000000000..7a6f0d985
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing/EntityFramework/MessageQueueDbContextOptions.cs
@@ -0,0 +1,24 @@
+namespace LearningHub.Nhs.MessageQueueing.EntityFramework
+{
+ using Microsoft.EntityFrameworkCore;
+
+ ///
+ /// The MessageQueueDbContextOptions.
+ ///
+ public class MessageQueueDbContextOptions
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The options.
+ public MessageQueueDbContextOptions(DbContextOptions options)
+ {
+ this.Options = options;
+ }
+
+ ///
+ /// Gets the options.
+ ///
+ public DbContextOptions Options { get; }
+ }
+}
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing/Helpers/DataTableBuilder.cs b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Helpers/DataTableBuilder.cs
new file mode 100644
index 000000000..f4e278b94
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Helpers/DataTableBuilder.cs
@@ -0,0 +1,34 @@
+namespace LearningHub.Nhs.MessageQueueing.Helpers
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Data;
+ using LearningHub.Nhs.Models.Entities.GovNotifyMessaging;
+
+ ///
+ /// DataTable Builder.
+ ///
+ public static class DataTableBuilder
+ {
+ ///
+ /// ToQueueRequestDataTable.
+ ///
+ /// The requests list.
+ /// The table.
+ public static DataTable ToQueueRequestDataTable(IEnumerable requests)
+ {
+ var table = new DataTable();
+ table.Columns.Add("Recipient", typeof(string));
+ table.Columns.Add("TemplateId", typeof(string));
+ table.Columns.Add("Personalisation", typeof(string));
+ table.Columns.Add("DeliverAfter", typeof(DateTimeOffset));
+
+ foreach (var req in requests)
+ {
+ table.Rows.Add(req.Recipient, req.TemplateId, req.Personalisation, req.DeliverAfter);
+ }
+
+ return table;
+ }
+ }
+}
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing/LearningHub.Nhs.MessageQueueing.csproj b/MessageQueueing/LearningHub.Nhs.MessageQueueing/LearningHub.Nhs.MessageQueueing.csproj
new file mode 100644
index 000000000..1d7e25a32
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing/LearningHub.Nhs.MessageQueueing.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ enable
+ true
+
+
+
+
+
+
+
+
+
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing/Repositories/IMessageQueueRepository.cs b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Repositories/IMessageQueueRepository.cs
new file mode 100644
index 000000000..110343012
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Repositories/IMessageQueueRepository.cs
@@ -0,0 +1,47 @@
+namespace LearningHub.Nhs.MessageQueueing.Repositories
+{
+ using System.Collections.Generic;
+ using System.Threading.Tasks;
+ using LearningHub.Nhs.Models.Entities.GovNotifyMessaging;
+ using LearningHub.Nhs.Models.GovNotifyMessaging;
+
+ ///
+ /// The IEmailQueueRepository class.
+ ///
+ public interface IMessageQueueRepository
+ {
+ ///
+ /// The QueueMessagesAsync.
+ ///
+ /// The emails list.
+ /// The .
+ Task QueueMessagesAsync(IEnumerable emails);
+
+ ///
+ /// The GetPendingEmailsAsync.
+ ///
+ /// The .
+ Task> GetPendingEmailsAsync();
+
+ ///
+ /// Marks a message as failed, or queues it for a retry.
+ ///
+ /// The response.
+ /// The .
+ Task MessageDeliveryFailed(GovNotifyResponse response);
+
+ ///
+ /// Marks a message as send.
+ ///
+ /// The response.
+ /// The .
+ Task MessageDeliverySuccess(GovNotifyResponse response);
+
+ ///
+ /// Save failed one-off email.
+ ///
+ /// The email request.
+ /// The .
+ Task SaveFailedSingleEmail(SingleEmailFailedRequest request);
+ }
+}
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing/Repositories/MessageQueueRepository.cs b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Repositories/MessageQueueRepository.cs
new file mode 100644
index 000000000..8e5059bd6
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Repositories/MessageQueueRepository.cs
@@ -0,0 +1,90 @@
+namespace LearningHub.Nhs.MessageQueueing.Repositories
+{
+ using System.Collections.Generic;
+ using System.Data;
+ using System.Threading.Tasks;
+ using LearningHub.Nhs.MessageQueueing.EntityFramework;
+ using LearningHub.Nhs.MessageQueueing.Helpers;
+ using LearningHub.Nhs.Models.Entities.GovNotifyMessaging;
+ using LearningHub.Nhs.Models.GovNotifyMessaging;
+ using Microsoft.Data.SqlClient;
+ using Microsoft.EntityFrameworkCore;
+
+ ///
+ /// The MessageQueueRepository.
+ ///
+ public class MessageQueueRepository : IMessageQueueRepository
+ {
+ private readonly MessageQueueDbContext dbContext;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The context.
+ public MessageQueueRepository(MessageQueueDbContext dbContext)
+ {
+ this.dbContext = dbContext;
+ }
+
+ ///
+ /// The QueueMessagesAsync.
+ ///
+ /// The queue requests.
+ /// The .
+ public async Task QueueMessagesAsync(IEnumerable requests)
+ {
+ var dataTable = DataTableBuilder.ToQueueRequestDataTable(requests);
+ var param0 = new SqlParameter("@p0", SqlDbType.Structured) { Value = dataTable, TypeName = "dbo.QueueRequestTableType" };
+ await this.dbContext.Database.ExecuteSqlRawAsync("dbo.CreateQueueRequests @p0", param0);
+ }
+
+ ///
+ /// The GetPendingEmailsAsync.
+ ///
+ /// The .
+ public async Task> GetPendingEmailsAsync()
+ {
+ var result = await this.dbContext.PendingMessageRequests.FromSqlRaw("[dbo].[GetQueueRequests]")
+ .AsNoTracking().ToListAsync();
+ return result;
+ }
+
+ ///
+ /// The Update Email request as success.
+ ///
+ /// Th response.
+ /// The .
+ public async Task MessageDeliverySuccess(GovNotifyResponse response)
+ {
+ var param0 = new SqlParameter("@p0", SqlDbType.Int) { Value = response.Id };
+ var param1 = new SqlParameter("@p1", SqlDbType.NVarChar) { Value = response.NotificationId };
+ await this.dbContext.Database.ExecuteSqlRawAsync("dbo.MessageDeliverySuccess @p0, @p1", param0, param1);
+ }
+
+ ///
+ /// The Update Email request as failed.
+ ///
+ /// Th response.
+ /// The .
+ public async Task MessageDeliveryFailed(GovNotifyResponse response)
+ {
+ var param0 = new SqlParameter("@p0", SqlDbType.Int) { Value = response.Id };
+ var param1 = new SqlParameter("@p1", SqlDbType.NVarChar) { Value = response.ErrorMessage };
+ await this.dbContext.Database.ExecuteSqlRawAsync("dbo.MessageDeliveryFailed @p0, @p1", param0, param1);
+ }
+
+ ///
+ /// The Save failed Single Emails.
+ ///
+ /// The request.
+ /// The .
+ public async Task SaveFailedSingleEmail(SingleEmailFailedRequest request)
+ {
+ var param0 = new SqlParameter("@p0", SqlDbType.NVarChar) { Value = request.Recipient };
+ var param1 = new SqlParameter("@p1", SqlDbType.NVarChar) { Value = request.TemplateId };
+ var param2 = new SqlParameter("@p2", SqlDbType.NVarChar) { Value = request.Personalisation };
+ var param3 = new SqlParameter("@p3", SqlDbType.NVarChar) { Value = request.ErrorMessage };
+ await this.dbContext.Database.ExecuteSqlRawAsync("dbo.SaveFailedSingleEmail @p0, @p1, @p2, @p3", param0, param1, param2, param3);
+ }
+ }
+}
diff --git a/MessageQueueing/LearningHub.Nhs.MessageQueueing/Startup.cs b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Startup.cs
new file mode 100644
index 000000000..e3cfa65d1
--- /dev/null
+++ b/MessageQueueing/LearningHub.Nhs.MessageQueueing/Startup.cs
@@ -0,0 +1,32 @@
+namespace LearningHub.Nhs.MessageQueueing
+{
+ using LearningHub.Nhs.MessageQueueing.EntityFramework;
+ using LearningHub.Nhs.MessageQueueing.Repositories;
+ using Microsoft.EntityFrameworkCore;
+ using Microsoft.Extensions.Configuration;
+ using Microsoft.Extensions.DependencyInjection;
+
+ ///
+ /// Contains methods to configure the project to be called in an API startup class.
+ ///
+ public static class Startup
+ {
+ ///
+ /// Registers the implementations in the project with ASP.NET DI.
+ ///
+ /// The IServiceCollection.
+ /// The IConfiguration.
+ public static void AddQueueingRepositories(this IServiceCollection services, IConfiguration configuration)
+ {
+ var dbContextOptions = new DbContextOptionsBuilder()
+ .UseSqlServer(configuration.GetConnectionString("GovNotifyMessageDbConnection"), providerOptions => { providerOptions.EnableRetryOnFailure(3); })
+ .Options;
+
+ services.AddSingleton(dbContextOptions);
+ services.AddSingleton();
+
+ services.AddDbContext();
+ services.AddScoped();
+ }
+ }
+}
diff --git a/LearningHub.Nhs.MessagingService/Interfaces/IGovNotifyService.cs b/MessagingService/LearningHub.Nhs.MessagingService/Interfaces/IGovNotifyService.cs
similarity index 73%
rename from LearningHub.Nhs.MessagingService/Interfaces/IGovNotifyService.cs
rename to MessagingService/LearningHub.Nhs.MessagingService/Interfaces/IGovNotifyService.cs
index 23d0d3738..588d766e7 100644
--- a/LearningHub.Nhs.MessagingService/Interfaces/IGovNotifyService.cs
+++ b/MessagingService/LearningHub.Nhs.MessagingService/Interfaces/IGovNotifyService.cs
@@ -2,6 +2,7 @@
{
using System.Collections.Generic;
using System.Threading.Tasks;
+ using LearningHub.Nhs.Models.GovNotifyMessaging;
///
/// IMessageServices.
@@ -15,7 +16,7 @@ public interface IGovNotifyService
/// templateId.
/// personalisation.
/// The .
- Task SendEmailAsync(string email, string templateId, Dictionary personalisation);
+ Task SendEmailAsync(string email, string templateId, Dictionary personalisation);
///
/// Send SmsAsync.
@@ -24,6 +25,6 @@ public interface IGovNotifyService
/// templateId.
/// personalisation.
/// The .
- Task SendSmsAsync(string phoneNumber, string templateId, Dictionary personalisation);
+ Task SendSmsAsync(string phoneNumber, string templateId, Dictionary personalisation);
}
}
diff --git a/LearningHub.Nhs.MessagingService/LearningHub.Nhs.MessagingService.csproj b/MessagingService/LearningHub.Nhs.MessagingService/LearningHub.Nhs.MessagingService.csproj
similarity index 90%
rename from LearningHub.Nhs.MessagingService/LearningHub.Nhs.MessagingService.csproj
rename to MessagingService/LearningHub.Nhs.MessagingService/LearningHub.Nhs.MessagingService.csproj
index d21593e42..bd12f3577 100644
--- a/LearningHub.Nhs.MessagingService/LearningHub.Nhs.MessagingService.csproj
+++ b/MessagingService/LearningHub.Nhs.MessagingService/LearningHub.Nhs.MessagingService.csproj
@@ -8,6 +8,7 @@
+
diff --git a/LearningHub.Nhs.MessagingService/Model/MessagingServiceModel.cs b/MessagingService/LearningHub.Nhs.MessagingService/MessagingOptions/MessagingServiceOptions.cs
similarity index 80%
rename from LearningHub.Nhs.MessagingService/Model/MessagingServiceModel.cs
rename to MessagingService/LearningHub.Nhs.MessagingService/MessagingOptions/MessagingServiceOptions.cs
index 66a3f210e..b4b395f31 100644
--- a/LearningHub.Nhs.MessagingService/Model/MessagingServiceModel.cs
+++ b/MessagingService/LearningHub.Nhs.MessagingService/MessagingOptions/MessagingServiceOptions.cs
@@ -3,12 +3,12 @@
///
/// MessagingServiceModel.
///
- public class MessagingServiceModel
+ public class MessagingServiceOptions
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- public MessagingServiceModel()
+ public MessagingServiceOptions()
{
// Current = this;
}
diff --git a/MessagingService/LearningHub.Nhs.MessagingService/Services/GovNotifyService.cs b/MessagingService/LearningHub.Nhs.MessagingService/Services/GovNotifyService.cs
new file mode 100644
index 000000000..9d06a21e6
--- /dev/null
+++ b/MessagingService/LearningHub.Nhs.MessagingService/Services/GovNotifyService.cs
@@ -0,0 +1,141 @@
+namespace LearningHub.Nhs.MessagingService.Services
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text.Json;
+ using System.Threading.Tasks;
+ using LearningHub.Nhs.MessagingService.Interfaces;
+ using LearningHub.Nhs.MessagingService.Model;
+ using LearningHub.Nhs.Models.GovNotifyMessaging;
+ using Microsoft.Extensions.Options;
+ using Notify.Client;
+ using Notify.Exceptions;
+
+ ///
+ /// GovNotify Service class.
+ ///
+ public class GovNotifyService : IGovNotifyService
+ {
+ private readonly NotificationClient client;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Messaging Service Options.
+ public GovNotifyService(IOptions options)
+ {
+ this.client = new NotificationClient(options.Value.GovNotifyApiKey);
+ }
+
+ ///
+ /// Sends an email via the UK Gov.Notify service.
+ ///
+ /// The recipient's email address.
+ /// The ID of the Gov.Notify template to be used for the email.
+ ///
+ /// A dictionary containing key-value pairs for personalising the email template.
+ /// Keys should match the placeholders in the Gov.Notify template.
+ ///
+ /// The .
+ public async Task SendEmailAsync(string email, string templateId, Dictionary personalisation)
+ {
+ try
+ {
+ var normalisedPersonlisation = new Dictionary();
+ if (personalisation != null)
+ {
+ foreach (var item in personalisation)
+ {
+ if (item.Value is JsonElement element)
+ {
+ normalisedPersonlisation[item.Key] = element.ToString();
+ }
+ else
+ {
+ normalisedPersonlisation[item.Key] = item.Value;
+ }
+ }
+ }
+
+ var response = await this.client.SendEmailAsync(email, templateId, normalisedPersonlisation);
+ return new GovNotifyResponse
+ {
+ IsSuccess = true,
+ NotificationId = response.id,
+ };
+ }
+ catch (NotifyClientException ex)
+ {
+ return new GovNotifyResponse
+ {
+ IsSuccess = false,
+ ErrorMessage = ex.Message,
+ ////Retry = true,
+ };
+ }
+ catch (Exception ex)
+ {
+ return new GovNotifyResponse
+ {
+ IsSuccess = false,
+ ErrorMessage = ex.Message,
+ ////Retry = true,
+ };
+ }
+ }
+
+ ///
+ /// Sends an SMS via the UK Gov.Notify service.
+ ///
+ /// The recipient's phone number.
+ /// The ID of the Gov.Notify template to be used for the SMS.
+ ///
+ /// A dictionary containing key-value pairs for personalising the SMS template.
+ /// Keys should match the placeholders in the Gov.Notify template.
+ ///
+ /// The .
+ public async Task SendSmsAsync(string phoneNumber, string templateId, Dictionary personalisation)
+ {
+ try
+ {
+ var normalisedPersonlisation = new Dictionary();
+ foreach (var item in personalisation)
+ {
+ if (item.Value is JsonElement element)
+ {
+ normalisedPersonlisation[item.Key] = element.ToString();
+ }
+ else
+ {
+ normalisedPersonlisation[item.Key] = item.Value;
+ }
+ }
+
+ var response = await this.client.SendSmsAsync(phoneNumber, templateId, normalisedPersonlisation);
+ return new GovNotifyResponse
+ {
+ IsSuccess = true,
+ NotificationId = response.id,
+ };
+ }
+ catch (NotifyClientException ex)
+ {
+ return new GovNotifyResponse
+ {
+ IsSuccess = false,
+ ErrorMessage = ex.Message,
+ ////Retry = true,
+ };
+ }
+ catch (Exception ex)
+ {
+ return new GovNotifyResponse
+ {
+ IsSuccess = false,
+ ErrorMessage = ex.Message,
+ ////Retry = true,
+ };
+ }
+ }
+ }
+}
diff --git a/LearningHub.Nhs.MessagingService/Startup.cs b/MessagingService/LearningHub.Nhs.MessagingService/Startup.cs
similarity index 90%
rename from LearningHub.Nhs.MessagingService/Startup.cs
rename to MessagingService/LearningHub.Nhs.MessagingService/Startup.cs
index 522b98bda..30359eb08 100644
--- a/LearningHub.Nhs.MessagingService/Startup.cs
+++ b/MessagingService/LearningHub.Nhs.MessagingService/Startup.cs
@@ -18,7 +18,7 @@ public static class Startup
/// The IConfiguration.
public static void AddMessagingServices(this IServiceCollection services, IConfiguration configuration)
{
- services.Configure(configuration.GetSection("GovNotify"));
+ services.Configure(configuration.GetSection("GovNotify"));
services.AddScoped();
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj
index f34790d51..a4341e802 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj
index 20b3a1c06..d3907645f 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj
index f84d5121c..b7850fdea 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj
@@ -30,7 +30,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/GovNotifyMessagingController.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/GovNotifyMessagingController.cs
index 05066a292..574b9dced 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/GovNotifyMessagingController.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/GovNotifyMessagingController.cs
@@ -1,11 +1,16 @@
namespace LearningHub.NHS.OpenAPI.Controllers
{
using System;
+ using System.Collections.Generic;
+ using System.Linq;
using System.Threading.Tasks;
+ using LearningHub.Nhs.MessageQueueing.Repositories;
using LearningHub.Nhs.MessagingService.Interfaces;
- using LearningHub.Nhs.MessagingService.Model;
+ using LearningHub.Nhs.Models.Entities.GovNotifyMessaging;
+ using LearningHub.Nhs.Models.GovNotifyMessaging;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
+ using Newtonsoft.Json;
///
/// GovNotify Messaging Controller.
@@ -15,14 +20,17 @@
public class GovNotifyMessagingController : OpenApiControllerBase
{
private readonly IGovNotifyService messageService;
+ private readonly IMessageQueueRepository messageQueueRepository;
///
/// Initializes a new instance of the class.
///
- /// The catalogue service.
- public GovNotifyMessagingController(IGovNotifyService messageService)
+ /// The message service.
+ /// The email Queue Repository.
+ public GovNotifyMessagingController(IGovNotifyService messageService, IMessageQueueRepository messageQueueRepository)
{
this.messageService = messageService;
+ this.messageQueueRepository = messageQueueRepository;
}
///
@@ -30,18 +38,35 @@ public GovNotifyMessagingController(IGovNotifyService messageService)
///
/// personalisation.
/// The .
- [Route("sendemail")]
+ [Route("SendEmail")]
[HttpPost]
- public async Task SendEmailAsync([FromBody] SendEmailRequest request)
+ public async Task SendEmailAsync([FromBody] EmailRequest request)
{
try
{
- if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.TemplateId))
+ if (string.IsNullOrWhiteSpace(request.Recipient) || string.IsNullOrWhiteSpace(request.TemplateId))
{
return this.BadRequest("Email and template ID are required");
}
- var response = await this.messageService.SendEmailAsync(request.Email, request.TemplateId, request.Personalisation);
+ var response = await this.messageService.SendEmailAsync(request.Recipient, request.TemplateId, request.Personalisation);
+
+ Dictionary test = new Dictionary();
+ if (response != null)
+ {
+ if (!response.IsSuccess && (request.Id == null || request.Id <= 0))
+ {
+ var failedRequest = new SingleEmailFailedRequest
+ {
+ Recipient = request.Recipient,
+ TemplateId = request.TemplateId,
+ Personalisation = request.Personalisation != null ? JsonConvert.SerializeObject(request.Personalisation.ToDictionary(kvp => kvp.Key, kvp => kvp.Value?.ToString())) : null,
+ ErrorMessage = response.ErrorMessage,
+ };
+ await this.messageQueueRepository.SaveFailedSingleEmail(failedRequest);
+ }
+ }
+
return this.Ok(response);
}
catch (Exception ex)
@@ -55,9 +80,9 @@ public async Task SendEmailAsync([FromBody] SendEmailRequest requ
///
/// SendSmsRequest.
/// The .
- [Route("sendsms")]
+ [Route("SendSms")]
[HttpPost]
- public async Task SendSmsAsync([FromBody] SendSmsRequest request)
+ public async Task SendSmsAsync([FromBody] SmsRequest request)
{
try
{
@@ -74,5 +99,69 @@ public async Task SendSmsAsync([FromBody] SendSmsRequest request)
return this.Ok(ex.Message);
}
}
+
+ ///
+ /// To queue the MessageRequests.
+ ///
+ /// The QueueRequestList.
+ /// The .
+ [Route("QueueRequests")]
+ [HttpPost]
+ public async Task QueueRequests([FromBody] QueueMessageList request)
+ {
+ if (request?.Messages == null || !request.Messages.Any())
+ {
+ return this.BadRequest("At least one email must be provided in the request.");
+ }
+
+ var requests = request.Messages.Select(q => new QueueRequests
+ {
+ Recipient = q.Recipient,
+ TemplateId = q.TemplateId,
+ Personalisation = q.Personalisation != null ? JsonConvert.SerializeObject(q.Personalisation) : null,
+ DeliverAfter = q.DeliverAfter ?? null,
+ });
+
+ await this.messageQueueRepository.QueueMessagesAsync(requests);
+
+ return this.Ok(new { Message = $"{requests.Count()} message requests queued successfully." });
+ }
+
+ ///
+ /// To fetch the Pending or failed Message Requests.
+ ///
+ /// The .
+ [Route("PendingMessageRequests")]
+ [HttpGet]
+ public async Task> PendingMessageRequests()
+ {
+ return await this.messageQueueRepository.GetPendingEmailsAsync();
+ }
+
+ ///
+ /// Update message request as Success.
+ ///
+ /// The response.
+ /// The .
+ [Route("MessageSuccessUpdate")]
+ [HttpPost]
+ public async Task MessageSuccessUpdate([FromBody] GovNotifyResponse response)
+ {
+ await this.messageQueueRepository.MessageDeliverySuccess(response);
+ return this.Ok();
+ }
+
+ ///
+ /// Update message request as Failed.
+ ///
+ /// The response.
+ /// The .
+ [Route("MessageFailedUpdate")]
+ [HttpPost]
+ public async Task MessageFailedUpdate([FromBody] GovNotifyResponse response)
+ {
+ await this.messageQueueRepository.MessageDeliveryFailed(response);
+ return this.Ok();
+ }
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj b/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj
index 6ed354944..5969f63c9 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj
@@ -1,4 +1,4 @@
-
+
enable
@@ -31,7 +31,8 @@
-
+
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs
index f3dc3f51b..ea03ad70f 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs
@@ -31,6 +31,8 @@ namespace LearningHub.NHS.OpenAPI
using System;
using LearningHub.Nhs.Models.Extensions;
using LearningHub.Nhs.MessagingService;
+ using LearningHub.Nhs.MessageQueueing;
+ using Microsoft.AspNetCore.Authentication.Cookies;
///
/// The Startup class.
@@ -60,6 +62,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddConfig(this.Configuration);
services.AddApiKeyAuth();
+ services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
services.AddAuthentication()
.AddJwtBearer(options =>
@@ -86,6 +89,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddControllers(options => options.Filters.Add(new HttpResponseExceptionFilter()));
services.AddControllers(opt => { opt.Filters.Add(new AuthorizeFilter()); });
services.AddMessagingServices(this.Configuration);
+ services.AddQueueingRepositories(this.Configuration);
services.AddSwaggerGen(
c =>
{
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/SwaggerDefinitions/v1.3.0.json b/OpenAPI/LearningHub.Nhs.OpenApi/SwaggerDefinitions/v1.3.0.json
index 9633b6117..00bb8cf37 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/SwaggerDefinitions/v1.3.0.json
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/SwaggerDefinitions/v1.3.0.json
@@ -6034,29 +6034,28 @@
}
}
},
- "/GovNotifyMessage/sendsms": {
+ "/GovNotifyMessage/SendSms": {
"post": {
"tags": [
"SendSms"
],
"summary": "Send an SMS.",
- "required": [ "mobileNumber", "templateId" ],
"requestBody": {
"description": "The Sends an SMS using the UK Gov.Notify service.",
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/SendSmsRequest"
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.SmsRequest"
}
},
"text/json": {
"schema": {
- "$ref": "#/components/schemas/SendSmsRequest"
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.SmsRequest"
}
},
"application/*+json": {
"schema": {
- "$ref": "#/components/schemas/SendSmsRequest"
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.SmsRequest"
}
}
}
@@ -6074,7 +6073,7 @@
}
}
},
- "/GovNotifyMessage/sendemail": {
+ "/GovNotifyMessage/SendEmail": {
"post": {
"tags": [
"SendEmail"
@@ -6085,17 +6084,17 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/SendEmailRequest"
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.EmailRequest"
}
},
"text/json": {
"schema": {
- "$ref": "#/components/schemas/SendEmailRequest"
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.EmailRequest"
}
},
"application/*+json": {
"schema": {
- "$ref": "#/components/schemas/SendEmailRequest"
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.EmailRequest"
}
}
}
@@ -6112,6 +6111,45 @@
}
}
}
+ },
+ "/GovNotifyMessage/QueueRequests": {
+ "post": {
+ "tags": [
+ "QueueRequests"
+ ],
+ "summary": "Queue one or more email/sms request for later processing.",
+ "requestBody": {
+ "description": "A list of sms/email requests to be queued for sending.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.QueueRequestsList"
+ }
+ },
+ "text/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.QueueRequestsList"
+ }
+ },
+ "application/*+json": {
+ "schema": {
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.QueueRequestsList"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Requests are queued successfully."
+ },
+ "400": {
+ "description": "Bad request, invalid input."
+ },
+ "500": {
+ "description": "Internal server error."
+ }
+ }
+ }
}
},
"components": {
@@ -14218,50 +14256,85 @@
},
"additionalProperties": false
},
- "SendSmsRequest": {
+ "LearningHub.Nhs.Models.GovNotifyMessaging.SmsRequest": {
"type": "object",
- "required": [ "mobileNumber", "templateId" ],
+ "required": [ "PhoneNumber", "TemplateId" ],
"properties": {
- "mobileNumber": {
+ "PhoneNumber": {
"type": "string",
"nullable": false,
"description": "The recipient's mobile number."
},
- "templateId": {
+ "TemplateId": {
"type": "string",
"nullable": false,
"description": "The ID of the template to be used for the email."
},
- "personalisation": {
+ "Personalisation": {
"type": "object",
- "additionalProperties:": {
+ "additionalProperties": {
"type": "string"
},
"description": "Key-value pairs for personalising the sms template."
}
}
},
- "SendEmailRequest": {
+ "LearningHub.Nhs.Models.GovNotifyMessaging.EmailRequest": {
"type": "object",
"properties": {
- "emailAddress": {
+ "Recipient": {
"type": "string",
"nullable": false,
"description": "The recipient's email address."
},
- "templateId": {
+ "TemplateId": {
"type": "string",
"nullable": false,
"description": "The ID of the template to be used for the email."
},
- "personalisation": {
+ "Personalisation": {
"type": "object",
- "additionalProperties:": {
+ "additionalProperties": {
"type": "string"
},
"description": "Key-value pairs for personalising the email template."
}
}
+ },
+ "LearningHub.Nhs.Models.GovNotifyMessaging.QueueRequestsList": {
+ "type": "object",
+ "properties": {
+ "Messages": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/LearningHub.Nhs.Models.GovNotifyMessaging.QueueRequests"
+ }
+ }
+ }
+ },
+ "LearningHub.Nhs.Models.GovNotifyMessaging.QueueRequests": {
+ "type": "object",
+ "properties": {
+ "Recipient": {
+ "type": "string",
+ "nullable": false
+ },
+ "TemplateId": {
+ "type": "string",
+ "nullable": false
+ },
+ "DeliverAfter": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "Personalisation": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Key-value pairs for personalising the template."
+ }
+ }
}
},
"securitySchemes": {
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
index 56c507cff..f9c27f84e 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
@@ -11,6 +11,7 @@
"ElfhHubDbConnection": "",
"LearningHubDbConnection": "",
"LearningHubRedis": "",
+ "GovNotifyMessageDbConnection": "",
"NLogDb": ""
},
"Auth": {
@@ -38,6 +39,12 @@
"Keys": [
""
]
+ },
+ {
+ "Name": "MessageQueueProcessor",
+ "Keys": [
+ ""
+ ]
}
]
},
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj
index 0a697a51f..655caa351 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj
index 50e3d7536..537f585bd 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj
index 55c8a1be4..42d7766fc 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj
@@ -19,7 +19,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj
index 2f5518784..5b6a9d92e 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj b/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj
index 583caa9f2..b215db06c 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj
@@ -20,7 +20,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj b/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj
index bb0c6c6cc..37286151e 100644
--- a/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj
+++ b/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj
@@ -29,7 +29,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj b/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj
index 74d2ccc77..8173a68b2 100644
--- a/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj
+++ b/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj
@@ -9,7 +9,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj b/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj
index 9663e4ee7..ca8916c4e 100644
--- a/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj
+++ b/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj b/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj
index d41ba9e68..1c2dfe61b 100644
--- a/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj
+++ b/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj b/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj
index 904bda4c8..a84412769 100644
--- a/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj
+++ b/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj b/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj
index b259b3a7e..c76a6ee5c 100644
--- a/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj
+++ b/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj
@@ -16,7 +16,7 @@
-
+
all
diff --git a/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj b/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj
index f78df0084..06af56b2a 100644
--- a/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj
+++ b/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj b/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj
index e99e5300a..903884270 100644
--- a/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj
+++ b/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj
index 697d1db2f..3119248d5 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj
@@ -25,7 +25,7 @@
-
+
all
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj
index 89ca1344e..bc30ad48a 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj
@@ -9,7 +9,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj
index 4ab608bac..5ab9d00b1 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj
@@ -10,7 +10,7 @@
-
+
all
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj
index 7dd7febb7..539446335 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj
index 5b83ec893..693ef008d 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj
index bf0235325..a184bb27f 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj
@@ -12,7 +12,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive