diff --git a/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs b/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs index 14e1300f3c..a6cde93c0c 100644 --- a/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs +++ b/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs @@ -62,5 +62,7 @@ public ListedCapabilityStatement() public IDictionary AdditionalData { get; } public ICollection Profile { get; } + + public ICollection Instantiates { get; internal set; } } } diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs b/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs index 028897374e..6fb147f142 100644 --- a/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs +++ b/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs @@ -216,6 +216,12 @@ ResourceElement SetMetadata(Resource resource, string versionId, DateTimeOffset services.AddTransient(typeof(IScopeProvider<>), typeof(ScopeProvider<>)); services.AddScoped(); + + services.TypesInSameAssembly(KnownAssemblies.All) + .AssignableTo() + .Transient() + .AsService(); + services.AddFactory>>(); } } } diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs new file mode 100644 index 0000000000..33daad5f93 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs @@ -0,0 +1,114 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Health.Extensions.DependencyInjection; +using Microsoft.Health.Fhir.Core.Features.Conformance; +using Microsoft.Health.Fhir.Core.Features.Conformance.Models; +using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; +using Microsoft.Health.Fhir.Tests.Common; +using Microsoft.Health.Test.Utilities; +using NSubstitute; +using Xunit; + +namespace Microsoft.Health.Fhir.Shared.Core.UnitTests.Features.Conformance +{ + [Trait(Traits.OwningTeam, OwningTeam.Fhir)] + [Trait(Traits.Category, Categories.Conformance)] + public class InstantiatesCapabilityProviderTests + { + private readonly InstantiatesCapabilityProvider _provider; + private readonly List _capabilities; + + public InstantiatesCapabilityProviderTests() + { + _capabilities = new List(); + var s = Substitute.For>>(); + s.Value.Returns(_capabilities); + + _provider = new InstantiatesCapabilityProvider(() => s); + } + + [Theory] + [InlineData(1)] + [InlineData(0)] + [InlineData(1, 0)] + [InlineData(0, 0, 0)] + [InlineData(1, 2, 3, 4)] + [InlineData(1, 0, 3, 0)] + public async Task GivenCapabilities_WhenBuilding_ThenInstantiatesFieldIsPopulated( + params int[] counts) + { + var urls = AddCapabilities(counts); + var instantiates = new HashSet(StringComparer.OrdinalIgnoreCase); + var builder = Substitute.For(); + builder.Apply(Arg.Any>()).Returns( + x => + { + var action = (Action)x[0]; + var statement = new ListedCapabilityStatement(); + action(statement); + if (statement.Instantiates != null) + { + foreach (var i in statement.Instantiates) + { + instantiates.Add(i); + } + } + + return builder; + }); + + await _provider.BuildAsync(builder, CancellationToken.None); + + Assert.Equal(urls.Count, instantiates.Count); + Assert.All( + urls, + x => + { + Assert.Contains(x, instantiates); + }); + _capabilities.ForEach(x => x.Received(1).TryGetUrls(out Arg.Any>())); + builder.Received(urls.Any() ? 1 : 0).Apply(Arg.Any>()); + } + + private List AddCapabilities(int[] counts) + { + _capabilities.Clear(); + var capabilityUrls = new List(); + var i = 0; + foreach (var count in counts) + { + var app = $"app{i}"; + var urls = Enumerable.Range(0, count).Select(x => $"http://hl7.org/fhir/{app}/CapabilityStatement/{x}"); + var cap = Substitute.For(); + cap.TryGetUrls(out Arg.Any>()).Returns( + x => + { + var c = count; + var copy = new List(urls); + if (c > 0) + { + x[0] = copy; + return true; + } + + x[0] = null; + return false; + }); + + _capabilities.Add(cap); + capabilityUrls.AddRange(urls); + i++; + } + + return capabilityUrls; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs new file mode 100644 index 0000000000..f0234d2a68 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using Microsoft.Extensions.Options; +using Microsoft.Health.Fhir.Core.Configs; +using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; +using Microsoft.Health.Fhir.Tests.Common; +using Microsoft.Health.Test.Utilities; +using Xunit; + +namespace Microsoft.Health.Fhir.Shared.Core.UnitTests.Features.Conformance +{ + [Trait(Traits.OwningTeam, OwningTeam.Fhir)] + [Trait(Traits.Category, Categories.Conformance)] + public class SmartV2InstantiateCapabilityTests + { + [Theory] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public void GivenSecurityConfiguration_WhenSmartV2IsEnabled_ThenInstantiateCapabilityUrlsAreReturned( + bool enabled, + bool enabledWithout) + { + var securityConfiguration = new SecurityConfiguration + { + Authorization = new AuthorizationConfiguration + { + Enabled = enabled, + EnableSmartWithoutAuth = enabledWithout, + }, + }; + + var instantiateCapability = new SmartV2InstantiateCapability( + Options.Create(securityConfiguration)); + if (instantiateCapability.TryGetUrls(out var urls)) + { + Assert.True(enabled || enabledWithout); + Assert.NotNull(urls); + Assert.NotEmpty(urls); + } + else + { + Assert.False(enabled || enabledWithout); + Assert.Null(urls); + } + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems index b25b7cc9c7..194f74dfa7 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems @@ -18,6 +18,8 @@ + + diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/IInstantiateCapability.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/IInstantiateCapability.cs new file mode 100644 index 0000000000..dfa2366b92 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/IInstantiateCapability.cs @@ -0,0 +1,14 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Collections.Generic; + +namespace Microsoft.Health.Fhir.Shared.Core.Features.Conformance +{ + public interface IInstantiateCapability + { + bool TryGetUrls(out IEnumerable urls); + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs new file mode 100644 index 0000000000..0839d9b258 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs @@ -0,0 +1,60 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using EnsureThat; +using Microsoft.Health.Extensions.DependencyInjection; +using Microsoft.Health.Fhir.Core.Features.Conformance; + +namespace Microsoft.Health.Fhir.Shared.Core.Features.Conformance +{ + public class InstantiatesCapabilityProvider : IProvideCapability + { + private readonly Func>> _instantiateCapabilityDelegate; + + public InstantiatesCapabilityProvider( + Func>> instantiateCapabilityDelegate) + { + EnsureArg.IsNotNull(instantiateCapabilityDelegate, nameof(instantiateCapabilityDelegate)); + + _instantiateCapabilityDelegate = instantiateCapabilityDelegate; + } + + public Task BuildAsync( + ICapabilityStatementBuilder builder, + CancellationToken cancellationToken) + { + EnsureArg.IsNotNull(builder, nameof(builder)); + + var instantiateUrls = new HashSet(StringComparer.OrdinalIgnoreCase); + using var instantiates = _instantiateCapabilityDelegate(); + foreach (var instantiate in instantiates.Value) + { + if (instantiate.TryGetUrls(out var urls) && urls != null && urls.Any()) + { + foreach (var url in urls) + { + instantiateUrls.Add(url); + } + } + } + + if (instantiateUrls.Any()) + { + builder.Apply( + x => + { + x.Instantiates = instantiateUrls; + }); + } + + return Task.CompletedTask; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs new file mode 100644 index 0000000000..78a84ecef4 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Collections.Generic; +using EnsureThat; +using Microsoft.Extensions.Options; +using Microsoft.Health.Fhir.Core.Configs; + +namespace Microsoft.Health.Fhir.Shared.Core.Features.Conformance +{ + public class SmartV2InstantiateCapability : IInstantiateCapability + { + private static readonly string[] Urls = + { + "http://hl7.org/fhir/smart-app-launch/CapabilityStatement/smart-app-state-server", + }; + + private readonly SecurityConfiguration _securityConfiguration; + + public SmartV2InstantiateCapability(IOptions securityConfiguration) + { + EnsureArg.IsNotNull(securityConfiguration?.Value, nameof(securityConfiguration)); + + _securityConfiguration = securityConfiguration.Value; + } + + public bool TryGetUrls(out IEnumerable urls) + { + urls = null; + if (_securityConfiguration.Authorization.Enabled + || _securityConfiguration.Authorization.EnableSmartWithoutAuth) + { + urls = Urls; + return true; + } + + return false; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/USCore6InstantiateCapability.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/USCore6InstantiateCapability.cs new file mode 100644 index 0000000000..850786c806 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/USCore6InstantiateCapability.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Collections.Generic; +using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; + +namespace Microsoft.Health.Fhir.Core.Features.Conformance +{ + public class USCore6InstantiateCapability : IInstantiateCapability + { + private static readonly string[] Urls = + { + "http://hl7.org/fhir/us/core/CapabilityStatement/us-core-server", + }; + + public bool TryGetUrls(out IEnumerable urls) + { + urls = Urls; + return true; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems b/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems index db0242a3a9..066719b51c 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems +++ b/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems @@ -18,7 +18,11 @@ + + + +