diff --git a/.github/workflows/ci-cd-main.yml b/.github/workflows/ci-cd-main.yml index 6a126287b..630076309 100644 --- a/.github/workflows/ci-cd-main.yml +++ b/.github/workflows/ci-cd-main.yml @@ -98,10 +98,21 @@ jobs: version: ${{ needs.get-current-version.outputs.version }}-${{ needs.generate-git-short-sha.outputs.gitShortSha }} runMigration: ${{ github.event_name == 'workflow_dispatch' || needs.check-for-changes.outputs.hasMigrationChanges == 'true' }} +# publish-sdk-to-nuget: +# uses: ./.github/workflows/workflow-publish-nuget.yml +# needs: [ get-current-version, generate-git-short-sha, check-for-changes ] +# if: ${{ needs.check-for-changes.outputs.hasSwaggerSchemaChanges == 'true' }} +# with: +# version: ${{ needs.get-current-version.outputs.version }}-rc.${{ needs.generate-git-short-sha.outputs.gitShortSha }} +# path: 'src/Digdir.Library.Dialogporten.WebApiClient.csproj' +# source: 'https://api.nuget.org/v3/index.json' +# secrets: +# NUGET_API_KEY: ${{ secrets.NUGET_API_TEST_KEY }} + publish-schema-npm: name: Deploy schema npm package needs: [check-for-changes, get-current-version, generate-git-short-sha, deploy-apps] - if: ${{ always() && !failure() && !cancelled() && (github.event_name == 'workflow_dispatch' || needs.check-for-changes.outputs.hasSchemaChanges == 'true') }} + if: ${{ always() && !failure() && !cancelled() && (github.event_name == 'workflow_dispatch' || needs.check-for-changes.outputs.hasSwaggerSchemaChanges == 'true' || needs.check-for-changes.outputs.hasGqlSchemaChanges == 'true') }} uses: ./.github/workflows/workflow-publish-schema.yml with: version: ${{ needs.get-current-version.outputs.version }}-${{ needs.generate-git-short-sha.outputs.gitShortSha }} diff --git a/.github/workflows/ci-cd-pull-request.yml b/.github/workflows/ci-cd-pull-request.yml index 67d057123..96b6e0b71 100644 --- a/.github/workflows/ci-cd-pull-request.yml +++ b/.github/workflows/ci-cd-pull-request.yml @@ -2,10 +2,9 @@ on: pull_request: - branches: [main] + branches: [ main ] paths-ignore: - "tests/k6/**" - - "CHANGELOG.md" jobs: generate-git-short-sha: @@ -19,15 +18,15 @@ jobs: check-for-changes: name: Check for changes uses: ./.github/workflows/workflow-check-for-changes.yml - + build: uses: ./.github/workflows/workflow-build-and-test.yml - needs: [check-for-changes] + needs: [ check-for-changes ] if: ${{ needs.check-for-changes.outputs.hasBackendChanges == 'true' || needs.check-for-changes.outputs.hasTestChanges == 'true' }} build-infrastructure: uses: ./.github/workflows/workflow-build-infrastructure.yml - needs: [check-for-changes] + needs: [ check-for-changes ] if: ${{ always() && needs.check-for-changes.outputs.hasInfraChanges == 'true' }} secrets: AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} @@ -35,7 +34,7 @@ jobs: AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} with: environment: "test" - + dry-run-deploy-infra: name: Dry run deploy infrastructure uses: ./.github/workflows/workflow-deploy-infra.yml @@ -93,7 +92,7 @@ jobs: delete-github-deployments: name: Delete GitHub deployments uses: ./.github/workflows/workflow-delete-deployments.yml - needs: [dry-run-deploy-apps, dry-run-deploy-infra] + needs: [ dry-run-deploy-apps, dry-run-deploy-infra ] if: ${{ always() && !failure() && !cancelled() }} with: - gitSha: ${{ github.event.pull_request.head.sha }} \ No newline at end of file + gitSha: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/ci-cd-staging.yml b/.github/workflows/ci-cd-staging.yml index 980b4a3b6..69c068d5b 100644 --- a/.github/workflows/ci-cd-staging.yml +++ b/.github/workflows/ci-cd-staging.yml @@ -79,6 +79,17 @@ jobs: runMigration: ${{ needs.check-for-changes.outputs.hasMigrationChanges == 'true' }} ref: "refs/tags/v${{ github.event.client_payload.version }}" +# publish-sdk-to-nuget: +# uses: ./.github/workflows/workflow-publish-nuget.yml +# needs: [ get-current-version, check-for-changes ] +# if: ${{ needs.check-for-changes.outputs.hasSwaggerSchemaChanges == 'true' }} +# with: +# version: ${{ needs.get-current-version.outputs.version }} +# path: 'src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj' +# source: 'https://api.nuget.org/v3/index.json' +# secrets: +# NUGET_API_KEY: ${{ secrets.NUGET_API_TEST_KEY }} + store-apps-version: name: Store Latest Deployed Apps Version as GitHub Variable needs: [deploy-apps] @@ -94,7 +105,7 @@ jobs: publish-schema-npm: name: Publish schema npm package needs: [check-for-changes, deploy-apps] - if: ${{ always() && !failure() && !cancelled() && needs.check-for-changes.outputs.hasSchemaChanges == 'true' }} + if: ${{ always() && !failure() && !cancelled() && needs.check-for-changes.outputs.hasSwaggerSchemaChanges == 'true' || needs.check-for-changes.outputs.hasGqlSchemaChanges == 'true' }} uses: ./.github/workflows/workflow-publish-schema.yml with: version: ${{ github.event.client_payload.version }} diff --git a/.github/workflows/workflow-check-for-changes.yml b/.github/workflows/workflow-check-for-changes.yml index b15de102c..f5f7cd386 100644 --- a/.github/workflows/workflow-check-for-changes.yml +++ b/.github/workflows/workflow-check-for-changes.yml @@ -26,9 +26,12 @@ on: hasSlackNotifierChanges: description: "Slack Notifier function related files changed" value: ${{ jobs.check-for-changes.outputs.hasSlackNotifierChanges }} - hasSchemaChanges: - description: "Schema has changed" - value: ${{ jobs.check-for-changes.outputs.hasSchemaChanges }} + hasSwaggerSchemaChanges: + description: "Swagger schema has changed" + value: ${{ jobs.check-for-changes.outputs.hasSwaggerSchemaChanges }} + hasGqlSchemaChanges: + description: "GraphQL schema has changed" + value: ${{ jobs.check-for-changes.outputs.hasGqlSchemaChanges }} hasMigrationChanges: description: "Migration related files changed" value: ${{ jobs.check-for-changes.outputs.hasMigrationChanges }} @@ -42,7 +45,8 @@ jobs: hasSlackNotifierChanges: ${{ steps.filter.outputs.slackNotifier_any_modified == 'true'}} hasBackendChanges: ${{ steps.filter-backend.outputs.backend_any_modified == 'true' }} hasTestChanges: ${{ steps.filter-backend.outputs.tests_any_modified == 'true' }} - hasSchemaChanges: ${{ steps.filter-backend.outputs.schema_any_modified == 'true'}} + hasSwaggerSchemaChanges: ${{ steps.filter-backend.outputs.swagger_schema_any_modified == 'true'}} + hasGqlSchemaChanges: ${{ steps.filter-backend.outputs.gql_schema_any_modified == 'true'}} hasMigrationChanges: ${{ steps.filter-backend.outputs.migration_any_modified == 'true'}} steps: - name: Checkout @@ -75,7 +79,9 @@ jobs: - '.azure/modules/containerApp/**/*' tests: - 'tests/**/*' - schema: - - 'docs/schema/V1/**/*' + swagger_schema: + - 'docs/schema/V1/swagger.verified.json' + gql_schema: + - 'docs/schema/V1/schema.verified.graphql' migration: - 'src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/**/*' diff --git a/.github/workflows/workflow-publish-nuget.yml b/.github/workflows/workflow-publish-nuget.yml new file mode 100644 index 000000000..c0e401725 --- /dev/null +++ b/.github/workflows/workflow-publish-nuget.yml @@ -0,0 +1,44 @@ +name: "Publish nuget package" + +on: + workflow_call: + inputs: + version: + description: "Version" + required: true + type: string + path: + description: "Path to project" + required: true + type: string + source: + description: "Nuget Source" + required: true + type: string + secrets: + NUGET_API_KEY: + required: true +jobs: + build-and-push: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Pack with debug symbols + run: dotnet pack --configuration Release -p:Version="${{ inputs.version }}" -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --output . "${{ inputs.path }}" + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: package + path: '*.*nupkg' + + - name: Push to NuGet + run: dotnet nuget push *.nupkg --source "${{ inputs.source }}" --api-key ${{secrets.NUGET_API_KEY}} diff --git a/Digdir.Domain.Dialogporten.sln b/Digdir.Domain.Dialogporten.sln index 049d6c3eb..858783cd1 100644 --- a/Digdir.Domain.Dialogporten.sln +++ b/Digdir.Domain.Dialogporten.sln @@ -47,7 +47,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Tool.Dialogporten.Ed25519KeyPairGenerator", "src\Digdir.Tool.Dialogporten.Ed25519KeyPairGenerator\Digdir.Tool.Dialogporten.Ed25519KeyPairGenerator.csproj", "{030909AA-5B61-46B4-9B74-0D2D779478FF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten.WebApi.Integration.Tests", "tests\Digdir.Domain.Dialogporten.WebApi.Integration.Tests\Digdir.Domain.Dialogporten.WebApi.Integration.Tests.csproj", "{42004236-D45C-4A1F-9FF9-CF12B7388389}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten.WebApi.Unit.Tests", "tests\Digdir.Domain.Dialogporten.WebApi.Unit.Tests\Digdir.Domain.Dialogporten.WebApi.Unit.Tests.csproj", "{42004236-D45C-4A1F-9FF9-CF12B7388389}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten.GraphQL", "src\Digdir.Domain.Dialogporten.GraphQL\Digdir.Domain.Dialogporten.GraphQL.csproj", "{234FE24D-1047-4E29-A625-1EB406C37A2D}" EndProject @@ -61,8 +61,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Library.Utils.AspNet", "src\Digdir.Library.Utils.AspNet\Digdir.Library.Utils.AspNet.csproj", "{6A485C65-3613-4A49-A16F-2789119F6F38}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApiClient", "WebApiClient", "{9B809C3A-B169-4599-A2D3-A25E87C510FC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Library.Dialogporten.WebApiClient", "src\Digdir.Library.Dialogporten.WebApiClient\Digdir.Library.Dialogporten.WebApiClient.csproj", "{714FBB11-ADC0-44E8-A768-D1A59D641D31}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Tool.Dialogporten.LargeDataSetGenerator", "src\Digdir.Tool.Dialogporten.LargeDataSetGenerator\Digdir.Tool.Dialogporten.LargeDataSetGenerator.csproj", "{B0E0E9EE-AFBE-4013-908C-5F8DF66AB671}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Library.Dialogporten.WebApiClient.WebApiSample", "src\Digdir.Library.Dialogporten.WebApiClient.WebApiSample\Digdir.Library.Dialogporten.WebApiClient.WebApiSample.csproj", "{FBF19369-21CD-437D-BB88-CCB81EC947CF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{21A54524-CC15-42A7-804B-1E4DEBFAA1F7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApiClient", "WebApiClient", "{020E53CD-4575-44BA-81AC-26CE948EE0E7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Library.Dialogporten.WebApiClient.Unit.Tests", "tests\Digdir.Library.Dialogporten.WebApiClient.Unit.Tests\Digdir.Library.Dialogporten.WebApiClient.Unit.Tests.csproj", "{E6CBC569-6821-4DBB-A819-AC95AA8A0682}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -149,10 +161,22 @@ Global {6A485C65-3613-4A49-A16F-2789119F6F38}.Debug|Any CPU.Build.0 = Debug|Any CPU {6A485C65-3613-4A49-A16F-2789119F6F38}.Release|Any CPU.ActiveCfg = Release|Any CPU {6A485C65-3613-4A49-A16F-2789119F6F38}.Release|Any CPU.Build.0 = Release|Any CPU + {714FBB11-ADC0-44E8-A768-D1A59D641D31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {714FBB11-ADC0-44E8-A768-D1A59D641D31}.Debug|Any CPU.Build.0 = Debug|Any CPU + {714FBB11-ADC0-44E8-A768-D1A59D641D31}.Release|Any CPU.ActiveCfg = Release|Any CPU + {714FBB11-ADC0-44E8-A768-D1A59D641D31}.Release|Any CPU.Build.0 = Release|Any CPU {B0E0E9EE-AFBE-4013-908C-5F8DF66AB671}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B0E0E9EE-AFBE-4013-908C-5F8DF66AB671}.Debug|Any CPU.Build.0 = Debug|Any CPU {B0E0E9EE-AFBE-4013-908C-5F8DF66AB671}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0E0E9EE-AFBE-4013-908C-5F8DF66AB671}.Release|Any CPU.Build.0 = Release|Any CPU + {FBF19369-21CD-437D-BB88-CCB81EC947CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBF19369-21CD-437D-BB88-CCB81EC947CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBF19369-21CD-437D-BB88-CCB81EC947CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBF19369-21CD-437D-BB88-CCB81EC947CF}.Release|Any CPU.Build.0 = Release|Any CPU + {E6CBC569-6821-4DBB-A819-AC95AA8A0682}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6CBC569-6821-4DBB-A819-AC95AA8A0682}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6CBC569-6821-4DBB-A819-AC95AA8A0682}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6CBC569-6821-4DBB-A819-AC95AA8A0682}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -181,7 +205,13 @@ Global {0900E3CF-F9D8-4B29-957F-484B3B028D6D} = {320B47A0-5EB8-4B6E-8C84-90633A1849CA} {E389C7C8-9610-40AC-86DC-769B1B7DC78E} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7} {6A485C65-3613-4A49-A16F-2789119F6F38} = {096E9B69-6783-4446-A895-0B6D7729A0D9} + {9B809C3A-B169-4599-A2D3-A25E87C510FC} = {096E9B69-6783-4446-A895-0B6D7729A0D9} + {714FBB11-ADC0-44E8-A768-D1A59D641D31} = {9B809C3A-B169-4599-A2D3-A25E87C510FC} {B0E0E9EE-AFBE-4013-908C-5F8DF66AB671} = {3C2C775D-F2D1-42A2-B53F-CC6D5FF59633} + {FBF19369-21CD-437D-BB88-CCB81EC947CF} = {9B809C3A-B169-4599-A2D3-A25E87C510FC} + {21A54524-CC15-42A7-804B-1E4DEBFAA1F7} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7} + {020E53CD-4575-44BA-81AC-26CE948EE0E7} = {21A54524-CC15-42A7-804B-1E4DEBFAA1F7} + {E6CBC569-6821-4DBB-A819-AC95AA8A0682} = {020E53CD-4575-44BA-81AC-26CE948EE0E7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B2FE67FF-7622-4AFB-AD8E-961B6A39D888} diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index 92d7d02af..1c9c9084b 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -7268,7 +7268,7 @@ }, "servers": [ { - "url": "https://altinn-dev-api.azure-api.net/dialogporten" + "url": "https://localhost:7214/" } ] } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs index 19808ad54..9ea2aa82a 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQuery.cs @@ -54,9 +54,7 @@ public sealed class SearchDialogQuery : SortablePaginationParameter - /// If set to 'include', the result will include both deleted and non-deleted dialogs - /// If set to 'exclude', the result will only include non-deleted dialogs - /// If set to 'only', the result will only include deleted dialogs + /// If set to 'include', the result will include both deleted and non-deleted dialogs. If set to 'exclude', the result will only include non-deleted dialogs. If set to 'only', the result will only include deleted dialogs /// public DeletedFilter? Deleted { diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj index 7b927a34f..a2138a614 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj +++ b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj @@ -8,14 +8,18 @@ - - - - + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -25,4 +29,8 @@ + + + + diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 3605573d0..bd5b8d305 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -115,6 +115,26 @@ static void BuildAndRun(string[] args) x.RemoveEmptyRequestSchema = true; x.DocumentSettings = s => { + s.PostProcess = document => + { + var dialogportenBaseUri = builder.Configuration + .GetSection(ApplicationSettings.ConfigurationSectionName) + .Get()! + .Dialogporten + .BaseUri + .ToString(); + + document.Servers.Clear(); + document.Servers.Add(new OpenApiServer + { + Url = dialogportenBaseUri + }); + document.Generator = null; + document.ReplaceProblemDetailsDescriptions(); + document.MakeCollectionsNullable(); + document.FixJwtBearerCasing(); + document.RemoveSystemStringHeaderTitles(); + }; s.Title = "Dialogporten"; s.DocumentName = "v1"; s.Version = "v1"; @@ -158,7 +178,6 @@ static void BuildAndRun(string[] args) } var app = builder.Build(); - app.MapAspNetHealthChecks() .MapControllers(); @@ -197,26 +216,7 @@ static void BuildAndRun(string[] args) x.Errors.ResponseBuilder = ErrorResponseBuilderExtensions.ResponseBuilder; }) .UseAddSwaggerCorsHeader() - .UseSwaggerGen(config => - { - config.PostProcess = (document, _) => - { - var dialogportenBaseUri = builder.Configuration - .GetSection(ApplicationSettings.ConfigurationSectionName) - .Get()! - .Dialogporten - .BaseUri - .ToString(); - - document.Servers.Clear(); - document.Servers.Add(new OpenApiServer { Url = dialogportenBaseUri }); - document.Generator = null; - document.ReplaceProblemDetailsDescriptions(); - document.MakeCollectionsNullable(); - document.FixJwtBearerCasing(); - document.RemoveSystemStringHeaderTitles(); - }; - }, uiConfig => + .UseSwaggerGen(uiConfig: uiConfig => { // Hide schemas view uiConfig.DefaultModelsExpandDepth = -1; diff --git a/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Digdir.Library.Dialogporten.WebApiClient.WebApiSample.csproj b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Digdir.Library.Dialogporten.WebApiClient.WebApiSample.csproj new file mode 100644 index 000000000..beedf265b --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Digdir.Library.Dialogporten.WebApiClient.WebApiSample.csproj @@ -0,0 +1,19 @@ + + + + + net9.0 + 750256a4-f332-4783-8802-8a7d9566f9cb + enable + enable + + + + + + + + + + + diff --git a/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Program.cs b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Program.cs new file mode 100644 index 000000000..dd9700d16 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Program.cs @@ -0,0 +1,31 @@ +using Altinn.ApiClients.Dialogporten; +using Altinn.ApiClients.Dialogporten.Features.V1; +using Microsoft.AspNetCore.Mvc; + +var builder = WebApplication.CreateBuilder(args); + +var dialogportenSettings = builder.Configuration + .GetSection("DialogportenSettings") + .Get()!; +builder.Services.AddDialogportenClient(dialogportenSettings); + +builder.Services.AddOpenApi(); + +var app = builder.Build(); +app.MapOpenApi(); +app.UseHttpsRedirection(); + +app.MapPost("/dialogTokenVerify", ( + [FromServices] IDialogTokenValidator dialogTokenVerifier, + [FromBody] string token) + => dialogTokenVerifier.Validate(token).IsValid + ? Results.Ok() + : Results.Unauthorized()); + +app.MapGet("/dialog/{dialogId:Guid}", ( + [FromServices] IServiceownerApi serviceOwnerApi, + [FromRoute] Guid dialogId, + CancellationToken cancellationToken) + => Results.Ok(serviceOwnerApi.V1ServiceOwnerDialogsGetGetDialog(dialogId, null!, cancellationToken))); + +app.Run(); diff --git a/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Properties/launchSettings.json b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Properties/launchSettings.json new file mode 100644 index 000000000..67adf16f7 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5006", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7171;http://localhost:5006", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/WebApiSample.http b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/WebApiSample.http new file mode 100644 index 000000000..e5f2d214e --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/WebApiSample.http @@ -0,0 +1,16 @@ +@HostAddress = http://localhost:5006 +@dialogId = DIALOG_ID_HERE +@dialogToken = "DIALOG_TOKEN_HERE" + +### Verify DialogToken + +POST {{HostAddress}}/dialogTokenVerify/ +Accept: application/json + +{ + "token": {{dialogToken}} +} + +### Get dialog by id +GET {{HostAddress}}/dialog/{{dialogId}} +Accept: application/json diff --git a/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/appsettings.json b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/appsettings.json new file mode 100644 index 000000000..c8998404d --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/appsettings.json @@ -0,0 +1,19 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "DialogportenSettings": { + "BaseUri": "https://localhost:7214", + "ThrowOnPublicKeyFetchInit": false, + "Maskinporten": { + "Environment": "test", + "Scope": "digdir:dialogporten.serviceprovider digdir:dialogporten.serviceprovider.search", + "ClientId": "Configure in local secrets", + "EncodedJwk": "Configure in local secrets" + } + } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/.refitter b/src/Digdir.Library.Dialogporten.WebApiClient/.refitter new file mode 100644 index 000000000..097e97970 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/.refitter @@ -0,0 +1,18 @@ +{ + "openApiPath": "../Digdir.Domain.Dialogporten.WebApi/bin/Release/net9.0/swagger.json", + "namespace": "Altinn.ApiClients.Dialogporten.Features.V1", + "outputFolder": "Features/V1", + "operationNameGenerator": "SingleClientFromOperationId", + "trimUnusedSchema": true, + "multipleInterfaces": "ByTag", + "includeTags": [ + "Serviceowner" + ], + "useCancellationTokens": true, + "returnIApiResponse": true, + "useDynamicQuerystringParameters": true, + "outputFilename": "RefitterInterface.cs", + "codeGeneratorSettings": { + "dateFormat": "yyyy-MM-ddTHH:mm:ssZ" + } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/AssemblyMarker.cs b/src/Digdir.Library.Dialogporten.WebApiClient/AssemblyMarker.cs new file mode 100644 index 000000000..fa23cf0eb --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/AssemblyMarker.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +namespace Altinn.ApiClients.Dialogporten; + +internal sealed class AssemblyMarker +{ + public static readonly Assembly Assembly = typeof(AssemblyMarker).Assembly; +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Common/Exceptions/IncompleteDialogportenClientInitializationException.cs b/src/Digdir.Library.Dialogporten.WebApiClient/Common/Exceptions/IncompleteDialogportenClientInitializationException.cs new file mode 100644 index 000000000..6c08ce255 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Common/Exceptions/IncompleteDialogportenClientInitializationException.cs @@ -0,0 +1,3 @@ +namespace Altinn.ApiClients.Dialogporten.Common.Exceptions; + +public sealed class IncompleteDialogportenClientInitializationException(string message) : Exception(message); diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Common/IClock.cs b/src/Digdir.Library.Dialogporten.WebApiClient/Common/IClock.cs new file mode 100644 index 000000000..a4c6b040d --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Common/IClock.cs @@ -0,0 +1,11 @@ +namespace Altinn.ApiClients.Dialogporten.Common; + +internal interface IClock +{ + DateTimeOffset UtcNow { get; } +} + +internal class DefaultClock : IClock +{ + public DateTimeOffset UtcNow => DateTimeOffset.UtcNow; +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/DialogportenSettings.cs b/src/Digdir.Library.Dialogporten.WebApiClient/DialogportenSettings.cs new file mode 100644 index 000000000..2861026cf --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/DialogportenSettings.cs @@ -0,0 +1,25 @@ +using Altinn.ApiClients.Maskinporten.Config; + +namespace Altinn.ApiClients.Dialogporten; + +public sealed class DialogportenSettings +{ + /// + /// The base URI for the dialogporten endpoint, up to but excluding "/api/v...". + /// For example the base URI of 'https://altinn-tt02-api.azure-api.net/dialogporten/api/v1/serviceowner/dialogs' + /// is 'https://altinn-tt02-api.azure-api.net/dialogporten'. + /// + public string BaseUri { get; set; } = null!; + + /// + /// If true, the library will throw an exception if it cannot fetch public keys from dialogporten .wellKnown endpoint. + /// + /// + /// Default is true. + /// + public bool ThrowOnPublicKeyFetchInit { get; set; } = true; + + public MaskinportenSettings Maskinporten { get; set; } = null!; + + internal static bool Validate() => true; +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj b/src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj new file mode 100644 index 000000000..4b44b6e50 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj @@ -0,0 +1,40 @@ + + + + README.md + LICENSE + Digitaliseringsdirektoratet + digdir;altinn;dialogporten + git + https://github.com/altinn/dialogporten + Altinn.ApiClients.Dialogporten + Altinn.ApiClients.Dialogporten + Altinn.ApiClients.Dialogporten + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Features/V1/RefitterInterface.cs b/src/Digdir.Library.Dialogporten.WebApiClient/Features/V1/RefitterInterface.cs new file mode 100644 index 000000000..cc3dd0aa0 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Features/V1/RefitterInterface.cs @@ -0,0 +1,4332 @@ +// +// This code was generated by Refitter. +// + + +using Refit; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable annotations + +namespace Altinn.ApiClients.Dialogporten.Features.V1 +{ + public class V1ServiceOwnerDialogsSearchSearchDialogQueryParams + { + + /// + /// Filter by one or more service resources + /// + [Query(CollectionFormat.Multi)] + public IEnumerable ServiceResource { get; set; } + + /// + /// Filter by one or more owning parties + /// + [Query(CollectionFormat.Multi)] + public IEnumerable Party { get; set; } + + /// + /// Filter by end user id + /// + [Query] + public string EndUserId { get; set; } + + /// + /// Filter by one or more extended statuses + /// + [Query(CollectionFormat.Multi)] + public IEnumerable ExtendedStatus { get; set; } + + /// + /// Filter by external reference + /// + [Query] + public string ExternalReference { get; set; } + + /// + /// Filter by status + /// + [Query(CollectionFormat.Multi)] + public IEnumerable Status { get; set; } + + /// + /// If set to 'include', the result will include both deleted and non-deleted dialogs. If set to 'exclude', the result will only include non-deleted dialogs. If set to 'only', the result will only include deleted dialogs + /// + [Query] + public V1Common_DeletedFilter? Deleted { get; set; } + + /// + /// Only return dialogs created after this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? CreatedAfter { get; set; } + + /// + /// Only return dialogs created before this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? CreatedBefore { get; set; } + + /// + /// Only return dialogs updated after this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? UpdatedAfter { get; set; } + + /// + /// Only return dialogs updated before this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? UpdatedBefore { get; set; } + + /// + /// Only return dialogs with due date after this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? DueAfter { get; set; } + + /// + /// Only return dialogs with due date before this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? DueBefore { get; set; } + + /// + /// Only return dialogs with visible-from date after this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? VisibleAfter { get; set; } + + /// + /// Only return dialogs with visible-from date before this date + /// + [Query(Format = "yyyy-MM-ddTHH:mm:ssZ")] + public System.DateTimeOffset? VisibleBefore { get; set; } + + /// + /// Filter by process + /// + [Query] + public string Process { get; set; } + + /// + /// Filter by Display state + /// + [Query(CollectionFormat.Multi)] + public IEnumerable SystemLabel { get; set; } + + /// + /// Search string for free text search. Will attempt to fuzzily match in all free text fields in the aggregate + /// + [Query] + public string Search { get; set; } + + /// + /// Limit free text search to texts with this language code, e.g. 'nb', 'en'. Culture codes will be normalized to neutral language codes (ISO 639). Default: search all culture codes + /// + [Query] + public string SearchLanguageCode { get; set; } + + [Query] + public OrderSetOfTOrderDefinitionAndTTarget OrderBy { get; set; } + + /// + /// Supply "continuationToken" for the response to get the next page of results, if hasNextPage is true + /// + [Query] + public ContinuationTokenSetOfTOrderDefinitionAndTTarget ContinuationToken { get; set; } + + /// + /// Limit the number of results per page (1-1000, default: 100) + /// + [Query] + public int? Limit { get; set; } + + } + + public class V1ServiceOwnerDialogActivitiesNotificationConditionNotificationConditionQueryParams + { + public V1ServiceOwnerDialogActivitiesNotificationConditionNotificationConditionQueryParams(V1ServiceOwnerDialogActivitiesQueriesNotificationCondition_NotificationConditionType conditionType, DialogsEntitiesActivities_DialogActivityType activityType) + { + + ConditionType = conditionType; + ActivityType = activityType; + } + + [Query] + public V1ServiceOwnerDialogActivitiesQueriesNotificationCondition_NotificationConditionType ConditionType { get; set; } + + [Query] + public DialogsEntitiesActivities_DialogActivityType ActivityType { get; set; } + + [Query] + public System.Guid? TransmissionId { get; set; } + + } + + /// Gets a list of dialog transmissions + [System.CodeDom.Compiler.GeneratedCode("Refitter", "1.5.2.0")] + public partial interface IServiceownerApi + { + /// Gets a list of dialog transmissions + /// Gets the list of transmissions belonging to a dialog + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog transmission list. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to get the supplied dialog (not owned by authenticated organization or has additional scope requirements defined in policy). + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}/transmissions")] + Task>> V1ServiceOwnerDialogTransmissionsSearchSearchDialogTransmission(System.Guid dialogId, CancellationToken cancellationToken = default); + + /// Adds a transmission to a dialog + /// + /// The transmission is created with the given configuration. For more information see the documentation (link TBD). + /// + /// Optimistic concurrency control is implemented using the If-Match header. Supply the Revision value from the GetDialog endpoint to ensure that the dialog is not modified/deleted by another request in the meantime. + /// + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 201 + /// The UUID of the created dialog transmission. A relative URL to the newly created activity is set in the \"Location\" header. + /// + /// + /// 204 + /// No Content + /// + /// + /// 400 + /// Validation error occurred. See problem details for a list of errors. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to create child entity for the given dialog (dialog not owned by authenticated organization or has additional scope requirements defined in service identifiers policy). + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// 412 + /// The supplied If-Match header did not match the current Revision value for the dialog. The request was not applied. + /// + /// + /// 422 + /// Domain error occurred. See problem details for a list of errors. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Post("/api/v1/serviceowner/dialogs/{dialogId}/transmissions")] + Task> V1ServiceOwnerDialogTransmissionsCreateDialogTransmission(System.Guid dialogId, [Body, AliasAs("CreateTransmissionRequest")] V1ServiceOwnerDialogTransmissionsCreate_TransmissionRequest createTransmissionRequest, [Header("if-Match")] System.Guid? if_Match, CancellationToken cancellationToken = default); + + /// Gets a single dialog transmission + /// Gets a single transmission belonging to a dialog. For more information see the documentation (link TBD). + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog transmission. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to get child entity for the given dialog (dialog not owned by authenticated organization or has additional scope requirements defined in service identifiers policy). + /// + /// + /// 404 + /// The given dialog ID was not found or was deleted, or the given transmission ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}/transmissions/{transmissionId}")] + Task> V1ServiceOwnerDialogTransmissionsGetGetDialogTransmission(System.Guid dialogId, System.Guid transmissionId, CancellationToken cancellationToken = default); + + /// Gets all seen log records for a dialog + /// Gets all seen log records for a dialog. For more information see the documentation (link TBD). + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog seen log records. + /// + /// + /// 401 + /// Unauthorized + /// + /// + /// 403 + /// Forbidden + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}/seenlog")] + Task>> V1ServiceOwnerDialogSeenLogsSearchSearchDialogSeenLog(System.Guid dialogId, CancellationToken cancellationToken = default); + + /// Gets a single dialog seen log record + /// Gets a single dialog seen log record. For more information see the documentation (link TBD). + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog seen log record. + /// + /// + /// 401 + /// Unauthorized + /// + /// + /// 403 + /// Forbidden + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}/seenlog/{seenLogId}")] + Task> V1ServiceOwnerDialogSeenLogsGetGetDialogSeenLog(System.Guid dialogId, System.Guid seenLogId, CancellationToken cancellationToken = default); + + /// Replaces a dialog + /// + /// Replaces a given dialog with the supplied model. For more information see the documentation (link TBD). + /// + /// Optimistic concurrency control is implemented using the If-Match header. Supply the Revision value from the GetDialog endpoint to ensure that the dialog is not modified/deleted by another request in the meantime. + /// + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 204 + /// The dialog aggregate was updated successfully. + /// + /// + /// 400 + /// Validation error occurred. See problem details for a list of errors. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to update the supplied dialog (not owned by authenticated organization or has additional scope requirements defined in policy). + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// 412 + /// The supplied If-Match header did not match the current Revision value for the dialog. The request was not applied. + /// + /// + /// 422 + /// Domain error occurred. See problem details for a list of errors. + /// + /// + /// + [Headers("Accept: application/problem+json")] + [Put("/api/v1/serviceowner/dialogs/{dialogId}")] + Task V1ServiceOwnerDialogsUpdateDialog(System.Guid dialogId, [Body] V1ServiceOwnerDialogsCommandsUpdate_Dialog dto, [Header("if-Match")] System.Guid? if_Match, CancellationToken cancellationToken = default); + + /// Gets a single dialog + /// + /// Gets a single dialog aggregate. For more information see the documentation (link TBD). + /// + /// Note that this operation may return deleted dialogs (see the field `DeletedAt`). + /// + /// Filter by end user id + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog aggregate. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to get the supplied dialog (not owned by authenticated organization or has additional scope requirements defined in policy). + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}")] + Task> V1ServiceOwnerDialogsGetGetDialog(System.Guid dialogId, [Query] string endUserId, CancellationToken cancellationToken = default); + + /// Deletes a dialog + /// + /// Deletes a given dialog (soft delete). For more information see the documentation (link TBD). + /// + /// Note that the dialog will still be available on the single details endpoint, but will have a deleted status. It will not appear on the list endpoint for either service owners nor end users. + /// If end users attempt to access the dialog via the details endpoint, they will get a 410 Gone response. + /// + /// Optimistic concurrency control is implemented using the If-Match header. Supply the Revision value from the GetDialog endpoint to ensure that the dialog is not deleted by another request in the meantime. + /// + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 204 + /// The dialog aggregate was deleted successfully. + /// + /// + /// 400 + /// Validation error occurred. See problem details for a list of errors. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to delete the supplied dialog (not owned by authenticated organization or has additional scope requirements defined in policy). + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// 412 + /// The supplied If-Match header did not match the current Revision value for the dialog. The request was not applied. + /// + /// + /// + [Headers("Accept: application/problem+json")] + [Delete("/api/v1/serviceowner/dialogs/{dialogId}")] + Task V1ServiceOwnerDialogsDeleteDialog(System.Guid dialogId, [Header("if-Match")] System.Guid? if_Match, CancellationToken cancellationToken = default); + + /// Patch a single dialog + /// + /// Patches a dialog aggregate with a RFC6902 JSON Patch document. The patch document must be a JSON array of RFC6902 operations. + /// See [https://tools.ietf.org/html/rfc6902](https://tools.ietf.org/html/rfc6902) for more information. + /// + /// Optimistic concurrency control is implemented using the If-Match header. Supply the Revision value from the GetDialog endpoint to ensure that the dialog is not modified/deleted by another request in the meantime. + /// + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 204 + /// Patch was successfully applied. + /// + /// + /// 400 + /// Validation error occurred. See problem details for a list of errors. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \\\"digdir:dialogporten.serviceprovider\\\" + /// + /// + /// 403 + /// Unauthorized to update a dialog for the given serviceResource (not owned by authenticated organization or has additional scope requirements defined in policy) + /// + /// + /// 404 + /// The given dialog ID was not found or is deleted + /// + /// + /// 412 + /// The supplied Revision does not match the current Revision of the dialog + /// + /// + /// 422 + /// Domain error occurred. See problem details for a list of errors. + /// + /// + /// + [Headers("Accept: application/json")] + [Patch("/api/v1/serviceowner/dialogs/{dialogId}")] + Task V1ServiceOwnerDialogsPatchDialog(System.Guid dialogId, [Body] IEnumerable patchDocument, [Header("If-Match")] System.Guid? etag, CancellationToken cancellationToken = default); + + /// Gets a list of dialogs + /// + /// Performs a search for dialogs, returning a paginated list of dialogs. For more information see the documentation (link TBD). + /// + /// * All date parameters must contain explicit time zone. Example: 2023-10-27T10:00:00Z or 2023-10-27T10:00:00+01:00 + /// * See "continuationToken" in the response for how to get the next page of results. + /// * hasNextPage will be set to true if there are more items to get. + /// + /// The dynamic querystring parameter wrapping all others. + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog list. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider.search\". + /// + /// + /// + [Headers("Accept: application/json")] + [Get("/api/v1/serviceowner/dialogs")] + Task> V1ServiceOwnerDialogsSearchSearchDialog([Query] V1ServiceOwnerDialogsSearchSearchDialogQueryParams queryParams, CancellationToken cancellationToken = default); + + /// Creates a new dialog + /// + /// The dialog is created with the given configuration. For more information see the documentation (link TBD). + /// + /// For detailed information on validation rules, see [the source for CreateDialogCommandValidator](https://github.com/altinn/dialogporten/blob/main/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs) + /// + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 201 + /// The UUID of the created dialog aggregate. A relative URL to the newly created activity is set in the \"Location\" header. + /// + /// + /// 204 + /// No Content + /// + /// + /// 400 + /// Validation error occurred. See problem details for a list of errors. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to create a dialog for the given serviceResource (not owned by authenticated organization or has additional scope requirements defined in policy). + /// + /// + /// 409 + /// Dialog with IdempotentKey 01941821-ffca-73a1-9335-435a882be014 has already been created. + /// + /// + /// 422 + /// Domain error occurred. See problem details for a list of errors. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Post("/api/v1/serviceowner/dialogs")] + Task> V1ServiceOwnerDialogsCreateDialog([Body] V1ServiceOwnerDialogsCommandsCreate_Dialog dto, CancellationToken cancellationToken = default); + + /// Restore a dialog + /// Restore a dialog. For more information see the documentation (link TBD). + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 204 + /// The dialog aggregate was restored successfully. + /// + /// + /// 401 + /// Unauthorized + /// + /// + /// 403 + /// Forbidden + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 412 + /// The supplied If-Match header did not match the current Revision value for the dialog. The request was not applied. + /// + /// + /// + [Headers("Accept: application/problem+json")] + [Post("/api/v1/serviceowner/dialogs/{dialogId}/actions/restore")] + Task V1ServiceOwnerDialogsRestoreRestoreDialog(System.Guid dialogId, [Header("if-Match")] System.Guid? if_Match, CancellationToken cancellationToken = default); + + /// Permanently deletes a dialog + /// + /// Deletes a given dialog (hard delete). For more information see the documentation (link TBD). + /// + /// Optimistic concurrency control is implemented using the If-Match header. Supply the Revision value from the GetDialog endpoint to ensure that the dialog is not deleted by another request in the meantime. + /// + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 204 + /// The dialog aggregate was deleted successfully. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to delete the supplied dialog (not owned by authenticated organization or has additional scope requirements defined in policy). + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 412 + /// The supplied If-Match header did not match the current Revision value for the dialog. The request was not applied. + /// + /// + /// + [Headers("Accept: application/problem+json")] + [Post("/api/v1/serviceowner/dialogs/{dialogId}/actions/purge")] + Task V1ServiceOwnerDialogsPurgePurgeDialog(System.Guid dialogId, [Header("if-Match")] System.Guid? if_Match, CancellationToken cancellationToken = default); + + /// Gets a list of dialog activities + /// Gets the list of activities belonging to a dialog + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog activity list. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to get the supplied dialog (not owned by authenticated organization or has additional scope requirements defined in policy). + /// + /// + /// + [Headers("Accept: application/json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}/activities")] + Task>> V1ServiceOwnerDialogActivitiesSearchSearchDialogActivity(System.Guid dialogId, CancellationToken cancellationToken = default); + + /// Adds a activity to a dialogs activity history + /// + /// The activity is created with the given configuration. For more information see the documentation (link TBD). + /// + /// Optimistic concurrency control is implemented using the If-Match header. Supply the Revision value from the GetDialog endpoint to ensure that the dialog is not modified/deleted by another request in the meantime. + /// + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 201 + /// The UUID of the created dialog activity. A relative URL to the newly created activity is set in the \"Location\" header. + /// + /// + /// 204 + /// No Content + /// + /// + /// 400 + /// Validation error occurred. See problem details for a list of errors. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to create child entity for the given dialog (dialog not owned by authenticated organization or has additional scope requirements defined in service identifiers policy). + /// + /// + /// 404 + /// The given dialog ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// 412 + /// The supplied If-Match header did not match the current Revision value for the dialog. The request was not applied. + /// + /// + /// 422 + /// Domain error occurred. See problem details for a list of errors. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Post("/api/v1/serviceowner/dialogs/{dialogId}/activities")] + Task> V1ServiceOwnerDialogActivitiesCreateDialogActivity(System.Guid dialogId, [Body, AliasAs("CreateActivityRequest")] V1ServiceOwnerDialogActivitiesCreate_ActivityRequest createActivityRequest, [Header("if-Match")] System.Guid? if_Match, CancellationToken cancellationToken = default); + + /// Returns a boolean value based on conditions used to determine if a notification is to be sent + /// Used by Altinn Notification only. Takes a dialogId and returns a boolean value based on conditions used to determine if a notification is to be sent. + /// The dynamic querystring parameter wrapping all others. + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the notification determination. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"altinn:system/notifications.condition.check\". + /// + /// + /// 403 + /// Forbidden + /// + /// + /// + [Headers("Accept: application/json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}/actions/should-send-notification")] + Task> V1ServiceOwnerDialogActivitiesNotificationConditionNotificationCondition(System.Guid dialogId, [Query] V1ServiceOwnerDialogActivitiesNotificationConditionNotificationConditionQueryParams queryParams, CancellationToken cancellationToken = default); + + /// Gets a single dialog activity + /// Gets a single activity belonging to a dialog. For more information see the documentation (link TBD). + /// + /// A representing the instance containing the result: + /// + /// + /// Status + /// Description + /// + /// + /// 200 + /// Successfully returned the dialog activity. + /// + /// + /// 401 + /// Missing or invalid authentication token. Requires a Maskinporten-token with the scope \"digdir:dialogporten.serviceprovider\". + /// + /// + /// 403 + /// Unauthorized to get child entity for the given dialog (dialog not owned by authenticated organization or has additional scope requirements defined in service identifiers policy). + /// + /// + /// 404 + /// The given dialog ID was not found or was deleted, or the given activity ID was not found. + /// + /// + /// 410 + /// Entity with the given key(s) is removed. + /// + /// + /// + [Headers("Accept: application/json, application/problem+json")] + [Get("/api/v1/serviceowner/dialogs/{dialogId}/activities/{activityId}")] + Task> V1ServiceOwnerDialogActivitiesGetGetDialogActivity(System.Guid dialogId, System.Guid activityId, CancellationToken cancellationToken = default); + } + +} + +//---------------------- +// +// Generated using the NSwag toolchain v14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." + +namespace Altinn.ApiClients.Dialogporten.Features.V1 +{ + using System = global::System; + + + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesSearch_Transmission + { + /// + /// The unique identifier for the transmission in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The date and time when the transmission was created. + /// + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// The authorization attribute associated with the transmission. + /// + + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// The extended type URI for the transmission. + /// + + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// The unique identifier for the related transmission, if any. + /// + + [JsonPropertyName("relatedTransmissionId")] + public System.Guid? RelatedTransmissionId { get; set; } + + /// + /// The date and time when the transmission was deleted, if applicable. + /// + + [JsonPropertyName("deletedAt")] + public System.DateTimeOffset? DeletedAt { get; set; } + + /// + /// The type of the transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesTransmissions_DialogTransmissionType Type { get; set; } + + /// + /// The sender actor information for the transmission. + /// + + [JsonPropertyName("sender")] + public V1ServiceOwnerCommonActors_Actor Sender { get; set; } + + /// + /// The content of the transmission. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogTransmissionsQueriesSearch_Content Content { get; set; } + + /// + /// The attachments associated with the transmission. + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DialogsEntitiesTransmissions_DialogTransmissionType + { + + [System.Runtime.Serialization.EnumMember(Value = @"Information")] + Information = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Acceptance")] + Acceptance = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"Rejection")] + Rejection = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"Request")] + Request = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"Alert")] + Alert = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"Decision")] + Decision = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"Submission")] + Submission = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"Correction")] + Correction = 7, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerCommonActors_Actor + { + /// + /// The type of actor that sent the transmission. + /// + + [JsonPropertyName("actorType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Actors_ActorType ActorType { get; set; } + + /// + /// Specifies the name of the entity that sent the transmission. Mutually exclusive with ActorId. If ActorId + ///
is supplied, the name will be automatically populated from the name registries. + ///
+ + [JsonPropertyName("actorName")] + public string ActorName { get; set; } + + /// + /// The identifier of the person or organization that sent the transmission. Mutually exclusive with ActorName. + ///
Might be omitted if ActorType is "ServiceOwner". + ///
+ + [JsonPropertyName("actorId")] + public string ActorId { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Actors_ActorType + { + + [System.Runtime.Serialization.EnumMember(Value = @"PartyRepresentative")] + PartyRepresentative = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"ServiceOwner")] + ServiceOwner = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesSearch_Content + { + /// + /// The title of the content. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// The summary of the content. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. + /// + + [JsonPropertyName("contentReference")] + public V1CommonContent_ContentValue ContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1CommonContent_ContentValue + { + /// + /// A list of localizations for the content. + /// + + [JsonPropertyName("value")] + public ICollection Value { get; set; } + + /// + /// Media type of the content, this can also indicate that the content is embeddable. + ///
For a list of supported media types, see (link TBD). + ///
+ + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1CommonLocalizations_Localization + { + /// + /// The localized text or URI reference. + /// + + [JsonPropertyName("value")] + public string Value { get; set; } + + /// + /// The language code of the localization in ISO 639-1 format. + /// + + [JsonPropertyName("languageCode")] + public string LanguageCode { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesSearch_Attachment + { + /// + /// The unique identifier for the attachment in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesSearch_AttachmentUrl + { + /// + /// The unique identifier for the attachment URL in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The fully qualified URL of the attachment. Will be set to "urn:dialogporten:unauthorized" if the user is + ///
not authorized to access the transmission. + ///
+ + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// The type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Attachments_AttachmentUrlConsumerType + { + + [System.Runtime.Serialization.EnumMember(Value = @"Gui")] + Gui = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Api")] + Api = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesGet_Transmission + { + /// + /// The unique identifier for the transmission in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The date and time when the transmission was created. + /// + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// The authorization attribute associated with the transmission. + /// + + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// The extended type URI for the transmission. + /// + + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// The unique identifier for the related transmission, if any. + /// + + [JsonPropertyName("relatedTransmissionId")] + public System.Guid? RelatedTransmissionId { get; set; } + + /// + /// The date and time when the transmission was deleted, if applicable. + /// + + [JsonPropertyName("deletedAt")] + public System.DateTimeOffset? DeletedAt { get; set; } + + /// + /// The type of the transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesTransmissions_DialogTransmissionType Type { get; set; } + + /// + /// The sender actor information for the transmission. + /// + + [JsonPropertyName("sender")] + public V1ServiceOwnerCommonActors_Actor Sender { get; set; } + + /// + /// The content of the transmission. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogTransmissionsQueriesGet_Content Content { get; set; } + + /// + /// The attachments associated with the transmission. + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ProblemDetails + { + + [JsonPropertyName("type")] + public string Type { get; set; } = "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1"; + + [JsonPropertyName("title")] + public string Title { get; set; } = "One or more validation errors occurred."; + + [JsonPropertyName("status")] + public int Status { get; set; } = 400; + + [JsonPropertyName("instance")] + public string Instance { get; set; } = "/api/route"; + + [JsonPropertyName("traceId")] + public string TraceId { get; set; } = "0HMPNHL0JHL76:00000001"; + + [JsonPropertyName("detail")] + public string Detail { get; set; } + + [JsonPropertyName("errors")] + public ICollection Errors { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ProblemDetails_Error + { + + [JsonPropertyName("name")] + public string Name { get; set; } = "Error or field name"; + + [JsonPropertyName("reason")] + public string Reason { get; set; } = "Error reason"; + + [JsonPropertyName("code")] + public string Code { get; set; } + + [JsonPropertyName("severity")] + public string Severity { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesGet_Content + { + /// + /// The title of the content. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// The summary of the content. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. + ///
Allowed media types: application/vnd.dialogporten.frontchannelembed+json;type=markdown + ///
+ + [JsonPropertyName("contentReference")] + public V1CommonContent_ContentValue ContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesGet_Attachment + { + /// + /// The unique identifier for the attachment in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsQueriesGet_AttachmentUrl + { + /// + /// The unique identifier for the attachment URL in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The fully qualified URL of the attachment. Will be set to "urn:dialogporten:unauthorized" if the user is + ///
not authorized to access the transmission. + ///
+ + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// The type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogTransmissionsCreate_TransmissionRequest + { + /// + /// The UUDIv7 of the action may be provided to support idempotent additions to the list of transmissions. + ///
If not supplied, a new UUIDv7 will be generated. + ///
+ + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// If supplied, overrides the creating date and time for the transmission. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// Arbitrary URI/URN describing a service-specific transmission type. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// Reference to any other transmission that this transmission is related to. + /// + + [JsonPropertyName("relatedTransmissionId")] + public System.Guid? RelatedTransmissionId { get; set; } + + /// + /// The type of transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesTransmissions_DialogTransmissionType Type { get; set; } + + /// + /// The actor that sent the transmission. + /// + + [JsonPropertyName("sender")] + public V1ServiceOwnerCommonActors_Actor Sender { get; set; } + + /// + /// The transmission unstructured text content. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsCommandsUpdate_TransmissionContent Content { get; set; } + + /// + /// The transmission-level attachments. + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_TransmissionContent + { + /// + /// The transmission title. Must be text/plain. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// The transmission summary. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. Must be HTTPS. + ///
Allowed media types: application/vnd.dialogporten.frontchannelembed+json;type=markdown + ///
+ + [JsonPropertyName("contentReference")] + public V1CommonContent_ContentValue ContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_TransmissionAttachment + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent additions of transmission attachments. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_TransmissionAttachmentUrl + { + /// + /// The fully qualified URL of the attachment. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// The type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogSeenLogsQueriesSearch_SeenLog + { + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + [JsonPropertyName("seenAt")] + public System.DateTimeOffset SeenAt { get; set; } + + [JsonPropertyName("seenBy")] + public V1ServiceOwnerCommonActors_Actor SeenBy { get; set; } + + [JsonPropertyName("isViaServiceOwner")] + public bool? IsViaServiceOwner { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogSeenLogsQueriesGet_SeenLog + { + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + [JsonPropertyName("seenAt")] + public System.DateTimeOffset SeenAt { get; set; } + + [JsonPropertyName("seenBy")] + public V1ServiceOwnerCommonActors_Actor SeenBy { get; set; } + + [JsonPropertyName("isViaServiceOwner")] + public bool? IsViaServiceOwner { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_Dialog + { + /// + /// Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come + ///
to a natural completion (successful or not). + ///
+ + [JsonPropertyName("progress")] + public int? Progress { get; set; } + + /// + /// Arbitrary string with a service-specific indicator of status, typically used to indicate a fine-grained state of + ///
the dialog to further specify the "status" enum. + ///
+ + [JsonPropertyName("extendedStatus")] + public string ExtendedStatus { get; set; } + + /// + /// Arbitrary string with a service-specific reference to an external system or service. + /// + + [JsonPropertyName("externalReference")] + public string ExternalReference { get; set; } + + /// + /// The timestamp when the dialog should be made visible for authorized end users. If not provided, the dialog will be + ///
immediately available. + ///
+ + [JsonPropertyName("visibleFrom")] + public System.DateTimeOffset? VisibleFrom { get; set; } + + /// + /// The due date for the dialog. Dialogs past due date might be marked as such in frontends but will still be available. + /// + + [JsonPropertyName("dueAt")] + public System.DateTimeOffset? DueAt { get; set; } + + /// + /// Optional process identifier used to indicate a business process this dialog belongs to. + /// + + [JsonPropertyName("process")] + public string Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + + [JsonPropertyName("precedingProcess")] + public string PrecedingProcess { get; set; } + + /// + /// The expiration date for the dialog. This is the last date when the dialog is available for the end user. + ///
+ ///
After this date is passed, the dialog will be considered expired and no longer available for the end user in any + ///
API. If not supplied, the dialog will be considered to never expire. This field can be changed after creation. + ///
+ + [JsonPropertyName("expiresAt")] + public System.DateTimeOffset? ExpiresAt { get; set; } + + /// + /// The aggregated status of the dialog. + /// + + [JsonPropertyName("status")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntities_DialogStatus Status { get; set; } + + /// + /// The dialog unstructured text content. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsCommandsUpdate_Content Content { get; set; } + + /// + /// A list of words (tags) that will be used in dialog search queries. Not visible in end-user DTO. + /// + + [JsonPropertyName("searchTags")] + public ICollection SearchTags { get; set; } + + /// + /// The attachments associated with the dialog (on an aggregate level). + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + /// + /// The immutable list of transmissions associated with the dialog. When updating via PUT, any transmissions + ///
added here will be appended to the existing list of transmissions. + ///
+ + [JsonPropertyName("transmissions")] + public ICollection Transmissions { get; set; } + + /// + /// The GUI actions associated with the dialog. Should be used in browser-based interactive frontends. + /// + + [JsonPropertyName("guiActions")] + public ICollection GuiActions { get; set; } + + /// + /// The API actions associated with the dialog. Should be used in specialized, non-browser-based integrations. + /// + + [JsonPropertyName("apiActions")] + public ICollection ApiActions { get; set; } + + /// + /// An immutable list of activities associated with the dialog. When updating via PUT, any activities added here + ///
will be appended to the existing list of activities. + ///
+ + [JsonPropertyName("activities")] + public ICollection Activities { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DialogsEntities_DialogStatus + { + + [System.Runtime.Serialization.EnumMember(Value = @"New")] + New = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"InProgress")] + InProgress = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"Draft")] + Draft = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"Sent")] + Sent = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"RequiresAttention")] + RequiresAttention = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"Completed")] + Completed = 5, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_Content + { + /// + /// The title of the dialog. Must be text/plain. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// A short summary of the dialog and its current state. Must be text/plain. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Overridden sender name. If not supplied, assume "org" as the sender name. Must be text/plain if supplied. + /// + + [JsonPropertyName("senderName")] + public V1CommonContent_ContentValue SenderName { get; set; } + + /// + /// Additional information about the dialog, this may contain Markdown. + /// + + [JsonPropertyName("additionalInfo")] + public V1CommonContent_ContentValue AdditionalInfo { get; set; } + + /// + /// Used as the human-readable label used to describe the "ExtendedStatus" field. Must be text/plain. + /// + + [JsonPropertyName("extendedStatus")] + public V1CommonContent_ContentValue ExtendedStatus { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. Must be HTTPS. + /// + + [JsonPropertyName("mainContentReference")] + public V1CommonContent_ContentValue MainContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_SearchTag + { + /// + /// A search tag value. + /// + + [JsonPropertyName("value")] + public string Value { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_Attachment + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent additions of attachments. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_AttachmentUrl + { + /// + /// A UUIDv7 used for merging existing data, unknown IDs will be ignored as this entity does not support user-defined IDs. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// The fully qualified URL of the attachment. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// The type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_Transmission + { + /// + /// The UUDIv7 of the action may be provided to support idempotent additions to the list of transmissions. + ///
If not supplied, a new UUIDv7 will be generated. + ///
+ + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// If supplied, overrides the creating date and time for the transmission. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// Arbitrary URI/URN describing a service-specific transmission type. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// Reference to any other transmission that this transmission is related to. + /// + + [JsonPropertyName("relatedTransmissionId")] + public System.Guid? RelatedTransmissionId { get; set; } + + /// + /// The type of transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesTransmissions_DialogTransmissionType Type { get; set; } + + /// + /// The actor that sent the transmission. + /// + + [JsonPropertyName("sender")] + public V1ServiceOwnerCommonActors_Actor Sender { get; set; } + + /// + /// The transmission unstructured text content. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsCommandsUpdate_TransmissionContent Content { get; set; } + + /// + /// The transmission-level attachments. + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_GuiAction + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent additions of Gui Actions. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// The action identifier for the action, corresponding to the "action" attributeId used in the XACML service policy. + /// + + [JsonPropertyName("action")] + public string Action { get; set; } + + /// + /// The fully qualified URL of the action, to which the user will be redirected when the action is triggered. Will be set to + ///
"urn:dialogporten:unauthorized" if the user is not authorized to perform the action. + ///
+ + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// Indicates whether the action results in the dialog being deleted. Used by frontends to implement custom UX + ///
for delete actions. + ///
+ + [JsonPropertyName("isDeleteDialogAction")] + public bool IsDeleteDialogAction { get; set; } + + /// + /// The HTTP method that the frontend should use when redirecting the user. + /// + + [JsonPropertyName("httpMethod")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Http_HttpVerb? HttpMethod { get; set; } + + /// + /// Indicates a priority for the action, making it possible for frontends to adapt GUI elements based on action + ///
priority. + ///
+ + [JsonPropertyName("priority")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActions_DialogGuiActionPriority Priority { get; set; } + + /// + /// The title of the action, this should be short and in verb form. Must be text/plain. + /// + + [JsonPropertyName("title")] + public ICollection Title { get; set; } + + /// + /// If there should be a prompt asking the user for confirmation before the action is executed, + ///
this field should contain the prompt text. + ///
+ + [JsonPropertyName("prompt")] + public ICollection Prompt { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Http_HttpVerb + { + + [System.Runtime.Serialization.EnumMember(Value = @"GET")] + GET = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"POST")] + POST = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"PUT")] + PUT = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"PATCH")] + PATCH = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"DELETE")] + DELETE = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"HEAD")] + HEAD = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"OPTIONS")] + OPTIONS = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"TRACE")] + TRACE = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"CONNECT")] + CONNECT = 8, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DialogsEntitiesActions_DialogGuiActionPriority + { + + [System.Runtime.Serialization.EnumMember(Value = @"Primary")] + Primary = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Secondary")] + Secondary = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"Tertiary")] + Tertiary = 2, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_ApiAction + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent additions of Api Actions. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// String identifier for the action, corresponding to the "action" attributeId used in the XACML service policy, + ///
which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ + [JsonPropertyName("action")] + public string Action { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// The endpoints associated with the action. + /// + + [JsonPropertyName("endpoints")] + public ICollection Endpoints { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_ApiActionEndpoint + { + /// + /// A UUIDv7 used for merging existing data, unknown IDs will be ignored as this entity does not support user-defined IDs. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// Arbitrary string indicating the version of the endpoint. + /// + + [JsonPropertyName("version")] + public string Version { get; set; } + + /// + /// The fully qualified URL of the API endpoint. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The HTTP method that the endpoint expects for this action. + /// + + [JsonPropertyName("httpMethod")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Http_HttpVerb HttpMethod { get; set; } + + /// + /// Link to documentation for the endpoint, providing documentation for integrators. Should be a URL to a + ///
human-readable page. + ///
+ + [JsonPropertyName("documentationUrl")] + public System.Uri DocumentationUrl { get; set; } + + /// + /// Link to the request schema for the endpoint. Used to provide documentation for integrators. + ///
Dialogporten will not validate information on this endpoint. + ///
+ + [JsonPropertyName("requestSchema")] + public System.Uri RequestSchema { get; set; } + + /// + /// Link to the response schema for the endpoint. Used to provide documentation for integrators. + ///
Dialogporten will not validate information on this endpoint. + ///
+ + [JsonPropertyName("responseSchema")] + public System.Uri ResponseSchema { get; set; } + + /// + /// Boolean indicating if the endpoint is deprecated. + /// + + [JsonPropertyName("deprecated")] + public bool Deprecated { get; set; } + + /// + /// Date and time when the endpoint will no longer function. Only set if the endpoint is deprecated. Dialogporten + ///
will not enforce this date. + ///
+ + [JsonPropertyName("sunsetAt")] + public System.DateTimeOffset? SunsetAt { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsUpdate_Activity + { + /// + /// The UUDIv7 of the action may be provided to support idempotent additions to the list of activities. + ///
If not supplied, a new UUIDv7 will be generated. + ///
+ + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// If supplied, overrides the creating date and time for the transmission. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("createdAt")] + public System.DateTimeOffset? CreatedAt { get; set; } + + /// + /// Arbitrary URI/URN describing a service-specific transmission type. + /// + + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// The type of transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActivities_DialogActivityType Type { get; set; } + + /// + /// If the activity is related to a particular transmission, this field will contain the transmission identifier. + ///
Must be present in the request body. + ///
+ + [JsonPropertyName("transmissionId")] + public System.Guid? TransmissionId { get; set; } + + /// + /// The actor that performed the activity. + /// + + [JsonPropertyName("performedBy")] + public V1ServiceOwnerCommonActors_Actor PerformedBy { get; set; } + + /// + /// Unstructured text describing the activity. Only set if the activity type is "Information". + /// + + [JsonPropertyName("description")] + public ICollection Description { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DialogsEntitiesActivities_DialogActivityType + { + + [System.Runtime.Serialization.EnumMember(Value = @"DialogCreated")] + DialogCreated = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"DialogClosed")] + DialogClosed = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"Information")] + Information = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"TransmissionOpened")] + TransmissionOpened = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"PaymentMade")] + PaymentMade = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"SignatureProvided")] + SignatureProvided = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"DialogOpened")] + DialogOpened = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"DialogDeleted")] + DialogDeleted = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"DialogRestored")] + DialogRestored = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"SentToSigning")] + SentToSigning = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"SentToFormFill")] + SentToFormFill = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"SentToSendIn")] + SentToSendIn = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"SentToPayment")] + SentToPayment = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"FormSubmitted")] + FormSubmitted = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"FormSaved")] + FormSaved = 14, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaginatedListOfV1ServiceOwnerDialogsQueriesSearch_Dialog + { + /// + /// The paginated list of items + /// + + [JsonPropertyName("items")] + public ICollection Items { get; set; } + + /// + /// Whether there are more items available that can be fetched by supplying the continuation token + /// + + [JsonPropertyName("hasNextPage")] + public bool HasNextPage { get; set; } + + /// + /// The continuation token to be used to fetch the next page of items + /// + + [JsonPropertyName("continuationToken")] + public string ContinuationToken { get; set; } + + /// + /// The current sorting order of the items + /// + + [JsonPropertyName("orderBy")] + public string OrderBy { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesSearch_Dialog + { + /// + /// The unique identifier for the dialog in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The service owner code representing the organization (service owner) related to this dialog. + /// + + [JsonPropertyName("org")] + public string Org { get; set; } + + /// + /// The unique identifier for the revision in UUIDv4 format. + /// + + [JsonPropertyName("revision")] + public System.Guid Revision { get; set; } + + /// + /// The service identifier for the service that the dialog is related to in URN-format. + ///
This corresponds to a service resource in the Altinn Resource Registry. + ///
+ + [JsonPropertyName("serviceResource")] + public string ServiceResource { get; set; } + + /// + /// The ServiceResource type, as defined in Altinn Resource Registry (see ResourceType). + /// + + [JsonPropertyName("serviceResourceType")] + public string ServiceResourceType { get; set; } + + /// + /// The party code representing the organization or person that the dialog belongs to in URN format. + /// + + [JsonPropertyName("party")] + public string Party { get; set; } + + /// + /// Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come + ///
to a natural completion (successful or not). + ///
+ + [JsonPropertyName("progress")] + public int? Progress { get; set; } + + /// + /// Optional process identifier used to indicate a business process this dialog belongs to. + /// + + [JsonPropertyName("process")] + public string Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + + [JsonPropertyName("precedingProcess")] + public string PrecedingProcess { get; set; } + + /// + /// The number of attachments in the dialog made available for browser-based frontends. + /// + + [JsonPropertyName("guiAttachmentCount")] + public int? GuiAttachmentCount { get; set; } + + /// + /// Arbitrary string with a service-specific indicator of status, typically used to indicate a fine-grained state of + ///
the dialog to further specify the "status" enum. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details on the possible values (if + ///
in use). + ///
+ + [JsonPropertyName("extendedStatus")] + public string ExtendedStatus { get; set; } + + /// + /// Arbitrary string with a service-specific reference to an external system or service. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("externalReference")] + public string ExternalReference { get; set; } + + /// + /// The date and time when the dialog was created. + /// + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// The date and time when the dialog was last updated. + /// + + [JsonPropertyName("updatedAt")] + public System.DateTimeOffset UpdatedAt { get; set; } + + /// + /// The due date for the dialog. This is the last date when the dialog is expected to be completed. + /// + + [JsonPropertyName("dueAt")] + public System.DateTimeOffset? DueAt { get; set; } + + /// + /// If deleted, the date and time when the deletion was performed. + /// + + [JsonPropertyName("deletedAt")] + public System.DateTimeOffset? DeletedAt { get; set; } + + /// + /// The timestamp when the dialog will be made visible for authorized end users. + /// + + [JsonPropertyName("visibleFrom")] + public System.DateTimeOffset? VisibleFrom { get; set; } + + /// + /// The aggregated status of the dialog. + /// + + [JsonPropertyName("status")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntities_DialogStatus Status { get; set; } + + /// + /// Current display state. + /// + + [JsonPropertyName("systemLabel")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogEndUserContextsEntities_SystemLabel SystemLabel { get; set; } + + /// + /// The latest entry in the dialog's activity log. + /// + + [JsonPropertyName("latestActivity")] + public V1ServiceOwnerDialogsQueriesSearch_DialogActivity LatestActivity { get; set; } + + /// + /// The list of seen log entries for the dialog newer than the dialog ChangedAt date. + /// + + [JsonPropertyName("seenSinceLastUpdate")] + public ICollection SeenSinceLastUpdate { get; set; } + + /// + /// The content of the dialog in search results. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsQueriesSearch_Content Content { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DialogEndUserContextsEntities_SystemLabel + { + + [System.Runtime.Serialization.EnumMember(Value = @"Default")] + Default = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Bin")] + Bin = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"Archive")] + Archive = 2, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesSearch_DialogActivity + { + /// + /// The unique identifier for the activity in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The date and time when the activity was created. + /// + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset? CreatedAt { get; set; } + + /// + /// An arbitrary string with a service-specific activity type. + ///
+ ///
Consult the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// The type of activity. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActivities_DialogActivityType Type { get; set; } + + /// + /// If the activity is related to a particular transmission, this field will contain the transmission identifier. + /// + + [JsonPropertyName("transmissionId")] + public System.Guid? TransmissionId { get; set; } + + /// + /// The actor that performed the activity. + /// + + [JsonPropertyName("performedBy")] + public V1ServiceOwnerCommonActors_Actor PerformedBy { get; set; } + + /// + /// Unstructured text describing the activity. Only set if the activity type is "Information". + /// + + [JsonPropertyName("description")] + public ICollection Description { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesSearch_DialogSeenLog + { + /// + /// The unique identifier for the seen log entry in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The timestamp when the dialog revision was seen. + /// + + [JsonPropertyName("seenAt")] + public System.DateTimeOffset SeenAt { get; set; } + + /// + /// The actor that saw the dialog revision. + /// + + [JsonPropertyName("seenBy")] + public V1ServiceOwnerCommonActors_Actor SeenBy { get; set; } + + /// + /// Flag indicating whether the seen log entry was created via the service owner. + ///
+ ///
This is used when the service owner uses the service owner API to implement its own frontend. + ///
+ + [JsonPropertyName("isViaServiceOwner")] + public bool? IsViaServiceOwner { get; set; } + + /// + /// Flag indicating whether the seen log entry was created by the end user supplied in the query. + /// + + [JsonPropertyName("isCurrentEndUser")] + public bool IsCurrentEndUser { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesSearch_Content + { + /// + /// The title of the dialog. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// A short summary of the dialog and its current state. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Overridden sender name. If not supplied, assume "org" as the sender name. + /// + + [JsonPropertyName("senderName")] + public V1CommonContent_ContentValue SenderName { get; set; } + + /// + /// Used as the human-readable label used to describe the "ExtendedStatus" field. + /// + + [JsonPropertyName("extendedStatus")] + public V1CommonContent_ContentValue ExtendedStatus { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_Dialog + { + /// + /// The unique identifier for the dialog in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// An optional key to ensure idempotency in dialog creation. If provided, it allows for the safe re-submission of the same dialog creation request without creating duplicate entries. + ///
+ ///
+ + [JsonPropertyName("idempotentKey")] + public string IdempotentKey { get; set; } + + /// + /// The unique identifier for the revision in UUIDv4 format. + /// + + [JsonPropertyName("revision")] + public System.Guid Revision { get; set; } + + /// + /// The service owner code representing the organization (service owner) related to this dialog. + /// + + [JsonPropertyName("org")] + public string Org { get; set; } + + /// + /// The service identifier for the service that the dialog is related to in URN-format. + ///
This corresponds to a service resource in the Altinn Resource Registry. + ///
+ + [JsonPropertyName("serviceResource")] + public string ServiceResource { get; set; } + + /// + /// The ServiceResource type, as defined in Altinn Resource Registry (see ResourceType). + /// + + [JsonPropertyName("serviceResourceType")] + public string ServiceResourceType { get; set; } + + /// + /// The party code representing the organization or person that the dialog belongs to in URN format. + /// + + [JsonPropertyName("party")] + public string Party { get; set; } + + /// + /// Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come + ///
to a natural completion (successful or not). + ///
+ + [JsonPropertyName("progress")] + public int? Progress { get; set; } + + /// + /// Optional process identifier used to indicate a business process this dialog belongs to. + /// + + [JsonPropertyName("process")] + public string Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + + [JsonPropertyName("precedingProcess")] + public string PrecedingProcess { get; set; } + + /// + /// Arbitrary string with a service-specific indicator of status, typically used to indicate a fine-grained state of + ///
the dialog to further specify the "status" enum. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details on the possible values (if + ///
in use). + ///
+ + [JsonPropertyName("extendedStatus")] + public string ExtendedStatus { get; set; } + + /// + /// Arbitrary string with a service-specific reference to an external system or service. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("externalReference")] + public string ExternalReference { get; set; } + + /// + /// If deleted, the date and time when the deletion was performed. + /// + + [JsonPropertyName("deletedAt")] + public System.DateTimeOffset? DeletedAt { get; set; } + + /// + /// The timestamp when the dialog will be made visible for authorized end users. + /// + + [JsonPropertyName("visibleFrom")] + public System.DateTimeOffset? VisibleFrom { get; set; } + + /// + /// The due date for the dialog. Dialogs past due date might be marked as such in frontends but will still be available. + /// + + [JsonPropertyName("dueAt")] + public System.DateTimeOffset? DueAt { get; set; } + + /// + /// The expiration date for the dialog. This is the last date when the dialog is available for the end user. + ///
+ ///
After this date is passed, the dialog will be considered expired and no longer available for the end user in any + ///
API. If not supplied, the dialog will be considered to never expire. This field can be changed by the service + ///
owner after the dialog has been created. + ///
+ + [JsonPropertyName("expiresAt")] + public System.DateTimeOffset? ExpiresAt { get; set; } + + /// + /// The date and time when the dialog was created. + /// + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// The date and time when the dialog was last updated. + /// + + [JsonPropertyName("updatedAt")] + public System.DateTimeOffset UpdatedAt { get; set; } + + /// + /// The aggregated status of the dialog. + /// + + [JsonPropertyName("status")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntities_DialogStatus Status { get; set; } + + /// + /// Current display state. + /// + + [JsonPropertyName("systemLabel")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogEndUserContextsEntities_SystemLabel SystemLabel { get; set; } + + /// + /// The dialog unstructured text content. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsQueriesGet_Content Content { get; set; } + + /// + /// The list of words (tags) that will be used in dialog search queries. Not visible in end-user DTO. + /// + + [JsonPropertyName("searchTags")] + public ICollection SearchTags { get; set; } + + /// + /// The attachments associated with the dialog (on an aggregate level). + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + /// + /// The immutable list of transmissions associated with the dialog. + /// + + [JsonPropertyName("transmissions")] + public ICollection Transmissions { get; set; } + + /// + /// The GUI actions associated with the dialog. Should be used in browser-based interactive frontends. + /// + + [JsonPropertyName("guiActions")] + public ICollection GuiActions { get; set; } + + /// + /// The API actions associated with the dialog. Should be used in specialized, non-browser-based integrations. + /// + + [JsonPropertyName("apiActions")] + public ICollection ApiActions { get; set; } + + /// + /// An immutable list of activities associated with the dialog. + /// + + [JsonPropertyName("activities")] + public ICollection Activities { get; set; } + + /// + /// The list of seen log entries for the dialog newer than the dialog ChangedAt date. + /// + + [JsonPropertyName("seenSinceLastUpdate")] + public ICollection SeenSinceLastUpdate { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OrderSetOfTOrderDefinitionAndTTarget + { + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ContinuationTokenSetOfTOrderDefinitionAndTTarget + { + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum V1Common_DeletedFilter + { + + [System.Runtime.Serialization.EnumMember(Value = @"Exclude")] + Exclude = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Include")] + Include = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"Only")] + Only = 2, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_Content + { + /// + /// The title of the dialog. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// A short summary of the dialog and its current state. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Overridden sender name. If not supplied, assume "org" as the sender name. + /// + + [JsonPropertyName("senderName")] + public V1CommonContent_ContentValue SenderName { get; set; } + + /// + /// Additional information about the dialog, this may contain Markdown. + /// + + [JsonPropertyName("additionalInfo")] + public V1CommonContent_ContentValue AdditionalInfo { get; set; } + + /// + /// Used as the human-readable label used to describe the "ExtendedStatus" field. + /// + + [JsonPropertyName("extendedStatus")] + public V1CommonContent_ContentValue ExtendedStatus { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. Must be HTTPS. + ///
Allowed media types: application/vnd.dialogporten.frontchannelembed+json;type=markdown + ///
+ + [JsonPropertyName("mainContentReference")] + public V1CommonContent_ContentValue MainContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_SearchTag + { + /// + /// A search tag value. + /// + + [JsonPropertyName("value")] + public string Value { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogAttachment + { + /// + /// The unique identifier for the attachment in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogAttachmentUrl + { + /// + /// The unique identifier for the attachment URL in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The fully qualified URL of the attachment. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// What type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogTransmission + { + /// + /// The unique identifier for the transmission in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The date and time when the transmission was created. + /// + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// Flag indicating if the authenticated user supplied in the query is authorized for this transmission. + /// + + [JsonPropertyName("isAuthorized")] + public bool? IsAuthorized { get; set; } + + /// + /// Arbitrary URI/URN describing a service-specific transmission type. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// Reference to any other transmission that this transmission is related to. + /// + + [JsonPropertyName("relatedTransmissionId")] + public System.Guid? RelatedTransmissionId { get; set; } + + /// + /// The type of transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesTransmissions_DialogTransmissionType Type { get; set; } + + /// + /// The actor that sent the transmission. + /// + + [JsonPropertyName("sender")] + public V1ServiceOwnerCommonActors_Actor Sender { get; set; } + + /// + /// The transmission unstructured text content. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsQueriesGet_DialogTransmissionContent Content { get; set; } + + /// + /// The transmission-level attachments. + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogTransmissionContent + { + /// + /// The transmission title. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// The transmission summary. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. Must be HTTPS. + ///
Allowed media types: application/vnd.dialogporten.frontchannelembed+json;type=markdown + ///
+ + [JsonPropertyName("contentReference")] + public V1CommonContent_ContentValue ContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogTransmissionAttachment + { + /// + /// The unique identifier for the attachment in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogTransmissionAttachmentUrl + { + /// + /// The fully qualified URL of the attachment. Will be set to "urn:dialogporten:unauthorized" if the user is + ///
not authorized to access the transmission. + ///
+ + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// The type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogGuiAction + { + /// + /// The unique identifier for the action in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The action identifier for the action, corresponding to the "action" attributeId used in the XACML service policy. + /// + + [JsonPropertyName("action")] + public string Action { get; set; } + + /// + /// The fully qualified URL of the action, to which the user will be redirected when the action is triggered. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// Whether the user, if supplied in the query, is authorized to perform the action. + /// + + [JsonPropertyName("isAuthorized")] + public bool? IsAuthorized { get; set; } + + /// + /// Indicates whether the action results in the dialog being deleted. Used by frontends to implement custom UX + ///
for delete actions. + ///
+ + [JsonPropertyName("isDeleteDialogAction")] + public bool IsDeleteDialogAction { get; set; } + + /// + /// Indicates a priority for the action, making it possible for frontends to adapt GUI elements based on action + ///
priority. + ///
+ + [JsonPropertyName("priority")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActions_DialogGuiActionPriority Priority { get; set; } + + /// + /// The HTTP method that the frontend should use when redirecting the user. + /// + + [JsonPropertyName("httpMethod")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Http_HttpVerb HttpMethod { get; set; } + + /// + /// The title of the action, this should be short and in verb form. + /// + + [JsonPropertyName("title")] + public ICollection Title { get; set; } + + /// + /// If there should be a prompt asking the user for confirmation before the action is executed, + ///
this field should contain the prompt text. + ///
+ + [JsonPropertyName("prompt")] + public ICollection Prompt { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogApiAction + { + /// + /// The unique identifier for the action in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// String identifier for the action, corresponding to the "action" attributeId used in the XACML service policy, + ///
which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ + [JsonPropertyName("action")] + public string Action { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// True if the authenticated user (set in the query) is authorized for this action. + /// + + [JsonPropertyName("isAuthorized")] + public bool? IsAuthorized { get; set; } + + /// + /// The endpoints associated with the action. + /// + + [JsonPropertyName("endpoints")] + public ICollection Endpoints { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogApiActionEndpoint + { + /// + /// The unique identifier for the endpoint in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// Arbitrary string indicating the version of the endpoint. + ///
+ ///
Consult the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("version")] + public string Version { get; set; } + + /// + /// The fully qualified URL of the API endpoint. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The HTTP method that the endpoint expects for this action. + /// + + [JsonPropertyName("httpMethod")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Http_HttpVerb HttpMethod { get; set; } + + /// + /// Link to service provider documentation for the endpoint. Used for service owners to provide documentation for + ///
integrators. Should be a URL to a human-readable page. + ///
+ + [JsonPropertyName("documentationUrl")] + public System.Uri DocumentationUrl { get; set; } + + /// + /// Link to the request schema for the endpoint. Used by service owners to provide documentation for integrators. + ///
Dialogporten will not validate information on this endpoint. + ///
+ + [JsonPropertyName("requestSchema")] + public System.Uri RequestSchema { get; set; } + + /// + /// Link to the response schema for the endpoint. Used for service owners to provide documentation for integrators. + ///
Dialogporten will not validate information on this endpoint. + ///
+ + [JsonPropertyName("responseSchema")] + public System.Uri ResponseSchema { get; set; } + + /// + /// Boolean indicating if the endpoint is deprecated. Integrators should migrate to endpoints with a higher version. + /// + + [JsonPropertyName("deprecated")] + public bool Deprecated { get; set; } + + /// + /// Date and time when the service owner has indicated that endpoint will no longer function. Only set if the endpoint + ///
is deprecated. Dialogporten will not enforce this date. + ///
+ + [JsonPropertyName("sunsetAt")] + public System.DateTimeOffset? SunsetAt { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogActivity + { + /// + /// The unique identifier for the activity in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The date and time when the activity was created. + /// + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset? CreatedAt { get; set; } + + /// + /// An arbitrary URI/URN with a service-specific activity type. + ///
+ ///
Consult the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// The type of activity. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActivities_DialogActivityType Type { get; set; } + + /// + /// If the activity is related to a particular transmission, this field will contain the transmission identifier. + /// + + [JsonPropertyName("transmissionId")] + public System.Guid? TransmissionId { get; set; } + + /// + /// The actor that performed the activity. + /// + + [JsonPropertyName("performedBy")] + public V1ServiceOwnerCommonActors_Actor PerformedBy { get; set; } + + /// + /// Unstructured text describing the activity. Only set if the activity type is "Information". + /// + + [JsonPropertyName("description")] + public ICollection Description { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsQueriesGet_DialogSeenLog + { + /// + /// The unique identifier for the seen log entry in UUIDv7 format. + /// + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + /// + /// The timestamp when the dialog revision was seen. + /// + + [JsonPropertyName("seenAt")] + public System.DateTimeOffset SeenAt { get; set; } + + /// + /// The actor that saw the dialog revision. + /// + + [JsonPropertyName("seenBy")] + public V1ServiceOwnerCommonActors_Actor SeenBy { get; set; } + + /// + /// Flag indicating whether the seen log entry was created via the service owner. + ///
+ ///
This is used when the service owner uses the service owner API to implement its own frontend. + ///
+ + [JsonPropertyName("isViaServiceOwner")] + public bool? IsViaServiceOwner { get; set; } + + /// + /// Flag indicating whether the seen log entry was created by the current end user, if provided in the query. + /// + + [JsonPropertyName("isCurrentEndUser")] + public bool IsCurrentEndUser { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_Dialog + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent creation of dialogs. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// An optional key to ensure idempotency in dialog creation. If provided, it allows for the safe re-submission of the same dialog creation request without creating duplicate entries. + /// + + [JsonPropertyName("idempotentKey")] + public string IdempotentKey { get; set; } + + /// + /// The service identifier for the service that the dialog is related to in URN-format. + ///
This corresponds to a resource in the Altinn Resource Registry, which the authenticated organization + ///
must own, i.e., be listed as the "competent authority" in the Resource Registry entry. + ///
+ + [JsonPropertyName("serviceResource")] + public string ServiceResource { get; set; } + + /// + /// The party code representing the organization or person that the dialog belongs to in URN format. + /// + + [JsonPropertyName("party")] + public string Party { get; set; } + + /// + /// Advisory indicator of progress, represented as 1-100 percentage value. 100% representing a dialog that has come + ///
to a natural completion (successful or not). + ///
+ + [JsonPropertyName("progress")] + public int? Progress { get; set; } + + /// + /// Arbitrary string with a service-specific indicator of status, typically used to indicate a fine-grained state of + ///
the dialog to further specify the "status" enum. + ///
+ + [JsonPropertyName("extendedStatus")] + public string ExtendedStatus { get; set; } + + /// + /// Arbitrary string with a service-specific reference to an external system or service. + /// + + [JsonPropertyName("externalReference")] + public string ExternalReference { get; set; } + + /// + /// The timestamp when the dialog should be made visible for authorized end users. If not provided, the dialog will be + ///
immediately available. + ///
+ + [JsonPropertyName("visibleFrom")] + public System.DateTimeOffset? VisibleFrom { get; set; } + + /// + /// The due date for the dialog. Dialogs past due date might be marked as such in frontends but will still be available. + /// + + [JsonPropertyName("dueAt")] + public System.DateTimeOffset? DueAt { get; set; } + + /// + /// Optional process identifier used to indicate a business process this dialog belongs to. + /// + + [JsonPropertyName("process")] + public string Process { get; set; } + + /// + /// Optional preceding process identifier to indicate the business process that preceded the process indicated in the "Process" field. Cannot be set without also "Process" being set. + /// + + [JsonPropertyName("precedingProcess")] + public string PrecedingProcess { get; set; } + + /// + /// The expiration date for the dialog. This is the last date when the dialog is available for the end user. + ///
+ ///
After this date is passed, the dialog will be considered expired and no longer available for the end user in any + ///
API. If not supplied, the dialog will be considered to never expire. This field can be changed after creation. + ///
+ + [JsonPropertyName("expiresAt")] + public System.DateTimeOffset? ExpiresAt { get; set; } + + /// + /// If set, will override the date and time when the dialog is set as created. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// If set, will override the date and time when the dialog is set as last updated. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("updatedAt")] + public System.DateTimeOffset UpdatedAt { get; set; } + + /// + /// The aggregated status of the dialog. + /// + + [JsonPropertyName("status")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntities_DialogStatus Status { get; set; } + + /// + /// Set the system label of the dialog Migration purposes. + /// + + [JsonPropertyName("systemLabel")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogEndUserContextsEntities_SystemLabel? SystemLabel { get; set; } + + /// + /// The dialog unstructured text content. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsCommandsCreate_Content Content { get; set; } + + /// + /// A list of words (tags) that will be used in dialog search queries. Not visible in end-user DTO. + /// + + [JsonPropertyName("searchTags")] + public ICollection SearchTags { get; set; } + + /// + /// The attachments associated with the dialog (on an aggregate level). + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + /// + /// The immutable list of transmissions associated with the dialog. + /// + + [JsonPropertyName("transmissions")] + public ICollection Transmissions { get; set; } + + /// + /// The GUI actions associated with the dialog. Should be used in browser-based interactive frontends. + /// + + [JsonPropertyName("guiActions")] + public ICollection GuiActions { get; set; } + + /// + /// The API actions associated with the dialog. Should be used in specialized, non-browser-based integrations. + /// + + [JsonPropertyName("apiActions")] + public ICollection ApiActions { get; set; } + + /// + /// An immutable list of activities associated with the dialog. + /// + + [JsonPropertyName("activities")] + public ICollection Activities { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_Content + { + /// + /// The title of the dialog. + ///
Supported media types: text/plain + ///
+ + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// A short summary of the dialog and its current state. + ///
Supported media types: text/plain + ///
+ + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Overridden sender name. If not supplied, assume "org" as the sender name. Must be text/plain if supplied. + ///
Supported media types: text/plain + ///
+ + [JsonPropertyName("senderName")] + public V1CommonContent_ContentValue SenderName { get; set; } + + /// + /// Additional information about the dialog. + ///
Supported media types: text/plain, text/markdown + ///
+ + [JsonPropertyName("additionalInfo")] + public V1CommonContent_ContentValue AdditionalInfo { get; set; } + + /// + /// Used as the human-readable label used to describe the "ExtendedStatus" field. + ///
Supported media types: text/plain + ///
+ + [JsonPropertyName("extendedStatus")] + public V1CommonContent_ContentValue ExtendedStatus { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. Must be HTTPS. + ///
Supported media types: application/vnd.dialogporten.frontchannelembed+json;type=markdown + ///
+ + [JsonPropertyName("mainContentReference")] + public V1CommonContent_ContentValue MainContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_SearchTag + { + /// + /// A search tag value. + /// + + [JsonPropertyName("value")] + public string Value { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_Attachment + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent creation of attachments. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_AttachmentUrl + { + /// + /// The fully qualified URL of the attachment. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// The type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_Transmission + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent creation of transmissions. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// If supplied, overrides the creating date and time for the transmission. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// Arbitrary URI/URN describing a service-specific transmission type. + ///
+ ///
Refer to the service-specific documentation provided by the service owner for details (if in use). + ///
+ + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// Reference to any other transmission that this transmission is related to. + /// + + [JsonPropertyName("relatedTransmissionId")] + public System.Guid? RelatedTransmissionId { get; set; } + + /// + /// The type of transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesTransmissions_DialogTransmissionType Type { get; set; } + + /// + /// The actor that sent the transmission. + /// + + [JsonPropertyName("sender")] + public V1ServiceOwnerCommonActors_Actor Sender { get; set; } + + /// + /// The transmission unstructured text content. + /// + + [JsonPropertyName("content")] + public V1ServiceOwnerDialogsCommandsCreate_TransmissionContent Content { get; set; } + + /// + /// The transmission-level attachments. + /// + + [JsonPropertyName("attachments")] + public ICollection Attachments { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_TransmissionContent + { + /// + /// The transmission title. Must be text/plain. + /// + + [JsonPropertyName("title")] + public V1CommonContent_ContentValue Title { get; set; } + + /// + /// The transmission summary. + /// + + [JsonPropertyName("summary")] + public V1CommonContent_ContentValue Summary { get; set; } + + /// + /// Front-channel embedded content. Used to dynamically embed content in the frontend from an external URL. Must be HTTPS. + ///
Allowed media types: application/vnd.dialogporten.frontchannelembed+json;type=markdown + ///
+ + [JsonPropertyName("contentReference")] + public V1CommonContent_ContentValue ContentReference { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_TransmissionAttachment + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent creation of transmission attachments. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// The display name of the attachment that should be used in GUIs. + /// + + [JsonPropertyName("displayName")] + public ICollection DisplayName { get; set; } + + /// + /// The URLs associated with the attachment, each referring to a different representation of the attachment. + /// + + [JsonPropertyName("urls")] + public ICollection Urls { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_TransmissionAttachmentUrl + { + /// + /// The fully qualified URL of the attachment. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The media type of the attachment. + /// + + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } + + /// + /// The type of consumer the URL is intended for. + /// + + [JsonPropertyName("consumerType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Attachments_AttachmentUrlConsumerType ConsumerType { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_GuiAction + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent creation of Gui Actions. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// The action identifier for the action, corresponding to the "action" attributeId used in the XACML service policy. + /// + + [JsonPropertyName("action")] + public string Action { get; set; } + + /// + /// The fully qualified URL of the action, to which the user will be redirected when the action is triggered. Will be set to + ///
"urn:dialogporten:unauthorized" if the user is not authorized to perform the action. + ///
+ + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// Indicates whether the action results in the dialog being deleted. Used by frontends to implement custom UX + ///
for delete actions. + ///
+ + [JsonPropertyName("isDeleteDialogAction")] + public bool IsDeleteDialogAction { get; set; } + + /// + /// The HTTP method that the frontend should use when redirecting the user. + /// + + [JsonPropertyName("httpMethod")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Http_HttpVerb? HttpMethod { get; set; } + + /// + /// Indicates a priority for the action, making it possible for frontends to adapt GUI elements based on action + ///
priority. + ///
+ + [JsonPropertyName("priority")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActions_DialogGuiActionPriority Priority { get; set; } + + /// + /// The title of the action, this should be short and in verb form. Must be text/plain. + /// + + [JsonPropertyName("title")] + public ICollection Title { get; set; } + + /// + /// If there should be a prompt asking the user for confirmation before the action is executed, + ///
this field should contain the prompt text. + ///
+ + [JsonPropertyName("prompt")] + public ICollection Prompt { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_ApiAction + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent creation of Api Actions. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// String identifier for the action, corresponding to the "action" attributeId used in the XACML service policy, + ///
which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ + [JsonPropertyName("action")] + public string Action { get; set; } + + /// + /// Contains an authorization resource attributeId, that can used in custom authorization rules in the XACML service + ///
policy, which by default is the policy belonging to the service referred to by "serviceResource" in the dialog. + ///
+ ///
Can also be used to refer to other service policies. + ///
+ + [JsonPropertyName("authorizationAttribute")] + public string AuthorizationAttribute { get; set; } + + /// + /// The endpoints associated with the action. + /// + + [JsonPropertyName("endpoints")] + public ICollection Endpoints { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_ApiActionEndpoint + { + /// + /// Arbitrary string indicating the version of the endpoint. + /// + + [JsonPropertyName("version")] + public string Version { get; set; } + + /// + /// The fully qualified URL of the API endpoint. + /// + + [JsonPropertyName("url")] + public System.Uri Url { get; set; } + + /// + /// The HTTP method that the endpoint expects for this action. + /// + + [JsonPropertyName("httpMethod")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public Http_HttpVerb HttpMethod { get; set; } + + /// + /// Link to documentation for the endpoint, providing documentation for integrators. Should be a URL to a + ///
human-readable page. + ///
+ + [JsonPropertyName("documentationUrl")] + public System.Uri DocumentationUrl { get; set; } + + /// + /// Link to the request schema for the endpoint. Used to provide documentation for integrators. + ///
Dialogporten will not validate information on this endpoint. + ///
+ + [JsonPropertyName("requestSchema")] + public System.Uri RequestSchema { get; set; } + + /// + /// Link to the response schema for the endpoint. Used to provide documentation for integrators. + ///
Dialogporten will not validate information on this endpoint. + ///
+ + [JsonPropertyName("responseSchema")] + public System.Uri ResponseSchema { get; set; } + + /// + /// Boolean indicating if the endpoint is deprecated. + /// + + [JsonPropertyName("deprecated")] + public bool Deprecated { get; set; } + + /// + /// Date and time when the endpoint will no longer function. Only set if the endpoint is deprecated. Dialogporten + ///
will not enforce this date. + ///
+ + [JsonPropertyName("sunsetAt")] + public System.DateTimeOffset? SunsetAt { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogsCommandsCreate_Activity + { + /// + /// A self-defined UUIDv7 may be provided to support idempotent creation of activities. If not provided, a new UUIDv7 will be generated. + /// + + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// If supplied, overrides the creating date and time for the transmission. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("createdAt")] + public System.DateTimeOffset? CreatedAt { get; set; } + + /// + /// Arbitrary URI/URN describing a service-specific transmission type. + /// + + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// The type of transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActivities_DialogActivityType Type { get; set; } + + /// + /// If the activity is related to a particular transmission, this field will contain the transmission identifier. + ///
Must be present in the request body. + ///
+ + [JsonPropertyName("transmissionId")] + public System.Guid? TransmissionId { get; set; } + + /// + /// The actor that performed the activity. + /// + + [JsonPropertyName("performedBy")] + public V1ServiceOwnerCommonActors_Actor PerformedBy { get; set; } + + /// + /// Unstructured text describing the activity. Only set if the activity type is "Information". + /// + + [JsonPropertyName("description")] + public ICollection Description { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogActivitiesQueriesSearch_Activity + { + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset CreatedAt { get; set; } + + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActivities_DialogActivityType Type { get; set; } + + [JsonPropertyName("deletedAt")] + public System.DateTimeOffset? DeletedAt { get; set; } + + [JsonPropertyName("transmissionId")] + public System.Guid? TransmissionId { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogActivitiesQueriesNotificationCondition_NotificationCondition + { + + [JsonPropertyName("sendNotification")] + public bool SendNotification { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogActivitiesQueriesGet_Activity + { + + [JsonPropertyName("id")] + public System.Guid Id { get; set; } + + [JsonPropertyName("createdAt")] + public System.DateTimeOffset? CreatedAt { get; set; } + + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActivities_DialogActivityType Type { get; set; } + + [JsonPropertyName("deletedAt")] + public System.DateTimeOffset? DeletedAt { get; set; } + + [JsonPropertyName("transmissionId")] + public System.Guid? TransmissionId { get; set; } + + [JsonPropertyName("performedBy")] + public V1ServiceOwnerCommonActors_Actor PerformedBy { get; set; } + + [JsonPropertyName("description")] + public ICollection Description { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum V1ServiceOwnerDialogActivitiesQueriesNotificationCondition_NotificationConditionType + { + + [System.Runtime.Serialization.EnumMember(Value = @"NotExists")] + NotExists = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Exists")] + Exists = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class V1ServiceOwnerDialogActivitiesCreate_ActivityRequest + { + /// + /// The UUDIv7 of the action may be provided to support idempotent additions to the list of activities. + ///
If not supplied, a new UUIDv7 will be generated. + ///
+ + [JsonPropertyName("id")] + public System.Guid? Id { get; set; } + + /// + /// If supplied, overrides the creating date and time for the transmission. + ///
If not supplied, the current date /time will be used. + ///
+ + [JsonPropertyName("createdAt")] + public System.DateTimeOffset? CreatedAt { get; set; } + + /// + /// Arbitrary URI/URN describing a service-specific transmission type. + /// + + [JsonPropertyName("extendedType")] + public System.Uri ExtendedType { get; set; } + + /// + /// The type of transmission. + /// + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DialogsEntitiesActivities_DialogActivityType Type { get; set; } + + /// + /// If the activity is related to a particular transmission, this field will contain the transmission identifier. + ///
Must be present in the request body. + ///
+ + [JsonPropertyName("transmissionId")] + public System.Guid? TransmissionId { get; set; } + + /// + /// The actor that performed the activity. + /// + + [JsonPropertyName("performedBy")] + public V1ServiceOwnerCommonActors_Actor PerformedBy { get; set; } + + /// + /// Unstructured text describing the activity. Only set if the activity type is "Information". + /// + + [JsonPropertyName("description")] + public ICollection Description { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class JsonPatchOperations_Operation + { + + [JsonPropertyName("operationType")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public JsonPatchOperations_OperationType OperationType { get; set; } + + [JsonPropertyName("path")] + public string Path { get; set; } + + [JsonPropertyName("op")] + public string Op { get; set; } + + [JsonPropertyName("from")] + public string From { get; set; } + + [JsonPropertyName("value")] + public object Value { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] + public enum JsonPatchOperations_OperationType + { + + [System.Runtime.Serialization.EnumMember(Value = @"Add")] + Add = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Remove")] + Remove = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"Replace")] + Replace = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"Move")] + Move = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"Copy")] + Copy = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"Test")] + Test = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"Invalid")] + Invalid = 6, + + } + + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 \ No newline at end of file diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs b/src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs new file mode 100644 index 000000000..36a38ff81 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs @@ -0,0 +1,12 @@ +namespace Altinn.ApiClients.Dialogporten; + +public interface IDialogTokenValidator +{ + IValidationResult Validate(ReadOnlySpan token); +} + +public interface IValidationResult +{ + bool IsValid { get; } + Dictionary> Errors { get; } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Infrastructure/IInternalDialogportenApi.cs b/src/Digdir.Library.Dialogporten.WebApiClient/Infrastructure/IInternalDialogportenApi.cs new file mode 100644 index 000000000..fae0f2fbb --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Infrastructure/IInternalDialogportenApi.cs @@ -0,0 +1,24 @@ +using Refit; + +namespace Altinn.ApiClients.Dialogporten.Infrastructure; + +internal interface IInternalDialogportenApi +{ + [Get("/api/v1/.well-known/jwks.json")] + Task GetJwks(CancellationToken cancellationToken); +} + +internal sealed class DialogportenJwks +{ + public required List Keys { get; init; } + + internal sealed class JsonWebKey + { + public required string Kty { get; init; } + public required string Use { get; init; } + public required string Kid { get; init; } + public required string Crv { get; init; } + public required string X { get; init; } + public required string Alg { get; init; } + } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/README.md b/src/Digdir.Library.Dialogporten.WebApiClient/README.md new file mode 100644 index 000000000..ba77839b2 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/README.md @@ -0,0 +1,44 @@ +# SO SDK + +Simple overview +Refit-based client SDK Based on https://github.com/altinn/altinn-apiclient-maskinporten + +The refit-Interface is autogenerated with refitter. It uses OperationId to create method names. +Uses refit IApiResponse on returns. + +## Installation + +Install nuget + +## Usage + +This library provides extensions methods providing means to create dialogporten clients. + +Setup + +```json +{ + "dialogportenSettings": { + "BaseUri": "", + "ThrowOnPublicKeyFetchInit": "", + "Maskinporten": { + "ClientId": "", + "Environment": "", + "Scope": "", + "EncodedJwk": "" + } + } +} +``` + +```C# +var configuration = new ConfigurationBuilder() + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .Build(); + +var services = new ServiceCollection(); + +services.AddSingleton(configuration); + +services.AddDialogportenClient(); +``` diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/ServiceCollectionExtensions.cs b/src/Digdir.Library.Dialogporten.WebApiClient/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..e9f1914f0 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/ServiceCollectionExtensions.cs @@ -0,0 +1,59 @@ +using System.CodeDom.Compiler; +using System.Reflection; +using Altinn.ApiClients.Dialogporten.Common; +using Altinn.ApiClients.Dialogporten.Infrastructure; +using Altinn.ApiClients.Dialogporten.Services; +using Altinn.ApiClients.Maskinporten.Extensions; +using Altinn.ApiClients.Maskinporten.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using Refit; + +namespace Altinn.ApiClients.Dialogporten; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddDialogportenClient(this IServiceCollection services, DialogportenSettings settings) + { + if (!DialogportenSettings.Validate()) + { + throw new InvalidOperationException("Invalid configuration"); + } + services.TryAddSingleton>(new OptionsWrapper(settings)); + + services.RegisterMaskinportenClientDefinition("dialogporten-sp-sdk", settings.Maskinporten); + + var refitClients = AssemblyMarker.Assembly.GetTypes() + .Where(x => + x.IsInterface && + x.GetCustomAttribute()?.Tool == "Refitter") + .ToList(); + + foreach (var refitClient in refitClients) + { + services + .AddRefitClient(refitClient) + .ConfigureHttpClient(c => c.BaseAddress = new Uri(settings.BaseUri)) + .AddMaskinportenHttpMessageHandler("dialogporten-sp-sdk"); + } + + services + .AddRefitClient() + .ConfigureHttpClient(c => c.BaseAddress = new Uri(settings.BaseUri)); + + services.AddHostedService(); + services.TryAddTransient(); + services.TryAddSingleton(); + services.TryAddSingleton(x => x.GetRequiredService()); + services.TryAddTransient(); + return services; + } + + public static IServiceCollection AddDialogportenClient(this IServiceCollection services, Action configureOptions) + { + var dialogportenSettings = new DialogportenSettings(); + configureOptions.Invoke(dialogportenSettings); + return services.AddDialogportenClient(dialogportenSettings); + } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Services/DefaultValidationResult.cs b/src/Digdir.Library.Dialogporten.WebApiClient/Services/DefaultValidationResult.cs new file mode 100644 index 000000000..987a17321 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Services/DefaultValidationResult.cs @@ -0,0 +1,17 @@ +namespace Altinn.ApiClients.Dialogporten.Services; + +internal sealed class DefaultValidationResult : IValidationResult +{ + public Dictionary> Errors { get; } = []; + public bool IsValid => Errors.Count == 0; + + internal void AddError(string key, string message) + { + if (!Errors.TryGetValue(key, out var messages)) + { + Errors[key] = messages = []; + } + + messages.Add(message); + } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs b/src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs new file mode 100644 index 000000000..ac75cfa34 --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs @@ -0,0 +1,260 @@ +using System.Buffers; +using System.Buffers.Text; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using System.Text.Json; +using Altinn.ApiClients.Dialogporten.Common; +using NSec.Cryptography; + +namespace Altinn.ApiClients.Dialogporten.Services; + +internal sealed class DialogTokenValidator : IDialogTokenValidator +{ + private readonly IEdDsaSecurityKeysCache _publicKeysCache; + private readonly IClock _clock; + + public DialogTokenValidator(IEdDsaSecurityKeysCache publicKeysCache, IClock clock) + { + _publicKeysCache = publicKeysCache; + _clock = clock; + } + + public IValidationResult Validate(ReadOnlySpan token) + { + const string tokenPropertyName = "token"; + var validationResult = new DefaultValidationResult(); + Span tokenDecodeBuffer = stackalloc byte[Base64Url.GetMaxDecodedLength(token.Length)]; + + if (!TryDecodeToken(token, tokenDecodeBuffer, out var tokenParts, out var decodedTokenParts)) + { + validationResult.AddError(tokenPropertyName, "Invalid token format"); + return validationResult; + } + + if (!VerifySignature(tokenParts, decodedTokenParts)) + { + validationResult.AddError(tokenPropertyName, "Invalid signature"); + } + + if (!VerifyExpiration(decodedTokenParts)) + { + validationResult.AddError(tokenPropertyName, "Token has expired"); + } + + return validationResult; + } + + private static bool TryDecodeToken( + ReadOnlySpan token, + Span tokenDecodeBuffer, + out JwksTokenParts tokenParts, + out JwksTokenParts decodedTokenParts) + { + decodedTokenParts = default; + if (!TryGetTokenParts(token, out tokenParts) || + !TryDecodeParts(tokenDecodeBuffer, tokenParts, out decodedTokenParts)) + { + return false; + } + + // Validate that the header and body are valid JSON + return IsValidJson(decodedTokenParts.Header) && + IsValidJson(decodedTokenParts.Body); + } + + private static bool IsValidJson(ReadOnlySpan span) + { + var reader = new Utf8JsonReader(span); + try + { + while (reader.Read()) { } + + return true; + } + catch (JsonException) { } + return false; + } + + private static bool TryGetTokenParts(ReadOnlySpan token, out JwksTokenParts tokenParts) + { + tokenParts = default; + var enumerator = token.Split('.'); + // Header + if (!enumerator.MoveNext()) return false; + var header = token[enumerator.Current]; + + // Body + if (!enumerator.MoveNext()) return false; + var body = token[enumerator.Current]; + + // Signature + if (!enumerator.MoveNext()) return false; + var signature = token[enumerator.Current]; + + tokenParts = new JwksTokenParts(token, header, body, signature); + return !enumerator.MoveNext(); + } + + private static bool TryDecodeParts( + Span buffer, + JwksTokenParts parts, + out JwksTokenParts decodedParts) + { + decodedParts = default; + var bufferPointer = 0; + if (!TryDecodePart(parts.Header, buffer, out var header, out var headerLength)) + { + return false; + } + + bufferPointer += headerLength; + buffer[bufferPointer++] = (byte)'.'; + if (!TryDecodePart(parts.Body, buffer[bufferPointer..], out var body, out var bodyLength)) + { + return false; + } + + bufferPointer += bodyLength; + buffer[bufferPointer++] = (byte)'.'; + if (!TryDecodePart(parts.Signature, buffer[bufferPointer..], out var signature, out _)) + { + return false; + } + + decodedParts = new JwksTokenParts(buffer, header, body, signature); + return true; + } + + private bool VerifySignature( + JwksTokenParts tokenParts, + JwksTokenParts decodedTokenParts) + { + var publicKeys = _publicKeysCache.PublicKeys; + if (publicKeys.Count == 0) + { + throw new InvalidOperationException( + "No public keys available. Most likely due to an error when fetching the " + + "public keys from the dialogporten well-known endpoint. Please check the " + + "logs for more information. Alternatively, set " + + "DialogportenSettings.ThrowOnPublicKeyFetchInit=true to ensure public " + + "keys are fetched before starting up the application."); + } + + var rawSignedPartLength = tokenParts.Header.Length + tokenParts.Body.Length + 1; + Span signedPartBuffer = stackalloc byte[Encoding.UTF8.GetMaxByteCount(rawSignedPartLength)]; + if (!Encoding.UTF8.TryGetBytes(tokenParts.Buffer[..rawSignedPartLength], signedPartBuffer, out var signedPartLength)) + { + return false; + } + + var signedPart = signedPartBuffer[..signedPartLength]; + + return TryGetPublicKey(publicKeys, decodedTokenParts.Header, out var publicKey) + && SignatureAlgorithm.Ed25519.Verify(publicKey, signedPart, decodedTokenParts.Signature); + } + + private bool VerifyExpiration(JwksTokenParts decodedTokenParts) + { + const string expiresPropertyName = "exp"; + if (!TryGetPropertyValue(decodedTokenParts.Body, expiresPropertyName, out var expiresSpan)) + { + return false; + } + + if (!Utf8Parser.TryParse(expiresSpan, out long expiresUnixTimeSeconds, out var bytesConsumed)) + { + return false; + } + + if (bytesConsumed != expiresSpan.Length) + { + return false; + } + + var expires = DateTimeOffset.FromUnixTimeSeconds(expiresUnixTimeSeconds); + return expires >= _clock.UtcNow; + } + + private static bool TryDecodePart(ReadOnlySpan tokenPart, Span buffer, out ReadOnlySpan span, out int length) + { + span = default; + if (!TryDecodeFromChars(tokenPart, buffer, out length)) + { + return false; + } + + span = buffer[..length]; + return true; + } + + private static bool TryDecodeFromChars(ReadOnlySpan source, Span destination, out int bytesWritten) + { + var result = Base64Url.DecodeFromChars(source, destination, out _, out bytesWritten); + return result is OperationStatus.Done; + } + + private static bool TryGetPublicKey(ReadOnlyCollection keyPairs, ReadOnlySpan header, [NotNullWhen(true)] out PublicKey? publicKey) + { + const string kidPropertyName = "kid"; + publicKey = null; + if (!TryGetPropertyValue(header, kidPropertyName, out var tokenKid)) + { + return false; + } + + Span kidCharBuffer = stackalloc char[Encoding.UTF8.GetMaxCharCount(tokenKid.Length)]; + if (!Encoding.UTF8.TryGetChars(tokenKid, kidCharBuffer, out var charsWritten)) + { + return false; + } + + foreach (var (kid, key) in keyPairs) + { + if (!kid.AsSpan().SequenceEqual(kidCharBuffer[..charsWritten])) continue; + publicKey = key; + return true; + } + + return false; + } + + private static bool TryGetPropertyValue(ReadOnlySpan json, ReadOnlySpan name, out ReadOnlySpan value) + { + value = default; + var reader = new Utf8JsonReader(json); + while (reader.Read()) + { + if (!IsPropertyName(reader, name)) continue; + reader.Read(); + value = reader.ValueSpan; + return true; + } + return false; + } + + private static bool IsPropertyName(Utf8JsonReader reader, ReadOnlySpan name) + { + return reader.TokenType == JsonTokenType.PropertyName && reader.ValueTextEquals(name); + } + + private readonly ref struct JwksTokenParts + where T : unmanaged + { + public ReadOnlySpan Buffer { get; } + + public ReadOnlySpan Header { get; } + + public ReadOnlySpan Body { get; } + + public ReadOnlySpan Signature { get; } + + public JwksTokenParts(ReadOnlySpan buffer, ReadOnlySpan header, ReadOnlySpan body, ReadOnlySpan signature) + { + Buffer = buffer; + Header = header; + Body = body; + Signature = signature; + } + } +} diff --git a/src/Digdir.Library.Dialogporten.WebApiClient/Services/EdDsaSecurityKeysCacheService.cs b/src/Digdir.Library.Dialogporten.WebApiClient/Services/EdDsaSecurityKeysCacheService.cs new file mode 100644 index 000000000..22b4b6c2c --- /dev/null +++ b/src/Digdir.Library.Dialogporten.WebApiClient/Services/EdDsaSecurityKeysCacheService.cs @@ -0,0 +1,120 @@ +using System.Buffers.Text; +using System.Collections.ObjectModel; +using Altinn.ApiClients.Dialogporten.Common; +using Altinn.ApiClients.Dialogporten.Common.Exceptions; +using Altinn.ApiClients.Dialogporten.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using NSec.Cryptography; + +namespace Altinn.ApiClients.Dialogporten.Services; + +internal interface IEdDsaSecurityKeysCache +{ + ReadOnlyCollection PublicKeys { get; } +} + +internal sealed class DefaultEdDsaSecurityKeysCache : IEdDsaSecurityKeysCache +{ + private List _publicKeys = []; + public ReadOnlyCollection PublicKeys => _publicKeys.AsReadOnly(); + internal void SetPublicKeys(List publicKeys) => _publicKeys = publicKeys; +} + +internal sealed class EdDsaSecurityKeysCacheService : BackgroundService +{ + private static readonly TimeSpan InitInterval = TimeSpan.FromSeconds(10); + private static readonly TimeSpan ErrorInterval = TimeSpan.FromMinutes(10); + private static readonly TimeSpan RefreshInterval = TimeSpan.FromHours(12); + + private readonly PeriodicTimer _timer = new(InitInterval); + private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly ILogger _logger; + private readonly DialogportenSettings _settings; + private readonly DefaultEdDsaSecurityKeysCache _cache; + private const string EdDsaAlg = "EdDSA"; + + public EdDsaSecurityKeysCacheService( + IServiceScopeFactory serviceScopeFactory, + ILogger logger, + IOptions settings, + DefaultEdDsaSecurityKeysCache cache) + { + _serviceScopeFactory = serviceScopeFactory; + _logger = logger; + _cache = cache; + _settings = settings.Value; + } + + public override async Task StartAsync(CancellationToken cancellationToken) + { + if (!_settings.ThrowOnPublicKeyFetchInit) + { + await base.StartAsync(cancellationToken); + return; + } + + if (!await TryRefreshAsync(cancellationToken)) + { + throw new IncompleteDialogportenClientInitializationException("Failed to fetch public keys."); + } + + _timer.Period = RefreshInterval; + await base.StartAsync(cancellationToken); + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + while (await _timer.WaitForNextTickAsync(cancellationToken)) + { + _timer.Period = await TryRefreshAsync(cancellationToken) + ? RefreshInterval + : ErrorInterval; + } + } + + private async Task TryRefreshAsync(CancellationToken cancellationToken) + { + try + { + await RefreshAsync(cancellationToken); + } + catch (Exception e) + { + _logger.LogError(e, "An error occurred while refreshing the EdDsa keys."); + return false; + } + + return true; + } + + + private async Task RefreshAsync(CancellationToken cancellationToken) + { + using var scope = _serviceScopeFactory.CreateScope(); + var dialogportenApi = scope.ServiceProvider.GetRequiredService(); + var jwks = await dialogportenApi.GetJwks(cancellationToken); + + var keys = jwks.Keys + .Where(x => StringComparer.OrdinalIgnoreCase.Equals(x.Alg, EdDsaAlg)) + .Select(k => new PublicKeyPair( + k.Kid, + PublicKey.Import( + SignatureAlgorithm.Ed25519, + Base64Url.DecodeFromChars(k.X), + KeyBlobFormat.RawPublicKey))) + .ToList(); + + _cache.SetPublicKeys(keys); + } + + public override void Dispose() + { + _timer.Dispose(); + base.Dispose(); + } +} + +internal sealed record PublicKeyPair(string Kid, PublicKey Key); diff --git a/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests.csproj b/tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests.csproj similarity index 100% rename from tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests.csproj rename to tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests.csproj diff --git a/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Features/V1/SwaggerSnapshotTests.cs b/tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Features/V1/SwaggerSnapshotTests.cs similarity index 72% rename from tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Features/V1/SwaggerSnapshotTests.cs rename to tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Features/V1/SwaggerSnapshotTests.cs index 32b0f33e5..4f1e096e0 100644 --- a/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Features/V1/SwaggerSnapshotTests.cs +++ b/tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Features/V1/SwaggerSnapshotTests.cs @@ -1,22 +1,19 @@ +#if DEBUG +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously. +#endif // DEBUG + using System.Diagnostics.CodeAnalysis; using System.Text.Json; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; -namespace Digdir.Domain.Dialogporten.WebApi.Integration.Tests.Features.V1; +namespace Digdir.Domain.Dialogporten.WebApi.Unit.Tests.Features.V1; -public class SwaggerSnapshotTests : IClassFixture> +public class SwaggerSnapshotTests { - private readonly WebApplicationFactory _webApplicationFactory; - - public SwaggerSnapshotTests(WebApplicationFactory webApplicationFactory) - { - _webApplicationFactory = webApplicationFactory; - } [Fact] public async Task FailIfSwaggerSnapshotDoesNotMatch() { +#if RELEASE // Arrange // This test checks for changes against the published version of the swagger.verified.json file // The file is located at /docs/schema/ on the solution root @@ -25,29 +22,37 @@ public async Task FailIfSwaggerSnapshotDoesNotMatch() var rootPath = Utils.GetSolutionRootFolder(); var swaggerPath = Path.Combine(rootPath!, "docs/schema/V1"); - var client = _webApplicationFactory - .WithWebHostBuilder(builder => builder.UseEnvironment("test")) - .CreateClient(); +#if NET9_0 + var newSwaggerPath = Path.Combine(rootPath!, "src/Digdir.Domain.Dialogporten.WebApi/bin/Release/net9.0/swagger.json"); +#endif // NET9_0 + Assert.True(File.Exists(newSwaggerPath), $"Swagger file not found at {newSwaggerPath}. Make sure you have built the project in RELEASE mode."); // Act - var response = await client.GetAsync("/swagger/v1/swagger.json"); - var newSwagger = await response.Content.ReadAsStringAsync(); + var newSwagger = await File.ReadAllTextAsync(newSwaggerPath); + // The order of the properties in the swagger.json file is not cross-platform deterministic. - // Running client.GetAsync("/swagger/v1/swagger.json"); on Windows and Mac will produce + // Running Nswag on Windows and Mac will produce // different ordering of the results (although the content is the same). So we force an // alphabetical ordering of the properties to make the test deterministic. // Ref: https://github.com/altinn/dialogporten/issues/996 var orderedSwagger = SortJson(newSwagger); // Assert - response.EnsureSuccessStatusCode(); await Verify(orderedSwagger, extension: "json") .UseFileName("swagger") .UseDirectory(swaggerPath); +#else // RELEASE + Assert.Fail( + "Swagger snapshot tests are not supported in DEBUG mode. Swagger is NOT generated in DEBUG mode, this is to keep build times low. Therefore, this test will always fail. Run in RELEASE mode to enable."); + +#endif // RELEASE } - private static readonly JsonSerializerOptions SerializerOptions = new() { WriteIndented = true }; + private static readonly JsonSerializerOptions SerializerOptions = new() + { + WriteIndented = true + }; private static string SortJson(string jsonString) { diff --git a/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Utils.cs b/tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Utils.cs similarity index 87% rename from tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Utils.cs rename to tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Utils.cs index 3f44e2cbe..7d5ce1614 100644 --- a/tests/Digdir.Domain.Dialogporten.WebApi.Integration.Tests/Utils.cs +++ b/tests/Digdir.Domain.Dialogporten.WebApi.Unit.Tests/Utils.cs @@ -1,4 +1,4 @@ -namespace Digdir.Domain.Dialogporten.WebApi.Integration.Tests; +namespace Digdir.Domain.Dialogporten.WebApi.Unit.Tests; public static class Utils { diff --git a/tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/DialogTokenValidatorTests.cs b/tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/DialogTokenValidatorTests.cs new file mode 100644 index 000000000..4b2b760ff --- /dev/null +++ b/tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/DialogTokenValidatorTests.cs @@ -0,0 +1,261 @@ +using System.Buffers.Text; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Text; +using System.Text.Json; +using Altinn.ApiClients.Dialogporten.Common; +using Altinn.ApiClients.Dialogporten.Services; +using NSec.Cryptography; +using NSubstitute; + +namespace Digdir.Library.Dialogporten.WebApiClient.Unit.Tests; + +public class DialogTokenValidatorTests +{ + private const string ValidTimeStampString = "2025-02-14T09:00:00Z"; + private const string DialogToken = + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRwLXN0YWdpbmctMjQwMzIyLW81eW1uIn0.eyJqdGkiOiIzOGNmZGNiOS0zODhiLTQ3YjgtYTFiZi05ZjE1YjI4MTk4OTQiLCJjIjoidXJuOmFsdGlubjpwZXJzb246aWRlbnRpZmllci1ubzoxNDg4NjQ5ODIyNiIsImwiOjMsInAiOiJ1cm46YWx0aW5uOnBlcnNvbjppZGVudGlmaWVyLW5vOjE0ODg2NDk4MjI2IiwicyI6InVybjphbHRpbm46cmVzb3VyY2U6ZGFnbC1jb3JyZXNwb25kZW5jZSIsImkiOiIwMTk0ZmU4Mi05MjgwLTc3YTUtYTdjZC01ZmYwZTZhNmZhMDciLCJhIjoicmVhZCIsImlzcyI6Imh0dHBzOi8vcGxhdGZvcm0udHQwMi5hbHRpbm4ubm8vZGlhbG9ncG9ydGVuL2FwaS92MSIsImlhdCI6MTczOTUyMzM2NywibmJmIjoxNzM5NTIzMzY3LCJleHAiOjE3Mzk1MjM5Njd9.O_f-RJhRPT7B76S7aOGw6jfxKDki3uJQLLC8nVlcNVJWFIOQUsy6gU4bG1ZdqoMBZPvb2K2X4I5fGpHW9dQMAA"; + private static readonly PublicKeyPair[] ValidPublicKeyPairs = + [ + new("dp-staging-240322-o5ymn", ToPublicKey("zs9hR9oqgf53th2lTdrBq3C1TZ9UlR-HVJOiUpWV63o")), + new("dp-staging-240322-rju3g", ToPublicKey("23Sijekv5ATW4sSEiRPzL_rXH-zRV8MK8jcs5ExCmSU")) + ]; + + [Fact] + public void ShouldReturnIsValid_GivenValidToken() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + // Act + var result = sut.Validate(DialogToken); + + // Assert + Assert.True(result.IsValid); + } + + [Fact] + public void ShouldThrowException_GivenNoPublicKeys() + { + + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture)); + + // Assert + Assert.Throws(() => sut.Validate(DialogToken)); + } + + [Fact] + public void ShouldReturnError_GivenMalformedToken() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + // Act + var result = sut.Validate("This.TokenIsMalformed...."); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid token format", result.Errors["token"]); + } + + [Fact] + public void ShouldReturnError_GivenInvalidToken() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + // Act + var result = sut.Validate("This.TokenIs.Invalid"); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid token format", result.Errors["token"]); + } + [Fact] + public void ShouldReturnError_GivenNoPublicKeyWithCorrectKeyId() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + var token = UpdateTokenHeader(DialogToken, "kid", "dp-testing-fake-kid"); + // Act + var result = sut.Validate(token); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid signature", result.Errors["token"]); + } + + [Fact] + public void ShouldReturnError_GivenExpiredToken() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse("2025-02-17T09:00:00Z", CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + // Act + var result = sut.Validate(DialogToken); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Token has expired", result.Errors["token"]); + } + + [Fact] + public void ShouldReturnError_GivenEmptyToken() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + // Act + var result = sut.Validate(""); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid token format", result.Errors["token"]); + } + + [Fact] + public void ShouldReturnError_GivenTokenWithWrongSignature() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + var token = UpdateTokenPayload(DialogToken, "l", "4"); + + // Act + var result = sut.Validate(token); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid signature", result.Errors["token"]); + } + + [Fact] + public void ShouldReturnError_GivenTokenWithWrongAlg() + { + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + var token = UpdateTokenHeader(DialogToken, "alg", "RS512"); + + // Act + var result = sut.Validate(token); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid signature", result.Errors["token"]); + } + + [Fact] + public void ShouldReturnError_GivenMalformedJsonHeader() + { + var invalidHeader = """ + { + "alg": "EdDSA", + "typ": "JWT", + "kid": "dp-staging-240322-o5ymn" + """u8; + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + var tokenParts = DialogToken.Split('.'); + tokenParts[0] = Base64Url.EncodeToString(invalidHeader); + var token = string.Join(".", tokenParts); + + // Act + var result = sut.Validate(token); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid token format", result.Errors["token"]); + } + + [Fact] + public void ShouldReturnError_GivenMalformedJsonBody() + { + var invalidBody = """ + { + "jti": "38cfdcb9-388b-47b8-a1bf-9f15b2819894", + "c": "urn:altinn:person:identifier-no:14886498226", + """u8; + // Arrange + var sut = GetSut( + DateTimeOffset.Parse(ValidTimeStampString, CultureInfo.InvariantCulture), + ValidPublicKeyPairs); + + var tokenParts = DialogToken.Split('.'); + tokenParts[1] = Base64Url.EncodeToString(invalidBody); + var token = string.Join(".", tokenParts); + + // Act + var result = sut.Validate(token); + + // Assert + Assert.False(result.IsValid); + Assert.True(result.Errors.ContainsKey("token")); + Assert.Contains("Invalid token format", result.Errors["token"]); + } + + private static DialogTokenValidator GetSut(DateTimeOffset simulatedNow, params PublicKeyPair[] publicKeyPairs) + { + var keyCache = Substitute.For(); + var clock = Substitute.For(); + keyCache.PublicKeys.Returns(new ReadOnlyCollection(publicKeyPairs)); + clock.UtcNow.Returns(simulatedNow); + return new DialogTokenValidator(keyCache, clock); + } + + private static PublicKey ToPublicKey(string key) + => PublicKey.Import(SignatureAlgorithm.Ed25519, Base64Url.DecodeFromChars(key), KeyBlobFormat.RawPublicKey); + + private static string UpdateTokenParts(string part, string property, string value) + { + var decodedPart = Base64Url.DecodeFromChars(part); + var json = JsonSerializer.Deserialize>(decodedPart)!; + json[property] = value; + var encodedPart = Base64Url.EncodeToUtf8(JsonSerializer.SerializeToUtf8Bytes(json)); + return Encoding.UTF8.GetString(encodedPart); + } + + private static string UpdateTokenPayload(string token, string property, string value) + { + var tokenParts = token.Split('.'); + tokenParts[1] = UpdateTokenParts(tokenParts[1], property, value); + return string.Join(".", tokenParts); + } + + private static string UpdateTokenHeader(string token, string property, string value) + { + var tokenParts = token.Split('.'); + tokenParts[0] = UpdateTokenParts(tokenParts[0], property, value); + return string.Join(".", tokenParts); + } +} diff --git a/tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests.csproj b/tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests.csproj new file mode 100644 index 000000000..c26e687a5 --- /dev/null +++ b/tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests.csproj @@ -0,0 +1,26 @@ + + + + net9.0 + + false + true + + + + + + + + + + + + + + + + + + +