Skip to content

Commit

Permalink
notifications funcitonality added #GCPActive (#62)
Browse files Browse the repository at this point in the history
* copied all code

* Added repository logic

* all notifications code in single folder

* Reverted changes to other components

* added readme

* copied with namespace

* added nullable enable

* My suggested changes to feature/notifications (#65)

---------

Co-authored-by: Ivar Nesje <[email protected]>
  • Loading branch information
acn-sbuad and ivarne authored Nov 20, 2023
1 parent 974e636 commit be99926
Show file tree
Hide file tree
Showing 64 changed files with 2,497 additions and 11 deletions.
12 changes: 8 additions & 4 deletions src/Configuration/LocalPlatformSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class LocalPlatformSettings
string _localTestDataPath = null;

/// <summary>
/// The endpoint for the bridge
/// The path to the local storage folder
/// </summary>
public string LocalTestingStorageBasePath { get; set; }

Expand All @@ -21,12 +21,16 @@ public class LocalPlatformSettings

public string BlobStorageFolder { get; set; } = "blobs/";

public string NotificationsStorageFolder { get; set; } = "notifications/";

/// <summary>
/// Folder where static test data like profile, authorization, and register data is available for local testing.
/// </summary>
public string LocalTestingStaticTestDataPath {
public string LocalTestingStaticTestDataPath
{
get => _localTestDataPath;
set {
set
{
if (!value.EndsWith(Path.DirectorySeparatorChar) &&
!value.EndsWith(Path.AltDirectorySeparatorChar))
{
Expand All @@ -47,7 +51,7 @@ public string LocalTestingStaticTestDataPath {
/// <summary>
public string LocalAppMode { get; set; }

public string DocumentDbFolder { get; set; } = "documentdb/";
public string DocumentDbFolder { get; set; } = "documentdb/";

public string InstanceCollectionFolder { get; set; } = "instances/";

Expand Down
4 changes: 4 additions & 0 deletions src/LocalTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
<TargetFramework>net6.0</TargetFramework>
<UserSecretsId>56f36ce2-b44b-415e-a8a5-f399a76e35b9</UserSecretsId>
<ImplicitUsings>enable</ImplicitUsings>

<!-- Allow copied code to use #if LOCALTEST to maintain changes for localtest from core services -->
<DefineConstants>$(DefineConstants);LOCALTEST</DefineConstants>
</PropertyGroup>

<ItemGroup>
Expand All @@ -12,6 +15,7 @@
<PackageReference Include="Altinn.Platform.Models" Version="1.2.0" />
<PackageReference Include="Altinn.Platform.Storage.Interface" Version="3.22.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
<PackageReference Include="FluentValidation" Version="11.8.0" />
<PackageReference Include="JWTCookieAuthentication" Version="2.4.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#nullable enable
#if !LOCALTEST
using Altinn.Notifications.Configuration;
#endif
using Altinn.Notifications.Core.Models;
using Altinn.Notifications.Core.Models.Orders;
using Altinn.Notifications.Core.Services.Interfaces;
using Altinn.Notifications.Extensions;
using Altinn.Notifications.Mappers;
using Altinn.Notifications.Models;
using Altinn.Notifications.Validators;

using FluentValidation;

#if !LOCALTEST
using Microsoft.AspNetCore.Authorization;
#endif
using Microsoft.AspNetCore.Mvc;

#if !LOCALTEST
using Swashbuckle.AspNetCore.Annotations;
using Swashbuckle.AspNetCore.Filters;
#endif

namespace Altinn.Notifications.Controllers;

/// <summary>
/// Controller for all operations related to email notification orders
/// </summary>
[Route("notifications/api/v1/orders/email")]
[ApiController]
#if !LOCALTEST
[Authorize(Policy = AuthorizationConstants.POLICY_CREATE_SCOPE_OR_PLATFORM_ACCESS)]
[SwaggerResponse(401, "Caller is unauthorized")]
[SwaggerResponse(403, "Caller is not authorized to access the requested resource")]
# endif
public class EmailNotificationOrdersController : ControllerBase
{
private readonly IValidator<EmailNotificationOrderRequestExt> _validator;
private readonly IEmailNotificationOrderService _orderService;

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

/// <summary>
/// Add an email notification order.
/// </summary>
/// <remarks>
/// The API will accept the request after som basic validation of the request.
/// The system will also attempt to verify that it will be possible to fulfill the order.
/// </remarks>
/// <returns>The id of the registered notification order</returns>
[HttpPost]
[Consumes("application/json")]
[Produces("application/json")]
#if !LOCALTEST
[SwaggerResponse(202, "The notification order was accepted", typeof(OrderIdExt))]
[SwaggerResponse(400, "The notification order is invalid", typeof(ValidationProblemDetails))]
[SwaggerResponseHeader(202, "Location", "string", "Link to access the newly created notification order.")]
#endif
public async Task<ActionResult<OrderIdExt>> Post(EmailNotificationOrderRequestExt emailNotificationOrderRequest)
{
var validationResult = _validator.Validate(emailNotificationOrderRequest);
if (!validationResult.IsValid)
{
validationResult.AddToModelState(ModelState);
return ValidationProblem(ModelState);
}

#if LOCALTEST
string creator = "localtest";
#else
string? creator = HttpContext.GetOrg();

if (creator == null)
{
return Forbid();
}
#endif

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

if (error != null)
{
return StatusCode(error.ErrorCode, error.ErrorMessage);
}

string selfLink = registeredOrder!.GetSelfLink();
return Accepted(selfLink, new OrderIdExt(registeredOrder!.Id));
}
}
81 changes: 81 additions & 0 deletions src/Notifications/API/Extensions/ResourceLinkExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#nullable enable
using Altinn.Notifications.Core.Models.Orders;
using Altinn.Notifications.Models;

namespace Altinn.Notifications.Extensions;

/// <summary>
/// Extension class for ResourceLinks
/// </summary>
public static class ResourceLinkExtensions
{
private static string? _baseUri;

/// <summary>
/// Initializes the ResourceLinkExtensions with the base URI from settings.
/// </summary>
/// <remarks>
/// Should be called during startup to ensure base url is set
/// </remarks>
public static void Initialize(string baseUri)
{
_baseUri = baseUri;
}

/// <summary>
/// Sets the resource links on an external notification order
/// </summary>
/// <exception cref="InvalidOperationException">Exception if class has not been initialized in Program.cs</exception>
public static void SetResourceLinks(this NotificationOrderExt order)
{
if (_baseUri == null)
{
throw new InvalidOperationException("ResourceLinkExtensions has not been initialized with the base URI.");
}

string self = _baseUri + "/notifications/api/v1/orders/" + order.Id;

order.Links = new()
{
Self = self,
Status = self + "/status",
Notifications = self + "/notifications"
};
}

/// <summary>
/// Gets the self link for the provided notification order
/// </summary>
/// <exception cref="InvalidOperationException">Exception if class has not been initialized in Program.cs</exception>
public static void NotificationSummaryResourceLinks(this NotificationOrderWithStatusExt order)
{
if (_baseUri == null)
{
throw new InvalidOperationException("ResourceLinkExtensions has not been initialized with the base URI.");
}

string baseUri = $"{_baseUri}/notifications/api/v1/orders/{order!.Id}/notifications/";

if (order.NotificationsStatusSummary?.Email != null)
{
order.NotificationsStatusSummary.Email.Links = new()
{
Self = baseUri + "email"
};
}
}

/// <summary>
/// Gets the self link for the provided notification order
/// </summary>
/// <exception cref="InvalidOperationException">Exception if class has not been initialized in Program.cs</exception>
public static string GetSelfLink(this NotificationOrder order)
{
if (_baseUri == null)
{
throw new InvalidOperationException("ResourceLinkExtensions has not been initialized with the base URI.");
}

return _baseUri + "/notifications/api/v1/orders/" + order!.Id;
}
}
Loading

0 comments on commit be99926

Please sign in to comment.