Skip to content

Commit

Permalink
Add call to next step in process before completing
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronny Birkeli committed Nov 8, 2022
1 parent 1aa49b6 commit bc19964
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,32 +28,35 @@ public class EformidlingStatusCheckEventHandler : IEventHandler
{
private readonly IEFormidlingClient _eFormidlingClient;
private readonly ILogger<EformidlingStatusCheckEventHandler> _logger;
private readonly HttpClient _httpClient;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IMaskinportenService _maskinportenService;
private readonly MaskinportenSettings _maskinportenSettings;
private readonly IX509CertificateProvider _x509CertificateProvider;
private readonly PlatformSettings _platformSettings;
private readonly GeneralSettings _generalSettings;

/// <summary>
/// Initializes a new instance of the <see cref="EformidlingStatusCheckEventHandler"/> class.
/// </summary>
public EformidlingStatusCheckEventHandler(
IEFormidlingClient eFormidlingClient,
HttpClient httpClient,
IHttpClientFactory httpClientFactory,
ILogger<EformidlingStatusCheckEventHandler> logger,
IMaskinportenService maskinportenService,
IOptions<MaskinportenSettings> maskinportenSettings,
IX509CertificateProvider x509CertificateProvider,
IOptions<PlatformSettings> platformSettings
IOptions<PlatformSettings> platformSettings,
IOptions<GeneralSettings> generalSettings
)
{
_eFormidlingClient = eFormidlingClient;
_logger = logger;
_httpClient = httpClient;
_httpClientFactory = httpClientFactory;
_maskinportenService = maskinportenService;
_maskinportenSettings = maskinportenSettings.Value;
_x509CertificateProvider = x509CertificateProvider;
_platformSettings = platformSettings.Value;
_generalSettings = generalSettings.Value;
}

/// <inheritDoc/>
Expand All @@ -66,6 +69,7 @@ public async Task<bool> ProcessEvent(CloudEvent cloudEvent)

_logger.LogInformation("Received reminder for subject {subject}", subject);

AppIdentifier appIdentifier = AppIdentifier.CreateFromUrl(cloudEvent.Source.ToString());
InstanceIdentifier instanceIdentifier = InstanceIdentifier.CreateFromUrl(cloudEvent.Source.ToString());

// Instance GUID is used as shipment identifier
Expand All @@ -78,7 +82,8 @@ public async Task<bool> ProcessEvent(CloudEvent cloudEvent)
// Moving forward sending to Eformidling should considered as a ServiceTask with auto advance in the process
// when the message is confirmed.

_ = await AddCompleteConfirmation(instanceIdentifier.InstanceOwnerPartyId, instanceIdentifier.InstanceGuid);
await ProcessMoveNext(appIdentifier, instanceIdentifier);
_ = await AddCompleteConfirmation(instanceIdentifier);

return true;
}
Expand All @@ -102,23 +107,43 @@ public async Task<bool> ProcessEvent(CloudEvent cloudEvent)
// and be handled by the Platform team manually.
}

private async Task ProcessMoveNext(AppIdentifier appIdentifier, InstanceIdentifier instanceIdentifier)
{
string url = $"https://{appIdentifier.Org}.apps.{_generalSettings.HostName}/{appIdentifier}/instances/{instanceIdentifier}/process";

HttpClient httpClient = _httpClientFactory.CreateClient();

HttpResponseMessage response = await httpClient.PutAsync(url, new StringContent(string.Empty));

if (response.IsSuccessStatusCode)
{
_logger.LogInformation("Moved instance {instanceId} to next step.", instanceIdentifier);
}
else
{
_logger.LogError("Failed moving instance {instanceId} to next step.", instanceIdentifier);
}
}

/// This is basically a duplicate of the method in <see cref="InstanceClient"/>
/// Duplication is done since the original method requires an http context
/// with a logged on user/org, while we would like to authenticate against maskinporten
/// here and now and avoid calling out of the app and back into the app on the matching
/// endpoint in InstanceController. This method should be remove once we have a better
/// endpoint in InstanceController. This method should be removed once we have a better
/// alernative for authenticating the app/org without having a http request context with
/// a logged on user/org.
private async Task<Instance> AddCompleteConfirmation(int instanceOwnerPartyId, Guid instanceGuid)
private async Task<Instance> AddCompleteConfirmation(InstanceIdentifier instanceIdentifier)
{
string apiUrl = $"instances/{instanceOwnerPartyId}/{instanceGuid}/complete";
string url = $"instances/{instanceIdentifier.InstanceOwnerPartyId}/{instanceIdentifier.InstanceGuid}/complete";

TokenResponse altinnToken = await GetOrganizationToken();

_httpClient.BaseAddress = new Uri(_platformSettings.ApiStorageEndpoint);
_httpClient.DefaultRequestHeaders.Add(General.SubscriptionKeyHeaderName, _platformSettings.SubscriptionKey);
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await _httpClient.PostAsync(altinnToken.AccessToken, apiUrl, new StringContent(string.Empty));
HttpClient httpClient = _httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(_platformSettings.ApiStorageEndpoint);
httpClient.DefaultRequestHeaders.Add(General.SubscriptionKeyHeaderName, _platformSettings.SubscriptionKey);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

HttpResponseMessage response = await httpClient.PostAsync(altinnToken.AccessToken, url, new StringContent(string.Empty));

if (response.StatusCode == HttpStatusCode.OK)
{
Expand Down
34 changes: 34 additions & 0 deletions src/Altinn.App.Core/Models/AppIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,39 @@ public override int GetHashCode()
{
return Org.GetHashCode() ^ App.GetHashCode();
}

/// <summary>
/// A absolute url expected to point to an Altinn 3 app ie. the first two segments of the path
/// has to be the organization and the app name for example: https://org.apps.altinn.no/{org}/{app}/api/...
/// </summary>
/// <param name="url">The url to parse</param>
/// <returns>A new instance of <see cref="AppIdentifier"/></returns>
public static AppIdentifier CreateFromUrl(string url)
{
if (url == null)
{
throw new ArgumentNullException(nameof(url));
}

if (!Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
throw new ArgumentException($"The provided url ({url}) is not well formed. Please check that it is an absolute url with at least two path segments.");
}

Uri uri = new(url, UriKind.Absolute);

// Remove the first slash as this will only result in an empty first segment when splitting.
string[] segments = uri.PathAndQuery[1..].Split("/");

if (segments.Length < 2)
{
throw new ArgumentException($"The provided url ({url} must contain at least two path segments.)");
}

var org = segments[0];
var app = segments[1];

return new AppIdentifier(org, app);
}
}
}
12 changes: 10 additions & 2 deletions src/Altinn.App.Core/Models/InstanceIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ public static InstanceIdentifier CreateFromUrl(string url)

/// <summary>
/// Gets the instance id to be used when looking up this instance in storage api.
/// The url needs to conform to .../instances/{instanceOwerId}/{instanceOwnerGuid}/... pattern.
/// The url needs to conform to .../instances/{instanceOwnerId}/{instanceGuid}/... pattern.
/// </summary>
/// <returns>Instance id combinging instance owner and instance guid.</returns>
/// <returns>Instance id combining instance owner and instance guid.</returns>
public string GetInstanceId()
{
if (IsNoInstance)
Expand All @@ -84,6 +84,14 @@ public string GetInstanceId()
return $"{InstanceOwnerPartyId}/{InstanceGuid}";
}

/// <summary>
/// A string on the format {instanceOwnerId}/{instanceGuid} without leading or trailing slashes.
/// </summary>
public override string ToString()
{
return GetInstanceId();
}

/// <summary>
/// Deconstructs an instance id into it's two logical parts - instanceOwnerPartyId and instanceGuid.
/// Party represents either the person or the organization that owns the instance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private static CloudEvent GetValidCloudEvent()
private static EformidlingStatusCheckEventHandler GetMockedEventHandler()
{
var eFormidlingClientMock = new Mock<IEFormidlingClient>();
var httpClient = new Mock<HttpClient>();
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
var eFormidlingLoggerMock = new Mock<ILogger<EformidlingStatusCheckEventHandler>>();

var httpClientMock = new Mock<HttpClient>();
Expand All @@ -58,15 +58,18 @@ private static EformidlingStatusCheckEventHandler GetMockedEventHandler()
var maskinportenSettingsMock = new Mock<IOptions<MaskinportenSettings>>();
var x509CertificateProviderMock = new Mock<IX509CertificateProvider>();
var platformSettingsMock = new Mock<IOptions<PlatformSettings>>();
var generalSettingsMock = new Mock<IOptions<GeneralSettings>>();

EformidlingStatusCheckEventHandler eventHandler = new(
eFormidlingClientMock.Object,
httpClient.Object,
httpClientFactoryMock.Object,
eFormidlingLoggerMock.Object,
maskinportenServiceMock.Object,
maskinportenSettingsMock.Object,
x509CertificateProviderMock.Object,
platformSettingsMock.Object);
platformSettingsMock.Object,
generalSettingsMock.Object
);
return eventHandler;
}
}
Expand Down
20 changes: 20 additions & 0 deletions test/Altinn.App.Core.Tests/Models/AppIdentifierTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,26 @@ public void Constructor_Equals_ShouldBeEqual()
appIdentifier1.Should().BeEquivalentTo(appIdentifier2);
appIdentifier1.GetHashCode().Should().Be(appIdentifier2.GetHashCode());
}

[Theory]
[InlineData("https://dihe.apps.tt02.altinn.no/dihe/redusert-foreldrebetaling-bhg/api/v1/eventsreceiver?code=16eda4f0-653a-4fdc-b516-c4702392a4eb", "dihe", "redusert-foreldrebetaling-bhg")]
public void CreateFromUrl_ValidUrl_ShouldConstruct(string url, string expectedOrg, string expectedApp)
{
AppIdentifier appIdentifier = AppIdentifier.CreateFromUrl(url);

appIdentifier.Org.Should().Be(expectedOrg);
appIdentifier.App.Should().Be(expectedApp);
}

[Theory]
[InlineData("https://dihe.apps.tt02.altinn.no/dihe")]
[InlineData("dihe/redusert-foreldrebetaling-bhg")]
public void CreateFromUrl_InvalidUrl_ShouldThrowArgumentException(string url)
{
Action action = () => AppIdentifier.CreateFromUrl(url);

action.Should().Throw<ArgumentException>();
}
}

#pragma warning restore CA1806 // Do not ignore method results
Expand Down

0 comments on commit bc19964

Please sign in to comment.