From 5610117139769de7fb7ec1ca757e12201b52d57f Mon Sep 17 00:00:00 2001
From: Stephanie Buadu <47737608+acn-sbuad@users.noreply.github.com>
Date: Wed, 15 May 2024 12:35:59 +0200
Subject: [PATCH] new endpoint for unit contact points (#151)
* new endpoint for unit contact points
* added UnitProfileClientTest
* test implemented, but not working
* fixed unit test for unitclient
* fixed code smell
* still fixing code smells
* fixed final code smell
* Update src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs
* Fixed pr comments
---
.../Integrations/IUnitProfileClient.cs | 17 +++
.../ServiceCollectionExtensions.cs | 4 +-
.../Unit.ContactPoints/IUnitContactPoints.cs | 16 +++
.../UnitContactPointLookup.cs | 18 +++
.../UnitContactPointService.cs | 28 ++++
.../Unit.ContactPoints/UnitContactPoints.cs | 36 ++++++
.../User.ContactPoints/UserContactPoints.cs | 2 +-
.../PartyNotificationContactPoints.cs | 75 +++++++++++
.../SblBridge/UnitProfileClient.cs | 70 ++++++++++
.../ServiceCollectionExtensions.cs | 6 +-
.../Controllers/UnitContactPointController.cs | 45 +++++++
.../Controllers/UserContactPointController.cs | 1 +
.../Models}/UserContactPointLookup.cs | 4 +-
src/Altinn.Profile/appsettings.json | 2 +-
.../UnitContactPointControllerTests.cs | 122 ++++++++++++++++++
.../UserContactPointControllerTests.cs | 1 +
.../Utils/WebApplicationFactorySetup.cs | 8 ++
.../User/UserProfileCachingDecoratorTest.cs | 0
.../PartyNotificationContactPointsTests.cs | 74 +++++++++++
.../SblBridge/UnitProfileClientTest.cs | 118 +++++++++++++++++
20 files changed, 640 insertions(+), 7 deletions(-)
create mode 100644 src/Altinn.Profile.Core/Integrations/IUnitProfileClient.cs
create mode 100644 src/Altinn.Profile.Core/Unit.ContactPoints/IUnitContactPoints.cs
create mode 100644 src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointLookup.cs
create mode 100644 src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointService.cs
create mode 100644 src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPoints.cs
create mode 100644 src/Altinn.Profile.Integrations/SblBridge/PartyNotificationContactPoints.cs
create mode 100644 src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs
create mode 100644 src/Altinn.Profile/Controllers/UnitContactPointController.cs
rename src/{Altinn.Profile.Core/User.ContactPoints => Altinn.Profile/Models}/UserContactPointLookup.cs (82%)
create mode 100644 test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UnitContactPointControllerTests.cs
rename test/Altinn.Profile.Tests/{Core => Profile.Core}/User/UserProfileCachingDecoratorTest.cs (100%)
create mode 100644 test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/PartyNotificationContactPointsTests.cs
create mode 100644 test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/UnitProfileClientTest.cs
diff --git a/src/Altinn.Profile.Core/Integrations/IUnitProfileClient.cs b/src/Altinn.Profile.Core/Integrations/IUnitProfileClient.cs
new file mode 100644
index 0000000..500783f
--- /dev/null
+++ b/src/Altinn.Profile.Core/Integrations/IUnitProfileClient.cs
@@ -0,0 +1,17 @@
+using Altinn.Profile.Core.Unit.ContactPoints;
+
+namespace Altinn.Profile.Core.Integrations
+{
+ ///
+ /// Interface describing a client for the user profile service
+ ///
+ public interface IUnitProfileClient
+ {
+ ///
+ /// Provides a list of user registered contact points based on the lookup criteria
+ ///
+ /// Lookup object containing a list of organizations and a resource
+ /// A list of unit contact points
+ Task> GetUserRegisteredContactPoints(UnitContactPointLookup lookup);
+ }
+}
diff --git a/src/Altinn.Profile.Core/ServiceCollectionExtensions.cs b/src/Altinn.Profile.Core/ServiceCollectionExtensions.cs
index 0b3d3af..da1f54d 100644
--- a/src/Altinn.Profile.Core/ServiceCollectionExtensions.cs
+++ b/src/Altinn.Profile.Core/ServiceCollectionExtensions.cs
@@ -1,4 +1,5 @@
using Altinn.Profile.Core;
+using Altinn.Profile.Core.Unit.ContactPoints;
using Altinn.Profile.Core.User;
using Altinn.Profile.Core.User.ContactPoints;
@@ -24,6 +25,7 @@ public static void AddCoreServices(this IServiceCollection services, IConfigurat
.AddMemoryCache()
.AddSingleton()
.AddSingleton()
- .Decorate();
+ .Decorate()
+ .AddSingleton();
}
}
diff --git a/src/Altinn.Profile.Core/Unit.ContactPoints/IUnitContactPoints.cs b/src/Altinn.Profile.Core/Unit.ContactPoints/IUnitContactPoints.cs
new file mode 100644
index 0000000..3aec836
--- /dev/null
+++ b/src/Altinn.Profile.Core/Unit.ContactPoints/IUnitContactPoints.cs
@@ -0,0 +1,16 @@
+using Altinn.Profile.Core.Unit.ContactPoints;
+
+namespace Altinn.Profile.Core.User.ContactPoints;
+
+///
+/// Class describing the methods required for user contact point service
+///
+public interface IUnitContactPoints
+{
+ ///
+ /// Method for retriveing user registered contact points for a unit
+ ///
+ /// A lookup object containing a list of organisation numbers and the resource to lookup contact points for
+ /// The users' contact points and reservation status or a boolean if failure.
+ Task> GetUserRegisteredContactPoints(UnitContactPointLookup lookup);
+}
diff --git a/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointLookup.cs b/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointLookup.cs
new file mode 100644
index 0000000..4ca1d51
--- /dev/null
+++ b/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointLookup.cs
@@ -0,0 +1,18 @@
+namespace Altinn.Profile.Core.Unit.ContactPoints
+{
+ ///
+ /// A class describing the query model for contact points for units
+ ///
+ public class UnitContactPointLookup
+ {
+ ///
+ /// Gets or sets the list of organisation numbers to lookup contact points for
+ ///
+ public List OrganizationNumbers { get; set; } = [];
+
+ ///
+ /// Gets or sets the resource id to filter the contact points by
+ ///
+ public string ResourceId { get; set; } = string.Empty;
+ }
+}
diff --git a/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointService.cs b/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointService.cs
new file mode 100644
index 0000000..a16ca10
--- /dev/null
+++ b/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPointService.cs
@@ -0,0 +1,28 @@
+using Altinn.Profile.Core.Integrations;
+using Altinn.Profile.Core.User.ContactPoints;
+
+namespace Altinn.Profile.Core.Unit.ContactPoints
+{
+ ///
+ /// Implementation of the interface using a REST client to retrieve profile data "/>
+ ///
+ public class UnitContactPointService : IUnitContactPoints
+ {
+ private readonly IUnitProfileClient _unitClient;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UnitContactPointService(IUnitProfileClient unitClient)
+ {
+ _unitClient = unitClient;
+ }
+
+ ///
+ public async Task> GetUserRegisteredContactPoints(UnitContactPointLookup lookup)
+ {
+ Result result = await _unitClient.GetUserRegisteredContactPoints(lookup);
+ return result;
+ }
+ }
+}
diff --git a/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPoints.cs b/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPoints.cs
new file mode 100644
index 0000000..9233d25
--- /dev/null
+++ b/src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPoints.cs
@@ -0,0 +1,36 @@
+using Altinn.Profile.Core.User.ContactPoints;
+
+namespace Altinn.Profile.Core.Unit.ContactPoints
+{
+ ///
+ /// Class describing the user registered contact points for a unit
+ ///
+ public class UnitContactPoints
+ {
+ ///
+ /// Gets or sets the organization number of the organization.
+ ///
+ public string OrganizationNumber { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the party id of the organization.
+ ///
+ public int PartyId { get; set; }
+
+ ///
+ /// Gets or sets a list of multiple contanct points associated with the organisation.
+ ///
+ public List UserContactPoints { get; set; } = [];
+ }
+
+ ///
+ /// A list representation of
+ ///
+ public class UnitContactPointsList
+ {
+ ///
+ /// A list containing contact points for users
+ ///
+ public List ContactPointsList { get; set; } = [];
+ }
+}
diff --git a/src/Altinn.Profile.Core/User.ContactPoints/UserContactPoints.cs b/src/Altinn.Profile.Core/User.ContactPoints/UserContactPoints.cs
index e7e335c..f705bfe 100644
--- a/src/Altinn.Profile.Core/User.ContactPoints/UserContactPoints.cs
+++ b/src/Altinn.Profile.Core/User.ContactPoints/UserContactPoints.cs
@@ -1,7 +1,7 @@
namespace Altinn.Profile.Core.User.ContactPoints;
///
-/// Class describing the availability of contact points for a user
+/// Class describing the contact points for a user
///
public class UserContactPoints
{
diff --git a/src/Altinn.Profile.Integrations/SblBridge/PartyNotificationContactPoints.cs b/src/Altinn.Profile.Integrations/SblBridge/PartyNotificationContactPoints.cs
new file mode 100644
index 0000000..a74643e
--- /dev/null
+++ b/src/Altinn.Profile.Integrations/SblBridge/PartyNotificationContactPoints.cs
@@ -0,0 +1,75 @@
+using Altinn.Profile.Core.Unit.ContactPoints;
+using Altinn.Profile.Core.User.ContactPoints;
+
+namespace Altinn.Profile.Integrations.SblBridge
+{
+ ///
+ /// Model describing a container for a list of contact points.
+ ///
+ public class PartyNotificationContactPoints
+ {
+ ///
+ /// Gets or sets the party id of the organisation.
+ ///
+ public Guid? PartyId { get; set; }
+
+ ///
+ /// Gets or sets the legacy id of the organisation.
+ ///
+ public int LegacyPartyId { get; set; }
+
+ ///
+ /// Gets or sets the organization number of the organisation.
+ ///
+ public string OrganizationNumber { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a list of multiple contanct points associated with the organisation.
+ ///
+ public List ContactPoints { get; set; } = new List();
+
+ ///
+ /// Maps a list of to a list of .
+ ///
+ public static UnitContactPointsList MapToUnitContactPoints(List source)
+ {
+ List contactPoints = source.Select(partyNotificationEndpoint => new UnitContactPoints
+ {
+ OrganizationNumber = partyNotificationEndpoint.OrganizationNumber,
+ PartyId = partyNotificationEndpoint.LegacyPartyId,
+ UserContactPoints = partyNotificationEndpoint.ContactPoints.Select(contactPoint => new UserContactPoints
+ {
+ UserId = contactPoint.LegacyUserId,
+ Email = contactPoint.Email,
+ MobileNumber = contactPoint.MobileNumber
+ }).ToList()
+ }).ToList();
+
+ return new UnitContactPointsList() { ContactPointsList = contactPoints };
+ }
+ }
+
+ ///
+ /// Model describing the contact information that a user has associated with a party they can represent.
+ ///
+ public class UserRegisteredContactPoint
+ {
+ ///
+ /// Gets or sets the legacy user id for the owner of this party notification endpoint.
+ ///
+ ///
+ /// This was named as legacy for consistency. Property for UUID will probably never be added.
+ ///
+ public int LegacyUserId { get; set; }
+
+ ///
+ /// Gets or sets the email address for this contact point.
+ ///
+ public string Email { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the mobile number for this contact point.
+ ///
+ public string MobileNumber { get; set; } = string.Empty;
+ }
+}
diff --git a/src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs b/src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs
new file mode 100644
index 0000000..a8d77cb
--- /dev/null
+++ b/src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs
@@ -0,0 +1,70 @@
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+using Altinn.Profile.Core;
+using Altinn.Profile.Core.Integrations;
+using Altinn.Profile.Core.Unit.ContactPoints;
+
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+namespace Altinn.Profile.Integrations.SblBridge;
+
+///
+/// Represents an implementation of using SBLBridge to obtain unit profile information.
+///
+public class UnitProfileClient : IUnitProfileClient
+{
+ private readonly ILogger _logger;
+ private readonly HttpClient _client;
+ private readonly JsonSerializerOptions _serializerOptions;
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// HttpClient from default http client factory
+ /// the logger
+ /// the sbl bridge settings
+ public UnitProfileClient(
+ HttpClient httpClient,
+ ILogger logger,
+ IOptions settings)
+ {
+ _logger = logger;
+ _client = httpClient;
+ _client.BaseAddress = new Uri(settings.Value.ApiProfileEndpoint);
+
+ _serializerOptions = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ PropertyNameCaseInsensitive = true,
+ Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
+ };
+ }
+
+ ///
+ public async Task> GetUserRegisteredContactPoints(UnitContactPointLookup lookup)
+ {
+ string endpoint = $"units/contactpointslookup";
+
+ StringContent requestBody = new StringContent(JsonSerializer.Serialize(lookup), Encoding.UTF8, "application/json");
+
+ HttpResponseMessage response = await _client.PostAsync(endpoint, requestBody);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ _logger.LogError(
+ "// UnitClient // GetUserRegisteredContactPoints // Unexpected response. Failed with {StatusCode} and message {Message}",
+ response.StatusCode,
+ await response.Content.ReadAsStringAsync());
+
+ return false;
+ }
+
+ string content = await response.Content.ReadAsStringAsync();
+ List partyNotificationEndpoints = JsonSerializer.Deserialize>(content, _serializerOptions)!;
+
+ return PartyNotificationContactPoints.MapToUnitContactPoints(partyNotificationEndpoints);
+ }
+}
diff --git a/src/Altinn.Profile.Integrations/ServiceCollectionExtensions.cs b/src/Altinn.Profile.Integrations/ServiceCollectionExtensions.cs
index f1ee636..703128c 100644
--- a/src/Altinn.Profile.Integrations/ServiceCollectionExtensions.cs
+++ b/src/Altinn.Profile.Integrations/ServiceCollectionExtensions.cs
@@ -22,8 +22,8 @@ public static void AddSblBridgeClients(this IServiceCollection services, IConfig
.Get()
?? throw new ArgumentNullException(nameof(config), "Required SblBridgeSettings is missing from application configuration");
- services
- .Configure(config.GetSection(nameof(SblBridgeSettings)))
- .AddHttpClient();
+ services.Configure(config.GetSection(nameof(SblBridgeSettings)));
+ services.AddHttpClient();
+ services.AddHttpClient();
}
}
diff --git a/src/Altinn.Profile/Controllers/UnitContactPointController.cs b/src/Altinn.Profile/Controllers/UnitContactPointController.cs
new file mode 100644
index 0000000..59887a2
--- /dev/null
+++ b/src/Altinn.Profile/Controllers/UnitContactPointController.cs
@@ -0,0 +1,45 @@
+using System.Threading.Tasks;
+
+using Altinn.Profile.Core;
+using Altinn.Profile.Core.Unit.ContactPoints;
+using Altinn.Profile.Core.User.ContactPoints;
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Altinn.Profile.Controllers
+{
+ ///
+ /// Controller for unit profile contact point API endpoints for internal consumption (e.g. Notifications) requiring neither authenticated user token nor access token authorization.
+ ///
+ [Route("profile/api/v1/units/contactpoint")]
+ [ApiExplorerSettings(IgnoreApi = true)]
+ [Consumes("application/json")]
+ [Produces("application/json")]
+ public class UnitContactPointController : ControllerBase
+ {
+ private readonly IUnitContactPoints _contactPointService;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UnitContactPointController(IUnitContactPoints contactPointsService)
+ {
+ _contactPointService = contactPointsService;
+ }
+
+ ///
+ /// Endpoint looking up the contact points for the units provided in the lookup object in the request body
+ ///
+ /// Returns an overview of the user registered contact points for the provided units and given resource
+ [HttpPost("lookup")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task> PostLookup([FromBody] UnitContactPointLookup unitContactPointLookup)
+ {
+ Result result = await _contactPointService.GetUserRegisteredContactPoints(unitContactPointLookup);
+ return result.Match>(
+ success => Ok(success),
+ _ => Problem("Could not retrieve contact points"));
+ }
+ }
+}
diff --git a/src/Altinn.Profile/Controllers/UserContactPointController.cs b/src/Altinn.Profile/Controllers/UserContactPointController.cs
index c11722f..d45d328 100644
--- a/src/Altinn.Profile/Controllers/UserContactPointController.cs
+++ b/src/Altinn.Profile/Controllers/UserContactPointController.cs
@@ -2,6 +2,7 @@
using Altinn.Profile.Core;
using Altinn.Profile.Core.User.ContactPoints;
+using Altinn.Profile.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
diff --git a/src/Altinn.Profile.Core/User.ContactPoints/UserContactPointLookup.cs b/src/Altinn.Profile/Models/UserContactPointLookup.cs
similarity index 82%
rename from src/Altinn.Profile.Core/User.ContactPoints/UserContactPointLookup.cs
rename to src/Altinn.Profile/Models/UserContactPointLookup.cs
index f3db92f..1451e30 100644
--- a/src/Altinn.Profile.Core/User.ContactPoints/UserContactPointLookup.cs
+++ b/src/Altinn.Profile/Models/UserContactPointLookup.cs
@@ -1,4 +1,6 @@
-namespace Altinn.Profile.Core.User.ContactPoints;
+using System.Collections.Generic;
+
+namespace Altinn.Profile.Models;
///
/// A class respresenting a user contact point lookup object
diff --git a/src/Altinn.Profile/appsettings.json b/src/Altinn.Profile/appsettings.json
index 2eb678f..d2b678e 100644
--- a/src/Altinn.Profile/appsettings.json
+++ b/src/Altinn.Profile/appsettings.json
@@ -4,7 +4,7 @@
"JwtCookieName": "AltinnStudioRuntime"
},
"SblBridgeSettings": {
- "ApiProfileEndpoint": "https://at22.altinn.cloud/sblbridge/profile/api/"
+ "ApiProfileEndpoint": "https://at24.altinn.cloud/sblbridge/profile/api/"
},
"CoreSettings": {
"ProfileCacheLifetimeSeconds": 600
diff --git a/test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UnitContactPointControllerTests.cs b/test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UnitContactPointControllerTests.cs
new file mode 100644
index 0000000..fa664c5
--- /dev/null
+++ b/test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UnitContactPointControllerTests.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+using Altinn.Profile.Controllers;
+using Altinn.Profile.Core.Unit.ContactPoints;
+using Altinn.Profile.Integrations.SblBridge;
+using Altinn.Profile.Tests.IntegrationTests.Mocks;
+using Altinn.Profile.Tests.IntegrationTests.Utils;
+
+using Microsoft.AspNetCore.Mvc.Testing;
+
+using Xunit;
+
+namespace Altinn.Profile.Tests.IntegrationTests.API.Controllers
+{
+ public class UnitContactPointControllerTests : IClassFixture>
+ {
+ private readonly WebApplicationFactorySetup _webApplicationFactorySetup;
+
+ private readonly JsonSerializerOptions _serializerOptions = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ PropertyNameCaseInsensitive = true
+ };
+
+ public UnitContactPointControllerTests(WebApplicationFactory factory)
+ {
+ _webApplicationFactorySetup = new WebApplicationFactorySetup(factory);
+
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = new DelegatingHandlerStub(async (request, token) =>
+ {
+ string requestString = await request.Content.ReadAsStringAsync(token);
+ UnitContactPointLookup lookup = JsonSerializer.Deserialize(requestString, _serializerOptions);
+ return GetSBlResponseFromSBL(lookup.OrganizationNumbers[0]);
+ });
+
+ SblBridgeSettings sblBrideSettings = new() { ApiProfileEndpoint = "http://localhost/" };
+ _webApplicationFactorySetup.SblBridgeSettingsOptions.Setup(s => s.Value).Returns(sblBrideSettings);
+ }
+
+ [Fact]
+ public async Task PostLookup_SuccessResult_ReturnsOk()
+ {
+ // Arrange
+ UnitContactPointLookup input = new()
+ {
+ OrganizationNumbers = ["123456789"],
+ ResourceId = "app_ttd_apps-test"
+ };
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+ HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, "/profile/api/v1/units/contactpoint/lookup")
+ {
+ Content = new StringContent(JsonSerializer.Serialize(input, _serializerOptions), System.Text.Encoding.UTF8, "application/json")
+ };
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ string responseContent = await response.Content.ReadAsStringAsync();
+ var actual = JsonSerializer.Deserialize(responseContent, _serializerOptions);
+ Assert.Single(actual.ContactPointsList);
+ }
+
+ [Fact]
+ public async Task PostLookup_ErrorResult_ReturnsProblemDetails()
+ {
+ // Arrange
+ UnitContactPointLookup input = new()
+ {
+ OrganizationNumbers = ["error-org"],
+ ResourceId = "app_ttd_apps-test"
+ };
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+ HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, "/profile/api/v1/units/contactpoint/lookup")
+ {
+ Content = new StringContent(JsonSerializer.Serialize(input, _serializerOptions), System.Text.Encoding.UTF8, "application/json")
+ };
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
+ }
+
+ private HttpResponseMessage GetSBlResponseFromSBL(string orgNo)
+ {
+ switch (orgNo)
+ {
+ case "123456789":
+ var input = new List()
+ {
+ new PartyNotificationContactPoints()
+ {
+ ContactPoints = [new UserRegisteredContactPoint()
+ {
+ LegacyUserId = 20001,
+ Email = "user@email.com"
+ }
+ ],
+ LegacyPartyId = 50001,
+ OrganizationNumber = "123456789",
+ PartyId = Guid.NewGuid()
+ }
+ };
+
+ return new HttpResponseMessage() { Content = JsonContent.Create(input, options: _serializerOptions), StatusCode = HttpStatusCode.OK };
+ default:
+ return new HttpResponseMessage() { StatusCode = HttpStatusCode.ServiceUnavailable };
+ }
+ }
+ }
+}
diff --git a/test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UserContactPointControllerTests.cs b/test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UserContactPointControllerTests.cs
index beea3ee..4fd4299 100644
--- a/test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UserContactPointControllerTests.cs
+++ b/test/Altinn.Profile.Tests/IntegrationTests/API/Controllers/UserContactPointControllerTests.cs
@@ -9,6 +9,7 @@
using Altinn.Profile.Controllers;
using Altinn.Profile.Core.User.ContactPoints;
using Altinn.Profile.Integrations.SblBridge;
+using Altinn.Profile.Models;
using Altinn.Profile.Tests.IntegrationTests.Mocks;
using Altinn.Profile.Tests.IntegrationTests.Utils;
using Altinn.Profile.Tests.Testdata;
diff --git a/test/Altinn.Profile.Tests/IntegrationTests/Utils/WebApplicationFactorySetup.cs b/test/Altinn.Profile.Tests/IntegrationTests/Utils/WebApplicationFactorySetup.cs
index cb8cd38..d437dd2 100644
--- a/test/Altinn.Profile.Tests/IntegrationTests/Utils/WebApplicationFactorySetup.cs
+++ b/test/Altinn.Profile.Tests/IntegrationTests/Utils/WebApplicationFactorySetup.cs
@@ -30,6 +30,8 @@ public WebApplicationFactorySetup(WebApplicationFactory webApplicationFactory
public Mock> UserProfileClientLogger { get; set; } = new();
+ public Mock> UnitProfileClientLogger { get; set; } = new();
+
public Mock> SblBridgeSettingsOptions { get; set; } = new();
public HttpMessageHandler SblBridgeHttpMessageHandler { get; set; } = new DelegatingHandlerStub();
@@ -59,6 +61,12 @@ public HttpClient GetTestServerClient()
new HttpClient(SblBridgeHttpMessageHandler),
UserProfileClientLogger.Object,
SblBridgeSettingsOptions.Object));
+
+ services.AddSingleton(
+ new UnitProfileClient(
+ new HttpClient(SblBridgeHttpMessageHandler),
+ UnitProfileClientLogger.Object,
+ SblBridgeSettingsOptions.Object));
});
}).CreateClient();
}
diff --git a/test/Altinn.Profile.Tests/Core/User/UserProfileCachingDecoratorTest.cs b/test/Altinn.Profile.Tests/Profile.Core/User/UserProfileCachingDecoratorTest.cs
similarity index 100%
rename from test/Altinn.Profile.Tests/Core/User/UserProfileCachingDecoratorTest.cs
rename to test/Altinn.Profile.Tests/Profile.Core/User/UserProfileCachingDecoratorTest.cs
diff --git a/test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/PartyNotificationContactPointsTests.cs b/test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/PartyNotificationContactPointsTests.cs
new file mode 100644
index 0000000..e1216b1
--- /dev/null
+++ b/test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/PartyNotificationContactPointsTests.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+
+using Altinn.Profile.Core.Unit.ContactPoints;
+using Altinn.Profile.Core.User.ContactPoints;
+using Altinn.Profile.Integrations.SblBridge;
+
+using Xunit;
+
+namespace Altinn.Profile.Tests.Profile.Integrations.SblBridge
+{
+ public class PartyNotificationContactPointsTests
+ {
+ [Fact]
+ public void MapToUnitContactPoints_EmptyListProvided_EmptyListReturned()
+ {
+ // Act
+ UnitContactPointsList actual = PartyNotificationContactPoints.MapToUnitContactPoints([]);
+
+ // Assert
+ Assert.Empty(actual.ContactPointsList);
+ }
+
+ [Fact]
+ public void MapToUnitContactPoints_LegacyPartyIdMappedToPartyId()
+ {
+ // Arrange
+ List input = new List
+ {
+ new PartyNotificationContactPoints
+ {
+ PartyId = Guid.NewGuid(),
+ LegacyPartyId = 512345,
+ OrganizationNumber = "123456789",
+ ContactPoints = new List
+ {
+ new UserRegisteredContactPoint
+ {
+ LegacyUserId = 212345,
+ Email = "user@domain.com",
+ MobileNumber = "12345678"
+ }
+ }
+ }
+ };
+
+ UnitContactPointsList expected = new()
+ {
+ ContactPointsList = [new UnitContactPoints()
+ {
+ OrganizationNumber = "123456789",
+ PartyId = 512345,
+ UserContactPoints = [
+ new UserContactPoints()
+ {
+ UserId = 212345,
+ Email = "user@domain.com",
+ MobileNumber = "12345678",
+ IsReserved = false,
+ NationalIdentityNumber = string.Empty
+ }
+ ]
+ }
+ ]
+ };
+
+ // Act
+ var actual = PartyNotificationContactPoints.MapToUnitContactPoints(input);
+
+ // Assert
+ Assert.Equivalent(expected.ContactPointsList, actual.ContactPointsList);
+ }
+ }
+}
diff --git a/test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/UnitProfileClientTest.cs b/test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/UnitProfileClientTest.cs
new file mode 100644
index 0000000..40a9d27
--- /dev/null
+++ b/test/Altinn.Profile.Tests/Profile.Integrations/SblBridge/UnitProfileClientTest.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Threading.Tasks;
+
+using Altinn.Profile.Core;
+using Altinn.Profile.Core.Unit.ContactPoints;
+using Altinn.Profile.Integrations.SblBridge;
+using Altinn.Profile.Tests.IntegrationTests.Mocks;
+
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+using Moq;
+
+using Xunit;
+
+namespace Altinn.Profile.Tests.Profile.Integrations.SblBridge
+{
+ public class UnitProfileClientTest
+ {
+ [Fact]
+ public async Task GetUserRegisteredContactPoints_BridgeRespondsWithOk_UnitContactPointsListReturned()
+ {
+ // Arrange
+ UnitContactPointLookup lookup = new()
+ {
+ OrganizationNumbers = ["123456789"],
+ ResourceId = "app_ttd_apps-test"
+ };
+
+ var sblBridgeHttpMessageHandler = new DelegatingHandlerStub(async (request, token) =>
+ {
+ if (request!.RequestUri!.AbsolutePath.EndsWith("units/contactpointslookup"))
+ {
+ var contentData = new List();
+ JsonContent content = JsonContent.Create(contentData);
+
+ return await Task.FromResult(new HttpResponseMessage()
+ {
+ StatusCode = HttpStatusCode.OK,
+ Content = content
+ });
+ }
+
+ return new HttpResponseMessage(HttpStatusCode.NotFound);
+ });
+
+ SblBridgeSettings settings = new()
+ {
+ ApiProfileEndpoint = "https://platform.at22.altinn.cloud/profile/api/v1/"
+ };
+
+ var sut = new UnitProfileClient(
+ new HttpClient(sblBridgeHttpMessageHandler),
+ Mock.Of>(),
+ Options.Create(settings));
+
+ // Act
+ Result result = await sut.GetUserRegisteredContactPoints(lookup);
+
+ // Assert
+ result.Match(
+ success =>
+ {
+ Assert.IsType(success);
+ },
+ error => throw new Exception("No error value should be returned if SBL client respons with 200 OK."))
+;
+ }
+
+ [Fact]
+ public async Task GetUserRegisteredContactPoints_BridgeRespondsWithServiceUnavailable_ErrorReturned_UnitContactPointsListReturned()
+ {
+ // Arrange
+ UnitContactPointLookup lookup = new()
+ {
+ OrganizationNumbers = ["123456789"],
+ ResourceId = "app_ttd_apps-test"
+ };
+
+ var sblBridgeHttpMessageHandler = new DelegatingHandlerStub((request, token) =>
+ {
+ if (request!.RequestUri!.AbsolutePath.EndsWith("units/contactpointslookup"))
+ {
+ return Task.FromResult(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
+ }
+
+ return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound));
+ });
+
+ SblBridgeSettings settings = new()
+ {
+ ApiProfileEndpoint = "https://platform.at22.altinn.cloud/profile/api/v1/"
+ };
+
+ var sut = new UnitProfileClient(
+ new HttpClient(sblBridgeHttpMessageHandler),
+ Mock.Of>(),
+ Options.Create(settings));
+
+ // Act
+ Result result = await sut.GetUserRegisteredContactPoints(lookup);
+
+ // Assert
+ result.Match(
+ success => throw new Exception("No success value should be returned if SBL client respons with 5xx."),
+ error =>
+ {
+ Assert.IsType(error);
+ Assert.False(error);
+ })
+;
+ }
+ }
+}