Skip to content

Commit

Permalink
#336 Implementation of core logic for placing an sms notification ord…
Browse files Browse the repository at this point in the history
…er (#380)

* SMS notification channel added in the ENUM

* SMS template added in NotificationTemplate

* SMS template added in NotificationTemplate 2

* Added JSON subtype for SMS in the notification interface

* Renamed class and interface for OrderRequestService

* Renamed RegisterNotificationorder method

* Default email from address property name fixed

* Added default sender number in the config

* Extended method for setting default value when empty

* Fixed the prop name for the default SMS sender

* Shortened sender setting method name

* Fixed the code documentation or comment

* Fixed the code documentation or comment

* Renamed property to make more generic

* Tweaks needed for the property name change

* SMS template post valid scope accepted test

* Reverting last wrong commit

* Added unit test default SMS sender

* Renamed some tests to mark them specific for email

* SMS test for expected register notificaiton order

* SMS test for no sender handle and default inserted

* Renamed SenderHandle to SenderNumber again as agreed

* Renamed NotificationOrderConfig default proporty for SMS as agreed

* Renamed _orderService to _orderRequestService
  • Loading branch information
khanrn authored Jan 19, 2024
1 parent feae74a commit 812501d
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ public class NotificationOrderConfig
/// Default from address for email notifications
/// </summary>
public string DefaultEmailFromAddress { get; set; } = string.Empty;

/// <summary>
/// Default sender number for sms notifications
/// </summary>
public string DefaultSmsSenderNumber { get; set; } = string.Empty;
}
7 changes: 6 additions & 1 deletion src/Altinn.Notifications.Core/Enums/NotificationChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@ public enum NotificationChannel
/// <summary>
/// The selected channel for the notification is email.
/// </summary>
Email
Email,

/// <summary>
/// The selected channel for the notification is SMS.
/// </summary>
Sms
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
/// </summary>
public enum NotificationTemplateType
{
Email
Email,
Sms
}
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static void AddCoreServices(this IServiceCollection services, IConfigurat
.AddSingleton<IDateTimeService, DateTimeService>()
.AddSingleton<IOrderProcessingService, OrderProcessingService>()
.AddSingleton<IGetOrderService, GetOrderService>()
.AddSingleton<IEmailNotificationOrderService, EmailNotificationOrderService>()
.AddSingleton<IOrderRequestService, OrderRequestService>()
.AddSingleton<INotificationSummaryService, NotificationSummaryService>()
.AddSingleton<IEmailNotificationService, EmailNotificationService>()
.AddSingleton<IAltinnServiceUpdateService, AltinnServiceUpdateService>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Altinn.Notifications.Core.Models.NotificationTemplate;
/// Base class for a notification template
/// </summary>
[JsonDerivedType(typeof(EmailTemplate), "email")]
[JsonDerivedType(typeof(SmsTemplate), "sms")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "$")]
public interface INotificationTemplate
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Altinn.Notifications.Core.Enums;

namespace Altinn.Notifications.Core.Models.NotificationTemplate;

/// <summary>
/// Template for an SMS notification
/// </summary>
public class SmsTemplate : INotificationTemplate
{
/// <inheritdoc/>
public NotificationTemplateType Type { get; internal set; }

/// <summary>
/// Gets the number from which the SMS is created by the template
/// </summary>
public string SenderNumber { get; internal set; } = string.Empty;

/// <summary>
/// Gets the body of SMSs created by the template
/// </summary>
public string Body { get; internal set; } = string.Empty;

/// <summary>
/// Initializes a new instance of the <see cref="SmsTemplate"/> class.
/// </summary>
public SmsTemplate(string? senderNumber, string body)
{
SenderNumber = senderNumber ?? string.Empty;
Body = body;
Type = NotificationTemplateType.Sms;
}

/// <summary>
/// Initializes a new instance of the <see cref="SmsTemplate"/> class.
/// </summary>
internal SmsTemplate()
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
namespace Altinn.Notifications.Core.Services.Interfaces;

/// <summary>
/// Interface for the email notification order service
/// Interface for the notification order service
/// </summary>
public interface IEmailNotificationOrderService
public interface IOrderRequestService
{
/// <summary>
/// Registers a new order
/// </summary>
/// <param name="orderRequest">The email notification order request</param>
/// <param name="orderRequest">The notification order request</param>
/// <returns>The registered notification order</returns>
public Task<(NotificationOrder? Order, ServiceError? Error)> RegisterEmailNotificationOrder(NotificationOrderRequest orderRequest);
public Task<(NotificationOrder? Order, ServiceError? Error)> RegisterNotificationOrder(NotificationOrderRequest orderRequest);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,35 @@
namespace Altinn.Notifications.Core.Services;

/// <summary>
/// Implementation of the <see cref="IEmailNotificationOrderService"/>.
/// Implementation of the <see cref="IOrderRequestService"/>.
/// </summary>
public class EmailNotificationOrderService : IEmailNotificationOrderService
public class OrderRequestService : IOrderRequestService
{
private readonly IOrderRepository _repository;
private readonly IGuidService _guid;
private readonly IDateTimeService _dateTime;
private readonly string _defaultFromAddress;
private readonly string _defaultEmailFromAddress;
private readonly string _defaultSmsSender;

/// <summary>
/// Initializes a new instance of the <see cref="EmailNotificationOrderService"/> class.
/// Initializes a new instance of the <see cref="OrderRequestService"/> class.
/// </summary>
public EmailNotificationOrderService(IOrderRepository repository, IGuidService guid, IDateTimeService dateTime, IOptions<NotificationOrderConfig> config)
public OrderRequestService(IOrderRepository repository, IGuidService guid, IDateTimeService dateTime, IOptions<NotificationOrderConfig> config)
{
_repository = repository;
_guid = guid;
_dateTime = dateTime;
_defaultFromAddress = config.Value.DefaultEmailFromAddress;
_defaultEmailFromAddress = config.Value.DefaultEmailFromAddress;
_defaultSmsSender = config.Value.DefaultSmsSenderNumber;
}

/// <inheritdoc/>
public async Task<(NotificationOrder? Order, ServiceError? Error)> RegisterEmailNotificationOrder(NotificationOrderRequest orderRequest)
public async Task<(NotificationOrder? Order, ServiceError? Error)> RegisterNotificationOrder(NotificationOrderRequest orderRequest)
{
Guid orderId = _guid.NewGuid();
DateTime created = _dateTime.UtcNow();

var templates = SetFromAddressIfNotDefined(orderRequest.Templates);
var templates = SetSenderIfNotDefined(orderRequest.Templates);

var order = new NotificationOrder(
orderId,
Expand All @@ -53,11 +55,16 @@ public EmailNotificationOrderService(IOrderRepository repository, IGuidService g
return (savedOrder, null);
}

private List<INotificationTemplate> SetFromAddressIfNotDefined(List<INotificationTemplate> templates)
private List<INotificationTemplate> SetSenderIfNotDefined(List<INotificationTemplate> templates)
{
foreach (var template in templates.OfType<EmailTemplate>().Where(template => string.IsNullOrEmpty(template.FromAddress)))
{
template.FromAddress = _defaultFromAddress;
template.FromAddress = _defaultEmailFromAddress;
}

foreach (var template in templates.OfType<SmsTemplate>().Where(template => string.IsNullOrEmpty(template.SenderNumber)))
{
template.SenderNumber = _defaultSmsSender;
}

return templates;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ namespace Altinn.Notifications.Controllers;
public class EmailNotificationOrdersController : ControllerBase
{
private readonly IValidator<EmailNotificationOrderRequestExt> _validator;
private readonly IEmailNotificationOrderService _orderService;
private readonly IOrderRequestService _orderRequestService;

/// <summary>
/// Initializes a new instance of the <see cref="EmailNotificationOrdersController"/> class.
/// </summary>
public EmailNotificationOrdersController(IValidator<EmailNotificationOrderRequestExt> validator, IEmailNotificationOrderService orderService)
public EmailNotificationOrdersController(IValidator<EmailNotificationOrderRequestExt> validator, IOrderRequestService orderRequestService)
{
_validator = validator;
_orderService = orderService;
_orderRequestService = orderRequestService;
}

/// <summary>
Expand Down Expand Up @@ -71,7 +71,7 @@ public async Task<ActionResult<OrderIdExt>> Post(EmailNotificationOrderRequestEx
}

var orderRequest = emailNotificationOrderRequest.MapToOrderRequest(creator);
(NotificationOrder? registeredOrder, ServiceError? error) = await _orderService.RegisterEmailNotificationOrder(orderRequest);
(NotificationOrder? registeredOrder, ServiceError? error) = await _orderRequestService.RegisterNotificationOrder(orderRequest);

if (error != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ public async Task Post_UserClaimsPrincipal_Forbidden()
public async Task Post_ServiceReturnsError_ServerError()
{
// Arrange
Mock<IEmailNotificationOrderService> serviceMock = new();
serviceMock.Setup(s => s.RegisterEmailNotificationOrder(It.IsAny<NotificationOrderRequest>()))
Mock<IOrderRequestService> serviceMock = new();
serviceMock.Setup(s => s.RegisterNotificationOrder(It.IsAny<NotificationOrderRequest>()))
.ReturnsAsync((null, new ServiceError(500)));

HttpClient client = GetTestClient(orderService: serviceMock.Object);
Expand All @@ -196,8 +196,8 @@ public async Task Post_ServiceReturnsError_ServerError()
public async Task Post_ValidScope_ServiceReturnsOrder_Accepted()
{
// Arrange
Mock<IEmailNotificationOrderService> serviceMock = new();
serviceMock.Setup(s => s.RegisterEmailNotificationOrder(It.IsAny<NotificationOrderRequest>()))
Mock<IOrderRequestService> serviceMock = new();
serviceMock.Setup(s => s.RegisterNotificationOrder(It.IsAny<NotificationOrderRequest>()))
.Callback<NotificationOrderRequest>(orderRequest =>
{
var emailTemplate = orderRequest.Templates
Expand Down Expand Up @@ -235,8 +235,8 @@ public async Task Post_ValidScope_ServiceReturnsOrder_Accepted()
public async Task Post_ValidAccessToken_ServiceReturnsOrder_Accepted()
{
// Arrange
Mock<IEmailNotificationOrderService> serviceMock = new();
serviceMock.Setup(s => s.RegisterEmailNotificationOrder(It.IsAny<NotificationOrderRequest>()))
Mock<IOrderRequestService> serviceMock = new();
serviceMock.Setup(s => s.RegisterNotificationOrder(It.IsAny<NotificationOrderRequest>()))
.Callback<NotificationOrderRequest>(orderRequest =>
{
var emailTemplate = orderRequest.Templates
Expand Down Expand Up @@ -274,9 +274,9 @@ public async Task Post_ValidAccessToken_ServiceReturnsOrder_Accepted()
public async Task Post_OrderWithoutFromAddress_StringEmptyUsedAsServiceInput_Accepted()
{
// Arrange
Mock<IEmailNotificationOrderService> serviceMock = new();
Mock<IOrderRequestService> serviceMock = new();

serviceMock.Setup(s => s.RegisterEmailNotificationOrder(It.IsAny<NotificationOrderRequest>()))
serviceMock.Setup(s => s.RegisterNotificationOrder(It.IsAny<NotificationOrderRequest>()))
.Callback<NotificationOrderRequest>(orderRequest =>
{
var emailTemplate = orderRequest.Templates
Expand Down Expand Up @@ -321,7 +321,7 @@ public async Task Post_OrderWithoutFromAddress_StringEmptyUsedAsServiceInput_Acc
serviceMock.VerifyAll();
}

private HttpClient GetTestClient(IValidator<EmailNotificationOrderRequestExt>? validator = null, IEmailNotificationOrderService? orderService = null)
private HttpClient GetTestClient(IValidator<EmailNotificationOrderRequestExt>? validator = null, IOrderRequestService? orderService = null)
{
if (validator == null)
{
Expand All @@ -333,7 +333,7 @@ private HttpClient GetTestClient(IValidator<EmailNotificationOrderRequestExt>? v

if (orderService == null)
{
var orderServiceMock = new Mock<IEmailNotificationOrderService>();
var orderServiceMock = new Mock<IOrderRequestService>();
orderService = orderServiceMock.Object;
}

Expand Down
Loading

0 comments on commit 812501d

Please sign in to comment.