From b3a9129ab3835906d15daf737036338a098ca92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Fri, 5 Apr 2024 17:23:59 +0200 Subject: [PATCH 1/3] chore: Refactor MappingUtils (#599) * Removed salt input, weird behavior to take input that the tool itself has generated * Changed old name, it used to be related to mapping * Put it in the DI container --- .../ApplicationExtensions.cs | 1 + .../Common/ICompactJwsGenerator.cs | 1 - .../Common/MappingUtils.cs | 28 +++++++++++++------ .../Queries/Get/GetDialogActivityQuery.cs | 1 - .../Search/SearchDialogActivityQuery.cs | 1 - .../Dialogs/Queries/Get/GetDialogQuery.cs | 9 +++--- .../Queries/Search/SearchDialogQuery.cs | 11 ++++---- .../Dialogs/Entities/DialogEntity.cs | 1 - .../InfrastructureExtensions.cs | 6 ---- .../Get/GetDialogActivityEndpoint.cs | 1 - .../Search/SearchDialogActivityEndpoint.cs | 1 - .../Get/GetDialogElementEndpoint.cs | 1 - .../Search/SearchDialogElementEndpoint.cs | 1 - .../Update/UpdateDialogElementEndpoint.cs | 1 - .../Dialogs/Purge/PurgeDialogEndpoint.cs | 1 - 15 files changed, 31 insertions(+), 34 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs index d37f9ca13..8b248668d 100644 --- a/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs @@ -39,6 +39,7 @@ public static IServiceCollection AddApplication(this IServiceCollection services .AddScoped() // Transient + .AddTransient() .AddTransient() .AddTransient() .AddTransient() diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/ICompactJwsGenerator.cs b/src/Digdir.Domain.Dialogporten.Application/Common/ICompactJwsGenerator.cs index 8d988cffe..a4f002bfc 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/ICompactJwsGenerator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/ICompactJwsGenerator.cs @@ -1,7 +1,6 @@ using System.Buffers.Text; using System.Text; using System.Text.Json; -using System.Text.Json.Serialization; using Microsoft.Extensions.Options; using NSec.Cryptography; diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/MappingUtils.cs b/src/Digdir.Domain.Dialogporten.Application/Common/MappingUtils.cs index 2e53a9b4d..4a3ca8f22 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/MappingUtils.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/MappingUtils.cs @@ -1,24 +1,34 @@ +using System.Diagnostics.CodeAnalysis; using System.Security.Cryptography; using System.Text; namespace Digdir.Domain.Dialogporten.Application.Common; -internal static class MappingUtils +internal interface IStringHasher { - internal static byte[] GetHashSalt(int size = 16) => RandomNumberGenerator.GetBytes(size); + [return: NotNullIfNotNull(nameof(personIdentifier))] + string? Hash(string? personIdentifier); +} + +internal class RandomSaltStringHasher : IStringHasher +{ + private const int SaltSize = 16; + private readonly Lazy _lazySalt = new(() => RandomNumberGenerator.GetBytes(SaltSize)); - internal static string HashPid(string personIdentifier, byte[] salt) + public string? Hash(string? personIdentifier) { + if (string.IsNullOrWhiteSpace(personIdentifier)) + { + return null; + } + var identifierBytes = Encoding.UTF8.GetBytes(personIdentifier); - Span buffer = stackalloc byte[identifierBytes.Length + salt.Length]; + Span buffer = stackalloc byte[identifierBytes.Length + _lazySalt.Value.Length]; identifierBytes.CopyTo(buffer); - salt.CopyTo(buffer[identifierBytes.Length..]); + _lazySalt.Value.CopyTo(buffer[identifierBytes.Length..]); var hashBytes = SHA256.HashData(buffer); - return BitConverter - .ToString(hashBytes, 0, 5) - .Replace("-", "") - .ToLowerInvariant(); + return BitConverter.ToString(hashBytes, 0, 5).Replace("-", "").ToLowerInvariant(); } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Get/GetDialogActivityQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Get/GetDialogActivityQuery.cs index bd6545728..1c71c9c2f 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Get/GetDialogActivityQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Get/GetDialogActivityQuery.cs @@ -1,5 +1,4 @@ using AutoMapper; -using Digdir.Domain.Dialogporten.Application.Common; using Digdir.Domain.Dialogporten.Application.Common.ReturnTypes; using Digdir.Domain.Dialogporten.Application.Externals; using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Search/SearchDialogActivityQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Search/SearchDialogActivityQuery.cs index a46226480..6c5765204 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Search/SearchDialogActivityQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/DialogActivities/Queries/Search/SearchDialogActivityQuery.cs @@ -1,5 +1,4 @@ using AutoMapper; -using Digdir.Domain.Dialogporten.Application.Common; using Digdir.Domain.Dialogporten.Application.Common.ReturnTypes; using Digdir.Domain.Dialogporten.Application.Externals; using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs index 906019d20..23a6f99b8 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs @@ -8,7 +8,6 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; using OneOf; namespace Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Get; @@ -30,6 +29,7 @@ internal sealed class GetDialogQueryHandler : IRequestHandler Handle(GetDialogQuery request, CancellationToken cancellationToken) @@ -115,13 +117,12 @@ public async Task Handle(GetDialogQuery request, CancellationTo var dialogDto = _mapper.Map(dialog); - var salt = MappingUtils.GetHashSalt(); dialogDto.SeenLog = dialog.SeenLog .Select(log => { var logDto = _mapper.Map(log); logDto.IsAuthenticatedUser = log.EndUserId == userPid; - logDto.EndUserIdHash = MappingUtils.HashPid(log.EndUserId, salt); + logDto.EndUserIdHash = _stringHasher.Hash(log.EndUserId); return logDto; }) .ToList(); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs index a77d9b12a..2bcdf6c75 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs @@ -10,7 +10,6 @@ using Digdir.Domain.Dialogporten.Application.Externals; using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; -using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Localizations; using MediatR; using Microsoft.EntityFrameworkCore; @@ -117,19 +116,22 @@ internal sealed class SearchDialogQueryHandler : IRequestHandler Handle(SearchDialogQuery request, CancellationToken cancellationToken) @@ -175,14 +177,13 @@ public async Task Handle(SearchDialogQuery request, Cancella .ProjectTo(_mapper.ConfigurationProvider) .ToPaginatedListAsync(request, cancellationToken: cancellationToken); - var salt = MappingUtils.GetHashSalt(); foreach (var seenLog in paginatedList.Items.SelectMany(x => x.SeenLog)) { // Before we hash the end user id, check if the seen log entry is for the current user seenLog.IsAuthenticatedUser = userPid == seenLog.EndUserIdHash; - // TODO: Add test to not expose unhashed end user id to the client + // TODO: Add test to not expose un-hashed end user id to the client // https://github.com/digdir/dialogporten/issues/596 - seenLog.EndUserIdHash = MappingUtils.HashPid(seenLog.EndUserIdHash, salt); + seenLog.EndUserIdHash = _stringHasher.Hash(seenLog.EndUserIdHash); } return paginatedList; diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs index d0bdd2149..e883422a8 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs @@ -3,7 +3,6 @@ using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Elements; using Digdir.Domain.Dialogporten.Domain.Dialogs.Events; -using Digdir.Domain.Dialogporten.Domain.Localizations; using Digdir.Library.Entity.Abstractions; using Digdir.Library.Entity.Abstractions.Features.Aggregate; using Digdir.Library.Entity.Abstractions.Features.EventPublisher; diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 32f1a7791..bf9aab711 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -25,13 +25,7 @@ using Digdir.Domain.Dialogporten.Infrastructure.Altinn.Events; using Digdir.Domain.Dialogporten.Infrastructure.Altinn.OrganizationRegistry; using Digdir.Domain.Dialogporten.Infrastructure.Altinn.ResourceRegistry; -using System.Text.Json; -using Microsoft.Extensions.Caching.StackExchangeRedis; -using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Caching.Memory; using ZiggyCreatures.Caching.Fusion; -using ZiggyCreatures.Caching.Fusion.Backplane.StackExchangeRedis; using Digdir.Domain.Dialogporten.Infrastructure.Altinn.NameRegistry; namespace Digdir.Domain.Dialogporten.Infrastructure; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Get/GetDialogActivityEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Get/GetDialogActivityEndpoint.cs index 9423f7ec1..e5eaebcbe 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Get/GetDialogActivityEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Get/GetDialogActivityEndpoint.cs @@ -1,7 +1,6 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.DialogActivities.Queries.Get; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; -using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Extensions; using FastEndpoints; using MediatR; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Search/SearchDialogActivityEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Search/SearchDialogActivityEndpoint.cs index dd29e6059..d2a2fab61 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Search/SearchDialogActivityEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogActivities/Search/SearchDialogActivityEndpoint.cs @@ -1,7 +1,6 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.DialogActivities.Queries.Search; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; -using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Extensions; using FastEndpoints; using MediatR; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Get/GetDialogElementEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Get/GetDialogElementEndpoint.cs index d07088722..05517ea3a 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Get/GetDialogElementEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Get/GetDialogElementEndpoint.cs @@ -1,7 +1,6 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.DialogElements.Queries.Get; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; -using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Extensions; using FastEndpoints; using MediatR; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Search/SearchDialogElementEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Search/SearchDialogElementEndpoint.cs index a93a23f98..b0b7ae4ff 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Search/SearchDialogElementEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/EndUser/DialogElements/Search/SearchDialogElementEndpoint.cs @@ -1,7 +1,6 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.DialogElements.Queries.Search; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; -using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Extensions; using FastEndpoints; using MediatR; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/Update/UpdateDialogElementEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/Update/UpdateDialogElementEndpoint.cs index 441e97be9..7a738206e 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/Update/UpdateDialogElementEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogElements/Update/UpdateDialogElementEndpoint.cs @@ -6,7 +6,6 @@ using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; -using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Extensions; using FastEndpoints; using MediatR; using IMapper = AutoMapper.IMapper; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Purge/PurgeDialogEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Purge/PurgeDialogEndpoint.cs index b3d5be7c4..6690ec7de 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Purge/PurgeDialogEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Purge/PurgeDialogEndpoint.cs @@ -2,7 +2,6 @@ using Digdir.Domain.Dialogporten.WebApi.Common; using Digdir.Domain.Dialogporten.WebApi.Common.Authorization; using Digdir.Domain.Dialogporten.WebApi.Common.Extensions; -using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.Common.Extensions; using FastEndpoints; using MediatR; From bbe27d740947a550dd05a80b7108a1f93ff7ca2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Mon, 8 Apr 2024 11:14:06 +0200 Subject: [PATCH 2/3] chore: code cleaning (#605) * Naming conventions * Typos * Trailing commas * Collection expressions * Expression bodies --- .../Extensions/ClaimsPrincipalExtensions.cs | 2 +- ...uentValidationDateTimeOffsetExtensions.cs} | 4 ++-- ...> FluentValidationEnumerableExtensions.cs} | 2 +- ...entValidationLocalizationDtoExtensions.cs} | 0 ...entValidationPartyIdentifierExtensions.cs} | 0 ...cs => FluentValidationStringExtensions.cs} | 4 ++-- ...ns.cs => FluentValidationUriExtensions.cs} | 0 .../Common/Extensions/OneOfExtensions.cs | 12 +++++----- .../Common/Extensions/QueryableExtensions.cs | 4 +--- .../Common/Extensions/TypeExtensions.cs | 4 +--- .../Pagination/Extensions/OrderExtensions.cs | 22 +++++++------------ .../Extensions/TryParseExtensions.cs | 16 +++++++------- .../Pagination/OrderOption/IOrderOptions.cs | 4 +--- .../Common/Pagination/PaginationExtensions.cs | 4 ++-- .../Common/ReturnTypes/ConcurrencyError.cs | 2 +- .../Dialogs/Queries/Get/GetDialogQuery.cs | 7 ++++-- .../Create/CreateDialogCommandValidator.cs | 6 ++--- .../Update/UpdateDialogCommandValidator.cs | 6 ++--- .../Dialogs/Queries/Search/SearchDialogDto.cs | 2 +- .../Common/AzureAppConfigurationExtensions.cs | 2 +- .../Program.cs | 4 ++-- .../Dialogs/Entities/DialogEntity.cs | 8 ++----- .../AltinnAuthorizationClient.cs | 6 ++--- .../NameRegistryClient.cs | 12 +++++----- .../OrganizationRegistryClient.cs | 4 ++-- .../ResourceRegistryClient.cs | 4 ++-- .../Common/Serialization/SerializerOptions.cs | 5 ++--- .../InfrastructureExtensions.cs | 6 ++--- .../Persistence/ContextDesignTimeFactory.cs | 1 + .../OutboxMessageConsumerDefinition.cs | 5 +---- .../Program.cs | 4 ++-- .../Common/Authentication/TokenIssuerCache.cs | 17 +++++++++----- ...nApiDocumentGeneratorSettingsExtensions.cs | 2 +- .../AzureAppConfigurationExtensions.cs | 2 +- .../Common/Extensions/EndpointExtensions.cs | 4 +++- .../Common/Extensions/StringExtensions.cs | 4 +--- .../Json/DateTimeNotSupportedConverter.cs | 11 ++++------ .../Endpoints/V1/MetadataGroup.cs | 2 +- .../Update/UpdateDialogSwaggerConfig.cs | 2 +- .../V1/WellKnown/Jwks/Get/GetJwksEndpoint.cs | 2 +- .../Features/Aggregate/AggregateNode.cs | 10 ++++----- .../Features/Lookup/AbstractLookupEntity.cs | 10 ++------- .../Features/Updatable/UpdatableExtensions.cs | 4 +--- .../EntityLibraryEfCoreExtensions.cs | 6 ++--- .../Features/Lookup/LookupEntityExtensions.cs | 4 ++-- .../SoftDeletable/SoftDeletableExtensions.cs | 10 ++------- .../Common/DialogApplication.cs | 2 +- .../V1/Dialogs/Commands/CreateDialogTests.cs | 4 ++-- .../Ed25519GeneratorTests.cs | 2 +- .../DecisionRequestHelperTests.cs | 10 +++------ 50 files changed, 118 insertions(+), 152 deletions(-) rename src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/{FluentValidation_DateTimeOffset_Extensions.cs => FluentValidationDateTimeOffsetExtensions.cs} (95%) rename src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/{FluentValidation_Enumerable_Extensions.cs => FluentValidationEnumerableExtensions.cs} (97%) rename src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/{FluentValidation_LocalizationDto_Extensions.cs => FluentValidationLocalizationDtoExtensions.cs} (100%) rename src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/{FluentValidation_PartyIdentifier_Extensions.cs => FluentValidationPartyIdentifierExtensions.cs} (100%) rename src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/{FluentValidation_String_Extensions.cs => FluentValidationStringExtensions.cs} (73%) rename src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/{FluentValidation_Uri_Extensions.cs => FluentValidationUriExtensions.cs} (100%) diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/ClaimsPrincipalExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/ClaimsPrincipalExtensions.cs index d1872b0b2..0a7746098 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/ClaimsPrincipalExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/ClaimsPrincipalExtensions.cs @@ -86,7 +86,7 @@ public static bool TryGetOrgNumber(this Claim? consumerClaim, [NotNullWhen(true) public static bool TryGetAuthenticationLevel(this ClaimsPrincipal claimsPrincipal, [NotNullWhen(true)] out int? authenticationLevel) { - string[] claimTypes = { "acr", "urn:altinn:authlevel" }; + string[] claimTypes = ["acr", "urn:altinn:authlevel"]; foreach (var claimType in claimTypes) { diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_DateTimeOffset_Extensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationDateTimeOffsetExtensions.cs similarity index 95% rename from src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_DateTimeOffset_Extensions.cs rename to src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationDateTimeOffsetExtensions.cs index 367475be0..91f2f8e2b 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_DateTimeOffset_Extensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationDateTimeOffsetExtensions.cs @@ -2,7 +2,7 @@ namespace Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation; -internal static class FluentValidation_DateTimeOffset_Extensions +internal static class FluentValidationDateTimeOffsetExtensions { public const string InPastMessage = "'{PropertyName}' must be in the past."; public const string InFutureMessage = "'{PropertyName}' must be in the future."; @@ -37,4 +37,4 @@ public static IRuleBuilderOptions IsInPast(this IRuleBuild .LessThanOrEqualTo(DateTimeOffset.UtcNow) .WithMessage(InPastMessage); } -} \ No newline at end of file +} diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_Enumerable_Extensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationEnumerableExtensions.cs similarity index 97% rename from src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_Enumerable_Extensions.cs rename to src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationEnumerableExtensions.cs index 0d41e7e56..5d9205023 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_Enumerable_Extensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationEnumerableExtensions.cs @@ -5,7 +5,7 @@ namespace Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation; -internal static class FluentValidation_Enumerable_Extensions +internal static class FluentValidationEnumerableExtensions { public static IRuleBuilderOptions> UniqueBy( this IRuleBuilder> ruleBuilder, diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_LocalizationDto_Extensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationLocalizationDtoExtensions.cs similarity index 100% rename from src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_LocalizationDto_Extensions.cs rename to src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationLocalizationDtoExtensions.cs diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_PartyIdentifier_Extensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationPartyIdentifierExtensions.cs similarity index 100% rename from src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_PartyIdentifier_Extensions.cs rename to src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationPartyIdentifierExtensions.cs diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_String_Extensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationStringExtensions.cs similarity index 73% rename from src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_String_Extensions.cs rename to src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationStringExtensions.cs index be25899bc..1a4f27e5b 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_String_Extensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationStringExtensions.cs @@ -2,12 +2,12 @@ namespace Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation; -internal static class FluentValidation_String_Extensions +internal static class FluentValidationStringExtensions { public static IRuleBuilderOptions IsValidUri(this IRuleBuilder ruleBuilder) { return ruleBuilder .Must(uri => uri is null || Uri.IsWellFormedUriString(uri, UriKind.RelativeOrAbsolute)) - .WithMessage("'{PropertyName}' is not a well formated URI."); + .WithMessage("'{PropertyName}' is not a well formatted URI."); } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_Uri_Extensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationUriExtensions.cs similarity index 100% rename from src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidation_Uri_Extensions.cs rename to src/Digdir.Domain.Dialogporten.Application/Common/Extensions/FluentValidation/FluentValidationUriExtensions.cs diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/OneOfExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/OneOfExtensions.cs index 3471e0d74..cfc146ca1 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/OneOfExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/OneOfExtensions.cs @@ -6,12 +6,12 @@ namespace Digdir.Domain.Dialogporten.Application.Common.Extensions; internal static class OneOfExtensions { - private static readonly ConcurrentDictionary<(Type, Type), MethodInfo?> _oneOfFactoryByType = new(); + private static readonly ConcurrentDictionary<(Type, Type), MethodInfo?> OneOfFactoryByType = new(); public static bool TryConvertToOneOf(object value, [NotNullWhen(true)] out TOneOf? result) { ArgumentNullException.ThrowIfNull(value); - var oneOfFactory = _oneOfFactoryByType.GetOrAdd( + var oneOfFactory = OneOfFactoryByType.GetOrAdd( key: new(typeof(TOneOf), value.GetType()), valueFactory: GetOneOfFactoryOrNull); result = (TOneOf)oneOfFactory?.Invoke(null, [value])! ?? default; @@ -20,12 +20,12 @@ public static bool TryConvertToOneOf(object value, [NotNullWhen(true)] o private static MethodInfo? GetOneOfFactoryOrNull((Type, Type) arg) { - const string ImplicitOperatorName = "op_Implicit"; - const BindingFlags ImplicitOperatorFlags = BindingFlags.Static | BindingFlags.Public; + const string implicitOperatorName = "op_Implicit"; + const BindingFlags implicitOperatorFlags = BindingFlags.Static | BindingFlags.Public; var (oneOf, type) = arg; var oneOfImplicitOperator = oneOf.GetMethod( - name: ImplicitOperatorName, - bindingAttr: ImplicitOperatorFlags, + name: implicitOperatorName, + bindingAttr: implicitOperatorFlags, types: [type]); return oneOfImplicitOperator; } diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/QueryableExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/QueryableExtensions.cs index 7364abb80..da2006fb5 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/QueryableExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/QueryableExtensions.cs @@ -8,9 +8,7 @@ namespace Digdir.Domain.Dialogporten.Application.Common.Extensions; public static class QueryableExtensions { public static IQueryable WhereIf(this IQueryable source, bool predicate, Expression> queryPredicate) - { - return predicate ? source.Where(queryPredicate) : source; - } + => predicate ? source.Where(queryPredicate) : source; private static readonly Type DialogType = typeof(DialogEntity); private static readonly PropertyInfo DialogIdPropertyInfo = DialogType.GetProperty(nameof(DialogEntity.Id))!; diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/TypeExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/TypeExtensions.cs index ab67eccde..69da536c2 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/TypeExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/TypeExtensions.cs @@ -3,7 +3,5 @@ internal static class TypeExtensions { public static bool IsNullableType(this Type type) - { - return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); - } + => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); } diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/OrderExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/OrderExtensions.cs index 413c816f5..37edf00cf 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/OrderExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/OrderExtensions.cs @@ -9,10 +9,7 @@ namespace Digdir.Domain.Dialogporten.Application.Common.Pagination.Extensions; internal static class OrderExtensions { public static OrderSet DefaultIfNull(this OrderSet? orderSet) - where TOrderDefinition : IOrderDefinition - { - return orderSet ?? OrderSet.Default; - } + where TOrderDefinition : IOrderDefinition => orderSet ?? OrderSet.Default; public static IQueryable ApplyOrder(this IQueryable query, IOrderSet orderSet) { @@ -81,9 +78,9 @@ public static IQueryable ApplyCondition(this IQueryable query, IOrderSe // where a, b, c, ... are the order by expressions and an, bn, cn, ... // are the values from the continuation token. It's a repeating pattern // where the previous properties are equal and the next property is less than - // or greater than the next value, depending on the sort order. + // or greater than the next value, depending on the sort order. // See https://phauer.com/2018/web-api-pagination-timestamp-id-continuation-token/ for more info. - // The algorithm is as follows: + // The algorithm is as follows: // equalParst = [ a = an, b = bn, c = cn, ... ] // ltGtParts = [ a < an, b < bn, c < cn, ... ] // lgGtEqualParst = [ a < an, a = an AND b < bn, a = an AND b = bn AND c < cn, ... ] @@ -139,8 +136,8 @@ when x.orderBody.Type.IsNullableType() } /// - /// The not null "block" is added when the continuation token is null in descending - /// order, meaning we are still in the beginning where the null values are and + /// The not null "block" is added when the continuation token is null in descending + /// order, meaning we are still in the beginning where the null values are and /// have not reached the set where the not null values start. /// private static BinaryExpression IncludeNotNullsBlock(Expression orderBody) @@ -150,8 +147,8 @@ private static BinaryExpression IncludeNotNullsBlock(Expression orderBody) } /// - /// The null "block" is added when a nullable continuation token is not null in - /// ascending order, meaning we have not reached the end of the pagination + /// The null "block" is added when a nullable continuation token is not null in + /// ascending order, meaning we have not reached the end of the pagination /// where the null values are. /// private static BinaryExpression IncludeNullsBlock(Expression orderBody, Expression valueExpression) @@ -171,9 +168,6 @@ public ParameterReplacer(ParameterExpression newParameter) _newParameter = newParameter; } - protected override Expression VisitParameter(ParameterExpression node) - { - return _newParameter; - } + protected override Expression VisitParameter(ParameterExpression node) => _newParameter; } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/TryParseExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/TryParseExtensions.cs index c3f3c4568..a82ed9a3c 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/TryParseExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/Extensions/TryParseExtensions.cs @@ -7,7 +7,7 @@ namespace Digdir.Domain.Dialogporten.Application.Common.Pagination.Extensions; public static class TryParseExtensions { - private static readonly ConcurrentDictionary _tryParseByType = new(); + private static readonly ConcurrentDictionary TryParseByType = new(); public static bool TryParse(Type type, string? value, out object? result) { @@ -27,7 +27,7 @@ public static bool TryParse(Type type, string? value, out object? result) return true; } - var method = _tryParseByType.GetOrAdd(type, t => TryFindTryParseMethod(t, out var m) ? m : null); + var method = TryParseByType.GetOrAdd(type, t => TryFindTryParseMethod(t, out var m) ? m : null); if (method is null) { return false; @@ -53,11 +53,11 @@ private static bool TryFindTryParseMethod(Type type, [NotNullWhen(true)] out Met var method = (MethodInfo)m; if (method.Name != tryParseMethodName) return false; if (method.ReturnParameter.ParameterType != typeof(bool)) return false; - var parms = method.GetParameters(); - if (parms.Length != 2) return false; - if (parms[0].ParameterType != typeof(string)) return false; - if (parms[1].ParameterType != type.MakeByRefType()) return false; - if (!parms[1].IsOut) return false; + var parameters = method.GetParameters(); + if (parameters.Length != 2) return false; + if (parameters[0].ParameterType != typeof(string)) return false; + if (parameters[1].ParameterType != type.MakeByRefType()) return false; + if (!parameters[1].IsOut) return false; return true; @@ -70,4 +70,4 @@ private static bool TryFindTryParseMethod(Type type, [NotNullWhen(true)] out Met return method is not null; } -} \ No newline at end of file +} diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/OrderOption/IOrderOptions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/OrderOption/IOrderOptions.cs index bebbb7a73..57ca1c2bb 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/OrderOption/IOrderOptions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/OrderOption/IOrderOptions.cs @@ -19,7 +19,6 @@ internal static class OrderOptions internal class OrderOptions : IOrderOptions { - private readonly string _defaultKey; private readonly Dictionary> _optionByKey; public Order DefaultOrder { get; } @@ -27,9 +26,8 @@ internal class OrderOptions : IOrderOptions public OrderOptions(string defaultKey, Dictionary> optionByKey) { - _defaultKey = defaultKey; _optionByKey = optionByKey; - DefaultOrder = new(_defaultKey, _optionByKey[_defaultKey]); + DefaultOrder = new(defaultKey, _optionByKey[defaultKey]); IdOrder = new(PaginationConstants.OrderIdKey, _optionByKey[PaginationConstants.OrderIdKey]); } diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/PaginationExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/PaginationExtensions.cs index 1d0e98e76..1515624c1 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/PaginationExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Pagination/PaginationExtensions.cs @@ -41,12 +41,12 @@ private static async Task> CreateAsync( { ArgumentNullException.ThrowIfNull(source); - const int OneMore = 1; + const int oneMore = 1; var items = await source .ApplyOrder(orderSet) .ApplyCondition(orderSet, continuationTokenSet) - .Take(limit + OneMore) + .Take(limit + oneMore) .ToArrayAsync(cancellationToken); // Fetch one more item than requested to determine if there is a next page diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/ReturnTypes/ConcurrencyError.cs b/src/Digdir.Domain.Dialogporten.Application/Common/ReturnTypes/ConcurrencyError.cs index fd3f7c640..86119bf38 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/ReturnTypes/ConcurrencyError.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/ReturnTypes/ConcurrencyError.cs @@ -1,3 +1,3 @@ namespace Digdir.Domain.Dialogporten.Application.Common.ReturnTypes; -public record ConcurrencyError(); \ No newline at end of file +public record ConcurrencyError; diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs index 23a6f99b8..cc1ebeb10 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs @@ -164,8 +164,11 @@ private static void DecorateWithAuthorization(GetDialogDto dto, // Simple "read" on the main resource will give access to a dialog element, unless a authorization attribute is set, // in which case an "elementread" action is required - foreach (var dialogElement in dto.Elements.Where(dialogElement => (dialogElement.AuthorizationAttribute is null && action == Constants.ReadAction) - || (dialogElement.AuthorizationAttribute is not null && action == Constants.ElementReadAction))) + var elements = dto.Elements.Where(dialogElement => + (dialogElement.AuthorizationAttribute is null && action == Constants.ReadAction) || + (dialogElement.AuthorizationAttribute is not null && action == Constants.ElementReadAction)); + + foreach (var dialogElement in elements) { dialogElement.IsAuthorized = true; } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs index 924c57a69..c4676b4f9 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommandValidator.cs @@ -47,15 +47,15 @@ public CreateDialogCommandValidator( RuleFor(x => x.ExpiresAt) .IsInFuture() .GreaterThanOrEqualTo(x => x.DueAt) - .WithMessage(FluentValidation_DateTimeOffset_Extensions.InFutureOfMessage) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) .When(x => x.DueAt.HasValue, ApplyConditionTo.CurrentValidator) .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidation_DateTimeOffset_Extensions.InFutureOfMessage) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.DueAt) .IsInFuture() .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidation_DateTimeOffset_Extensions.InFutureOfMessage) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.VisibleFrom) .IsInFuture(); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs index b5cb6fce7..a9cc68534 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommandValidator.cs @@ -43,14 +43,14 @@ public UpdateDialogDtoValidator( RuleFor(x => x.ExpiresAt) .GreaterThanOrEqualTo(x => x.DueAt) - .WithMessage(FluentValidation_DateTimeOffset_Extensions.InFutureOfMessage) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) .When(x => x.DueAt.HasValue, ApplyConditionTo.CurrentValidator) .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidation_DateTimeOffset_Extensions.InFutureOfMessage) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.DueAt) .GreaterThanOrEqualTo(x => x.VisibleFrom) - .WithMessage(FluentValidation_DateTimeOffset_Extensions.InFutureOfMessage) + .WithMessage(FluentValidationDateTimeOffsetExtensions.InFutureOfMessage) .When(x => x.VisibleFrom.HasValue, ApplyConditionTo.CurrentValidator); RuleFor(x => x.Status) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs index 6b5e2111d..53f3ab060 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs @@ -10,7 +10,7 @@ public sealed class SearchDialogDto public string Org { get; set; } = null!; public string ServiceResource { get; set; } = null!; public string Party { get; set; } = null!; - public string? EndUserId { get; set; } = null!; + public string? EndUserId { get; set; } public int? Progress { get; set; } public string? ExtendedStatus { get; set; } public DateTimeOffset CreatedAt { get; set; } diff --git a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Common/AzureAppConfigurationExtensions.cs b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Common/AzureAppConfigurationExtensions.cs index 1ffadfe9b..d2314c6b8 100644 --- a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Common/AzureAppConfigurationExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Common/AzureAppConfigurationExtensions.cs @@ -6,7 +6,7 @@ namespace Digdir.Domain.Dialogporten.ChangeDataCapture.Common; /// -/// Wrapper around azure app configuration bootstrapping such that azure app +/// Wrapper around azure app configuration bootstrapping such that azure app /// config is activated through the environment variable AZURE_APPCONFIG_URI. /// internal static class AzureAppConfigurationExtensions diff --git a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Program.cs b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Program.cs index 734261833..95576462f 100644 --- a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Program.cs +++ b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Program.cs @@ -45,7 +45,7 @@ static void BuildAndRun(string[] args) .ReadFrom.Services(services) .Enrich.FromLogContext() .WriteTo.Conditional( - condition: x => builder.Environment.IsDevelopment(), + condition: _ => builder.Environment.IsDevelopment(), configureSink: x => x.Console(formatProvider: CultureInfo.InvariantCulture)) .WriteTo.ApplicationInsights( services.GetRequiredService(), @@ -69,7 +69,7 @@ static void BuildAndRun(string[] args) }); }); }) - .AddSingleton(x => new PostgresCdcSSubscriptionOptions + .AddSingleton(_ => new PostgresCdcSSubscriptionOptions ( ConnectionString: builder.Configuration["Infrastructure:DialogDbConnectionString"]!, ReplicationSlotName: builder.Configuration["ReplicationSlotName"]!, diff --git a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs index e883422a8..4888be2ca 100644 --- a/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs +++ b/src/Digdir.Domain.Dialogporten.Domain/Dialogs/Entities/DialogEntity.cs @@ -68,9 +68,7 @@ public void SoftDelete() } public void OnCreate(AggregateNode self, DateTimeOffset utcNow) - { - _domainEvents.Add(new DialogCreatedDomainEvent(Id, ServiceResource, Party)); - } + => _domainEvents.Add(new DialogCreatedDomainEvent(Id, ServiceResource, Party)); public void OnUpdate(AggregateNode self, DateTimeOffset utcNow) { @@ -88,9 +86,7 @@ x.Entity is not DialogSearchTag && } public void OnDelete(AggregateNode self, DateTimeOffset utcNow) - { - _domainEvents.Add(new DialogDeletedDomainEvent(Id, ServiceResource, Party)); - } + => _domainEvents.Add(new DialogDeletedDomainEvent(Id, ServiceResource, Party)); public void UpdateSeenAt(string endUserId, string? endUserName) { diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs index 1c6bd08d6..eeb272953 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs @@ -121,7 +121,7 @@ private List GetOrCreateClaimsBasedOnEndUserId(string? endUserId) return claims; } - private static readonly JsonSerializerOptions _serializerOptions = new() + private static readonly JsonSerializerOptions SerializerOptions = new() { PropertyNameCaseInsensitive = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault @@ -130,7 +130,7 @@ private List GetOrCreateClaimsBasedOnEndUserId(string? endUserId) private async Task SendRequest(XacmlJsonRequestRoot xacmlJsonRequest, CancellationToken cancellationToken) { const string apiUrl = "authorization/api/v1/authorize"; - var requestJson = JsonSerializer.Serialize(xacmlJsonRequest, _serializerOptions); + var requestJson = JsonSerializer.Serialize(xacmlJsonRequest, SerializerOptions); _logger.LogDebug("Generated XACML request: {RequestJson}", requestJson); var httpContent = new StringContent(requestJson, Encoding.UTF8, "application/json"); @@ -147,6 +147,6 @@ private List GetOrCreateClaimsBasedOnEndUserId(string? endUserId) } var responseData = await response.Content.ReadAsStringAsync(cancellationToken); - return JsonSerializer.Deserialize(responseData, _serializerOptions); + return JsonSerializer.Deserialize(responseData, SerializerOptions); } } diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/NameRegistryClient.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/NameRegistryClient.cs index e8e385470..da0579782 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/NameRegistryClient.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/NameRegistryClient.cs @@ -11,14 +11,14 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.Altinn.NameRegistry; internal class NameRegistryClient : INameRegistry { - private static readonly DistributedCacheEntryOptions _oneDayCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) }; - private static readonly DistributedCacheEntryOptions _zeroCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.MinValue }; + private static readonly DistributedCacheEntryOptions OneDayCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) }; + private static readonly DistributedCacheEntryOptions ZeroCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.MinValue }; private readonly IFusionCache _cache; private readonly HttpClient _client; private readonly ILogger _logger; - private static readonly JsonSerializerOptions _serializerOptions = new() + private static readonly JsonSerializerOptions SerializerOptions = new() { PropertyNameCaseInsensitive = true, @@ -36,7 +36,7 @@ public NameRegistryClient(HttpClient client, IFusionCacheProvider cacheProvider, { return await _cache.GetOrSetAsync( $"Name_{personalIdentificationNumber}", - (ct) => GetNameFromRegister(personalIdentificationNumber, ct), + ct => GetNameFromRegister(personalIdentificationNumber, ct), token: cancellationToken); } @@ -51,7 +51,7 @@ public NameRegistryClient(HttpClient client, IFusionCacheProvider cacheProvider, ] }; - var requestJson = JsonSerializer.Serialize(nameLookup, _serializerOptions); + var requestJson = JsonSerializer.Serialize(nameLookup, SerializerOptions); var httpContent = new StringContent(requestJson, Encoding.UTF8, "application/json"); var response = await _client.PostAsync(apiUrl, httpContent, cancellationToken); @@ -67,7 +67,7 @@ public NameRegistryClient(HttpClient client, IFusionCacheProvider cacheProvider, } var responseData = await response.Content.ReadAsStringAsync(cancellationToken); - var nameLookupResult = JsonSerializer.Deserialize(responseData, _serializerOptions); + var nameLookupResult = JsonSerializer.Deserialize(responseData, SerializerOptions); return nameLookupResult?.PartyNames.FirstOrDefault()?.Name; } diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs index 8c5c4e349..131f6a322 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs @@ -9,8 +9,8 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.Altinn.OrganizationRegistry; internal class OrganizationRegistryClient : IOrganizationRegistry { private const string OrgShortNameReferenceCacheKey = "OrgShortNameReference"; - private static readonly DistributedCacheEntryOptions _oneDayCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) }; - private static readonly DistributedCacheEntryOptions _zeroCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.MinValue }; + private static readonly DistributedCacheEntryOptions OneDayCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) }; + private static readonly DistributedCacheEntryOptions ZeroCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.MinValue }; private readonly IFusionCache _cache; private readonly HttpClient _client; diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs index 0e9c81d5c..7d4595eff 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs @@ -10,8 +10,8 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.Altinn.ResourceRegistry; internal sealed class ResourceRegistryClient : IResourceRegistry { private const string OrgResourceReferenceCacheKey = "OrgResourceReference"; - private static readonly DistributedCacheEntryOptions _oneDayCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) }; - private static readonly DistributedCacheEntryOptions _zeroCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.MinValue }; + private static readonly DistributedCacheEntryOptions OneDayCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) }; + private static readonly DistributedCacheEntryOptions ZeroCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.MinValue }; private readonly IFusionCache _cache; private readonly HttpClient _client; diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Common/Serialization/SerializerOptions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Common/Serialization/SerializerOptions.cs index b07ae7b3c..fcf6e1f2d 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Common/Serialization/SerializerOptions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Common/Serialization/SerializerOptions.cs @@ -7,7 +7,7 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.Common.Serialization; internal static class SerializerOptions { - private static readonly Lazy _polymorphismOptions = new(() => + private static readonly Lazy PolymorphismOptions = new(() => { var options = new JsonPolymorphismOptions(); var domainEventType = typeof(IDomainEvent); @@ -45,7 +45,7 @@ private static void DomainEventModifier(JsonTypeInfo typeInfo) return; } - typeInfo.PolymorphismOptions = _polymorphismOptions.Value; + typeInfo.PolymorphismOptions = PolymorphismOptions.Value; } } @@ -54,4 +54,3 @@ internal class LowerCaseNamingPolicy : JsonNamingPolicy public override string ConvertName(string name) => name.ToLowerInvariant(); } - diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index bf9aab711..0fa59ac00 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -74,15 +74,15 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi services.ConfigureFusionCache(nameof(Altinn.NameRegistry), new() { - Duration = TimeSpan.FromDays(1), + Duration = TimeSpan.FromDays(1) }) .ConfigureFusionCache(nameof(Altinn.ResourceRegistry), new() { - Duration = TimeSpan.FromMinutes(20), + Duration = TimeSpan.FromMinutes(20) }) .ConfigureFusionCache(nameof(Altinn.OrganizationRegistry), new() { - Duration = TimeSpan.FromDays(1), + Duration = TimeSpan.FromDays(1) }); services.AddDbContext((services, options) => diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/ContextDesignTimeFactory.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/ContextDesignTimeFactory.cs index 59aa577c1..204c47f7b 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/ContextDesignTimeFactory.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/ContextDesignTimeFactory.cs @@ -14,6 +14,7 @@ public DialogDbContext CreateDbContext(string[] args) var localPostgresConnectionString = new ConfigurationBuilder() .AddUserSecrets(Assembly.GetExecutingAssembly(), true) .Build()[ConnectionStringConfigName]; + return new(new DbContextOptionsBuilder() .UseNpgsql(localPostgresConnectionString) .Options); diff --git a/src/Digdir.Domain.Dialogporten.Service/Consumers/OutboxMessages/OutboxMessageConsumerDefinition.cs b/src/Digdir.Domain.Dialogporten.Service/Consumers/OutboxMessages/OutboxMessageConsumerDefinition.cs index 44f53771d..69925382a 100644 --- a/src/Digdir.Domain.Dialogporten.Service/Consumers/OutboxMessages/OutboxMessageConsumerDefinition.cs +++ b/src/Digdir.Domain.Dialogporten.Service/Consumers/OutboxMessages/OutboxMessageConsumerDefinition.cs @@ -7,8 +7,5 @@ public sealed class OutboxMessageConsumerDefinition : ConsumerDefinition consumerConfigurator, - IRegistrationContext context) - { - endpointConfigurator.ConfigureConsumeTopology = false; - } + IRegistrationContext context) => endpointConfigurator.ConfigureConsumeTopology = false; } diff --git a/src/Digdir.Domain.Dialogporten.Service/Program.cs b/src/Digdir.Domain.Dialogporten.Service/Program.cs index bd96a720b..aab622cba 100644 --- a/src/Digdir.Domain.Dialogporten.Service/Program.cs +++ b/src/Digdir.Domain.Dialogporten.Service/Program.cs @@ -9,7 +9,7 @@ using Digdir.Domain.Dialogporten.Service; // TODO: Add AppConfiguration and key vault -// TODO: Configure RabbitMQ connection settings +// TODO: Configure RabbitMQ connection settings // TODO: Configure Postgres connection settings // TODO: Improve exceptions thrown in this assembly @@ -49,7 +49,7 @@ static void BuildAndRun(string[] args) .ReadFrom.Services(services) .Enrich.FromLogContext() .WriteTo.Conditional( - condition: x => builder.Environment.IsDevelopment(), + condition: _ => builder.Environment.IsDevelopment(), configureSink: x => x.Console(formatProvider: CultureInfo.InvariantCulture)) .WriteTo.ApplicationInsights( services.GetRequiredService(), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Authentication/TokenIssuerCache.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Authentication/TokenIssuerCache.cs index f582ca58d..d6f9b84fd 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Authentication/TokenIssuerCache.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Authentication/TokenIssuerCache.cs @@ -35,9 +35,17 @@ public TokenIssuerCache(IOptions apiSettings) private async Task EnsureInitializedAsync() { - if (_initialized) return; + if (_initialized) + { + return; + } + await _initializationSemaphore.WaitAsync(); - if (_initialized) return; + + if (_initialized) + { + return; + } try { @@ -57,8 +65,5 @@ private async Task EnsureInitializedAsync() } } - public void Dispose() - { - _initializationSemaphore.Dispose(); - } + public void Dispose() => _initializationSemaphore.Dispose(); } diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AspNetCoreOpenApiDocumentGeneratorSettingsExtensions.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AspNetCoreOpenApiDocumentGeneratorSettingsExtensions.cs index ae636709d..22f251eb3 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AspNetCoreOpenApiDocumentGeneratorSettingsExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AspNetCoreOpenApiDocumentGeneratorSettingsExtensions.cs @@ -15,7 +15,7 @@ public static AspNetCoreOpenApiDocumentGeneratorSettings CleanupPaginatedLists( settings.OperationProcessors.Add(new PaginatedListParametersProcessor()); // Attempt to remove the definitions that NSwag generates for this - foreach (var ignoreType in new Type[] + foreach (var ignoreType in new[] { typeof(ContinuationTokenSet<,>), typeof(Order<>), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AzureAppConfigurationExtensions.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AzureAppConfigurationExtensions.cs index 39211d8de..a0c7112e0 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AzureAppConfigurationExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/AzureAppConfigurationExtensions.cs @@ -6,7 +6,7 @@ namespace Digdir.Domain.Dialogporten.WebApi.Common.Extensions; /// -/// Wrapper around azure app configuration bootstrapping such that azure app +/// Wrapper around azure app configuration bootstrapping such that azure app /// config is activated through the environment variable AZURE_APPCONFIG_URI. /// internal static class AzureAppConfigurationExtensions diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs index 281d35ac0..911d21bd6 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/EndpointExtensions.cs @@ -8,8 +8,10 @@ public static class EndpointExtensions { public static Task BadRequestAsync(this IEndpoint ep, ValidationError failure, CancellationToken cancellationToken = default) => ep.BadRequestAsync(failure.Errors, cancellationToken); + public static Task BadRequestAsync(this IEndpoint ep, IEnumerable failures, CancellationToken cancellationToken = default) - => ep.HttpContext.Response.SendErrorsAsync(failures.ToList() ?? [], StatusCodes.Status400BadRequest, cancellation: cancellationToken); + => ep.HttpContext.Response.SendErrorsAsync(failures.ToList(), cancellation: cancellationToken); + public static Task BadRequestAsync(this IEndpoint ep, BadRequest badRequest, CancellationToken cancellationToken = default) => ep.HttpContext.Response.SendErrorsAsync( badRequest.ToValidationResults(), diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/StringExtensions.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/StringExtensions.cs index 0c2ed2974..888723e46 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/StringExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Extensions/StringExtensions.cs @@ -5,7 +5,5 @@ namespace Digdir.Domain.Dialogporten.WebApi.Common.Extensions; internal static class StringExtensions { public static string FormatInvariant(this string pattern, params object[] args) - { - return string.Format(CultureInfo.InvariantCulture, pattern, args); - } + => string.Format(CultureInfo.InvariantCulture, pattern, args); } diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Common/Json/DateTimeNotSupportedConverter.cs b/src/Digdir.Domain.Dialogporten.WebApi/Common/Json/DateTimeNotSupportedConverter.cs index a5e57b8b0..8ff6b1dbd 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Common/Json/DateTimeNotSupportedConverter.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Common/Json/DateTimeNotSupportedConverter.cs @@ -12,11 +12,8 @@ internal sealed class DateTimeNotSupportedConverter : JsonConverter "error as a consumer."; public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - throw new NotSupportedException(ErrorMessage); - } + => throw new NotSupportedException(ErrorMessage); + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) - { - throw new NotSupportedException(ErrorMessage); - } -} \ No newline at end of file + => throw new NotSupportedException(ErrorMessage); +} diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/MetadataGroup.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/MetadataGroup.cs index 5c1882870..e12c50162 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/MetadataGroup.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/MetadataGroup.cs @@ -7,7 +7,7 @@ public sealed class MetadataGroup : Group private const string GroupName = "Metadata"; public MetadataGroup() { - Configure(String.Empty, ep => + Configure(string.Empty, ep => { ep.DontAutoTag(); ep.Description(x => x.WithTags(GroupName)); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogSwaggerConfig.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogSwaggerConfig.cs index 443b5e5ec..b2dc22d22 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogSwaggerConfig.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/Dialogs/Update/UpdateDialogSwaggerConfig.cs @@ -144,7 +144,7 @@ public static RouteHandlerBuilder SetDescription(RouteHandlerBuilder builder) => Url = new Uri("https://example.com/some-api-action"), DocumentationUrl = new Uri("https://example.com/some-api-action-doc"), RequestSchema = new Uri("https://example.com/some-api-action-request-schema"), - ResponseSchema = new Uri("https://example.com/some-api-action-response-schema"), + ResponseSchema = new Uri("https://example.com/some-api-action-response-schema") } ] } diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/WellKnown/Jwks/Get/GetJwksEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/WellKnown/Jwks/Get/GetJwksEndpoint.cs index 86c8ed655..0191583f4 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/WellKnown/Jwks/Get/GetJwksEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/WellKnown/Jwks/Get/GetJwksEndpoint.cs @@ -26,7 +26,7 @@ public override async Task HandleAsync(CancellationToken ct) { var result = await _sender.Send(new GetJwksQuery(), ct); - HttpContext.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() + HttpContext.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = TimeSpan.FromHours(24) diff --git a/src/Digdir.Library.Entity.Abstractions/Features/Aggregate/AggregateNode.cs b/src/Digdir.Library.Entity.Abstractions/Features/Aggregate/AggregateNode.cs index 14f02f63a..300597e6a 100644 --- a/src/Digdir.Library.Entity.Abstractions/Features/Aggregate/AggregateNode.cs +++ b/src/Digdir.Library.Entity.Abstractions/Features/Aggregate/AggregateNode.cs @@ -7,9 +7,9 @@ namespace Digdir.Library.Entity.Abstractions.Features.Aggregate; /// public abstract class AggregateNode { - private static readonly Type _openGenericAggregateNodeType = typeof(AggregateNode<>); - private readonly HashSet _children = new(); - private readonly HashSet _parents = new(); + private static readonly Type OpenGenericAggregateNodeType = typeof(AggregateNode<>); + private readonly HashSet _children = []; + private readonly HashSet _parents = []; private readonly List _modifiedProperties; /// @@ -25,7 +25,7 @@ public abstract class AggregateNode /// /// A collection of modified children. A child node is modified if it itself /// is modified, or one of its children are modified. Modified in this - /// context meens added, modified, or deleted. + /// context means added, modified, or deleted. /// public IReadOnlyCollection Children => _children; @@ -78,7 +78,7 @@ internal static AggregateNode Create(Type type, object entity, AggregateNodeStat } var nodeArguments = new[] { entity, state, modifiedProperties }; - var genericType = _openGenericAggregateNodeType.MakeGenericType(type); + var genericType = OpenGenericAggregateNodeType.MakeGenericType(type); var node = (AggregateNode)Activator.CreateInstance(genericType, BindingFlags.NonPublic | BindingFlags.Instance, null, nodeArguments, null)!; return node; diff --git a/src/Digdir.Library.Entity.Abstractions/Features/Lookup/AbstractLookupEntity.cs b/src/Digdir.Library.Entity.Abstractions/Features/Lookup/AbstractLookupEntity.cs index 90701c066..33ca30877 100644 --- a/src/Digdir.Library.Entity.Abstractions/Features/Lookup/AbstractLookupEntity.cs +++ b/src/Digdir.Library.Entity.Abstractions/Features/Lookup/AbstractLookupEntity.cs @@ -102,10 +102,7 @@ public override bool Equals(object? obj) } /// - public override int GetHashCode() - { - return Id.GetHashCode(); - } + public override int GetHashCode() => Id.GetHashCode(); /// public static explicit operator TEnum(AbstractLookupEntity entity) @@ -119,8 +116,5 @@ public static explicit operator AbstractLookupEntity(TEnum id) return GetUninitializedSelf().MapValue(id); } - private static TSelf GetUninitializedSelf() - { - return (TSelf)RuntimeHelpers.GetUninitializedObject(typeof(TSelf)); - } + private static TSelf GetUninitializedSelf() => (TSelf)RuntimeHelpers.GetUninitializedObject(typeof(TSelf)); } diff --git a/src/Digdir.Library.Entity.Abstractions/Features/Updatable/UpdatableExtensions.cs b/src/Digdir.Library.Entity.Abstractions/Features/Updatable/UpdatableExtensions.cs index abcb04525..349b60f43 100644 --- a/src/Digdir.Library.Entity.Abstractions/Features/Updatable/UpdatableExtensions.cs +++ b/src/Digdir.Library.Entity.Abstractions/Features/Updatable/UpdatableExtensions.cs @@ -11,7 +11,5 @@ public static class UpdatableExtensions /// The to update. /// The update time in UTC. public static void Update(this IUpdateableEntity updateable, DateTimeOffset utcNow) - { - updateable.UpdatedAt = utcNow; - } + => updateable.UpdatedAt = utcNow; } diff --git a/src/Digdir.Library.Entity.EntityFrameworkCore/EntityLibraryEfCoreExtensions.cs b/src/Digdir.Library.Entity.EntityFrameworkCore/EntityLibraryEfCoreExtensions.cs index 687b334b0..afcbf1da2 100644 --- a/src/Digdir.Library.Entity.EntityFrameworkCore/EntityLibraryEfCoreExtensions.cs +++ b/src/Digdir.Library.Entity.EntityFrameworkCore/EntityLibraryEfCoreExtensions.cs @@ -115,10 +115,8 @@ public static PropertyBuilder HasUnlimitedLength(this PropertyBuilder(this ModelBuilder modelBuilder, Action buildAction) where TEntity : class - { - return modelBuilder.EntitiesOfType(typeof(TEntity), buildAction); - } + internal static ModelBuilder EntitiesOfType(this ModelBuilder modelBuilder, Action buildAction) + where TEntity : class => modelBuilder.EntitiesOfType(typeof(TEntity), buildAction); internal static ModelBuilder EntitiesOfType(this ModelBuilder modelBuilder, Type type, Action buildAction) diff --git a/src/Digdir.Library.Entity.EntityFrameworkCore/Features/Lookup/LookupEntityExtensions.cs b/src/Digdir.Library.Entity.EntityFrameworkCore/Features/Lookup/LookupEntityExtensions.cs index 27a1e20dd..a629c3ece 100644 --- a/src/Digdir.Library.Entity.EntityFrameworkCore/Features/Lookup/LookupEntityExtensions.cs +++ b/src/Digdir.Library.Entity.EntityFrameworkCore/Features/Lookup/LookupEntityExtensions.cs @@ -9,7 +9,7 @@ namespace Digdir.Library.Entity.EntityFrameworkCore.Features.Lookup; internal static class LookupEntityExtensions { - private static readonly ConcurrentDictionary _lookupEntityMethodCache = new(); + private static readonly ConcurrentDictionary LookupEntityMethodCache = new(); public static ModelBuilder AddLookupEntities(this ModelBuilder modelBuilder) { @@ -54,7 +54,7 @@ private static IEnumerable GetLookupEntityValues(Type type) private static bool TryGetLookupValueMethodInfo(this Type type, [NotNullWhen(true)] out MethodInfo? methodInfo) { - methodInfo = _lookupEntityMethodCache.GetOrAdd(type, GetLookupEntityMethod); + methodInfo = LookupEntityMethodCache.GetOrAdd(type, GetLookupEntityMethod); return methodInfo is not null; } diff --git a/src/Digdir.Library.Entity.EntityFrameworkCore/Features/SoftDeletable/SoftDeletableExtensions.cs b/src/Digdir.Library.Entity.EntityFrameworkCore/Features/SoftDeletable/SoftDeletableExtensions.cs index 465299af7..26c2c75ce 100644 --- a/src/Digdir.Library.Entity.EntityFrameworkCore/Features/SoftDeletable/SoftDeletableExtensions.cs +++ b/src/Digdir.Library.Entity.EntityFrameworkCore/Features/SoftDeletable/SoftDeletableExtensions.cs @@ -26,10 +26,7 @@ public static class SoftDeletableExtensions /// access to change tracking information and operations for the entity. /// public static EntityEntry HardRemove(this DbSet set, TSoftDeletableEntity entity) - where TSoftDeletableEntity : class, ISoftDeletableEntity - { - return set.Remove(entity); - } + where TSoftDeletableEntity : class, ISoftDeletableEntity => set.Remove(entity); /// /// Marks a as hard deleted. @@ -146,8 +143,5 @@ private static List> AssertNoModifiedSoftDelet } private static void EnableSoftDeletableQueryFilter_Internal(ModelBuilder modelBuilder) - where T : class, ISoftDeletableEntity - { - modelBuilder.Entity().HasQueryFilter(x => !x.Deleted); - } + where T : class, ISoftDeletableEntity => modelBuilder.Entity().HasQueryFilter(x => !x.Deleted); } diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/DialogApplication.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/DialogApplication.cs index d9932bea4..b8e7a7483 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/DialogApplication.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/DialogApplication.cs @@ -106,7 +106,7 @@ private static IOptions CreateApplicationSettingsSubstitute Kid = "kid2", PrivateComponent = "private2", PublicComponent = "public2" - }, + } } } }); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Dialogs/Commands/CreateDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Dialogs/Commands/CreateDialogTests.cs index 109c15fce..34bd91a49 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Dialogs/Commands/CreateDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Dialogs/Commands/CreateDialogTests.cs @@ -20,7 +20,7 @@ public async Task Create_CreatesDialog_WhenDialogIsSimple() var response = await Application.Send(createCommand); // Assert - response.TryPickT0(out var success, out var _).Should().BeTrue(); + response.TryPickT0(out var success, out _).Should().BeTrue(); success.Value.Should().Be(expectedDialogId); } @@ -36,7 +36,7 @@ public async Task Create_CreateDialog_WhenDialogIsComplex() var result = await Application.Send(createDialogCommand); // Assert - result.TryPickT0(out var success, out var _).Should().BeTrue(); + result.TryPickT0(out var success, out _).Should().BeTrue(); success.Value.Should().Be(expectedDialogId); } diff --git a/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Ed25519GeneratorTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Ed25519GeneratorTests.cs index ab6c78bc8..9c2231deb 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Ed25519GeneratorTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Ed25519GeneratorTests.cs @@ -27,7 +27,7 @@ public void ValidJwsIsGenerated() Kid = "unittestkeypair2", PrivateComponent = "", PublicComponent = "" - }, + } } } }; diff --git a/tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/DecisionRequestHelperTests.cs b/tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/DecisionRequestHelperTests.cs index 6d4eceb31..56bf62603 100644 --- a/tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/DecisionRequestHelperTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/DecisionRequestHelperTests.cs @@ -183,12 +183,8 @@ private static XacmlJsonResponse CreateMockedXamlJsonResponse(XacmlJsonRequestRo } private static List GetAsClaims(params (string, string)[] claims) - { - return claims.Select(c => new Claim(c.Item1, c.Item2)).ToList(); - } + => claims.Select(c => new Claim(c.Item1, c.Item2)).ToList(); - private static bool ContainsSameElements(IEnumerable collection, IEnumerable expectedElements) - { - return expectedElements.All(expected => collection.Contains(expected)) && collection.Count() == expectedElements.Count(); - } + private static bool ContainsSameElements(IEnumerable collection, IEnumerable expectedElements) => + expectedElements.All(collection.Contains) && collection.Count() == expectedElements.Count(); } From 85fdf92778d0e008de4cd9c4eaee741bf91ecc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Mon, 8 Apr 2024 11:14:59 +0200 Subject: [PATCH 3/3] chore: Add seen log to service owner (#604) Not marking as feat., there is already a PR merged that adds the SeenLog split in the changelog. Will edit changelog with more notes before merging 1.4.0 --- docs/swagger/V1/swagger.verified.json | 70 +++++++++++++++++-- .../Dialogs/Queries/Get/GetDialogDto.cs | 4 +- .../Dialogs/Queries/Get/GetDialogQuery.cs | 4 +- .../Dialogs/Queries/Get/MappingProfile.cs | 2 +- .../Dialogs/Queries/Search/MappingProfile.cs | 2 +- .../Dialogs/Queries/Search/SearchDialogDto.cs | 4 +- .../Queries/Search/SearchDialogQuery.cs | 4 +- .../Dialogs/Queries/Get/GetDialogDto.cs | 13 ++++ .../Dialogs/Queries/Get/GetDialogQuery.cs | 32 +++++++-- .../Dialogs/Queries/Get/MappingProfile.cs | 5 +- .../Dialogs/Queries/Search/MappingProfile.cs | 7 ++ .../Dialogs/Queries/Search/SearchDialogDto.cs | 12 ++++ .../Queries/Search/SearchDialogQuery.cs | 21 +++++- 13 files changed, 158 insertions(+), 22 deletions(-) diff --git a/docs/swagger/V1/swagger.verified.json b/docs/swagger/V1/swagger.verified.json index 5faf7ca90..882c5df4d 100644 --- a/docs/swagger/V1/swagger.verified.json +++ b/docs/swagger/V1/swagger.verified.json @@ -2602,6 +2602,12 @@ "items": { "$ref": "#/components/schemas/SearchDialogContentDtoSO" } + }, + "seenSinceLastUpdate": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchDialogDialogSeenRecordDtoSO" + } } } }, @@ -2620,6 +2626,31 @@ } } }, + "SearchDialogDialogSeenRecordDtoSO": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "endUserIdHash": { + "type": "string" + }, + "endUserName": { + "type": "string", + "nullable": true + }, + "isCurrentEndUser": { + "type": "boolean", + "nullable": true + } + } + }, "GetDialogDtoSO": { "type": "object", "additionalProperties": false, @@ -2721,6 +2752,12 @@ "items": { "$ref": "#/components/schemas/GetDialogDialogActivityDtoSO" } + }, + "seenSinceLastUpdate": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetDialogDialogSeenRecordDtoSO" + } } } }, @@ -2961,6 +2998,31 @@ } } }, + "GetDialogDialogSeenRecordDtoSO": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "guid" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "endUserIdHash": { + "type": "string" + }, + "endUserName": { + "type": "string", + "nullable": true + }, + "isCurrentEndUser": { + "type": "boolean", + "nullable": true + } + } + }, "CreateDialogCommand": { "type": "object", "additionalProperties": false, @@ -3471,7 +3533,7 @@ "$ref": "#/components/schemas/SearchDialogContentDto" } }, - "seenLog": { + "seenSinceLastUpdate": { "type": "array", "items": { "$ref": "#/components/schemas/SearchDialogDialogSeenRecordDto" @@ -3559,7 +3621,7 @@ "type": "string", "nullable": true }, - "isAuthenticatedUser": { + "isCurrentEndUser": { "type": "boolean" } } @@ -3658,7 +3720,7 @@ "$ref": "#/components/schemas/GetDialogDialogActivityDto" } }, - "seenLog": { + "seenSinceLastUpdate": { "type": "array", "items": { "$ref": "#/components/schemas/GetDialogDialogSeenRecordDto" @@ -3924,7 +3986,7 @@ "type": "string", "nullable": true }, - "isAuthenticatedUser": { + "isCurrentEndUser": { "type": "boolean" } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs index 3d7a04d56..e4056533f 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogDto.cs @@ -33,7 +33,7 @@ public sealed class GetDialogDto public List GuiActions { get; set; } = []; public List ApiActions { get; set; } = []; public List Activities { get; set; } = []; - public List SeenLog { get; set; } = []; + public List SeenSinceLastUpdate { get; set; } = []; } public class GetDialogDialogSeenRecordDto @@ -45,7 +45,7 @@ public class GetDialogDialogSeenRecordDto public string? EndUserName { get; set; } - public bool IsAuthenticatedUser { get; set; } + public bool IsCurrentEndUser { get; set; } } public sealed class GetDialogContentDto diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs index cc1ebeb10..b5ade7164 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/GetDialogQuery.cs @@ -117,11 +117,11 @@ public async Task Handle(GetDialogQuery request, CancellationTo var dialogDto = _mapper.Map(dialog); - dialogDto.SeenLog = dialog.SeenLog + dialogDto.SeenSinceLastUpdate = dialog.SeenLog .Select(log => { var logDto = _mapper.Map(log); - logDto.IsAuthenticatedUser = log.EndUserId == userPid; + logDto.IsCurrentEndUser = log.EndUserId == userPid; logDto.EndUserIdHash = _stringHasher.Hash(log.EndUserId); return logDto; }) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs index c3ca7b3b4..44528f860 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Get/MappingProfile.cs @@ -14,7 +14,7 @@ public MappingProfile() CreateMap() .ForMember(dest => dest.Revision, opt => opt.MapFrom(src => src.Revision)) .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusId)) - .ForMember(dest => dest.SeenLog, opt => opt.Ignore()); + .ForMember(dest => dest.SeenSinceLastUpdate, opt => opt.Ignore()); CreateMap(); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs index a4cc6015b..8987b0c99 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/MappingProfile.cs @@ -16,7 +16,7 @@ public MappingProfile() .OrderByDescending(activity => activity.CreatedAt).ThenByDescending(activity => activity.Id) .FirstOrDefault() )) - .ForMember(dest => dest.SeenLog, opt => opt.MapFrom(src => src.SeenLog + .ForMember(dest => dest.SeenSinceLastUpdate, opt => opt.MapFrom(src => src.SeenLog .Where(x => x.CreatedAt >= x.Dialog.UpdatedAt) .OrderByDescending(x => x.CreatedAt) )) diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs index 0e62cf7a8..fafb9fff0 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogDto.cs @@ -23,7 +23,7 @@ public sealed class SearchDialogDto public SearchDialogDialogActivityDto? LatestActivity { get; set; } public List Content { get; set; } = []; - public List SeenLog { get; set; } = []; + public List SeenSinceLastUpdate { get; set; } = []; } public class SearchDialogDialogSeenRecordDto @@ -35,7 +35,7 @@ public class SearchDialogDialogSeenRecordDto public string? EndUserName { get; set; } - public bool IsAuthenticatedUser { get; set; } + public bool IsCurrentEndUser { get; set; } } public sealed class SearchDialogContentDto diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs index 2bcdf6c75..f30f26dc8 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQuery.cs @@ -177,10 +177,10 @@ public async Task Handle(SearchDialogQuery request, Cancella .ProjectTo(_mapper.ConfigurationProvider) .ToPaginatedListAsync(request, cancellationToken: cancellationToken); - foreach (var seenLog in paginatedList.Items.SelectMany(x => x.SeenLog)) + foreach (var seenLog in paginatedList.Items.SelectMany(x => x.SeenSinceLastUpdate)) { // Before we hash the end user id, check if the seen log entry is for the current user - seenLog.IsAuthenticatedUser = userPid == seenLog.EndUserIdHash; + seenLog.IsCurrentEndUser = userPid == seenLog.EndUserIdHash; // TODO: Add test to not expose un-hashed end user id to the client // https://github.com/digdir/dialogporten/issues/596 seenLog.EndUserIdHash = _stringHasher.Hash(seenLog.EndUserIdHash); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs index 683ec16c3..caf584dfd 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogDto.cs @@ -35,6 +35,19 @@ public sealed class GetDialogDto public List GuiActions { get; set; } = []; public List ApiActions { get; set; } = []; public List Activities { get; set; } = []; + public List SeenSinceLastUpdate { get; set; } = []; +} + +public class GetDialogDialogSeenRecordDto +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + + public string EndUserIdHash { get; set; } = null!; + + public string? EndUserName { get; set; } + + public bool? IsCurrentEndUser { get; set; } } public sealed class GetDialogContentDto diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs index 33898db80..a946a0a19 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/GetDialogQuery.cs @@ -1,5 +1,4 @@ using AutoMapper; -using AutoMapper.QueryableExtensions; using Digdir.Domain.Dialogporten.Application.Common; using Digdir.Domain.Dialogporten.Application.Common.ReturnTypes; using Digdir.Domain.Dialogporten.Application.Externals; @@ -23,15 +22,18 @@ internal sealed class GetDialogQueryHandler : IRequestHandler Handle(GetDialogQuery request, CancellationToken cancellationToken) @@ -54,10 +56,14 @@ public async Task Handle(GetDialogQuery request, CancellationTo .ThenInclude(x => x.Title!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode)) .Include(x => x.ApiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id)) .ThenInclude(x => x.Endpoints.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id)) + .Include(x => x.Activities).ThenInclude(x => x.PerformedBy!.Localizations) + .Include(x => x.Activities).ThenInclude(x => x.Description!.Localizations) + .Include(x => x.SeenLog + .Where(x => x.CreatedAt >= x.Dialog.UpdatedAt) + .OrderBy(x => x.CreatedAt)) .IgnoreQueryFilters() - .AsNoTracking() + .AsNoTracking() // TODO: Remove when #386 is implemented .Where(x => resourceIds.Contains(x.ServiceResource)) - .ProjectTo(_mapper.ConfigurationProvider) .FirstOrDefaultAsync(x => x.Id == request.DialogId, cancellationToken); if (dialog is null) @@ -65,6 +71,22 @@ public async Task Handle(GetDialogQuery request, CancellationTo return new EntityNotFound(request.DialogId); } - return dialog; + // TODO: Add SeenLog if optional parameter pid on behalf of end user is present + // https://github.com/digdir/dialogporten/issues/386 + + var dialogDto = _mapper.Map(dialog); + + dialogDto.SeenSinceLastUpdate = dialog.SeenLog + .Select(log => + { + var logDto = _mapper.Map(log); + // TODO: Set when #386 is implemented + // logDto.IsAuthenticatedUser = log.EndUserId == userPid; + logDto.EndUserIdHash = _stringHasher.Hash(log.EndUserId); + return logDto; + }) + .ToList(); + + return dialogDto; } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs index 081e4bbb5..1500a9f9b 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Get/MappingProfile.cs @@ -13,7 +13,10 @@ public MappingProfile() { CreateMap() .ForMember(dest => dest.Revision, opt => opt.MapFrom(src => src.Revision)) - .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusId)); + .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusId)) + .ForMember(dest => dest.SeenSinceLastUpdate, opt => opt.Ignore()); + + CreateMap(); CreateMap() .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.TypeId)); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs index a7cd3871a..09f3a90dc 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/MappingProfile.cs @@ -9,9 +9,16 @@ internal sealed class MappingProfile : Profile public MappingProfile() { CreateMap() + .ForMember(dest => dest.SeenSinceLastUpdate, opt => opt.MapFrom(src => src.SeenLog + .Where(x => x.CreatedAt >= x.Dialog.UpdatedAt) + .OrderByDescending(x => x.CreatedAt) + )) .ForMember(dest => dest.Content, opt => opt.MapFrom(src => src.Content.Where(x => x.Type.OutputInList))) .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusId)); + CreateMap() + .ForMember(dest => dest.EndUserIdHash, opt => opt.MapFrom(src => src.EndUserId)); + CreateMap(); CreateMap() diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs index 53f3ab060..2e4135f04 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogDto.cs @@ -21,6 +21,18 @@ public sealed class SearchDialogDto public DialogStatus.Values Status { get; set; } public List Content { get; set; } = []; + public List SeenSinceLastUpdate { get; set; } = []; +} + +public class SearchDialogDialogSeenRecordDto +{ + public Guid Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + + public string EndUserIdHash { get; set; } = null!; + + public string? EndUserName { get; set; } + public bool? IsCurrentEndUser { get; set; } } public sealed class SearchDialogSearchTagDto 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 fbc69ca43..724c504d4 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 @@ -123,17 +123,20 @@ internal sealed class SearchDialogQueryHandler : IRequestHandler Handle(SearchDialogQuery request, CancellationToken cancellationToken) @@ -174,8 +177,22 @@ public async Task Handle(SearchDialogQuery request, Cancella query = query.WhereUserIsAuthorizedFor(authorizedResources); } - return await query + var paginatedList = await query .ProjectTo(_mapper.ConfigurationProvider) .ToPaginatedListAsync(request, cancellationToken: cancellationToken); + + foreach (var seenRecord in paginatedList.Items.SelectMany(x => x.SeenSinceLastUpdate)) + { + if (request.EndUserId is not null) + { + seenRecord.IsCurrentEndUser = seenRecord.EndUserIdHash == request.EndUserId; + } + + // TODO: Add test to not expose un-hashed end user id to the client + // https://github.com/digdir/dialogporten/issues/596 + seenRecord.EndUserIdHash = _stringHasher.Hash(seenRecord.EndUserIdHash); + } + + return paginatedList; } }