Skip to content

Commit

Permalink
new endpoint for unit contact points
Browse files Browse the repository at this point in the history
  • Loading branch information
acn-sbuad committed May 3, 2024
1 parent 651afb8 commit 0dbabbd
Show file tree
Hide file tree
Showing 14 changed files with 302 additions and 6 deletions.
17 changes: 17 additions & 0 deletions src/Altinn.Profile.Core/Integrations/IUnitProfileClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Altinn.Profile.Core.Unit.ContactPoints;

namespace Altinn.Profile.Core.Integrations
{
/// <summary>
/// Interface describing a client for the user profile service
/// </summary>
public interface IUnitProfileClient
{
/// <summary>
/// Provides a list of user registered contact points based on the lookup criteria
/// </summary>
/// <param name="lookup">Lookup object containing a list of organizations and a resource</param>
/// <returns>A list of unit contact points</returns>
Task<Result<UnitContactPointsList, bool>> GetUserRegisteredContactPoints(UnitContactPointLookup lookup);
}
}
4 changes: 3 additions & 1 deletion src/Altinn.Profile.Core/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -24,6 +25,7 @@ public static void AddCoreServices(this IServiceCollection services, IConfigurat
.AddMemoryCache()
.AddSingleton<IUserProfileService, UserProfileService>()
.AddSingleton<IUserContactPoints, UserContactPointService>()
.Decorate<IUserProfileService, UserProfileCachingDecorator>();
.Decorate<IUserProfileService, UserProfileCachingDecorator>()
.AddSingleton<IUnitContactPoints, UnitContactPointService>();
}
}
16 changes: 16 additions & 0 deletions src/Altinn.Profile.Core/Unit.ContactPoints/IUnitContactPoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Altinn.Profile.Core.Unit.ContactPoints;

namespace Altinn.Profile.Core.User.ContactPoints;

/// <summary>
/// Class describing the methods required for user contact point service
/// </summary>
public interface IUnitContactPoints
{
/// <summary>
/// Method for retriveing user registered contact points for a unit
/// </summary>
/// <param name="lookup">A lookup object containing a list of organisation numbers and the resource to lookup contact points for</param>
/// <returns>The users' contact points and reservation status or a boolean if failure.</returns>
Task<Result<UnitContactPointsList, bool>> GetUserRegisteredContactPoints(UnitContactPointLookup lookup);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Altinn.Profile.Core.Unit.ContactPoints
{ /// <summary>
/// A class describing the query model for contact points for units
/// </summary>
public class UnitContactPointLookup
{
/// <summary>
/// Gets or sets the list of organisation numbers to lookup contact points for
/// </summary>
public List<string> OrganizationNumbers { get; set; } = [];

/// <summary>
/// Gets or sets the resource id to filter the contact points by
/// </summary>
public string ResourceId { get; set; } = string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Altinn.Profile.Core.Integrations;
using Altinn.Profile.Core.User.ContactPoints;

namespace Altinn.Profile.Core.Unit.ContactPoints
{
/// <summary>
/// Implementation of the <see cref="IUnitContactPoints"/> interface using a REST client to retrieve profile data "/>
/// </summary>
public class UnitContactPointService : IUnitContactPoints
{
private readonly IUnitProfileClient _unitClient;

/// <summary>
/// Initializes a new instance of the <see cref="UnitContactPointService"/> class.
/// </summary>
public UnitContactPointService(IUnitProfileClient unitClient)
{
_unitClient = unitClient;
}

/// <inheritdoc/>
public async Task<Result<UnitContactPointsList, bool>> GetUserRegisteredContactPoints(UnitContactPointLookup lookup)
{
Result<UnitContactPointsList, bool> result = await _unitClient.GetUserRegisteredContactPoints(lookup);
return result;
}
}
}
36 changes: 36 additions & 0 deletions src/Altinn.Profile.Core/Unit.ContactPoints/UnitContactPoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Altinn.Profile.Core.User.ContactPoints;

namespace Altinn.Profile.Core.Unit.ContactPoints
{
/// <summary>
/// Class describing the user registered contact points for a unit
/// </summary>
public class UnitContactPoints
{
/// <summary>
/// Gets or sets the organization number of the organization.
/// </summary>
public string OrganizationNumber { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the party id of the organization.
/// </summary>
public int PartyId { get; set; }

/// <summary>
/// Gets or sets a list of multiple contanct points associated with the organisation.
/// </summary>
public List<UserContactPoints> UserContactPoints { get; set; } = [];
}

/// <summary>
/// A list representation of <see cref="UserContactPoints"/>
/// </summary>
public class UnitContactPointsList
{
/// <summary>
/// A list containing contact points for users
/// </summary>
public List<UnitContactPoints> ContactPointsList { get; set; } = [];
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Altinn.Profile.Core.User.ContactPoints;

/// <summary>
/// Class describing the availability of contact points for a user
/// Class describing the contact points for a user
/// </summary>
public class UserContactPoints
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace Altinn.Profile.Integrations.SblBridge
{
/// <summary>
/// Model describing a container for a list of contact points.
/// </summary>
public class PartyNotificationContactPoints
{
/// <summary>
/// Gets or sets the party id of the organisation.
/// </summary>
public Guid? PartyId { get; set; }

/// <summary>
/// Gets or sets the legacy id of the organisation.
/// </summary>
public int LegacyPartyId { get; set; }

/// <summary>
/// Gets or sets the organization number of the organisation.
/// </summary>
public string OrganizationNumber { get; set; } = string.Empty;

/// <summary>
/// Gets or sets a list of multiple contanct points associated with the organisation.
/// </summary>
public List<UserRegisteredContactPoint> ContactPoints { get; set; } = new List<UserRegisteredContactPoint>();
}

/// <summary>
/// Model describing the contact information that a user has associated with a party they can represent.
/// </summary>
public class UserRegisteredContactPoint
{
/// <summary>
/// Gets or sets the legacy user id for the owner of this party notification endpoint.
/// </summary>
/// <remarks>
/// This was named as legacy for consistency. Property for UUID will probably never be added.
/// </remarks>
public int LegacyUserId { get; set; }

/// <summary>
/// Gets or sets the email address for this contact point.
/// </summary>
public string Email { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the mobile number for this contact point.
/// </summary>
public string MobileNumber { get; set; } = string.Empty;
}
}
79 changes: 79 additions & 0 deletions src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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 Altinn.Profile.Core.User.ContactPoints;

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Altinn.Profile.Integrations.SblBridge;

/// <summary>
/// Represents an implementation of <see cref="IUnitContactPointClient"/> using SBLBridge to obtain unit profile information.
/// </summary>
public class UnitProfileClient : IUnitProfileClient
{
private readonly ILogger<UnitProfileClient> _logger;
private readonly HttpClient _client;
private readonly JsonSerializerOptions _serializerOptions;

/// <summary>
/// Initializes a new instance of the <see cref="UnitProfileClient"/> class
/// </summary>
/// <param name="httpClient">HttpClient from default http client factory</param>
/// <param name="logger">the logger</param>
/// <param name="settings">the sbl bridge settings</param>
public UnitProfileClient(
HttpClient httpClient,
ILogger<UnitProfileClient> logger,
IOptions<SblBridgeSettings> settings)
{
_logger = logger;
_client = httpClient;
_client.BaseAddress = new Uri(settings.Value.ApiProfileEndpoint);

_serializerOptions = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNameCaseInsensitive = true,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
};
}

/// <inheritdoc />
public async Task<Result<UnitContactPointsList, bool>> 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 // An error occured when retrieving unit contact points. Failed with {statusCode}", response.StatusCode);

Check warning on line 58 in src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Use PascalCase for named placeholders. (https://rules.sonarsource.com/csharp/RSPEC-6678)

Check warning on line 58 in src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Use PascalCase for named placeholders. (https://rules.sonarsource.com/csharp/RSPEC-6678)

Check warning on line 58 in src/Altinn.Profile.Integrations/SblBridge/UnitProfileClient.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Use PascalCase for named placeholders. (https://rules.sonarsource.com/csharp/RSPEC-6678)
return false;
}

string content = await response.Content.ReadAsStringAsync();
List<PartyNotificationContactPoints> partyNotificationEndpoints = JsonSerializer.Deserialize<List<PartyNotificationContactPoints>>(content, _serializerOptions)!;

List<UnitContactPoints> contactPoints = partyNotificationEndpoints.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 };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public static void AddSblBridgeClients(this IServiceCollection services, IConfig
.Get<SblBridgeSettings>()
?? throw new ArgumentNullException(nameof(config), "Required SblBridgeSettings is missing from application configuration");

services
.Configure<SblBridgeSettings>(config.GetSection(nameof(SblBridgeSettings)))
.AddHttpClient<IUserProfileClient, UserProfileClient>();
services.Configure<SblBridgeSettings>(config.GetSection(nameof(SblBridgeSettings)));
services.AddHttpClient<IUserProfileClient, UserProfileClient>();
services.AddHttpClient<IUnitProfileClient, UnitProfileClient>();
}
}
45 changes: 45 additions & 0 deletions src/Altinn.Profile/Controllers/UnitContactPointController.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Controller for unit profile contact point API endpoints for internal consumption (e.g. Notifications) requiring neither authenticated user token nor access token authorization.
/// </summary>
[Route("profile/api/v1/units/contactpoint")]
[ApiExplorerSettings(IgnoreApi = true)]
[Consumes("application/json")]
[Produces("application/json")]
public class UnitContactPointController : ControllerBase
{
private readonly IUnitContactPoints _contactPointService;

/// <summary>
/// Initializes a new instance of the <see cref="UnitContactPointController"/> class.
/// </summary>
public UnitContactPointController(IUnitContactPoints contactPointsService)
{
_contactPointService = contactPointsService;
}

/// <summary>
/// Endpoint looking up the contact points for the units provided in the lookup object in the request body
/// </summary>
/// <returns>Returns an overview of the user registered contact points for the provided units and given resource</returns>
[HttpPost("lookup")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<UnitContactPointsList>> PostLookup([FromBody] UnitContactPointLookup unitContactPointLookup)
{
Result<UnitContactPointsList, bool> result = await _contactPointService.GetUserRegisteredContactPoints(unitContactPointLookup);
return result.Match<ActionResult<UnitContactPointsList>>(
success => Ok(success),
_ => Problem("Could not retrieve contact points"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Altinn.Profile.Core.User.ContactPoints;
using System.Collections.Generic;

namespace Altinn.Profile.Models;

/// <summary>
/// A class respresenting a user contact point lookup object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 0dbabbd

Please sign in to comment.