diff --git a/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs index b962d8198..bdd505b52 100644 --- a/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/ApplicationExtensions.cs @@ -2,6 +2,7 @@ using Digdir.Domain.Dialogporten.Application.Common.Behaviours; using Digdir.Domain.Dialogporten.Application.Common.Extensions; using Digdir.Domain.Dialogporten.Application.Common.Extensions.OptionExtensions; +using Digdir.Domain.Dialogporten.Application.Common.Services; using FluentValidation; using MediatR; using Microsoft.Extensions.Configuration; @@ -43,6 +44,7 @@ public static IServiceCollection AddApplication(this IServiceCollection services .AddTransient() .AddTransient() .AddTransient() + .AddTransient() .AddTransient() .AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)) .AddTransient(typeof(IPipelineBehavior<,>), typeof(DomainContextBehaviour<,>)); diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/IUserOrganizationRegistry.cs b/src/Digdir.Domain.Dialogporten.Application/Common/IUserOrganizationRegistry.cs index 99bb14be3..74904737d 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/IUserOrganizationRegistry.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/IUserOrganizationRegistry.cs @@ -7,6 +7,7 @@ namespace Digdir.Domain.Dialogporten.Application.Common; public interface IUserOrganizationRegistry { Task GetCurrentUserOrgShortName(CancellationToken cancellationToken); + Task?> GetCurrentUserOrgLongNames(CancellationToken cancellationToken); } public class UserOrganizationRegistry : IUserOrganizationRegistry @@ -32,7 +33,21 @@ public UserOrganizationRegistry(IUser user, IOrganizationRegistry organizationRe return null; } - return await _organizationRegistry.GetOrgShortName(orgNumber, cancellationToken); + var orgInfo = await _organizationRegistry.GetOrgInfo(orgNumber, cancellationToken); + + return orgInfo?.ShortName; + } + + public async Task?> GetCurrentUserOrgLongNames(CancellationToken cancellationToken) + { + if (!_user.TryGetOrgNumber(out var orgNumber)) + { + return null; + } + + var orgInfo = await _organizationRegistry.GetOrgInfo(orgNumber, cancellationToken); + + return orgInfo?.LongNames.ToArray(); } } @@ -41,4 +56,6 @@ internal sealed class LocalDevelopmentUserOrganizationRegistryDecorator : IUserO public LocalDevelopmentUserOrganizationRegistryDecorator(IUserOrganizationRegistry _) { } public Task GetCurrentUserOrgShortName(CancellationToken cancellationToken) => Task.FromResult("digdir")!; + public Task?> GetCurrentUserOrgLongNames(CancellationToken cancellationToken) => + Task.FromResult?>(new[] { new OrganizationLongName { LongName = "Digdir", Language = "nb" } }); } diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Services/DialogActivityService.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Services/DialogActivityService.cs new file mode 100644 index 000000000..21dd4eb32 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Services/DialogActivityService.cs @@ -0,0 +1,35 @@ +using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; +using Digdir.Domain.Dialogporten.Domain.Localizations; + +namespace Digdir.Domain.Dialogporten.Application.Common.Services; + +public interface IDialogActivityService +{ + Task EnsurePerformedByIsSetForActivities(IEnumerable activities, CancellationToken cancellationToken); +} + +public class DialogActivityService : IDialogActivityService +{ + private readonly IUserOrganizationRegistry _userOrganizationRegistry; + + public DialogActivityService( + IUserOrganizationRegistry userOrganizationRegistry + ) + { + _userOrganizationRegistry = userOrganizationRegistry; + } + + public async Task EnsurePerformedByIsSetForActivities(IEnumerable activities, CancellationToken cancellationToken) + { + // TODO: if organization cannot be found we need to handle this. Put on a queue to be retried later(?) https://github.com/digdir/dialogporten/issues/639 + foreach (var activity in activities) + { + var organizationLongNames = await _userOrganizationRegistry.GetCurrentUserOrgLongNames(cancellationToken); + activity.PerformedBy ??= new DialogActivityPerformedBy + { + Localizations = organizationLongNames?.Select(x => new Localization { Value = x.LongName, CultureCode = x.Language }).ToList() ?? new List(), + }; + } + } +} + diff --git a/src/Digdir.Domain.Dialogporten.Application/Externals/IOrganizationRegistry.cs b/src/Digdir.Domain.Dialogporten.Application/Externals/IOrganizationRegistry.cs index 9be3196e1..923f61760 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Externals/IOrganizationRegistry.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Externals/IOrganizationRegistry.cs @@ -2,5 +2,18 @@ namespace Digdir.Domain.Dialogporten.Application.Externals; public interface IOrganizationRegistry { - Task GetOrgShortName(string orgNumber, CancellationToken cancellationToken); + Task GetOrgInfo(string orgNumber, CancellationToken cancellationToken); } + +public sealed class OrganizationLongName +{ + public required string LongName { get; init; } + public required string Language { get; init; } +} + +public sealed class OrganizationInfo +{ + public required string OrgNumber { get; init; } + public required string ShortName { get; init; } + public required IList LongNames { get; init; } +} \ No newline at end of file diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs index c2bf775f5..c8de6de81 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Create/CreateDialogCommand.cs @@ -2,11 +2,13 @@ using AutoMapper; using Digdir.Domain.Dialogporten.Application.Common; using Digdir.Domain.Dialogporten.Application.Common.ReturnTypes; +using Digdir.Domain.Dialogporten.Application.Common.Services; using Digdir.Domain.Dialogporten.Application.Externals; using Digdir.Domain.Dialogporten.Domain.Common; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Elements; +using Digdir.Domain.Dialogporten.Domain.Localizations; using MediatR; using OneOf; using OneOf.Types; @@ -26,6 +28,7 @@ internal sealed class CreateDialogCommandHandler : IRequestHandler Handle(CreateDialogCommand request, CancellationToken cancellationToken) @@ -77,6 +82,8 @@ public async Task Handle(CreateDialogCommand request, Cancel _domainContext.AddError(DomainFailure.EntityExists(existingElementIds)); } + await _dialogActivityService.EnsurePerformedByIsSetForActivities(dialog.Activities, cancellationToken); + await _db.Dialogs.AddAsync(dialog, cancellationToken); var saveResult = await _unitOfWork.SaveChangesAsync(cancellationToken); diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs index 41f553d82..6c6e16e9a 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Commands/Update/UpdateDialogCommand.cs @@ -2,12 +2,14 @@ using Digdir.Domain.Dialogporten.Application.Common; using Digdir.Domain.Dialogporten.Application.Common.Extensions.Enumerables; using Digdir.Domain.Dialogporten.Application.Common.ReturnTypes; +using Digdir.Domain.Dialogporten.Application.Common.Services; using Digdir.Domain.Dialogporten.Application.Externals; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Actions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Content; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Elements; +using Digdir.Domain.Dialogporten.Domain.Localizations; using MediatR; using Microsoft.EntityFrameworkCore; using OneOf; @@ -32,19 +34,22 @@ internal sealed class UpdateDialogCommandHandler : IRequestHandler Handle(UpdateDialogCommand request, CancellationToken cancellationToken) @@ -165,6 +170,9 @@ private async Task AppendActivity(DialogEntity dialog, UpdateDialogDto dto, Canc { var newDialogActivities = _mapper.Map>(dto.Activities); + + await _dialogActivityService.EnsurePerformedByIsSetForActivities(newDialogActivities, cancellationToken); + var existingIds = await _db.GetExistingIds(newDialogActivities, cancellationToken); if (existingIds.Count != 0) { diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs index 131f6a322..a371f9dcf 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/OrganizationRegistry/OrganizationRegistryClient.cs @@ -8,7 +8,8 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.Altinn.OrganizationRegistry; internal class OrganizationRegistryClient : IOrganizationRegistry { - private const string OrgShortNameReferenceCacheKey = "OrgShortNameReference"; + private const string OrgNameReferenceCacheKey = "OrgNameReference"; + private static readonly DistributedCacheEntryOptions OneDayCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) }; private static readonly DistributedCacheEntryOptions ZeroCacheDuration = new() { AbsoluteExpiration = DateTimeOffset.MinValue }; @@ -20,28 +21,35 @@ public OrganizationRegistryClient(HttpClient client, IFusionCacheProvider cacheP _client = client ?? throw new ArgumentNullException(nameof(client)); _cache = cacheProvider.GetCache(nameof(OrganizationRegistry)) ?? throw new ArgumentNullException(nameof(cacheProvider)); } - public async Task GetOrgShortName(string orgNumber, CancellationToken cancellationToken) + + public async Task GetOrgInfo(string orgNumber, CancellationToken cancellationToken) { - var orgShortNameByOrgNumber = await _cache.GetOrSetAsync(OrgShortNameReferenceCacheKey, async token => await GetOrgShortNameByOrgNumber(token), token: cancellationToken); - orgShortNameByOrgNumber.TryGetValue(orgNumber, out var orgShortName); + var orgInfoByOrgNumber = await _cache.GetOrSetAsync(OrgNameReferenceCacheKey, GetOrgInfo, token: cancellationToken); + orgInfoByOrgNumber.TryGetValue(orgNumber, out var orgInfo); - return orgShortName; + return orgInfo; } - private async Task> GetOrgShortNameByOrgNumber(CancellationToken cancellationToken) + private async Task> GetOrgInfo(CancellationToken cancellationToken) { const string searchEndpoint = "orgs/altinn-orgs.json"; var response = await _client .GetFromJsonAsync(searchEndpoint, cancellationToken) ?? throw new UnreachableException(); - var orgShortNameByOrgNumber = response + var orgInfoByOrgNumber = response .Orgs - .ToDictionary( - pair => pair.Value.Orgnr, - pair => pair.Key - ); + .ToDictionary(pair => pair.Value.Orgnr, pair => new OrganizationInfo + { + OrgNumber = pair.Value.Orgnr, + ShortName = pair.Key, + LongNames = pair.Value.Name?.Select(name => new OrganizationLongName + { + LongName = name.Value, + Language = name.Key + }).ToList() ?? new List() + }); - return orgShortNameByOrgNumber; + return orgInfoByOrgNumber; } private sealed class OrganizationRegistryResponse @@ -57,4 +65,4 @@ private sealed class OrganizationDetails public string? Homepage { get; init; } public IList? Environments { get; init; } } -} +} \ No newline at end of file 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 b8e7a7483..3edc304f9 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/DialogApplication.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/DialogApplication.cs @@ -118,8 +118,13 @@ private static IOrganizationRegistry CreateOrganizationRegistrySubstitute() var organizationRegistrySubstitute = Substitute.For(); organizationRegistrySubstitute - .GetOrgShortName(Arg.Any(), Arg.Any()) - .Returns("digdir"); + .GetOrgInfo(Arg.Any(), Arg.Any()) + .Returns(new OrganizationInfo + { + OrgNumber = "991825827", + ShortName = "digdir", + LongNames = new[] { new OrganizationLongName { LongName = "Digitaliseringsdirektoratet", Language = "nb" } } + }); return organizationRegistrySubstitute; }