diff --git a/src/Altinn.App.Api/Controllers/ResourceController.cs b/src/Altinn.App.Api/Controllers/ResourceController.cs
index e38ad0cc8e..c7e0d18320 100644
--- a/src/Altinn.App.Api/Controllers/ResourceController.cs
+++ b/src/Altinn.App.Api/Controllers/ResourceController.cs
@@ -1,3 +1,4 @@
+using Altinn.App.Core.Features;
using Altinn.App.Core.Helpers;
using Altinn.App.Core.Internal.App;
using Microsoft.AspNetCore.Mvc;
@@ -11,14 +12,17 @@ namespace Altinn.App.Api.Controllers;
public class ResourceController : ControllerBase
{
private readonly IAppResources _appResourceService;
+ private readonly AppImplementationFactory _appImplementationFactory;
///
/// Initializes a new instance of the class
///
/// The execution service
- public ResourceController(IAppResources appResourcesService)
+ /// The service provider
+ public ResourceController(IAppResources appResourcesService, IServiceProvider serviceProvider)
{
_appResourceService = appResourcesService;
+ _appImplementationFactory = serviceProvider.GetRequiredService();
}
///
@@ -71,6 +75,44 @@ public ActionResult GetLayouts(string org, string app, string id)
return Ok(layouts);
}
+ ///
+ /// Endpoint for layouts with instance context.
+ /// Uses ICustomLayoutForInstance if implemented with IAppResources as fallback.
+ ///
+ /// The application owner short name
+ /// The application name
+ /// The instance owner party id
+ /// The instance id
+ /// The layout set id
+ /// A collection of FormLayout objects in JSON format.
+ [ProducesResponseType(typeof(string), StatusCodes.Status200OK, "application/json")]
+ [HttpGet]
+ [Route("{org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layouts/{layoutSetId}")]
+ public async Task GetInstanceLayouts(
+ string org,
+ string app,
+ int instanceOwnerPartyId,
+ string instanceId,
+ string layoutSetId
+ )
+ {
+ ICustomLayoutForInstance? customLayoutService = _appImplementationFactory.Get();
+ if (customLayoutService is not null)
+ {
+ string? customLayout = await customLayoutService.GetCustomLayoutForInstance(
+ layoutSetId,
+ instanceOwnerPartyId,
+ Guid.Parse(instanceId)
+ );
+ if (customLayout is not null)
+ {
+ return Ok(customLayout);
+ }
+ }
+ string layouts = _appResourceService.GetLayoutsForSet(layoutSetId);
+ return Ok(layouts);
+ }
+
///
/// Get the layout settings.
///
@@ -86,6 +128,44 @@ public ActionResult GetLayoutSettings(string org, string app)
return Ok(settings);
}
+ ///
+ /// Endpoint for layout settings with instance context.
+ /// Uses ICustomLayoutForInstance if implemented with IAppResources as fallback.
+ ///
+ /// The application owner short name
+ /// The application name
+ /// The instance owner party id
+ /// The instance id
+ /// The layout set id
+ /// The settings in the form of a string.
+ [ProducesResponseType(typeof(string), StatusCodes.Status200OK, "application/json")]
+ [HttpGet]
+ [Route("{org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layoutsettings/{layoutSetId}")]
+ public async Task GetInstanceLayoutSettings(
+ string org,
+ string app,
+ int instanceOwnerPartyId,
+ string instanceId,
+ string layoutSetId
+ )
+ {
+ ICustomLayoutForInstance? customLayoutService = _appImplementationFactory.Get();
+ if (customLayoutService is not null)
+ {
+ string? customLayoutSettings = await customLayoutService.GetCustomLayoutSettingsForInstance(
+ layoutSetId,
+ instanceOwnerPartyId,
+ Guid.Parse(instanceId)
+ );
+ if (customLayoutSettings is not null)
+ {
+ return Ok(customLayoutSettings);
+ }
+ }
+ string? settings = _appResourceService.GetLayoutSettingsStringForSet(layoutSetId);
+ return Ok(settings);
+ }
+
///
/// Get the layout settings.
///
diff --git a/src/Altinn.App.Core/Features/FeatureFlags.cs b/src/Altinn.App.Core/Features/FeatureFlags.cs
index 402dbc4509..a5373e2ff2 100644
--- a/src/Altinn.App.Core/Features/FeatureFlags.cs
+++ b/src/Altinn.App.Core/Features/FeatureFlags.cs
@@ -12,4 +12,11 @@ public static class FeatureFlags
/// return validation errors in the response body instead of a string.
///
public const string JsonObjectInDataResponse = "JsonObjectInDataResponse";
+
+ // TODO: write a better summary here
+ ///
+ /// Enabling this feature changes backend endpoint used for layouts to
+ /// add instance identifier.
+ ///
+ public const string AddInstanceIdentifierToLayoutRequests = "AddInstanceIdentifierToLayoutRequests";
}
diff --git a/src/Altinn.App.Core/Internal/App/FrontendFeatures.cs b/src/Altinn.App.Core/Internal/App/FrontendFeatures.cs
index 45c975a29f..e19f9037a3 100644
--- a/src/Altinn.App.Core/Internal/App/FrontendFeatures.cs
+++ b/src/Altinn.App.Core/Internal/App/FrontendFeatures.cs
@@ -26,6 +26,15 @@ public FrontendFeatures(IFeatureManager featureManager)
{
_features.Add("jsonObjectInDataResponse", false);
}
+
+ if (featureManager.IsEnabledAsync(FeatureFlags.AddInstanceIdentifierToLayoutRequests).Result)
+ {
+ _features.Add("addInstanceIdentifierToLayoutRequests", true);
+ }
+ else
+ {
+ _features.Add("addInstanceIdentifierToLayoutRequests", false);
+ }
}
///
diff --git a/src/Altinn.App.Core/Internal/App/ICustomLayoutForInstance.cs b/src/Altinn.App.Core/Internal/App/ICustomLayoutForInstance.cs
new file mode 100644
index 0000000000..0c1745b098
--- /dev/null
+++ b/src/Altinn.App.Core/Internal/App/ICustomLayoutForInstance.cs
@@ -0,0 +1,26 @@
+using Altinn.App.Core.Features;
+
+namespace Altinn.App.Core.Internal.App;
+
+///
+/// Interface for getting custom layouts for an instance.
+///
+[ImplementableByApps]
+public interface ICustomLayoutForInstance
+{
+ ///
+ /// Gets the custom layout
+ ///
+ /// The layout set ID
+ /// The instance owner party ID
+ /// The instance GUID
+ Task GetCustomLayoutForInstance(string layoutSetId, int instanceOwnerPartyId, Guid instanceGuid);
+
+ ///
+ /// Gets the custom layout settings
+ ///
+ /// The layout set ID
+ /// The instance owner party ID
+ /// The instance GUID
+ Task GetCustomLayoutSettingsForInstance(string layoutSetId, int instanceOwnerPartyId, Guid instanceGuid);
+}
diff --git a/src/Altinn.App.Core/Models/DataElementIdentifier.cs b/src/Altinn.App.Core/Models/DataElementIdentifier.cs
index ca5a655ea4..194a7efbd5 100644
--- a/src/Altinn.App.Core/Models/DataElementIdentifier.cs
+++ b/src/Altinn.App.Core/Models/DataElementIdentifier.cs
@@ -55,7 +55,8 @@ public DataElementIdentifier(DataElement dataElement)
///
/// Implicit conversion to allow DataElements to be used as DataElementIds
///
- public static implicit operator DataElementIdentifier(DataElement dataElement) => new(dataElement);
+ public static implicit operator DataElementIdentifier(DataElement dataElement) =>
+ dataElement is null ? throw new ArgumentNullException(nameof(dataElement)) : new(dataElement);
///
/// Implicit conversion to allow DataElements to be used as DataElementIds,
diff --git a/test/Altinn.App.Api.Tests/Controllers/ResourceController_CustomLayoutTests.cs b/test/Altinn.App.Api.Tests/Controllers/ResourceController_CustomLayoutTests.cs
new file mode 100644
index 0000000000..a0c6fc37f7
--- /dev/null
+++ b/test/Altinn.App.Api.Tests/Controllers/ResourceController_CustomLayoutTests.cs
@@ -0,0 +1,131 @@
+using System.Net;
+using System.Text.Json;
+using Altinn.App.Api.Tests.Data;
+using Altinn.App.Core.Internal.App;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit.Abstractions;
+
+namespace Altinn.App.Api.Tests.Controllers;
+
+public class ResourceController_CustomLayoutTests : ApiTestBase, IClassFixture>
+{
+ public ResourceController_CustomLayoutTests(WebApplicationFactory factory, ITestOutputHelper outputHelper)
+ : base(factory, outputHelper) { }
+
+ private class CustomLayoutForInstance : ICustomLayoutForInstance
+ {
+ public Task GetCustomLayoutForInstance(string layoutSetId, int instanceOwnerPartyId, Guid instanceId)
+ {
+ return Task.FromResult(instanceId.ToString());
+ }
+
+ public Task GetCustomLayoutSettingsForInstance(
+ string layoutSetId,
+ int instanceOwnerPartyId,
+ Guid instanceId
+ )
+ {
+ return Task.FromResult(instanceId.ToString());
+ }
+ }
+
+ [Fact]
+ public async Task GetLayoutsForSet_WithCustomLayoutForInstanceService_ReturnsOk()
+ {
+ OverrideServicesForThisTest = (services) =>
+ {
+ services.AddSingleton();
+ };
+
+ string org = "tdd";
+ string app = "contributer-restriction";
+ int instanceOwnerPartyId = 500600;
+ Guid instanceGuid = Guid.Parse("cff1cb24-5bc1-4888-8e06-c634753c5144");
+ string layoutSetId = "default";
+ using HttpClient client = GetRootedUserClient(org, app, 1337, instanceOwnerPartyId);
+
+ TestData.PrepareInstance(org, app, instanceOwnerPartyId, instanceGuid);
+ var response = await client.GetAsync(
+ $"/{org}/{app}/instances/{instanceOwnerPartyId}/{instanceGuid}/layouts/{layoutSetId}"
+ );
+
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ var content = await response.Content.ReadAsStringAsync();
+ Assert.Equal(instanceGuid.ToString(), content);
+ }
+
+ [Fact]
+ public async Task GetLayoutsForSet_WithoutCustomLayoutForInstanceService_ReturnsOk()
+ {
+ string org = "tdd";
+ string app = "contributer-restriction";
+ int instanceOwnerPartyId = 500600;
+ Guid instanceGuid = Guid.Parse("cff1cb24-5bc1-4888-8e06-c634753c5144");
+ string layoutSetId = "default";
+ using HttpClient client = GetRootedUserClient(org, app, 1337, instanceOwnerPartyId);
+
+ TestData.PrepareInstance(org, app, instanceOwnerPartyId, instanceGuid);
+ var response = await client.GetAsync(
+ $"/{org}/{app}/instances/{instanceOwnerPartyId}/{instanceGuid}/layouts/{layoutSetId}"
+ );
+
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ var content = await response.Content.ReadAsStringAsync();
+ using var jsonDoc = JsonDocument.Parse(content);
+ var root = jsonDoc.RootElement;
+ Assert.Equal(JsonValueKind.Object, root.ValueKind);
+ Assert.True(root.TryGetProperty("page", out var pageLayout));
+ Assert.True(pageLayout.TryGetProperty("data", out var data));
+ Assert.True(data.TryGetProperty("layout", out var layout));
+ Assert.Equal(JsonValueKind.Array, layout.ValueKind);
+ Assert.True(layout.GetArrayLength() > 0);
+ }
+
+ [Fact]
+ public async Task GetLayoutSettingsForSet_WithCustomLayoutForInstanceService_ReturnsOk()
+ {
+ OverrideServicesForThisTest = (services) =>
+ {
+ services.AddSingleton();
+ };
+
+ string org = "tdd";
+ string app = "contributer-restriction";
+ int instanceOwnerPartyId = 500600;
+ Guid instanceGuid = Guid.Parse("cff1cb24-5bc1-4888-8e06-c634753c5144");
+ string layoutSetId = "default";
+ using HttpClient client = GetRootedUserClient(org, app, 1337, instanceOwnerPartyId);
+
+ TestData.PrepareInstance(org, app, instanceOwnerPartyId, instanceGuid);
+ var response = await client.GetAsync(
+ $"/{org}/{app}/instances/{instanceOwnerPartyId}/{instanceGuid}/layoutsettings/{layoutSetId}"
+ );
+
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ var content = await response.Content.ReadAsStringAsync();
+ Assert.Equal(instanceGuid.ToString(), content);
+ }
+
+ [Fact]
+ public async Task GetLayoutSettingsForSet_WithoutCustomLayoutForInstanceService_ReturnsOk()
+ {
+ string org = "tdd";
+ string app = "contributer-restriction";
+ int instanceOwnerPartyId = 500600;
+ Guid instanceGuid = Guid.Parse("cff1cb24-5bc1-4888-8e06-c634753c5144");
+ string layoutSetId = "default";
+ using HttpClient client = GetRootedUserClient(org, app, 1337, instanceOwnerPartyId);
+
+ TestData.PrepareInstance(org, app, instanceOwnerPartyId, instanceGuid);
+ var response = await client.GetAsync(
+ $"/{org}/{app}/instances/{instanceOwnerPartyId}/{instanceGuid}/layoutsettings/{layoutSetId}"
+ );
+
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ var content = await response.Content.ReadAsStringAsync();
+ using var jsonDoc = JsonDocument.Parse(content);
+ var root = jsonDoc.RootElement;
+ Assert.Equal(JsonValueKind.Object, root.ValueKind);
+ }
+}
diff --git a/test/Altinn.App.Api.Tests/OpenApi/OpenApiSpecChangeDetection.SaveJsonSwagger.verified.json b/test/Altinn.App.Api.Tests/OpenApi/OpenApiSpecChangeDetection.SaveJsonSwagger.verified.json
index 488438728d..97f4fcbe7c 100644
--- a/test/Altinn.App.Api.Tests/OpenApi/OpenApiSpecChangeDetection.SaveJsonSwagger.verified.json
+++ b/test/Altinn.App.Api.Tests/OpenApi/OpenApiSpecChangeDetection.SaveJsonSwagger.verified.json
@@ -5440,6 +5440,74 @@
}
}
},
+ "/{org}/{app}/instances/{instanceOwnerPartyId}/{instanceId}/layouts/{layoutSetId}": {
+ "get": {
+ "tags": [
+ "Resource"
+ ],
+ "summary": "Endpoint for layouts with instance context.\nUses ICustomLayoutForInstance if implemented with IAppResources as fallback.",
+ "parameters": [
+ {
+ "name": "org",
+ "in": "path",
+ "description": "The application owner short name",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "app",
+ "in": "path",
+ "description": "The application name",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "instanceOwnerPartyId",
+ "in": "path",
+ "description": "The instance owner party id",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ {
+ "name": "instanceId",
+ "in": "path",
+ "description": "The instance id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "layoutSetId",
+ "in": "path",
+ "description": "The layout set id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/{org}/{app}/api/layoutsettings": {
"get": {
"tags": [
@@ -5480,6 +5548,74 @@
}
}
},
+ "/{org}/{app}/instances/{instanceOwnerPartyId}/{instanceId}/layoutsettings/{layoutSetId}": {
+ "get": {
+ "tags": [
+ "Resource"
+ ],
+ "summary": "Endpoint for layout settings with instance context.\nUses ICustomLayoutForInstance if implemented with IAppResources as fallback.",
+ "parameters": [
+ {
+ "name": "org",
+ "in": "path",
+ "description": "The application owner short name",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "app",
+ "in": "path",
+ "description": "The application name",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "instanceOwnerPartyId",
+ "in": "path",
+ "description": "The instance owner party id",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ {
+ "name": "instanceId",
+ "in": "path",
+ "description": "The instance id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "layoutSetId",
+ "in": "path",
+ "description": "The layout set id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/{org}/{app}/api/layoutsettings/{id}": {
"get": {
"tags": [
diff --git a/test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt b/test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
index fb9c76b447..9b0af95cea 100644
--- a/test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
+++ b/test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
@@ -523,7 +523,7 @@ namespace Altinn.App.Api.Controllers
[Microsoft.AspNetCore.Mvc.ApiController]
public class ResourceController : Microsoft.AspNetCore.Mvc.ControllerBase
{
- public ResourceController(Altinn.App.Core.Internal.App.IAppResources appResourcesService) { }
+ public ResourceController(Altinn.App.Core.Internal.App.IAppResources appResourcesService, System.IServiceProvider serviceProvider) { }
[Microsoft.AspNetCore.Mvc.HttpGet]
[Microsoft.AspNetCore.Mvc.ProducesResponseType(204)]
[Microsoft.AspNetCore.Mvc.ProducesResponseType(typeof(string), 200, "application/json", new string[0])]
@@ -531,6 +531,16 @@ namespace Altinn.App.Api.Controllers
public System.Threading.Tasks.Task GetFooterLayout(string org, string app) { }
[Microsoft.AspNetCore.Mvc.HttpGet]
[Microsoft.AspNetCore.Mvc.ProducesResponseType(typeof(string), 200, "application/json", new string[0])]
+ [Microsoft.AspNetCore.Mvc.Route("{org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layoutsettings/{lay" +
+ "outSetId}")]
+ public System.Threading.Tasks.Task GetInstanceLayoutSettings(string org, string app, int instanceOwnerPartyId, string instanceId, string layoutSetId) { }
+ [Microsoft.AspNetCore.Mvc.HttpGet]
+ [Microsoft.AspNetCore.Mvc.ProducesResponseType(typeof(string), 200, "application/json", new string[0])]
+ [Microsoft.AspNetCore.Mvc.Route("{org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layouts/{layoutSetI" +
+ "d}")]
+ public System.Threading.Tasks.Task GetInstanceLayouts(string org, string app, int instanceOwnerPartyId, string instanceId, string layoutSetId) { }
+ [Microsoft.AspNetCore.Mvc.HttpGet]
+ [Microsoft.AspNetCore.Mvc.ProducesResponseType(typeof(string), 200, "application/json", new string[0])]
[Microsoft.AspNetCore.Mvc.Route("{org}/{app}/api/layoutsets")]
public Microsoft.AspNetCore.Mvc.ActionResult GetLayoutSets(string org, string app) { }
[Microsoft.AspNetCore.Mvc.HttpGet]
diff --git a/test/Altinn.App.Core.Tests/Internal/App/AppMetadataTest.GetApplicationMetadata_deserialize_serialize_unmapped_properties.verified.txt b/test/Altinn.App.Core.Tests/Internal/App/AppMetadataTest.GetApplicationMetadata_deserialize_serialize_unmapped_properties.verified.txt
index e847f790dc..9ebfdf0b25 100644
--- a/test/Altinn.App.Core.Tests/Internal/App/AppMetadataTest.GetApplicationMetadata_deserialize_serialize_unmapped_properties.verified.txt
+++ b/test/Altinn.App.Core.Tests/Internal/App/AppMetadataTest.GetApplicationMetadata_deserialize_serialize_unmapped_properties.verified.txt
@@ -3,7 +3,8 @@
"Features": {
"footer": true,
"processActions": true,
- "jsonObjectInDataResponse": false
+ "jsonObjectInDataResponse": false,
+ "addInstanceIdentifierToLayoutRequests": false
},
"OnEntry": {
"InstanceSelection": null,
diff --git a/test/Altinn.App.Core.Tests/Internal/App/FrontendFeaturesTest.cs b/test/Altinn.App.Core.Tests/Internal/App/FrontendFeaturesTest.cs
index b5f6f5f747..95c27b0816 100644
--- a/test/Altinn.App.Core.Tests/Internal/App/FrontendFeaturesTest.cs
+++ b/test/Altinn.App.Core.Tests/Internal/App/FrontendFeaturesTest.cs
@@ -17,6 +17,7 @@ public async Task GetFeatures_returns_list_of_enabled_features()
{ "footer", true },
{ "processActions", true },
{ "jsonObjectInDataResponse", false },
+ { "addInstanceIdentifierToLayoutRequests", false },
};
var featureManagerMock = new Mock();
IFrontendFeatures frontendFeatures = new FrontendFeatures(featureManagerMock.Object);
@@ -34,9 +35,13 @@ public async Task GetFeatures_returns_list_of_enabled_features_when_feature_flag
{ "footer", true },
{ "processActions", true },
{ "jsonObjectInDataResponse", true },
+ { "addInstanceIdentifierToLayoutRequests", true },
};
var featureManagerMock = new Mock();
featureManagerMock.Setup(f => f.IsEnabledAsync(FeatureFlags.JsonObjectInDataResponse)).ReturnsAsync(true);
+ featureManagerMock
+ .Setup(f => f.IsEnabledAsync(FeatureFlags.AddInstanceIdentifierToLayoutRequests))
+ .ReturnsAsync(true);
IFrontendFeatures frontendFeatures = new FrontendFeatures(featureManagerMock.Object);
var actual = await frontendFeatures.GetFrontendFeatures();
actual.Should().BeEquivalentTo(expected);
diff --git a/test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt b/test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
index ec33a03324..7164f6b0c0 100644
--- a/test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
+++ b/test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
@@ -1150,6 +1150,7 @@ namespace Altinn.App.Core.Features
}
public static class FeatureFlags
{
+ public const string AddInstanceIdentifierToLayoutRequests = "AddInstanceIdentifierToLayoutRequests";
public const string JsonObjectInDataResponse = "JsonObjectInDataResponse";
}
public interface IAppOptionsProvider
@@ -2930,6 +2931,11 @@ namespace Altinn.App.Core.Internal.App
{
System.Threading.Tasks.Task GetApplication(string org, string app);
}
+ public interface ICustomLayoutForInstance
+ {
+ System.Threading.Tasks.Task GetCustomLayoutForInstance(string layoutSetId, int instanceOwnerPartyId, System.Guid instanceGuid);
+ System.Threading.Tasks.Task GetCustomLayoutSettingsForInstance(string layoutSetId, int instanceOwnerPartyId, System.Guid instanceGuid);
+ }
public interface IFrontendFeatures
{
System.Threading.Tasks.Task> GetFrontendFeatures();
diff --git a/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Custom_0_Metadata.verified.txt b/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Custom_0_Metadata.verified.txt
index 4f24127ecb..f5216f4b51 100644
--- a/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Custom_0_Metadata.verified.txt
+++ b/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Custom_0_Metadata.verified.txt
@@ -715,6 +715,34 @@
]
}
},
+ {
+ endpoint: GET {org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layouts/{layoutSetId},
+ metadata: {
+ errorMessageTextResourceKeyUser: authorization.scopes.insufficient,
+ errorMessageTextResourceKeyServiceOwner: authorization.scopes.insufficient,
+ requiredScopesUsers: [
+ custom:instances.read,
+ altinn:portal/enduser
+ ],
+ requiredScopesServiceOwners: [
+ custom:serviceowner/instances.read
+ ]
+ }
+ },
+ {
+ endpoint: GET {org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layoutsettings/{layoutSetId},
+ metadata: {
+ errorMessageTextResourceKeyUser: authorization.scopes.insufficient,
+ errorMessageTextResourceKeyServiceOwner: authorization.scopes.insufficient,
+ requiredScopesUsers: [
+ custom:instances.read,
+ altinn:portal/enduser
+ ],
+ requiredScopesServiceOwners: [
+ custom:serviceowner/instances.read
+ ]
+ }
+ },
{
endpoint: GET {org}/{app}/legacy/instances/{instanceOwnerPartyId:int}/{instanceGuid:guid}/copy,
metadata: {
diff --git a/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Standard_0_Metadata.verified.txt b/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Standard_0_Metadata.verified.txt
index 3ae594f897..a6cdcb811a 100644
--- a/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Standard_0_Metadata.verified.txt
+++ b/test/Altinn.App.Integration.Tests/CustomScopes/_snapshots/CustomScopesTests.Metadata_Standard_0_Metadata.verified.txt
@@ -580,6 +580,24 @@
requiredScopesServiceOwners: null
}
},
+ {
+ endpoint: GET {org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layouts/{layoutSetId},
+ metadata: {
+ errorMessageTextResourceKeyUser: null,
+ errorMessageTextResourceKeyServiceOwner: null,
+ requiredScopesUsers: null,
+ requiredScopesServiceOwners: null
+ }
+ },
+ {
+ endpoint: GET {org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceId}/layoutsettings/{layoutSetId},
+ metadata: {
+ errorMessageTextResourceKeyUser: null,
+ errorMessageTextResourceKeyServiceOwner: null,
+ requiredScopesUsers: null,
+ requiredScopesServiceOwners: null
+ }
+ },
{
endpoint: GET {org}/{app}/legacy/instances/{instanceOwnerPartyId:int}/{instanceGuid:guid}/copy,
metadata: {
diff --git a/test/Altinn.App.Integration.Tests/PartyTypesAllowed/_snapshots/SubunitOnlyAppTests.ApplicationMetadata_0.verified.txt b/test/Altinn.App.Integration.Tests/PartyTypesAllowed/_snapshots/SubunitOnlyAppTests.ApplicationMetadata_0.verified.txt
index 490482384b..abf291d5c2 100644
--- a/test/Altinn.App.Integration.Tests/PartyTypesAllowed/_snapshots/SubunitOnlyAppTests.ApplicationMetadata_0.verified.txt
+++ b/test/Altinn.App.Integration.Tests/PartyTypesAllowed/_snapshots/SubunitOnlyAppTests.ApplicationMetadata_0.verified.txt
@@ -55,6 +55,7 @@
Response: {
Id: ttd/basic,
Features: {
+ addInstanceIdentifierToLayoutRequests: false,
footer: true,
jsonObjectInDataResponse: false,
processActions: true