Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions LearningHub.Nhs.MessagingService/Interfaces/IGovNotifyService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace LearningHub.Nhs.MessagingService.Interfaces
{
using System.Collections.Generic;
using System.Threading.Tasks;

/// <summary>
/// IMessageServices.
/// </summary>
public interface IGovNotifyService
{
/// <summary>
/// Send EmailAsync.
/// </summary>
/// <param name="email">email.</param>
/// <param name="templateId">templateId.</param>
/// <param name="personalisation">personalisation.</param>
/// <returns>The <see cref="Task"/>.</returns>
Task<string> SendEmailAsync(string email, string templateId, Dictionary<string, dynamic> personalisation);

/// <summary>
/// Send SmsAsync.
/// </summary>
/// <param name="phoneNumber">phoneNumber.</param>
/// <param name="templateId">templateId.</param>
/// <param name="personalisation">personalisation.</param>
/// <returns>The <see cref="Task"/>.</returns>
Task<string> SendSmsAsync(string phoneNumber, string templateId, Dictionary<string, dynamic> personalisation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GovukNotify" Version="7.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0" />
</ItemGroup>
</Project>
21 changes: 21 additions & 0 deletions LearningHub.Nhs.MessagingService/Model/MessagingServiceModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace LearningHub.Nhs.MessagingService.Model
{
/// <summary>
/// MessagingServiceModel.
/// </summary>
public class MessagingServiceModel
{
/// <summary>
/// Initializes a new instance of the <see cref="MessagingServiceModel"/> class.
/// </summary>
public MessagingServiceModel()
{
// Current = this;
}

/// <summary>
/// Gets or Sets ApiKey.
/// </summary>
public string GovNotifyApiKey { get; set; } = string.Empty;
}
}
28 changes: 28 additions & 0 deletions LearningHub.Nhs.MessagingService/Model/SendEmailRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace LearningHub.Nhs.MessagingService.Model
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// Defines the <see cref="SendEmailRequest" />.
/// </summary>
public class SendEmailRequest
{
/// <summary>
/// Gets or Sets the Email.
/// </summary>
[Required]
public string Email { get; set; }

/// <summary>
/// Gets or Sets the TemplateId.
/// </summary>
[Required]
public string TemplateId { get; set; }

/// <summary>
/// Gets or Sets the Personalisation.
/// </summary>
public Dictionary<string, dynamic> Personalisation { get; set; }
}
}
28 changes: 28 additions & 0 deletions LearningHub.Nhs.MessagingService/Model/SendSmsRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace LearningHub.Nhs.MessagingService.Model
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// Defines the <see cref="SendSmsRequest" />.
/// </summary>
public class SendSmsRequest
{
/// <summary>
/// Gets or Sets the PhoneNumber.
/// </summary>
[Required]
public string PhoneNumber { get; set; }

/// <summary>
/// Gets or Sets the TemplateId.
/// </summary>
[Required]
public string TemplateId { get; set; }

/// <summary>
/// Gets or Sets the Personalisation.
/// </summary>
public Dictionary<string, dynamic> Personalisation { get; set; }
}
}
91 changes: 91 additions & 0 deletions LearningHub.Nhs.MessagingService/Services/GovNotifyService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
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;

/// <summary>
/// GovNotify Service class.
/// </summary>
public class GovNotifyService : IGovNotifyService
{
private readonly NotificationClient client;

/// <summary>
/// Initializes a new instance of the <see cref="GovNotifyService"/> class.
/// GovNotifyService.
/// </summary>
/// <param name="options">The Messaging Service Model.</param>
public GovNotifyService(IOptions<MessagingServiceModel> options)
{
this.client = new NotificationClient(options.Value.GovNotifyApiKey);
}

/// <summary>
/// Sends an email via the UK Gov.Notify service.
/// </summary>
/// <param name="email">The recipient's email address.</param>
/// <param name="templateId">The ID of the Gov.Notify template to be used for the email.</param>
/// <param name="personalisation">
/// A dictionary containing key-value pairs for personalising the email template.
/// Keys should match the placeholders in the Gov.Notify template.
/// </param>
/// <returns>
/// A unique message ID representing the queued email.
/// </returns>
public async Task<string> SendEmailAsync(string email, string templateId, Dictionary<string, dynamic> personalisation)
{
var normalisedPersonlisation = new Dictionary<string, dynamic>();
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;
}

/// <summary>
/// Sends an SMS via the UK Gov.Notify service.
/// </summary>
/// <param name="phoneNumber">The recipient's phone number.</param>
/// <param name="templateId">The ID of the Gov.Notify template to be used for the SMS.</param>
/// <param name="personalisation">
/// A dictionary containing key-value pairs for personalising the SMS template.
/// Keys should match the placeholders in the Gov.Notify template.
/// </param>
/// <returns>
/// A unique message ID representing the queued SMS.
/// </returns>
public async Task<string> SendSmsAsync(string phoneNumber, string templateId, Dictionary<string, dynamic> personalisation)
{
var normalisedPersonlisation = new Dictionary<string, dynamic>();
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;
}
}
}
25 changes: 25 additions & 0 deletions LearningHub.Nhs.MessagingService/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace LearningHub.Nhs.MessagingService
{
using LearningHub.Nhs.MessagingService.Interfaces;
using LearningHub.Nhs.MessagingService.Model;
using LearningHub.Nhs.MessagingService.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Contains methods to configure the project to be called in an API startup class.
/// </summary>
public static class Startup
{
/// <summary>
/// Registers the implementations in the project with ASP.NET DI.
/// </summary>
/// <param name="services">The IServiceCollection.</param>
/// <param name="configuration">The IConfiguration.</param>
public static void AddMessagingServices(this IServiceCollection services, IConfiguration configuration)
{
services.Configure<MessagingServiceModel>(configuration.GetSection("GovNotify"));
services.AddScoped<IGovNotifyService, GovNotifyService>();
}
}
}
13 changes: 13 additions & 0 deletions LearningHub.Nhs.WebUI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LearningHub.Nhs.ReportApi.S
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.WebUI.AutomatedUiTests", "LearningHub.Nhs.WebUI.AutomatedUiTests\LearningHub.Nhs.WebUI.AutomatedUiTests.csproj", "{A84EC50B-2B01-4819-A2B1-BD867B7595CA}"
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}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -345,6 +349,14 @@ 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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -380,6 +392,7 @@ 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}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1ECA38C8-7C69-4DE6-8293-852C603F4217}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
namespace LearningHub.NHS.OpenAPI.Controllers
{
using System;
using System.Threading.Tasks;
using LearningHub.Nhs.MessagingService.Interfaces;
using LearningHub.Nhs.MessagingService.Model;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

/// <summary>
/// GovNotify Messaging Controller.
/// </summary>
[Route("GovNotifyMessage")]
[Authorize]
public class GovNotifyMessagingController : OpenApiControllerBase
{
private readonly IGovNotifyService messageService;

/// <summary>
/// Initializes a new instance of the <see cref="GovNotifyMessagingController"/> class.
/// </summary>
/// <param name="messageService">The catalogue service.</param>
public GovNotifyMessagingController(IGovNotifyService messageService)
{
this.messageService = messageService;
}

/// <summary>
/// Sends an email using UK Gov.Notify.
/// </summary>
/// <param name="request">personalisation.</param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
[Route("sendemail")]
[HttpPost]
public async Task<IActionResult> SendEmailAsync([FromBody] SendEmailRequest request)
{
try
{
if (string.IsNullOrWhiteSpace(request.Email) || 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);
return this.Ok(response);
}
catch (Exception ex)
{
return this.Ok(ex.Message);
}
}

/// <summary>
/// Sends a sms using UK Gov.Notify.
/// </summary>
/// <param name="request">SendSmsRequest.</param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
[Route("sendsms")]
[HttpPost]
public async Task<IActionResult> SendSmsAsync([FromBody] SendSmsRequest request)
{
try
{
if (string.IsNullOrWhiteSpace(request.PhoneNumber) || string.IsNullOrWhiteSpace(request.TemplateId))
{
return this.BadRequest("phoneNumber and template ID are required");
}

var response = await this.messageService.SendSmsAsync(request.PhoneNumber, request.TemplateId, request.Personalisation);
return this.Ok(response);
}
catch (Exception ex)
{
return this.Ok(ex.Message);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\LearningHub.Nhs.MessagingService\LearningHub.Nhs.MessagingService.csproj" />
<ProjectReference Include="..\LearningHub.Nhs.OpenApi.Repositories.Interface\LearningHub.Nhs.OpenApi.Repositories.Interface.csproj" />
<ProjectReference Include="..\LearningHub.Nhs.OpenApi.Repositories\LearningHub.Nhs.OpenApi.Repositories.csproj" />
<ProjectReference Include="..\LearningHub.Nhs.OpenApi.Services.Interface\LearningHub.Nhs.OpenApi.Services.Interface.csproj" />
Expand Down
2 changes: 2 additions & 0 deletions OpenAPI/LearningHub.Nhs.OpenApi/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace LearningHub.NHS.OpenAPI
using System.Configuration;
using System;
using LearningHub.Nhs.Models.Extensions;
using LearningHub.Nhs.MessagingService;

/// <summary>
/// The Startup class.
Expand Down Expand Up @@ -84,6 +85,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddApplicationInsightsTelemetry();
services.AddControllers(options => options.Filters.Add(new HttpResponseExceptionFilter()));
services.AddControllers(opt => { opt.Filters.Add(new AuthorizeFilter()); });
services.AddMessagingServices(this.Configuration);
services.AddSwaggerGen(
c =>
{
Expand Down
Loading
Loading