From 0244c5027dc7012025af3272f47ce97324d0506c Mon Sep 17 00:00:00 2001 From: Jezz Santos Date: Sat, 13 Jan 2024 08:48:17 +1300 Subject: [PATCH] Added email delivery of messages --- docs/design-principles/0030-recording.md | 22 +- .../0090-authentication-authorization.md | 26 ++ .../0090-authentication-authorization.md.md | 15 - docs/design-principles/0100-email-delivery.md | 18 ++ docs/images/Email-Delivery.png | Bin 0 -> 69248 bytes docs/images/Sources.pptx | Bin 467185 -> 474129 bytes .../HostExtensions.cs | 3 +- .../Lambdas/DeliverEmail.cs | 24 ++ .../serverless.template | 17 + .../AncillaryApplicationSpec.cs | 293 ++++++++++++++++-- .../AncillaryApplication.cs | 96 +++++- .../IAncillaryApplication.cs | 7 + .../Resources.Designer.cs | 45 +++ src/AncillaryApplication/Resources.resx | 15 + .../AuditsApiSpec.cs | 6 +- .../EmailsApiSpec.cs | 129 ++++++++ .../Stubs/StubEmailDeliveryService.cs | 28 ++ ...Service.cs => StubUsageDeliveryService.cs} | 4 +- .../UsagesApiSpec.cs | 24 +- .../DeliverUsageRequestValidatorSpec.cs | 40 +++ .../AncillaryModule.cs | 11 +- .../Emails/DeliverUsageRequestValidator.cs | 16 + .../Api/Emails/EmailsApi.cs | 41 +++ .../NullEmailDeliveryService.cs | 39 +++ ...Service.cs => NullUsageDeliveryService.cs} | 10 +- src/ApiHost1/ApiHostModule.cs | 6 +- .../IEmailDeliveryService.cs | 17 + ...eueRepository.cs => IEmailMessageQueue.cs} | 2 +- ...ingService.cs => IUsageDeliveryService.cs} | 8 +- ...eueRepository.cs => IUsageMessageQueue.cs} | 2 +- .../ReadModels/EmailMessage.cs | 4 +- ...gService.cs => IEmailSchedulingService.cs} | 7 +- .../Functions/DeliverEmail.cs | 23 ++ .../HostExtensions.cs | 1 + .../Recording/QueuedUsageReporter.cs | 10 +- ...ueueRepository.cs => EmailMessageQueue.cs} | 4 +- ...ueueRepository.cs => UsageMessageQueue.cs} | 4 +- .../EmailNotificationsService.cs | 10 +- ...ce.cs => QueuingEmailSchedulingService.cs} | 18 +- .../Ancillary/DeliverEmailRequest.cs | 9 + .../Ancillary/DrainAllEmailsRequest.cs | 10 + .../Extensions/HostExtensions.cs | 4 +- .../AWSLambdas/AWSLambdasApiSpec.cs | 107 +------ .../AzureFunctions/AzureFunctionsApiSpec.cs | 105 +------ .../DeliverAuditSpecBase.cs | 62 ++++ .../DeliverEmailSpecBase.cs | 67 ++++ .../Workers/DeliverEmailRelayWorker.cs | 33 ++ src/SaaStack.sln.DotSettings | 11 + 48 files changed, 1132 insertions(+), 321 deletions(-) create mode 100644 docs/design-principles/0090-authentication-authorization.md delete mode 100644 docs/design-principles/0090-authentication-authorization.md.md create mode 100644 docs/design-principles/0100-email-delivery.md create mode 100644 docs/images/Email-Delivery.png create mode 100644 src/AWSLambdas.Api.WorkerHost/Lambdas/DeliverEmail.cs create mode 100644 src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs create mode 100644 src/AncillaryInfrastructure.IntegrationTests/Stubs/StubEmailDeliveryService.cs rename src/AncillaryInfrastructure.IntegrationTests/Stubs/{StubUsageReportingService.cs => StubUsageDeliveryService.cs} (80%) create mode 100644 src/AncillaryInfrastructure.UnitTests/Api/Emails/DeliverUsageRequestValidatorSpec.cs create mode 100644 src/AncillaryInfrastructure/Api/Emails/DeliverUsageRequestValidator.cs create mode 100644 src/AncillaryInfrastructure/Api/Emails/EmailsApi.cs create mode 100644 src/AncillaryInfrastructure/ApplicationServices/NullEmailDeliveryService.cs rename src/AncillaryInfrastructure/ApplicationServices/{NullUsageReportingService.cs => NullUsageDeliveryService.cs} (63%) create mode 100644 src/Application.Persistence.Shared/IEmailDeliveryService.cs rename src/Application.Persistence.Shared/{IUsageMessageQueueRepository.cs => IEmailMessageQueue.cs} (69%) rename src/Application.Persistence.Shared/{IUsageReportingService.cs => IUsageDeliveryService.cs} (52%) rename src/Application.Persistence.Shared/{IEmailMessageQueueRepository.cs => IUsageMessageQueue.cs} (69%) rename src/Application.Services.Shared/{IEmailSendingService.cs => IEmailSchedulingService.cs} (66%) create mode 100644 src/AzureFunctions.Api.WorkerHost/Functions/DeliverEmail.cs rename src/Infrastructure.Persistence.Shared/ApplicationServices/{EmailMessageQueueRepository.cs => EmailMessageQueue.cs} (90%) rename src/Infrastructure.Persistence.Shared/ApplicationServices/{UsageMessageQueueRepository.cs => UsageMessageQueue.cs} (90%) rename src/Infrastructure.Shared/ApplicationServices/{EmailSendingService.cs => QueuingEmailSchedulingService.cs} (63%) create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DeliverEmailRequest.cs create mode 100644 src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DrainAllEmailsRequest.cs create mode 100644 src/Infrastructure.Worker.Api.IntegrationTests/DeliverAuditSpecBase.cs create mode 100644 src/Infrastructure.Worker.Api.IntegrationTests/DeliverEmailSpecBase.cs create mode 100644 src/Infrastructure.Workers.Api/Workers/DeliverEmailRelayWorker.cs diff --git a/docs/design-principles/0030-recording.md b/docs/design-principles/0030-recording.md index 0d28cbdb..64484512 100644 --- a/docs/design-principles/0030-recording.md +++ b/docs/design-principles/0030-recording.md @@ -131,33 +131,37 @@ These are generally non-technical or system performance-related events but more This is simply achieved by leveraging the infrastructure of the `ILoggerFactory` of .NET. -## Recorder +## The Recorder The `HostRecorder` is used in all running hosts (e.g., ApiHosts, WebsiteHost, FunctionHosts and TestingHosts). -The adapters that are used by the `HostRecorder` to send telemetry to its various infrastructure components are configurable via `RecordingOptions,` which are tailored for each host and to the specific cloud environment the `HostRecorder` is running in. +The adapters that are used by the `HostRecorder` to send telemetry to its various infrastructure components are configurable via `RecordingOptions,` which are tailored for each host and to the specific cloud environment the `HostRecorder` is running in (i.e. Azure or AWS). For example, this is the default infrastructure that is used by the `HostRecorder` when deployed to Azure. -> Similar components are used, by default, when deployed to AWS, except that Application Insights is replaced by Cloud Watch, the queues are replaced by SQS queues, and the Audits are stored in an RDS store. +![Azure Recording](../images/Recorder-Azure.png) -![](../images/Recorder-Azure.png) +When deployed to AWS, Application Insights is replaced by Cloud Watch, the queues are replaced by SQS queues, and the Audits are stored in an RDS database. + +![AWS Recording](../images/Recorder-AWS.png) No matter what the host actually is, there are two main flows of data that are handled by the `HostRecorder`. Both are high in reliability and both are asynchronous. ### Traces, Crashes, Measures -By default, all Traces, Crashes, and Measures are offloaded to Application Insights directly using the Application Insights `TelemetryClient` SDK. +When deployed to Azure, all Traces, Crashes, and Measures are offloaded to Application Insights directly using the Application Insights `TelemetryClient` SDK. + +> The client SDK for Application Insights manages buffering and store-and-forward of this data asynchronously so that individual HTTP requests can return immediately without paying the tax of uploading the data to the cloud. The SDK supports buffering, retries, and other strategies to deliver the data reliably (using the `ServerTelemetryChannel`). See https://learn.microsoft.com/en-us/azure/azure-monitor/app/telemetry-channels for more details. -> This SDK manages buffering and store-and-forward of this data asynchronously so that individual HTTP requests can return immediately without paying the tax of uploading the data to the cloud. The SDK supports buffering, retries, and other strategies to deliver the data reliably (using the `ServerTelemetryChannel`). See https://learn.microsoft.com/en-us/azure/azure-monitor/app/telemetry-channels for more details. +When deployed to AWS, all Traces, Crashes and Measures are offloaded to CloudWatch X-Ray using the client SDK. ### Audits and Usages -Audits are ultimately destined to be stored permanently in a database. Usages are typically relayed to a remote 3rd party system. +Audits are ultimately destined to be stored permanently in a database. Usages are typically relayed to a remote 3rd party system (i.e. Google Analytics, MixPanel, Amplitude etc). -In both cases, to avoid tying up the client's HTTP request, the telemetry for these types is first stored on a reliable queue, and then later, an API call to the Ancillary API is issued that delivers the telemetry to its respective destination. +In both cases, to avoid tying up the client's HTTP request, the telemetry for these types is first "scheduled" on a reliable queue, and then later, an API call to the Ancillary API is issued that "delivers" the telemetry to its final destination. -> In Azure, an Azure Function is triggered when the telemetry arrives on a queue, and the Azure Function simply calls an API in the Ancillary API to deliver the telemetry to its destination. The Azure Function Trigger is a reliable means to handle this process, since if the API call fails, the message will return to the queue, and subsequent failures will result in the message moving to the poison queue, to be dealt with manually. +> On Azure, an Azure Function is triggered when the telemetry arrives on a queue, and the Azure Function simply calls an API in the Ancillary API to deliver the telemetry to its destination. The Azure Function Trigger is a reliable means to handle this process, since if the API call fails, the message will return to the queue, and subsequent failures will result in the message moving to the poison queue, to be dealt with manually. > In AWS, a Lambda does the same job as the Azure Function above, and the SQS adapter is configured with poison queues (a.k.a a dead-letter queue) to operate in exactly the same way. diff --git a/docs/design-principles/0090-authentication-authorization.md b/docs/design-principles/0090-authentication-authorization.md new file mode 100644 index 00000000..2ccaa28e --- /dev/null +++ b/docs/design-principles/0090-authentication-authorization.md @@ -0,0 +1,26 @@ +# Authentication & Authorization + +## Design Principles + +## Implementation + +### Password Credential Authentication + +### Token Authorization + +### HMAC Authentication/Authorization + +### APIKey Authorization + +### Cookie Authentication + +### Cookie Authorization + +* Usually performed by a BackendForFrontend component, reverse-proxies the token hidden in the cookie, into a token passed to the backend + +### Declarative Authorization Syntax + +### Role Based Authorization + +### Feature Based Authorization + \ No newline at end of file diff --git a/docs/design-principles/0090-authentication-authorization.md.md b/docs/design-principles/0090-authentication-authorization.md.md deleted file mode 100644 index 20818abb..00000000 --- a/docs/design-principles/0090-authentication-authorization.md.md +++ /dev/null @@ -1,15 +0,0 @@ -# Authentication & Authorization - -## Design Principles - -## Implementation - -Cookie Authentication - -Usually performed by a BackendForFrontend component, reverse-proxies the token hidden in the cookie, into a token passed to the backend - -Authorization - -For marked endpoints, verifies that the cookie exists. - - \ No newline at end of file diff --git a/docs/design-principles/0100-email-delivery.md b/docs/design-principles/0100-email-delivery.md new file mode 100644 index 00000000..0c2dcc47 --- /dev/null +++ b/docs/design-principles/0100-email-delivery.md @@ -0,0 +1,18 @@ +# Email Delivery + +## Design Principles + +Many processes in the backend of a SaaS product aim to alert the user to activities or processes in a SaaS product, that warrant their attention, and most of these notifications/alerts are ultimately delivered by email (albeit some are delivered by other means too, i.e. in-app, SMS texts etc). + +Sending emails is often done via 3rd party systems like: SendGrid, MailGun, PostMark etc., over HTTP. Due to its nature, this mechanism isn't very reliable, especially with systems under load. + +* We need to "broker" between the sending of emails and the delivering of them to make the entire process more reliable, and we need to provide observability when things go wrong. +* Since an inbound API request to any API backend can yield of the order ~10 emails per API call, delivering them reliably across HTTP can require minutes of time. If you consider the possibility of retries and back-offs etc. We simply could not afford to keep API clients blocked and waiting while email delivery takes place, let alone the risk of timing out their connection to the inbound API call in the first place. + +Fortunately, an individual email arriving in a person inbox is not a time-critical and synchronous usability function to begin with. Some delay is anticipated. + +Thus we need to take advantage of all these facts and engineer a reliable mechanism. + +## Implementation + +![Email Delivery](../../docs/images/Email-Delivery.png) \ No newline at end of file diff --git a/docs/images/Email-Delivery.png b/docs/images/Email-Delivery.png new file mode 100644 index 0000000000000000000000000000000000000000..272e9f23be0355aac3036b71abcdc2aaeed2cad9 GIT binary patch literal 69248 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
  • 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 literal 0 HcmV?d00001 diff --git a/docs/images/Sources.pptx b/docs/images/Sources.pptx index 8e3a1b733f8a5d81a0e2c9204ce92c7810e17065..f622b503b3f63e6fb63fe64503e8895e468e52a2 100644 GIT binary patch delta 58775 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 => - new CrashTraceOnlyRecorder("Azure API Lambdas", c.Resolve(), + new CrashTraceOnlyRecorder("AWS API Lambdas", c.Resolve(), c.Resolve())); services.AddSingleton(c => new InterHostServiceClient(c.Resolve(), @@ -43,5 +43,6 @@ public static void AddDependencies(this IServiceCollection services, IConfigurat c.Resolve().GetAncillaryApiHostBaseUrl())); services.AddSingleton, DeliverUsageRelayWorker>(); services.AddSingleton, DeliverAuditRelayWorker>(); + services.AddSingleton, DeliverEmailRelayWorker>(); } } \ No newline at end of file diff --git a/src/AWSLambdas.Api.WorkerHost/Lambdas/DeliverEmail.cs b/src/AWSLambdas.Api.WorkerHost/Lambdas/DeliverEmail.cs new file mode 100644 index 00000000..4d6a917e --- /dev/null +++ b/src/AWSLambdas.Api.WorkerHost/Lambdas/DeliverEmail.cs @@ -0,0 +1,24 @@ +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Core; +using Amazon.Lambda.SQSEvents; +using Application.Persistence.Shared.ReadModels; +using AWSLambdas.Api.WorkerHost.Extensions; +using Infrastructure.Workers.Api; + +namespace AWSLambdas.Api.WorkerHost.Lambdas; + +public class DeliverEmail +{ + private readonly IQueueMonitoringApiRelayWorker _worker; + + public DeliverEmail(IQueueMonitoringApiRelayWorker worker) + { + _worker = worker; + } + + [LambdaFunction] + public async Task Run(SQSEvent sqsEvent, ILambdaContext context) + { + return await sqsEvent.RelayRecordsAsync(_worker, CancellationToken.None); + } +} \ No newline at end of file diff --git a/src/AWSLambdas.Api.WorkerHost/serverless.template b/src/AWSLambdas.Api.WorkerHost/serverless.template index 193ed72a..edd49ab4 100644 --- a/src/AWSLambdas.Api.WorkerHost/serverless.template +++ b/src/AWSLambdas.Api.WorkerHost/serverless.template @@ -36,6 +36,23 @@ "PackageType": "Zip", "Handler": "AWSLambdas.Api.WorkerHost::AWSLambdas.Api.WorkerHost.Lambdas.DeliverAudit_Run_Generated::Run" } + }, + "AWSLambdasApiWorkerHostLambdasDeliverEmailRunGenerated": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations" + }, + "Properties": { + "Runtime": "dotnet6", + "CodeUri": ".", + "MemorySize": 256, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Zip", + "Handler": "AWSLambdas.Api.WorkerHost::AWSLambdas.Api.WorkerHost.Lambdas.DeliverEmail_Run_Generated::Run" + } } } } \ No newline at end of file diff --git a/src/AncillaryApplication.UnitTests/AncillaryApplicationSpec.cs b/src/AncillaryApplication.UnitTests/AncillaryApplicationSpec.cs index c5c7a477..50654b9a 100644 --- a/src/AncillaryApplication.UnitTests/AncillaryApplicationSpec.cs +++ b/src/AncillaryApplication.UnitTests/AncillaryApplicationSpec.cs @@ -22,8 +22,10 @@ public class AncillaryApplicationSpec private readonly Mock _auditMessageRepository; private readonly Mock _auditRepository; private readonly Mock _caller; - private readonly Mock _usageMessageRepository; - private readonly Mock _usageReportingService; + private readonly Mock _emailDeliveryService; + private readonly Mock _emailMessageQueue; + private readonly Mock _usageDeliveryService; + private readonly Mock _usageMessageQueue; public AncillaryApplicationSpec() { @@ -32,15 +34,18 @@ public AncillaryApplicationSpec() idFactory.Setup(idf => idf.Create(It.IsAny())) .Returns(new Result("anid".ToId())); _caller = new Mock(); - _usageMessageRepository = new Mock(); - _usageReportingService = new Mock(); + _usageMessageQueue = new Mock(); + _usageDeliveryService = new Mock(); _auditMessageRepository = new Mock(); _auditRepository = new Mock(); _auditRepository.Setup(ar => ar.SaveAsync(It.IsAny(), It.IsAny())) .Returns((AuditRoot root, CancellationToken _) => Task.FromResult>(root)); + _emailMessageQueue = new Mock(); + _emailDeliveryService = new Mock(); - _application = new AncillaryApplication(recorder.Object, idFactory.Object, _usageMessageRepository.Object, - _usageReportingService.Object, _auditMessageRepository.Object, _auditRepository.Object); + _application = new AncillaryApplication(recorder.Object, idFactory.Object, _usageMessageQueue.Object, + _usageDeliveryService.Object, _auditMessageRepository.Object, _auditRepository.Object, + _emailMessageQueue.Object, _emailDeliveryService.Object); } [Fact] @@ -50,8 +55,8 @@ public async Task WhenDeliverUsageAsyncAndMessageIsNotRehydratable_ThenReturnsEr result.Should().BeError(ErrorCode.RuleViolation, Resources.AncillaryApplication_InvalidQueuedMessage.Format(nameof(UsageMessage), "anunknownmessage")); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), It.IsAny(), It.IsAny(), + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny()), Times.Never); } @@ -68,8 +73,8 @@ public async Task WhenDeliverUsageAsyncAndMessageHasNoForId_ThenReturnsError() result.Should().BeError(ErrorCode.RuleViolation, Resources.AncillaryApplication_MissingUsageForId); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), It.IsAny(), It.IsAny(), + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny()), Times.Never); } @@ -86,8 +91,8 @@ public async Task WhenDeliverUsageAsyncAndMessageHasNoEventName_ThenReturnsError result.Should().BeError(ErrorCode.RuleViolation, Resources.AncillaryApplication_MissingUsageEventName); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), It.IsAny(), It.IsAny(), + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny()), Times.Never); } @@ -107,8 +112,8 @@ public async Task WhenDeliverUsageAsync_ThenDelivers() var result = await _application.DeliverUsageAsync(_caller.Object, messageAsJson, CancellationToken.None); result.Should().BeSuccess(); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), "aforid", "aneventname", + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), "aforid", "aneventname", It.Is>(dic => dic.Count == 1 && dic["aname"] == "avalue" @@ -169,11 +174,157 @@ public async Task WhenDeliverAuditAsync_ThenDelivers() ), It.IsAny())); } + [Fact] + public async Task WhenDeliverEmailAsyncAndMessageIsNotRehydratable_ThenReturnsError() + { + var result = await _application.DeliverEmailAsync(_caller.Object, "anunknownmessage", CancellationToken.None); + + result.Should().BeError(ErrorCode.RuleViolation, + Resources.AncillaryApplication_InvalidQueuedMessage.Format(nameof(EmailMessage), "anunknownmessage")); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); + } + + [Fact] + public async Task WhenDeliverEmailAsyncAndMessageHasNoHtml_ThenReturnsError() + { + var messageAsJson = new EmailMessage + { + Html = null + }.ToJson()!; + + var result = await _application.DeliverEmailAsync(_caller.Object, messageAsJson, CancellationToken.None); + + result.Should().BeError(ErrorCode.RuleViolation, + Resources.AncillaryApplication_MissingEmailHtml); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); + } + + [Fact] + public async Task WhenDeliverEmailAsyncAndMessageHasNoSubject_ThenReturnsError() + { + var messageAsJson = new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = null + } + }.ToJson()!; + + var result = await _application.DeliverEmailAsync(_caller.Object, messageAsJson, CancellationToken.None); + + result.Should().BeError(ErrorCode.RuleViolation, + Resources.AncillaryApplication_MissingEmailSubject); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); + } + + [Fact] + public async Task WhenDeliverEmailAsyncAndMessageHasNoBody_ThenReturnsError() + { + var messageAsJson = new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = "asubject", + HtmlBody = null + } + }.ToJson()!; + + var result = await _application.DeliverEmailAsync(_caller.Object, messageAsJson, CancellationToken.None); + + result.Should().BeError(ErrorCode.RuleViolation, + Resources.AncillaryApplication_MissingEmailBody); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); + } + + [Fact] + public async Task WhenDeliverEmailAsyncAndMessageHasNoRecipient_ThenReturnsError() + { + var messageAsJson = new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = "asubject", + HtmlBody = "abody", + ToEmailAddress = null + } + }.ToJson()!; + + var result = await _application.DeliverEmailAsync(_caller.Object, messageAsJson, CancellationToken.None); + + result.Should().BeError(ErrorCode.RuleViolation, + Resources.AncillaryApplication_MissingEmailRecipient); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); + } + + [Fact] + public async Task WhenDeliverEmailAsyncAndMessageHasNoSender_ThenReturnsError() + { + var messageAsJson = new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = "asubject", + HtmlBody = "abody", + ToEmailAddress = "arecipientemailaddress", + FromEmailAddress = null + } + }.ToJson()!; + + var result = await _application.DeliverEmailAsync(_caller.Object, messageAsJson, CancellationToken.None); + + result.Should().BeError(ErrorCode.RuleViolation, + Resources.AncillaryApplication_MissingEmailSender); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); + } + + [Fact] + public async Task WhenDeliverEmailAsync_ThenDelivers() + { + var messageAsJson = new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = "asubject", + HtmlBody = "abody", + ToEmailAddress = "arecipientemailaddress", + ToDisplayName = "arecipient", + FromEmailAddress = "asenderemailaddress", + FromDisplayName = "asender" + } + }.ToJson()!; + + var result = await _application.DeliverEmailAsync(_caller.Object, messageAsJson, CancellationToken.None); + + result.Should().BeSuccess(); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), "asubject", "abody", "arecipientemailaddress", + "arecipient", "asenderemailaddress", "asender", + It.IsAny())); + } + #if TESTINGONLY [Fact] public async Task WhenDrainAllUsagesAsyncAndNoneOnQueue_ThenDoesNotDeliver() { - _usageMessageRepository.Setup(umr => + _usageMessageQueue.Setup(umr => umr.PopSingleAsync(It.IsAny>>>(), It.IsAny())) .Returns(Task.FromResult>(false)); @@ -181,11 +332,11 @@ public async Task WhenDrainAllUsagesAsyncAndNoneOnQueue_ThenDoesNotDeliver() var result = await _application.DrainAllUsagesAsync(_caller.Object, CancellationToken.None); result.Should().BeSuccess(); - _usageMessageRepository.Verify( + _usageMessageQueue.Verify( urs => urs.PopSingleAsync(It.IsAny>>>(), It.IsAny())); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), It.IsAny(), It.IsAny(), + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny()), Times.Never); } @@ -203,7 +354,7 @@ public async Task WhenDrainAllUsagesAsyncAndSomeOnQueue_ThenDeliversAll() EventName = "aneventname2" }; var callbackCount = 1; - _usageMessageRepository.Setup(umr => + _usageMessageQueue.Setup(umr => umr.PopSingleAsync(It.IsAny>>>(), It.IsAny())) .Callback((Func>> action, CancellationToken _) => @@ -227,17 +378,17 @@ public async Task WhenDrainAllUsagesAsyncAndSomeOnQueue_ThenDeliversAll() var result = await _application.DrainAllUsagesAsync(_caller.Object, CancellationToken.None); result.Should().BeSuccess(); - _usageMessageRepository.Verify( + _usageMessageQueue.Verify( urs => urs.PopSingleAsync(It.IsAny>>>(), It.IsAny()), Times.Exactly(2)); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), "aforid1", "aneventname1", + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), "aforid1", "aneventname1", It.IsAny>(), It.IsAny())); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), "aforid2", "aneventname2", + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), "aforid2", "aneventname2", It.IsAny>(), It.IsAny())); - _usageReportingService.Verify( - urs => urs.TrackAsync(It.IsAny(), It.IsAny(), It.IsAny(), + _usageDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny()), Times.Exactly(2)); } @@ -308,5 +459,95 @@ public async Task WhenDrainAllAuditsAsyncAndSomeOnQueue_ThenDeliversAll() _auditRepository.Verify(ar => ar.SaveAsync(It.IsAny(), It.IsAny()), Times.Exactly(2)); } + + [Fact] + public async Task WhenDrainAllEmailsAsyncAndNoneOnQueue_ThenDoesNotDeliver() + { + _emailMessageQueue.Setup(umr => + umr.PopSingleAsync(It.IsAny>>>(), + It.IsAny())) + .Returns(Task.FromResult>(false)); + + var result = await _application.DrainAllEmailsAsync(_caller.Object, CancellationToken.None); + + result.Should().BeSuccess(); + _emailMessageQueue.Verify( + urs => urs.PopSingleAsync(It.IsAny>>>(), + It.IsAny())); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); + } + + [Fact] + public async Task WhenDrainAllEmailsAsyncAndSomeOnQueue_ThenDeliversAll() + { + var message1 = new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = "asubject1", + HtmlBody = "abody1", + ToEmailAddress = "arecipientemailaddress1", + ToDisplayName = "arecipient1", + FromEmailAddress = "asenderemailaddress1", + FromDisplayName = "asender1" + } + }; + var message2 = new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = "asubject2", + HtmlBody = "abody2", + ToEmailAddress = "arecipientemailaddress2", + ToDisplayName = "arecipient2", + FromEmailAddress = "asenderemailaddress2", + FromDisplayName = "asender2" + } + }; + var callbackCount = 1; + _emailMessageQueue.Setup(umr => + umr.PopSingleAsync(It.IsAny>>>(), + It.IsAny())) + .Callback((Func>> action, CancellationToken _) => + { + if (callbackCount == 1) + { + action(message1, CancellationToken.None); + } + + if (callbackCount == 2) + { + action(message2, CancellationToken.None); + } + }) + .Returns((Func>> _, CancellationToken _) => + { + callbackCount++; + return Task.FromResult>(callbackCount is 1 or 2); + }); + + var result = await _application.DrainAllEmailsAsync(_caller.Object, CancellationToken.None); + + result.Should().BeSuccess(); + _emailMessageQueue.Verify( + urs => urs.PopSingleAsync(It.IsAny>>>(), + It.IsAny()), Times.Exactly(2)); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), "asubject1", "abody1", "arecipientemailaddress1", + "arecipient1", "asenderemailaddress1", "asender1", + It.IsAny())); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), "asubject2", "abody2", "arecipientemailaddress2", + "arecipient2", "asenderemailaddress2", "asender2", + It.IsAny())); + _emailDeliveryService.Verify( + urs => urs.DeliverAsync(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), + Times.Exactly(2)); + } #endif } \ No newline at end of file diff --git a/src/AncillaryApplication/AncillaryApplication.cs b/src/AncillaryApplication/AncillaryApplication.cs index f9d08151..1ce9bdf4 100644 --- a/src/AncillaryApplication/AncillaryApplication.cs +++ b/src/AncillaryApplication/AncillaryApplication.cs @@ -18,21 +18,45 @@ public class AncillaryApplication : IAncillaryApplication { private readonly IAuditMessageQueueRepository _auditMessageQueueRepository; private readonly IAuditRepository _auditRepository; + private readonly IEmailDeliveryService _emailDeliveryService; + private readonly IEmailMessageQueue _emailMessageQueue; private readonly IIdentifierFactory _idFactory; private readonly IRecorder _recorder; - private readonly IUsageMessageQueueRepository _usageMessageQueueRepository; - private readonly IUsageReportingService _usageReportingService; + private readonly IUsageDeliveryService _usageDeliveryService; + private readonly IUsageMessageQueue _usageMessageQueue; public AncillaryApplication(IRecorder recorder, IIdentifierFactory idFactory, - IUsageMessageQueueRepository usageMessageQueueRepository, IUsageReportingService usageReportingService, - IAuditMessageQueueRepository auditMessageQueueRepository, IAuditRepository auditRepository) + IUsageMessageQueue usageMessageQueue, IUsageDeliveryService usageDeliveryService, + IAuditMessageQueueRepository auditMessageQueueRepository, IAuditRepository auditRepository, + IEmailMessageQueue emailMessageQueue, IEmailDeliveryService emailDeliveryService) { _recorder = recorder; _idFactory = idFactory; - _usageMessageQueueRepository = usageMessageQueueRepository; - _usageReportingService = usageReportingService; + _usageMessageQueue = usageMessageQueue; + _usageDeliveryService = usageDeliveryService; _auditMessageQueueRepository = auditMessageQueueRepository; _auditRepository = auditRepository; + _emailMessageQueue = emailMessageQueue; + _emailDeliveryService = emailDeliveryService; + } + + public async Task> DeliverEmailAsync(ICallerContext context, string messageAsJson, + CancellationToken cancellationToken) + { + var rehydrated = RehydrateMessage(messageAsJson); + if (!rehydrated.IsSuccessful) + { + return rehydrated.Error; + } + + var delivered = await DeliverEmailAsync(context, rehydrated.Value, cancellationToken); + if (!delivered.IsSuccessful) + { + return delivered.Error; + } + + _recorder.TraceInformation(context.ToCall(), "Delivered email message: {Message}", messageAsJson); + return true; } public async Task> DeliverUsageAsync(ICallerContext context, string messageAsJson, @@ -89,13 +113,25 @@ public async Task> DeliverAuditAsync(ICallerContext context, return true; } +#if TESTINGONLY + public async Task> DrainAllEmailsAsync(ICallerContext context, CancellationToken cancellationToken) + { + await DrainAllAsync(_emailMessageQueue, + message => DeliverEmailAsync(context, message, cancellationToken), cancellationToken); + + _recorder.TraceInformation(context.ToCall(), "Drained all email messages"); + + return Result.Ok; + } +#endif + #if TESTINGONLY public async Task> DrainAllUsagesAsync(ICallerContext context, CancellationToken cancellationToken) { - await DrainAllAsync(_usageMessageQueueRepository, + await DrainAllAsync(_usageMessageQueue, message => DeliverUsageAsync(context, message, cancellationToken), cancellationToken); - _recorder.TraceInformation(context.ToCall(), "Drained all usages"); + _recorder.TraceInformation(context.ToCall(), "Drained all usage messages"); return Result.Ok; } @@ -107,12 +143,52 @@ public async Task> DrainAllAuditsAsync(ICallerContext context, Can await DrainAllAsync(_auditMessageQueueRepository, message => DeliverAuditAsync(context, message, cancellationToken), cancellationToken); - _recorder.TraceInformation(context.ToCall(), "Drained all audits"); + _recorder.TraceInformation(context.ToCall(), "Drained all audit messages"); return Result.Ok; } #endif + private async Task> DeliverEmailAsync(ICallerContext context, EmailMessage message, + CancellationToken cancellationToken) + { + if (message.Html.IsInvalidParameter(x => x.Exists(), nameof(EmailMessage.Html), out _)) + { + return Error.RuleViolation(Resources.AncillaryApplication_MissingEmailHtml); + } + + if (message.Html!.Subject.IsInvalidParameter(x => x.HasValue(), nameof(EmailMessage.Html.Subject), out _)) + { + return Error.RuleViolation(Resources.AncillaryApplication_MissingEmailSubject); + } + + if (message.Html.HtmlBody.IsInvalidParameter(x => x.HasValue(), nameof(EmailMessage.Html.HtmlBody), out _)) + { + return Error.RuleViolation(Resources.AncillaryApplication_MissingEmailBody); + } + + if (message.Html.ToEmailAddress.IsInvalidParameter(x => x.HasValue(), nameof(EmailMessage.Html.ToEmailAddress), + out _)) + { + return Error.RuleViolation(Resources.AncillaryApplication_MissingEmailRecipient); + } + + if (message.Html.FromEmailAddress.IsInvalidParameter(x => x.HasValue(), + nameof(EmailMessage.Html.FromEmailAddress), out _)) + { + return Error.RuleViolation(Resources.AncillaryApplication_MissingEmailSender); + } + + await _emailDeliveryService.DeliverAsync(context, message.Html.Subject!, message.Html.HtmlBody!, + message.Html.ToEmailAddress!, message.Html.ToDisplayName, message.Html.FromEmailAddress!, + message.Html.FromDisplayName, + cancellationToken); + + _recorder.TraceInformation(context.ToCall(), "Delivered email to {For}", message.Html.ToEmailAddress!); + + return true; + } + private async Task> DeliverUsageAsync(ICallerContext context, UsageMessage message, CancellationToken cancellationToken) { @@ -126,7 +202,7 @@ private async Task> DeliverUsageAsync(ICallerContext context return Error.RuleViolation(Resources.AncillaryApplication_MissingUsageEventName); } - await _usageReportingService.TrackAsync(context, message.ForId!, message.EventName!, message.Additional, + await _usageDeliveryService.DeliverAsync(context, message.ForId!, message.EventName!, message.Additional, cancellationToken); _recorder.TraceInformation(context.ToCall(), "Delivered usage for {For}", message.ForId!); diff --git a/src/AncillaryApplication/IAncillaryApplication.cs b/src/AncillaryApplication/IAncillaryApplication.cs index fdfca6fd..fd992c03 100644 --- a/src/AncillaryApplication/IAncillaryApplication.cs +++ b/src/AncillaryApplication/IAncillaryApplication.cs @@ -9,6 +9,9 @@ public interface IAncillaryApplication Task> DeliverAuditAsync(ICallerContext context, string messageAsJson, CancellationToken cancellationToken); + Task> DeliverEmailAsync(ICallerContext context, string messageAsJson, + CancellationToken cancellationToken); + Task> DeliverUsageAsync(ICallerContext context, string messageAsJson, CancellationToken cancellationToken); @@ -16,6 +19,10 @@ Task> DeliverUsageAsync(ICallerContext context, string messa Task> DrainAllAuditsAsync(ICallerContext context, CancellationToken cancellationToken); #endif +#if TESTINGONLY + Task> DrainAllEmailsAsync(ICallerContext context, CancellationToken cancellationToken); +#endif + #if TESTINGONLY Task> DrainAllUsagesAsync(ICallerContext context, CancellationToken cancellationToken); #endif diff --git a/src/AncillaryApplication/Resources.Designer.cs b/src/AncillaryApplication/Resources.Designer.cs index d451b0c0..1152100b 100644 --- a/src/AncillaryApplication/Resources.Designer.cs +++ b/src/AncillaryApplication/Resources.Designer.cs @@ -77,6 +77,51 @@ internal static string AncillaryApplication_MissingAuditCode { } } + /// + /// Looks up a localized string similar to The email message is missing a 'HtmlBody'. + /// + internal static string AncillaryApplication_MissingEmailBody { + get { + return ResourceManager.GetString("AncillaryApplication_MissingEmailBody", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The email message is missing the 'HTML' email. + /// + internal static string AncillaryApplication_MissingEmailHtml { + get { + return ResourceManager.GetString("AncillaryApplication_MissingEmailHtml", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The email message is missing a 'ToEmailAddress' recipient. + /// + internal static string AncillaryApplication_MissingEmailRecipient { + get { + return ResourceManager.GetString("AncillaryApplication_MissingEmailRecipient", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The email message is missing a 'FromEmailAddress' sender. + /// + internal static string AncillaryApplication_MissingEmailSender { + get { + return ResourceManager.GetString("AncillaryApplication_MissingEmailSender", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The email message is missing a 'Subject'. + /// + internal static string AncillaryApplication_MissingEmailSubject { + get { + return ResourceManager.GetString("AncillaryApplication_MissingEmailSubject", resourceCulture); + } + } + /// /// Looks up a localized string similar to The audit message is missing a 'TenantId'. /// diff --git a/src/AncillaryApplication/Resources.resx b/src/AncillaryApplication/Resources.resx index cd36ccca..b070821a 100644 --- a/src/AncillaryApplication/Resources.resx +++ b/src/AncillaryApplication/Resources.resx @@ -39,4 +39,19 @@ The audit message is missing a 'TenantId' + + The email message is missing the 'HTML' email + + + The email message is missing a 'Subject' + + + The email message is missing a 'HtmlBody' + + + The email message is missing a 'ToEmailAddress' recipient + + + The email message is missing a 'FromEmailAddress' sender + \ No newline at end of file diff --git a/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs index ea5b1cc5..b589ce0d 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/AuditsApiSpec.cs @@ -34,12 +34,12 @@ public async Task WhenDeliverAudit_ThenDelivers() { Message = new AuditMessage { + MessageId = "amessageid", + TenantId = "atenantid", CallId = "acallid", CallerId = "acallerid", - TenantId = "atenantid", AuditCode = "anauditcode", AgainstId = "anagainstid", - MessageId = "amessageid", MessageTemplate = "amessagetemplate", Arguments = new List { "anarg1", "anarg2" } }.ToJson()! @@ -128,6 +128,6 @@ public async Task WhenDrainAllAuditsAndSome_ThenDrains() private static void OverrideDependencies(IServiceCollection services) { - services.AddSingleton(); + services.AddSingleton(); } } \ No newline at end of file diff --git a/src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs new file mode 100644 index 00000000..4b8cc19d --- /dev/null +++ b/src/AncillaryInfrastructure.IntegrationTests/EmailsApiSpec.cs @@ -0,0 +1,129 @@ +using AncillaryInfrastructure.IntegrationTests.Stubs; +using ApiHost1; +using Application.Persistence.Shared; +using Application.Persistence.Shared.ReadModels; +using Common; +using Common.Extensions; +using FluentAssertions; +using Infrastructure.Web.Api.Common.Extensions; +using Infrastructure.Web.Api.Operations.Shared.Ancillary; +using IntegrationTesting.WebApi.Common; +using Microsoft.Extensions.DependencyInjection; +using UnitTesting.Common; +using Xunit; +using Task = System.Threading.Tasks.Task; + +namespace AncillaryInfrastructure.IntegrationTests; + +[Trait("Category", "Integration.Web")] +[Collection("API")] +public class EmailsApiSpec : WebApiSpec +{ + private readonly StubEmailDeliveryService _emailDeliveryService; + private readonly IEmailMessageQueue _emailMessageQueue; + + public EmailsApiSpec(WebApiSetup setup) : base(setup, OverrideDependencies) + { + EmptyAllRepositories(setup); + _emailDeliveryService = setup.GetRequiredService().As(); + _emailDeliveryService.Reset(); + _emailMessageQueue = setup.GetRequiredService(); + _emailMessageQueue.DestroyAllAsync(CancellationToken.None).GetAwaiter().GetResult(); + } + + [Fact] + public async Task WhenDeliverEmail_ThenDelivers() + { + var request = new DeliverEmailRequest + { + Message = new EmailMessage + { + MessageId = "amessageid", + CallId = "acallid", + CallerId = "acallerid", + Html = new QueuedEmailHtmlMessage + { + FromDisplayName = "afromdisplayname", + FromEmailAddress = "afromemail", + HtmlBody = "anhtmlbody", + Subject = "asubject", + ToDisplayName = "atodisplayname", + ToEmailAddress = "atoemail" + } + }.ToJson()! + }; + var result = await Api.PostAsync(request, req => req.SetHMACAuth(request, "asecret")); + + result.Content.Value.IsDelivered.Should().BeTrue(); + _emailDeliveryService.LastSubject.Should().Be("asubject"); + } + +#if TESTINGONLY + [Fact] + public async Task WhenDrainAllEmailsAndNone_ThenDoesNotDrainAny() + { + var request = new DrainAllEmailsRequest(); + await Api.PostAsync(request, req => req.SetHMACAuth(request, "asecret")); + + _emailDeliveryService.LastSubject.Should().BeNone(); + } +#endif + +#if TESTINGONLY + [Fact] + public async Task WhenDrainAllEmailsAndSome_ThenDrains() + { + var call = CallContext.CreateCustom("acallid", "acallerid", "atenantid"); + await _emailMessageQueue.PushAsync(call, new EmailMessage + { + MessageId = "amessageid1", + Html = new QueuedEmailHtmlMessage + { + FromDisplayName = "afromdisplayname", + FromEmailAddress = "afromemail", + HtmlBody = "anhtmlbody", + Subject = "asubject1", + ToDisplayName = "atodisplayname", + ToEmailAddress = "atoemail" + } + }, CancellationToken.None); + await _emailMessageQueue.PushAsync(call, new EmailMessage + { + MessageId = "amessageid2", + Html = new QueuedEmailHtmlMessage + { + FromDisplayName = "afromdisplayname", + FromEmailAddress = "afromemail", + HtmlBody = "anhtmlbody", + Subject = "asubject2", + ToDisplayName = "atodisplayname", + ToEmailAddress = "atoemail" + } + }, CancellationToken.None); + await _emailMessageQueue.PushAsync(call, new EmailMessage + { + MessageId = "amessageid3", + Html = new QueuedEmailHtmlMessage + { + FromDisplayName = "afromdisplayname", + FromEmailAddress = "afromemail", + HtmlBody = "anhtmlbody", + Subject = "asubject3", + ToDisplayName = "atodisplayname", + ToEmailAddress = "atoemail" + } + }, CancellationToken.None); + + var request = new DrainAllEmailsRequest(); + await Api.PostAsync(request, req => req.SetHMACAuth(request, "asecret")); + + _emailDeliveryService.AllSubjects.Count.Should().Be(3); + _emailDeliveryService.AllSubjects.Should().ContainInOrder("asubject1", "asubject2", "asubject3"); + } +#endif + + private static void OverrideDependencies(IServiceCollection services) + { + services.AddSingleton(); + } +} \ No newline at end of file diff --git a/src/AncillaryInfrastructure.IntegrationTests/Stubs/StubEmailDeliveryService.cs b/src/AncillaryInfrastructure.IntegrationTests/Stubs/StubEmailDeliveryService.cs new file mode 100644 index 00000000..cb9c3ce8 --- /dev/null +++ b/src/AncillaryInfrastructure.IntegrationTests/Stubs/StubEmailDeliveryService.cs @@ -0,0 +1,28 @@ +using Application.Interfaces; +using Application.Persistence.Shared; +using Common; + +namespace AncillaryInfrastructure.IntegrationTests.Stubs; + +public sealed class StubEmailDeliveryService : IEmailDeliveryService +{ + public List AllSubjects { get; private set; } = new(); + + public Optional LastSubject { get; private set; } = Optional.None; + + public Task> DeliverAsync(ICallerContext context, string subject, string htmlBody, + string toEmailAddress, string? toDisplayName, + string fromEmailAddress, string? fromDisplayName, CancellationToken cancellationToken = default) + { + AllSubjects.Add(subject); + LastSubject = Optional.Some(subject); + + return Task.FromResult(Result.Ok); + } + + public void Reset() + { + AllSubjects = new List(); + LastSubject = Optional.None; + } +} \ No newline at end of file diff --git a/src/AncillaryInfrastructure.IntegrationTests/Stubs/StubUsageReportingService.cs b/src/AncillaryInfrastructure.IntegrationTests/Stubs/StubUsageDeliveryService.cs similarity index 80% rename from src/AncillaryInfrastructure.IntegrationTests/Stubs/StubUsageReportingService.cs rename to src/AncillaryInfrastructure.IntegrationTests/Stubs/StubUsageDeliveryService.cs index 9a393b0c..bd362efb 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/Stubs/StubUsageReportingService.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/Stubs/StubUsageDeliveryService.cs @@ -4,13 +4,13 @@ namespace AncillaryInfrastructure.IntegrationTests.Stubs; -public sealed class StubUsageReportingService : IUsageReportingService +public sealed class StubUsageDeliveryService : IUsageDeliveryService { public List AllEventNames { get; private set; } = new(); public Optional LastEventName { get; private set; } = Optional.None; - public Task> TrackAsync(ICallerContext context, string forId, string eventName, + public Task> DeliverAsync(ICallerContext context, string forId, string eventName, Dictionary? additional = null, CancellationToken cancellationToken = default) { diff --git a/src/AncillaryInfrastructure.IntegrationTests/UsagesApiSpec.cs b/src/AncillaryInfrastructure.IntegrationTests/UsagesApiSpec.cs index 42290c4a..40642736 100644 --- a/src/AncillaryInfrastructure.IntegrationTests/UsagesApiSpec.cs +++ b/src/AncillaryInfrastructure.IntegrationTests/UsagesApiSpec.cs @@ -19,15 +19,15 @@ namespace AncillaryInfrastructure.IntegrationTests; [Collection("API")] public class UsagesApiSpec : WebApiSpec { - private readonly IUsageMessageQueueRepository _usageMessageQueue; - private readonly StubUsageReportingService _usageReportingService; + private readonly StubUsageDeliveryService _usageDeliveryService; + private readonly IUsageMessageQueue _usageMessageQueue; public UsagesApiSpec(WebApiSetup setup) : base(setup, OverrideDependencies) { EmptyAllRepositories(setup); - _usageReportingService = setup.GetRequiredService().As(); - _usageReportingService.Reset(); - _usageMessageQueue = setup.GetRequiredService(); + _usageDeliveryService = setup.GetRequiredService().As(); + _usageDeliveryService.Reset(); + _usageMessageQueue = setup.GetRequiredService(); _usageMessageQueue.DestroyAllAsync(CancellationToken.None).GetAwaiter().GetResult(); } @@ -38,17 +38,17 @@ public async Task WhenDeliverUsage_ThenDelivers() { Message = new UsageMessage { + MessageId = "amessageid", CallId = "acallid", CallerId = "acallerid", EventName = "aneventname", - ForId = "aforid", - MessageId = "amessageid" + ForId = "aforid" }.ToJson()! }; var result = await Api.PostAsync(request, req => req.SetHMACAuth(request, "asecret")); result.Content.Value.IsDelivered.Should().BeTrue(); - _usageReportingService.LastEventName.Should().Be("aneventname"); + _usageDeliveryService.LastEventName.Should().Be("aneventname"); } #if TESTINGONLY @@ -58,7 +58,7 @@ public async Task WhenDrainAllUsagesAndNone_ThenDoesNotDrainAny() var request = new DrainAllUsagesRequest(); await Api.PostAsync(request, req => req.SetHMACAuth(request, "asecret")); - _usageReportingService.LastEventName.Should().BeNone(); + _usageDeliveryService.LastEventName.Should().BeNone(); } #endif @@ -89,13 +89,13 @@ public async Task WhenDrainAllUsagesAndSome_ThenDrains() var request = new DrainAllUsagesRequest(); await Api.PostAsync(request, req => req.SetHMACAuth(request, "asecret")); - _usageReportingService.AllEventNames.Count.Should().Be(3); - _usageReportingService.AllEventNames.Should().ContainInOrder("aneventname1", "aneventname2", "aneventname3"); + _usageDeliveryService.AllEventNames.Count.Should().Be(3); + _usageDeliveryService.AllEventNames.Should().ContainInOrder("aneventname1", "aneventname2", "aneventname3"); } #endif private static void OverrideDependencies(IServiceCollection services) { - services.AddSingleton(); + services.AddSingleton(); } } \ No newline at end of file diff --git a/src/AncillaryInfrastructure.UnitTests/Api/Emails/DeliverUsageRequestValidatorSpec.cs b/src/AncillaryInfrastructure.UnitTests/Api/Emails/DeliverUsageRequestValidatorSpec.cs new file mode 100644 index 00000000..86c79f19 --- /dev/null +++ b/src/AncillaryInfrastructure.UnitTests/Api/Emails/DeliverUsageRequestValidatorSpec.cs @@ -0,0 +1,40 @@ +using AncillaryInfrastructure.Api.Emails; +using FluentAssertions; +using FluentValidation; +using Infrastructure.Web.Api.Operations.Shared.Ancillary; +using UnitTesting.Common.Validation; +using Xunit; + +namespace AncillaryInfrastructure.UnitTests.Api.Emails; + +[Trait("Category", "Unit")] +public class DeliverEmailRequestValidatorSpec +{ + private readonly DeliverEmailRequest _dto; + private readonly DeliverEmailRequestValidator _validator; + + public DeliverEmailRequestValidatorSpec() + { + _validator = new DeliverEmailRequestValidator(); + _dto = new DeliverEmailRequest + { + Message = "amessage" + }; + } + + [Fact] + public void WhenAllProperties_ThenSucceeds() + { + _validator.ValidateAndThrow(_dto); + } + + [Fact] + public void WhenMessageIsNull_ThenThrows() + { + _dto.Message = null!; + + _validator.Invoking(x => x.ValidateAndThrow(_dto)) + .Should().Throw() + .WithMessageLike(Resources.AnyQueueMessageValidator_InvalidMessage); + } +} \ No newline at end of file diff --git a/src/AncillaryInfrastructure/AncillaryModule.cs b/src/AncillaryInfrastructure/AncillaryModule.cs index 473298a7..e80347db 100644 --- a/src/AncillaryInfrastructure/AncillaryModule.cs +++ b/src/AncillaryInfrastructure/AncillaryModule.cs @@ -39,12 +39,12 @@ public Action RegisterServices { services.RegisterUnshared(); services.RegisterUnshared(); - services.RegisterUnshared(c => - new UsageMessageQueueRepository(c.Resolve(), c.ResolveForPlatform())); + services.RegisterUnshared(c => + new UsageMessageQueue(c.Resolve(), c.ResolveForPlatform())); services.RegisterUnshared(c => new AuditMessageQueueRepository(c.Resolve(), c.ResolveForPlatform())); - services.RegisterUnshared(c => - new EmailMessageQueueRepository(c.Resolve(), c.ResolveForPlatform())); + services.RegisterUnshared(c => + new EmailMessageQueue(c.Resolve(), c.ResolveForPlatform())); services.RegisterUnshared(c => new AuditRepository(c.ResolveForUnshared(), c.ResolveForUnshared(), c.ResolveForUnshared>(), @@ -53,7 +53,8 @@ public Action RegisterServices c => new AuditProjection(c.ResolveForUnshared(), c.ResolveForUnshared(), c.ResolveForPlatform())); - services.RegisterUnshared(); + services.RegisterUnshared(); + services.RegisterUnshared(); }; } } diff --git a/src/AncillaryInfrastructure/Api/Emails/DeliverUsageRequestValidator.cs b/src/AncillaryInfrastructure/Api/Emails/DeliverUsageRequestValidator.cs new file mode 100644 index 00000000..c40652b0 --- /dev/null +++ b/src/AncillaryInfrastructure/Api/Emails/DeliverUsageRequestValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; +using Infrastructure.Web.Api.Operations.Shared.Ancillary; +using JetBrains.Annotations; + +namespace AncillaryInfrastructure.Api.Emails; + +[UsedImplicitly] +public class DeliverEmailRequestValidator : AbstractValidator +{ + public DeliverEmailRequestValidator() + { + RuleFor(req => req.Message) + .NotEmpty() + .WithMessage(Resources.AnyQueueMessageValidator_InvalidMessage); + } +} \ No newline at end of file diff --git a/src/AncillaryInfrastructure/Api/Emails/EmailsApi.cs b/src/AncillaryInfrastructure/Api/Emails/EmailsApi.cs new file mode 100644 index 00000000..2c474eb1 --- /dev/null +++ b/src/AncillaryInfrastructure/Api/Emails/EmailsApi.cs @@ -0,0 +1,41 @@ +using AncillaryApplication; +using Common; +using Infrastructure.Interfaces; +using Infrastructure.Web.Api.Common.Extensions; +using Infrastructure.Web.Api.Interfaces; +using Infrastructure.Web.Api.Operations.Shared.Ancillary; + +namespace AncillaryInfrastructure.Api.Emails; + +public sealed class EmailsApi : IWebApiService +{ + private readonly IAncillaryApplication _ancillaryApplication; + private readonly ICallerContextFactory _contextFactory; + + public EmailsApi(ICallerContextFactory contextFactory, IAncillaryApplication ancillaryApplication) + { + _contextFactory = contextFactory; + _ancillaryApplication = ancillaryApplication; + } + + public async Task> Deliver(DeliverEmailRequest request, + CancellationToken cancellationToken) + { + var delivered = + await _ancillaryApplication.DeliverEmailAsync(_contextFactory.Create(), request.Message, cancellationToken); + + return () => delivered.HandleApplicationResult(_ => + new PostResult(new DeliverMessageResponse { IsDelivered = true })); + } + +#if TESTINGONLY + public async Task DrainAll(DrainAllEmailsRequest request, + CancellationToken cancellationToken) + { + var result = await _ancillaryApplication.DrainAllEmailsAsync(_contextFactory.Create(), cancellationToken); + + return () => result.Match(() => new Result(), + error => new Result(error)); + } +#endif +} \ No newline at end of file diff --git a/src/AncillaryInfrastructure/ApplicationServices/NullEmailDeliveryService.cs b/src/AncillaryInfrastructure/ApplicationServices/NullEmailDeliveryService.cs new file mode 100644 index 00000000..0677a6c8 --- /dev/null +++ b/src/AncillaryInfrastructure/ApplicationServices/NullEmailDeliveryService.cs @@ -0,0 +1,39 @@ +using Application.Common; +using Application.Interfaces; +using Application.Persistence.Shared; +using Common; +using Common.Extensions; +using Task = System.Threading.Tasks.Task; + +namespace AncillaryInfrastructure.ApplicationServices; + +/// +/// Provides a that does nothing +/// +public class NullEmailDeliveryService : IEmailDeliveryService +{ + private readonly IRecorder _recorder; + + public NullEmailDeliveryService(IRecorder recorder) + { + _recorder = recorder; + } + + public Task> DeliverAsync(ICallerContext context, string subject, string htmlBody, + string toEmailAddress, string? toDisplayName, + string fromEmailAddress, string? fromDisplayName, CancellationToken cancellationToken = default) + { + _recorder.TraceInformation(context.ToCall(), + $"{nameof(NullUsageDeliveryService)} delivers email event {{Event}} for {{For}} with properties: {{Properties}}", + subject, toEmailAddress, new + { + To = toEmailAddress, + ToDisplayName = toDisplayName, + From = fromEmailAddress, + FromDisplayName = fromDisplayName, + Body = htmlBody + }.ToJson()!); + + return Task.FromResult(Result.Ok); + } +} \ No newline at end of file diff --git a/src/AncillaryInfrastructure/ApplicationServices/NullUsageReportingService.cs b/src/AncillaryInfrastructure/ApplicationServices/NullUsageDeliveryService.cs similarity index 63% rename from src/AncillaryInfrastructure/ApplicationServices/NullUsageReportingService.cs rename to src/AncillaryInfrastructure/ApplicationServices/NullUsageDeliveryService.cs index cf94223f..6cce0fa8 100644 --- a/src/AncillaryInfrastructure/ApplicationServices/NullUsageReportingService.cs +++ b/src/AncillaryInfrastructure/ApplicationServices/NullUsageDeliveryService.cs @@ -8,18 +8,18 @@ namespace AncillaryInfrastructure.ApplicationServices; /// -/// Provides a that does nothing +/// Provides a that does nothing /// -public class NullUsageReportingService : IUsageReportingService +public class NullUsageDeliveryService : IUsageDeliveryService { private readonly IRecorder _recorder; - public NullUsageReportingService(IRecorder recorder) + public NullUsageDeliveryService(IRecorder recorder) { _recorder = recorder; } - public Task> TrackAsync(ICallerContext context, string forId, string eventName, + public Task> DeliverAsync(ICallerContext context, string forId, string eventName, Dictionary? additional = null, CancellationToken cancellationToken = default) { @@ -27,7 +27,7 @@ public Task> TrackAsync(ICallerContext context, string forId, stri ? additional.ToJson()! : "none"; _recorder.TraceInformation(context.ToCall(), - $"{nameof(NullUsageReportingService)} tracks usage event {{Event}} for {{For}} with properties: {{Properties}}", + $"{nameof(NullUsageDeliveryService)} delivers usage event {{Event}} for {{For}} with properties: {{Properties}}", eventName, forId, properties); return Task.FromResult(Result.Ok); diff --git a/src/ApiHost1/ApiHostModule.cs b/src/ApiHost1/ApiHostModule.cs index 770cbdb5..a05776a1 100644 --- a/src/ApiHost1/ApiHostModule.cs +++ b/src/ApiHost1/ApiHostModule.cs @@ -29,13 +29,13 @@ public Action RegisterServices { return (_, services) => { - services.RegisterUnshared(c => - new EmailMessageQueueRepository(c.Resolve(), c.ResolveForPlatform())); + services.RegisterUnshared(c => + new EmailMessageQueue(c.Resolve(), c.ResolveForPlatform())); services.RegisterUnshared(); services.RegisterUnshared(); services.RegisterUnshared(); - services.RegisterUnshared(); + services.RegisterUnshared(); }; } } diff --git a/src/Application.Persistence.Shared/IEmailDeliveryService.cs b/src/Application.Persistence.Shared/IEmailDeliveryService.cs new file mode 100644 index 00000000..4492aba8 --- /dev/null +++ b/src/Application.Persistence.Shared/IEmailDeliveryService.cs @@ -0,0 +1,17 @@ +using Application.Interfaces; +using Common; + +namespace Application.Persistence.Shared; + +/// +/// Defines a service to which we can deliver email events +/// +public interface IEmailDeliveryService +{ + /// + /// Delivers the email + /// + Task> DeliverAsync(ICallerContext context, string subject, string htmlBody, string toEmailAddress, + string? toDisplayName, + string fromEmailAddress, string? fromDisplayName, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/src/Application.Persistence.Shared/IUsageMessageQueueRepository.cs b/src/Application.Persistence.Shared/IEmailMessageQueue.cs similarity index 69% rename from src/Application.Persistence.Shared/IUsageMessageQueueRepository.cs rename to src/Application.Persistence.Shared/IEmailMessageQueue.cs index 59652482..22f19629 100644 --- a/src/Application.Persistence.Shared/IUsageMessageQueueRepository.cs +++ b/src/Application.Persistence.Shared/IEmailMessageQueue.cs @@ -4,7 +4,7 @@ namespace Application.Persistence.Shared; -public interface IUsageMessageQueueRepository : IMessageQueueStore, IApplicationRepository +public interface IEmailMessageQueue : IMessageQueueStore, IApplicationRepository { new Task> DestroyAllAsync(CancellationToken cancellationToken); } \ No newline at end of file diff --git a/src/Application.Persistence.Shared/IUsageReportingService.cs b/src/Application.Persistence.Shared/IUsageDeliveryService.cs similarity index 52% rename from src/Application.Persistence.Shared/IUsageReportingService.cs rename to src/Application.Persistence.Shared/IUsageDeliveryService.cs index 6ec21026..cef428f5 100644 --- a/src/Application.Persistence.Shared/IUsageReportingService.cs +++ b/src/Application.Persistence.Shared/IUsageDeliveryService.cs @@ -4,13 +4,13 @@ namespace Application.Persistence.Shared; /// -/// Defines a service to which we can report usages events +/// Defines a service to which we can deliver usages events /// -public interface IUsageReportingService +public interface IUsageDeliveryService { /// - /// Tracks the usage event + /// Delivers the usage event /// - Task> TrackAsync(ICallerContext context, string forId, string eventName, + Task> DeliverAsync(ICallerContext context, string forId, string eventName, Dictionary? additional = null, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/Application.Persistence.Shared/IEmailMessageQueueRepository.cs b/src/Application.Persistence.Shared/IUsageMessageQueue.cs similarity index 69% rename from src/Application.Persistence.Shared/IEmailMessageQueueRepository.cs rename to src/Application.Persistence.Shared/IUsageMessageQueue.cs index ba8f7d88..9ff896bb 100644 --- a/src/Application.Persistence.Shared/IEmailMessageQueueRepository.cs +++ b/src/Application.Persistence.Shared/IUsageMessageQueue.cs @@ -4,7 +4,7 @@ namespace Application.Persistence.Shared; -public interface IEmailMessageQueueRepository : IMessageQueueStore, IApplicationRepository +public interface IUsageMessageQueue : IMessageQueueStore, IApplicationRepository { new Task> DestroyAllAsync(CancellationToken cancellationToken); } \ No newline at end of file diff --git a/src/Application.Persistence.Shared/ReadModels/EmailMessage.cs b/src/Application.Persistence.Shared/ReadModels/EmailMessage.cs index 239209fa..a89d5659 100644 --- a/src/Application.Persistence.Shared/ReadModels/EmailMessage.cs +++ b/src/Application.Persistence.Shared/ReadModels/EmailMessage.cs @@ -12,7 +12,7 @@ public class QueuedEmailHtmlMessage { public string? FromDisplayName { get; set; } - public string? FromEmail { get; set; } + public string? FromEmailAddress { get; set; } public string? HtmlBody { get; set; } @@ -20,5 +20,5 @@ public class QueuedEmailHtmlMessage public string? ToDisplayName { get; set; } - public string? ToEmail { get; set; } + public string? ToEmailAddress { get; set; } } \ No newline at end of file diff --git a/src/Application.Services.Shared/IEmailSendingService.cs b/src/Application.Services.Shared/IEmailSchedulingService.cs similarity index 66% rename from src/Application.Services.Shared/IEmailSendingService.cs rename to src/Application.Services.Shared/IEmailSchedulingService.cs index 62f1bfa1..424b75b8 100644 --- a/src/Application.Services.Shared/IEmailSendingService.cs +++ b/src/Application.Services.Shared/IEmailSchedulingService.cs @@ -4,11 +4,12 @@ namespace Application.Services.Shared; /// -/// Defines an asynchronous email sending service, that will queue messages for asynchronous and deferred delivery +/// Defines an email scheduling service, that will schedule messages for asynchronous and deferred delivery /// -public interface IEmailSendingService +public interface IEmailSchedulingService { - Task> SendHtmlEmail(ICallerContext caller, HtmlEmail htmlEmail, CancellationToken cancellationToken); + Task> ScheduleHtmlEmail(ICallerContext caller, HtmlEmail htmlEmail, + CancellationToken cancellationToken); } /// diff --git a/src/AzureFunctions.Api.WorkerHost/Functions/DeliverEmail.cs b/src/AzureFunctions.Api.WorkerHost/Functions/DeliverEmail.cs new file mode 100644 index 00000000..36265e8a --- /dev/null +++ b/src/AzureFunctions.Api.WorkerHost/Functions/DeliverEmail.cs @@ -0,0 +1,23 @@ +using Application.Persistence.Shared.ReadModels; +using Infrastructure.Workers.Api; +using Infrastructure.Workers.Api.Workers; +using Microsoft.Azure.Functions.Worker; + +namespace AzureFunctions.Api.WorkerHost.Functions; + +public sealed class DeliverEmail +{ + private readonly IQueueMonitoringApiRelayWorker _worker; + + public DeliverEmail(IQueueMonitoringApiRelayWorker worker) + { + _worker = worker; + } + + [Function(nameof(DeliverEmail))] + public Task Run([QueueTrigger(DeliverEmailRelayWorker.QueueName)] EmailMessage message, + FunctionContext context) + { + return _worker.RelayMessageOrThrowAsync(message, context.CancellationToken); + } +} \ No newline at end of file diff --git a/src/AzureFunctions.Api.WorkerHost/HostExtensions.cs b/src/AzureFunctions.Api.WorkerHost/HostExtensions.cs index dcf5b17f..b648033c 100644 --- a/src/AzureFunctions.Api.WorkerHost/HostExtensions.cs +++ b/src/AzureFunctions.Api.WorkerHost/HostExtensions.cs @@ -48,5 +48,6 @@ public static void AddDependencies(this IServiceCollection services, HostBuilder c.Resolve().GetAncillaryApiHostBaseUrl())); services.AddSingleton, DeliverUsageRelayWorker>(); services.AddSingleton, DeliverAuditRelayWorker>(); + services.AddSingleton, DeliverEmailRelayWorker>(); } } \ No newline at end of file diff --git a/src/Infrastructure.Common/Recording/QueuedUsageReporter.cs b/src/Infrastructure.Common/Recording/QueuedUsageReporter.cs index 7a8e42d0..5f49e7e8 100644 --- a/src/Infrastructure.Common/Recording/QueuedUsageReporter.cs +++ b/src/Infrastructure.Common/Recording/QueuedUsageReporter.cs @@ -26,11 +26,11 @@ namespace Infrastructure.Common.Recording; /// public class QueuedUsageReporter : IUsageReporter { - private readonly IUsageMessageQueueRepository _repository; + private readonly IUsageMessageQueue _queue; // ReSharper disable once UnusedParameter.Local public QueuedUsageReporter(IDependencyContainer container, ISettings settings) - : this(new UsageMessageQueueRepository(NullRecorder.Instance, + : this(new UsageMessageQueue(NullRecorder.Instance, #if !TESTINGONLY #if HOSTEDONAZURE AzureStorageAccountQueueStore.Create(NullRecorder.Instance, settings) @@ -44,9 +44,9 @@ public QueuedUsageReporter(IDependencyContainer container, ISettings settings) { } - internal QueuedUsageReporter(IUsageMessageQueueRepository repository) + internal QueuedUsageReporter(IUsageMessageQueue queue) { - _repository = repository; + _queue = queue; } public void Track(ICallContext? context, string forId, string eventName, @@ -70,6 +70,6 @@ public void Track(ICallContext? context, string forId, string eventName, : string.Empty) }; - _repository.PushAsync(call, message, CancellationToken.None).GetAwaiter().GetResult(); + _queue.PushAsync(call, message, CancellationToken.None).GetAwaiter().GetResult(); } } \ No newline at end of file diff --git a/src/Infrastructure.Persistence.Shared/ApplicationServices/EmailMessageQueueRepository.cs b/src/Infrastructure.Persistence.Shared/ApplicationServices/EmailMessageQueue.cs similarity index 90% rename from src/Infrastructure.Persistence.Shared/ApplicationServices/EmailMessageQueueRepository.cs rename to src/Infrastructure.Persistence.Shared/ApplicationServices/EmailMessageQueue.cs index 6201185d..063b90db 100644 --- a/src/Infrastructure.Persistence.Shared/ApplicationServices/EmailMessageQueueRepository.cs +++ b/src/Infrastructure.Persistence.Shared/ApplicationServices/EmailMessageQueue.cs @@ -7,11 +7,11 @@ namespace Infrastructure.Persistence.Shared.ApplicationServices; -public class EmailMessageQueueRepository : IEmailMessageQueueRepository +public class EmailMessageQueue : IEmailMessageQueue { private readonly MessageQueueStore _messageQueue; - public EmailMessageQueueRepository(IRecorder recorder, IQueueStore store) + public EmailMessageQueue(IRecorder recorder, IQueueStore store) { _messageQueue = new MessageQueueStore(recorder, store); } diff --git a/src/Infrastructure.Persistence.Shared/ApplicationServices/UsageMessageQueueRepository.cs b/src/Infrastructure.Persistence.Shared/ApplicationServices/UsageMessageQueue.cs similarity index 90% rename from src/Infrastructure.Persistence.Shared/ApplicationServices/UsageMessageQueueRepository.cs rename to src/Infrastructure.Persistence.Shared/ApplicationServices/UsageMessageQueue.cs index af80b690..7dd246a2 100644 --- a/src/Infrastructure.Persistence.Shared/ApplicationServices/UsageMessageQueueRepository.cs +++ b/src/Infrastructure.Persistence.Shared/ApplicationServices/UsageMessageQueue.cs @@ -7,11 +7,11 @@ namespace Infrastructure.Persistence.Shared.ApplicationServices; -public class UsageMessageQueueRepository : IUsageMessageQueueRepository +public class UsageMessageQueue : IUsageMessageQueue { private readonly MessageQueueStore _messageQueue; - public UsageMessageQueueRepository(IRecorder recorder, IQueueStore store) + public UsageMessageQueue(IRecorder recorder, IQueueStore store) { _messageQueue = new MessageQueueStore(recorder, store); } diff --git a/src/Infrastructure.Shared/ApplicationServices/EmailNotificationsService.cs b/src/Infrastructure.Shared/ApplicationServices/EmailNotificationsService.cs index d3e505d1..fbe48c64 100644 --- a/src/Infrastructure.Shared/ApplicationServices/EmailNotificationsService.cs +++ b/src/Infrastructure.Shared/ApplicationServices/EmailNotificationsService.cs @@ -9,14 +9,14 @@ namespace Infrastructure.Shared.ApplicationServices; /// /// Provides a that delivers notifications via asynchronous email delivery using -/// +/// /// public class EmailNotificationsService : INotificationsService { public const string ProductNameSettingName = "ApplicationServices:Notifications:SenderProductName"; public const string SenderDisplayNameSettingName = "ApplicationServices:Notifications:SenderDisplayName"; public const string SenderEmailAddressSettingName = "ApplicationServices:Notifications:SenderEmailAddress"; - private readonly IEmailSendingService _emailSendingService; + private readonly IEmailSchedulingService _emailSchedulingService; private readonly IHostSettings _hostSettings; private readonly string _productName; private readonly string _senderEmailAddress; @@ -24,11 +24,11 @@ public class EmailNotificationsService : INotificationsService private readonly IWebsiteUiService _websiteUiService; public EmailNotificationsService(IConfigurationSettings settings, IHostSettings hostSettings, - IWebsiteUiService websiteUiService, IEmailSendingService emailSendingService) + IWebsiteUiService websiteUiService, IEmailSchedulingService emailSchedulingService) { _hostSettings = hostSettings; _websiteUiService = websiteUiService; - _emailSendingService = emailSendingService; + _emailSchedulingService = emailSchedulingService; _productName = settings.Platform.GetString(ProductNameSettingName, nameof(EmailNotificationsService)); _senderEmailAddress = settings.Platform.GetString(SenderEmailAddressSettingName, nameof(EmailNotificationsService)); @@ -48,7 +48,7 @@ public async Task> NotifyPasswordRegistrationConfirmationAsync(ICa $"" + $"

    This is an automated email from the support team at {_productName}

    "; - return await _emailSendingService.SendHtmlEmail(caller, new HtmlEmail + return await _emailSchedulingService.ScheduleHtmlEmail(caller, new HtmlEmail { Subject = $"Welcome to {_productName}", Body = htmlBody, diff --git a/src/Infrastructure.Shared/ApplicationServices/EmailSendingService.cs b/src/Infrastructure.Shared/ApplicationServices/QueuingEmailSchedulingService.cs similarity index 63% rename from src/Infrastructure.Shared/ApplicationServices/EmailSendingService.cs rename to src/Infrastructure.Shared/ApplicationServices/QueuingEmailSchedulingService.cs index e74309c4..7049b8e2 100644 --- a/src/Infrastructure.Shared/ApplicationServices/EmailSendingService.cs +++ b/src/Infrastructure.Shared/ApplicationServices/QueuingEmailSchedulingService.cs @@ -8,31 +8,31 @@ namespace Infrastructure.Shared.ApplicationServices; /// -/// Provides a queueing service for asynchronous delivery of emails +/// Provides an queue scheduling service, that will schedule messages for asynchronous and deferred delivery /// -public class EmailSendingService : IEmailSendingService +public class QueuingEmailSchedulingService : IEmailSchedulingService { private readonly IRecorder _recorder; - private readonly IEmailMessageQueueRepository _repository; + private readonly IEmailMessageQueue _queue; - public EmailSendingService(IRecorder recorder, IEmailMessageQueueRepository repository) + public QueuingEmailSchedulingService(IRecorder recorder, IEmailMessageQueue queue) { _recorder = recorder; - _repository = repository; + _queue = queue; } - public async Task> SendHtmlEmail(ICallerContext caller, HtmlEmail htmlEmail, + public async Task> ScheduleHtmlEmail(ICallerContext caller, HtmlEmail htmlEmail, CancellationToken cancellationToken) { - var queued = await _repository.PushAsync(caller.ToCall(), new EmailMessage + var queued = await _queue.PushAsync(caller.ToCall(), new EmailMessage { Html = new QueuedEmailHtmlMessage { Subject = htmlEmail.Subject, - FromEmail = htmlEmail.FromEmailAddress, + FromEmailAddress = htmlEmail.FromEmailAddress, FromDisplayName = htmlEmail.FromDisplayName, HtmlBody = htmlEmail.Body, - ToEmail = htmlEmail.ToEmailAddress, + ToEmailAddress = htmlEmail.ToEmailAddress, ToDisplayName = htmlEmail.ToDisplayName } }, cancellationToken); diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DeliverEmailRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DeliverEmailRequest.cs new file mode 100644 index 00000000..a8b66854 --- /dev/null +++ b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DeliverEmailRequest.cs @@ -0,0 +1,9 @@ +using Infrastructure.Web.Api.Interfaces; + +namespace Infrastructure.Web.Api.Operations.Shared.Ancillary; + +[Route("/emails/deliver", ServiceOperation.Post, AccessType.HMAC)] +public class DeliverEmailRequest : UnTenantedRequest +{ + public required string Message { get; set; } +} \ No newline at end of file diff --git a/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DrainAllEmailsRequest.cs b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DrainAllEmailsRequest.cs new file mode 100644 index 00000000..0274bfc8 --- /dev/null +++ b/src/Infrastructure.Web.Api.Operations.Shared/Ancillary/DrainAllEmailsRequest.cs @@ -0,0 +1,10 @@ +#if TESTINGONLY +using Infrastructure.Web.Api.Interfaces; + +namespace Infrastructure.Web.Api.Operations.Shared.Ancillary; + +[Route("/emails/drain", ServiceOperation.Post, AccessType.HMAC, true)] +public class DrainAllEmailsRequest : UnTenantedEmptyRequest +{ +} +#endif \ No newline at end of file diff --git a/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs b/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs index 86195cae..7fa9557e 100644 --- a/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs +++ b/src/Infrastructure.Web.Hosting.Common/Extensions/HostExtensions.cs @@ -59,8 +59,8 @@ public static class HostExtensions { #if TESTINGONLY { "audits", new DrainAllAuditsRequest() }, - { "usages", new DrainAllUsagesRequest() } - // { "emails", new DrainAllEmailsRequest() }, + { "usages", new DrainAllUsagesRequest() }, + { "emails", new DrainAllEmailsRequest() }, // { "events", new DrainAllEventsRequest() }, #endif }; diff --git a/src/Infrastructure.Worker.Api.IntegrationTests/AWSLambdas/AWSLambdasApiSpec.cs b/src/Infrastructure.Worker.Api.IntegrationTests/AWSLambdas/AWSLambdasApiSpec.cs index 309f9586..0f386fa1 100644 --- a/src/Infrastructure.Worker.Api.IntegrationTests/AWSLambdas/AWSLambdasApiSpec.cs +++ b/src/Infrastructure.Worker.Api.IntegrationTests/AWSLambdas/AWSLambdasApiSpec.cs @@ -1,15 +1,5 @@ -using Application.Persistence.Shared.ReadModels; -using Common.Extensions; -using FluentAssertions; -using Infrastructure.Web.Api.Operations.Shared.Ancillary; -using Infrastructure.Web.Interfaces.Clients; -using Infrastructure.Worker.Api.IntegrationTests.Stubs; -using Infrastructure.Workers.Api.Workers; using JetBrains.Annotations; -using Microsoft.Extensions.DependencyInjection; -using UnitTesting.Common; using Xunit; -using Task = System.Threading.Tasks.Task; namespace Infrastructure.Worker.Api.IntegrationTests.AWSLambdas; @@ -25,102 +15,21 @@ public DeliverUsageSpec(AWSLambdaHostSetup setup) : base(setup) } } - // public class DeliverUsageSpec : ApiWorkerSpec - // { - // private readonly StubServiceClient _serviceClient; - // - // public DeliverUsageSpec(AWSLambdaHostSetup setup) : base(setup, OverrideDependencies) - // { - // setup.QueueStore.DestroyAllAsync(DeliverUsageRelayWorker.QueueName, CancellationToken.None).GetAwaiter() - // .GetResult(); - // _serviceClient = setup.GetRequiredService().As(); - // _serviceClient.Reset(); - // } - // - // [Fact] - // public async Task WhenMessageQueuedContainingInvalidContent_ThenApiNotCalled() - // { - // await Setup.QueueStore.PushAsync(DeliverUsageRelayWorker.QueueName, "aninvalidusagemessage", - // CancellationToken.None); - // - // Setup.WaitForQueueProcessingToComplete(); - // - // (await Setup.QueueStore.CountAsync(DeliverUsageRelayWorker.QueueName, CancellationToken.None)) - // .Should().Be(0); - // _serviceClient.LastPostedMessage.Should().BeNone(); - // } - // - // [Fact] - // public async Task WhenMessageQueuedContaining_ThenApiCalled() - // { - // var message = new UsageMessage - // { - // ForId = "aforid", - // EventName = "aneventname" - // }.ToJson()!; - // await Setup.QueueStore.PushAsync(DeliverUsageRelayWorker.QueueName, message, CancellationToken.None); - // - // Setup.WaitForQueueProcessingToComplete(); - // - // (await Setup.QueueStore.CountAsync(DeliverUsageRelayWorker.QueueName, CancellationToken.None)) - // .Should().Be(0); - // _serviceClient.LastPostedMessage.Value.Should() - // .BeEquivalentTo(new DeliverUsageRequest { Message = message }); - // } - // - // private static void OverrideDependencies(IServiceCollection services) - // { - // services.AddSingleton(); - // } - // } - [Trait("Category", "Integration.External")] [Collection("AWSLambdas")] - public class DeliverAuditSpec : ApiWorkerSpec + public class DeliverAuditSpec : DeliverAuditSpecBase { - private readonly StubServiceClient _serviceClient; - - public DeliverAuditSpec(AWSLambdaHostSetup setup) : base(setup, OverrideDependencies) - { - setup.QueueStore.DestroyAllAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None).GetAwaiter() - .GetResult(); - _serviceClient = setup.GetRequiredService().As(); - _serviceClient.Reset(); - } - - [Fact] - public async Task WhenMessageQueuedContainingInvalidContent_ThenApiNotCalled() - { - await Setup.QueueStore.PushAsync(DeliverAuditRelayWorker.QueueName, "aninvalidusagemessage", - CancellationToken.None); - - Setup.WaitForQueueProcessingToComplete(); - - (await Setup.QueueStore.CountAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None)) - .Should().Be(0); - _serviceClient.LastPostedMessage.Should().BeNone(); - } - - [Fact] - public async Task WhenMessageQueuedContaining_ThenApiCalled() + public DeliverAuditSpec(AWSLambdaHostSetup setup) : base(setup) { - var message = new AuditMessage - { - AuditCode = "anauditcode" - }.ToJson()!; - await Setup.QueueStore.PushAsync(DeliverAuditRelayWorker.QueueName, message, CancellationToken.None); - - Setup.WaitForQueueProcessingToComplete(); - - (await Setup.QueueStore.CountAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None)) - .Should().Be(0); - _serviceClient.LastPostedMessage.Value.Should() - .BeEquivalentTo(new DeliverAuditRequest { Message = message }); } + } - private static void OverrideDependencies(IServiceCollection services) + [Trait("Category", "Integration.External")] + [Collection("AWSLambdas")] + public class DeliverEmailSpec : DeliverEmailSpecBase + { + public DeliverEmailSpec(AWSLambdaHostSetup setup) : base(setup) { - services.AddSingleton(); } } } \ No newline at end of file diff --git a/src/Infrastructure.Worker.Api.IntegrationTests/AzureFunctions/AzureFunctionsApiSpec.cs b/src/Infrastructure.Worker.Api.IntegrationTests/AzureFunctions/AzureFunctionsApiSpec.cs index 8253a3d9..51fa1572 100644 --- a/src/Infrastructure.Worker.Api.IntegrationTests/AzureFunctions/AzureFunctionsApiSpec.cs +++ b/src/Infrastructure.Worker.Api.IntegrationTests/AzureFunctions/AzureFunctionsApiSpec.cs @@ -1,15 +1,5 @@ -using Application.Persistence.Shared.ReadModels; -using Common.Extensions; -using FluentAssertions; -using Infrastructure.Web.Api.Operations.Shared.Ancillary; -using Infrastructure.Web.Interfaces.Clients; -using Infrastructure.Worker.Api.IntegrationTests.Stubs; -using Infrastructure.Workers.Api.Workers; using JetBrains.Annotations; -using Microsoft.Extensions.DependencyInjection; -using UnitTesting.Common; using Xunit; -using Task = System.Threading.Tasks.Task; namespace Infrastructure.Worker.Api.IntegrationTests.AzureFunctions; @@ -18,103 +8,28 @@ public class AzureFunctionsApiSpec { [Trait("Category", "Integration.External")] [Collection("AzureFunctions")] - public class DeliverUsageSpec : ApiWorkerSpec + public class DeliverUsageSpec : DeliverUsageSpecBase { - private readonly StubServiceClient _serviceClient; - - public DeliverUsageSpec(AzureFunctionHostSetup setup) : base(setup, OverrideDependencies) - { - setup.QueueStore.DestroyAllAsync(DeliverUsageRelayWorker.QueueName, CancellationToken.None).GetAwaiter() - .GetResult(); - _serviceClient = setup.GetRequiredService().As(); - _serviceClient.Reset(); - } - - [Fact] - public async Task WhenMessageQueuedContainingInvalidContent_ThenApiNotCalled() + public DeliverUsageSpec(AzureFunctionHostSetup setup) : base(setup) { - await Setup.QueueStore.PushAsync(DeliverUsageRelayWorker.QueueName, "aninvalidusagemessage", - CancellationToken.None); - - Setup.WaitForQueueProcessingToComplete(); - - (await Setup.QueueStore.CountAsync(DeliverUsageRelayWorker.QueueName, CancellationToken.None)) - .Should().Be(0); - _serviceClient.LastPostedMessage.Should().BeNone(); - } - - [Fact] - public async Task WhenMessageQueuedContaining_ThenApiCalled() - { - var message = new UsageMessage - { - ForId = "aforid", - EventName = "aneventname" - }.ToJson()!; - await Setup.QueueStore.PushAsync(DeliverUsageRelayWorker.QueueName, message, CancellationToken.None); - - Setup.WaitForQueueProcessingToComplete(); - - (await Setup.QueueStore.CountAsync(DeliverUsageRelayWorker.QueueName, CancellationToken.None)) - .Should().Be(0); - _serviceClient.LastPostedMessage.Value.Should() - .BeEquivalentTo(new DeliverUsageRequest { Message = message }); - } - - private static void OverrideDependencies(IServiceCollection services) - { - services.AddSingleton(); } } [Trait("Category", "Integration.External")] [Collection("AzureFunctions")] - public class DeliverAuditSpec : ApiWorkerSpec + public class DeliverAuditSpec : DeliverAuditSpecBase { - private readonly StubServiceClient _serviceClient; - - public DeliverAuditSpec(AzureFunctionHostSetup setup) : base(setup, OverrideDependencies) + public DeliverAuditSpec(AzureFunctionHostSetup setup) : base(setup) { - setup.QueueStore.DestroyAllAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None).GetAwaiter() - .GetResult(); - _serviceClient = setup.GetRequiredService().As(); - _serviceClient.Reset(); - } - - [Fact] - public async Task WhenMessageQueuedContainingInvalidContent_ThenApiNotCalled() - { - await Setup.QueueStore.PushAsync(DeliverAuditRelayWorker.QueueName, "aninvalidusagemessage", - CancellationToken.None); - - Setup.WaitForQueueProcessingToComplete(); - - (await Setup.QueueStore.CountAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None)) - .Should().Be(0); - _serviceClient.LastPostedMessage.Should().BeNone(); - } - - [Fact] - public async Task WhenMessageQueuedContaining_ThenApiCalled() - { - var message = new AuditMessage - { - TenantId = "atenantid", - AuditCode = "anauditcode" - }.ToJson()!; - await Setup.QueueStore.PushAsync(DeliverAuditRelayWorker.QueueName, message, CancellationToken.None); - - Setup.WaitForQueueProcessingToComplete(); - - (await Setup.QueueStore.CountAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None)) - .Should().Be(0); - _serviceClient.LastPostedMessage.Value.Should() - .BeEquivalentTo(new DeliverAuditRequest { Message = message }); } + } - private static void OverrideDependencies(IServiceCollection services) + [Trait("Category", "Integration.External")] + [Collection("AzureFunctions")] + public class DeliverEmailSpec : DeliverEmailSpecBase + { + public DeliverEmailSpec(AzureFunctionHostSetup setup) : base(setup) { - services.AddSingleton(); } } } \ No newline at end of file diff --git a/src/Infrastructure.Worker.Api.IntegrationTests/DeliverAuditSpecBase.cs b/src/Infrastructure.Worker.Api.IntegrationTests/DeliverAuditSpecBase.cs new file mode 100644 index 00000000..69c180e7 --- /dev/null +++ b/src/Infrastructure.Worker.Api.IntegrationTests/DeliverAuditSpecBase.cs @@ -0,0 +1,62 @@ +using Application.Persistence.Shared.ReadModels; +using Common.Extensions; +using FluentAssertions; +using Infrastructure.Web.Api.Operations.Shared.Ancillary; +using Infrastructure.Web.Interfaces.Clients; +using Infrastructure.Worker.Api.IntegrationTests.Stubs; +using Infrastructure.Workers.Api.Workers; +using Microsoft.Extensions.DependencyInjection; +using UnitTesting.Common; +using Xunit; + +namespace Infrastructure.Worker.Api.IntegrationTests; + +public abstract class DeliverAuditSpecBase : ApiWorkerSpec + where TSetup : class, IApiWorkerSpec +{ + private readonly StubServiceClient _serviceClient; + + protected DeliverAuditSpecBase(TSetup setup) : base(setup, OverrideDependencies) + { + setup.QueueStore.DestroyAllAsync(DeliverUsageRelayWorker.QueueName, CancellationToken.None).GetAwaiter() + .GetResult(); + _serviceClient = setup.GetRequiredService().As(); + _serviceClient.Reset(); + } + + [Fact] + public async Task WhenMessageQueuedContainingInvalidContent_ThenApiNotCalled() + { + await Setup.QueueStore.PushAsync(DeliverAuditRelayWorker.QueueName, "aninvalidusagemessage", + CancellationToken.None); + + Setup.WaitForQueueProcessingToComplete(); + + (await Setup.QueueStore.CountAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None)) + .Should().Be(0); + _serviceClient.LastPostedMessage.Should().BeNone(); + } + + [Fact] + public async Task WhenMessageQueuedContaining_ThenApiCalled() + { + var message = new AuditMessage + { + TenantId = "atenantid", + AuditCode = "anauditcode" + }.ToJson()!; + await Setup.QueueStore.PushAsync(DeliverAuditRelayWorker.QueueName, message, CancellationToken.None); + + Setup.WaitForQueueProcessingToComplete(); + + (await Setup.QueueStore.CountAsync(DeliverAuditRelayWorker.QueueName, CancellationToken.None)) + .Should().Be(0); + _serviceClient.LastPostedMessage.Value.Should() + .BeEquivalentTo(new DeliverAuditRequest { Message = message }); + } + + private static void OverrideDependencies(IServiceCollection services) + { + services.AddSingleton(); + } +} \ No newline at end of file diff --git a/src/Infrastructure.Worker.Api.IntegrationTests/DeliverEmailSpecBase.cs b/src/Infrastructure.Worker.Api.IntegrationTests/DeliverEmailSpecBase.cs new file mode 100644 index 00000000..cec14ad1 --- /dev/null +++ b/src/Infrastructure.Worker.Api.IntegrationTests/DeliverEmailSpecBase.cs @@ -0,0 +1,67 @@ +using Application.Persistence.Shared.ReadModels; +using FluentAssertions; +using Infrastructure.Web.Api.Operations.Shared.Ancillary; +using Infrastructure.Web.Interfaces.Clients; +using Infrastructure.Worker.Api.IntegrationTests.Stubs; +using Infrastructure.Workers.Api.Workers; +using Microsoft.Extensions.DependencyInjection; +using UnitTesting.Common; +using Xunit; +using StringExtensions = Common.Extensions.StringExtensions; + +namespace Infrastructure.Worker.Api.IntegrationTests; + +public abstract class DeliverEmailSpecBase : ApiWorkerSpec + where TSetup : class, IApiWorkerSpec +{ + private readonly StubServiceClient _serviceClient; + + protected DeliverEmailSpecBase(TSetup setup) : base(setup, OverrideDependencies) + { + setup.QueueStore.DestroyAllAsync(DeliverEmailRelayWorker.QueueName, CancellationToken.None).GetAwaiter() + .GetResult(); + _serviceClient = setup.GetRequiredService().As(); + _serviceClient.Reset(); + } + + [Fact] + public async Task WhenMessageQueuedContainingInvalidContent_ThenApiNotCalled() + { + await Setup.QueueStore.PushAsync(DeliverEmailRelayWorker.QueueName, "aninvalidemailmessage", + CancellationToken.None); + + Setup.WaitForQueueProcessingToComplete(); + + (await Setup.QueueStore.CountAsync(DeliverEmailRelayWorker.QueueName, CancellationToken.None)) + .Should().Be(0); + _serviceClient.LastPostedMessage.Should().BeNone(); + } + + [Fact] + public async Task WhenMessageQueuedContaining_ThenApiCalled() + { + var message = StringExtensions.ToJson(new EmailMessage + { + Html = new QueuedEmailHtmlMessage + { + Subject = "asubject", + HtmlBody = "abody", + ToEmailAddress = "arecipientemailaddress", + FromEmailAddress = "asenderemailaddress" + } + })!; + await Setup.QueueStore.PushAsync(DeliverEmailRelayWorker.QueueName, message, CancellationToken.None); + + Setup.WaitForQueueProcessingToComplete(); + + (await Setup.QueueStore.CountAsync(DeliverEmailRelayWorker.QueueName, CancellationToken.None)) + .Should().Be(0); + _serviceClient.LastPostedMessage.Value.Should() + .BeEquivalentTo(new DeliverEmailRequest { Message = message }); + } + + private static void OverrideDependencies(IServiceCollection services) + { + services.AddSingleton(); + } +} \ No newline at end of file diff --git a/src/Infrastructure.Workers.Api/Workers/DeliverEmailRelayWorker.cs b/src/Infrastructure.Workers.Api/Workers/DeliverEmailRelayWorker.cs new file mode 100644 index 00000000..ce7290e5 --- /dev/null +++ b/src/Infrastructure.Workers.Api/Workers/DeliverEmailRelayWorker.cs @@ -0,0 +1,33 @@ +using Application.Interfaces.Services; +using Application.Persistence.Shared.ReadModels; +using Common; +using Common.Extensions; +using Infrastructure.Web.Api.Operations.Shared.Ancillary; +using Infrastructure.Web.Interfaces.Clients; +using Task = System.Threading.Tasks.Task; + +namespace Infrastructure.Workers.Api.Workers; + +public sealed class DeliverEmailRelayWorker : IQueueMonitoringApiRelayWorker +{ + public const string QueueName = "emails"; + private readonly IRecorder _recorder; + private readonly IServiceClient _serviceClient; + private readonly IHostSettings _settings; + + public DeliverEmailRelayWorker(IRecorder recorder, IHostSettings settings, IServiceClient serviceClient) + { + _recorder = recorder; + _settings = settings; + _serviceClient = serviceClient; + } + + public async Task RelayMessageOrThrowAsync(EmailMessage message, CancellationToken cancellationToken) + { + await _serviceClient.PostQueuedMessageToApiOrThrowAsync(_recorder, + message, new DeliverEmailRequest + { + Message = message.ToJson()! + }, _settings.GetAncillaryApiHostHmacAuthSecret(), cancellationToken); + } +} \ No newline at end of file diff --git a/src/SaaStack.sln.DotSettings b/src/SaaStack.sln.DotSettings index 224f1fd3..811a77cf 100644 --- a/src/SaaStack.sln.DotSettings +++ b/src/SaaStack.sln.DotSettings @@ -804,6 +804,8 @@ public void When$condition$_Then$outcome$() True True True + True + True True True True @@ -840,8 +842,10 @@ public void When$condition$_Then$outcome$() True True True + True True True + True True True True @@ -890,6 +894,8 @@ public void When$condition$_Then$outcome$() True True True + True + True True True True @@ -904,6 +910,8 @@ public void When$condition$_Then$outcome$() True True True + True + True True True True @@ -915,11 +923,14 @@ public void When$condition$_Then$outcome$() True True True + True True True True True True + True + True True True True

    Please click this link to confirm your email address