Skip to content

Commit 483e130

Browse files
committed
TD-5474: Create a new messaging service project
1 parent e0e1771 commit 483e130

File tree

13 files changed

+459
-0
lines changed

13 files changed

+459
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace LearningHub.Nhs.MessagingService.Interfaces
2+
{
3+
using System.Collections.Generic;
4+
using System.Threading.Tasks;
5+
6+
/// <summary>
7+
/// IMessageServices.
8+
/// </summary>
9+
public interface IGovNotifyService
10+
{
11+
/// <summary>
12+
/// Send EmailAsync.
13+
/// </summary>
14+
/// <param name="email">email.</param>
15+
/// <param name="templateId">templateId.</param>
16+
/// <param name="personalisation">personalisation.</param>
17+
/// <returns>The <see cref="Task"/>.</returns>
18+
Task<string> SendEmailAsync(string email, string templateId, Dictionary<string, dynamic> personalisation);
19+
20+
/// <summary>
21+
/// Send SmsAsync.
22+
/// </summary>
23+
/// <param name="phoneNumber">phoneNumber.</param>
24+
/// <param name="templateId">templateId.</param>
25+
/// <param name="personalisation">personalisation.</param>
26+
/// <returns>The <see cref="Task"/>.</returns>
27+
Task<string> SendSmsAsync(string phoneNumber, string templateId, Dictionary<string, dynamic> personalisation);
28+
}
29+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="GovukNotify" Version="7.2.0" />
11+
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.1" />
12+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.1" />
13+
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
14+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0" />
15+
</ItemGroup>
16+
</Project>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace LearningHub.Nhs.MessagingService.Model
2+
{
3+
/// <summary>
4+
/// MessagingServiceModel.
5+
/// </summary>
6+
public class MessagingServiceModel
7+
{
8+
/// <summary>
9+
/// Initializes a new instance of the <see cref="MessagingServiceModel"/> class.
10+
/// </summary>
11+
public MessagingServiceModel()
12+
{
13+
// Current = this;
14+
}
15+
16+
/// <summary>
17+
/// Gets or Sets ApiKey.
18+
/// </summary>
19+
public string GovNotifyApiKey { get; set; } = string.Empty;
20+
}
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace LearningHub.Nhs.MessagingService.Model
2+
{
3+
using System.Collections.Generic;
4+
using System.ComponentModel.DataAnnotations;
5+
6+
/// <summary>
7+
/// Defines the <see cref="SendEmailRequest" />.
8+
/// </summary>
9+
public class SendEmailRequest
10+
{
11+
/// <summary>
12+
/// Gets or Sets the Email.
13+
/// </summary>
14+
[Required]
15+
public string Email { get; set; }
16+
17+
/// <summary>
18+
/// Gets or Sets the TemplateId.
19+
/// </summary>
20+
[Required]
21+
public string TemplateId { get; set; }
22+
23+
/// <summary>
24+
/// Gets or Sets the Personalisation.
25+
/// </summary>
26+
public Dictionary<string, dynamic> Personalisation { get; set; }
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace LearningHub.Nhs.MessagingService.Model
2+
{
3+
using System.Collections.Generic;
4+
using System.ComponentModel.DataAnnotations;
5+
6+
/// <summary>
7+
/// Defines the <see cref="SendSmsRequest" />.
8+
/// </summary>
9+
public class SendSmsRequest
10+
{
11+
/// <summary>
12+
/// Gets or Sets the PhoneNumber.
13+
/// </summary>
14+
[Required]
15+
public string PhoneNumber { get; set; }
16+
17+
/// <summary>
18+
/// Gets or Sets the TemplateId.
19+
/// </summary>
20+
[Required]
21+
public string TemplateId { get; set; }
22+
23+
/// <summary>
24+
/// Gets or Sets the Personalisation.
25+
/// </summary>
26+
public Dictionary<string, dynamic> Personalisation { get; set; }
27+
}
28+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
namespace LearningHub.Nhs.MessagingService.Services
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Text.Json;
6+
using System.Threading.Tasks;
7+
using LearningHub.Nhs.MessagingService.Interfaces;
8+
using LearningHub.Nhs.MessagingService.Model;
9+
using Microsoft.Extensions.Options;
10+
using Notify.Client;
11+
12+
/// <summary>
13+
/// GovNotify Service class.
14+
/// </summary>
15+
public class GovNotifyService : IGovNotifyService
16+
{
17+
private readonly NotificationClient client;
18+
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="GovNotifyService"/> class.
21+
/// GovNotifyService.
22+
/// </summary>
23+
/// <param name="options">The Messaging Service Model.</param>
24+
public GovNotifyService(IOptions<MessagingServiceModel> options)
25+
{
26+
this.client = new NotificationClient(options.Value.GovNotifyApiKey);
27+
}
28+
29+
/// <summary>
30+
/// Sends an email via the UK Gov.Notify service.
31+
/// </summary>
32+
/// <param name="email">The recipient's email address.</param>
33+
/// <param name="templateId">The ID of the Gov.Notify template to be used for the email.</param>
34+
/// <param name="personalisation">
35+
/// A dictionary containing key-value pairs for personalising the email template.
36+
/// Keys should match the placeholders in the Gov.Notify template.
37+
/// </param>
38+
/// <returns>
39+
/// A unique message ID representing the queued email.
40+
/// </returns>
41+
public async Task<string> SendEmailAsync(string email, string templateId, Dictionary<string, dynamic> personalisation)
42+
{
43+
var normalisedPersonlisation = new Dictionary<string, dynamic>();
44+
foreach (var item in personalisation)
45+
{
46+
if (item.Value is JsonElement element)
47+
{
48+
normalisedPersonlisation[item.Key] = element.ToString();
49+
}
50+
else
51+
{
52+
normalisedPersonlisation[item.Key] = item.Value;
53+
}
54+
}
55+
56+
var response = await this.client.SendEmailAsync(email, templateId, normalisedPersonlisation);
57+
return response.id;
58+
}
59+
60+
/// <summary>
61+
/// Sends an SMS via the UK Gov.Notify service.
62+
/// </summary>
63+
/// <param name="phoneNumber">The recipient's phone number.</param>
64+
/// <param name="templateId">The ID of the Gov.Notify template to be used for the SMS.</param>
65+
/// <param name="personalisation">
66+
/// A dictionary containing key-value pairs for personalising the SMS template.
67+
/// Keys should match the placeholders in the Gov.Notify template.
68+
/// </param>
69+
/// <returns>
70+
/// A unique message ID representing the queued SMS.
71+
/// </returns>
72+
public async Task<string> SendSmsAsync(string phoneNumber, string templateId, Dictionary<string, dynamic> personalisation)
73+
{
74+
var normalisedPersonlisation = new Dictionary<string, dynamic>();
75+
foreach (var item in personalisation)
76+
{
77+
if (item.Value is JsonElement element)
78+
{
79+
normalisedPersonlisation[item.Key] = element.ToString();
80+
}
81+
else
82+
{
83+
normalisedPersonlisation[item.Key] = item.Value;
84+
}
85+
}
86+
87+
var response = await this.client.SendSmsAsync(phoneNumber, templateId, normalisedPersonlisation);
88+
return response.id;
89+
}
90+
}
91+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace LearningHub.Nhs.MessagingService
2+
{
3+
using LearningHub.Nhs.MessagingService.Interfaces;
4+
using LearningHub.Nhs.MessagingService.Model;
5+
using LearningHub.Nhs.MessagingService.Services;
6+
using Microsoft.Extensions.Configuration;
7+
using Microsoft.Extensions.DependencyInjection;
8+
9+
/// <summary>
10+
/// Contains methods to configure the project to be called in an API startup class.
11+
/// </summary>
12+
public static class Startup
13+
{
14+
/// <summary>
15+
/// Registers the implementations in the project with ASP.NET DI.
16+
/// </summary>
17+
/// <param name="services">The IServiceCollection.</param>
18+
/// <param name="configuration">The IConfiguration.</param>
19+
public static void AddMessagingServices(this IServiceCollection services, IConfiguration configuration)
20+
{
21+
services.Configure<MessagingServiceModel>(configuration.GetSection("GovNotify"));
22+
services.AddScoped<IGovNotifyService, GovNotifyService>();
23+
}
24+
}
25+
}

LearningHub.Nhs.WebUI.sln

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LearningHub.Nhs.ReportApi.S
8181
EndProject
8282
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.WebUI.AutomatedUiTests", "LearningHub.Nhs.WebUI.AutomatedUiTests\LearningHub.Nhs.WebUI.AutomatedUiTests.csproj", "{A84EC50B-2B01-4819-A2B1-BD867B7595CA}"
8383
EndProject
84+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MessagingService", "MessagingService", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
85+
EndProject
86+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.MessagingService", "LearningHub.Nhs.MessagingService\LearningHub.Nhs.MessagingService.csproj", "{713B0099-60E3-4D28-980F-448FC68BC7EE}"
87+
EndProject
8488
Global
8589
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8690
Debug|Any CPU = Debug|Any CPU
@@ -345,6 +349,14 @@ Global
345349
{A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|Any CPU.Build.0 = Release|Any CPU
346350
{A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|x64.ActiveCfg = Release|Any CPU
347351
{A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|x64.Build.0 = Release|Any CPU
352+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
353+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
354+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|x64.ActiveCfg = Debug|Any CPU
355+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Debug|x64.Build.0 = Debug|Any CPU
356+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
357+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|Any CPU.Build.0 = Release|Any CPU
358+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|x64.ActiveCfg = Release|Any CPU
359+
{713B0099-60E3-4D28-980F-448FC68BC7EE}.Release|x64.Build.0 = Release|Any CPU
348360
EndGlobalSection
349361
GlobalSection(SolutionProperties) = preSolution
350362
HideSolutionNode = FALSE
@@ -380,6 +392,7 @@ Global
380392
{E585A74A-F358-4446-B10E-0FF07B4FF601} = {A4209011-1740-4902-B889-2F2FAF98383F}
381393
{AAC8306E-1DEB-460D-84C7-40166D189B88} = {A4209011-1740-4902-B889-2F2FAF98383F}
382394
{6167F037-166C-4C5A-81BE-55618E77D4E8} = {A4209011-1740-4902-B889-2F2FAF98383F}
395+
{713B0099-60E3-4D28-980F-448FC68BC7EE} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
383396
EndGlobalSection
384397
GlobalSection(ExtensibilityGlobals) = postSolution
385398
SolutionGuid = {1ECA38C8-7C69-4DE6-8293-852C603F4217}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
namespace LearningHub.NHS.OpenAPI.Controllers
2+
{
3+
using System;
4+
using System.Threading.Tasks;
5+
using LearningHub.Nhs.MessagingService.Interfaces;
6+
using LearningHub.Nhs.MessagingService.Model;
7+
using Microsoft.AspNetCore.Authorization;
8+
using Microsoft.AspNetCore.Mvc;
9+
10+
/// <summary>
11+
/// GovNotify Messaging Controller.
12+
/// </summary>
13+
[Route("GovNotifyMessage")]
14+
[Authorize]
15+
public class GovNotifyMessagingController : OpenApiControllerBase
16+
{
17+
private readonly IGovNotifyService messageService;
18+
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="GovNotifyMessagingController"/> class.
21+
/// </summary>
22+
/// <param name="messageService">The catalogue service.</param>
23+
public GovNotifyMessagingController(IGovNotifyService messageService)
24+
{
25+
this.messageService = messageService;
26+
}
27+
28+
/// <summary>
29+
/// Sends an email using UK Gov.Notify.
30+
/// </summary>
31+
/// <param name="request">personalisation.</param>
32+
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
33+
[Route("sendemail")]
34+
[HttpPost]
35+
public async Task<IActionResult> SendEmailAsync([FromBody] SendEmailRequest request)
36+
{
37+
try
38+
{
39+
if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.TemplateId))
40+
{
41+
return this.BadRequest("Email and template ID are required");
42+
}
43+
44+
var response = await this.messageService.SendEmailAsync(request.Email, request.TemplateId, request.Personalisation);
45+
return this.Ok(response);
46+
}
47+
catch (Exception ex)
48+
{
49+
return this.Ok(ex.Message);
50+
}
51+
}
52+
53+
/// <summary>
54+
/// Sends a sms using UK Gov.Notify.
55+
/// </summary>
56+
/// <param name="request">SendSmsRequest.</param>
57+
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
58+
[Route("sendsms")]
59+
[HttpPost]
60+
public async Task<IActionResult> SendSmsAsync([FromBody] SendSmsRequest request)
61+
{
62+
try
63+
{
64+
if (string.IsNullOrWhiteSpace(request.PhoneNumber) || string.IsNullOrWhiteSpace(request.TemplateId))
65+
{
66+
return this.BadRequest("phoneNumber and template ID are required");
67+
}
68+
69+
var response = await this.messageService.SendSmsAsync(request.PhoneNumber, request.TemplateId, request.Personalisation);
70+
return this.Ok(response);
71+
}
72+
catch (Exception ex)
73+
{
74+
return this.Ok(ex.Message);
75+
}
76+
}
77+
}
78+
}

OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
</ItemGroup>
3232

3333
<ItemGroup>
34+
<ProjectReference Include="..\..\LearningHub.Nhs.MessagingService\LearningHub.Nhs.MessagingService.csproj" />
3435
<ProjectReference Include="..\LearningHub.Nhs.OpenApi.Repositories.Interface\LearningHub.Nhs.OpenApi.Repositories.Interface.csproj" />
3536
<ProjectReference Include="..\LearningHub.Nhs.OpenApi.Repositories\LearningHub.Nhs.OpenApi.Repositories.csproj" />
3637
<ProjectReference Include="..\LearningHub.Nhs.OpenApi.Services.Interface\LearningHub.Nhs.OpenApi.Services.Interface.csproj" />

0 commit comments

Comments
 (0)