Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ensure performed by is set for activities #628

Merged
merged 19 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -43,6 +44,7 @@ public static IServiceCollection AddApplication(this IServiceCollection services
.AddTransient<IUserOrganizationRegistry, UserOrganizationRegistry>()
.AddTransient<IUserResourceRegistry, UserResourceRegistry>()
.AddTransient<IUserNameRegistry, UserNameRegistry>()
.AddTransient<IDialogActivityService, DialogActivityService>()
.AddTransient<IClock, Clock>()
.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>))
.AddTransient(typeof(IPipelineBehavior<,>), typeof(DomainContextBehaviour<,>));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace Digdir.Domain.Dialogporten.Application.Common;
public interface IUserOrganizationRegistry
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ikke innført i denne PR-en, men jeg synes at bruken av "organization" blir misvisende, siden det er snakk om tjenesteeiere (som vi ellers kaller "service owners") og ikke bare hvilken som helst organisasjon. Har eksperimentert litt i en branch, som jeg mener har en bedre oppdeling mht externals-servicene og "current user"-servicene, som altså er sammenstillingene av IUser og externals-ene (implementasjonen har dog andre problemer som er knyttet til usertype, så den er ikke brukanes pt)

{
Task<string?> GetCurrentUserOrgShortName(CancellationToken cancellationToken);
Task<IList<OrganizationLongName>?> GetCurrentUserOrgLongNames(CancellationToken cancellationToken);
}

public class UserOrganizationRegistry : IUserOrganizationRegistry
Expand All @@ -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<IList<OrganizationLongName>?> GetCurrentUserOrgLongNames(CancellationToken cancellationToken)
{
if (!_user.TryGetOrgNumber(out var orgNumber))
{
return null;
}

var orgInfo = await _organizationRegistry.GetOrgInfo(orgNumber, cancellationToken);

return orgInfo?.LongNames.ToArray();
}
}

Expand All @@ -41,4 +56,6 @@ internal sealed class LocalDevelopmentUserOrganizationRegistryDecorator : IUserO
public LocalDevelopmentUserOrganizationRegistryDecorator(IUserOrganizationRegistry _) { }

public Task<string?> GetCurrentUserOrgShortName(CancellationToken cancellationToken) => Task.FromResult("digdir")!;
public Task<IList<OrganizationLongName>?> GetCurrentUserOrgLongNames(CancellationToken cancellationToken) =>
Task.FromResult<IList<OrganizationLongName>?>(new[] { new OrganizationLongName { LongName = "Digdir", Language = "nb" } });
}
Original file line number Diff line number Diff line change
@@ -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<DialogActivity> activities, CancellationToken cancellationToken);
}

public class DialogActivityService : IDialogActivityService
{
private readonly IUserOrganizationRegistry _userOrganizationRegistry;

public DialogActivityService(
IUserOrganizationRegistry userOrganizationRegistry
)
{
_userOrganizationRegistry = userOrganizationRegistry;
}

public async Task EnsurePerformedByIsSetForActivities(IEnumerable<DialogActivity> 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<Localization>(),
};
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,18 @@ namespace Digdir.Domain.Dialogporten.Application.Externals;

public interface IOrganizationRegistry
{
Task<string?> GetOrgShortName(string orgNumber, CancellationToken cancellationToken);
Task<OrganizationInfo?> GetOrgInfo(string orgNumber, CancellationToken cancellationToken);
}

public sealed class OrganizationLongName
{
public required string LongName { get; init; }
public required string Language { get; init; }
oskogstad marked this conversation as resolved.
Show resolved Hide resolved
}

public sealed class OrganizationInfo
{
public required string OrgNumber { get; init; }
public required string ShortName { get; init; }
public required IList<OrganizationLongName> LongNames { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,21 +28,24 @@ internal sealed class CreateDialogCommandHandler : IRequestHandler<CreateDialogC
private readonly IDomainContext _domainContext;
private readonly IUserResourceRegistry _userResourceRegistry;
private readonly IUserOrganizationRegistry _userOrganizationRegistry;
private readonly IDialogActivityService _dialogActivityService;

public CreateDialogCommandHandler(
IDialogDbContext db,
IMapper mapper,
IUnitOfWork unitOfWork,
IDomainContext domainContext,
IUserResourceRegistry userResourceRegistry,
IUserOrganizationRegistry userOrganizationRegistry)
IUserOrganizationRegistry userOrganizationRegistry,
oskogstad marked this conversation as resolved.
Show resolved Hide resolved
IDialogActivityService dialogActivityService)
{
_db = db ?? throw new ArgumentNullException(nameof(db));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
_unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
_domainContext = domainContext ?? throw new ArgumentNullException(nameof(domainContext));
_userResourceRegistry = userResourceRegistry ?? throw new ArgumentNullException(nameof(userResourceRegistry));
_userOrganizationRegistry = userOrganizationRegistry ?? throw new ArgumentNullException(nameof(userOrganizationRegistry));
_dialogActivityService = dialogActivityService ?? throw new ArgumentNullException(nameof(dialogActivityService));
}

public async Task<CreateDialogResult> Handle(CreateDialogCommand request, CancellationToken cancellationToken)
Expand Down Expand Up @@ -77,6 +82,8 @@ public async Task<CreateDialogResult> Handle(CreateDialogCommand request, Cancel
_domainContext.AddError(DomainFailure.EntityExists<DialogElement>(existingElementIds));
}

await _dialogActivityService.EnsurePerformedByIsSetForActivities(dialog.Activities, cancellationToken);

await _db.Dialogs.AddAsync(dialog, cancellationToken);

var saveResult = await _unitOfWork.SaveChangesAsync(cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -32,19 +34,22 @@ internal sealed class UpdateDialogCommandHandler : IRequestHandler<UpdateDialogC
private readonly IUnitOfWork _unitOfWork;
private readonly IDomainContext _domainContext;
private readonly IUserResourceRegistry _userResourceRegistry;
private readonly IDialogActivityService _dialogActivityService;

public UpdateDialogCommandHandler(
IDialogDbContext db,
IMapper mapper,
IUnitOfWork unitOfWork,
IDomainContext domainContext,
IUserResourceRegistry userResourceRegistry)
IUserResourceRegistry userResourceRegistry,
IDialogActivityService dialogActivityService)
{
_db = db ?? throw new ArgumentNullException(nameof(db));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
_unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
_domainContext = domainContext ?? throw new ArgumentNullException(nameof(domainContext));
_userResourceRegistry = userResourceRegistry ?? throw new ArgumentNullException(nameof(userResourceRegistry));
_dialogActivityService = dialogActivityService ?? throw new ArgumentNullException(nameof(dialogActivityService));
}

public async Task<UpdateDialogResult> Handle(UpdateDialogCommand request, CancellationToken cancellationToken)
Expand Down Expand Up @@ -165,6 +170,9 @@ private async Task AppendActivity(DialogEntity dialog, UpdateDialogDto dto, Canc
{
var newDialogActivities = _mapper.Map<List<DialogActivity>>(dto.Activities);


await _dialogActivityService.EnsurePerformedByIsSetForActivities(newDialogActivities, cancellationToken);

var existingIds = await _db.GetExistingIds(newDialogActivities, cancellationToken);
if (existingIds.Count != 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

Expand All @@ -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<string?> GetOrgShortName(string orgNumber, CancellationToken cancellationToken)

public async Task<OrganizationInfo?> 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<Dictionary<string, string>> GetOrgShortNameByOrgNumber(CancellationToken cancellationToken)
private async Task<Dictionary<string, OrganizationInfo>> GetOrgInfo(CancellationToken cancellationToken)
{
const string searchEndpoint = "orgs/altinn-orgs.json";
var response = await _client
.GetFromJsonAsync<OrganizationRegistryResponse>(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<OrganizationLongName>()
});

return orgShortNameByOrgNumber;
return orgInfoByOrgNumber;
}

private sealed class OrganizationRegistryResponse
Expand All @@ -57,4 +65,4 @@ private sealed class OrganizationDetails
public string? Homepage { get; init; }
public IList<string>? Environments { get; init; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,13 @@ private static IOrganizationRegistry CreateOrganizationRegistrySubstitute()
var organizationRegistrySubstitute = Substitute.For<IOrganizationRegistry>();

organizationRegistrySubstitute
.GetOrgShortName(Arg.Any<string>(), Arg.Any<CancellationToken>())
.Returns("digdir");
.GetOrgInfo(Arg.Any<string>(), Arg.Any<CancellationToken>())
.Returns(new OrganizationInfo
{
OrgNumber = "991825827",
ShortName = "digdir",
LongNames = new[] { new OrganizationLongName { LongName = "Digitaliseringsdirektoratet", Language = "nb" } }
});

return organizationRegistrySubstitute;
}
Expand Down