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

feat: Introduce Actor Entity #1775

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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 @@ -4,6 +4,7 @@
using Digdir.Library.Entity.Abstractions.Features.Identifiable;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using Digdir.Domain.Dialogporten.Domain.Actors;
using Digdir.Domain.Dialogporten.Domain.DialogEndUserContexts.Entities;
using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Contents;
using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions;
Expand Down Expand Up @@ -45,6 +46,8 @@ public interface IDialogDbContext
DbSet<LabelAssignmentLog> LabelAssignmentLogs { get; }
DbSet<ResourcePolicyInformation> ResourcePolicyInformation { get; }

DbSet<ActorName> ActorName { get; }

/// <summary>
/// Validate a property on the <typeparamref name="TEntity"/> using a lambda
/// expression to specify the predicate only when the property is modified.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public MappingProfile()

CreateMap<Actor, ActorDto>()
.ForMember(dest => dest.ActorType, opt => opt.MapFrom(src => src.ActorTypeId))
.ForMember(dest => dest.ActorId, opt => opt.MapFrom(src => IdentifierMasker.GetMaybeMaskedIdentifier(src.ActorId)));
.ForMember(dest => dest.ActorId, opt => opt.MapFrom(src => IdentifierMasker.GetMaybeMaskedIdentifier(src.ActorId)))
.ForMember(dest => dest.ActorName, opt => opt.MapFrom(src => src.ActorNameEntity == null ? src.ActorName! : src.ActorNameEntity.Name));

foreach (var outputActor in derivedActorTypes)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public async Task<GetActivityResult> Handle(GetActivityQuery request,
var dialog = await _dbContext.Dialogs
.Include(x => x.Activities.Where(x => x.Id == request.ActivityId))
.ThenInclude(x => x.PerformedBy)
.ThenInclude(x => x.ActorNameEntity)
.Include(x => x.Activities.Where(x => x.Id == request.ActivityId))
.ThenInclude(x => x.Description!.Localizations)
.IgnoreQueryFilters()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task<SearchLabelAssignmentLogResult> Handle(SearchLabelAssignmentLo
.AsNoTracking()
.Include(x => x.DialogEndUserContext)
.ThenInclude(x => x.LabelAssignmentLogs)
.ThenInclude(x => x.PerformedBy)
.ThenInclude(x => x.PerformedBy).ThenInclude(x => x.ActorNameEntity)
.FirstOrDefaultAsync(x => x.Id == request.DialogId, cancellationToken: cancellationToken);

if (dialog == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task<GetSeenLogResult> Handle(GetSeenLogQuery request,
var dialog = await _dbContext.Dialogs
.AsNoTracking()
.Include(x => x.SeenLog.Where(x => x.Id == request.SeenLogId))
.ThenInclude(x => x.SeenBy)
.ThenInclude(x => x.SeenBy).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.FirstOrDefaultAsync(x => x.Id == request.DialogId,
cancellationToken: cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async Task<SearchSeenLogResult> Handle(SearchSeenLogQuery request, Cancel
var dialog = await _db.Dialogs
.AsNoTracking()
.Include(x => x.SeenLog)
.ThenInclude(x => x.SeenBy)
.ThenInclude(x => x.SeenBy).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.FirstOrDefaultAsync(x => x.Id == request.DialogId,
cancellationToken: cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public async Task<GetTransmissionResult> Handle(GetTransmissionQuery request,
.ThenInclude(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Urls.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.Transmissions)
.ThenInclude(x => x.Sender)
.ThenInclude(x => x.Sender).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.FirstOrDefaultAsync(x => x.Id == request.DialogId,
cancellationToken: cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public async Task<SearchTransmissionResult> Handle(SearchTransmissionQuery reque
.ThenInclude(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Urls.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.Transmissions)
.ThenInclude(x => x.Sender)
.ThenInclude(x => x.Sender).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.FirstOrDefaultAsync(x => x.Id == request.DialogId,
cancellationToken: cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,16 @@ public async Task<GetDialogResult> Handle(GetDialogQuery request, CancellationTo
.Include(x => x.Transmissions)
.ThenInclude(x => x.Content)
.ThenInclude(x => x.Value.Localizations)
.Include(x => x.Transmissions).ThenInclude(x => x.Sender)
.Include(x => x.Transmissions).ThenInclude(x => x.Sender).ThenInclude(x => x.ActorNameEntity)
.Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.Urls)
.Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.DisplayName!.Localizations)
.Include(x => x.Activities).ThenInclude(x => x.Description!.Localizations)
.Include(x => x.Activities).ThenInclude(x => x.PerformedBy)
.Include(x => x.Activities).ThenInclude(x => x.PerformedBy).ThenInclude(x => x.ActorNameEntity)
.Include(x => x.SeenLog
.Where(x => x.CreatedAt >= x.Dialog.UpdatedAt)
.OrderBy(x => x.CreatedAt))
.ThenInclude(x => x.SeenBy)
.ThenInclude(x => x.ActorNameEntity)
.Include(x => x.DialogEndUserContext)
.Where(x => !x.VisibleFrom.HasValue || x.VisibleFrom < _clock.UtcNowOffset)
.IgnoreQueryFilters()
Expand Down Expand Up @@ -139,8 +140,9 @@ public async Task<GetDialogResult> Handle(GetDialogQuery request, CancellationTo
dialogDto.SeenSinceLastUpdate = dialog.SeenLog
.Select(log =>
{
var actorId = log.SeenBy.ActorNameEntity != null ? log.SeenBy.ActorNameEntity.ActorId : log.SeenBy.ActorId;
var logDto = _mapper.Map<DialogSeenLogDto>(log);
logDto.IsCurrentEndUser = currentUserInformation.UserId.ExternalIdWithPrefix == log.SeenBy.ActorId;
logDto.IsCurrentEndUser = currentUserInformation.UserId.ExternalIdWithPrefix == actorId;
return logDto;
})
.ToList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public MappingProfile()

CreateMap<ActorDto, Actor>()
.ForMember(dest => dest.ActorType, opt => opt.Ignore())
.ForMember(dest => dest.ActorTypeId, opt => opt.MapFrom(src => src.ActorType));
.ForMember(dest => dest.ActorTypeId, opt => opt.MapFrom(src => src.ActorType))
.ForMember(dest => dest.ActorId, opt => opt.MapFrom(src => src.ActorId));

foreach (var inputActor in derivedActorTypes)
{
Expand All @@ -29,7 +30,8 @@ public MappingProfile()

CreateMap<Actor, ActorDto>()
.ForMember(dest => dest.ActorId, opt => opt.MapFrom(src => src.ActorId))
.ForMember(dest => dest.ActorType, opt => opt.MapFrom(src => src.ActorTypeId));
.ForMember(dest => dest.ActorType, opt => opt.MapFrom(src => src.ActorTypeId))
.ForMember(dest => dest.ActorName, opt => opt.MapFrom(src => src.ActorNameEntity == null ? src.ActorName! : src.ActorNameEntity.Name));

foreach (var outputActor in derivedActorTypes)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public async Task<GetActivityResult> Handle(GetActivityQuery request,

var dialog = await _dbContext.Dialogs
.Include(x => x.Activities.Where(x => x.Id == request.ActivityId))
.ThenInclude(x => x.PerformedBy)
.ThenInclude(x => x.PerformedBy).ThenInclude(x => x.ActorNameEntity)
.Include(x => x.Activities.Where(x => x.Id == request.ActivityId))
.ThenInclude(x => x.Description!.Localizations)
.IgnoreQueryFilters()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public async Task<GetSeenLogResult> Handle(GetSeenLogQuery request,
var dialog = await _dbContext.Dialogs
.AsNoTracking()
.Include(x => x.SeenLog.Where(x => x.Id == request.SeenLogId))
.ThenInclude(x => x.SeenBy)
.ThenInclude(x => x.SeenBy).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.WhereIf(!_userResourceRegistry.IsCurrentUserServiceOwnerAdmin(),
x => resourceIds.Contains(x.ServiceResource))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task<SearchSeenLogResult> Handle(SearchSeenLogQuery request, Cancel
var dialog = await _db.Dialogs
.AsNoTracking()
.Include(x => x.SeenLog)
.ThenInclude(x => x.SeenBy)
.ThenInclude(x => x.SeenBy).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.WhereIf(!_userResourceRegistry.IsCurrentUserServiceOwnerAdmin(),
x => resourceIds.Contains(x.ServiceResource))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public async Task<GetTransmissionResult> Handle(GetTransmissionQuery request,
.ThenInclude(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Urls.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.Transmissions)
.ThenInclude(x => x.Sender)
.ThenInclude(x => x.Sender).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.WhereIf(!_userResourceRegistry.IsCurrentUserServiceOwnerAdmin(),
x => resourceIds.Contains(x.ServiceResource))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task<SearchTransmissionResult> Handle(SearchTransmissionQuery reque
.ThenInclude(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Urls.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.Transmissions)
.ThenInclude(x => x.Sender)
.ThenInclude(x => x.Sender).ThenInclude(x => x.ActorNameEntity)
.IgnoreQueryFilters()
.WhereIf(!_userResourceRegistry.IsCurrentUserServiceOwnerAdmin(),
x => resourceIds.Contains(x.ServiceResource))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ public async Task<CreateDialogResult> Handle(CreateDialogCommand request, Cancel
{
dialog.Org = serviceResourceInformation.OwnOrgShortName;
}

CreateDialogEndUserContext(request, dialog);
await EnsureNoExistingUserDefinedIds(dialog, cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ public async Task<GetDialogResult> Handle(GetDialogQuery request, CancellationTo
.Include(x => x.Transmissions)
.ThenInclude(x => x.Content)
.ThenInclude(x => x.Value.Localizations)
.Include(x => x.Transmissions).ThenInclude(x => x.Sender)
.Include(x => x.Transmissions).ThenInclude(x => x.Sender).ThenInclude(x => x.ActorNameEntity)
.Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.Urls)
.Include(x => x.Transmissions).ThenInclude(x => x.Attachments).ThenInclude(x => x.DisplayName!.Localizations)
.Include(x => x.Activities).ThenInclude(x => x.Description!.Localizations)
.Include(x => x.Activities).ThenInclude(x => x.PerformedBy)
.Include(x => x.Activities).ThenInclude(x => x.PerformedBy).ThenInclude(x => x.ActorNameEntity)
.Include(x => x.SeenLog
.Where(x => x.CreatedAt >= x.Dialog.UpdatedAt)
.OrderBy(x => x.CreatedAt))
.ThenInclude(x => x.SeenBy)
.ThenInclude(x => x.SeenBy).ThenInclude(x => x.ActorNameEntity)
.Include(x => x.DialogEndUserContext)
.IgnoreQueryFilters()
.WhereIf(!_userResourceRegistry.IsCurrentUserServiceOwnerAdmin(), x => resourceIds.Contains(x.ServiceResource))
Expand Down
2 changes: 2 additions & 0 deletions src/Digdir.Domain.Dialogporten.Domain/Actors/Actor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ public abstract class Actor : IEntity

public ActorType.Values ActorTypeId { get; set; }
public ActorType ActorType { get; set; } = null!;

public ActorName? ActorNameEntity { get; set; }
}
12 changes: 12 additions & 0 deletions src/Digdir.Domain.Dialogporten.Domain/Actors/ActorName.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Digdir.Library.Entity.Abstractions;
using Digdir.Library.Entity.Abstractions.Features.Immutable;

namespace Digdir.Domain.Dialogporten.Domain.Actors;

public sealed class ActorName : IImmutableEntity
{
public Guid Id { get; set; }
public string ActorId { get; set; } = null!;
public string Name { get; set; } = null!;
public DateTimeOffset CreatedAt { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Digdir.Domain.Dialogporten.Domain.Actors;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Digdir.Domain.Dialogporten.Infrastructure.Persistence.Configurations.Actors;

internal sealed class ActorNameConfiguration : IEntityTypeConfiguration<ActorName>
{
public void Configure(EntityTypeBuilder<ActorName> builder)
{
builder.HasIndex(x => new { x.ActorId, x.Name }).IsUnique();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public DialogDbContext(DbContextOptions<DialogDbContext> options) : base(options
public DbSet<LabelAssignmentLog> LabelAssignmentLogs => Set<LabelAssignmentLog>();
public DbSet<NotificationAcknowledgement> NotificationAcknowledgements => Set<NotificationAcknowledgement>();
public DbSet<ResourcePolicyInformation> ResourcePolicyInformation => Set<ResourcePolicyInformation>();
public DbSet<ActorName> ActorName => Set<ActorName>();

//protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
// optionsBuilder.LogTo(Console.WriteLine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Digdir.Domain.Dialogporten.Application.Externals;
using Digdir.Domain.Dialogporten.Domain.Actors;
using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities;
using Digdir.Library.Entity.Abstractions.Features.Identifiable;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;

Expand All @@ -14,14 +15,17 @@ internal sealed class PopulateActorNameInterceptor : SaveChangesInterceptor

private readonly IDomainContext _domainContext;
private readonly IPartyNameRegistry _partyNameRegistry;
private readonly ITransactionTime _transactionTime;
private bool _hasBeenExecuted;

public PopulateActorNameInterceptor(
ITransactionTime transactionTime,
IDomainContext domainContext,
IPartyNameRegistry partyNameRegistry)
{
_domainContext = domainContext ?? throw new ArgumentNullException(nameof(domainContext));
_partyNameRegistry = partyNameRegistry ?? throw new ArgumentNullException(nameof(partyNameRegistry));
_transactionTime = transactionTime ?? throw new ArgumentNullException(nameof(transactionTime));
}

public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(
Expand Down Expand Up @@ -57,8 +61,8 @@ public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(

var actorNameById = new Dictionary<string, string?>();
foreach (var actorId in actors
.Select(x => x.ActorId!)
.Distinct())
.Select(x => x.ActorId!)
.Distinct())
{
actorNameById[actorId] = await _partyNameRegistry.GetName(actorId, cancellationToken);
}
Expand Down Expand Up @@ -86,7 +90,28 @@ public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(
continue;
}

actor.ActorName = actorName;
var actorNameEntity = await dbContext.Set<ActorName>()
.FirstOrDefaultAsync(x => x.ActorId == actor.ActorId && x.Name == actorName, cancellationToken);
if (actorNameEntity is null)
{
actor.ActorNameEntity = new ActorName
{
Id = IdentifiableExtensions.CreateVersion7(),
CreatedAt = _transactionTime.Value,
Name = actorName,
ActorId = actor.ActorId!
};
dbContext.Add(actor.ActorNameEntity);
}
else
{
actor.ActorNameEntity = actorNameEntity;
}

// ActorName is not set/overwritten by the Interceptor.
// In cases where ActorName and ActorId is given, ActorName might not equal ActorNameEntity.ActorName
// ActorName should not be used when ActorNameEntity is used therefore its set to null
actor.ActorName = null;
}

_hasBeenExecuted = true;
Expand Down
Loading
Loading